From ec2ecdf28b59ec3c7541df9f4f7df10953951a39 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 15 Jun 2026 16:40:48 -0400 Subject: [PATCH] =?UTF-8?q?refactor(#1283):=20T3=20=E2=80=94=20migrate=209?= =?UTF-8?q?=20multi-leaf=20callers=20off=20the=20core=20spine=20(batch=202?= =?UTF-8?q?)=20(#1285)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate 9 files' entire core surface to the leaf modules directly (behaviour-identical — leaves are the objects core re-exports by reference): config, docs, gap-checker, graphify-command-router (namespace core.output -> io.output), init (17 core symbols -> 8 leaves), profile-output, uat, verification, workstream. All 9 now import zero core symbols and are removed from the allowlist (18 -> 9). Stale core.* docstrings corrected. core.cts re-exports untouched (still serve the remaining 9 files); teardown is T-final. No behaviour change. Closes #1283 Co-authored-by: Claude Opus 4.8 --- .../lint-core-spine-imports.allowlist.json | 11 +---- src/config.cts | 7 +++- src/docs.cts | 13 +++++- src/gap-checker.cts | 7 +++- src/graphify-command-router.cts | 14 +++---- src/init.cts | 40 +++++++++++-------- src/profile-output.cts | 7 +++- src/uat.cts | 10 ++++- src/verification.cts | 13 +++--- src/workstream.cts | 10 ++++- 10 files changed, 81 insertions(+), 51 deletions(-) diff --git a/scripts/lint-core-spine-imports.allowlist.json b/scripts/lint-core-spine-imports.allowlist.json index 3f1ffbcb1..b16d4b4e5 100644 --- a/scripts/lint-core-spine-imports.allowlist.json +++ b/scripts/lint-core-spine-imports.allowlist.json @@ -5,19 +5,10 @@ "src/audit-command-router.cts", "src/check-command-router.cts", "src/commands.cts", - "src/config.cts", - "src/docs.cts", - "src/gap-checker.cts", - "src/graphify-command-router.cts", - "src/init.cts", "src/intel-command-router.cts", "src/phase.cts", - "src/profile-output.cts", "src/roadmap.cts", "src/state.cts", - "src/template.cts", - "src/uat.cts", - "src/verification.cts", - "src/workstream.cts" + "src/template.cts" ] } diff --git a/src/config.cts b/src/config.cts index 3bcd20bd2..35a3afed5 100644 --- a/src/config.cts +++ b/src/config.cts @@ -10,8 +10,11 @@ import fs from 'node:fs'; import path from 'node:path'; import os from 'node:os'; // eslint-disable-next-line @typescript-eslint/no-require-imports -import core = require('./core.cjs'); -const { output, error, ERROR_REASON, CONFIG_DEFAULTS } = core; +import io = require('./io.cjs'); +const { output, error, ERROR_REASON } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import configLoader = require('./config-loader.cjs'); +const { CONFIG_DEFAULTS } = configLoader; import { platformWriteSync, platformEnsureDir } from './shell-command-projection.cjs'; // eslint-disable-next-line @typescript-eslint/no-require-imports import planningWorkspace = require('./planning-workspace.cjs'); diff --git a/src/docs.cts b/src/docs.cts index 196e5093e..f8ab16438 100644 --- a/src/docs.cts +++ b/src/docs.cts @@ -13,8 +13,17 @@ 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 { output, loadConfig, resolveModelInternal, pathExistsInternal, toPosixPath } = core; +import io = require('./io.cjs'); +const { output } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import configLoader = require('./config-loader.cjs'); +const { loadConfig } = configLoader; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import modelResolver = require('./model-resolver.cjs'); +const { resolveModelInternal } = modelResolver; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import coreUtils = require('./core-utils.cjs'); +const { pathExistsInternal, toPosixPath } = coreUtils; // eslint-disable-next-line @typescript-eslint/no-require-imports import agentInstallCheck = require('./agent-install-check.cjs'); const { checkAgentsInstalled } = agentInstallCheck; diff --git a/src/gap-checker.cts b/src/gap-checker.cts index f89510a8a..aa1f4839f 100644 --- a/src/gap-checker.cts +++ b/src/gap-checker.cts @@ -19,8 +19,11 @@ 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 { escapeRegex, output, error } = core; +import io = require('./io.cjs'); +const { output, error } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import phaseId = require('./phase-id.cjs'); +const { escapeRegex } = phaseId; // eslint-disable-next-line @typescript-eslint/no-require-imports import planningWorkspace = require('./planning-workspace.cjs'); const { planningPaths, planningDir, findContextMdIn } = planningWorkspace; diff --git a/src/graphify-command-router.cts b/src/graphify-command-router.cts index c736f4f09..0cea739d2 100644 --- a/src/graphify-command-router.cts +++ b/src/graphify-command-router.cts @@ -26,11 +26,9 @@ // eslint-disable-next-line @typescript-eslint/no-require-imports import graphify = require('./graphify.cjs'); // eslint-disable-next-line @typescript-eslint/no-require-imports -import core = require('./core.cjs'); -// eslint-disable-next-line @typescript-eslint/no-require-imports import io = require('./io.cjs'); -const { ERROR_REASON } = io; +const { output, ERROR_REASON } = io; // ─── Types ──────────────────────────────────────────────────────────────────── @@ -73,16 +71,16 @@ function routeGraphifyCommand({ args, cwd, raw, error, _graphify }: RouteGraphif } budget = parseInt(rawBudget, 10); } - core.output(g.graphifyQuery(cwd, term, { budget }), raw); + output(g.graphifyQuery(cwd, term, { budget }), raw); } else if (subcommand === 'status') { - core.output(g.graphifyStatus(cwd), raw); + output(g.graphifyStatus(cwd), raw); } else if (subcommand === 'diff') { - core.output(g.graphifyDiff(cwd), raw); + output(g.graphifyDiff(cwd), raw); } else if (subcommand === 'build') { if (args[2] === 'snapshot') { - core.output(g.writeSnapshot(cwd), raw); + output(g.writeSnapshot(cwd), raw); } else { - core.output(g.graphifyBuild(cwd), raw); + output(g.graphifyBuild(cwd), raw); } } else { error( diff --git a/src/init.cts b/src/init.cts index e70a07e46..5f7626c93 100644 --- a/src/init.cts +++ b/src/init.cts @@ -10,8 +10,22 @@ import fs from 'node:fs'; import path from 'node:path'; import os from 'node:os'; import { execGit, platformWriteSync, platformReadSync } from './shell-command-projection.cjs'; -// eslint-disable-next-line @typescript-eslint/no-require-imports -- core.cjs is an export= CommonJS module -import core = require('./core.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- io.cjs is an export= CommonJS module +import io = require('./io.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- config-loader.cjs is an export= CommonJS module +import configLoader = require('./config-loader.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- model-resolver.cjs is an export= CommonJS module +import modelResolver = require('./model-resolver.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-locator.cjs is an export= CommonJS module +import phaseLocator = require('./phase-locator.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- roadmap-parser.cjs is an export= CommonJS module +import roadmapParser = require('./roadmap-parser.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- core-utils.cjs is an export= CommonJS module +import coreUtils = require('./core-utils.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module +import phaseId = require('./phase-id.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- worktree-safety.cjs is an export= CommonJS module +import worktreeSafety = require('./worktree-safety.cjs'); // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module import planningWorkspace = require('./planning-workspace.cjs'); import { maskIfSecret } from './secrets.cjs'; @@ -32,25 +46,20 @@ const { checkAgentsInstalled } = agentInstallCheck; import gitBaseBranch = require('./git-base-branch.cjs'); const { gitWorktreeInfoInternal } = gitBaseBranch; +const { output, error } = io; +const { loadConfig } = configLoader; +const { resolveModelInternal, resolveGranularityInternal, assertValidGranularityOverride } = modelResolver; +const { findPhaseInternal } = phaseLocator; const { - loadConfig, - resolveModelInternal, - resolveGranularityInternal, - assertValidGranularityOverride, - findPhaseInternal, getRoadmapPhaseInternal, - pathExistsInternal, - generateSlugInternal, getMilestoneInfo, getMilestonePhaseFilter, stripShippedMilestones, extractCurrentMilestone, - normalizePhaseName, - toPosixPath, - output, - error, - phaseTokenMatches, -} = core; +} = roadmapParser; +const { pathExistsInternal, generateSlugInternal, toPosixPath } = coreUtils; +const { normalizePhaseName, phaseTokenMatches } = phaseId; +const { pruneOrphanedWorktrees } = worktreeSafety; const { planningPaths, @@ -1517,7 +1526,6 @@ function cmdInitManager(cwd: string, raw: boolean): void { function cmdInitProgress(cwd: string, raw: boolean): void { try { - const { pruneOrphanedWorktrees } = core; (pruneOrphanedWorktrees as (cwd: string) => void)(cwd); } catch { /* intentionally empty */ diff --git a/src/profile-output.cts b/src/profile-output.cts index 4ddcf22ec..f51533eac 100644 --- a/src/profile-output.cts +++ b/src/profile-output.cts @@ -17,8 +17,11 @@ import fs from 'node:fs'; import path from 'node:path'; import os from 'node:os'; // eslint-disable-next-line @typescript-eslint/no-require-imports -import core = require('./core.cjs'); -const { output, error, loadConfig } = core; +import io = require('./io.cjs'); +const { output, error } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import configLoader = require('./config-loader.cjs'); +const { loadConfig } = configLoader; import { platformReadSync as safeReadFile, platformWriteSync, platformEnsureDir } from './shell-command-projection.cjs'; import { getGlobalSkillDir, getGlobalConfigDir } from './runtime-homes.cjs'; import { formatGsdSlash, resolveRuntime } from './runtime-slash.cjs'; diff --git a/src/uat.cts b/src/uat.cts index 654ef057f..918948aa8 100644 --- a/src/uat.cts +++ b/src/uat.cts @@ -12,8 +12,14 @@ 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 { output, error, getMilestonePhaseFilter, toPosixPath } = core; +import io = require('./io.cjs'); +const { output, error } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import roadmapParser = require('./roadmap-parser.cjs'); +const { getMilestonePhaseFilter } = roadmapParser; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import coreUtils = require('./core-utils.cjs'); +const { toPosixPath } = coreUtils; // eslint-disable-next-line @typescript-eslint/no-require-imports import planningWorkspace = require('./planning-workspace.cjs'); const { planningDir } = planningWorkspace; diff --git a/src/verification.cts b/src/verification.cts index 5a8e782c2..5d6ff36dc 100644 --- a/src/verification.cts +++ b/src/verification.cts @@ -18,12 +18,15 @@ import fs from 'node:fs'; import path from 'node:path'; -// eslint-disable-next-line @typescript-eslint/no-require-imports -- core.cjs is an export= CommonJS module -import core = require('./core.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- io.cjs is an export= CommonJS module +import io = require('./io.cjs'); +// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module +import phaseId = require('./phase-id.cjs'); // eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module import frontmatterMod = require('./frontmatter.cjs'); -const { output, extractPhaseToken } = core; +const { output, error } = io; +const { extractPhaseToken } = phaseId; const { extractFrontmatter } = frontmatterMod; // ─── Constants ──────────────────────────────────────────────────────────────── @@ -210,7 +213,7 @@ function readVerificationStatus( /** * CLI command handler: resolve phaseDir against cwd, call readVerificationStatus, - * emit via core.output(). + * emit via io.output(). * * @param cwd - Current working directory (used to resolve phaseDirArg). * @param phaseDirArg - Phase directory path (absolute or relative to cwd). @@ -218,7 +221,7 @@ function readVerificationStatus( */ function cmdVerificationStatus(cwd: string, phaseDirArg: string | undefined, raw: boolean): void { if (!phaseDirArg) { - core.error('phase directory required for verification.status'); + error('phase directory required for verification.status'); return; } const phaseDir = path.resolve(cwd, phaseDirArg); diff --git a/src/workstream.cts b/src/workstream.cts index c700af816..8e9bd5be4 100644 --- a/src/workstream.cts +++ b/src/workstream.cts @@ -15,8 +15,14 @@ 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 { output, error, toPosixPath, getMilestoneInfo, generateSlugInternal } = core; +import io = require('./io.cjs'); +const { output, error } = io; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import coreUtils = require('./core-utils.cjs'); +const { toPosixPath, generateSlugInternal } = coreUtils; +// eslint-disable-next-line @typescript-eslint/no-require-imports +import roadmapParser = require('./roadmap-parser.cjs'); +const { getMilestoneInfo } = roadmapParser; import { platformWriteSync, platformEnsureDir } from './shell-command-projection.cjs'; // eslint-disable-next-line @typescript-eslint/no-require-imports import planningWorkspace = require('./planning-workspace.cjs');