Six independent windows-only failure clusters identified from the windows-22 CI log on1be0e4e2: - scripts/command-contract-helpers.cjs: parseFrontmatter split on `\n` → on Windows checkout (autocrlf=true) every line carries trailing \r, lines.indexOf('---', 1) returns -1, all fields read as missing. Drove the bulk of three "67 subtests failed" suite-level errors covering workstreams.md, workspace.md, verify-work.md, add-tests.md, etc. Fix: split(/\r?\n/). - tests/enh-3271-sdk-adr-structure.test.cjs: same CRLF pattern — H2 captures pulled '\r' into headings like "decision\r", breaking equality checks on "## Decision" / "## Consequences". Fix: same. - tests/runtime-bridge-sync-smoke.test.cjs: await import(BRIDGE_PATH) passed a Windows absolute path to Node's ESM loader, which rejects with "Only URLs with a scheme in: file, data, and node are supported." Fix: wrap once at module scope with pathToFileURL. pathToFileURL is a no-op for POSIX absolute paths. - tests/bug-2957-claude-global-postinstall-message.test.cjs: hardcoded '/tmp/gsd-test-settings.json' resolved to D:\tmp\... on Windows where the parent dir doesn't exist → ENOENT on fs.writeFileSync inside finishInstall. Fix: os.tmpdir() + pid suffix. - tests/bug-2774-worktree-cleanup-workspace-safety.test.cjs: the "while/read loop" subtest and the "end-to-end against real git worktrees" describe both assert POSIX shell behavior (process substitution `< <(...)`, RUNNER~1 8.3-shortname mismatch). Skip on win32 with explicit reasons (satisfies the no-unconditional-win32-skip guard). - tests/bug-2838-summary-rescue-gitignored-planning.test.cjs: entire describe extracts bash rescue blocks from workflow .md files and runs them; the shell contract itself is the test's point. Skip on win32 with reason. - tests/helpers.cjs cleanup(): bumped rmSync retry budget from 10×100ms to 20×250ms — 1s wasn't enough for Windows Defender's deferred handle release; bumping to 5s should absorb the residual EBUSY failures observed in bug-1736 / bug-2248 / bug-2698 after the first retry bump landed in1be0e4e2. Validated: holodeck (ubuntu docker) 11224/0 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.7 KiB
JavaScript
73 lines
2.7 KiB
JavaScript
'use strict';
|
|
|
|
process.env.GSD_TEST_MODE = '1';
|
|
|
|
/**
|
|
* Bug #2957: post-install message for `--claude --global` must instruct
|
|
* users to restart Claude Code and offer the skill-name fallback, since
|
|
* the skills-only install layout (CC 2.1.88+) leaves nothing in
|
|
* commands/gsd/ for the slash menu to read on older configurations.
|
|
*
|
|
* Captures the call to finishInstall(runtime='claude', isGlobal=true) and
|
|
* asserts the printed message contains both invocation paths.
|
|
*/
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const path = require('node:path');
|
|
const os = require('node:os');
|
|
|
|
const ROOT = path.join(__dirname, '..');
|
|
const SETTINGS_PATH = path.join(os.tmpdir(), `gsd-test-settings-${process.pid}.json`);
|
|
const installModule = require(path.join(ROOT, 'bin', 'install.js'));
|
|
|
|
function captureFinishInstallOutput(runtime, isGlobal) {
|
|
const original = console.log;
|
|
const lines = [];
|
|
console.log = (...args) => { lines.push(args.join(' ')); };
|
|
try {
|
|
installModule.finishInstall(
|
|
SETTINGS_PATH,
|
|
{},
|
|
null,
|
|
false,
|
|
runtime,
|
|
isGlobal,
|
|
null,
|
|
);
|
|
} finally {
|
|
console.log = original;
|
|
}
|
|
// Strip ANSI color escapes so message-content assertions don't couple to colors.
|
|
return lines.join('\n').replace(/\x1B\[[0-9;]*m/g, '');
|
|
}
|
|
|
|
describe('Bug #2957: claude+global post-install message', () => {
|
|
test('claude+global message tells the user to restart and offers skill-name fallback', () => {
|
|
const output = captureFinishInstallOutput('claude', true);
|
|
|
|
assert.match(output, /restart claude code/i, 'should mention restart');
|
|
assert.match(output, /\/gsd-new-project/, 'should still mention /gsd-new-project');
|
|
assert.match(output, /gsd-new-project skill/i, 'should mention the skill name fallback');
|
|
assert.doesNotMatch(
|
|
output,
|
|
/open a blank directory/i,
|
|
'global claude install should replace, not extend, the legacy generic instruction',
|
|
);
|
|
});
|
|
|
|
test('claude+local message keeps the original /gsd-new-project instruction', () => {
|
|
const output = captureFinishInstallOutput('claude', false);
|
|
|
|
assert.match(output, /\/gsd-new-project/, 'should still mention /gsd-new-project');
|
|
assert.doesNotMatch(output, /restart claude code/i, 'local install does not require the skills restart note');
|
|
});
|
|
|
|
test('non-claude runtimes keep their original message format', () => {
|
|
const output = captureFinishInstallOutput('opencode', true);
|
|
|
|
assert.match(output, /Open a blank directory/, 'opencode message should be unchanged');
|
|
assert.doesNotMatch(output, /restart/i, 'opencode message should not have the claude-specific restart note');
|
|
});
|
|
});
|