chore: clean up clear-cut ESLint warnings (#732) (#734)

Pay down pre-existing error→warn lint debt. Removes dead imports/vars, unused functions, redundant regex/string escapes, and stale eslint-disable directives; converts unused `catch (_e)` to optional catch binding (src/*.cts).

No behavior change. Lint 345→125 warnings (0 errors); deferred categories (n/no-process-exit, test-sleeps, control-regex) tracked in #732 for follow-up. Full test suite green (0 failures); code-review verified all removals unused and all escape fixes semantics-preserving.

Closes #732

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-06 11:24:48 -04:00
committed by GitHub
parent 42b74100f1
commit ba231ecbfc
117 changed files with 132 additions and 350 deletions

View File

@@ -298,13 +298,11 @@ async function main() {
// Optional workstream override for parallel milestone work.
// Priority: --ws flag > GSD_WORKSTREAM env var > session/shared pointer > null.
let ws = null;
let workstreamContext = null;
try {
workstreamContext = resolveActiveWorkstream(cwd, args, process.env, {
getStored: getActiveWorkstream,
});
ws = workstreamContext.ws;
args = workstreamContext.args;
// Set env var so all modules (planningDir, planningPaths) auto-resolve workstream paths.
applyResolvedWorkstreamEnv(workstreamContext, process.env);

View File

@@ -442,7 +442,7 @@ function resolveBaseRef() {
* security), so every concrete match that pickAffectedTests put into `selected`
* belongs to one of those suites and will be exercised by running all three.
*/
function resolveRunPlan({ changedFiles, selected, widenRequired, criticalPath, noChanges }) {
function resolveRunPlan({ changedFiles: _changedFiles, selected, widenRequired, criticalPath, noChanges }) {
if (noChanges) {
return { mode: 'suite', suite: 'unit' };
}

View File

@@ -17,7 +17,7 @@
const fs = require('node:fs');
const path = require('node:path');
const { parseFragment, FRAGMENT_ERROR } = require('./parse.cjs');
const { parseFragment } = require('./parse.cjs');
const { renderChangelog } = require('./render.cjs');
const { serializeChangelog, parseChangelog } = require('./serialize.cjs');
const { renderGithubReleaseNotes } = require('./github-release-notes.cjs');

View File

@@ -27,7 +27,7 @@
const fs = require('fs');
const path = require('path');
const { execFileSync, spawnSync } = require('child_process');
const { spawnSync } = require('child_process');
// On Windows, npm ships as npm.cmd (a batch wrapper); spawnSync without
// shell:true requires the exact filename including extension.

View File

@@ -11,8 +11,7 @@
// Exit 0 = merged cleanly (or merge was a no-op).
// Exit 1 = merge conflict or fetch failure.
const { execFileSync, execSync } = require('child_process');
const path = require('path');
const { execFileSync } = require('child_process');
function run(cmd, args, opts) {
try {
@@ -50,11 +49,9 @@ if (token && repo) {
}
// Fetch base branch with retry.
let fetched = false;
for (let attempt = 1; attempt <= 3; attempt++) {
const result = run('git', ['fetch', 'origin', baseBranch]);
if (result) {
fetched = true;
break;
}
if (attempt === 3) {

View File

@@ -3,7 +3,6 @@
const { execFileSync } = require('child_process');
const { existsSync, readdirSync, appendFileSync } = require('fs');
const { join } = require('path');
const RULES = [
{

View File

@@ -133,7 +133,7 @@ function checkAgent(profile) {
return ['agent file not found: ' + agentPath];
}
const { fields, body } = parseAgentFile(agentPath);
const { fields } = parseAgentFile(agentPath);
const fullContent = fs.readFileSync(agentPath, 'utf8');
// (a) frontmatter fields

View File

@@ -30,7 +30,7 @@ const DRY_RUN = process.argv.includes('--dry-run');
const ROOT = path.join(__dirname, '..');
const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
const AT_PATH_PATTERN = /@(?:~|\$HOME)\/.+?gsd-core\/[^\s`\)]+/;
const AT_PATH_PATTERN = /@(?:~|\$HOME)\/.+?gsd-core\/[^\s`)]+/;
const mkAtRe = () => new RegExp(AT_PATH_PATTERN.source, 'g');
function transformLine(line) {

View File

@@ -96,9 +96,6 @@ function removeResolverLines(lines, preamble) {
const result = [];
let i = 0;
// Build a set of preamble lines for fast lookup (to strip previously-inserted preambles)
const preambleLineSet = new Set(preamble);
while (i < lines.length) {
const line = lines[i];
const trimmed = line.trim();

View File

@@ -271,7 +271,7 @@ function createHub({ cjsRegistry, manifest, logger }: HubOptions = {}): { dispat
}
// err variant: already has kind + typed payload
// Double-cast through unknown to satisfy strict index-signature check.
return hubResult as unknown as Record<string, unknown>; // eslint-disable-line @typescript-eslint/no-unsafe-return
return hubResult as unknown as Record<string, unknown>;
}
/**

View File

@@ -679,7 +679,6 @@ function cmdConfigSetModelProfile(cwd: string, profile: string | undefined, raw:
error(`Usage: config-set-model-profile <${VALID_PROFILES.join('|')}>`);
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const normalizedProfile = profile!.toLowerCase().trim();
if (!VALID_PROFILES.includes(normalizedProfile)) {
error(`Invalid profile '${String(profile)}'. Valid profiles: ${VALID_PROFILES.join(', ')}`);

View File

@@ -33,7 +33,7 @@ function isGraphifyEnabled(planningDir: string): boolean {
(config.graphify as Record<string, unknown>).enabled === true
) return true;
return false;
} catch (_e) {
} catch {
return false;
}
}
@@ -230,7 +230,7 @@ function safeReadJson(filePath: string): Graph | null {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as Graph;
} catch (_e) {
} catch {
return null;
}
}

View File

@@ -61,7 +61,7 @@ function isIntelEnabled(planningDir: string): boolean {
(config.intel as Record<string, unknown>).enabled === true
) return true;
return false;
} catch (_e) {
} catch {
return false;
}
}
@@ -104,7 +104,7 @@ function safeReadJson(filePath: string): IntelData | null {
const raw = platformReadSync(filePath);
if (raw === null) return null;
return JSON.parse(raw) as IntelData;
} catch (_e) {
} catch {
return null;
}
}
@@ -118,7 +118,7 @@ function hashFile(filePath: string): string | null {
const content = platformReadSync(filePath);
if (content === null) return null;
return crypto.createHash('sha256').update(content).digest('hex');
} catch (_e) {
} catch {
return null;
}
}
@@ -175,22 +175,6 @@ function matchesInValue(value: unknown, lowerTerm: string): boolean {
return false;
}
/**
* Search for a term in arch.md text content.
* Returns matching lines.
*/
function searchArchMd(filePath: string, term: string): string[] {
try {
const content = platformReadSync(filePath);
if (content === null) return [];
const lowerTerm = term.toLowerCase();
const lines = content.split(/\r?\n/);
return lines.filter(line => line.toLowerCase().includes(lowerTerm));
} catch (_e) {
return [];
}
}
// ─── Public API ──────────────────────────────────────────────────────────────
interface IntelQueryResult {

View File

@@ -12,7 +12,6 @@
// Types
// ---------------------------------------------------------------------------
type ProviderKind = 'docs' | 'web' | 'scrape';
type ConfidenceLevel = 'HIGH' | 'MEDIUM' | 'LOW';
interface ProviderWaterfall {

View File

@@ -27,9 +27,6 @@ const MIGRATED_PHASE_HEADING_RE = /^#{2,4}\s*(?:\[[^\]]+\]\s*)?Phase\s+\d+-\d{2}
// The optional bracket-token prefix (e.g., [GSD]) must be tested before the emoji group.
const MILESTONE_HEADING_RE = /^##\s+(?:\[[^\]]+\]\s+|Roadmap\s+|[✅🚧]\s*)?v(\d+)\.(\d+)(?:\s|:)/iu;
// Matches checklist phase references: - [ ] **Phase N:** or - [x] **Phase N:** (also decimal)
const CHECKLIST_PHASE_RE = /^(\s*-\s*\[[ x]\]\s*\*{0,2})Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
// ─── Types ────────────────────────────────────────────────────────────────────
interface ParsedPhaseEntry {
@@ -199,19 +196,6 @@ function buildNewDirName(oldDirName: string, newId: string, projectCode: string
return projectCode ? `${projectCode}-${newBase}` : newBase;
}
/**
* Read project_code from config.json if present.
*/
function readProjectCode(configPath: string): string | null {
try {
const raw = fs.readFileSync(configPath, 'utf8');
const parsed = JSON.parse(raw) as Record<string, unknown>;
return typeof parsed['project_code'] === 'string' ? parsed['project_code'] : null;
} catch {
return null;
}
}
// ─── computeMigrationPlan ─────────────────────────────────────────────────────
/**

View File

@@ -17,7 +17,7 @@ import fs from 'node:fs';
import path from 'node:path';
// eslint-disable-next-line @typescript-eslint/no-require-imports
import core = require('./core.cjs');
const { toPosixPath, readSubdirectories } = core;
const { readSubdirectories } = core;
// eslint-disable-next-line @typescript-eslint/no-require-imports
import planScan = require('./plan-scan.cjs');
// eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -163,7 +163,6 @@ function getOtherActiveWorkstreamInventories(cwd: string, excludeWs: string): Wo
.filter(inventory => !isCompletedInventory(inventory.status));
}
// Re-export toPosixPath for compatibility (used by callers indirectly through core)
export = {
countPhaseFiles,
countRoadmapPhases,

View File

@@ -192,8 +192,6 @@ function extractFrontmatterField(stateContent, fieldName) {
// Capture stdout from cmdPhaseComplete (it calls output() which writes to stdout)
function capturePhaseComplete(cwd, phaseNum) {
const { execFileSync } = require('child_process');
const TOOLS = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
// We invoke gsd-tools directly for the full CJS path, but with GSD_DISABLE_SDK_BRIDGE=1
// to force the CJS implementation. Since no env var disables bridge, we call cmdPhaseComplete
// directly and redirect output capture.

View File

@@ -25,7 +25,7 @@ const EXPECTED_AGENTS = Object.keys(MODEL_PROFILES);
* We use --cwd to point at the project, and GSD_INSTALL_DIR env to override
* the agents directory location for testing.
*/
function createAgentsDir(configDir, agentNames = []) {
function _createAgentsDir(configDir, agentNames = []) {
const agentsDir = path.join(configDir, AGENTS_DIR_NAME);
fs.mkdirSync(agentsDir, { recursive: true });
for (const name of agentNames) {

View File

@@ -3,7 +3,7 @@
// IS what the runtime loads. Testing text content tests the deployed contract.
// Per CONTRIBUTING.md exception matrix.
const { test, describe, beforeEach, afterEach } = require('node:test');
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

View File

@@ -6,7 +6,7 @@
* for phases with frontend indicators.
*/
const { describe, it, test, beforeEach } = require('node:test');
const { describe, test, beforeEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

View File

@@ -24,7 +24,7 @@ const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { createTempProject, cleanup, runGsdTools, captureConsole } = require('./helpers.cjs');
const { createTempProject, cleanup, captureConsole } = require('./helpers.cjs');
const { getMilestonePhaseFilter } = require('../gsd-core/bin/lib/core.cjs');
// ─── helpers ─────────────────────────────────────────────────────────────────

View File

@@ -25,7 +25,7 @@ const path = require('node:path');
const { execFileSync } = require('node:child_process');
// The helpers under test.
const { runNpm, isolatedNpmEnv, cleanup } = require('./helpers.cjs');
const { isolatedNpmEnv, cleanup } = require('./helpers.cjs');
// Resolve a filesystem path to its canonical (symlink-free) form even if the
// leaf does not exist yet (e.g. ~/.npm before npm has written its cache).

View File

@@ -87,7 +87,6 @@ describe('bug-211: launcher ~/.claude home fallback', () => {
// in the same directory as gsd-tools, create a dedicated shim dir with a
// symlink to node only (no gsd-tools there).
const nodeBin = execFileSync('which', ['node'], { encoding: 'utf8' }).trim();
const nodeBinDir = path.dirname(nodeBin);
const systemPaths = (process.env.PATH || '/usr/bin:/bin')
.split(path.delimiter)
.filter((p) => {

View File

@@ -45,7 +45,7 @@ const os = require('os');
const { execFileSync } = require('child_process');
const HOOKS_DIR = path.join(__dirname, '..', 'hooks');
const CHECK_UPDATE_FILE = path.join(HOOKS_DIR, 'gsd-check-update.js');
const _CHECK_UPDATE_FILE = path.join(HOOKS_DIR, 'gsd-check-update.js');
const WORKER_FILE = path.join(HOOKS_DIR, 'gsd-check-update-worker.js');
const INSTALL_SCRIPT = path.join(__dirname, '..', 'bin', 'install.js');
const BUILD_SCRIPT = path.join(__dirname, '..', 'scripts', 'build-hooks.js');
@@ -142,11 +142,11 @@ describe('bug #2136 part 2: stale-hook detector handles bash comment syntax', ()
// "(?:\/\/|#)" directly in source.
const hasBashAlternative =
src.includes('(?:\\/\\/|#)') || // escaped form (old template-literal style)
src.includes('(?:\/\/|#)'); // direct form in plain JS worker
src.includes('(?://|#)'); // direct form in plain JS worker
assert.ok(
hasBashAlternative,
'gsd-check-update-worker.js version regex must include an alternative for bash "#" comments. ' +
'Expected to find (?:\\/\\/|#) or (?:\/\/|#) in the source. ' +
'Expected to find (?:\\/\\/|#) or (?://|#) in the source. ' +
'The original "//" only regex causes bash hooks to always report hookVersion: "unknown"'
);
});

View File

@@ -17,7 +17,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const isWindows = process.platform === 'win32';

View File

@@ -35,7 +35,7 @@ describe('update.md — no bare ~.claude path references (#2470)', () => {
assert.strictEqual(
matches,
null,
`update.md must not contain bare ~/\.claude (without trailing slash) — installer scanner flags these as unresolved path refs: ${JSON.stringify(matches)}`
`update.md must not contain bare ~/.claude (without trailing slash) — installer scanner flags these as unresolved path refs: ${JSON.stringify(matches)}`
);
});
});

View File

@@ -13,7 +13,6 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const path = require('node:path');
const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs');
const { VALID_CONFIG_KEYS, isValidConfigKey } = require('../gsd-core/bin/lib/config-schema.cjs');

View File

@@ -49,14 +49,6 @@ const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
//
// Expand this list only if a new runtime-emitter module is introduced AND the
// bug-3584 test is updated to cover it.
const RUNTIME_EMITTER_EXCLUDES = new Set([
// Primary runtime-slash emitter (bug-3584 canonical contract):
path.join(ROOT, 'gsd-core', 'bin', 'lib', 'runtime-slash.cjs'),
// phase-lifecycle-policy.ts emits runtime-persisted slash references (bug-3584):
path.join(ROOT, 'gsd-core', 'bin', 'lib', 'phase-lifecycle-policy.ts'),
// Generated CJS files match the TS source's emitted form — never hand-edited:
// (matched below by .generated.cjs extension — see collectFiles exclusion)
]);
const SEARCH_DIRS = [
// NOTE: gsd-core/bin/lib is intentionally EXCLUDED from SEARCH_DIRS.

View File

@@ -40,8 +40,6 @@ const {
install,
validateCodexConfigSchema,
hasUserNamespacedAotHooks,
stripGsdFromCodexConfig,
installCodexConfig,
parseTomlToObject,
} = require('../bin/install.js');
@@ -222,7 +220,7 @@ describe('#2760 defect 3 — Hooks AoT preservation across install/uninstall/rei
runCodexInstall(codexHome);
const content = readCodexConfig(codexHome);
const parsed = parseTomlToObject(content);
parseTomlToObject(content);
const hooksJsonCommands = readHooksSessionStartCommands(codexHome);
const gsdHandlers = hooksJsonCommands.filter((cmd) => /gsd-check-update/.test(cmd));
@@ -233,7 +231,7 @@ describe('#2760 defect 3 — Hooks AoT preservation across install/uninstall/rei
writeCodexConfig(codexHome, '');
runCodexInstall(codexHome);
runCodexInstall(codexHome); // second install
const content = readCodexConfig(codexHome);
readCodexConfig(codexHome);
const hooksJsonCommands = readHooksSessionStartCommands(codexHome);
const gsdHandlers = hooksJsonCommands.filter((cmd) => /gsd-check-update/.test(cmd));

View File

@@ -26,12 +26,8 @@ const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const {
readGsdRuntimeProfileResolver,
readGsdEffectiveModelOverrides,
convertClaudeToOpencodeFrontmatter,
install,
} = require('../bin/install.js');

View File

@@ -34,7 +34,7 @@ const path = require('node:path');
const { cleanup, createTempDir } = require('./helpers.cjs');
const ROOT = path.join(__dirname, '..');
const { convertClaudeCommandToClaudeSkill, installRuntimeArtifacts, uninstallRuntimeArtifacts, skillFrontmatterName } =
const { convertClaudeCommandToClaudeSkill, installRuntimeArtifacts, skillFrontmatterName } =
require(path.join(ROOT, 'bin', 'install.js'));
const {

View File

@@ -1,10 +1,9 @@
'use strict';
process.env.GSD_TEST_MODE = '1';
const { test, describe, before, after } = require('node:test');
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const path = require('node:path');
const cp = require('node:child_process');
const ROOT = path.join(__dirname, '..');
const { checkLatestVersion, CHECK_REASON, PACKAGE_NAME } = require(

View File

@@ -28,7 +28,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const { createTempDir, cleanup } = require('./helpers.cjs');
const { install } = require('../bin/install.js');

View File

@@ -27,7 +27,6 @@ const {
getGlobalConfigDir,
getGlobalSkillsBase,
getGlobalSkillDir,
getGlobalSkillDisplayPath,
} = require(path.join(ROOT, 'gsd-core', 'bin', 'lib', 'runtime-homes.cjs'));
// Helper: run fn with an env var temporarily set

View File

@@ -18,7 +18,6 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
@@ -33,14 +32,6 @@ const planScanLib = path.join(ROOT, 'gsd-core', 'bin', 'lib', 'plan-scan.cjs');
// The simplest correct seam: inspect the source for the regex pattern and
// validate with a synthetic directory that the manager path returns correct counts.
// Build a temporary phase directory with the slug layout
function makeTempPhase(files) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-3128-'));
for (const f of files) {
fs.writeFileSync(path.join(dir, f), `# ${f}\n`);
}
return dir;
}
// Import countPhasePlansAndSummaries by monkey-patching: we inline the
// fixed filter logic and verify it matches the file on disk.

View File

@@ -25,7 +25,6 @@ const path = require('node:path');
const ROOT = path.join(__dirname, '..');
const WORKFLOW = path.join(ROOT, 'gsd-core', 'workflows', 'add-backlog.md');
const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
const WORKFLOWS_DIR = path.join(ROOT, 'gsd-core', 'workflows');
// ─── #3135: add-backlog workflow ─────────────────────────────────────────────

View File

@@ -104,7 +104,7 @@ describe('#3242 Bug A: body-only state.update preserves curated progress frontma
cleanup(tmpDir);
});
test('state.update "Last Activity" does not overwrite progress.completed_plans', (t) => {
test('state.update "Last Activity" does not overwrite progress.completed_plans', (_t) => {
const statePath = path.join(tmpDir, '.planning', 'STATE.md');
fs.writeFileSync(statePath, buildStateWithCuratedProgress({
completedPlans: 22,
@@ -220,7 +220,7 @@ describe('#3242 Bug B: progress.percent reflects phase fraction when ROADMAP dec
cleanup(tmpDir);
});
test('12 declared phases / 6 realized / 6/6 plans done → percent is 50, not 100', (t) => {
test('12 declared phases / 6 realized / 6/6 plans done → percent is 50, not 100', (_t) => {
const statePath = path.join(tmpDir, '.planning', 'STATE.md');
// Body: 6 realized phases visible to disk scan.
@@ -273,7 +273,7 @@ describe('#3242 Bug B: progress.percent reflects phase fraction when ROADMAP dec
);
});
test('all phases realized: percent equals plan fraction (no artificial cap)', (t) => {
test('all phases realized: percent equals plan fraction (no artificial cap)', (_t) => {
const statePath = path.join(tmpDir, '.planning', 'STATE.md');
fs.writeFileSync(statePath, [

View File

@@ -26,7 +26,6 @@ const os = require('os');
const { execFileSync } = require('child_process');
const { validateCodexConfigSchema, install } = require('../bin/install.js');
const installModule = require('../bin/install.js');
const { cleanup } = require('./helpers.cjs');
if (previousGsdTestMode === undefined) {

View File

@@ -29,7 +29,6 @@ const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const REPO_ROOT = path.join(__dirname, '..');
const MODEL_CATALOG_CJS = path.join(REPO_ROOT, 'gsd-core', 'bin', 'lib', 'model-catalog.cjs');

View File

@@ -31,7 +31,7 @@
* "no warning" pattern from #2687).
*/
const { describe, test, afterEach, before } = require('node:test');
const { describe, test, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');

View File

@@ -20,7 +20,7 @@
'use strict';
const { describe, test, beforeEach, afterEach } = require('node:test');
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');

View File

@@ -25,7 +25,6 @@ const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const crypto = require('node:crypto');
const {
runInstallerMigrations,
@@ -36,10 +35,6 @@ const {
} = require('../gsd-core/bin/lib/installer-migration-report.cjs');
const { createTempDir, cleanup } = require('./helpers.cjs');
function sha256(content) {
return crypto.createHash('sha256').update(content).digest('hex');
}
function writeFile(root, relPath, content) {
const fullPath = path.join(root, relPath);
fs.mkdirSync(path.dirname(fullPath), { recursive: true });

View File

@@ -11,7 +11,6 @@ process.env.GSD_TEST_MODE = '1';
const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const REPO_ROOT = path.join(__dirname, '..');

View File

@@ -38,7 +38,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { install, getCodexSkillAdapterHeader } = require('../bin/install.js');
const { parseFrontmatter, createTempDir, cleanup } = require('./helpers.cjs');

View File

@@ -27,7 +27,6 @@ const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const crypto = require('node:crypto');
const {
runInstallerMigrations,

View File

@@ -84,7 +84,7 @@ function createFixtureWithUserGsdDir() {
describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disable', () => {
test('(a) disabled cluster gsd-* dirs are removed from skills dir', (t) => {
const { configDir, skillsDir, gsdExplore, gsdHelp } = createFixture();
const { configDir, gsdExplore, gsdHelp } = createFixture();
t.after(() => cleanup(configDir));
// Surface state at configDir (= ~/.claude), NOT at skillsDir (= ~/.claude/skills).
@@ -116,7 +116,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
});
test('(b) gsd-* dirs in retained clusters are preserved', (t) => {
const { configDir, skillsDir, gsdHelp } = createFixture();
const { configDir, gsdHelp } = createFixture();
t.after(() => cleanup(configDir));
// Disable a cluster that does NOT include help (core_loop has help)
@@ -138,7 +138,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
});
test('(c) non-gsd user dirs are untouched', (t) => {
const { configDir, skillsDir, userSkill } = createFixture();
const { configDir, userSkill } = createFixture();
t.after(() => cleanup(configDir));
writeSurface(configDir, {
@@ -163,7 +163,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
});
test('(d) idempotence: running applySurface twice produces identical on-disk state', (t) => {
const { configDir, skillsDir, gsdExplore, gsdHelp, userSkill } = createFixture();
const { configDir, skillsDir, gsdExplore, userSkill } = createFixture();
t.after(() => cleanup(configDir));
writeSurface(configDir, {
@@ -212,7 +212,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
// 2. gsd-help/ — GSD-owned, disabled cluster → REMOVED
// 3. my-custom-skill/ — user-owned, no gsd- prefix → PRESERVED
// 4. gsd-mything/ — prefix match but NOT in manifest → PRESERVED (Finding 1 fix)
const { configDir, skillsDir, gsdExplore, gsdHelp, userSkill, userGsdDir } =
const { configDir, gsdExplore, gsdHelp, userSkill, userGsdDir } =
createFixtureWithUserGsdDir();
t.after(() => cleanup(configDir));

View File

@@ -42,7 +42,7 @@ const { cleanup } = require('./helpers.cjs');
const REPO_ROOT = path.resolve(__dirname, '..');
const INSTALL_PATH = path.join(REPO_ROOT, 'bin', 'install.js');
const install = require(INSTALL_PATH);
require(INSTALL_PATH);
const { readCmdNames } = require(path.join(REPO_ROOT, 'scripts', 'fix-slash-commands.cjs'));
// ---------------------------------------------------------------------------
@@ -400,7 +400,6 @@ describe('bug #3683 — workflow/reference colon-namespace leak (Claude local in
describe('G — negative: staged gemini workflows preserve colon-namespace refs', () => {
let tmpDir;
const cmdNames = readCmdNames();
const rosterRegex = buildRosterRegex(cmdNames);
before(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-3683-gem-'));

View File

@@ -83,7 +83,7 @@ describe('bug #3691 — Bug 1: Plans-block detection with inline summary', () =>
let tmpDir;
afterEach(() => cleanup(tmpDir));
test('Plans: N plans (inline count after colon) is detected as a Plans-block', (t) => {
test('Plans: N plans (inline count after colon) is detected as a Plans-block', (_t) => {
// Pre-fix: `Plans:\s*\n` requires bare newline — fails for "Plans: 2 plans\n"
// Post-fix: `Plans:[^\n]*\n` accepts any text after the colon
const roadmap = [
@@ -117,7 +117,7 @@ describe('bug #3691 — Bug 1: Plans-block detection with inline summary', () =>
assert.ok(written.includes('Wave'), 'wave annotation must appear in ROADMAP.md');
});
test('Plans: N plans across N waves (longer inline text) is detected', (t) => {
test('Plans: N plans across N waves (longer inline text) is detected', (_t) => {
const roadmap = [
'# Roadmap',
'',
@@ -144,7 +144,7 @@ describe('bug #3691 — Bug 1: Plans-block detection with inline summary', () =>
'Plans-block with "N plans across N waves" inline text must be detected');
});
test('**Plans:** (bold markdown wrapper) is detected as a Plans-block', (t) => {
test('**Plans:** (bold markdown wrapper) is detected as a Plans-block', (_t) => {
// Bold wrapper: `**Plans:** 3 plans across 2 waves`
const roadmap = [
'# Roadmap',
@@ -170,7 +170,7 @@ describe('bug #3691 — Bug 1: Plans-block detection with inline summary', () =>
'**Plans:** bold-wrapped header must be detected as a Plans-block');
});
test('bare Plans: (no inline text, legacy format) still works after fix', (t) => {
test('bare Plans: (no inline text, legacy format) still works after fix', (_t) => {
// Regression guard: the fix must not break the working case
const roadmap = [
'# Roadmap',
@@ -205,7 +205,7 @@ describe('bug #3691 — Bug 3: decimal plan IDs (e.g. 02.3-01-PLAN.md) parse cor
let tmpDir;
afterEach(() => cleanup(tmpDir));
test('decimal plan ID 02.3-01 is captured fully and matched to the correct wave', (t) => {
test('decimal plan ID 02.3-01 is captured fully and matched to the correct wave', (_t) => {
// Pre-fix: `[\w-]+?` stops at `.` → captures `02` only → planData.find misses → wave = 1 for all
// Post-fix: `[\w.-]+?` captures `02.3-01` → planData.find resolves → correct wave written
const roadmap = [
@@ -238,7 +238,7 @@ describe('bug #3691 — Bug 3: decimal plan IDs (e.g. 02.3-01-PLAN.md) parse cor
assert.ok(/Wave 2/.test(written), 'Wave 2 header must appear in output');
});
test('combined fixture: decimal phase + bold Plans: header (both bugs together)', (t) => {
test('combined fixture: decimal phase + bold Plans: header (both bugs together)', (_t) => {
// Exercises Bug 1 (bold **Plans:** header) AND Bug 3 (decimal IDs) simultaneously.
// This is the exact ROADMAP fragment from the issue report.
const roadmap = [
@@ -280,7 +280,7 @@ describe('review fix F3 — leading-dot plan ID is rejected (defensive guard)',
let tmpDir;
afterEach(() => cleanup(tmpDir));
test('checklist line with leading-dot plan ID is skipped and does not silently default to wave 1', (t) => {
test('checklist line with leading-dot plan ID is skipped and does not silently default to wave 1', (_t) => {
// Guards: `.invalid-PLAN.md` would be captured as `.invalid` by the `[\w.-]+?` regex
// (since `.` is now included), which starts with a dot — an invalid ID.
// Without the guard, planData.find() misses it and wave defaults to 1, silently
@@ -327,7 +327,7 @@ describe('review fix F4 — adversarial test gaps', () => {
let tmpDir;
afterEach(() => cleanup(tmpDir));
test('001.10-PLAN.md multi-decimal leading-zero ID is captured fully and wave-assigned correctly', (t) => {
test('001.10-PLAN.md multi-decimal leading-zero ID is captured fully and wave-assigned correctly', (_t) => {
// Guards regression of Bug 3: `[\w-]+?` would stop at the first `.` and
// capture `001` instead of `001.10`, which never matches any planData entry.
// Post-fix `[\w.-]+?` must capture `001.10` in full.
@@ -357,7 +357,7 @@ describe('review fix F4 — adversarial test gaps', () => {
'wave 2 dependency must be resolved from full 001.10-02 ID (not truncated to 001)');
});
test('**Plans:** (bold, no trailing text) is matched and checklist is processed', (t) => {
test('**Plans:** (bold, no trailing text) is matched and checklist is processed', (_t) => {
// Guards the bare-bold variant: `**Plans:**` with nothing after the colon.
// The `[^\n]*` quantifier accepts zero chars so this should already work,
// but this test would fail if `\*{0,2}Plans\*{0,2}` regressed to require no stars.

View File

@@ -16,7 +16,6 @@ const { cleanup } = require('./helpers.cjs');
const {
executeWorktreeWaveCleanupPlan,
planWorktreeWaveCleanup,
reapOrphanWorktrees,
} = require('../gsd-core/bin/lib/worktree-safety.cjs');

View File

@@ -13,7 +13,6 @@ const assert = require('node:assert/strict');
const path = require('path');
const {
PROFILES,
resolveProfile,
loadSkillsManifest,
} = require('../gsd-core/bin/lib/install-profiles.cjs');

View File

@@ -21,20 +21,10 @@ const fs = require('fs');
const path = require('path');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const REPO_ROOT = path.join(__dirname, '..');
describe('bug #3739 — gap-analysis padded-prefix CONTEXT.md', () => {
let tmpDir;
let phaseDir;
function writeRequirements(ids) {
const lines = ids.map((id, i) => `- [ ] **${id}** Requirement ${i + 1}`);
fs.writeFileSync(
path.join(tmpDir, '.planning', 'REQUIREMENTS.md'),
`# Requirements\n\n${lines.join('\n')}\n`
);
}
function writeContextAs(filename, decisions) {
const dLines = decisions.map(d => `- **${d.id}:** ${d.text}`).join('\n');
fs.writeFileSync(

View File

@@ -32,7 +32,6 @@ const { cleanup } = require('./helpers.cjs');
const REPO_ROOT = path.resolve(__dirname, '..');
const INSTALL_PATH = path.join(REPO_ROOT, 'bin', 'install.js');
const HOOKS_DIST_DIR = path.join(REPO_ROOT, 'hooks', 'dist');
const HOOKS_SRC_DIR = path.join(REPO_ROOT, 'hooks');
// ---------------------------------------------------------------------------
// Helpers

View File

@@ -184,7 +184,6 @@ describe('bug #3784: settings.md model profile UI exposes all 5 profiles', () =>
// commit bd53925f fixed a duplicate '{' introduced by 35fc1d21 when the model-profile
// AskUserQuestion was split into Q1+Q2. This test guards against a recurrence.
let depth = 0;
const maxDepth = 0;
for (const ch of presentBlock) {
if (ch === '{') { depth++; }
if (ch === '}') { depth--; }

View File

@@ -14,7 +14,7 @@
* the clock seam (in-process, using makeFakeClock — no subprocess needed).
*/
const { describe, it, test, before, after } = require('node:test');
const { describe, test, before, after } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

View File

@@ -4,9 +4,8 @@ process.env.GSD_TEST_MODE = "1";
const { describe, test, beforeEach, afterEach } = require("node:test");
const assert = require("node:assert/strict");
const path = require("path");
const { createTempProject, cleanup } = require("./helpers.cjs");
const { resolveEffortInternal, CONFIG_DEFAULTS } = require("../gsd-core/bin/lib/core.cjs");
const { resolveEffortInternal } = require("../gsd-core/bin/lib/core.cjs");
const { CONFIG_DEFAULTS: CANONICAL_CONFIG_DEFAULTS } = require("../gsd-core/bin/lib/configuration.cjs");
describe("#492 manifest effort fallback", () => {

View File

@@ -30,7 +30,6 @@ const { execFileSync } = require('node:child_process');
const {
install,
writeManifest,
convertClaudeCommandToCodexSkill,
} = require('../bin/install.js');
const { createTempDir, cleanup, captureConsole } = require('./helpers.cjs');

View File

@@ -93,7 +93,7 @@ function runExtract(args = [], changelogText = null) {
}
describe('changeset cli extract: version-range changelog extraction (#3496)', () => {
test('exits 2 with no output when no versions fall in range', (t) => {
test('exits 2 with no output when no versions fall in range', (_t) => {
const r = runExtract(['--from', '1.5.15', '--to', '1.5.15', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 2, `expected exit 2 for empty range, stderr=${r.stderr}`);
// F11: assert JSON structure is present and releases is empty array
@@ -101,7 +101,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.strictEqual(r.json.releases.length, 0, 'releases must be empty array on exit 2');
});
test('extracts versions strictly after from and up to and including to', (t) => {
test('extracts versions strictly after from and up to and including to', (_t) => {
const r = runExtract(['--from', '1.5.13', '--to', '1.5.15', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 0, `stderr=${r.stderr}`);
assert.ok(r.json, 'stdout must be valid JSON');
@@ -112,7 +112,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(!versions.includes('1.5.10'), '1.5.10 must NOT be in range (below from)');
});
test('accepts v-prefixed version arguments', (t) => {
test('accepts v-prefixed version arguments', (_t) => {
const r = runExtract(['--from', 'v1.5.13', '--to', 'v1.5.15', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 0, `stderr=${r.stderr}`);
assert.ok(r.json, 'stdout must be valid JSON');
@@ -122,7 +122,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(!versions.includes('1.5.13'));
});
test('captures multi-line bullets in extracted range', (t) => {
test('captures multi-line bullets in extracted range', (_t) => {
const r = runExtract(['--from', '1.5.13', '--to', '1.5.14', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 0, `stderr=${r.stderr}`);
const release = r.json.releases.find((rel) => rel.version === '1.5.14');
@@ -132,7 +132,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(prs.includes(102), 'multi-line bullet pr=102 must be captured');
});
test('emits markdown text (non-JSON) when --json is not passed', (t) => {
test('emits markdown text (non-JSON) when --json is not passed', (_t) => {
// Without --json the output is human-readable markdown, not JSON.
// Assert on structural facts derivable from the text: exactly the two
// matched releases appear as ## headers, using parseChangelog so we
@@ -149,13 +149,13 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(!versions.includes('1.5.13'), '1.5.13 must not appear in output (excluded by --from)');
});
test('missing --from or --to emits usage and exits non-zero', (t) => {
test('missing --from or --to emits usage and exits non-zero', (_t) => {
const r = runExtract(['--from', '1.0.0'], EXTRACT_CHANGELOG);
assert.notEqual(r.status, 0);
assert.ok(r.stderr.length > 0 || r.stdout.length > 0, 'must emit usage text');
});
test('rejects malformed --from semver (non-numeric component) with exit 1', (t) => {
test('rejects malformed --from semver (non-numeric component) with exit 1', (_t) => {
const r = runExtract(['--from', '1.41.x', '--to', '1.5.15', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 1, `expected exit 1 for malformed --from, stderr=${r.stderr}`);
assert.ok(r.json, 'stdout must be valid JSON on error');
@@ -163,7 +163,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(r.json.error.includes('--from'), 'error must mention --from');
});
test('rejects malformed --to semver (alphabetic) with exit 1', (t) => {
test('rejects malformed --to semver (alphabetic) with exit 1', (_t) => {
const r = runExtract(['--from', '1.5.13', '--to', 'foo', '--json'], EXTRACT_CHANGELOG);
assert.equal(r.status, 1, `expected exit 1 for malformed --to, stderr=${r.stderr}`);
assert.ok(r.json, 'stdout must be valid JSON on error');
@@ -171,7 +171,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
assert.ok(r.json.error.includes('--to'), 'error must mention --to');
});
test('preserves bullets without PR trailer in extracted output', (t) => {
test('preserves bullets without PR trailer in extracted output', (_t) => {
// Fixture with one no-PR bullet and one PR bullet.
const CHANGELOG_NO_PR = [
'# Changelog',
@@ -196,7 +196,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
});
// F2: pre-release entries must be excluded from range queries
test('F2: pre-release entry 1.0.0-rc.1 is excluded from range --from 0.9.9 --to 1.0.0', (t) => {
test('F2: pre-release entry 1.0.0-rc.1 is excluded from range --from 0.9.9 --to 1.0.0', (_t) => {
const CHANGELOG_WITH_PRERELEASE = [
'# Changelog',
'',
@@ -228,7 +228,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
});
// F3: linked-header format ## [1.42.1](url) - date must parse date correctly
test('F3: linked-header ## [1.42.1](url) - date parses date correctly', (t) => {
test('F3: linked-header ## [1.42.1](url) - date parses date correctly', (_t) => {
const CHANGELOG_LINKED = [
'# Changelog',
'',
@@ -255,7 +255,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
});
// F4: nested bullets must remain as separate bullets, not fold into parent
test('F4: nested bullets are not folded into parent bullet', (t) => {
test('F4: nested bullets are not folded into parent bullet', (_t) => {
const CHANGELOG_NESTED = [
'# Changelog',
'',
@@ -283,7 +283,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
});
// F5+F6: 4-part headers and v-prefix in-file headers
test('F5+F6: 4-part version in CHANGELOG is skipped, v-prefixed version parses without v', (t) => {
test('F5+F6: 4-part version in CHANGELOG is skipped, v-prefixed version parses without v', (_t) => {
const CHANGELOG_EDGE = [
'# Changelog',
'',
@@ -324,7 +324,7 @@ describe('changeset cli extract: version-range changelog extraction (#3496)', ()
// F1: workflows/update.md must reference the extract subcommand invocation.
// allow-test-rule: reads a product workflow .md file (not CJS source) to verify
// the user-facing instruction was wired; there is no behavioural runtime to invoke.
test('F1: workflows/update.md contains concrete extract subcommand invocation', (t) => {
test('F1: workflows/update.md contains concrete extract subcommand invocation', (_t) => {
const workflowPath = path.join(ROOT, 'gsd-core', 'workflows', 'update.md');
const workflowText = fs.readFileSync(workflowPath, 'utf8');
// The invocation is: node "$GSD_DIR/gsd-core/scripts/changeset/cli.cjs" extract

View File

@@ -25,7 +25,6 @@ const ROOT = path.join(__dirname, '..');
const {
convertClaudeCommandToClaudeSkill,
writeManifest,
install,
installRuntimeArtifacts,
uninstallRuntimeArtifacts,
} = require(path.join(ROOT, 'bin', 'install.js'));

View File

@@ -34,12 +34,11 @@ const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const { spawnSync } = require('node:child_process');
const { makeFakeClock } = require('./helpers/clock.cjs');
const { acquireStateLock, releaseStateLock, readModifyWriteStateMd } = require('../gsd-core/bin/lib/state.cjs');
const { withPlanningLock } = require('../gsd-core/bin/lib/planning-workspace.cjs');
const { createTempProject, cleanup, runGsdTools, TOOLS_PATH } = require('./helpers.cjs');
const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs');
// ─────────────────────────────────────────────────────────────────────────────
// 1. Fake-clock proof: acquireStateLock accepts and uses the clock seam
@@ -209,10 +208,6 @@ describe('withPlanningLock clock seam', () => {
// Clock that advances past lockTimeout on every sleep call so the while
// condition trips immediately after the first retry.
let nowValue = 0;
const clock = {
now() { return nowValue; },
sleep(ms) { nowValue += ms + 11000; }, // jump past lockTimeout on every sleep
};
// withPlanningLock exits the while loop (timeout), deletes the lock, then
// calls runWithHeldLock() which tries writeFileSync with { flag: 'wx' }.

View File

@@ -10,7 +10,7 @@
* wired into config, templates, and the ship workflow.
*/
const { describe, test, beforeEach, afterEach } = require('node:test');
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

View File

@@ -20,7 +20,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { normalizeContent } = require('../gsd-core/bin/lib/shell-command-projection.cjs');
@@ -31,13 +30,6 @@ const normalizeMd = (input) => normalizeContent('test.md', input).content;
// ─── Helpers ────────────────────────────────────────────────────────────────
function writeMinimalRoadmap(tmpDir, phases = ['1']) {
const lines = phases.map(n => `### Phase ${n}: Phase ${n} Description`).join('\n');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n${lines}\n`
);
}
function writeMinimalStateMd(tmpDir, content) {
const defaultContent = content || `# Session State\n\n## Current Position\n\nPhase: 1\n`;
@@ -47,22 +39,6 @@ function writeMinimalStateMd(tmpDir, content) {
);
}
function writeMinimalProjectMd(tmpDir) {
const sections = ['## What This Is', '## Core Value', '## Requirements'];
const content = sections.map(s => `${s}\n\nContent here.\n`).join('\n');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'PROJECT.md'),
`# Project\n\n${content}`
);
}
function writeValidConfigJson(tmpDir, overrides = {}) {
const base = { model_profile: 'balanced', commit_docs: true };
fs.writeFileSync(
path.join(tmpDir, '.planning', 'config.json'),
JSON.stringify({ ...base, ...overrides }, null, 2)
);
}
/**
* Generate a 50-phase project structure for stress testing.

View File

@@ -891,8 +891,6 @@ describe('Copilot content conversion - engine files', () => {
// ─── Copilot instructions merge/strip ──────────────────────────────────────────
describe('Copilot instructions merge/strip', () => {
let tmpDir;
const gsdContent = '- Follow project conventions\n- Use structured workflows';
function makeGsdBlock(content) {
@@ -1127,7 +1125,7 @@ describe('Copilot manifest and patches fixes', () => {
fs.mkdirSync(skillDir, { recursive: true });
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), '# Test Skill\n\nA test skill.');
const manifest = writeManifest(tmpDir, 'copilot');
writeManifest(tmpDir, 'copilot');
// Check manifest file was written
const manifestPath = path.join(tmpDir, 'gsd-file-manifest.json');

View File

@@ -22,9 +22,7 @@ const {
resolveModelInternal,
escapeRegex,
generateSlugInternal,
normalizePhaseName,
reapStaleTempFiles,
comparePhaseNum,
pathExistsInternal,
getMilestoneInfo,
getMilestonePhaseFilter,

View File

@@ -29,11 +29,11 @@ describe('Cursor CLI reviewer in /gsd-review (#1960)', () => {
describe('review.md workflow', () => {
const reviewPath = path.join(ROOT, 'gsd-core', 'workflows', 'review.md');
let content;
let _content;
test('review.md exists', () => {
assert.ok(fs.existsSync(reviewPath), 'review.md should exist');
content = fs.readFileSync(reviewPath, 'utf-8');
_content = fs.readFileSync(reviewPath, 'utf-8');
});
test('contains cursor CLI detection via command -v cursor-agent', () => {
@@ -220,7 +220,6 @@ describe('Cursor CLI reviewer in /gsd-review (#1960)', () => {
});
test('mentions Cursor in the review section', () => {
const c = fs.readFileSync(jaPath, 'utf-8');
assert.ok(
/Cursor/i.test(fs.readFileSync(jaPath, 'utf-8')),
'docs/ja-JP/FEATURES.md should mention Cursor in the review section'
@@ -254,7 +253,6 @@ describe('Cursor CLI reviewer in /gsd-review (#1960)', () => {
});
test('mentions Cursor in the review section', () => {
const c = fs.readFileSync(koPath, 'utf-8');
assert.ok(
/Cursor/i.test(fs.readFileSync(koPath, 'utf-8')),
'docs/ko-KR/FEATURES.md should mention Cursor in the review section'

View File

@@ -181,7 +181,7 @@ describe('trace correlation — end-to-end parentTraceId propagation', () => {
const allEvents = readJsonl(isolatedAuditPath);
assert.equal(allEvents.length, 3, 'must have 3 events total (root + valid child + invalid child)');
const [root, validChild, invalidChild] = allEvents;
const [, validChild, invalidChild] = allEvents;
// Valid child carries the correct parentTraceId
assert.strictEqual(validChild.parentTraceId, rootTraceId,

View File

@@ -309,10 +309,6 @@ describe('getLiveCommandTokens() — helper contract', () => {
test('contains exactly 3 tokens per slug (slash, colon, dollar)', () => {
const result = getLiveCommandTokens();
// Every /gsd-slug should have a matching /gsd:slug and $gsd-slug
let tokenCount = 0;
for (const token of result) {
if (token.startsWith('/gsd-')) tokenCount++;
}
const slashTokens = [...result].filter(t => t.startsWith('/gsd-'));
for (const slash of slashTokens) {
const slug = slash.slice('/gsd-'.length);

View File

@@ -35,7 +35,7 @@ describe('enh-2430 Part A — plan-phase LEARNINGS.md context load', () => {
test('plan-phase.md LEARNINGS load is inside the 1M context-window gate', () => {
content = content || readWorkflow('plan-phase.md');
const windowBlock = content.match(/\$\{CONTEXT_WINDOW >= 500000[\s\S]*?\` : ''\}/);
const windowBlock = content.match(/\$\{CONTEXT_WINDOW >= 500000[\s\S]*?` : ''\}/);
assert.ok(windowBlock, 'CONTEXT_WINDOW gate block must exist');
assert.ok(
windowBlock[0].includes('LEARNINGS.md'),
@@ -62,7 +62,7 @@ describe('enh-2430 Part A — plan-phase LEARNINGS.md context load', () => {
test('plan-phase.md LEARNINGS load includes Depends-on chain', () => {
content = content || readWorkflow('plan-phase.md');
const dependsSection = content.match(/Depends on.*?(\n.*?)+/);
content.match(/Depends on.*?(\n.*?)+/);
assert.ok(
content.includes('LEARNINGS.md from any phases listed in'),
'plan-phase.md must load LEARNINGS.md for Depends on chain phases'

View File

@@ -8,7 +8,7 @@
* Tests for ROADMAP wave dependency surfacing (#2447).
*/
const { test, describe, beforeEach, afterEach } = require('node:test');
const { test, describe, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');

View File

@@ -46,8 +46,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const {
resolveModelInternal,
resolveModelForTier,

View File

@@ -285,7 +285,7 @@ for (const payload of SHELL_PAYLOADS) {
// ─── Cross-cutting: --cwd points at a non-existent path ────────────────────
test('--cwd pointing at a non-existent path fails with a typed usage reason', (t) => {
test('--cwd pointing at a non-existent path fails with a typed usage reason', (_t) => {
const nonExistent = path.join(require('os').tmpdir(), 'cli-neg-no-such-dir-' + Date.now() + '-' + Math.random());
assert.equal(fs.existsSync(nonExistent), false, 'pre-check: path must not exist');
const result = runCli(['--cwd', nonExistent, 'config-get', 'model_profile'], { cwd: process.cwd() });

View File

@@ -37,8 +37,6 @@ const { test, mock } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const {
platformWriteSync,
platformEnsureDir,
@@ -83,7 +81,7 @@ test('platformWriteSync recovers when renameSync fails (EXDEV cross-device fallb
// Simulate rename failing once (e.g. cross-device move on a CI runner
// with overlayfs). The fallback path must write the content directly.
let renameCalls = 0;
const renameMock = mock.method(fs, 'renameSync', (src, dest) => {
const renameMock = mock.method(fs, 'renameSync', (_src, _dest) => {
renameCalls++;
const err = new Error('EXDEV: cross-device link not permitted');
err.code = 'EXDEV';

View File

@@ -19,7 +19,7 @@ const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { createTempProject, createTempDir, cleanup, runGsdTools } = require('./helpers.cjs');
const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs');
const {
resolveEffortInternal,

View File

@@ -55,7 +55,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
// ─── Imports (will fail until implementation exists) ────────────────────────
// resolveModelPolicy is a new internal function that must be exported from core.cjs.

View File

@@ -16,7 +16,6 @@ const {
reconstructFrontmatter,
spliceFrontmatter,
parseMustHavesBlock,
FRONTMATTER_SCHEMAS,
} = require('../gsd-core/bin/lib/frontmatter.cjs');
// ─── extractFrontmatter ─────────────────────────────────────────────────────

View File

@@ -214,7 +214,7 @@ describe('mvp-viz', () => {
function parseSkillFrontmatter(text) {
const lines = text.split(/\r?\n/);
const out = {};
let activeKey = null;
let _activeKey = null;
let activeList = null;
for (const raw of lines) {
const listItem = raw.match(/^\s+-\s+(.+?)\s*$/);
@@ -227,11 +227,11 @@ describe('mvp-viz', () => {
const [, key, rawValue] = kv;
const value = rawValue.trim();
if (value === '') {
activeKey = key;
_activeKey = key;
activeList = [];
out[key] = activeList;
} else {
activeKey = null;
_activeKey = null;
activeList = null;
out[key] = value;
}
@@ -365,7 +365,7 @@ describe('regressions', () => {
function parseBug3166SkillFrontmatter(text) {
const lines = text.split(/\r?\n/);
const out = {};
let activeKey = null;
let _activeKey = null;
let activeList = null;
for (const raw of lines) {
const listItem = raw.match(/^\s+-\s+(.+?)\s*$/);
@@ -378,11 +378,11 @@ describe('regressions', () => {
const [, key, rawValue] = kv;
const value = rawValue.trim();
if (value === '') {
activeKey = key;
_activeKey = key;
activeList = [];
out[key] = activeList;
} else {
activeKey = null;
_activeKey = null;
activeList = null;
out[key] = value;
}

View File

@@ -4,14 +4,13 @@
// Reads .md/.json/.yml product files whose deployed text IS what the
// runtime loads — testing text content tests the deployed contract.
const { describe, it, test, beforeEach, afterEach } = require('node:test');
const { describe, test, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { createTempDir, cleanup, runGsdTools } = require('./helpers.cjs');
const {
findGsd2Root,
parseSlicesFromRoadmap,
parseMilestoneTitle,
parseTaskTitle,

View File

@@ -55,7 +55,7 @@ const sourceFiles = sourceDirs.flatMap(collectSourceFiles);
* Scan files for a pattern, skipping comment lines.
* Returns an array of human-readable failure strings.
*/
function scanFiles(files, pattern, description) {
function scanFiles(files, pattern, _description) {
const failures = [];
for (const file of files) {
const content = fs.readFileSync(file, 'utf8');

View File

@@ -354,7 +354,6 @@ describe('stateReplaceFieldWithFallback field-miss warning', () => {
}
roadmapContent += '\n';
for (let i = 1; i <= 50; i++) {
const pad = String(i).padStart(2, '0');
roadmapContent += `### Phase ${i}: Feature ${i}\n\n**Goal:** Build feature ${i}\n**Plans:** 1 plans\n\n`;
}
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapContent);

View File

@@ -9,7 +9,6 @@ const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { cleanup, createTempDir } = require('./helpers.cjs');

View File

@@ -44,8 +44,6 @@ const {
shouldInstallSkill,
stageSkillsForMode,
cleanupStagedSkills,
loadSkillsManifest,
resolveProfile,
} = require('../gsd-core/bin/lib/install-profiles.cjs');
const {

View File

@@ -10,7 +10,7 @@
'use strict';
const { test, describe, before, after } = require('node:test');
const { test, describe, before } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');

View File

@@ -48,7 +48,6 @@ const {
const {
RUNTIME_META,
SKILL_RUNTIMES,
stripAnsi,
walk,
} = require('./helpers/install-shared.cjs');

View File

@@ -174,14 +174,6 @@ function assertHasGsdDirectory(root, relPath) {
);
}
function assertNoGsdDirectoryEntries(root, relPath) {
assert.equal(
listDirNames(root, relPath).some((name) => name.startsWith('gsd-')),
false,
`${relPath} should not contain generated GSD entries`
);
}
function assertFreshInstallContract(runtime, targetDir) {
const contract = RUNTIME_INSTALL_CONTRACTS[runtime];
assert.ok(contract, `missing runtime install contract for ${runtime}`);

View File

@@ -13,7 +13,7 @@
* 5. unknown user file under legacy dir -> baseline-preserve-user (NOT removed)
*/
const { describe, test, before } = require('node:test');
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');

View File

@@ -25,7 +25,6 @@ const {
intelApiSurface,
ensureIntelDir,
isIntelEnabled,
INTEL_FILES,
} = require('../gsd-core/bin/lib/intel.cjs');
// ─── Helpers ────────────────────────────────────────────────────────────────
@@ -49,7 +48,7 @@ function writeIntelJson(planningDir, filename, data) {
);
}
function writeIntelMd(planningDir, filename, content) {
function _writeIntelMd(planningDir, filename, content) {
const intelPath = path.join(planningDir, 'intel');
fs.mkdirSync(intelPath, { recursive: true });
fs.writeFileSync(path.join(intelPath, filename), content, 'utf8');

View File

@@ -9,8 +9,6 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawnSync } = require('child_process');

View File

@@ -19,15 +19,10 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { execFileSync, execSync, spawn } = require('child_process');
const { promisify } = require('util');
const { exec } = require('child_process');
const { spawn } = require('child_process');
const { runGsdTools, createTempProject, cleanup, TOOLS_PATH } = require('./helpers.cjs');
const execAsync = promisify(exec);
// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

View File

@@ -163,9 +163,6 @@ describe('milestone-summary command structure', () => {
});
describe('milestone-summary artifact path resolution', () => {
const { createTempProject, cleanup } = require('./helpers.cjs');
let tmpDir;
test('archived milestone paths point to milestones/ directory', () => {
const content = fs.readFileSync(workflowPath, 'utf-8');
// Archived roadmap path should be under milestones/
@@ -326,7 +323,7 @@ describe('milestone-summary git stats resilience', () => {
// ─────────────────────────────────────────────────────────────────────────────
describe('audit.cjs module (#2158)', () => {
const { createTempProject: createTP, cleanup: cleanTP, runGsdTools: run } = require('./helpers.cjs');
const { createTempProject: createTP, cleanup: cleanTP } = require('./helpers.cjs');
let tmpDir;
beforeEach(() => { tmpDir = createTP('audit-test'); });

View File

@@ -17,7 +17,6 @@ const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const glob = require('path');
const GSD_ROOT = path.join(__dirname, '..', 'gsd-core');
const UI_BRAND = path.join(GSD_ROOT, 'references', 'ui-brand.md');

View File

@@ -7,7 +7,7 @@
* observable behaviour (return values). No mocks, no vacuous truths.
*/
const { describe, test, beforeEach, afterEach } = require('node:test');
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const {

View File

@@ -22,12 +22,10 @@ const os = require('os');
const {
createHub,
ERROR_KINDS,
} = require('../../gsd-core/bin/lib/command-routing-hub.cjs');
const {
createDefaultLogger,
createNoOpLogger,
} = require('../../gsd-core/bin/lib/observability/logger.cjs');
const { cleanup } = require('../helpers.cjs');

View File

@@ -105,7 +105,7 @@ function normalizeTokens(text) {
return text
.toLowerCase()
.replace(/https?:\/\//g, ' ')
.replace(/[\[\]]/g, '')
.replace(/[[\]]/g, '')
.replace(/[^a-z0-9{}:_-]+/g, ' ')
.trim()
.split(/\s+/)

View File

@@ -21,7 +21,6 @@ const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { execSync } = require('node:child_process');
const ROOT = path.join(__dirname, '..');
const LITERAL = '@opengsd/gsd-core';

View File

@@ -104,7 +104,7 @@ describe('phase-command-router — CLI arg translation (CJS path)', () => {
test('routes phase add-batch: --descriptions JSON array parses correctly', () => {
const calls = [];
const phase = makePhase({
cmdPhaseAddBatch: (cwd, descriptions, raw) => calls.push({ descriptions }),
cmdPhaseAddBatch: (cwd, descriptions, _raw) => calls.push({ descriptions }),
});
routePhaseCommand({
@@ -121,7 +121,7 @@ describe('phase-command-router — CLI arg translation (CJS path)', () => {
test('routes phase add-batch: positional args used when --descriptions absent', () => {
const calls = [];
const phase = makePhase({
cmdPhaseAddBatch: (cwd, descriptions, raw) => calls.push({ descriptions }),
cmdPhaseAddBatch: (cwd, descriptions, _raw) => calls.push({ descriptions }),
});
routePhaseCommand({
@@ -162,7 +162,7 @@ describe('phase-command-router — CLI arg translation (CJS path)', () => {
test('routes phase remove: --force flag sets opts.force:true', () => {
const calls = [];
const phase = makePhase({
cmdPhaseRemove: (cwd, phaseNum, opts, raw) => calls.push({ opts }),
cmdPhaseRemove: (cwd, phaseNum, opts, _raw) => calls.push({ opts }),
});
routePhaseCommand({ phase, args: ['phase', 'remove', '--force', '03'], cwd: '/p', raw: false, error: (m) => { throw new Error(m); } });
@@ -402,7 +402,7 @@ describe('phase-command-router — integration: real hub + CJS phase handler', (
test('dispatches phase add-batch through real hub with --descriptions', () => {
const calls = [];
const phase = makePhase({
cmdPhaseAddBatch: (cwd, descriptions, raw) => calls.push({ descriptions }),
cmdPhaseAddBatch: (cwd, descriptions, _raw) => calls.push({ descriptions }),
});
let errorMsg = null;

View File

@@ -20,7 +20,7 @@ const fs = require('fs');
const path = require('path');
const os = require('node:os');
const { execFileSync } = require('node:child_process');
const { runGsdTools, createTempProject, createTempDir, cleanup } = require('./helpers.cjs');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const GSD_TOOLS_BIN = path.resolve(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');

View File

@@ -29,7 +29,6 @@ const path = require('path');
const COMMAND_PATH = path.join(__dirname, '..', 'commands', 'gsd', 'plan-review-convergence.md');
const WORKFLOW_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'plan-review-convergence.md');
const SCHEMA_PATH = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'config-schema.cjs');
const CONFIG_DOC_PATH = path.join(__dirname, '..', 'docs', 'CONFIGURATION.md');
// ─── Command source ────────────────────────────────────────────────────────

View File

@@ -5,7 +5,6 @@ const assert = require('node:assert/strict');
const path = require('path');
const {
POLICY,
VIOLATION,
inspectWorkflow,
runPolicyLint,

View File

@@ -156,7 +156,7 @@ describe('generate-claude-md command', () => {
const outputPath = path.join(tmpDir, 'CLAUDE.md');
fs.writeFileSync(outputPath, '# Custom CLAUDE.md\n\nUser content.\n');
const result = runGsdTools(['generate-claude-md', '--output', outputPath, '--auto', '--raw'], tmpDir);
runGsdTools(['generate-claude-md', '--output', outputPath, '--auto', '--raw'], tmpDir);
// Should merge, not overwrite
const content = fs.readFileSync(outputPath, 'utf-8');
assert.ok(content.length > 0, 'should still have content');

View File

@@ -9,7 +9,6 @@ const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { runGsdTools, createTempDir, createTempProject, cleanup } = require('./helpers.cjs');
// ─── scan-sessions ────────────────────────────────────────────────────────────

View File

@@ -84,7 +84,7 @@ describe('prompt-budget', () => {
requirements: null,
};
const { prompt, metadata } = applyBudget({ sections, budget: 200 });
const { metadata } = applyBudget({ sections, budget: 200 });
// context drops first per spec (priority 6), research second (priority 7)
assert.deepEqual(metadata.omitted, ['context', 'research']);
@@ -183,7 +183,7 @@ describe('prompt-budget', () => {
requirements: bigContent,
};
const { prompt, metadata } = applyBudget({ sections, budget: 200 });
const { metadata } = applyBudget({ sections, budget: 200 });
assert.deepEqual(metadata.omitted, ['context', 'research', 'requirements']);
assert.equal(metadata.noteInjected, true);
@@ -237,7 +237,7 @@ describe('prompt-budget', () => {
requirements: null,
};
const { prompt, metadata } = applyBudget({ sections, budget: 145 });
const { metadata } = applyBudget({ sections, budget: 145 });
// Research must be dropped (it caused the pressure)
assert.ok(metadata.omitted.includes('research'), 'research must be omitted');

Some files were not shown because too many files have changed in this diff Show More