* refactor(#1294): T-final — delete the core.cjs re-export spine (epic #1267 complete) After T0–T6 nothing imports core, so retire the spine and its scaffolding: - delete src/core.cts (and the gitignored gsd-core/bin/lib/core.cjs artifact; remove its .gitignore + eslint-ignore entries) - delete scripts/lint-core-spine-imports.cjs + its allowlist; drop it from the package.json lint:ci chain - regenerate docs/INVENTORY-MANIFEST.json (drops the core.cjs surface) - sweep stale references: CONTEXT.md glossary back-compat clauses (spine retired, callers import the leaf directly), planning-config.md CONFIG_DEFAULTS owner, and false present-tense core.cjs claims in leaf-module docstrings The ADR-857 decomposition is complete: the former Core god-module is fully dissolved into its leaf modules; no re-export spine remains. No behaviour change. Closes #1294 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#1294): migrate the computed-path core.cjs importers the literal grep missed bin/install.js used require(path.join(_gsdLibDir, 'core.cjs')) (a computed path, and bin/install.js was never in the convergence lint's scan roots), and ~8 test files referenced core.cjs via path.join/readFileSync/existsSync/FILE_ARG forms the literal-string migration grep missed. Route install.js's symbols to their leaves (RUNTIME_PROFILE_MAP->model-catalog, resolveTierEntry/EFFORT_SET-> model-resolver) and repoint/adjust the test references to the leaves. Recovers the 161 'Cannot find module core.cjs' failures from the spine deletion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -138,7 +138,6 @@ build/
|
|||||||
/gsd-core/bin/lib/runtime-config-adapter-registry.cjs
|
/gsd-core/bin/lib/runtime-config-adapter-registry.cjs
|
||||||
/gsd-core/bin/lib/runtime-hooks-surface.cjs
|
/gsd-core/bin/lib/runtime-hooks-surface.cjs
|
||||||
/gsd-core/bin/lib/command-routing-hub.cjs
|
/gsd-core/bin/lib/command-routing-hub.cjs
|
||||||
/gsd-core/bin/lib/core.cjs
|
|
||||||
/gsd-core/bin/lib/core-utils.cjs
|
/gsd-core/bin/lib/core-utils.cjs
|
||||||
/gsd-core/bin/lib/io.cjs
|
/gsd-core/bin/lib/io.cjs
|
||||||
/gsd-core/bin/lib/phase-id.cjs
|
/gsd-core/bin/lib/phase-id.cjs
|
||||||
|
|||||||
28
CONTEXT.md
28
CONTEXT.md
@@ -15,13 +15,13 @@ Module owning `milestone complete` (archive roadmap/requirements/phases, build M
|
|||||||
Module that composes Dispatch Policy Module, Query Execution Policy Module, and per-stage handlers (input-validation, plan, execution, result-builder, formatting, error-mapping, observability) into the end-to-end pipeline that produces a `QueryDispatchResult`. The SDK-era pipeline collapsed onto the Command Routing Hub per ADR-0174; current dispatch seam: `gsd-core/bin/lib/command-routing-hub.cjs` (see Command Routing Hub below).
|
Module that composes Dispatch Policy Module, Query Execution Policy Module, and per-stage handlers (input-validation, plan, execution, result-builder, formatting, error-mapping, observability) into the end-to-end pipeline that produces a `QueryDispatchResult`. The SDK-era pipeline collapsed onto the Command Routing Hub per ADR-0174; current dispatch seam: `gsd-core/bin/lib/command-routing-hub.cjs` (see Command Routing Hub below).
|
||||||
|
|
||||||
### Phase Id Module
|
### Phase Id Module
|
||||||
Module owning the pure phase-id parsing and matching helpers: phase-name normalization, phase-token extraction/matching, milestone- and phase-dir id parsing, and phase-markdown regex builders (`escapeRegex`, `normalizePhaseName`, `comparePhaseNum`, `extractPhaseToken`, `phaseTokenMatches`, `phaseMarkdownRegexSource`/`phaseMarkdownRegexSourceExact`, `getMilestoneFromPhaseId`, `getPhaseDirFromPhaseId`). Pure string/regex — no I/O, no config, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2a (#865) as the cycle-free leaf that unblocks the roadmap-parser and phase-locator extractions; `core.cjs` re-exports the helpers for back-compat. Source of truth: `gsd-core/bin/lib/phase-id.cjs` (generated from `src/phase-id.cts`).
|
Module owning the pure phase-id parsing and matching helpers: phase-name normalization, phase-token extraction/matching, milestone- and phase-dir id parsing, and phase-markdown regex builders (`escapeRegex`, `normalizePhaseName`, `comparePhaseNum`, `extractPhaseToken`, `phaseTokenMatches`, `phaseMarkdownRegexSource`/`phaseMarkdownRegexSourceExact`, `getMilestoneFromPhaseId`, `getPhaseDirFromPhaseId`). Pure string/regex — no I/O, no config, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2a (#865) as the cycle-free leaf that unblocks the roadmap-parser and phase-locator extractions; the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/phase-id.cjs` (generated from `src/phase-id.cts`).
|
||||||
|
|
||||||
### Phase Lifecycle Module
|
### Phase Lifecycle Module
|
||||||
Module owning phase create, rename, complete, remove, list, and plan-index operations, plus phase-dir prefix validation, STATE.md staleness detection, and auto-prune behaviour. Entry point: `gsd-core/bin/lib/phase.cjs` (CJS surface). Typed phase events: `GSDPhaseStartEvent`, `GSDPhaseStepStartEvent`, `GSDPhaseStepCompleteEvent`, `GSDPhaseCompleteEvent`. (The SDK native-query surface, the `types.ts` event definitions, `phase-runner.ts`, and `phase-prompt.ts` were retired with the SDK package per ADR-0174.)
|
Module owning phase create, rename, complete, remove, list, and plan-index operations, plus phase-dir prefix validation, STATE.md staleness detection, and auto-prune behaviour. Entry point: `gsd-core/bin/lib/phase.cjs` (CJS surface). Typed phase events: `GSDPhaseStartEvent`, `GSDPhaseStepStartEvent`, `GSDPhaseStepCompleteEvent`, `GSDPhaseCompleteEvent`. (The SDK native-query surface, the `types.ts` event definitions, `phase-runner.ts`, and `phase-prompt.ts` were retired with the SDK package per ADR-0174.)
|
||||||
|
|
||||||
### Phase Locator Module
|
### Phase Locator Module
|
||||||
Module owning phase-directory search and location: active-phase discovery against the `.planning/phases/` tree (`searchPhaseInDir`, `findPhaseInternal`) and archived-phase-dir enumeration (`getArchivedPhaseDirs`), matching phase ids/tokens against the filesystem. Depends only on leaf modules (`phase-id` for token/name matching, `core-utils` for fs-scan/path helpers, `planning-workspace` for `planningDir`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2d (#881); `core.cjs` re-exports `searchPhaseInDir`, `findPhaseInternal`, and `getArchivedPhaseDirs` for back-compat. Source of truth: `gsd-core/bin/lib/phase-locator.cjs` (generated from `src/phase-locator.cts`).
|
Module owning phase-directory search and location: active-phase discovery against the `.planning/phases/` tree (`searchPhaseInDir`, `findPhaseInternal`) and archived-phase-dir enumeration (`getArchivedPhaseDirs`), matching phase ids/tokens against the filesystem. Depends only on leaf modules (`phase-id` for token/name matching, `core-utils` for fs-scan/path helpers, `planning-workspace` for `planningDir`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2d (#881); the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/phase-locator.cjs` (generated from `src/phase-locator.cts`).
|
||||||
|
|
||||||
### Dispatch Policy Module
|
### Dispatch Policy Module
|
||||||
Module owning dispatch error mapping, fallback policy, timeout classification, and CLI exit mapping contract.
|
Module owning dispatch error mapping, fallback policy, timeout classification, and CLI exit mapping contract.
|
||||||
@@ -89,13 +89,13 @@ Module owning `.planning` path resolution, active workstream pointer policy (`se
|
|||||||
Module owning workstream directory discovery, per-workstream state projection, phase/plan/summary counting, roadmap-declared phase count, active marker projection, and active-workstream collision inputs. Command handlers render list/status/progress outputs from this inventory instead of rescanning `.planning/workstreams/*` directly. Source of truth for the pure projection is `gsd-core/bin/lib/workstream-inventory-builder.cjs` (a Builder Module); the Reader Adapter `gsd-core/bin/lib/workstream-inventory.cjs` collects filesystem inputs and delegates projection to the Builder.
|
Module owning workstream directory discovery, per-workstream state projection, phase/plan/summary counting, roadmap-declared phase count, active marker projection, and active-workstream collision inputs. Command handlers render list/status/progress outputs from this inventory instead of rescanning `.planning/workstreams/*` directly. Source of truth for the pure projection is `gsd-core/bin/lib/workstream-inventory-builder.cjs` (a Builder Module); the Reader Adapter `gsd-core/bin/lib/workstream-inventory.cjs` collects filesystem inputs and delegates projection to the Builder.
|
||||||
|
|
||||||
### Project-Root Resolution Module
|
### Project-Root Resolution Module
|
||||||
Module owning project-root resolution from any starting directory. Walks the ancestor chain (bounded by `FIND_PROJECT_ROOT_MAX_DEPTH = 10`) applying four heuristics in order: (0) own `.planning/` guard (#1362), (1) parent `.planning/config.json` `sub_repos` traversal, (2) legacy `multiRepo: true` boolean + ancestor `.git`, (3) `.git` heuristic with parent `.planning/`. Returns `startDir` when no ancestor qualifies. Sync `node:fs` I/O. Source of truth: `gsd-core/bin/lib/project-root.cjs`; consumed via a thin re-export at `gsd-core/bin/lib/core.cjs`.
|
Module owning project-root resolution from any starting directory. Walks the ancestor chain (bounded by `FIND_PROJECT_ROOT_MAX_DEPTH = 10`) applying four heuristics in order: (0) own `.planning/` guard (#1362), (1) parent `.planning/config.json` `sub_repos` traversal, (2) legacy `multiRepo: true` boolean + ancestor `.git`, (3) `.git` heuristic with parent `.planning/`. Returns `startDir` when no ancestor qualifies. Sync `node:fs` I/O. Source of truth: `gsd-core/bin/lib/project-root.cjs`; the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly.
|
||||||
|
|
||||||
### Planning Path Projection Module
|
### Planning Path Projection Module
|
||||||
Module owning projection from project/workstream context to concrete `.planning` paths. Policy precedence is `explicit workstream > env workstream > env project > root`. Invalid workspace context is a validation error at this seam rather than a silent fallback.
|
Module owning projection from project/workstream context to concrete `.planning` paths. Policy precedence is `explicit workstream > env workstream > env project > root`. Invalid workspace context is a validation error at this seam rather than a silent fallback.
|
||||||
|
|
||||||
### Worktree Safety Policy Module
|
### Worktree Safety Policy Module
|
||||||
CJS Module owning worktree lifecycle safety policy for the GSD orchestration layer. Interface: `resolveWorktreeContext(cwd, deps) → WorktreeContext` (linked-worktree root mapping), `parseWorktreePorcelain(output) → WorktreeEntry[]` (porcelain parser, skips detached HEAD), `planWorktreePrune(repoRoot, opts, deps) → PrunePlan` (metadata-prune plan, never destructive by default), `executeWorktreePrunePlan(plan, deps) → PruneResult` (executes prune; degrades gracefully on git timeout), `listLinkedWorktreePaths(repoRoot, deps) → LinkedPathsResult`, `inspectWorktreeHealth(repoRoot, opts, deps) → HealthResult` (orphan + stale detection), `snapshotWorktreeInventory(repoRoot, opts, deps) → InventoryResult`, `planWorktreeWaveCleanup(repoRoot, manifest) → CleanupPlan` (manifest-scoped, fail-closed), `executeWorktreeWaveCleanupPlan(plan, deps) → CleanupResult`. Source of truth: `gsd-core/bin/lib/worktree-safety.cjs`. Timeout path: all git subprocess calls are bounded; callers receive `ok:false, reason:'git_timed_out'` rather than a thrown exception. Test anchor: `tests/worktree-safety.test.cjs`. Planned (retiring the `core.cjs` spine, ADR-857): absorbs the two thin compositional wrappers that squatted in Core — `resolveWorktreeRoot(cwd, deps)` (a projection over `resolveWorktreeContext`) and `pruneOrphanedWorktrees(...)` (sequences `planWorktreePrune` + `executeWorktreePrunePlan` with a timeout warning) — so callers reach this single worktree-lifecycle seam directly instead of through Core. `gitWorktreeInfoInternal` does NOT move here — worktree-info detection belongs to the Git Query Module.
|
CJS Module owning worktree lifecycle safety policy for the GSD orchestration layer. Interface: `resolveWorktreeContext(cwd, deps) → WorktreeContext` (linked-worktree root mapping), `parseWorktreePorcelain(output) → WorktreeEntry[]` (porcelain parser, skips detached HEAD), `planWorktreePrune(repoRoot, opts, deps) → PrunePlan` (metadata-prune plan, never destructive by default), `executeWorktreePrunePlan(plan, deps) → PruneResult` (executes prune; degrades gracefully on git timeout), `listLinkedWorktreePaths(repoRoot, deps) → LinkedPathsResult`, `inspectWorktreeHealth(repoRoot, opts, deps) → HealthResult` (orphan + stale detection), `snapshotWorktreeInventory(repoRoot, opts, deps) → InventoryResult`, `planWorktreeWaveCleanup(repoRoot, manifest) → CleanupPlan` (manifest-scoped, fail-closed), `executeWorktreeWaveCleanupPlan(plan, deps) → CleanupResult`. Source of truth: `gsd-core/bin/lib/worktree-safety.cjs`. Timeout path: all git subprocess calls are bounded; callers receive `ok:false, reason:'git_timed_out'` rather than a thrown exception. Test anchor: `tests/worktree-safety.test.cjs`. The `core.cjs` re-export spine was retired in epic #1267: this module absorbed the two thin compositional wrappers that squatted in Core — `resolveWorktreeRoot(cwd, deps)` (a projection over `resolveWorktreeContext`) and `pruneOrphanedWorktrees(...)` (sequences `planWorktreePrune` + `executeWorktreePrunePlan` with a timeout warning) — so callers reach this single worktree-lifecycle seam directly. `gitWorktreeInfoInternal` did NOT move here — worktree-info detection belongs to the Git Query Module.
|
||||||
|
|
||||||
### Worktree Lifecycle Module
|
### Worktree Lifecycle Module
|
||||||
Workflow contract seam covering agent worktree lifecycle orchestration rules. The `worktree_branch_check` block lives in one canonical fragment (`gsd-core/references/worktree-branch-check.md`) that `execute-phase.md`, `quick.md`, `diagnose-issues.md`, and `execute-plan.md` embed at dispatch. Key invariants: `worktree_branch_check` is **verify-only and fail-closed** — the orchestrator owns worktree lifecycle and base recovery, so the sub-agent holds no state-correction primitives; HEAD attachment verified via `git symbolic-ref`; positive allow-list `^worktree-agent-*` enforced; `git update-ref` on protected refs is prohibited; on base mismatch the sub-agent halts with `exit 42` and surfaces to the orchestrator (#48); the orchestrator runs a cwd-drift guard at `execute_waves` entry that resolves the worktree root and refuses drift into an agent worktree (#48); cleanup is manifest-scoped (`WAVE_WORKTREE_MANIFEST`) not global-discovery-based; worktree spawning is sequential (one `run_in_background` at a time to avoid `config.lock` contention). Test anchor: `tests/worktree.test.cjs`.
|
Workflow contract seam covering agent worktree lifecycle orchestration rules. The `worktree_branch_check` block lives in one canonical fragment (`gsd-core/references/worktree-branch-check.md`) that `execute-phase.md`, `quick.md`, `diagnose-issues.md`, and `execute-plan.md` embed at dispatch. Key invariants: `worktree_branch_check` is **verify-only and fail-closed** — the orchestrator owns worktree lifecycle and base recovery, so the sub-agent holds no state-correction primitives; HEAD attachment verified via `git symbolic-ref`; positive allow-list `^worktree-agent-*` enforced; `git update-ref` on protected refs is prohibited; on base mismatch the sub-agent halts with `exit 42` and surfaces to the orchestrator (#48); the orchestrator runs a cwd-drift guard at `execute_waves` entry that resolves the worktree root and refuses drift into an agent worktree (#48); cleanup is manifest-scoped (`WAVE_WORKTREE_MANIFEST`) not global-discovery-based; worktree spawning is sequential (one `run_in_background` at a time to avoid `config.lock` contention). Test anchor: `tests/worktree.test.cjs`.
|
||||||
@@ -116,22 +116,22 @@ Module owning validation for Installer Migration Module records and planned acti
|
|||||||
Primary installer for all runtimes. Single production file: `bin/install.js` (generated). Exports: `install(isGlobal, runtime[, configDir])` → typed result `{ runtime, configDir, settingsPath, settings, statuslineCommand, updateBannerCommand }`; `uninstall(isGlobal, runtime[, configDir])`; `installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile)`; `uninstallRuntimeArtifacts(runtime, configDir, scope)`; `writeManifest(configDir, runtime)`. Runtime enum: `allRuntimes` (15 values: claude, antigravity, augment, cline, codebuddy, codex, copilot, cursor, gemini, hermes, kilo, opencode, qwen, trae, windsurf). Directory helpers: `getDirName(runtime)` → local dir name; `getConfigDirFromHome(runtime, isGlobal)` → shell-quoted path fragment. Per-runtime global config-dir resolution is delegated to `gsd-core/bin/lib/runtime-homes.cjs:getGlobalConfigDir(runtime[, explicitDir])` — the canonical, env-var–aware projection (`explicitDir` override + opencode/kilo `*_CONFIG` file-path precedence); the legacy in-installer `getGlobalDir`/`getOpencodeGlobalDir`/`getKiloGlobalDir` were retired into it (#56). Runtime-specific helpers: `resolveKiloConfigPath(configDir)`, `configureKiloPermissions(isGlobal[, explicitDir])`. Claude-specific permission helpers: `mergeClaudePermissions(settings)` — non-destructively appends GSD-owned allow/deny entries (see `GSD_CLAUDE_ALLOW_PERMISSIONS`, `GSD_CLAUDE_DENY_PERMISSIONS` constants) to a Claude Code settings object; called from `finishInstall` for `runtime === 'claude'` only; uninstall removes exactly these entries (#768). Layout-driven artifact copy/removal delegates to `gsd-core/bin/lib/runtime-artifact-layout.cjs:resolveRuntimeArtifactLayout` (throws `TypeError` for unknown runtimes). Seven runtimes with non-recursive skill loaders (claude global, cline, qwen, hermes, augment, trae, antigravity) use a nested router layout: 6 `gsd-ns-*` router bundles emitted as top-level skills, with concrete skills nested at `<router>/skills/<name>/SKILL.md` (hermes prefix='': `skills/gsd/ns-*/…`). The remaining skills-runtimes (cursor, codex, copilot, windsurf, codebuddy, opencode, kilo) use the flat `skills/gsd-<stem>/` layout unchanged. See Skill Surface Budget Module and Runtime Artifact Layout Module.
|
Primary installer for all runtimes. Single production file: `bin/install.js` (generated). Exports: `install(isGlobal, runtime[, configDir])` → typed result `{ runtime, configDir, settingsPath, settings, statuslineCommand, updateBannerCommand }`; `uninstall(isGlobal, runtime[, configDir])`; `installRuntimeArtifacts(runtime, configDir, scope, resolvedProfile)`; `uninstallRuntimeArtifacts(runtime, configDir, scope)`; `writeManifest(configDir, runtime)`. Runtime enum: `allRuntimes` (15 values: claude, antigravity, augment, cline, codebuddy, codex, copilot, cursor, gemini, hermes, kilo, opencode, qwen, trae, windsurf). Directory helpers: `getDirName(runtime)` → local dir name; `getConfigDirFromHome(runtime, isGlobal)` → shell-quoted path fragment. Per-runtime global config-dir resolution is delegated to `gsd-core/bin/lib/runtime-homes.cjs:getGlobalConfigDir(runtime[, explicitDir])` — the canonical, env-var–aware projection (`explicitDir` override + opencode/kilo `*_CONFIG` file-path precedence); the legacy in-installer `getGlobalDir`/`getOpencodeGlobalDir`/`getKiloGlobalDir` were retired into it (#56). Runtime-specific helpers: `resolveKiloConfigPath(configDir)`, `configureKiloPermissions(isGlobal[, explicitDir])`. Claude-specific permission helpers: `mergeClaudePermissions(settings)` — non-destructively appends GSD-owned allow/deny entries (see `GSD_CLAUDE_ALLOW_PERMISSIONS`, `GSD_CLAUDE_DENY_PERMISSIONS` constants) to a Claude Code settings object; called from `finishInstall` for `runtime === 'claude'` only; uninstall removes exactly these entries (#768). Layout-driven artifact copy/removal delegates to `gsd-core/bin/lib/runtime-artifact-layout.cjs:resolveRuntimeArtifactLayout` (throws `TypeError` for unknown runtimes). Seven runtimes with non-recursive skill loaders (claude global, cline, qwen, hermes, augment, trae, antigravity) use a nested router layout: 6 `gsd-ns-*` router bundles emitted as top-level skills, with concrete skills nested at `<router>/skills/<name>/SKILL.md` (hermes prefix='': `skills/gsd/ns-*/…`). The remaining skills-runtimes (cursor, codex, copilot, windsurf, codebuddy, opencode, kilo) use the flat `skills/gsd-<stem>/` layout unchanged. See Skill Surface Budget Module and Runtime Artifact Layout Module.
|
||||||
|
|
||||||
### I/O Module
|
### I/O Module
|
||||||
Module owning the tool's CLI I/O primitives: `output()` result emission (with large-payload temp-file spillover via `GSD_TEMP_DIR`/`ensureGsdTempDir`/`reapStaleTempFiles`), `error()` stderr emission with exit-code mapping, and the JSON-error-mode toggle (`setJsonErrorMode`/`getJsonErrorMode`, `ERROR_REASON`). Extracted from the Core module per ADR-857 rollout phase 1 (#859) so feature modules (`graphify`, `intel`, `audit`, `profile-pipeline`) depend on a small I/O seam instead of the core god-module; `core.cjs` re-exports the primitives for back-compat. Source of truth: `gsd-core/bin/lib/io.cjs` (generated from `src/io.cts`).
|
Module owning the tool's CLI I/O primitives: `output()` result emission (with large-payload temp-file spillover via `GSD_TEMP_DIR`/`ensureGsdTempDir`/`reapStaleTempFiles`), `error()` stderr emission with exit-code mapping, and the JSON-error-mode toggle (`setJsonErrorMode`/`getJsonErrorMode`, `ERROR_REASON`). Extracted from the Core module per ADR-857 rollout phase 1 (#859) so feature modules (`graphify`, `intel`, `audit`, `profile-pipeline`) depend on a small I/O seam instead of the core god-module; the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/io.cjs` (generated from `src/io.cts`).
|
||||||
|
|
||||||
### Roadmap Parser Module
|
### Roadmap Parser Module
|
||||||
Module owning ROADMAP.md parsing: shipped-milestone slicing, current-milestone extraction, milestone/phase lookups, and milestone-phase filtering (`stripShippedMilestones`, `extractCurrentMilestone`, `replaceInCurrentMilestone`, `getRoadmapPhaseInternal`, `getMilestoneInfo`, `getMilestonePhaseFilter`). Depends only on leaf modules (`phase-id`, `planning-workspace`, `shell-command-projection`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2b (#870), resolving the ROADMAP.md parse/write straddle so the Roadmap module (`roadmap.cjs`, which owns ROADMAP.md mutation) imports parsing directly instead of through Core; `core.cjs` re-exports the helpers for back-compat. Source of truth: `gsd-core/bin/lib/roadmap-parser.cjs` (generated from `src/roadmap-parser.cts`).
|
Module owning ROADMAP.md parsing: shipped-milestone slicing, current-milestone extraction, milestone/phase lookups, and milestone-phase filtering (`stripShippedMilestones`, `extractCurrentMilestone`, `replaceInCurrentMilestone`, `getRoadmapPhaseInternal`, `getMilestoneInfo`, `getMilestonePhaseFilter`). Depends only on leaf modules (`phase-id`, `planning-workspace`, `shell-command-projection`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2b (#870), resolving the ROADMAP.md parse/write straddle so the Roadmap module (`roadmap.cjs`, which owns ROADMAP.md mutation) imports parsing directly instead of through Core; the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/roadmap-parser.cjs` (generated from `src/roadmap-parser.cts`).
|
||||||
|
|
||||||
### Core Utilities Module
|
### Core Utilities Module
|
||||||
Module owning the shared low-level utility primitives extracted from Core: POSIX path normalization (`toPosixPath`), filesystem scanning (`detectSubRepos`, `readSubdirectories`, `getPhaseFileStats`, `pathExistsInternal`), and small pure helpers (`generateSlugInternal`, `extractOneLinerFromBody`, `filterPlanFiles`, `filterSummaryFiles`, `extractCanonicalPlanId`, `timeAgo`). Depends only on Node built-ins and already-leafed modules (`phase-id` for `comparePhaseNum`, `planning-workspace` for `findContextMdIn`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2c (#877) as the shared leaf that unblocks the phase-locator fs-search extraction (2d); `core.cjs` re-exports the public helpers for back-compat. Source of truth: `gsd-core/bin/lib/core-utils.cjs` (generated from `src/core-utils.cts`).
|
Module owning the shared low-level utility primitives extracted from Core: POSIX path normalization (`toPosixPath`), filesystem scanning (`detectSubRepos`, `readSubdirectories`, `getPhaseFileStats`, `pathExistsInternal`), and small pure helpers (`generateSlugInternal`, `extractOneLinerFromBody`, `filterPlanFiles`, `filterSummaryFiles`, `extractCanonicalPlanId`, `timeAgo`). Depends only on Node built-ins and already-leafed modules (`phase-id` for `comparePhaseNum`, `planning-workspace` for `findContextMdIn`) — no `loadConfig`, no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2c (#877) as the shared leaf that unblocks the phase-locator fs-search extraction (2d); the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/core-utils.cjs` (generated from `src/core-utils.cts`).
|
||||||
|
|
||||||
### Agent Install Check Module [Planned]
|
### Agent Install Check Module
|
||||||
Module owning agent-presence resolution and verification, extracted from the Core module as the cleanup step that retires the `core.cjs` re-export spine (the final ADR-857 decomposition). Interface: `getAgentsDir(runtime?, env?)` — env-var-aware, runtime-aware agents-directory resolution (the `claude` runtime resolves `__dirname`-relative); `checkAgentsInstalled(...)` — multi-runtime agent-presence check that validates `gsd-file-manifest.json` completeness and confirms the declared agents exist on disk. Pure read/verify — no install-write side effects (writes remain the Installer Module's). Consumed by the Init Command Module, the verify workflow, and the docs workflow. Source of truth: `gsd-core/bin/lib/agent-install-check.cjs` (generated from `src/agent-install-check.cts`); replaces the two functions that squatted in `core.cts`. See Installer Module and ADR-857.
|
Module owning agent-presence resolution and verification, extracted from the Core module as the cleanup step that retired the `core.cjs` re-export spine (the final ADR-857 decomposition, epic #1267). Interface: `getAgentsDir(runtime?, env?)` — env-var-aware, runtime-aware agents-directory resolution (the `claude` runtime resolves `__dirname`-relative); `checkAgentsInstalled(...)` — multi-runtime agent-presence check that validates `gsd-file-manifest.json` completeness and confirms the declared agents exist on disk. Pure read/verify — no install-write side effects (writes remain the Installer Module's). Consumed by the Init Command Module, the verify workflow, and the docs workflow. Source of truth: `gsd-core/bin/lib/agent-install-check.cjs` (generated from `src/agent-install-check.cts`); replaced the two functions that squatted in `core.cts`. See Installer Module and ADR-857.
|
||||||
|
|
||||||
### Config Loader Module
|
### Config Loader Module
|
||||||
Module owning project configuration loading: reads `.planning/config.json`, merges built-in defaults (`CONFIG_DEFAULTS`/`CANONICAL_CONFIG_DEFAULTS`), normalizes legacy keys, applies the active-workstream overlay, validates against the config schema, and warns on unknown keys/profile overrides (`loadConfig` plus its `_deepMergeConfig`/`isGitIgnored`/`_warnUnknownProfileOverrides` helpers). Depends only on leaf modules (`configuration`, `config-schema`, `planning-workspace`, `shell-command-projection`, `core-utils`, `model-catalog`) — no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2e (#885) as the prerequisite for the model-resolver extraction (the resolvers call `loadConfig`); `core.cjs` re-exports `loadConfig` for back-compat. Source of truth: `gsd-core/bin/lib/config-loader.cjs` (generated from `src/config-loader.cts`).
|
Module owning project configuration loading: reads `.planning/config.json`, merges built-in defaults (`CONFIG_DEFAULTS`/`CANONICAL_CONFIG_DEFAULTS`), normalizes legacy keys, applies the active-workstream overlay, validates against the config schema, and warns on unknown keys/profile overrides (`loadConfig` plus its `_deepMergeConfig`/`isGitIgnored`/`_warnUnknownProfileOverrides` helpers). Depends only on leaf modules (`configuration`, `config-schema`, `planning-workspace`, `shell-command-projection`, `core-utils`, `model-catalog`) — no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2e (#885) as the prerequisite for the model-resolver extraction (the resolvers call `loadConfig`); the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/config-loader.cjs` (generated from `src/config-loader.cts`).
|
||||||
|
|
||||||
### Model Resolver Module
|
### Model Resolver Module
|
||||||
Module owning model and effort resolution policy: resolves the model, runtime tier, planning granularity, reasoning effort, and fast-mode for a given agent by reading project config and resolving against the model profiles and catalog (`resolveModelInternal`, `resolveModelPolicy`, `resolveTierEntry`, `resolveModelForTier`, `resolveGranularityInternal`, `resolveEffortInternal`, `resolveFastModeInternal`, `resolveEffortForTier`, `nextEffort`, `assertValidGranularityOverride`). Depends only on leaf modules (`config-loader` for `loadConfig`, `configuration` for defaults, `model-profiles` and `model-catalog` for the static tables) — no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2f (#888) — the final core.cts decomposition step, leaving Core a thin re-export spine; `core.cjs` re-exports the resolvers for back-compat. Source of truth: `gsd-core/bin/lib/model-resolver.cjs` (generated from `src/model-resolver.cts`).
|
Module owning model and effort resolution policy: resolves the model, runtime tier, planning granularity, reasoning effort, and fast-mode for a given agent by reading project config and resolving against the model profiles and catalog (`resolveModelInternal`, `resolveModelPolicy`, `resolveTierEntry`, `resolveModelForTier`, `resolveGranularityInternal`, `resolveEffortInternal`, `resolveFastModeInternal`, `resolveEffortForTier`, `nextEffort`, `assertValidGranularityOverride`). Depends only on leaf modules (`config-loader` for `loadConfig`, `configuration` for defaults, `model-profiles` and `model-catalog` for the static tables) — no other core dependency. Extracted from the Core module per ADR-857 rollout phase 2f (#888) — the final core.cts decomposition step; the `core.cjs` re-export spine was retired in epic #1267, so callers import this leaf directly. Source of truth: `gsd-core/bin/lib/model-resolver.cjs` (generated from `src/model-resolver.cts`).
|
||||||
|
|
||||||
### Package Identity Module [Planned]
|
### Package Identity Module [Planned]
|
||||||
Single seam owning GSD's published-package coordinates so a repoint/rename is a one-line change instead of a tree-wide sweep. Source of truth is `package.json`; values are *derived*, not re-typed: `packageName` (`.name` → `@opengsd/get-shit-done-redux`), `binName` (`Object.keys(.bin)[0]` → `get-shit-done-redux`), `repoSlug` (parsed from `.repository.url` → `open-gsd/get-shit-done-redux`), plus derived `changelogRawUrl` and `manualInstallCommand({ scope, runtime })`. Generated `.cjs` per ADR-457 (generated-single-source); shipped under `gsd-core/bin/lib/`. Three consumer worlds: **Node** consumers `require()` it at runtime (worker, `check-latest-version.cjs`, `bin/install.js`); the **bash launcher** snippet receives the literal injected by `scripts/sync-runtime-launcher.cjs` at sync time; **prose/help** literals (`update.md`, installer help) carry a committed copy. A drift-guard lint (`scripts/lint-package-identity-drift.cjs`, sibling to `check:alias-drift`) fails CI on any raw package/repo literal outside `package.json`, the generated module, and the value-checked materialization sites — this is what keeps the seam real (`two adapters`, not one). Replaces the contradictory pair it consolidates: the runtime-broken `require('../package.json').name` in `hooks/gsd-check-update-worker.js` (#378, resolves to `undefined` post-install) and the hardcoded constant in `check-latest-version.cjs` (#2992). _Avoid_: "package name string", "the npm name" (when you mean the seam). See ADR-457 and Installer Module.
|
Single seam owning GSD's published-package coordinates so a repoint/rename is a one-line change instead of a tree-wide sweep. Source of truth is `package.json`; values are *derived*, not re-typed: `packageName` (`.name` → `@opengsd/get-shit-done-redux`), `binName` (`Object.keys(.bin)[0]` → `get-shit-done-redux`), `repoSlug` (parsed from `.repository.url` → `open-gsd/get-shit-done-redux`), plus derived `changelogRawUrl` and `manualInstallCommand({ scope, runtime })`. Generated `.cjs` per ADR-457 (generated-single-source); shipped under `gsd-core/bin/lib/`. Three consumer worlds: **Node** consumers `require()` it at runtime (worker, `check-latest-version.cjs`, `bin/install.js`); the **bash launcher** snippet receives the literal injected by `scripts/sync-runtime-launcher.cjs` at sync time; **prose/help** literals (`update.md`, installer help) carry a committed copy. A drift-guard lint (`scripts/lint-package-identity-drift.cjs`, sibling to `check:alias-drift`) fails CI on any raw package/repo literal outside `package.json`, the generated module, and the value-checked materialization sites — this is what keeps the seam real (`two adapters`, not one). Replaces the contradictory pair it consolidates: the runtime-broken `require('../package.json').name` in `hooks/gsd-check-update-worker.js` (#378, resolves to `undefined` post-install) and the hardcoded constant in `check-latest-version.cjs` (#2992). _Avoid_: "package name string", "the npm name" (when you mean the seam). See ADR-457 and Installer Module.
|
||||||
@@ -306,7 +306,7 @@ A legal deferred state of an Execute step (`external_job_waiting`): the executor
|
|||||||
`RULESET.TESTS.no-source-grep.exemption=// allow-test-rule: <runtime-contract-is-the-product> with one-line justification; reserved for tests where the file content IS the product surface (STATE.md, config.toml, hooks.json, agent .md). Migration to typed-IR parser tracked in #2974.`
|
`RULESET.TESTS.no-source-grep.exemption=// allow-test-rule: <runtime-contract-is-the-product> with one-line justification; reserved for tests where the file content IS the product surface (STATE.md, config.toml, hooks.json, agent .md). Migration to typed-IR parser tracked in #2974.`
|
||||||
`RULESET.TESTS.no-source-grep.tmp-file-traps=reading tmp files written by the SUT in tests still trips lint; round-trip through CLI (e.g. frontmatter get) instead of readFileSync+.includes()`
|
`RULESET.TESTS.no-source-grep.tmp-file-traps=reading tmp files written by the SUT in tests still trips lint; round-trip through CLI (e.g. frontmatter get) instead of readFileSync+.includes()`
|
||||||
|
|
||||||
`RULESET.TESTS.escape-regex=new RegExp("prefix${var}") must escapeRegex(var); core.cjs already exports escapeRegex; phase IDs like 5.1 contain . which is metacharacter`
|
`RULESET.TESTS.escape-regex=new RegExp("prefix${var}") must escapeRegex(var); phase-id.cjs exports escapeRegex (core.cjs re-export spine retired in epic #1267); phase IDs like 5.1 contain . which is metacharacter`
|
||||||
`RULESET.TESTS.no-dead-regex-in-includes=src.includes("foo.*bar") is always false — .* is regex metacharacter not wildcard; use new RegExp(...).test(src) or delete`
|
`RULESET.TESTS.no-dead-regex-in-includes=src.includes("foo.*bar") is always false — .* is regex metacharacter not wildcard; use new RegExp(...).test(src) or delete`
|
||||||
`RULESET.TESTS.guard-toplevel-readFileSync=module-level const src = readFileSync(...) throws before any test() registers — wrap in try/catch in test() or use lazy load`
|
`RULESET.TESTS.guard-toplevel-readFileSync=module-level const src = readFileSync(...) throws before any test() registers — wrap in try/catch in test() or use lazy load`
|
||||||
`RULESET.TESTS.coderabbit-fix-prefer=behavioral tests (call exported fn, capture JSON, assert typed fields) over source-grep`
|
`RULESET.TESTS.coderabbit-fix-prefer=behavioral tests (call exported fn, capture JSON, assert typed fields) over source-grep`
|
||||||
@@ -379,7 +379,7 @@ A legal deferred state of an Execute step (`external_job_waiting`): the executor
|
|||||||
`PR.3267.POSTMORTEM.recovery=[issue#3270 created, label approved-enhancement applied, PR reopened, body includes "Closes #3270", label no-changelog applied]`
|
`PR.3267.POSTMORTEM.recovery=[issue#3270 created, label approved-enhancement applied, PR reopened, body includes "Closes #3270", label no-changelog applied]`
|
||||||
|
|
||||||
`WORKTREE.SEAM.current=Worktree Safety Policy Module`
|
`WORKTREE.SEAM.current=Worktree Safety Policy Module`
|
||||||
`WORKTREE.SEAM.files=[gsd-core/bin/lib/worktree-safety.cjs, gsd-core/bin/lib/core.cjs]`
|
`WORKTREE.SEAM.files=[gsd-core/bin/lib/worktree-safety.cjs]`
|
||||||
`WORKTREE.SEAM.interface=[resolveWorktreeContext, parseWorktreePorcelain, planWorktreePrune, executeWorktreePrunePlan]`
|
`WORKTREE.SEAM.interface=[resolveWorktreeContext, parseWorktreePorcelain, planWorktreePrune, executeWorktreePrunePlan]`
|
||||||
`WORKTREE.SEAM.default-prune-policy=metadata_prune_only (non-destructive)`
|
`WORKTREE.SEAM.default-prune-policy=metadata_prune_only (non-destructive)`
|
||||||
`WORKTREE.SEAM.decision-1=retain non-destructive default; destructive path only as explicit future opt-in scaffold`
|
`WORKTREE.SEAM.decision-1=retain non-destructive default; destructive path only as explicit future opt-in scaffold`
|
||||||
@@ -683,7 +683,7 @@ Invariants:
|
|||||||
- Platform policy owned at the seam: `shell: process.platform === 'win32'` lives only in run-npm; probeTty returns `null` on Windows.
|
- Platform policy owned at the seam: `shell: process.platform === 'win32'` lives only in run-npm; probeTty returns `null` on Windows.
|
||||||
- Normalization policy: platformWriteSync owns full `normalizeMd` for `.md`; CRLF-to-LF + trailing newline for all others; callers must NOT pre-call `normalizeMd`.
|
- Normalization policy: platformWriteSync owns full `normalizeMd` for `.md`; CRLF-to-LF + trailing newline for all others; callers must NOT pre-call `normalizeMd`.
|
||||||
- `_normalizeMd` is re-implemented inline (not imported from `core.cjs`) to avoid circular dep.
|
- `_normalizeMd` is re-implemented inline (not imported from `core.cjs`) to avoid circular dep.
|
||||||
- `atomicWriteFileSync`, `safeReadFile`, `normalizeMd` remain in `core.cjs` exports until Phase 4 (#3468).
|
- `atomicWriteFileSync`, `safeReadFile`, `normalizeMd` were in `core.cjs` exports (retired in epic #1267); callers now import these from their respective leaf modules directly.
|
||||||
|
|
||||||
Migration plan: Phase 1 (#3465) seam additions complete; Phase 2 (#3466) targets 6 subprocess files; Phase 3 (#3467) targets 15 fs files (215 call sites); Phase 4 (#3468) removes compat exports.
|
Migration plan: Phase 1 (#3465) seam additions complete; Phase 2 (#3466) targets 6 subprocess files; Phase 3 (#3467) targets 15 fs files (215 call sites); Phase 4 (#3468) removes compat exports.
|
||||||
|
|
||||||
|
|||||||
@@ -265,9 +265,11 @@ const _gsdLibDir = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
|||||||
const { MODEL_PROFILES: GSD_MODEL_PROFILES } = require(path.join(_gsdLibDir, 'model-profiles.cjs'));
|
const { MODEL_PROFILES: GSD_MODEL_PROFILES } = require(path.join(_gsdLibDir, 'model-profiles.cjs'));
|
||||||
const {
|
const {
|
||||||
RUNTIME_PROFILE_MAP: GSD_RUNTIME_PROFILE_MAP,
|
RUNTIME_PROFILE_MAP: GSD_RUNTIME_PROFILE_MAP,
|
||||||
|
} = require(path.join(_gsdLibDir, 'model-catalog.cjs'));
|
||||||
|
const {
|
||||||
resolveTierEntry: gsdResolveTierEntry,
|
resolveTierEntry: gsdResolveTierEntry,
|
||||||
EFFORT_SET: GSD_EFFORT_SET,
|
EFFORT_SET: GSD_EFFORT_SET,
|
||||||
} = require(path.join(_gsdLibDir, 'core.cjs'));
|
} = require(path.join(_gsdLibDir, 'model-resolver.cjs'));
|
||||||
|
|
||||||
// #443 — model-catalog and config-defaults.manifest.json exports needed only
|
// #443 — model-catalog and config-defaults.manifest.json exports needed only
|
||||||
// by effort-resolution code paths (resolveInstallTimeEffort /
|
// by effort-resolution code paths (resolveInstallTimeEffort /
|
||||||
|
|||||||
@@ -300,7 +300,6 @@
|
|||||||
"configuration.cjs",
|
"configuration.cjs",
|
||||||
"context-utilization.cjs",
|
"context-utilization.cjs",
|
||||||
"core-utils.cjs",
|
"core-utils.cjs",
|
||||||
"core.cjs",
|
|
||||||
"decisions.cjs",
|
"decisions.cjs",
|
||||||
"docs.cjs",
|
"docs.cjs",
|
||||||
"drift.cjs",
|
"drift.cjs",
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ export default tseslint.config(
|
|||||||
'gsd-core/bin/lib/runtime-config-adapter-registry.cjs',
|
'gsd-core/bin/lib/runtime-config-adapter-registry.cjs',
|
||||||
'gsd-core/bin/lib/runtime-hooks-surface.cjs',
|
'gsd-core/bin/lib/runtime-hooks-surface.cjs',
|
||||||
'gsd-core/bin/lib/command-routing-hub.cjs',
|
'gsd-core/bin/lib/command-routing-hub.cjs',
|
||||||
'gsd-core/bin/lib/core.cjs',
|
|
||||||
'gsd-core/bin/lib/core-utils.cjs',
|
'gsd-core/bin/lib/core-utils.cjs',
|
||||||
'gsd-core/bin/lib/io.cjs',
|
'gsd-core/bin/lib/io.cjs',
|
||||||
'gsd-core/bin/lib/phase-id.cjs',
|
'gsd-core/bin/lib/phase-id.cjs',
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ Squash merge is recommended — keeps main branch history clean while preserving
|
|||||||
|
|
||||||
## Complete Field Reference
|
## Complete Field Reference
|
||||||
|
|
||||||
Generated from `CONFIG_DEFAULTS` (core.cjs) and `VALID_CONFIG_KEYS` (config.cjs).
|
Generated from `CONFIG_DEFAULTS` (configuration.cjs) and `VALID_CONFIG_KEYS` (config-schema.cjs).
|
||||||
|
|
||||||
### Core Fields
|
### Core Fields
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
"pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
|
"pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
|
||||||
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
|
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs && node scripts/lint-core-spine-imports.cjs",
|
"lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs",
|
||||||
"lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
|
"lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
|
||||||
"lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
|
"lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
|
||||||
"lint:regression-names": "node scripts/lint-regression-test-names.cjs",
|
"lint:regression-names": "node scripts/lint-regression-test-names.cjs",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"_comment": "Files allowed to import the core re-export spine during the staged retirement (issue #1268). Entries are REMOVED as each tranche migrates a leaf; the file + this lint are deleted in T-final.",
|
|
||||||
"allow": []
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Migration-convergence lint for the core re-export spine (issue #1268).
|
|
||||||
*
|
|
||||||
* The spine (core.cjs) is being staged for retirement: each tranche migrates a
|
|
||||||
* set of leaf importers to consume the individual modules directly. This lint
|
|
||||||
* makes CI RED the moment a NEW file starts importing the spine, preventing
|
|
||||||
* regressions as the tranche work proceeds.
|
|
||||||
*
|
|
||||||
* Allowlisted importers (the "T0 set") are files that already imported the
|
|
||||||
* spine when this lint was introduced. Entries are REMOVED from the allowlist
|
|
||||||
* as each tranche migrates a leaf. The allowlist + this script are deleted in
|
|
||||||
* T-final.
|
|
||||||
*
|
|
||||||
* Model: scripts/lint-package-identity-drift.cjs
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('node:fs');
|
|
||||||
const path = require('node:path');
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Core-spine import detection
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches any import form that targets the core spine at any relative depth,
|
|
||||||
* including the TS `import x = require(...)` form, dynamic imports, and bare
|
|
||||||
* side-effect imports.
|
|
||||||
*
|
|
||||||
* Patterns matched (illustrative):
|
|
||||||
* require('./core.cjs')
|
|
||||||
* require('./core')
|
|
||||||
* require('../core.cjs')
|
|
||||||
* require('./lib/core.cjs')
|
|
||||||
* require('../lib/core.cjs')
|
|
||||||
* require('../../lib/core.cjs')
|
|
||||||
* from './core.cjs'
|
|
||||||
* import core = require('../lib/core.cjs')
|
|
||||||
* import('./core.cjs') dynamic import
|
|
||||||
* await import('../lib/core.cjs') dynamic import
|
|
||||||
* import './core.cjs'; bare side-effect import
|
|
||||||
*
|
|
||||||
* Patterns NOT matched (boundary after bare `core` is quote or `.cjs`):
|
|
||||||
* require('./core-utils.cjs')
|
|
||||||
* require('./core-schema.cjs')
|
|
||||||
*
|
|
||||||
* The `import\s+` branch (bare side-effect) will NOT match
|
|
||||||
* `import x = require(...)` because a non-quote token follows `import `.
|
|
||||||
*/
|
|
||||||
const CORE_IMPORT_RE = /(?:require\(\s*|import\s*\(\s*|from\s+|import\s+)['"](?:\.\.?\/)+(?:lib\/)?core(?:\.cjs)?['"]/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if `line` is a real (non-commented) core-spine import.
|
|
||||||
* @param {string} line
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function lineImportsSpine(line) {
|
|
||||||
if (line.trimStart().startsWith('//')) return false;
|
|
||||||
return CORE_IMPORT_RE.test(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Directory walking
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively collect files under `dir` matching `extSet`, skipping
|
|
||||||
* `node_modules`, `.git`, `.memdb`, and any caller-supplied `skipDirs`.
|
|
||||||
* (The caller is responsible for scoping roots; this function does NOT itself
|
|
||||||
* skip `tests/` — that exclusion is achieved by not passing `tests/` as a root.)
|
|
||||||
*
|
|
||||||
* @param {string} dir - Absolute directory to walk.
|
|
||||||
* @param {Set<string>} extSet - File extensions to include (e.g. new Set(['.cts','.cjs'])).
|
|
||||||
* @param {Set<string>} skipDirs - Absolute paths of directories to skip entirely.
|
|
||||||
* @param {string[]} acc - Accumulator (modified in place).
|
|
||||||
* @returns {string[]}
|
|
||||||
*/
|
|
||||||
function walk(dir, extSet, skipDirs, acc) {
|
|
||||||
let entries;
|
|
||||||
try {
|
|
||||||
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
||||||
} catch {
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
for (const entry of entries) {
|
|
||||||
const full = path.join(dir, entry.name);
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.memdb') continue;
|
|
||||||
if (skipDirs.has(full)) continue;
|
|
||||||
walk(full, extSet, skipDirs, acc);
|
|
||||||
} else if (entry.isFile() && extSet.has(path.extname(entry.name))) {
|
|
||||||
acc.push(full);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Pure exported API
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan `roots` for source files that import the core spine but are not in
|
|
||||||
* `allowlistSet`.
|
|
||||||
*
|
|
||||||
* @param {string[]} roots - Absolute directories to scan.
|
|
||||||
* @param {Set<string>} allowlistSet - Repo-relative POSIX paths that are
|
|
||||||
* allowed to import the spine (the T0 set).
|
|
||||||
* @returns {{ file: string, line: number }[]}
|
|
||||||
* Repo-relative POSIX file path and 1-based line number for each violation.
|
|
||||||
*/
|
|
||||||
function scanCoreSpineImports(roots, allowlistSet) {
|
|
||||||
const repoRoot = path.join(__dirname, '..');
|
|
||||||
|
|
||||||
// gsd-core/bin/lib is excluded (generated artefacts — double-counts src/).
|
|
||||||
const skipDirs = new Set([path.join(repoRoot, 'gsd-core', 'bin', 'lib')]);
|
|
||||||
|
|
||||||
// src/*.cts → .cts only; gsd-core/bin/**/*.cjs → .cjs only.
|
|
||||||
// Accept either extension in each root; walk will naturally skip unsupported
|
|
||||||
// files via extSet filtering.
|
|
||||||
const extSet = new Set(['.cts', '.cjs']);
|
|
||||||
|
|
||||||
const violations = [];
|
|
||||||
|
|
||||||
for (const root of roots) {
|
|
||||||
const files = walk(root, extSet, skipDirs, []);
|
|
||||||
for (const abs of files) {
|
|
||||||
// Derive repo-relative POSIX path for allowlist lookup and reporting.
|
|
||||||
const rel = path.relative(repoRoot, abs).replace(/\\/g, '/');
|
|
||||||
|
|
||||||
let text;
|
|
||||||
try {
|
|
||||||
text = fs.readFileSync(abs, 'utf8');
|
|
||||||
} catch {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lines = text.split('\n');
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
if (lineImportsSpine(lines[i])) {
|
|
||||||
if (!allowlistSet.has(rel)) {
|
|
||||||
violations.push({ file: rel, line: i + 1 });
|
|
||||||
}
|
|
||||||
// Do NOT break: report every spine-import line so no violation is masked.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return violations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the allowlist JSON and return a Set of repo-relative paths.
|
|
||||||
*
|
|
||||||
* @param {string} allowlistPath - Absolute path to the JSON file.
|
|
||||||
* @returns {Set<string>}
|
|
||||||
*/
|
|
||||||
function loadAllowlist(allowlistPath) {
|
|
||||||
const raw = fs.readFileSync(allowlistPath, 'utf8');
|
|
||||||
const obj = JSON.parse(raw);
|
|
||||||
return new Set(obj.allow || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// CLI entry point
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
const repoRoot = path.join(__dirname, '..');
|
|
||||||
const allowlistPath = path.join(__dirname, 'lint-core-spine-imports.allowlist.json');
|
|
||||||
|
|
||||||
const allowlistSet = loadAllowlist(allowlistPath);
|
|
||||||
|
|
||||||
const roots = [
|
|
||||||
path.join(repoRoot, 'src'),
|
|
||||||
path.join(repoRoot, 'gsd-core', 'bin'),
|
|
||||||
];
|
|
||||||
|
|
||||||
const violations = scanCoreSpineImports(roots, allowlistSet);
|
|
||||||
|
|
||||||
if (violations.length === 0) {
|
|
||||||
process.stdout.write(
|
|
||||||
`ok core-spine-imports: ${allowlistSet.size} allowlisted importer(s), 0 new\n`,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stderr.write('core-spine-imports: new file(s) importing the core re-export spine detected.\n');
|
|
||||||
process.stderr.write('The spine (core.cjs) is being retired (issue #1268). Import the leaf module\n');
|
|
||||||
process.stderr.write('directly instead, or add to the allowlist only if genuinely transitional:\n');
|
|
||||||
for (const v of violations) {
|
|
||||||
process.stderr.write(` ${v.file}:${v.line}\n`);
|
|
||||||
}
|
|
||||||
process.stderr.write(`core-spine-imports: ${violations.length} violation(s)\n`);
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (require.main === module) main();
|
|
||||||
|
|
||||||
module.exports = { scanCoreSpineImports, loadAllowlist };
|
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
* - getAgentsDir(runtime?): string
|
* - getAgentsDir(runtime?): string
|
||||||
* - checkAgentsInstalled(runtime?): AgentsInstalledResult
|
* - checkAgentsInstalled(runtime?): AgentsInstalledResult
|
||||||
*
|
*
|
||||||
* Consumers that previously imported these via core.cjs continue to work:
|
* The core.cjs re-export spine was retired in epic #1267; callers import
|
||||||
* core.cjs re-exports both symbols BY REFERENCE from this module.
|
* these symbols from agent-install-check.cjs directly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
|||||||
@@ -7,11 +7,10 @@
|
|||||||
* normalizes legacy keys, applies the active-workstream overlay, validates
|
* normalizes legacy keys, applies the active-workstream overlay, validates
|
||||||
* against the config schema, and warns on unknown keys/profile overrides.
|
* against the config schema, and warns on unknown keys/profile overrides.
|
||||||
* Behaviour is preserved byte-for-behaviour from the prior location; only
|
* Behaviour is preserved byte-for-behaviour from the prior location; only
|
||||||
* the module boundary moved. core.cjs re-exports `loadConfig` for back-compat.
|
* the module boundary moved. The core.cjs re-export spine was retired in
|
||||||
|
* epic #1267; callers import loadConfig from config-loader.cjs directly.
|
||||||
*
|
*
|
||||||
* New imports should pull loadConfig from config-loader.cjs directly.
|
* Dependencies (leaf modules only):
|
||||||
*
|
|
||||||
* Dependencies (leaf modules only — no core.cjs):
|
|
||||||
* - node:fs / node:os / node:path (stdlib)
|
* - node:fs / node:os / node:path (stdlib)
|
||||||
* - ./configuration.cjs (normalizeLegacyKeys, CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS)
|
* - ./configuration.cjs (normalizeLegacyKeys, CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS)
|
||||||
* - ./config-schema.cjs (VALID_CONFIG_KEYS, DYNAMIC_KEY_PATTERNS)
|
* - ./config-schema.cjs (VALID_CONFIG_KEYS, DYNAMIC_KEY_PATTERNS)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*
|
*
|
||||||
* Imported by:
|
* Imported by:
|
||||||
* - config.cjs (isValidConfigKey validator)
|
* - config.cjs (isValidConfigKey validator)
|
||||||
* - core.cjs
|
|
||||||
* - many tests (config-schema.property.test.cjs, bug-*, feat-*, etc.)
|
* - many tests (config-schema.property.test.cjs, bug-*, feat-*, etc.)
|
||||||
|
* (core.cjs re-export spine retired in epic #1267)
|
||||||
*
|
*
|
||||||
* See Phase 2 Cycle 5 (#3536) — schema manifest migration.
|
* See Phase 2 Cycle 5 (#3536) — schema manifest migration.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
* TypeScript type definitions for GSD project config — model_policy block.
|
* TypeScript type definitions for GSD project config — model_policy block.
|
||||||
*
|
*
|
||||||
* These types reflect the model_policy config shape consumed by
|
* These types reflect the model_policy config shape consumed by
|
||||||
* resolveModelPolicy in core.cjs and validated by config-schema.cjs.
|
* resolveModelPolicy in model-resolver.cjs and validated by config-schema.cjs.
|
||||||
|
* (core.cjs re-export spine retired in epic #1267)
|
||||||
*
|
*
|
||||||
* See feat #49 (model_policy presets) and config-schema.manifest.json.
|
* See feat #49 (model_policy presets) and config-schema.manifest.json.
|
||||||
* Added under ADR-457: TS sources in src/ compile to CJS artifacts in
|
* Added under ADR-457: TS sources in src/ compile to CJS artifacts in
|
||||||
|
|||||||
219
src/core.cts
219
src/core.cts
@@ -1,219 +0,0 @@
|
|||||||
/**
|
|
||||||
* Core — Shared utilities, constants, and internal helpers
|
|
||||||
*
|
|
||||||
* ADR-457 build-at-publish: the hand-written bin/lib/core.cjs collapsed
|
|
||||||
* to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
|
|
||||||
* from the prior hand-written .cjs; only strict types are added.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// (fs, path, execGit removed — last callers relocated to leaf modules during #1268 T0 rehome)
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import ioModule = require('./io.cjs');
|
|
||||||
const { output, error, ERROR_REASON, setJsonErrorMode, getJsonErrorMode, GSD_TEMP_DIR, reapStaleTempFiles } = ioModule;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import phaseIdModule = require('./phase-id.cjs');
|
|
||||||
const { escapeRegex, normalizePhaseName, getMilestoneFromPhaseId, getPhaseDirFromPhaseId, phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, comparePhaseNum, extractPhaseToken, phaseTokenMatches } = phaseIdModule;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import roadmapParserModule = require('./roadmap-parser.cjs');
|
|
||||||
const { stripShippedMilestones, extractCurrentMilestone, replaceInCurrentMilestone, getRoadmapPhaseInternal, getMilestoneInfo, getMilestonePhaseFilter } = roadmapParserModule;
|
|
||||||
import { RUNTIME_PROFILE_MAP, KNOWN_RUNTIMES, RUNTIMES_WITH_REASONING_EFFORT, RUNTIMES_WITH_FAST_MODE, KNOWN_PROVIDERS, MODEL_ALIAS_MAP } from './model-catalog.cjs';
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import worktreeSafety = require('./worktree-safety.cjs');
|
|
||||||
const {
|
|
||||||
inspectWorktreeHealth,
|
|
||||||
} = worktreeSafety;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import planningWorkspace = require('./planning-workspace.cjs');
|
|
||||||
// Compatibility shim: new imports should use planning-workspace.cjs directly.
|
|
||||||
const {
|
|
||||||
planningDir,
|
|
||||||
planningRoot,
|
|
||||||
planningPaths,
|
|
||||||
withPlanningLock,
|
|
||||||
getActiveWorkstream,
|
|
||||||
setActiveWorkstream,
|
|
||||||
} = planningWorkspace;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import coreUtilsModule = require('./core-utils.cjs');
|
|
||||||
const {
|
|
||||||
toPosixPath,
|
|
||||||
detectSubRepos,
|
|
||||||
extractOneLinerFromBody,
|
|
||||||
pathExistsInternal,
|
|
||||||
generateSlugInternal,
|
|
||||||
filterPlanFiles,
|
|
||||||
filterSummaryFiles,
|
|
||||||
getPhaseFileStats,
|
|
||||||
readSubdirectories,
|
|
||||||
timeAgo,
|
|
||||||
} = coreUtilsModule;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import phaseLocatorModule = require('./phase-locator.cjs');
|
|
||||||
const { searchPhaseInDir, findPhaseInternal, getArchivedPhaseDirs } = phaseLocatorModule;
|
|
||||||
import { findProjectRoot } from './project-root.cjs';
|
|
||||||
|
|
||||||
// ─── Config Loader Module (extracted from core, ADR-857 phase 2e / #885) ─────
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import configLoaderModule = require('./config-loader.cjs');
|
|
||||||
const {
|
|
||||||
loadConfig,
|
|
||||||
isGitIgnored,
|
|
||||||
CONFIG_DEFAULTS,
|
|
||||||
_warnUnknownProfileOverrides,
|
|
||||||
RUNTIME_OVERRIDE_TIERS,
|
|
||||||
} = configLoaderModule;
|
|
||||||
|
|
||||||
// ─── Model Resolver Module (extracted from core, ADR-857 phase 2f / #888) ────
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
||||||
import modelResolverModule = require('./model-resolver.cjs');
|
|
||||||
const {
|
|
||||||
resolveTierEntry,
|
|
||||||
resolveModelPolicy,
|
|
||||||
resolveModelInternal,
|
|
||||||
VALID_GRANULARITIES,
|
|
||||||
resolveGranularityInternal,
|
|
||||||
assertValidGranularityOverride,
|
|
||||||
resolveModelForTier,
|
|
||||||
VALID_EFFORTS,
|
|
||||||
EFFORT_SET,
|
|
||||||
nextEffort,
|
|
||||||
resolveEffortInternal,
|
|
||||||
resolveFastModeInternal,
|
|
||||||
resolveEffortForTier,
|
|
||||||
} = modelResolverModule;
|
|
||||||
|
|
||||||
// ─── Path helpers ────────────────────────────────────────────────────────────
|
|
||||||
// toPosixPath and detectSubRepos moved to core-utils.cjs (ADR-857 phase 2c / #877).
|
|
||||||
// The destructured bindings above (from coreUtilsModule) make them available to
|
|
||||||
// core-internal callers; core.cjs re-exports toPosixPath and detectSubRepos for back-compat.
|
|
||||||
|
|
||||||
// findProjectRoot is now re-exported from the generated CJS module above.
|
|
||||||
|
|
||||||
// loadConfig, isGitIgnored, CONFIG_DEFAULTS, and related helpers moved to
|
|
||||||
// config-loader.cjs (ADR-857 phase 2e / #885). The destructured bindings above
|
|
||||||
// (from configLoaderModule) make them available to core-internal callers;
|
|
||||||
// core.cjs re-exports loadConfig and isGitIgnored for back-compat.
|
|
||||||
|
|
||||||
// ─── Planning workspace (pathing + active workstream + lock) moved to planning-workspace.cjs ───
|
|
||||||
|
|
||||||
// ─── Phase utilities (pure helpers re-exported from phase-id.cjs) ─────────────
|
|
||||||
// escapeRegex, normalizePhaseName, getMilestoneFromPhaseId, getPhaseDirFromPhaseId,
|
|
||||||
// phaseMarkdownRegexSource, phaseMarkdownRegexSourceExact, comparePhaseNum,
|
|
||||||
// extractPhaseToken, phaseTokenMatches
|
|
||||||
// — all imported via `phaseIdModule` above; internal callers use the destructured bindings.
|
|
||||||
|
|
||||||
// extractCanonicalPlanId moved to core-utils.cjs (ADR-857 phase 2c / #877).
|
|
||||||
// It is consumed exclusively by phase-locator.cjs, which imports it from
|
|
||||||
// core-utils.cjs directly. It is NOT destructured in core.cts and is NOT
|
|
||||||
// in core.cjs's public export = block (it was never public).
|
|
||||||
|
|
||||||
// searchPhaseInDir, findPhaseInternal, getArchivedPhaseDirs moved to phase-locator.cjs
|
|
||||||
// (ADR-857 phase 2d / #881). The destructured bindings above (from phaseLocatorModule)
|
|
||||||
// make them available to core-internal callers; core.cjs re-exports findPhaseInternal,
|
|
||||||
// getArchivedPhaseDirs, and searchPhaseInDir for back-compat.
|
|
||||||
|
|
||||||
// ─── Roadmap milestone scoping (re-exported from roadmap-parser.cjs) ──────────
|
|
||||||
// stripShippedMilestones, extractCurrentMilestone, replaceInCurrentMilestone,
|
|
||||||
// getRoadmapPhaseInternal, getMilestoneInfo, getMilestonePhaseFilter
|
|
||||||
// — all imported via `roadmapParserModule` above; internal callers use the destructured bindings.
|
|
||||||
|
|
||||||
// ─── Agent installation validation (#1371) ───────────────────────────────────
|
|
||||||
// getAgentsDir and checkAgentsInstalled moved to agent-install-check.cjs (T0 #1268).
|
|
||||||
// Re-exports removed in T1 (#1277); callers import directly from agent-install-check.cjs.
|
|
||||||
|
|
||||||
// ─── Model alias resolution ───────────────────────────────────────────────────
|
|
||||||
// RUNTIME_OVERRIDE_TIERS, _warnedConfigKeys, _warnUnknownProfileOverrides, and
|
|
||||||
// _resetRuntimeWarningCacheForTests moved to config-loader.cjs (ADR-857 phase 2e / #885)
|
|
||||||
// and model-resolver.cjs (ADR-857 phase 2f / #888) respectively.
|
|
||||||
// _resetRuntimeWarningCacheForTests is NO LONGER re-exported from core.cjs; callers
|
|
||||||
// must import it directly from config-loader.cjs / model-resolver.cjs (or use
|
|
||||||
// the shared resetRuntimeWarningCaches() helper in tests/helpers.cjs).
|
|
||||||
|
|
||||||
// resolveTierEntry, resolveModelPolicy, resolveModelInternal, VALID_GRANULARITIES,
|
|
||||||
// resolveGranularityInternal, assertValidGranularityOverride, resolveModelForTier,
|
|
||||||
// VALID_EFFORTS, EFFORT_SET, nextEffort, resolveEffortInternal, resolveFastModeInternal,
|
|
||||||
// resolveEffortForTier — all moved to model-resolver.cjs (ADR-857 phase 2f / #888).
|
|
||||||
// The destructured bindings above (from modelResolverModule) make them available to
|
|
||||||
// core-internal callers; core.cjs re-exports all 13 symbols for back-compat.
|
|
||||||
|
|
||||||
// ─── Summary body helpers / Misc utilities / Phase file helpers ───────────────
|
|
||||||
// extractOneLinerFromBody, pathExistsInternal, generateSlugInternal,
|
|
||||||
// filterPlanFiles, filterSummaryFiles, getPhaseFileStats, readSubdirectories,
|
|
||||||
// timeAgo — all moved to core-utils.cjs (ADR-857 phase 2c / #877).
|
|
||||||
// The destructured bindings above (from coreUtilsModule) make them available
|
|
||||||
// to core-internal callers; core.cjs re-exports the public ones for back-compat.
|
|
||||||
|
|
||||||
// MilestoneInfo, MilestonePhaseFilter, getMilestoneInfo, getMilestonePhaseFilter
|
|
||||||
// — all re-exported from roadmap-parser.cjs via roadmapParserModule above.
|
|
||||||
|
|
||||||
export = {
|
|
||||||
output,
|
|
||||||
error,
|
|
||||||
ERROR_REASON,
|
|
||||||
setJsonErrorMode,
|
|
||||||
getJsonErrorMode,
|
|
||||||
loadConfig,
|
|
||||||
isGitIgnored,
|
|
||||||
escapeRegex,
|
|
||||||
normalizePhaseName,
|
|
||||||
getMilestoneFromPhaseId,
|
|
||||||
getPhaseDirFromPhaseId,
|
|
||||||
phaseMarkdownRegexSource,
|
|
||||||
phaseMarkdownRegexSourceExact,
|
|
||||||
comparePhaseNum,
|
|
||||||
searchPhaseInDir,
|
|
||||||
extractPhaseToken,
|
|
||||||
phaseTokenMatches,
|
|
||||||
findPhaseInternal,
|
|
||||||
getArchivedPhaseDirs,
|
|
||||||
getRoadmapPhaseInternal,
|
|
||||||
resolveModelInternal,
|
|
||||||
resolveModelForTier,
|
|
||||||
resolveGranularityInternal,
|
|
||||||
VALID_GRANULARITIES,
|
|
||||||
assertValidGranularityOverride,
|
|
||||||
resolveEffortInternal,
|
|
||||||
resolveFastModeInternal,
|
|
||||||
resolveEffortForTier,
|
|
||||||
VALID_EFFORTS,
|
|
||||||
EFFORT_SET,
|
|
||||||
nextEffort,
|
|
||||||
RUNTIME_PROFILE_MAP,
|
|
||||||
RUNTIMES_WITH_REASONING_EFFORT,
|
|
||||||
RUNTIMES_WITH_FAST_MODE,
|
|
||||||
KNOWN_RUNTIMES,
|
|
||||||
RUNTIME_OVERRIDE_TIERS,
|
|
||||||
resolveTierEntry,
|
|
||||||
resolveModelPolicy,
|
|
||||||
KNOWN_PROVIDERS,
|
|
||||||
pathExistsInternal,
|
|
||||||
generateSlugInternal,
|
|
||||||
getMilestoneInfo,
|
|
||||||
getMilestonePhaseFilter,
|
|
||||||
stripShippedMilestones,
|
|
||||||
extractCurrentMilestone,
|
|
||||||
replaceInCurrentMilestone,
|
|
||||||
toPosixPath,
|
|
||||||
extractOneLinerFromBody,
|
|
||||||
resolveWorktreeRoot: worktreeSafety.resolveWorktreeRoot,
|
|
||||||
// Deprecated re-exports — prefer direct import from planning-workspace.cjs
|
|
||||||
withPlanningLock,
|
|
||||||
findProjectRoot,
|
|
||||||
detectSubRepos,
|
|
||||||
reapStaleTempFiles,
|
|
||||||
GSD_TEMP_DIR,
|
|
||||||
MODEL_ALIAS_MAP,
|
|
||||||
CONFIG_DEFAULTS,
|
|
||||||
planningDir,
|
|
||||||
planningRoot,
|
|
||||||
planningPaths,
|
|
||||||
getActiveWorkstream,
|
|
||||||
setActiveWorkstream,
|
|
||||||
filterPlanFiles,
|
|
||||||
filterSummaryFiles,
|
|
||||||
getPhaseFileStats,
|
|
||||||
readSubdirectories,
|
|
||||||
timeAgo,
|
|
||||||
pruneOrphanedWorktrees: worktreeSafety.pruneOrphanedWorktrees,
|
|
||||||
inspectWorktreeHealth,
|
|
||||||
};
|
|
||||||
@@ -176,7 +176,7 @@ export function resolveBaseBranch(
|
|||||||
): string {
|
): string {
|
||||||
const execGit: ExecGitFn = deps?.execGit ?? execGitSeam;
|
const execGit: ExecGitFn = deps?.execGit ?? execGitSeam;
|
||||||
|
|
||||||
// Derive .planning dir relative to cwd (mirrors planningDir() in core.cjs)
|
// Derive .planning dir relative to cwd (mirrors planningDir() in planning-workspace.cjs)
|
||||||
const planningDir = path.join(cwd, '.planning');
|
const planningDir = path.join(cwd, '.planning');
|
||||||
|
|
||||||
// 1. Config override
|
// 1. Config override
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
*
|
*
|
||||||
* Extracted from core.cts (ADR-857 rollout phase 1 / issue #859).
|
* Extracted from core.cts (ADR-857 rollout phase 1 / issue #859).
|
||||||
* The hand-written bodies are preserved byte-for-behaviour; only the module
|
* The hand-written bodies are preserved byte-for-behaviour; only the module
|
||||||
* boundary moved. core.cts re-exports every symbol here under its own
|
* boundary moved. The core.cjs re-export spine was retired in epic #1267;
|
||||||
* `export =` object so existing consumers are unaffected.
|
* callers import I/O primitives from io.cjs directly.
|
||||||
*
|
|
||||||
* New imports should pull I/O primitives from io.cjs directly.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ function cmdMilestoneComplete(cwd: string, version: string, options: MilestoneCo
|
|||||||
platformEnsureDir(archiveDir);
|
platformEnsureDir(archiveDir);
|
||||||
|
|
||||||
// Scope stats and accomplishments to only the phases belonging to the
|
// Scope stats and accomplishments to only the phases belonging to the
|
||||||
// current milestone's ROADMAP. Uses the shared filter from core.cjs
|
// current milestone's ROADMAP. Uses the shared filter from roadmap-parser.cjs
|
||||||
// (same logic used by cmdPhasesList and other callers).
|
// (same logic used by cmdPhasesList and other callers).
|
||||||
const isDirInMilestone = getMilestonePhaseFilter(cwd, version);
|
const isDirInMilestone = getMilestonePhaseFilter(cwd, version);
|
||||||
if (isDirInMilestone.missingExplicitVersion) {
|
if (isDirInMilestone.missingExplicitVersion) {
|
||||||
|
|||||||
@@ -6,11 +6,10 @@
|
|||||||
* planning granularity, reasoning effort, and fast-mode for a given agent by
|
* planning granularity, reasoning effort, and fast-mode for a given agent by
|
||||||
* reading project config and resolving against the model profiles and catalog.
|
* reading project config and resolving against the model profiles and catalog.
|
||||||
* Behaviour is preserved byte-for-behaviour from the prior location; only
|
* Behaviour is preserved byte-for-behaviour from the prior location; only
|
||||||
* the module boundary moved. core.cjs re-exports the resolvers for back-compat.
|
* the module boundary moved. The core.cjs re-export spine was retired in
|
||||||
|
* epic #1267; callers import resolvers from model-resolver.cjs directly.
|
||||||
*
|
*
|
||||||
* New imports should pull resolvers from model-resolver.cjs directly.
|
* Dependencies (leaf modules only):
|
||||||
*
|
|
||||||
* Dependencies (leaf modules only — no core.cjs):
|
|
||||||
* - node:fs / node:path (stdlib, not currently needed — included for future use)
|
* - node:fs / node:path (stdlib, not currently needed — included for future use)
|
||||||
* - ./config-loader.cjs (loadConfig)
|
* - ./config-loader.cjs (loadConfig)
|
||||||
* - ./configuration.cjs (CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS)
|
* - ./configuration.cjs (CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS)
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
*
|
*
|
||||||
* Extracted from core.cts (ADR-857 rollout phase 2a / issue #865).
|
* Extracted from core.cts (ADR-857 rollout phase 2a / issue #865).
|
||||||
* The hand-written bodies are preserved byte-for-behaviour; only the module
|
* The hand-written bodies are preserved byte-for-behaviour; only the module
|
||||||
* boundary moved. core.cts re-exports every symbol here under its own
|
* boundary moved. The core.cjs re-export spine was retired in epic #1267;
|
||||||
* `export =` object so existing consumers are unaffected.
|
* callers import phase-id helpers from phase-id.cjs directly.
|
||||||
*
|
|
||||||
* New imports should pull phase-id helpers from phase-id.cjs directly.
|
|
||||||
*
|
*
|
||||||
* Dependencies: none (pure string/regex, no Node built-ins required).
|
* Dependencies: none (pure string/regex, no Node built-ins required).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,13 +6,10 @@
|
|||||||
* (`searchPhaseInDir`, `findPhaseInternal`) and archived-phase-dir
|
* (`searchPhaseInDir`, `findPhaseInternal`) and archived-phase-dir
|
||||||
* enumeration (`getArchivedPhaseDirs`), matching phase ids/tokens against
|
* enumeration (`getArchivedPhaseDirs`), matching phase ids/tokens against
|
||||||
* the filesystem. Behaviour is preserved byte-for-behaviour from the prior
|
* the filesystem. Behaviour is preserved byte-for-behaviour from the prior
|
||||||
* location; only the module boundary moved. core.cjs re-exports
|
* location; only the module boundary moved. The core.cjs re-export spine
|
||||||
* `searchPhaseInDir`, `findPhaseInternal`, and `getArchivedPhaseDirs` for back-compat.
|
* was retired in epic #1267; callers import phase-locator helpers directly.
|
||||||
*
|
*
|
||||||
* New imports should pull phase-locator helpers from phase-locator.cjs
|
* Dependencies (leaf modules only — no loadConfig):
|
||||||
* directly.
|
|
||||||
*
|
|
||||||
* Dependencies (leaf modules only — no core.cjs, no loadConfig):
|
|
||||||
* - node:fs / node:path (stdlib)
|
* - node:fs / node:path (stdlib)
|
||||||
* - ./phase-id.cjs (normalizePhaseName, phaseTokenMatches, extractPhaseToken)
|
* - ./phase-id.cjs (normalizePhaseName, phaseTokenMatches, extractPhaseToken)
|
||||||
* - ./core-utils.cjs (readSubdirectories, getPhaseFileStats, extractCanonicalPlanId, toPosixPath)
|
* - ./core-utils.cjs (readSubdirectories, getPhaseFileStats, extractCanonicalPlanId, toPosixPath)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { execFileSync } from 'node:child_process';
|
import { execFileSync } from 'node:child_process';
|
||||||
// Import the leaf I/O module directly, not the core.cjs re-export spine (being retired, #1268).
|
// Import the leaf I/O module directly (core.cjs re-export spine retired in epic #1267).
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
import io = require('./io.cjs');
|
import io = require('./io.cjs');
|
||||||
const { output, error, ERROR_REASON } = io;
|
const { output, error, ERROR_REASON } = io;
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
* Owns shipped-milestone slicing, current-milestone extraction,
|
* Owns shipped-milestone slicing, current-milestone extraction,
|
||||||
* milestone/phase lookups, and milestone-phase filtering.
|
* milestone/phase lookups, and milestone-phase filtering.
|
||||||
* Behaviour is preserved byte-for-behaviour from the prior location;
|
* Behaviour is preserved byte-for-behaviour from the prior location;
|
||||||
* only the module boundary moved. core.cjs re-exports every symbol here
|
* only the module boundary moved. The core.cjs re-export spine was retired
|
||||||
* under its own `export =` object so existing consumers are unaffected.
|
* in epic #1267; callers import roadmap-parser helpers directly.
|
||||||
*
|
*
|
||||||
* New imports should pull roadmap-parser helpers from roadmap-parser.cjs directly.
|
* Dependencies (leaf modules only — no loadConfig):
|
||||||
*
|
|
||||||
* Dependencies (leaf modules only — no core.cjs, no loadConfig):
|
|
||||||
* - node:fs / node:path (stdlib)
|
* - node:fs / node:path (stdlib)
|
||||||
* - ./phase-id.cjs (escapeRegex, phaseMarkdownRegexSource)
|
* - ./phase-id.cjs (escapeRegex, phaseMarkdownRegexSource)
|
||||||
* - ./planning-workspace.cjs (planningDir)
|
* - ./planning-workspace.cjs (planningDir)
|
||||||
|
|||||||
@@ -251,8 +251,7 @@ function executeWorktreePrunePlan(plan: WorktreePrunePlan | null, deps: Worktree
|
|||||||
|
|
||||||
const result = execGit(['worktree', 'prune'], { cwd: plan.repoRoot });
|
const result = execGit(['worktree', 'prune'], { cwd: plan.repoRoot });
|
||||||
if (result.timedOut) {
|
if (result.timedOut) {
|
||||||
// AC4: surface timedOut as a first-class field so callers (e.g.
|
// AC4: surface timedOut as a first-class field so callers can log a structured WARNING rather
|
||||||
// pruneOrphanedWorktrees in core.cjs) can log a structured WARNING rather
|
|
||||||
// than silently ignoring it (PRED.k302 — error-swallowing-empty-sentinel).
|
// than silently ignoring it (PRED.k302 — error-swallowing-empty-sentinel).
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const assert = require('node:assert/strict');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const { extractOneLinerFromBody } = require(
|
const { extractOneLinerFromBody } = require(
|
||||||
path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core.cjs')
|
path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core-utils.cjs')
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('bug #2660: extractOneLinerFromBody', () => {
|
describe('bug #2660: extractOneLinerFromBody', () => {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const os = require('node:os');
|
|||||||
const { execFileSync } = require('node:child_process');
|
const { execFileSync } = require('node:child_process');
|
||||||
|
|
||||||
const GSD_TOOLS = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
const GSD_TOOLS = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||||
const { ERROR_REASON } = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core.cjs'));
|
const { ERROR_REASON } = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'io.cjs'));
|
||||||
const { cleanup } = require('./helpers.cjs');
|
const { cleanup } = require('./helpers.cjs');
|
||||||
|
|
||||||
describe('bug-2943: config-get returns schema default for context_window', () => {
|
describe('bug-2943: config-get returns schema default for context_window', () => {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ describe('no-source-grep rule', () => {
|
|||||||
code: `
|
code: `
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const src = fs.readFileSync(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core.cjs'), 'utf-8');
|
const src = fs.readFileSync(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'io.cjs'), 'utf-8');
|
||||||
src.includes('someFunction');
|
src.includes('someFunction');
|
||||||
`,
|
`,
|
||||||
filename: 'tests/foo.test.cjs',
|
filename: 'tests/foo.test.cjs',
|
||||||
@@ -105,7 +105,7 @@ describe('no-source-grep rule', () => {
|
|||||||
// allow-test-rule: pending migration
|
// allow-test-rule: pending migration
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const src = fs.readFileSync(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'core.cjs'), 'utf-8');
|
const src = fs.readFileSync(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'io.cjs'), 'utf-8');
|
||||||
src.includes('someFunction');
|
src.includes('someFunction');
|
||||||
`,
|
`,
|
||||||
filename: 'tests/foo.test.cjs',
|
filename: 'tests/foo.test.cjs',
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ describe('#3023 + #443: unified effort resolver (resolveEffortInternal) for Code
|
|||||||
beforeEach(() => { projectDir = makeTmp('effort'); });
|
beforeEach(() => { projectDir = makeTmp('effort'); });
|
||||||
afterEach(() => { rmr(projectDir); });
|
afterEach(() => { rmr(projectDir); });
|
||||||
|
|
||||||
test('resolveEffortInternal exported from core.cjs', () => {
|
test('resolveEffortInternal exported from model-resolver.cjs', () => {
|
||||||
assert.equal(typeof resolveEffortInternal, 'function');
|
assert.equal(typeof resolveEffortInternal, 'function');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -719,11 +719,11 @@ describe('#49 isValidConfigKey: model_policy.* keys accepted/rejected', () => {
|
|||||||
|
|
||||||
// ─── KNOWN_PROVIDERS export tests ─────────────────────────────────────────────
|
// ─── KNOWN_PROVIDERS export tests ─────────────────────────────────────────────
|
||||||
|
|
||||||
describe('#49 KNOWN_PROVIDERS exports from model-catalog.cjs and core.cjs', () => {
|
describe('#49 KNOWN_PROVIDERS exports from model-catalog.cjs', () => {
|
||||||
test('KNOWN_PROVIDERS exported from core.cjs includes all keys from providerPresets in catalog', () => {
|
test('KNOWN_PROVIDERS exported from model-catalog.cjs includes all keys from providerPresets in catalog', () => {
|
||||||
// KNOWN_PROVIDERS must be a Set (or array) exported from core.cjs.
|
// KNOWN_PROVIDERS must be a Set (or array) exported from model-catalog.cjs.
|
||||||
assert.ok(KNOWN_PROVIDERS != null,
|
assert.ok(KNOWN_PROVIDERS != null,
|
||||||
'KNOWN_PROVIDERS must be exported from core.cjs');
|
'KNOWN_PROVIDERS must be exported from model-catalog.cjs');
|
||||||
const isIterable = typeof KNOWN_PROVIDERS[Symbol.iterator] === 'function';
|
const isIterable = typeof KNOWN_PROVIDERS[Symbol.iterator] === 'function';
|
||||||
assert.ok(isIterable,
|
assert.ok(isIterable,
|
||||||
'KNOWN_PROVIDERS must be iterable (Set or array)');
|
'KNOWN_PROVIDERS must be iterable (Set or array)');
|
||||||
@@ -741,15 +741,14 @@ describe('#49 KNOWN_PROVIDERS exports from model-catalog.cjs and core.cjs', () =
|
|||||||
'KNOWN_PROVIDERS must not include "generic" (it is not a catalog-backed provider)');
|
'KNOWN_PROVIDERS must not include "generic" (it is not a catalog-backed provider)');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('KNOWN_PROVIDERS exported from model-catalog.cjs matches core.cjs re-export', () => {
|
test('KNOWN_PROVIDERS from model-catalog.cjs is the canonical export', () => {
|
||||||
// model-catalog.cjs must also export KNOWN_PROVIDERS (the canonical source).
|
// model-catalog.cjs is the canonical source of KNOWN_PROVIDERS.
|
||||||
// core.cjs re-exports it. Both must be identical.
|
|
||||||
assert.ok(modelCatalog.KNOWN_PROVIDERS != null,
|
assert.ok(modelCatalog.KNOWN_PROVIDERS != null,
|
||||||
'KNOWN_PROVIDERS must be exported from model-catalog.cjs');
|
'KNOWN_PROVIDERS must be exported from model-catalog.cjs');
|
||||||
const fromCatalog = [...modelCatalog.KNOWN_PROVIDERS].sort();
|
const fromCatalog = [...modelCatalog.KNOWN_PROVIDERS].sort();
|
||||||
const fromCore = [...KNOWN_PROVIDERS].sort();
|
const fromImport = [...KNOWN_PROVIDERS].sort();
|
||||||
assert.deepStrictEqual(fromCore, fromCatalog,
|
assert.deepStrictEqual(fromImport, fromCatalog,
|
||||||
'KNOWN_PROVIDERS from core.cjs (re-export) must match model-catalog.cjs canonical export');
|
'KNOWN_PROVIDERS imported from model-catalog.cjs must match the module export');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ describe('intel router: unit tests via recording mocks', () => {
|
|||||||
test('routeIntelCommand extract-exports: calls intelExtractExports(path.resolve(cwd, filePath))', () => {
|
test('routeIntelCommand extract-exports: calls intelExtractExports(path.resolve(cwd, filePath))', () => {
|
||||||
const calls = [];
|
const calls = [];
|
||||||
const c = makeCoreMock();
|
const c = makeCoreMock();
|
||||||
const FILE_ARG = 'lib/core.cjs';
|
const FILE_ARG = 'lib/io.cjs';
|
||||||
const EXPECTED = path.resolve(CWD, FILE_ARG);
|
const EXPECTED = path.resolve(CWD, FILE_ARG);
|
||||||
|
|
||||||
routeIntelCommand({
|
routeIntelCommand({
|
||||||
|
|||||||
@@ -619,14 +619,14 @@ describe('issue #2517: install end-to-end — per-project config reaches Codex T
|
|||||||
// resolver-construction time. Catches accidental relative-path drift in CI.
|
// resolver-construction time. Catches accidental relative-path drift in CI.
|
||||||
const installDir = path.dirname(require.resolve('../bin/install.js'));
|
const installDir = path.dirname(require.resolve('../bin/install.js'));
|
||||||
const libDir = path.join(installDir, '..', 'gsd-core', 'bin', 'lib');
|
const libDir = path.join(installDir, '..', 'gsd-core', 'bin', 'lib');
|
||||||
assert.ok(fs.existsSync(path.join(libDir, 'core.cjs')));
|
assert.ok(fs.existsSync(path.join(libDir, 'model-catalog.cjs')));
|
||||||
assert.ok(fs.existsSync(path.join(libDir, 'model-profiles.cjs')));
|
assert.ok(fs.existsSync(path.join(libDir, 'model-profiles.cjs')));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ─── RUNTIME_PROFILE_MAP single source of truth (finding #16) ───────────────
|
// ─── RUNTIME_PROFILE_MAP single source of truth (finding #16) ───────────────
|
||||||
describe('issue #2517: RUNTIME_PROFILE_MAP single source of truth (finding #16)', () => {
|
describe('issue #2517: RUNTIME_PROFILE_MAP single source of truth (finding #16)', () => {
|
||||||
test('install.js consumes the same map as core.cjs', () => {
|
test('install.js consumes the same map as model-catalog.cjs', () => {
|
||||||
// `bin/install.js` must NOT carry its own duplicate copy of the map.
|
// `bin/install.js` must NOT carry its own duplicate copy of the map.
|
||||||
// The shared resolver imported in install.js exposes `runtime` and the
|
// The shared resolver imported in install.js exposes `runtime` and the
|
||||||
// entries through `resolveTierEntry`, so any future drift between the two
|
// entries through `resolveTierEntry`, so any future drift between the two
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const WORKTREE_SAFETY_PATH = path.join(
|
|||||||
__dirname, '..', 'gsd-core', 'bin', 'lib', 'worktree-safety.cjs'
|
__dirname, '..', 'gsd-core', 'bin', 'lib', 'worktree-safety.cjs'
|
||||||
);
|
);
|
||||||
const CORE_PATH = path.join(
|
const CORE_PATH = path.join(
|
||||||
__dirname, '..', 'gsd-core', 'bin', 'lib', 'core.cjs'
|
__dirname, '..', 'gsd-core', 'bin', 'lib', 'worktree-safety.cjs'
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|||||||
Reference in New Issue
Block a user