* refactor(#179): migrate configuration module to sdk/src/config * chore(#179): add changeset for config module path migration
This commit is contained in:
5
.changeset/plucky-tunas-howl.md
Normal file
5
.changeset/plucky-tunas-howl.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 179
|
||||
---
|
||||
migrated the SDK Configuration Module from sdk/src/configuration to sdk/src/config and rewired generator/test paths with no behavioral change.
|
||||
@@ -71,7 +71,7 @@ Single dispatch seam (`get-shit-done/bin/lib/command-routing-hub.cjs`) that cent
|
||||
Module policy that defines query-time behavior when `.planning/config.json` is absent: use built-in defaults for parity-sensitive query Interfaces, and emit parity-aligned empty model ids for pre-project model resolution surfaces.
|
||||
|
||||
### Configuration Module
|
||||
Shared CJS/SDK Module owning config load, legacy-key normalization, defaults merge, and explicit on-disk migration for `.planning/config.json`. Interface: `loadConfig(cwd) → MergedConfig` (pure read, never writes disk), `normalizeLegacyKeys(parsed) → { parsed, normalizations[] }` (idempotent, pure, returns the list of normalizations applied), `mergeDefaults(parsed) → MergedConfig` (deep-merge of parsed config over canonical defaults), `migrateOnDisk(cwd) → MigrationReport` (explicit, opt-in, called by the installer and by `gsd-tools migrate-config`). Invariants: never mutates disk inside `loadConfig`; legacy top-level keys (`branching_strategy`, `sub_repos`, `multiRepo`, `depth`) are normalized into their canonical nested locations in the returned value; defaults come from the shared `sdk/shared/config-defaults.manifest.json`; schema (`VALID_CONFIG_KEYS`, `RUNTIME_STATE_KEYS`, `DYNAMIC_KEY_PATTERNS`) comes from `sdk/shared/config-schema.manifest.json`. Source of truth: `sdk/src/configuration/index.ts`; CJS callers consume the generator-emitted `get-shit-done/bin/lib/configuration.generated.cjs` via the thin Adapters at `bin/lib/core.cjs:loadConfig` and `bin/lib/config-schema.cjs`. Eliminates the recurring #3523-class drift bug structurally.
|
||||
Shared CJS/SDK Module owning config load, legacy-key normalization, defaults merge, and explicit on-disk migration for `.planning/config.json`. Interface: `loadConfig(cwd) → MergedConfig` (pure read, never writes disk), `normalizeLegacyKeys(parsed) → { parsed, normalizations[] }` (idempotent, pure, returns the list of normalizations applied), `mergeDefaults(parsed) → MergedConfig` (deep-merge of parsed config over canonical defaults), `migrateOnDisk(cwd) → MigrationReport` (explicit, opt-in, called by the installer and by `gsd-tools migrate-config`). Invariants: never mutates disk inside `loadConfig`; legacy top-level keys (`branching_strategy`, `sub_repos`, `multiRepo`, `depth`) are normalized into their canonical nested locations in the returned value; defaults come from the shared `sdk/shared/config-defaults.manifest.json`; schema (`VALID_CONFIG_KEYS`, `RUNTIME_STATE_KEYS`, `DYNAMIC_KEY_PATTERNS`) comes from `sdk/shared/config-schema.manifest.json`. Source of truth: `sdk/src/config/index.ts`; CJS callers consume the generator-emitted `get-shit-done/bin/lib/configuration.generated.cjs` via the thin Adapters at `bin/lib/core.cjs:loadConfig` and `bin/lib/config-schema.cjs`. Eliminates the recurring #3523-class drift bug structurally.
|
||||
|
||||
### Planning Workspace Module
|
||||
Module owning `.planning` path resolution, active workstream pointer policy (`session-scoped > shared`), pointer self-heal behavior, and planning lock semantics for workstream-aware execution.
|
||||
|
||||
@@ -32,7 +32,7 @@ The table below indexes by Module, not by physical layer. Each row names the sou
|
||||
| Module | Status | Source of truth | Generated artifacts | Adapters |
|
||||
|---|---|---|---|---|
|
||||
| **STATE.md Document Module** | New under this ADR (Phase 1) — see CONTEXT.md "STATE.md Document Module" | `sdk/src/state-document/index.ts` (promoted from `sdk/src/query/state-document.ts`) | `sdk/src/query/state-document.generated.ts`, `get-shit-done/bin/lib/state-document.generated.cjs` | `bin/lib/state.cjs` and `sdk/src/query/state*.ts` import the generated form |
|
||||
| **Configuration Module** | New under this ADR (Phase 2) — definition added to CONTEXT.md as part of Phase 2 | `sdk/src/configuration/index.ts` plus data manifests `sdk/shared/config-schema.manifest.json` and `sdk/shared/config-defaults.manifest.json` | `sdk/src/query/config-schema.generated.ts`, `get-shit-done/bin/lib/config-schema.generated.cjs`, `get-shit-done/bin/lib/configuration.generated.cjs` | `bin/lib/config.cjs`, `bin/lib/core.cjs:loadConfig`, `sdk/src/config.ts` |
|
||||
| **Configuration Module** | New under this ADR (Phase 2) — definition added to CONTEXT.md as part of Phase 2 | `sdk/src/config/index.ts` plus data manifests `sdk/shared/config-schema.manifest.json` and `sdk/shared/config-defaults.manifest.json` | `sdk/src/query/config-schema.generated.ts`, `get-shit-done/bin/lib/config-schema.generated.cjs`, `get-shit-done/bin/lib/configuration.generated.cjs` | `bin/lib/config.cjs`, `bin/lib/core.cjs:loadConfig`, `sdk/src/config.ts` |
|
||||
| **Workstream Inventory Module** (Builder) | Amended under this ADR (Phase 3) — Builder split documented in CONTEXT.md update | `sdk/src/workstream-inventory/builder.ts` (pure projection from directory entries + STATE.md text + plan scan results → typed inventory) | `sdk/src/query/workstream-inventory-builder.generated.ts`, `get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs` | Per-side fs Readers (`workstream-inventory.cjs` sync, `workstream-inventory.ts` async) call the Builder. Readers stay hand-authored because the fs idiom legitimately differs. |
|
||||
| **Project-Root Resolution Module** | New under this ADR (Phase 4) — short CONTEXT.md entry, behavior already de-facto shared | `sdk/src/project-root/index.ts` | `get-shit-done/bin/lib/project-root.generated.cjs` | `bin/lib/core.cjs` (`findProjectRoot`, `findEffectiveRoot`), `sdk/src/helpers.ts` |
|
||||
| **Frontmatter Module** | Conditional (Phase 3, only if drift catalogue confirms pair duplication) | `sdk/src/frontmatter/index.ts` | `get-shit-done/bin/lib/frontmatter.generated.cjs` | Existing handler call sites |
|
||||
|
||||
@@ -89,7 +89,7 @@ Phases are sized to ship in one to two PRs each. Each phase has its own GitHub i
|
||||
**Scope:**
|
||||
- Add a **Configuration Module** entry to `CONTEXT.md` first. Definition: "Module owning config load, legacy-key normalization, defaults merge, and explicit on-disk migration for `.planning/config.json`." Interface and invariants per ADR §6.
|
||||
- Extract `CONFIG_DEFAULTS`, `VALID_CONFIG_KEYS`, `DYNAMIC_KEY_PATTERNS`, `RUNTIME_STATE_KEYS` to two data manifests: `sdk/shared/config-schema.manifest.json` and `sdk/shared/config-defaults.manifest.json`. Precedent: `sdk/shared/model-catalog.json`.
|
||||
- Write the Configuration Module source at `sdk/src/configuration/index.ts`. Implementation imports the two manifests and exports `loadConfig`, `normalizeLegacyKeys`, `mergeDefaults`, `migrateOnDisk`.
|
||||
- Write the Configuration Module source at `sdk/src/config/index.ts`. Implementation imports the two manifests and exports `loadConfig`, `normalizeLegacyKeys`, `mergeDefaults`, `migrateOnDisk`.
|
||||
- Write `sdk/scripts/gen-configuration.ts` to emit `get-shit-done/bin/lib/configuration.generated.cjs` and (if needed) `sdk/src/query/config-schema.generated.ts`.
|
||||
- Write `sdk/scripts/check-configuration-fresh.mjs`.
|
||||
- Replace the inline implementations in `bin/lib/core.cjs:loadConfig` (lines 220–243, 434–449, 485) and `bin/lib/config.cjs` (the validation surface) with thin Adapters over the generated Module. Delete the inline `CONFIG_DEFAULTS`, the false-positive warning at `core.cjs:444-449`, and the duplicated `_deepMergeConfig`.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* GENERATED FILE — DO NOT EDIT.
|
||||
*
|
||||
* Source: sdk/src/configuration/index.ts
|
||||
* Source: sdk/src/config/index.ts
|
||||
* Regenerate: cd sdk && npm run gen:configuration
|
||||
*
|
||||
* Configuration Module — single source of truth for config loading,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Generator for get-shit-done/bin/lib/configuration.generated.cjs.
|
||||
*
|
||||
* Reads the compiled Configuration Module from sdk/dist/configuration/index.js
|
||||
* Reads the compiled Configuration Module from sdk/dist/config/index.js
|
||||
* and emits a CJS file that:
|
||||
* 1. Requires the two JSON manifests from sdk/shared/
|
||||
* 2. Exports loadConfig, normalizeLegacyKeys, mergeDefaults, migrateOnDisk,
|
||||
@@ -17,14 +17,14 @@ import { fileURLToPath } from 'node:url';
|
||||
import { resolve, dirname } from 'node:path';
|
||||
import { requireFreshDist } from './_gen-helpers.mjs';
|
||||
|
||||
requireFreshDist('sdk/dist/configuration/index.js', 'sdk/src/configuration/index.ts');
|
||||
requireFreshDist('sdk/dist/config/index.js', 'sdk/src/config/index.ts');
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(here, '..', '..');
|
||||
|
||||
// ─── Read the compiled dist file for function extraction ─────────────────────
|
||||
|
||||
const distPath = resolve(here, '..', 'dist', 'configuration', 'index.js');
|
||||
const distPath = resolve(here, '..', 'dist', 'config', 'index.js');
|
||||
const distSrc = readFileSync(distPath, 'utf-8');
|
||||
|
||||
/**
|
||||
@@ -85,7 +85,7 @@ export function buildConfigurationCjs() {
|
||||
`/**`,
|
||||
` * GENERATED FILE — DO NOT EDIT.`,
|
||||
` *`,
|
||||
` * Source: sdk/src/configuration/index.ts`,
|
||||
` * Source: sdk/src/config/index.ts`,
|
||||
` * Regenerate: cd sdk && npm run gen:configuration`,
|
||||
` *`,
|
||||
` * Configuration Module — single source of truth for config loading,`,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
CONFIG_DEFAULTS as CANONICAL_CONFIG_DEFAULTS,
|
||||
mergeDefaults as canonicalMergeDefaults,
|
||||
normalizeLegacyKeys,
|
||||
} from './configuration/index.js';
|
||||
} from './config/index.js';
|
||||
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Pinning tests for the Configuration Module (ADR-3524 §6).
|
||||
*
|
||||
* These tests pin the public interface contract. They are RED until
|
||||
* sdk/src/configuration/index.ts is created (Cycle 2).
|
||||
* sdk/src/config/index.ts is created (Cycle 2).
|
||||
*
|
||||
* Test precedent: sdk/src/config.test.ts (vitest + fs fixtures).
|
||||
*/
|
||||
@@ -24,7 +24,7 @@ import { join } from 'node:path';
|
||||
import { GSDError, ErrorClassification } from '../errors.js';
|
||||
import { VALID_PROFILES, getAgentToModelMapForProfile } from './config-query.js';
|
||||
import { VALID_CONFIG_KEYS, RUNTIME_STATE_KEYS, DYNAMIC_KEY_PATTERNS } from './config-schema.js';
|
||||
import { CONFIG_DEFAULTS } from '../configuration/index.js';
|
||||
import { CONFIG_DEFAULTS } from '../config/index.js';
|
||||
import { planningPaths } from './helpers.js';
|
||||
import { acquireStateLock, releaseStateLock } from './state-mutation.js';
|
||||
import { maskIfSecret } from './secrets.js';
|
||||
@@ -569,7 +569,7 @@ export const configNewProject: QueryHandler = async (args, projectDir, workstrea
|
||||
|
||||
// Build default config. Source is the canonical Configuration Module manifest
|
||||
// at sdk/shared/config-defaults.manifest.json (CONFIG_DEFAULTS from
|
||||
// sdk/src/configuration/index.ts) — but ONLY a subset is materialized at
|
||||
// sdk/src/config/index.ts) — but ONLY a subset is materialized at
|
||||
// init time. Legacy CJS `buildNewProjectConfig` (bin/lib/config.cjs:155-210)
|
||||
// intentionally omits keys whose value is meaningful only when set
|
||||
// explicitly so config-get returns "Key not found" and workflows fall back
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Thin re-export adapter — sources schema data from the Configuration Module
|
||||
* (sdk/src/configuration/index.ts), which reads from the manifest at
|
||||
* (sdk/src/config/index.ts), which reads from the manifest at
|
||||
* sdk/shared/config-schema.manifest.json.
|
||||
*
|
||||
* All inline literals have been removed. The manifest is the single source
|
||||
@@ -18,14 +18,14 @@ import {
|
||||
VALID_CONFIG_KEYS,
|
||||
RUNTIME_STATE_KEYS,
|
||||
DYNAMIC_KEY_PATTERNS,
|
||||
} from '../configuration/index.js';
|
||||
} from '../config/index.js';
|
||||
|
||||
export {
|
||||
VALID_CONFIG_KEYS,
|
||||
RUNTIME_STATE_KEYS,
|
||||
DYNAMIC_KEY_PATTERNS,
|
||||
type DynamicKeyPattern,
|
||||
} from '../configuration/index.js';
|
||||
} from '../config/index.js';
|
||||
|
||||
/** Returns true if keyPath is a valid config key (exact, runtime-state, or dynamic pattern). */
|
||||
export function isValidConfigKeyPath(keyPath: string): boolean {
|
||||
|
||||
@@ -90,15 +90,15 @@ test('CJS DYNAMIC_KEY_PATTERNS .source fields match manifest dynamicKeyPatterns'
|
||||
|
||||
// ─── SDK side: verify config-schema.ts re-exports from configuration module ─
|
||||
|
||||
test('SDK config-schema.ts re-exports from configuration module (not inline literals)', () => {
|
||||
test('SDK config-schema.ts re-exports from config module (not inline literals)', () => {
|
||||
const SDK_SCHEMA_PATH = path.join(ROOT, 'sdk', 'src', 'query', 'config-schema.ts');
|
||||
const src = fs.readFileSync(SDK_SCHEMA_PATH, 'utf8');
|
||||
|
||||
// After Cycle 5, the file must NOT contain inline key literals.
|
||||
// It should import/re-export from '../configuration/index.js'.
|
||||
// It should import/re-export from '../config/index.js'.
|
||||
assert.ok(
|
||||
src.includes("from '../configuration/index.js'"),
|
||||
'sdk/src/query/config-schema.ts must re-export from ../configuration/index.js (not inline literals)',
|
||||
src.includes("from '../config/index.js'"),
|
||||
'sdk/src/query/config-schema.ts must re-export from ../config/index.js (not inline literals)',
|
||||
);
|
||||
|
||||
// Must NOT contain a standalone new Set([...]) block with key literals.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Parity test: configuration.generated.cjs (CJS) vs sdk/dist/configuration/index.js (ESM).
|
||||
* Parity test: configuration.generated.cjs (CJS) vs sdk/dist/config/index.js (ESM).
|
||||
*
|
||||
* For every fixture in the vitest pinning tests, asserts that both sides produce
|
||||
* identical output. This ensures the generator faithfully replicates the TS source.
|
||||
@@ -44,7 +44,7 @@ function cleanup(dir) {
|
||||
let esm;
|
||||
|
||||
before(async () => {
|
||||
esm = await import('../sdk/dist/configuration/index.js');
|
||||
esm = await import('../sdk/dist/config/index.js');
|
||||
});
|
||||
|
||||
// ─── Parity helper ────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -73,8 +73,8 @@ const GENERATORS = [
|
||||
},
|
||||
{
|
||||
script: 'gen-configuration.mjs',
|
||||
dist: 'sdk/dist/configuration/index.js',
|
||||
ts: 'sdk/src/configuration/index.ts',
|
||||
dist: 'sdk/dist/config/index.js',
|
||||
ts: 'sdk/src/config/index.ts',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user