* fix(#2851): replace bare gsd-tools invocations with absolute path `gsd-tools` is not a published bin entry — package.json declares only get-shit-done-cc and gsd-sdk. The shipped invocation pattern is `node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" <subcommand>`, used by every other workflow file. Two leaked bare invocations: - get-shit-done/workflows/plan-phase.md §13e (gap-analysis) — reported in #2851; gap-analysis silently skipped on every plan-phase run - get-shit-done/workflows/ingest-docs.md §finalize (commit) — caught by the new structural test; ingest-docs commit step was broken Both updated to canonical absolute-path form. Adds tests/bug-2851-workflow-bare-gsd-tools.test.cjs which parses every markdown file under get-shit-done/workflows/, extracts shell-fenced code blocks, tokenizes each line, and asserts no token in command position is the bare string `gsd-tools` (the trailing `.cjs` is a different token). The test also asserts plan-phase.md's gap-analysis call uses the canonical `node …/gsd-tools.cjs` form. Closes #2851 * fix(#2851): catch third bare gsd-tools call in ingest-docs.md init After the first commit, the structural test was strengthened to detect bare `gsd-tools` inside `$(...)` and backtick command-substitution forms. The improved test surfaced a third leak: ingest-docs.md:55: INIT=$(gsd-tools init ingest-docs) Fixed to canonical form INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init ingest-docs) plus the standard `@file:` handoff line that every other workflow uses when capturing INIT (required by tests/windows-robustness.test.cjs). Updated tests/bug-2801-ingest-docs-handler.test.cjs to match either the bare `gsd-tools init ingest-docs` or canonical `gsd-tools.cjs" init ingest-docs` form — the test's intent is to verify the dispatch handler is wired, not to lock the bare-bin form that #2851 removes. Closes #2851 * test(#2851): tighten ingest-docs and gap-analysis assertions to canonical form CodeRabbit caught two soft assertions in the regression tests: 1. tests/bug-2801: the init-ingest-docs assertion accepted both the legacy bare `gsd-tools` form and the canonical node-path form. Since #2851 is the fix that removes the bare form, the test should only accept the canonical absolute-path invocation. Switched to parsed-bash-block extraction with an anchored regex on the full `node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs"` path. 2. tests/bug-2851: the gap-analysis assertion used two loose .includes()/word-boundary checks. Replaced with a single assert.match() against the full canonical path so non-canonical forms fail. * test(#2851): env-assignment skip accepts lowercase identifiers too CodeRabbit caught: the cmdIdx-skip regex /^[A-Z_][A-Z0-9_]*=/ only matched uppercase variable names, so a line like `tmp=1 gsd-tools init` would tokenize to ['tmp=1','gsd-tools','init'], the regex would fail on 'tmp=1', cmdIdx would stay at 0, and the command-position check would compare 'tmp=1' against 'gsd-tools' — false negative. POSIX shell variable names are [A-Za-z_][A-Za-z0-9_]*. Widen the regex to match the actual lexical rule. Existing uppercase forms still work (FOO=bar gsd-tools); now lowercase forms (tmp=1 gsd-tools) and mixed case forms are also detected.
This commit is contained in:
@@ -126,11 +126,19 @@ describe('bug-2801: ingest-docs.md workflow calls gsd-tools not gsd-sdk', () =>
|
||||
);
|
||||
});
|
||||
|
||||
test('ingest-docs.md init step uses gsd-tools init ingest-docs', () => {
|
||||
test('ingest-docs.md init step uses canonical node-path gsd-tools.cjs invocation', () => {
|
||||
const content = fs.readFileSync(WORKFLOW_FILE, 'utf-8');
|
||||
const lines = content.split('\n');
|
||||
const initLine = lines.find(l => /gsd-tools\s+init\s+ingest-docs/.test(l));
|
||||
assert.ok(initLine, 'workflow must contain "gsd-tools init ingest-docs"');
|
||||
// Parse fenced bash blocks structurally — do not match raw markdown text.
|
||||
const codeBlockRe = /```bash\n([\s\S]*?)```/g;
|
||||
const bashLines = [...content.matchAll(codeBlockRe)]
|
||||
.flatMap((m) => m[1].split('\n'))
|
||||
.filter((l) => !/^\s*#/.test(l));
|
||||
// Per #2851 the only valid form is the absolute-path node invocation; the
|
||||
// legacy bare `gsd-tools` is the bug being fixed and must not be accepted.
|
||||
const initLine = bashLines.find((l) =>
|
||||
/\bnode\s+["']?\$HOME\/\.claude\/get-shit-done\/bin\/gsd-tools\.cjs["']?\s+init\s+ingest-docs\b/.test(l)
|
||||
);
|
||||
assert.ok(initLine, 'workflow must invoke init ingest-docs via canonical node-path gsd-tools.cjs');
|
||||
});
|
||||
|
||||
test('cmdInitIngestDocs is exported from init.cjs', () => {
|
||||
|
||||
Reference in New Issue
Block a user