gsdd-cli 0.19.3 → 0.21.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.
- package/README.md +1 -0
- package/agents/executor.md +3 -0
- package/agents/planner.md +11 -1
- package/agents/verifier.md +2 -0
- package/bin/gsdd.mjs +4 -5
- package/bin/lib/health.mjs +21 -3
- package/bin/lib/init-runtime.mjs +7 -1
- package/bin/lib/lifecycle-preflight.mjs +5 -0
- package/bin/lib/lifecycle-state.mjs +1 -1
- package/bin/lib/rendering.mjs +8 -1
- package/bin/lib/session-fingerprint.mjs +42 -2
- package/bin/lib/templates.mjs +1 -1
- package/bin/lib/ui-proof.mjs +849 -0
- package/distilled/DESIGN.md +45 -1
- package/distilled/EVIDENCE-INDEX.md +7 -0
- package/distilled/templates/delegates/plan-checker.md +2 -0
- package/distilled/templates/ui-proof.md +174 -0
- package/distilled/workflows/audit-milestone.md +1 -0
- package/distilled/workflows/execute.md +7 -8
- package/distilled/workflows/plan-milestone-gaps.md +21 -0
- package/distilled/workflows/plan.md +9 -8
- package/distilled/workflows/quick.md +6 -0
- package/distilled/workflows/verify.md +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -346,6 +346,7 @@ Workflows are agent skills or commands, not plain shell utilities. How you invok
|
|
|
346
346
|
| `npx -y gsdd-cli init [--tools <platform>]` | Set up `.planning/`, generate skills/adapters |
|
|
347
347
|
| `npx -y gsdd-cli update [--tools <platform>] [--templates]` | Regenerate skills/adapters and refresh the repo-local helper runtime; `--templates` refreshes `.planning/templates/` and role contracts |
|
|
348
348
|
| `npx -y gsdd-cli health [--json]` | Check workspace integrity and generated-surface freshness (healthy/degraded/broken) |
|
|
349
|
+
| `npx -y gsdd-cli ui-proof validate <path> [--claim <public\|publication\|tracked\|delivery\|release>]` | Validate UI proof bundle metadata without requiring browser tooling; use `--claim` only when validating that stronger proof use |
|
|
349
350
|
| `npx -y gsdd-cli file-op <copy\|delete\|regex-sub>` | Run deterministic workspace-confined file copy, delete, and regex substitution |
|
|
350
351
|
| `npx -y gsdd-cli find-phase [N]` | Show phase info as JSON (for agent consumption) |
|
|
351
352
|
| `npx -y gsdd-cli phase-status <N> <status>` | Update a single ROADMAP phase status through the status-aware helper |
|
package/agents/executor.md
CHANGED
|
@@ -209,6 +209,9 @@ Before reporting a task complete:
|
|
|
209
209
|
- if a UI change is involved, verify the relevant rendering path
|
|
210
210
|
- if an API change is involved, hit the endpoint or targeted integration path
|
|
211
211
|
- A task is not complete because code was written. It is complete when the intended verification path actually passes.
|
|
212
|
+
|
|
213
|
+
### UI Proof Execution
|
|
214
|
+
If the plan defines UI proof slots, record observed proof against the exact claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit before claiming task completion. Artifact metadata must include `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; raw screenshots, traces, videos, DOM snapshots, and reports are local-only/unsafe by default and cannot back public, tracked, delivery, release, or publication proof claims. Use `gsdd ui-proof validate <path>` or `gsdd health` when a bundle exists. Artifact count, source comments, AST/cAST findings, semantic search, and Semble-like retrieval are not proof. Missing or weakly linked evidence must be recorded as proof debt, waiver, deferment, or reduced claim language rather than satisfied proof.
|
|
212
215
|
</execution_loop>
|
|
213
216
|
|
|
214
217
|
<checkpoint_protocol>
|
package/agents/planner.md
CHANGED
|
@@ -153,6 +153,14 @@ Any checkpoint must be justified by the task itself, not by planner caution or h
|
|
|
153
153
|
Any plan containing `checkpoint:*` must set `autonomous: false`.
|
|
154
154
|
</task_contract>
|
|
155
155
|
|
|
156
|
+
<ui_proof_planning>
|
|
157
|
+
For UI-sensitive work, plan proof slots that can later be matched exactly to claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit. Use only the stable evidence kinds `code`, `test`, `runtime`, `delivery`, and `human`.
|
|
158
|
+
|
|
159
|
+
Require observed artifacts to carry `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; when a planned slot is meant to support public, publication, tracked, delivery, or release proof, say to validate the observed bundle with `gsdd ui-proof validate <path> --claim <...>`. `gsdd ui-proof validate`/`gsdd health` must catch invalid bundle metadata when present.
|
|
160
|
+
|
|
161
|
+
Do not let source annotations, AST/cAST findings, semantic search, comments, or Semble-like retrieval satisfy proof slots; they are discovery hints only. Human acceptance can narrow or waive a claim and record proof debt, but it must not turn missing or mismatched non-human evidence into `satisfied` proof.
|
|
162
|
+
</ui_proof_planning>
|
|
163
|
+
|
|
156
164
|
<dependency_graph_example>
|
|
157
165
|
Example dependency graph:
|
|
158
166
|
|
|
@@ -184,7 +192,7 @@ Wave rule:
|
|
|
184
192
|
Write one or more `PLAN.md` files to the phase directory.
|
|
185
193
|
|
|
186
194
|
Keep the current GSDD schema exactly:
|
|
187
|
-
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `runtime`, `assurance`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `non_goals`, `hard_boundaries`, `escalation_triggers`, `approval_gates`, `anti_regression_targets`, `known_unknowns`, `high_leverage_surfaces`, `second_pass_required`, `closure_claim_limit`, `parallelism_budget`, `leverage`, `must_haves`
|
|
195
|
+
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `runtime`, `assurance`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `non_goals`, `hard_boundaries`, `escalation_triggers`, `approval_gates`, `anti_regression_targets`, `known_unknowns`, `ui_proof_slots`, `no_ui_proof_rationale`, `high_leverage_surfaces`, `second_pass_required`, `closure_claim_limit`, `parallelism_budget`, `leverage`, `must_haves`
|
|
188
196
|
- typed tasks with `files`, `action`, `verify`, and `done`
|
|
189
197
|
|
|
190
198
|
Typed frontmatter example:
|
|
@@ -215,6 +223,8 @@ anti_regression_targets:
|
|
|
215
223
|
- Existing session middleware behavior remains unchanged for already-supported routes.
|
|
216
224
|
known_unknowns:
|
|
217
225
|
- Exact copy wording for auth errors may still need product confirmation.
|
|
226
|
+
ui_proof_slots: []
|
|
227
|
+
no_ui_proof_rationale: Not UI-sensitive; scoped work does not claim a visible UI outcome.
|
|
218
228
|
high_leverage_surfaces: []
|
|
219
229
|
second_pass_required: false
|
|
220
230
|
closure_claim_limit: Do not claim phase completion until verification satisfies the evidence contract for the scoped truths.
|
package/agents/verifier.md
CHANGED
|
@@ -123,6 +123,8 @@ Do not return a flat symptom list when the same underlying breakage explains mul
|
|
|
123
123
|
|
|
124
124
|
Visual correctness, live interaction quality, and some external integrations still need explicit human checks.
|
|
125
125
|
|
|
126
|
+
For UI proof slots, fail closed unless observed proof is matched to the exact claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit. Artifact metadata must include `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; local-only or unsafe artifacts cannot back public, tracked, delivery, release, or publication proof claims, and `gsdd ui-proof validate`/`gsdd health` metadata failures block the stronger proof claim. Screenshots, traces, reports, Gherkin, a11y scans, E2E outputs, manual notes, source annotations, AST/cAST findings, semantic search, comments, and Semble-like retrieval do not satisfy proof by existence alone. Human acceptance records risk, waiver, deferment, proof debt, or a narrowed claim; it does not upgrade missing or mismatched non-human proof to `satisfied`.
|
|
127
|
+
|
|
126
128
|
## Step 9: Determine overall status
|
|
127
129
|
|
|
128
130
|
- `passed` when all programmatic checks pass and no human-only checks remain
|
package/bin/gsdd.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import { cmdFileOp } from './lib/file-ops.mjs';
|
|
|
19
19
|
import { createCmdHealth } from './lib/health.mjs';
|
|
20
20
|
import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
|
|
21
21
|
import { cmdSessionFingerprint } from './lib/session-fingerprint.mjs';
|
|
22
|
+
import { cmdUiProof } from './lib/ui-proof.mjs';
|
|
22
23
|
import { resolveWorkspaceContext } from './lib/workspace-root.mjs';
|
|
23
24
|
|
|
24
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -107,6 +108,7 @@ const COMMANDS = {
|
|
|
107
108
|
'file-op': cmdFileOp,
|
|
108
109
|
'lifecycle-preflight': cmdLifecyclePreflight,
|
|
109
110
|
'session-fingerprint': cmdSessionFingerprint,
|
|
111
|
+
'ui-proof': cmdUiProof,
|
|
110
112
|
'find-phase': cmdFindPhase,
|
|
111
113
|
'phase-status': cmdPhaseStatus,
|
|
112
114
|
verify: cmdVerify,
|
|
@@ -132,8 +134,5 @@ async function runCli(cliCommand = command, ...cliArgs) {
|
|
|
132
134
|
await COMMANDS[cliCommand](...normalizedArgs);
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
if (IS_MAIN)
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdSessionFingerprint, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
|
|
137
|
+
if (IS_MAIN) await runCli();
|
|
138
|
+
export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdSessionFingerprint, cmdUiProof, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
|
package/bin/lib/health.mjs
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
// evaluate once, so CWD must be computed inside function bodies.
|
|
5
5
|
|
|
6
6
|
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
7
|
-
import { join } from 'path';
|
|
7
|
+
import { join, relative } from 'path';
|
|
8
8
|
import { readManifest, detectModifications } from './manifest.mjs';
|
|
9
9
|
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';
|
|
13
14
|
import { resolveWorkspaceContext } from './workspace-root.mjs';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -31,7 +32,7 @@ export function createCmdHealth(ctx) {
|
|
|
31
32
|
}
|
|
32
33
|
const cwd = workspaceRoot;
|
|
33
34
|
const frameworkSourceMode = isFrameworkSourceRepo(cwd);
|
|
34
|
-
const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];
|
|
35
|
+
const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'E10', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];
|
|
35
36
|
|
|
36
37
|
// Pre-init guard
|
|
37
38
|
if (!existsSync(join(planningDir, 'config.json'))) {
|
|
@@ -123,7 +124,7 @@ export function createCmdHealth(ctx) {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
// E8: critical root template files missing
|
|
126
|
-
const requiredRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md'];
|
|
127
|
+
const requiredRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md', 'ui-proof.md'];
|
|
127
128
|
const missingRoot = requiredRootFiles.filter((f) => !existsSync(join(templatesDir, f)));
|
|
128
129
|
if (missingRoot.length > 0) {
|
|
129
130
|
errors.push({ id: 'E8', severity: 'ERROR', message: `.planning/templates/ missing critical root files: ${missingRoot.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
|
|
@@ -140,6 +141,23 @@ export function createCmdHealth(ctx) {
|
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
|
|
144
|
+
// E10: known UI proof bundles must satisfy deterministic metadata/privacy validation.
|
|
145
|
+
for (const bundlePath of findUiProofBundleFiles(planningDir)) {
|
|
146
|
+
const relativePath = relative(cwd, bundlePath).replace(/\\/g, '/');
|
|
147
|
+
const parsed = readUiProofBundleFile(bundlePath);
|
|
148
|
+
const validation = parsed.errors.length > 0
|
|
149
|
+
? { valid: false, errors: parsed.errors }
|
|
150
|
+
: validateUiProofBundle(parsed.bundle);
|
|
151
|
+
if (!validation.valid) {
|
|
152
|
+
errors.push({
|
|
153
|
+
id: 'E10',
|
|
154
|
+
severity: 'ERROR',
|
|
155
|
+
message: `${relativePath} has invalid UI proof metadata (${validation.errors.map((entry) => entry.code).join(', ')})`,
|
|
156
|
+
fix: 'Run `gsdd ui-proof validate <path>` and add required privacy metadata, claim limits, fixed evidence kinds, observation artifact references, and safe-to-publish handling.',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
143
161
|
// --- WARNING checks ---
|
|
144
162
|
|
|
145
163
|
// W1: generation-manifest.json missing
|
package/bin/lib/init-runtime.mjs
CHANGED
|
@@ -186,7 +186,12 @@ Commands:
|
|
|
186
186
|
phase-status <N> <status> Update ROADMAP.md phase status ([ ] / [-] / [x])
|
|
187
187
|
lifecycle-preflight <surface> [phase]
|
|
188
188
|
Inspect deterministic lifecycle gate results for a workflow surface
|
|
189
|
-
session-fingerprint write
|
|
189
|
+
session-fingerprint write [--allow-changed <ROADMAP.md,SPEC.md,config.json>]
|
|
190
|
+
Rebaseline planning-state drift after reviewing changed planning files
|
|
191
|
+
ui-proof validate <path> [--claim <public|publication|tracked|delivery|release>]
|
|
192
|
+
Validate UI proof metadata; use --claim for stronger proof uses
|
|
193
|
+
ui-proof compare <planned-slots-json> [observed-bundle-json ...]
|
|
194
|
+
Compare planned UI proof slots against observed bundles
|
|
190
195
|
help Show this summary
|
|
191
196
|
|
|
192
197
|
Platforms (for --tools):
|
|
@@ -257,6 +262,7 @@ Advanced/internal helpers (kept available, but not the primary first-run user st
|
|
|
257
262
|
lifecycle-preflight Inspect deterministic lifecycle gate results for a workflow surface
|
|
258
263
|
session-fingerprint Rebaseline the local planning-state fingerprint after review
|
|
259
264
|
phase-status Update ROADMAP.md phase status through the local helper surface
|
|
265
|
+
ui-proof Validate UI proof metadata and compare planned slots to observed bundles
|
|
260
266
|
file-op Deterministic workspace-confined file copy/delete/text mutation
|
|
261
267
|
`;
|
|
262
268
|
}
|
|
@@ -52,6 +52,11 @@ const SURFACE_POLICIES = {
|
|
|
52
52
|
ownedWrites: ['spec', 'roadmap', 'phase-directories'],
|
|
53
53
|
explicitLifecycleMutation: 'none',
|
|
54
54
|
},
|
|
55
|
+
'plan-milestone-gaps': {
|
|
56
|
+
classification: 'owned_write',
|
|
57
|
+
ownedWrites: ['roadmap', 'phase-directories'],
|
|
58
|
+
explicitLifecycleMutation: 'none',
|
|
59
|
+
},
|
|
55
60
|
resume: {
|
|
56
61
|
classification: 'owned_write',
|
|
57
62
|
ownedWrites: ['checkpoint-cleanup'],
|
|
@@ -6,7 +6,7 @@ const BROWNFIELD_CHANGE_DIR = 'brownfield-change';
|
|
|
6
6
|
const PHASE_LINE_RE = /^\s*[-*]\s*\[([ x-])\]\s*\*\*Phase\s+(\d+(?:\.\d+)*[a-z]?):\s*(.+?)\*\*(?:\s+—\s+\[([^\]]+)])?/i;
|
|
7
7
|
const PHASE_DETAIL_HEADING_RE = /^(#{3,})\s+Phase\s+(\d+(?:\.\d+)*[a-z]?)(?::|\b)/i;
|
|
8
8
|
const PHASE_DETAIL_STATUS_RE = /^\s*\*\*Status\*\*:\s*\[([ x-])\]/i;
|
|
9
|
-
const ACTIVE_MILESTONE_HEADING_RE =
|
|
9
|
+
const ACTIVE_MILESTONE_HEADING_RE = /^#{2,3}\s+(v[^\s]+)\s+(.+)$/im;
|
|
10
10
|
const MILESTONE_LEDGER_HEADING_RE = /^##\s+(?:✅\s+)?(v[^\s]+)\s*(?:—|-)?\s*(.*)$/i;
|
|
11
11
|
const DETAILS_OPEN_RE = /<details\b/i;
|
|
12
12
|
const DETAILS_CLOSE_RE = /<\/details>/i;
|
package/bin/lib/rendering.mjs
CHANGED
|
@@ -13,6 +13,7 @@ const HELPER_LIB_FILES = Object.freeze([
|
|
|
13
13
|
'lifecycle-state.mjs',
|
|
14
14
|
'phase.mjs',
|
|
15
15
|
'session-fingerprint.mjs',
|
|
16
|
+
'ui-proof.mjs',
|
|
16
17
|
'workspace-root.mjs',
|
|
17
18
|
]);
|
|
18
19
|
|
|
@@ -47,6 +48,7 @@ import { cmdFileOp } from './lib/file-ops.mjs';
|
|
|
47
48
|
import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
|
|
48
49
|
import { cmdPhaseStatus } from './lib/phase.mjs';
|
|
49
50
|
import { cmdSessionFingerprint } from './lib/session-fingerprint.mjs';
|
|
51
|
+
import { cmdUiProof } from './lib/ui-proof.mjs';
|
|
50
52
|
import { bootstrapHelperWorkspace, consumeWorkspaceRootArg, resolveWorkspaceContext } from './lib/workspace-root.mjs';
|
|
51
53
|
|
|
52
54
|
const COMMANDS = {
|
|
@@ -54,6 +56,7 @@ const COMMANDS = {
|
|
|
54
56
|
'lifecycle-preflight': cmdLifecyclePreflight,
|
|
55
57
|
'phase-status': cmdPhaseStatus,
|
|
56
58
|
'session-fingerprint': cmdSessionFingerprint,
|
|
59
|
+
'ui-proof': cmdUiProof,
|
|
57
60
|
};
|
|
58
61
|
|
|
59
62
|
function printHelp() {
|
|
@@ -69,8 +72,12 @@ function printHelp() {
|
|
|
69
72
|
' lifecycle-preflight <surface> [phase]',
|
|
70
73
|
' Inspect lifecycle gate results for a workflow surface',
|
|
71
74
|
' Example: node .planning/bin/gsdd.mjs lifecycle-preflight verify 1 --expects-mutation phase-status',
|
|
72
|
-
' session-fingerprint write',
|
|
75
|
+
' session-fingerprint write [--allow-changed <ROADMAP.md,SPEC.md,config.json>]',
|
|
73
76
|
' Rebaseline planning-state drift after reviewing changed planning files',
|
|
77
|
+
' ui-proof validate <path> [--claim <public|publication|tracked|delivery|release>]',
|
|
78
|
+
' Validate UI proof metadata; use --claim for stronger proof uses',
|
|
79
|
+
' ui-proof compare <planned-slots-json> [observed-bundle-json ...]',
|
|
80
|
+
' Compare planned UI proof slots against observed bundles',
|
|
74
81
|
'',
|
|
75
82
|
'Advanced option:',
|
|
76
83
|
' --workspace-root <path> Override workspace root discovery before or after the subcommand',
|
|
@@ -63,16 +63,56 @@ export function cmdSessionFingerprint(...args) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const [action] = normalizedArgs;
|
|
66
|
+
const [action, ...flags] = normalizedArgs;
|
|
67
67
|
if (action !== 'write') {
|
|
68
|
-
console.error('Usage: node .planning/bin/gsdd.mjs session-fingerprint write');
|
|
68
|
+
console.error('Usage: node .planning/bin/gsdd.mjs session-fingerprint write [--allow-changed <ROADMAP.md,SPEC.md,config.json>]');
|
|
69
69
|
process.exitCode = 1;
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
const allowChanged = parseAllowChanged(flags);
|
|
74
|
+
if (allowChanged.invalid) {
|
|
75
|
+
console.error('Usage: node .planning/bin/gsdd.mjs session-fingerprint write [--allow-changed <ROADMAP.md,SPEC.md,config.json>]');
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (allowChanged.files.length > 0) {
|
|
81
|
+
const drift = checkDrift(planningDir);
|
|
82
|
+
const changedFiles = drift.files.filter((file) => file.status !== 'unchanged').map((file) => file.file);
|
|
83
|
+
const unexpected = changedFiles.filter((file) => !allowChanged.files.includes(file));
|
|
84
|
+
if (unexpected.length > 0) {
|
|
85
|
+
output({
|
|
86
|
+
operation: 'session-fingerprint write',
|
|
87
|
+
changedFiles,
|
|
88
|
+
allowedChanged: allowChanged.files,
|
|
89
|
+
written: false,
|
|
90
|
+
reason: 'unexpected_planning_drift',
|
|
91
|
+
unexpected,
|
|
92
|
+
});
|
|
93
|
+
process.exitCode = 1;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
73
98
|
output({ operation: 'session-fingerprint write', fingerprint: writeFingerprint(planningDir) });
|
|
74
99
|
}
|
|
75
100
|
|
|
101
|
+
function parseAllowChanged(flags) {
|
|
102
|
+
const files = [];
|
|
103
|
+
for (let index = 0; index < flags.length; index += 1) {
|
|
104
|
+
if (flags[index] !== '--allow-changed') return { invalid: true, files: [] };
|
|
105
|
+
const value = flags[index + 1];
|
|
106
|
+
if (!value || value.startsWith('--')) return { invalid: true, files: [] };
|
|
107
|
+
files.push(...value.split(',').map((entry) => entry.trim()).filter(Boolean));
|
|
108
|
+
index += 1;
|
|
109
|
+
}
|
|
110
|
+
for (const file of files) {
|
|
111
|
+
if (!FINGERPRINT_SOURCES.includes(file)) return { invalid: true, files: [] };
|
|
112
|
+
}
|
|
113
|
+
return { invalid: false, files: [...new Set(files)] };
|
|
114
|
+
}
|
|
115
|
+
|
|
76
116
|
/**
|
|
77
117
|
* Read the stored fingerprint from .planning/.state-fingerprint.json.
|
|
78
118
|
* Returns null if the file does not exist or is unparseable.
|
package/bin/lib/templates.mjs
CHANGED
|
@@ -23,7 +23,7 @@ export function installProjectTemplates({ planningDir, distilledDir, agentsDir }
|
|
|
23
23
|
console.log(` - WARN: missing expected template subdir: ${subdir}/`);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
const expectedRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md'];
|
|
26
|
+
const expectedRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md', 'ui-proof.md'];
|
|
27
27
|
for (const file of expectedRootFiles) {
|
|
28
28
|
if (!existsSync(join(localTemplatesDir, file))) {
|
|
29
29
|
console.log(` - WARN: missing expected root template file: ${file}`);
|