fix(#4489): make capability-registry.test.cjs's extractShellBlocks CRLF-safe (#4584)

* fix(#4489): make capability-registry.test.cjs's extractShellBlocks CRLF-safe

Second, independent copy of the #4409 CRLF-fragile line-splitting bug,
explicitly flagged as out of scope there ("other duplicated helper in file
sibling test files not part of the shadowing chain, tracked separately if
divergent"). Same fix: content.split('\n') -> content.split(/\r?\n/),
matching src/text-lines.cts's splitLines() and the already-fixed sibling
copy in tests/runtime-launcher-parity.test.cjs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(#4488): regenerate INVENTORY-MANIFEST.json for tdd-red-evidence.cjs's ADR-457 untracking

Discovered while validating #4489's push: #4488's merge (untracking
gsd-core/bin/lib/tdd-red-evidence.cjs per ADR-457) left docs/INVENTORY-
MANIFEST.json stale, since that file was previously listed as a tracked
shipped artifact. Removed via node scripts/gen-inventory-manifest.cjs
--write. docs/INVENTORY.md already described this file as gitignored
(no update needed there -- it already documented the intended state).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* revert: undo incorrect INVENTORY-MANIFEST.json edit from 57f1457a27

The prior commit removed tdd-red-evidence.cjs's manifest entry based on a
false premise: a stale tsconfig.build.tsbuildinfo (gitignored, untouched
by git checkout/rebase) told tsc the file's compilation was already
current even though git's own checkout had deleted the actual output file
during this branch's rebase onto #4488's merge (a tracked-in-old-tree,
untracked-in-new-tree transition deletes the working-tree file regardless
of the new .gitignore entry). tsc's incremental cache doesn't verify its
recorded output still exists on disk, so it silently skipped re-emitting
it. Confirmed real root cause: deleting tsconfig.build.tsbuildinfo and
rebuilding fresh correctly re-emits gsd-core/bin/lib/tdd-red-evidence.cjs
(it is gitignored now, not deleted -- src/tdd-red-evidence.cts is
unaffected by ADR-457's tracked-vs-gitignored distinction and always
compiles). The manifest's own purpose (per its docstring) is 'every
shipped surface derived entirely from the filesystem' -- this file still
ships via the normal build, so it belongs in the manifest regardless of
git-tracking status. Net result matches next's own INVENTORY-MANIFEST.json
byte-for-byte; this correction should not have been needed at all had the
build cache been fresh when the prior commit was made.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-09-09 21:53:37 -04:00
committed by GitHub
parent 7fe440a838
commit b2d50ffd83

View File

@@ -6286,7 +6286,11 @@ const WORKFLOWS_DIR = path.join(__dirname, '..', 'gsd-core', 'workflows');
* between the ```bash / ```sh / ```shell fence markers. * between the ```bash / ```sh / ```shell fence markers.
*/ */
function extractShellBlocks(content) { function extractShellBlocks(content) {
const allLines = content.split('\n'); // #4489: CRLF-safe split (mirrors src/text-lines.cts's splitLines() and the
// fixed sibling copy in tests/runtime-launcher-parity.test.cjs:221) — a bare
// '\n' split leaves a trailing \r on every line on a CRLF checkout, which
// reaches lineHasBareGsdTools' whitespace tokenizer below.
const allLines = content.split(/\r?\n/);
const blocks = []; const blocks = [];
let inBlock = false; let inBlock = false;
let blockLang = null; let blockLang = null;
@@ -6369,6 +6373,41 @@ function lineHasBareGsdTools(line) {
const AGENTS_DIR = path.join(__dirname, '..', 'agents'); const AGENTS_DIR = path.join(__dirname, '..', 'agents');
describe('bug #4489: extractShellBlocks is CRLF-safe (sibling of #4409)', () => {
test('a CRLF-line-ending fenced block yields lines with no trailing \\r', () => {
const content = [
'# doc',
'',
'```bash',
'echo one',
'echo two',
'```',
'',
].join('\r\n');
const blocks = extractShellBlocks(content);
assert.strictEqual(blocks.length, 1, 'expected exactly one extracted block');
assert.deepStrictEqual(blocks[0].lines, ['echo one', 'echo two']);
for (const line of blocks[0].lines) {
assert.ok(!line.includes('\r'), `line carried a trailing/embedded \\r: ${JSON.stringify(line)}`);
}
});
test('LF-only input is unaffected (pre-existing behavior unchanged)', () => {
const content = [
'# doc',
'',
'```sh',
'echo one',
'echo two',
'```',
'',
].join('\n');
const blocks = extractShellBlocks(content);
assert.strictEqual(blocks.length, 1);
assert.deepStrictEqual(blocks[0].lines, ['echo one', 'echo two']);
});
});
describe('bug #1041: agent files must not call bare gsd-tools (all-runtime resolver)', () => { describe('bug #1041: agent files must not call bare gsd-tools (all-runtime resolver)', () => {
test('no agents/gsd-*.md file contains a bare gsd-tools command', () => { test('no agents/gsd-*.md file contains a bare gsd-tools command', () => {
const files = fs.readdirSync(AGENTS_DIR).filter((f) => f.startsWith('gsd-') && f.endsWith('.md')); const files = fs.readdirSync(AGENTS_DIR).filter((f) => f.startsWith('gsd-') && f.endsWith('.md'));