Commit Graph

7 Commits

Author SHA1 Message Date
Tom Boucher
33afb4f6eb chore(#452): add ESLint 9 flat-config harness with three custom AST rules (#460)
Install eslint@9 + typescript-eslint@8 + globals@16 + eslint-plugin-n@17 +
eslint-plugin-no-only-tests@3 + typescript as devDependencies.

eslint.config.mjs (flat config):
- Global ignores: node_modules, dist, .worktrees, .claude, coverage, the
  12 generated get-shit-done/bin/lib/*.cjs files
- Block for get-shit-done/bin/**/*.cjs + scripts/**/*.cjs: js.recommended +
  eslint-plugin-n + local plugin; generic quality rules (no-var, prefer-const,
  no-unused-vars, no-empty, n/no-process-exit)
- Block for tests/**/*.test.cjs: no-only-tests (error), local timing rules,
  no-restricted-syntax timing bans

eslint-rules/ local plugin (three AST rules, all at warn pending cleanup):
- no-source-grep: flag readFileSync on source .cjs/.js/.ts + text methods
- no-magic-sleep-in-tests: flag Atomics.wait and await-new-Promise(setTimeout)
- no-elapsed-assertion: flag assert*() on timing props (elapsed/duration/took/ms)

tsconfig.lint.json: allowJs + checkJs + noEmit for future type-aware passes.

tests/eslint-rules.test.cjs: 15 RuleTester unit tests (all pass, 0 fail).

package.json: add lint/lint:fix scripts; remove lint:tests (subsumed by ESLint
local/no-source-grep). Rules that produced pre-existing errors downgraded to
warn: no-useless-escape, no-unsafe-finally, no-regex-spaces, no-control-regex,
no-irregular-whitespace. ESLint exits 0 (warnings ok).

.github/workflows/test.yml lint-tests job: add npm ci + ESLint step; remove
"Lint — no source-grep tests" step (now covered by ESLint); bump timeout 3→5
min. .gitignore: add node_modules/.cache/eslint/ entry.

eslint --fix auto-cleaned: no-regex-spaces in tests, prefer-const in state.cjs,
redundant eslint-disable-next-line comments.

Co-authored-by: CI Rebase Check <ci@gsd-redux>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 10:54:49 -04:00
Tom Boucher
40e325b91f fix(3663): pass runtime+cmdNames to Claude converter for Hermes/Qwen
convertClaudeCommandToClaudeSkill(content, skillName, runtime, cmdNames) uses
the runtime arg to gate Hermes/Qwen branding and version: frontmatter emission
(#2808, #3583). Previously the layout module called it with only 2 args so the
runtime-specific formatting was never applied.

Changes:
- skillsKind() gains a runtime param (5th arg after converterName).
- stage() computes cmdNames = readGsdCommandNames() once per call (perf: avoids
  repeated fs.readdirSync in the converter) and wraps the real converter so all
  4 args are forwarded.
- readGsdCommandNames added to bin/install.js GSD_TEST_MODE exports block so the
  stage closure can call it without requiring the script separately.
- All switch arms updated to pass the canonical runtime string.

Converters that do not inspect runtime/cmdNames (Cursor, Codex, Copilot, etc.)
accept and ignore the extra arguments — no behaviour change for those runtimes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00
Tom Boucher
be5fe61221 fix(3663): lazy-require converters; remove GSD_TEST_MODE env mutation at module load
Previously runtime-artifact-layout.cjs set process.env.GSD_TEST_MODE at the
top level before requiring bin/install.js. Any caller that required this module
would silently inherit the GSD_TEST_MODE='1' side-effect for the lifetime of
the process.

Replace with a lazy loader (loadInstallExports / getInstallExports) that saves
the current GSD_TEST_MODE, sets it to '1' only if it was undefined, calls
require(), and restores the original value in a finally block. The exported
module.exports cache (_installExports) ensures the require is run at most once.

Converter names are now passed as strings to skillsKind; the stage closure
resolves them via getInstallExports()[converterName] at call time, so the
installer is not loaded until a stage() function is actually invoked.

Verification: node -e "require('./...runtime-artifact-layout.cjs'); console.log(process.env.GSD_TEST_MODE)"
prints undefined.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00
Tom Boucher
67dd09e509 fix(3663): restore .gsd-source marker resolution in findInstallSourceRoot
Both findInstallSourceRoot and findAgentsSourceRoot now accept an optional
runtimeConfigDir. When provided, they first check <runtimeConfigDir>/.gsd-source:
read the stored path, verify it exists, and return it. Fall through to the
path.dirname walk-up only when the marker is absent or points to a missing path.

The factory functions (commandsKind, agentsKind, skillsKind) now receive configDir
from the switch arms and pass it through to the finders. listSurface in surface.cjs
passes its runtimeConfigDir argument to findInstallSourceRoot so installed-from-source
layouts use the marker rather than the walk-up.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00
Tom Boucher
3711a4f04f fix(3663): replace ../../.. fallback with descriptive error per CLAUDE.md
Both findInstallSourceRoot and findAgentsSourceRoot previously returned a
path.join(__dirname, '..', '..', '..', ...) fallback when the walk-up loop
found nothing. Replace with throw per CLAUDE.md "No Relative Path Traversal"
policy: ..  chains silently break on CWD changes; a throw with the failing
__dirname in the message is an unambiguous diagnostic.

The walk-up loop already uses path.dirname iteratively (no literal ..); only
the dead-end fallback used the banned pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00
Tom Boucher
4d578394eb refactor(3663): migrate applySurface to layout-driven loop; add skills kind to _syncGsdDir
- applySurface(runtimeConfigDir, commandsDir, agentsDir, manifest, clusterMap) → applySurface(runtimeConfigDir, layout, manifest, clusterMap)
- _syncGsdDir extended to handle skills kind (dirs not files, prefix-gated removal)
- _findInstallSource/_findAgentsSource deleted; listSurface now uses findInstallSourceRoot() from runtime-artifact-layout.cjs
- findInstallSourceRoot exported from runtime-artifact-layout.cjs
- test(3663): update surface-apply.test.cjs to new layout-passing shape + add skills kind test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00
Tom Boucher
dc2a6278e5 feat(3663): add runtime-artifact-layout.cjs + resolve tests for all 15 runtimes
- New module: get-shit-done/bin/lib/runtime-artifact-layout.cjs
  - resolveRuntimeArtifactLayout(runtime, configDir, scope) → Layout
  - 15-runtime table (grok intentionally excluded, throws TypeError)
  - findInstallSourceRoot / findAgentsSourceRoot walk-up-only (no .gsd-source marker in Phase 1)
  - Loads bin/install.js converters via GSD_TEST_MODE guard
- Tests: 16 fixtures covering all runtimes + both claude scopes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 01:12:00 -04:00