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:
@@ -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);
|
||||
|
||||
@@ -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' };
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
const { execFileSync } = require('child_process');
|
||||
const { existsSync, readdirSync, appendFileSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
|
||||
const RULES = [
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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(', ')}`);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type ProviderKind = 'docs' | 'web' | 'scrape';
|
||||
type ConfidenceLevel = 'HIGH' | 'MEDIUM' | 'LOW';
|
||||
|
||||
interface ProviderWaterfall {
|
||||
|
||||
@@ -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 ─────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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"'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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)}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ─────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -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, [
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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, '..');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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-'));
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -16,7 +16,6 @@ const { cleanup } = require('./helpers.cjs');
|
||||
|
||||
const {
|
||||
executeWorktreeWaveCleanupPlan,
|
||||
planWorktreeWaveCleanup,
|
||||
reapOrphanWorktrees,
|
||||
} = require('../gsd-core/bin/lib/worktree-safety.cjs');
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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--; }
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,7 +25,6 @@ const ROOT = path.join(__dirname, '..');
|
||||
const {
|
||||
convertClaudeCommandToClaudeSkill,
|
||||
writeManifest,
|
||||
install,
|
||||
installRuntimeArtifacts,
|
||||
uninstallRuntimeArtifacts,
|
||||
} = require(path.join(ROOT, 'bin', 'install.js'));
|
||||
|
||||
@@ -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' }.
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -22,9 +22,7 @@ const {
|
||||
resolveModelInternal,
|
||||
escapeRegex,
|
||||
generateSlugInternal,
|
||||
normalizePhaseName,
|
||||
reapStaleTempFiles,
|
||||
comparePhaseNum,
|
||||
pathExistsInternal,
|
||||
getMilestoneInfo,
|
||||
getMilestonePhaseFilter,
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() });
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -16,7 +16,6 @@ const {
|
||||
reconstructFrontmatter,
|
||||
spliceFrontmatter,
|
||||
parseMustHavesBlock,
|
||||
FRONTMATTER_SCHEMAS,
|
||||
} = require('../gsd-core/bin/lib/frontmatter.cjs');
|
||||
|
||||
// ─── extractFrontmatter ─────────────────────────────────────────────────────
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ const {
|
||||
shouldInstallSkill,
|
||||
stageSkillsForMode,
|
||||
cleanupStagedSkills,
|
||||
loadSkillsManifest,
|
||||
resolveProfile,
|
||||
} = require('../gsd-core/bin/lib/install-profiles.cjs');
|
||||
|
||||
const {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -48,7 +48,6 @@ const {
|
||||
|
||||
const {
|
||||
RUNTIME_META,
|
||||
SKILL_RUNTIMES,
|
||||
stripAnsi,
|
||||
walk,
|
||||
} = require('./helpers/install-shared.cjs');
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -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'); });
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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+/)
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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 ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -5,7 +5,6 @@ const assert = require('node:assert/strict');
|
||||
const path = require('path');
|
||||
|
||||
const {
|
||||
POLICY,
|
||||
VIOLATION,
|
||||
inspectWorkflow,
|
||||
runPolicyLint,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 ────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user