gsdd-cli 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +53 -22
  2. package/agents/DISTILLATION.md +2 -2
  3. package/agents/README.md +4 -4
  4. package/agents/approach-explorer.md +4 -4
  5. package/agents/executor.md +14 -14
  6. package/agents/integration-checker.md +2 -2
  7. package/agents/researcher.md +2 -2
  8. package/agents/roadmapper.md +6 -6
  9. package/agents/synthesizer.md +18 -18
  10. package/agents/verifier.md +2 -2
  11. package/bin/adapters/agents.mjs +3 -3
  12. package/bin/adapters/claude.mjs +16 -14
  13. package/bin/adapters/opencode.mjs +15 -12
  14. package/bin/gsdd.mjs +16 -13
  15. package/bin/lib/{models.mjs → config.mjs} +23 -16
  16. package/bin/lib/control-map.mjs +17 -488
  17. package/bin/lib/health-truth.mjs +8 -13
  18. package/bin/lib/health.mjs +25 -39
  19. package/bin/lib/init-flow.mjs +44 -38
  20. package/bin/lib/init-prompts.mjs +3 -3
  21. package/bin/lib/init-runtime.mjs +11 -30
  22. package/bin/lib/lifecycle-preflight.mjs +97 -410
  23. package/bin/lib/lifecycle-state.mjs +2 -1
  24. package/bin/lib/next.mjs +243 -20
  25. package/bin/lib/phase.mjs +10 -315
  26. package/bin/lib/rendering.mjs +64 -44
  27. package/bin/lib/runtime-freshness.mjs +18 -15
  28. package/bin/lib/state-dir.mjs +45 -0
  29. package/bin/lib/templates.mjs +59 -22
  30. package/bin/lib/work-context.mjs +12 -1
  31. package/bin/lib/workflows.mjs +0 -1
  32. package/bin/lib/workspace-root.mjs +11 -6
  33. package/distilled/DESIGN.md +58 -2
  34. package/distilled/EVIDENCE-INDEX.md +15 -2
  35. package/distilled/README.md +23 -33
  36. package/distilled/SKILL.md +9 -10
  37. package/distilled/templates/agents.block.md +5 -5
  38. package/distilled/templates/approach.md +3 -3
  39. package/distilled/templates/auth-matrix.md +2 -2
  40. package/distilled/templates/brownfield-change/CHANGE.md +1 -1
  41. package/distilled/templates/delegates/approach-explorer.md +5 -5
  42. package/distilled/templates/delegates/mapper-arch.md +3 -3
  43. package/distilled/templates/delegates/mapper-concerns.md +4 -4
  44. package/distilled/templates/delegates/mapper-quality.md +3 -3
  45. package/distilled/templates/delegates/mapper-tech.md +3 -3
  46. package/distilled/templates/delegates/plan-checker.md +5 -5
  47. package/distilled/templates/delegates/researcher-architecture.md +3 -3
  48. package/distilled/templates/delegates/researcher-features.md +3 -3
  49. package/distilled/templates/delegates/researcher-pitfalls.md +3 -3
  50. package/distilled/templates/delegates/researcher-stack.md +3 -3
  51. package/distilled/templates/delegates/researcher-synthesizer.md +7 -7
  52. package/distilled/templates/research/architecture.md +1 -1
  53. package/distilled/templates/research/pitfalls.md +1 -1
  54. package/distilled/templates/research/stack.md +1 -1
  55. package/distilled/templates/roadmap.md +4 -4
  56. package/distilled/templates/spec.md +2 -2
  57. package/distilled/workflows/audit-milestone.md +22 -22
  58. package/distilled/workflows/complete-milestone.md +35 -35
  59. package/distilled/workflows/execute.md +29 -29
  60. package/distilled/workflows/map-codebase.md +30 -30
  61. package/distilled/workflows/new-milestone.md +18 -18
  62. package/distilled/workflows/new-project.md +45 -45
  63. package/distilled/workflows/pause.md +15 -15
  64. package/distilled/workflows/plan.md +63 -63
  65. package/distilled/workflows/progress.md +40 -39
  66. package/distilled/workflows/quick.md +43 -43
  67. package/distilled/workflows/resume.md +23 -22
  68. package/distilled/workflows/verify-work.md +7 -7
  69. package/distilled/workflows/verify.md +20 -20
  70. package/docs/BROWNFIELD-PROOF.md +1 -1
  71. package/docs/RUNTIME-SUPPORT.md +13 -13
  72. package/docs/USER-GUIDE.md +17 -20
  73. package/docs/claude/context-monitor.md +1 -1
  74. package/docs/proof/consumer-node-cli/README.md +1 -1
  75. package/package.json +3 -3
  76. package/bin/lib/closeout-report.mjs +0 -318
  77. package/bin/lib/evidence-contract.mjs +0 -325
  78. package/bin/lib/provenance.mjs +0 -390
  79. package/bin/lib/session-fingerprint.mjs +0 -223
  80. package/bin/lib/ui-proof.mjs +0 -1007
  81. package/distilled/workflows/plan-milestone-gaps.md +0 -204
@@ -10,15 +10,18 @@ import { output } from './cli-utils.mjs';
10
10
  import { runTruthChecks, TRUTH_CHECK_IDS } from './health-truth.mjs';
11
11
  import { evaluateLifecycleState } from './lifecycle-state.mjs';
12
12
  import { evaluateRuntimeFreshness } from './runtime-freshness.mjs';
13
- import { findUiProofBundleFiles, readUiProofBundleFile, validateUiProofBundle } from './ui-proof.mjs';
14
13
  import { resolveWorkspaceContext } from './workspace-root.mjs';
15
14
 
15
+ function statePath(stateDirName, relativePath = '') {
16
+ return relativePath ? `${stateDirName}/${relativePath}` : stateDirName;
17
+ }
18
+
16
19
  /**
17
20
  * Build the structured health report without printing or mutating workspace
18
21
  * state. ctx should provide: { frameworkVersion, workflows }.
19
22
  */
20
23
  export function buildHealthReport(ctx, healthArgs = []) {
21
- const { planningDir, workspaceRoot, invalid, error } = resolveWorkspaceContext(healthArgs);
24
+ const { planningDir, workspaceRoot, invalid, error, stateDirName = '.work' } = resolveWorkspaceContext(healthArgs);
22
25
  if (invalid) {
23
26
  return {
24
27
  status: 'broken',
@@ -30,13 +33,13 @@ export function buildHealthReport(ctx, healthArgs = []) {
30
33
  }
31
34
  const cwd = workspaceRoot;
32
35
  const frameworkSourceMode = isFrameworkSourceRepo(cwd);
33
- const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'E10', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];
36
+ const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];
34
37
 
35
38
  // Pre-init guard
36
39
  if (!existsSync(join(planningDir, 'config.json'))) {
37
40
  return {
38
41
  status: 'broken',
39
- errors: [{ id: 'E1', severity: 'ERROR', message: '.planning/config.json missing', fix: 'Run `npx -y gsdd-cli init`' }],
42
+ errors: [{ id: 'E1', severity: 'ERROR', message: `${statePath(stateDirName, 'config.json')} missing`, fix: 'Run `npx -y gsdd-cli init`' }],
40
43
  warnings: [],
41
44
  info: [],
42
45
  humanMessage: 'Not initialized. Run `npx -y gsdd-cli init`. If `gsdd` is installed globally, `gsdd init` is also fine.',
@@ -62,7 +65,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
62
65
  errors.push({ id: 'E2', severity: 'ERROR', message: `config.json missing required fields: ${missing.join(', ')}`, fix: 'Run `npx -y gsdd-cli init` to regenerate' });
63
66
  }
64
67
  } catch {
65
- errors.push({ id: 'E1', severity: 'ERROR', message: '.planning/config.json is unparseable', fix: 'Run `npx -y gsdd-cli init`' });
68
+ errors.push({ id: 'E1', severity: 'ERROR', message: `${statePath(stateDirName, 'config.json')} is unparseable`, fix: 'Run `npx -y gsdd-cli init`' });
66
69
  }
67
70
 
68
71
  // E3: templates/ missing
@@ -77,47 +80,47 @@ export function buildHealthReport(ctx, healthArgs = []) {
77
80
  const skipInstalledTemplateChecks = !hasTemplatesDir && frameworkSourceMode;
78
81
 
79
82
  if (!hasTemplatesDir && !skipInstalledTemplateChecks) {
80
- errors.push({ id: 'E3', severity: 'ERROR', message: '.planning/templates/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
83
+ errors.push({ id: 'E3', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
81
84
  } else if (hasTemplatesDir) {
82
85
  // E4: roles/ missing or empty
83
86
  if (!hasRolesDir) {
84
- errors.push({ id: 'E4', severity: 'ERROR', message: '.planning/templates/roles/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
87
+ errors.push({ id: 'E4', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/roles/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
85
88
  } else {
86
89
  const roleFiles = readdirSync(rolesDir).filter((f) => f.endsWith('.md'));
87
90
  if (roleFiles.length === 0) {
88
- errors.push({ id: 'E4', severity: 'ERROR', message: '.planning/templates/roles/ has 0 role files', fix: 'Run `npx -y gsdd-cli update --templates`' });
91
+ errors.push({ id: 'E4', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/roles/')} has 0 role files`, fix: 'Run `npx -y gsdd-cli update --templates`' });
89
92
  }
90
93
  }
91
94
 
92
95
  // E5: delegates/ missing or empty
93
96
  if (!hasDelegatesDir) {
94
- errors.push({ id: 'E5', severity: 'ERROR', message: '.planning/templates/delegates/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
97
+ errors.push({ id: 'E5', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/delegates/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
95
98
  } else {
96
99
  const delegateFiles = readdirSync(delegatesDir).filter((f) => f.endsWith('.md'));
97
100
  if (delegateFiles.length === 0) {
98
- errors.push({ id: 'E5', severity: 'ERROR', message: '.planning/templates/delegates/ has 0 delegate files', fix: 'Run `npx -y gsdd-cli update --templates`' });
101
+ errors.push({ id: 'E5', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/delegates/')} has 0 delegate files`, fix: 'Run `npx -y gsdd-cli update --templates`' });
99
102
  }
100
103
  }
101
104
 
102
105
  // E6: research/ missing or empty
103
106
  const researchDir = join(templatesDir, 'research');
104
107
  if (!existsSync(researchDir)) {
105
- errors.push({ id: 'E6', severity: 'ERROR', message: '.planning/templates/research/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
108
+ errors.push({ id: 'E6', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/research/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
106
109
  } else {
107
110
  const researchFiles = readdirSync(researchDir).filter((f) => f.endsWith('.md'));
108
111
  if (researchFiles.length === 0) {
109
- errors.push({ id: 'E6', severity: 'ERROR', message: '.planning/templates/research/ has 0 template files', fix: 'Run `npx -y gsdd-cli update --templates`' });
112
+ errors.push({ id: 'E6', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/research/')} has 0 template files`, fix: 'Run `npx -y gsdd-cli update --templates`' });
110
113
  }
111
114
  }
112
115
 
113
116
  // E7: codebase/ missing or empty
114
117
  const codebaseDir = join(templatesDir, 'codebase');
115
118
  if (!existsSync(codebaseDir)) {
116
- errors.push({ id: 'E7', severity: 'ERROR', message: '.planning/templates/codebase/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
119
+ errors.push({ id: 'E7', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/codebase/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
117
120
  } else {
118
121
  const codebaseFiles = readdirSync(codebaseDir).filter((f) => f.endsWith('.md'));
119
122
  if (codebaseFiles.length === 0) {
120
- errors.push({ id: 'E7', severity: 'ERROR', message: '.planning/templates/codebase/ has 0 template files', fix: 'Run `npx -y gsdd-cli update --templates`' });
123
+ errors.push({ id: 'E7', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/codebase/')} has 0 template files`, fix: 'Run `npx -y gsdd-cli update --templates`' });
121
124
  }
122
125
  }
123
126
 
@@ -125,37 +128,20 @@ export function buildHealthReport(ctx, healthArgs = []) {
125
128
  const requiredRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md', 'ui-proof.md'];
126
129
  const missingRoot = requiredRootFiles.filter((f) => !existsSync(join(templatesDir, f)));
127
130
  if (missingRoot.length > 0) {
128
- errors.push({ id: 'E8', severity: 'ERROR', message: `.planning/templates/ missing critical root files: ${missingRoot.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
131
+ errors.push({ id: 'E8', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/')} missing critical root files: ${missingRoot.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
129
132
  }
130
133
 
131
134
  const brownfieldChangeDir = join(templatesDir, 'brownfield-change');
132
135
  if (!existsSync(brownfieldChangeDir)) {
133
- errors.push({ id: 'E9', severity: 'ERROR', message: '.planning/templates/brownfield-change/ missing', fix: 'Run `npx -y gsdd-cli update --templates`' });
136
+ errors.push({ id: 'E9', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/brownfield-change/')} missing`, fix: 'Run `npx -y gsdd-cli update --templates`' });
134
137
  } else {
135
138
  const missingBrownfield = ['CHANGE.md', 'HANDOFF.md', 'VERIFICATION.md'].filter((file) => !existsSync(join(brownfieldChangeDir, file)));
136
139
  if (missingBrownfield.length > 0) {
137
- errors.push({ id: 'E9', severity: 'ERROR', message: `.planning/templates/brownfield-change/ missing critical files: ${missingBrownfield.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
140
+ errors.push({ id: 'E9', severity: 'ERROR', message: `${statePath(stateDirName, 'templates/brownfield-change/')} missing critical files: ${missingBrownfield.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
138
141
  }
139
142
  }
140
143
  }
141
144
 
142
- // E10: known UI proof bundles must satisfy deterministic metadata/privacy validation.
143
- for (const bundlePath of findUiProofBundleFiles(planningDir)) {
144
- const relativePath = relative(cwd, bundlePath).replace(/\\/g, '/');
145
- const parsed = readUiProofBundleFile(bundlePath);
146
- const validation = parsed.errors.length > 0
147
- ? { valid: false, errors: parsed.errors }
148
- : validateUiProofBundle(parsed.bundle, { requireLocalArtifactExists: true, workspaceRoot: cwd });
149
- if (!validation.valid) {
150
- errors.push({
151
- id: 'E10',
152
- severity: 'ERROR',
153
- message: `${relativePath} has invalid UI proof metadata (${validation.errors.map((entry) => entry.code).join(', ')})`,
154
- fix: 'Run `gsdd ui-proof validate <path>` and add required privacy metadata, claim limits, fixed evidence kinds, concise tool provenance, failure classification when failed or partial, observation artifact references, existing local artifact paths, and safe-to-publish handling.',
155
- });
156
- }
157
- }
158
-
159
145
  // --- WARNING checks ---
160
146
 
161
147
  // W1: generation-manifest.json missing
@@ -188,7 +174,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
188
174
  }
189
175
  }
190
176
 
191
- // W4: ROADMAP.md references phases not found in .planning/phases/
177
+ // W4: ROADMAP.md references phases not found in the resolved state phases directory.
192
178
  const roadmapPath = join(planningDir, 'ROADMAP.md');
193
179
  const phasesDir = join(planningDir, 'phases');
194
180
  const roadmap = existsSync(roadmapPath) ? readFileSync(roadmapPath, 'utf-8') : null;
@@ -199,7 +185,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
199
185
  warnings.push({
200
186
  id: 'W4',
201
187
  severity: 'WARN',
202
- message: `ROADMAP.md references active Phase ${phase.number} but no files found in .planning/phases/`,
188
+ message: `ROADMAP.md references active Phase ${phase.number} but no files found in ${statePath(stateDirName, 'phases/')}`,
203
189
  fix: 'Create missing phase dirs or update ROADMAP',
204
190
  });
205
191
  }
@@ -208,7 +194,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
208
194
  // W5: Phase dir has PLAN but no SUMMARY (stale in-progress)
209
195
  if (lifecycle.incompletePlans.length > 0) {
210
196
  for (const plan of lifecycle.incompletePlans) {
211
- const expectedSummary = `.planning/phases/${plan.dir}/${plan.baseId}-SUMMARY.md`;
197
+ const expectedSummary = statePath(stateDirName, `phases/${plan.dir}/${plan.baseId}-SUMMARY.md`);
212
198
  warnings.push({
213
199
  id: 'W5',
214
200
  severity: 'WARN',
@@ -227,7 +213,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
227
213
  ? evaluateRuntimeFreshness({ cwd, workflows: ctx.workflows })
228
214
  : null;
229
215
 
230
- warnings.push(...runTruthChecks(planningDir, cwd, healthCheckIds, { runtimeFreshnessReport }).map((warning) => {
216
+ warnings.push(...runTruthChecks(planningDir, cwd, healthCheckIds, { runtimeFreshnessReport, stateDirName }).map((warning) => {
231
217
  if (warning.id !== 'W10') return warning;
232
218
  return {
233
219
  ...warning,
@@ -235,7 +221,7 @@ export function buildHealthReport(ctx, healthArgs = []) {
235
221
  /^ROADMAP\/SPEC requirement status drift/,
236
222
  'ROADMAP lifecycle status drift (requirement checkbox and/or overview/detail phase status mismatch)'
237
223
  ),
238
- fix: 'Reconcile .planning/ROADMAP.md overview/detail phase markers and .planning/SPEC.md requirement checkboxes',
224
+ fix: `Reconcile ${statePath(stateDirName, 'ROADMAP.md')} overview/detail phase markers and ${statePath(stateDirName, 'SPEC.md')} requirement checkboxes`,
239
225
  };
240
226
  }));
241
227
 
@@ -3,7 +3,7 @@ import { dirname, join, isAbsolute } from 'path';
3
3
  import { buildPlanningCliHelperEntries, renderSkillContent } from './rendering.mjs';
4
4
  import { buildManifest, readManifest, writeManifest } from './manifest.mjs';
5
5
  import { parseFlagValue, parseToolsFlag, parseAutoFlag } from './cli-utils.mjs';
6
- import { buildDefaultConfig, COST_PROFILES, RIGOR_PROFILES } from './models.mjs';
6
+ import { buildDefaultConfig, COST_PROFILES, RIGOR_PROFILES } from './config.mjs';
7
7
  import { installProjectTemplates, refreshTemplates } from './templates.mjs';
8
8
  import {
9
9
  detectPlatforms,
@@ -84,34 +84,36 @@ export function createCmdInit(ctx) {
84
84
  parsedTools,
85
85
  isAuto,
86
86
  });
87
+ const { planningDir, stateDirName } = ctx;
87
88
 
88
- const existed = existsSync(ctx.planningDir);
89
- mkdirSync(join(ctx.planningDir, 'phases'), { recursive: true });
90
- mkdirSync(join(ctx.planningDir, 'research'), { recursive: true });
89
+ const existed = existsSync(planningDir);
90
+ mkdirSync(join(planningDir, 'phases'), { recursive: true });
91
+ mkdirSync(join(planningDir, 'research'), { recursive: true });
91
92
  console.log(existed
92
- ? ' - .planning/ already exists (ensured subdirectories)'
93
- : ' - created .planning/ directory structure');
93
+ ? ` - ${stateDirName}/ already exists (ensured subdirectories)`
94
+ : ` - created ${stateDirName}/ directory structure`);
94
95
 
95
96
  installProjectTemplates(ctx);
96
97
  await ensureConfig({
97
98
  cwd: ctx.cwd,
98
- planningDir: ctx.planningDir,
99
+ planningDir,
99
100
  isAuto,
100
101
  promptApi,
101
102
  preselectedConfig: interactiveSession.config,
103
+ stateDirName,
102
104
  });
103
- ensureGitignoreEntry(ctx.cwd, '.planning/.local/', ' - ensured .planning/.local/ is gitignored');
105
+ ensureGitignoreEntry(ctx.cwd, `${stateDirName}/.local/`, ` - ensured ${stateDirName}/.local/ is gitignored`);
104
106
 
105
107
  if (briefSource) {
106
- cpSync(briefSource, join(ctx.planningDir, 'PROJECT_BRIEF.md'));
107
- console.log(' - copied project brief to .planning/PROJECT_BRIEF.md');
108
+ cpSync(briefSource, join(planningDir, 'PROJECT_BRIEF.md'));
109
+ console.log(` - copied project brief to ${stateDirName}/PROJECT_BRIEF.md`);
108
110
  }
109
111
 
110
- generateOpenStandardSkills(ctx.cwd, ctx.workflows);
112
+ generateOpenStandardSkills(ctx.cwd, ctx.workflows, { stateDirName });
111
113
  console.log(' - generated open-standard skills (.agents/skills/gsdd-*)');
112
114
 
113
115
  generatePlanningCliHelpers(ctx);
114
- console.log(' - generated local workflow helpers (.planning/bin/gsdd*)');
116
+ console.log(` - generated local workflow helpers (${stateDirName}/bin/gsdd*)`);
115
117
 
116
118
  for (const adapter of resolveAdapters(ctx.adapters, interactiveSession.adapterTargets)) {
117
119
  adapter.generate();
@@ -119,8 +121,8 @@ export function createCmdInit(ctx) {
119
121
  console.log(` - ${adapter.summary('generated')}`);
120
122
  }
121
123
 
122
- const manifest = buildManifest({ planningDir: ctx.planningDir, frameworkVersion: ctx.frameworkVersion });
123
- writeManifest(ctx.planningDir, manifest);
124
+ const manifest = buildManifest({ planningDir, frameworkVersion: ctx.frameworkVersion });
125
+ writeManifest(planningDir, manifest);
124
126
  console.log(' - wrote generation manifest');
125
127
 
126
128
  console.log('\n\x1B[1m\x1B[32m✓ GSDD initialized.\x1B[0m');
@@ -135,6 +137,7 @@ export function createCmdUpdate(ctx) {
135
137
  return function cmdUpdate(...updateArgs) {
136
138
  const isDry = updateArgs.includes('--dry');
137
139
  const doTemplates = updateArgs.includes('--templates');
140
+ const { planningDir, stateDirName } = ctx;
138
141
 
139
142
  console.log(`gsdd update - regenerating adapter files${isDry ? ' (dry run)' : ''}\n`);
140
143
 
@@ -149,22 +152,22 @@ export function createCmdUpdate(ctx) {
149
152
  updated = true;
150
153
  }
151
154
 
152
- if (platforms.length > 0 || existsSync(ctx.planningDir) || hasGeneratedOpenStandardSkills(ctx.cwd)) {
155
+ if (platforms.length > 0 || existsSync(planningDir) || hasGeneratedOpenStandardSkills(ctx.cwd)) {
153
156
  if (isDry) {
154
157
  console.log(' - would update open-standard skills (.agents/skills/gsdd-*)');
155
158
  } else {
156
- generateOpenStandardSkills(ctx.cwd, ctx.workflows);
159
+ generateOpenStandardSkills(ctx.cwd, ctx.workflows, { stateDirName });
157
160
  console.log(' - updated open-standard skills (.agents/skills/gsdd-*)');
158
161
  }
159
162
  updated = true;
160
163
  }
161
164
 
162
- if (existsSync(ctx.planningDir)) {
165
+ if (existsSync(planningDir)) {
163
166
  if (isDry) {
164
- console.log(' - would update local workflow helpers (.planning/bin/gsdd*)');
167
+ console.log(` - would update local workflow helpers (${stateDirName}/bin/gsdd*)`);
165
168
  } else {
166
169
  generatePlanningCliHelpers(ctx);
167
- console.log(' - updated local workflow helpers (.planning/bin/gsdd*)');
170
+ console.log(` - updated local workflow helpers (${stateDirName}/bin/gsdd*)`);
168
171
  }
169
172
  updated = true;
170
173
  }
@@ -185,14 +188,14 @@ export function createCmdUpdate(ctx) {
185
188
  } else if (isDry) {
186
189
  console.log('\nDry run complete. No files were written.\n');
187
190
  } else {
188
- if (existsSync(ctx.planningDir)) {
191
+ if (existsSync(planningDir)) {
189
192
  const manifest = buildUpdateManifest({
190
- planningDir: ctx.planningDir,
193
+ planningDir,
191
194
  frameworkVersion: ctx.frameworkVersion,
192
195
  updateTemplates: doTemplates,
193
196
  });
194
197
  if (manifest) {
195
- writeManifest(ctx.planningDir, manifest);
198
+ writeManifest(planningDir, manifest);
196
199
  console.log(' - updated generation manifest');
197
200
  }
198
201
  }
@@ -216,20 +219,21 @@ function hasGeneratedOpenStandardSkills(cwd) {
216
219
  }
217
220
  }
218
221
 
219
- function generateOpenStandardSkills(cwd, workflows) {
222
+ function generateOpenStandardSkills(cwd, workflows, { stateDirName = '.work' } = {}) {
220
223
  for (const workflow of workflows) {
221
224
  const dir = join(cwd, '.agents', 'skills', workflow.name);
222
225
  mkdirSync(dir, { recursive: true });
223
- writeFileSync(join(dir, 'SKILL.md'), renderSkillContent(workflow));
226
+ writeFileSync(join(dir, 'SKILL.md'), renderSkillContent(workflow, { stateDirName }));
224
227
  }
225
228
  }
226
229
 
227
- function generatePlanningCliHelpers(ctx) {
230
+ function generatePlanningCliHelpers({ packageName, packageVersion, planningDir, stateDirName = '.work' }) {
228
231
  for (const entry of buildPlanningCliHelperEntries({
229
- packageName: ctx.packageName,
230
- packageVersion: ctx.packageVersion,
232
+ packageName,
233
+ packageVersion,
234
+ stateDirName,
231
235
  })) {
232
- const absolutePath = join(ctx.planningDir, entry.relativePath);
236
+ const absolutePath = join(planningDir, entry.relativePath);
233
237
  mkdirSync(dirname(absolutePath), { recursive: true });
234
238
  writeFileSync(absolutePath, entry.content);
235
239
  if (!absolutePath.endsWith('.cmd')) {
@@ -264,33 +268,35 @@ function stripManifestTimestamp(manifest) {
264
268
  return rest;
265
269
  }
266
270
 
267
- async function ensureConfig({ cwd, planningDir, isAuto, promptApi, preselectedConfig = null }) {
271
+ async function ensureConfig({ cwd, planningDir, stateDirName = '.work', isAuto, promptApi, preselectedConfig = null }) {
268
272
  const configFile = join(planningDir, 'config.json');
273
+ const ignoreEntry = `${stateDirName}/`;
274
+ const ignoreMsg = ` - ensured ${stateDirName}/ is gitignored`;
269
275
  if (existsSync(configFile)) {
270
- console.log(' - .planning/config.json already exists');
276
+ console.log(` - ${stateDirName}/config.json already exists`);
271
277
  return;
272
278
  }
273
279
 
274
280
  if (preselectedConfig) {
275
281
  writeFileSync(configFile, JSON.stringify(preselectedConfig, null, 2));
276
- console.log(' - saved .planning/config.json (guided wizard)\n');
277
- if (!preselectedConfig.commitDocs) ensureGitignoreEntry(cwd, '.planning/', ' - ensured .planning/ is gitignored');
282
+ console.log(` - saved ${stateDirName}/config.json (guided wizard)\n`);
283
+ if (!preselectedConfig.commitDocs) ensureGitignoreEntry(cwd, ignoreEntry, ignoreMsg);
278
284
  return;
279
285
  }
280
286
 
281
287
  if (isAuto) {
282
288
  const config = buildDefaultConfig({ autoAdvance: true });
283
289
  writeFileSync(configFile, JSON.stringify(config, null, 2));
284
- console.log(' - wrote .planning/config.json (auto defaults)\n');
285
- if (!config.commitDocs) ensureGitignoreEntry(cwd, '.planning/', ' - ensured .planning/ is gitignored');
290
+ console.log(` - wrote ${stateDirName}/config.json (auto defaults)\n`);
291
+ if (!config.commitDocs) ensureGitignoreEntry(cwd, ignoreEntry, ignoreMsg);
286
292
  return;
287
293
  }
288
294
 
289
295
  if (!process.stdin.isTTY) {
290
296
  const config = buildDefaultConfig({ autoAdvance: false });
291
297
  writeFileSync(configFile, JSON.stringify(config, null, 2));
292
- console.log(' - wrote .planning/config.json (non-interactive defaults)\n');
293
- if (!config.commitDocs) ensureGitignoreEntry(cwd, '.planning/', ' - ensured .planning/ is gitignored');
298
+ console.log(` - wrote ${stateDirName}/config.json (non-interactive defaults)\n`);
299
+ if (!config.commitDocs) ensureGitignoreEntry(cwd, ignoreEntry, ignoreMsg);
294
300
  return;
295
301
  }
296
302
 
@@ -303,8 +309,8 @@ async function ensureConfig({ cwd, planningDir, isAuto, promptApi, preselectedCo
303
309
  }
304
310
 
305
311
  writeFileSync(configFile, JSON.stringify(selected, null, 2));
306
- console.log(' - saved .planning/config.json (guided wizard)\n');
307
- if (!selected.commitDocs) ensureGitignoreEntry(cwd, '.planning/', ' - ensured .planning/ is gitignored');
312
+ console.log(` - saved ${stateDirName}/config.json (guided wizard)\n`);
313
+ if (!selected.commitDocs) ensureGitignoreEntry(cwd, ignoreEntry, ignoreMsg);
308
314
  }
309
315
 
310
316
  function ensureGitignoreEntry(cwd, entry, message) {
@@ -1,5 +1,5 @@
1
1
  import * as readline from 'readline';
2
- import { DEFAULT_GIT_PROTOCOL, resolveCost, resolveRigor } from './models.mjs';
2
+ import { DEFAULT_GIT_PROTOCOL, resolveCost, resolveRigor } from './config.mjs';
3
3
  import { buildRuntimeChoices, INIT_VERSION, resolveWizardAdapterTargets } from './init-runtime.mjs';
4
4
 
5
5
  const ANSI = {
@@ -79,8 +79,8 @@ export async function promptForConfig(cwd, { input = process.stdin, output = pro
79
79
  output,
80
80
  title: 'Planning docs in git',
81
81
  choices: [
82
- { value: true, label: 'yes', description: 'Track .planning/ in git.' },
83
- { value: false, label: 'no', description: 'Keep .planning/ local only.' },
82
+ { value: true, label: 'yes', description: 'Track .work/ in git.' },
83
+ { value: false, label: 'no', description: 'Keep .work/ local only.' },
84
84
  ],
85
85
  defaultIndex: 0,
86
86
  });
@@ -2,19 +2,19 @@ const RUNTIME_OPTIONS = [
2
2
  {
3
3
  id: 'claude',
4
4
  label: 'Claude Code',
5
- description: 'Directly validated native skills, commands, and agents with local freshness checks',
5
+ description: 'Recorded proof for native skills, commands, and agents with local freshness checks',
6
6
  kind: 'native',
7
7
  },
8
8
  {
9
9
  id: 'opencode',
10
10
  label: 'OpenCode',
11
- description: 'Directly validated native slash commands and agents with local freshness checks',
11
+ description: 'Recorded proof for native slash commands and agents with local freshness checks',
12
12
  kind: 'native',
13
13
  },
14
14
  {
15
15
  id: 'codex',
16
16
  label: 'Codex CLI',
17
- description: 'Directly validated portable skills plus native checker agents with local freshness checks',
17
+ description: 'Recorded proof for portable skills plus native checker agents with local freshness checks',
18
18
  kind: 'native',
19
19
  },
20
20
  {
@@ -163,7 +163,7 @@ export function getPostInitRoutingLines(selectedRuntimes) {
163
163
  export function getHelpText() {
164
164
  return `
165
165
  gsdd - Workspine CLI
166
- Repo-native delivery spine for long-horizon AI-assisted work across coding runtimes.
166
+ Plan, execute, and verify AI-assisted work from files in your repo — with proof before "done".
167
167
 
168
168
  Usage: gsdd <command> [args]
169
169
 
@@ -171,14 +171,14 @@ Commands:
171
171
  init [--tools <platform>] [--auto] [--brief <file>]
172
172
  Launch guided install wizard in TTYs, or use --tools for manual/headless setup
173
173
  --auto: non-interactive mode with smart defaults (requires --tools)
174
- --brief <file>: copy project brief to .planning/PROJECT_BRIEF.md
174
+ --brief <file>: copy project brief to .work/PROJECT_BRIEF.md
175
175
  install --global [--auto] [--tools <platform>] [--dry]
176
176
  Install reusable Workspine skills and native runtime surfaces into agent home directories
177
177
  --auto: non-interactive mode that installs detected local agent targets
178
178
  In TTYs, omitting --tools opens an agent picker
179
179
  update [--tools <platform>] [--templates] [--dry]
180
180
  Regenerate adapters from latest framework sources
181
- --templates: also refresh .planning/templates/ and roles
181
+ --templates: also refresh .work/templates/ and roles
182
182
  --dry: preview changes without writing files
183
183
  health [--json] Check workspace integrity (healthy/degraded/broken)
184
184
  next [--json] [--format auto|json|human] [--init]
@@ -192,18 +192,6 @@ Commands:
192
192
  phase-status <N> <status> Update ROADMAP.md phase status ([ ] / [-] / [x])
193
193
  lifecycle-preflight <surface> [phase]
194
194
  Inspect deterministic lifecycle gate results for a workflow surface
195
- session-fingerprint write [--allow-changed <ROADMAP.md,SPEC.md,config.json>]
196
- Rebaseline planning-state drift after reviewing changed planning files
197
- ui-proof validate <path> [--claim <public|publication|tracked|delivery|release>]
198
- Validate UI proof metadata; use --claim for stronger proof uses
199
- ui-proof compare <planned-slots-json> [observed-bundle-json ...]
200
- Compare planned UI proof slots against observed bundles
201
- control-map [--json] [--with-ignored] [--annotations <path>]
202
- Report computed repo/worktree/planning state and local annotations
203
- control-map annotate <set|clear>
204
- Maintain optional local intent annotations under .planning/.local/
205
- closeout-report [--json] [--phase <N>]
206
- Replay read-only closeout status from control-map, health, preflight, verify, and UI-proof signals
207
195
  help Show this summary
208
196
 
209
197
  Platforms (for --tools):
@@ -226,17 +214,17 @@ Global install targets:
226
214
  Notes:
227
215
  - use \`npx -y gsdd-cli init\` for repo-local setup; use \`npx -y gsdd-cli install --global --auto\` when you want reusable skills in detected agent homes
228
216
  - init always generates open-standard skills at .agents/skills/gsdd-*; this is the shared workflow entry surface
229
- - init also generates a local .planning/bin/gsdd* helper surface for workflow-embedded lifecycle helpers; it is internal/advanced, not the normal first-run user entrypoint
230
- - install --global never creates .planning/ in the current repo; it writes only selected agent-home surfaces and per-runtime Workspine manifests
217
+ - init also generates a local .work/bin/gsdd* helper surface for workflow-embedded lifecycle helpers; it is internal/advanced, not the normal first-run user entrypoint
218
+ - install --global never creates .work/ in the current repo; it writes only selected agent-home surfaces and per-runtime Workspine manifests
231
219
  - use \`npx -y gsdd-cli install --global --auto\` for non-interactive global install into detected agent homes; use \`--tools <targets>\` to override detection explicitly
232
220
  - repair or refresh a global install by rerunning \`npx -y gsdd-cli install --global --auto\` or \`npx -y gsdd-cli install --global --tools <targets>\`; runtime probes stay in test harnesses
233
- - Workspine is the public product name; the retained package, command, workflow, and workspace contracts stay gsdd-cli, gsdd, gsdd-*, and .planning/
221
+ - Workspine is the public product name; the retained package, command, workflow, and workspace contracts stay gsdd-cli, gsdd, gsdd-*, and .work/ (legacy planning workspaces are still read)
234
222
  - running \`npx -y gsdd-cli init\` in a terminal opens the guided runtime-selection wizard; bare \`gsdd init\` is equivalent only when globally installed
235
223
  - the wizard lets you pick runtimes first, then separately decide whether repo-wide AGENTS.md governance is worth installing
236
- - \`npx -y gsdd-cli health\` is for repo-local .planning/ workspaces; it compares local generated surfaces and points back to \`npx -y gsdd-cli update\` when they drift
224
+ - \`npx -y gsdd-cli health\` is for repo-local .work/ workspaces; it compares local generated surfaces and points back to \`npx -y gsdd-cli update\` when they drift
237
225
  - \`npx -y gsdd-cli next --init\` bootstraps the local .work continuity surface; plain \`next\` is read-only and emits a typed next-action packet
238
226
  - \`gsdd next\` defaults to JSON when stdout is captured; use \`--format human\` for the compact supervisor card
239
- - directly validated launch surfaces in this repo are Claude Code, OpenCode, and Codex CLI
227
+ - recorded launch proof in this repo currently covers Claude Code, OpenCode, and Codex CLI paths
240
228
  - Cursor, Copilot, and Gemini are qualified support through the shared .agents/skills/ surface plus optional governance
241
229
  - --tools remains the advanced/manual path and preserves legacy runtime aliases for backward compatibility
242
230
  - --tools codex generates .codex/agents/gsdd-plan-checker.toml (portable skill is the entry surface; $gsdd-plan is plan-only until explicit $gsdd-execute)
@@ -266,8 +254,6 @@ Examples:
266
254
  npx -y gsdd-cli next --init
267
255
  npx -y gsdd-cli find-phase
268
256
  npx -y gsdd-cli verify 1
269
- npx -y gsdd-cli control-map annotate set --id canonical --write-set src/app.ts
270
- npx -y gsdd-cli control-map annotate clear --id canonical
271
257
  npx -y gsdd-cli scaffold phase 4 Payments
272
258
 
273
259
  Workflows (run via skills/adapters generated by init, not direct CLI):
@@ -280,7 +266,6 @@ Workflows (run via skills/adapters generated by init, not direct CLI):
280
266
  gsdd-audit-milestone Cross-phase integration, requirements coverage, and E2E audit
281
267
  gsdd-complete-milestone Archive a shipped milestone and collapse roadmap state
282
268
  gsdd-new-milestone Start the next milestone with goals, requirements, and phases
283
- gsdd-plan-milestone-gaps Turn milestone-audit gaps into closure phases
284
269
  gsdd-quick Bounded brownfield lane for sub-hour work
285
270
  gsdd-pause Save session context to checkpoint
286
271
  gsdd-resume Restore context and route to the next action
@@ -293,11 +278,7 @@ Starting lanes after init:
293
278
 
294
279
  Advanced/internal helpers (kept available, but not the primary first-run user story):
295
280
  lifecycle-preflight Inspect deterministic lifecycle gate results for a workflow surface
296
- session-fingerprint Rebaseline the local planning-state fingerprint after review
297
281
  phase-status Update ROADMAP.md phase status through the local helper surface
298
- ui-proof Validate UI proof metadata and compare planned slots to observed bundles
299
- control-map Report computed repo/worktree/planning state; annotate only records local intent
300
- closeout-report Read-only post-merge closure replay; reports blockers, warnings, and next safe action
301
282
  next Read-only \`.work\` continuity router for the next coherent agent action
302
283
  file-op Deterministic workspace-confined file copy/delete/text mutation
303
284
  `;