gsd-pi 2.33.1-dev.ee47f1b → 2.34.0-dev.bbb5216
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/dist/bundled-resource-path.d.ts +8 -0
- package/dist/bundled-resource-path.js +14 -0
- package/dist/headless-query.js +6 -6
- package/dist/resources/extensions/gsd/auto/session.js +27 -32
- package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
- package/dist/resources/extensions/gsd/auto-loop.js +956 -0
- package/dist/resources/extensions/gsd/auto-observability.js +4 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
- package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
- package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
- package/dist/resources/extensions/gsd/auto-start.js +330 -309
- package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
- package/dist/resources/extensions/gsd/auto-timers.js +3 -4
- package/dist/resources/extensions/gsd/auto-verification.js +35 -73
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
- package/dist/resources/extensions/gsd/auto.js +283 -1013
- package/dist/resources/extensions/gsd/captures.js +10 -4
- package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
- package/dist/resources/extensions/gsd/git-service.js +1 -1
- package/dist/resources/extensions/gsd/gsd-db.js +296 -151
- package/dist/resources/extensions/gsd/index.js +92 -228
- package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
- package/dist/resources/extensions/gsd/progress-score.js +61 -156
- package/dist/resources/extensions/gsd/quick.js +98 -122
- package/dist/resources/extensions/gsd/session-lock.js +13 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/undo.js +43 -48
- package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
- package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
- package/dist/resources/extensions/gsd/verification-gate.js +6 -35
- package/dist/resources/extensions/gsd/worktree-command.js +30 -24
- package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
- package/dist/resources/extensions/gsd/worktree.js +7 -44
- package/dist/tool-bootstrap.js +59 -11
- package/dist/worktree-cli.js +7 -7
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +735 -2588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/src/models.generated.ts +1039 -2892
- package/packages/pi-coding-agent/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/session.ts +47 -30
- package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
- package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
- package/src/resources/extensions/gsd/auto-observability.ts +4 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
- package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
- package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
- package/src/resources/extensions/gsd/auto-start.ts +440 -354
- package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
- package/src/resources/extensions/gsd/auto-timers.ts +3 -4
- package/src/resources/extensions/gsd/auto-verification.ts +76 -90
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
- package/src/resources/extensions/gsd/auto.ts +515 -1199
- package/src/resources/extensions/gsd/captures.ts +10 -4
- package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
- package/src/resources/extensions/gsd/git-service.ts +8 -1
- package/src/resources/extensions/gsd/gitignore.ts +4 -2
- package/src/resources/extensions/gsd/gsd-db.ts +375 -180
- package/src/resources/extensions/gsd/index.ts +104 -263
- package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
- package/src/resources/extensions/gsd/progress-score.ts +65 -200
- package/src/resources/extensions/gsd/quick.ts +121 -125
- package/src/resources/extensions/gsd/session-lock.ts +11 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
- package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
- package/src/resources/extensions/gsd/types.ts +90 -81
- package/src/resources/extensions/gsd/undo.ts +42 -46
- package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
- package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
- package/src/resources/extensions/gsd/verification-gate.ts +6 -39
- package/src/resources/extensions/gsd/worktree-command.ts +36 -24
- package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
- package/src/resources/extensions/gsd/worktree.ts +7 -44
- package/dist/resources/extensions/gsd/auto-constants.js +0 -5
- package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
- package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
- package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
- package/src/resources/extensions/gsd/auto-constants.ts +0 -6
- package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
- package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
- package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
- package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
- package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
- package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
- package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
- package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +0 -434
|
@@ -4,30 +4,45 @@
|
|
|
4
4
|
|
|
5
5
|
// ─── Enums & Literal Unions ────────────────────────────────────────────────
|
|
6
6
|
|
|
7
|
-
export type RiskLevel =
|
|
8
|
-
export type Phase =
|
|
9
|
-
|
|
7
|
+
export type RiskLevel = "low" | "medium" | "high";
|
|
8
|
+
export type Phase =
|
|
9
|
+
| "pre-planning"
|
|
10
|
+
| "needs-discussion"
|
|
11
|
+
| "discussing"
|
|
12
|
+
| "researching"
|
|
13
|
+
| "planning"
|
|
14
|
+
| "executing"
|
|
15
|
+
| "verifying"
|
|
16
|
+
| "summarizing"
|
|
17
|
+
| "advancing"
|
|
18
|
+
| "validating-milestone"
|
|
19
|
+
| "completing-milestone"
|
|
20
|
+
| "replanning-slice"
|
|
21
|
+
| "complete"
|
|
22
|
+
| "paused"
|
|
23
|
+
| "blocked";
|
|
24
|
+
export type ContinueStatus = "in_progress" | "interrupted" | "compacted";
|
|
10
25
|
|
|
11
26
|
// ─── Roadmap (Milestone-level) ─────────────────────────────────────────────
|
|
12
27
|
|
|
13
28
|
export interface RoadmapSliceEntry {
|
|
14
|
-
id: string;
|
|
15
|
-
title: string;
|
|
29
|
+
id: string; // e.g. "S01"
|
|
30
|
+
title: string; // e.g. "Types + File I/O + Git Operations"
|
|
16
31
|
risk: RiskLevel;
|
|
17
|
-
depends: string[];
|
|
32
|
+
depends: string[]; // e.g. ["S01", "S02"]
|
|
18
33
|
done: boolean;
|
|
19
|
-
demo: string;
|
|
34
|
+
demo: string; // the "After this:" sentence
|
|
20
35
|
}
|
|
21
36
|
|
|
22
37
|
export interface BoundaryMapEntry {
|
|
23
|
-
fromSlice: string;
|
|
24
|
-
toSlice: string;
|
|
25
|
-
produces: string;
|
|
26
|
-
consumes: string;
|
|
38
|
+
fromSlice: string; // e.g. "S01"
|
|
39
|
+
toSlice: string; // e.g. "S02" or "terminal"
|
|
40
|
+
produces: string; // raw text block of what this slice produces
|
|
41
|
+
consumes: string; // raw text block of what it consumes (or "nothing")
|
|
27
42
|
}
|
|
28
43
|
|
|
29
44
|
export interface Roadmap {
|
|
30
|
-
title: string;
|
|
45
|
+
title: string; // e.g. "M001: GSD Extension — Hierarchical Planning with Auto Mode"
|
|
31
46
|
vision: string;
|
|
32
47
|
successCriteria: string[];
|
|
33
48
|
slices: RoadmapSliceEntry[];
|
|
@@ -37,29 +52,24 @@ export interface Roadmap {
|
|
|
37
52
|
// ─── Slice Plan ────────────────────────────────────────────────────────────
|
|
38
53
|
|
|
39
54
|
export interface TaskPlanEntry {
|
|
40
|
-
id: string;
|
|
41
|
-
title: string;
|
|
55
|
+
id: string; // e.g. "T01"
|
|
56
|
+
title: string; // e.g. "Core Type Definitions"
|
|
42
57
|
description: string;
|
|
43
58
|
done: boolean;
|
|
44
|
-
estimate: string;
|
|
45
|
-
files?: string[];
|
|
46
|
-
verify?: string;
|
|
59
|
+
estimate: string; // e.g. "30m", "2h" — informational only
|
|
60
|
+
files?: string[]; // e.g. ["types.ts", "files.ts"] — extracted from "- Files:" subline
|
|
61
|
+
verify?: string; // e.g. "run tests" — extracted from "- Verify:" subline
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
// ─── Verification Gate ─────────────────────────────────────────────────────
|
|
50
65
|
|
|
51
66
|
/** Result of a single verification command execution */
|
|
52
67
|
export interface VerificationCheck {
|
|
53
|
-
command: string;
|
|
54
|
-
exitCode: number;
|
|
68
|
+
command: string; // e.g. "npm run lint"
|
|
69
|
+
exitCode: number; // 0 = pass
|
|
55
70
|
stdout: string;
|
|
56
71
|
stderr: string;
|
|
57
72
|
durationMs: number;
|
|
58
|
-
blocking: boolean; // true for preference/task-plan sources, false for package-json (advisory only)
|
|
59
|
-
/** True when the failure was a spawn/infra error (ETIMEDOUT, ENOENT, ENOMEM)
|
|
60
|
-
* rather than the command itself failing. Infra errors are transient and
|
|
61
|
-
* should not trigger auto-fix retries — the agent cannot fix the OS. */
|
|
62
|
-
infraError?: boolean;
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/** A runtime error captured from bg-shell processes or browser console */
|
|
@@ -81,17 +91,17 @@ export interface AuditWarning {
|
|
|
81
91
|
|
|
82
92
|
/** Aggregate result from the verification gate */
|
|
83
93
|
export interface VerificationResult {
|
|
84
|
-
passed: boolean;
|
|
85
|
-
checks: VerificationCheck[];
|
|
94
|
+
passed: boolean; // true if all checks passed (or no checks discovered)
|
|
95
|
+
checks: VerificationCheck[]; // per-command results
|
|
86
96
|
discoverySource: "preference" | "task-plan" | "package-json" | "none";
|
|
87
|
-
timestamp: number;
|
|
88
|
-
runtimeErrors?: RuntimeError[];
|
|
89
|
-
auditWarnings?: AuditWarning[];
|
|
97
|
+
timestamp: number; // Date.now() at gate start
|
|
98
|
+
runtimeErrors?: RuntimeError[]; // optional — populated by captureRuntimeErrors()
|
|
99
|
+
auditWarnings?: AuditWarning[]; // optional — populated by runDependencyAudit()
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
export interface SlicePlan {
|
|
93
|
-
id: string;
|
|
94
|
-
title: string;
|
|
103
|
+
id: string; // e.g. "S01"
|
|
104
|
+
title: string; // from the H1
|
|
95
105
|
goal: string;
|
|
96
106
|
demo: string;
|
|
97
107
|
mustHaves: string[]; // top-level must-have bullet points
|
|
@@ -161,29 +171,29 @@ export interface Continue {
|
|
|
161
171
|
|
|
162
172
|
// ─── Secrets Manifest ──────────────────────────────────────────────────────
|
|
163
173
|
|
|
164
|
-
export type SecretsManifestEntryStatus =
|
|
174
|
+
export type SecretsManifestEntryStatus = "pending" | "collected" | "skipped";
|
|
165
175
|
|
|
166
176
|
export interface SecretsManifestEntry {
|
|
167
|
-
key: string;
|
|
168
|
-
service: string;
|
|
169
|
-
dashboardUrl: string;
|
|
170
|
-
guidance: string[];
|
|
171
|
-
formatHint: string;
|
|
177
|
+
key: string; // e.g. "OPENAI_API_KEY"
|
|
178
|
+
service: string; // e.g. "OpenAI"
|
|
179
|
+
dashboardUrl: string; // e.g. "https://platform.openai.com/api-keys" — empty if unknown
|
|
180
|
+
guidance: string[]; // numbered setup steps
|
|
181
|
+
formatHint: string; // e.g. "starts with sk-" — empty if unknown
|
|
172
182
|
status: SecretsManifestEntryStatus;
|
|
173
|
-
destination: string;
|
|
183
|
+
destination: string; // e.g. "dotenv", "vercel", "convex"
|
|
174
184
|
}
|
|
175
185
|
|
|
176
186
|
export interface SecretsManifest {
|
|
177
|
-
milestone: string;
|
|
178
|
-
generatedAt: string;
|
|
187
|
+
milestone: string; // e.g. "M001"
|
|
188
|
+
generatedAt: string; // ISO 8601 timestamp
|
|
179
189
|
entries: SecretsManifestEntry[];
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
export interface ManifestStatus {
|
|
183
|
-
pending: string[];
|
|
184
|
-
collected: string[];
|
|
185
|
-
skipped: string[];
|
|
186
|
-
existing: string[];
|
|
193
|
+
pending: string[]; // manifest status = pending AND not in env
|
|
194
|
+
collected: string[]; // manifest status = collected AND not in env
|
|
195
|
+
skipped: string[]; // manifest status = skipped
|
|
196
|
+
existing: string[]; // key present in .env or process.env (regardless of manifest status)
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
// ─── GSD State (Derived Dashboard) ────────────────────────────────────────
|
|
@@ -196,7 +206,7 @@ export interface ActiveRef {
|
|
|
196
206
|
export interface MilestoneRegistryEntry {
|
|
197
207
|
id: string;
|
|
198
208
|
title: string;
|
|
199
|
-
status:
|
|
209
|
+
status: "complete" | "active" | "pending" | "parked";
|
|
200
210
|
/** Milestone IDs that must be complete before this milestone becomes active. Populated from CONTEXT.md YAML frontmatter. */
|
|
201
211
|
dependsOn?: string[];
|
|
202
212
|
}
|
|
@@ -279,13 +289,13 @@ export interface HookDispatchResult {
|
|
|
279
289
|
|
|
280
290
|
// ─── Budget & Notification Types ──────────────────────────────────────────
|
|
281
291
|
|
|
282
|
-
export type BudgetEnforcementMode =
|
|
292
|
+
export type BudgetEnforcementMode = "warn" | "pause" | "halt";
|
|
283
293
|
|
|
284
|
-
export type TokenProfile =
|
|
294
|
+
export type TokenProfile = "budget" | "balanced" | "quality";
|
|
285
295
|
|
|
286
|
-
export type InlineLevel =
|
|
296
|
+
export type InlineLevel = "full" | "standard" | "minimal";
|
|
287
297
|
|
|
288
|
-
export type ComplexityTier =
|
|
298
|
+
export type ComplexityTier = "light" | "standard" | "heavy";
|
|
289
299
|
|
|
290
300
|
export interface ClassificationResult {
|
|
291
301
|
tier: ComplexityTier;
|
|
@@ -308,19 +318,18 @@ export interface PhaseSkipPreferences {
|
|
|
308
318
|
skip_reassess?: boolean;
|
|
309
319
|
skip_slice_research?: boolean;
|
|
310
320
|
skip_milestone_validation?: boolean;
|
|
311
|
-
/** When true, reassess-roadmap fires after each slice completion. Opt-in. */
|
|
312
321
|
reassess_after_slice?: boolean;
|
|
313
322
|
/** When true, auto-mode pauses before each slice for discussion (#789). */
|
|
314
323
|
require_slice_discussion?: boolean;
|
|
315
324
|
}
|
|
316
325
|
|
|
317
326
|
export interface NotificationPreferences {
|
|
318
|
-
enabled?: boolean;
|
|
319
|
-
on_complete?: boolean;
|
|
320
|
-
on_error?: boolean;
|
|
321
|
-
on_budget?: boolean;
|
|
322
|
-
on_milestone?: boolean;
|
|
323
|
-
on_attention?: boolean;
|
|
327
|
+
enabled?: boolean; // default true
|
|
328
|
+
on_complete?: boolean; // notify on each unit completion
|
|
329
|
+
on_error?: boolean; // notify on errors
|
|
330
|
+
on_budget?: boolean; // notify on budget thresholds
|
|
331
|
+
on_milestone?: boolean; // notify when milestone finishes
|
|
332
|
+
on_attention?: boolean; // notify when manual attention needed
|
|
324
333
|
}
|
|
325
334
|
|
|
326
335
|
// ─── Pre-Dispatch Hook Types ──────────────────────────────────────────────
|
|
@@ -331,7 +340,7 @@ export interface PreDispatchHookConfig {
|
|
|
331
340
|
/** Unit types this hook intercepts before dispatch (e.g., ["execute-task"]). */
|
|
332
341
|
before: string[];
|
|
333
342
|
/** Action to take: "modify" mutates the prompt, "skip" skips the unit, "replace" swaps it. */
|
|
334
|
-
action:
|
|
343
|
+
action: "modify" | "skip" | "replace";
|
|
335
344
|
/** For "modify": text prepended to the unit prompt. Supports {milestoneId}, {sliceId}, {taskId}. */
|
|
336
345
|
prepend?: string;
|
|
337
346
|
/** For "modify": text appended to the unit prompt. Supports {milestoneId}, {sliceId}, {taskId}. */
|
|
@@ -350,7 +359,7 @@ export interface PreDispatchHookConfig {
|
|
|
350
359
|
|
|
351
360
|
export interface PreDispatchResult {
|
|
352
361
|
/** What happened: the unit proceeds with modifications, was skipped, or was replaced. */
|
|
353
|
-
action:
|
|
362
|
+
action: "proceed" | "skip" | "replace";
|
|
354
363
|
/** Modified/replacement prompt (for "proceed" and "replace"). */
|
|
355
364
|
prompt?: string;
|
|
356
365
|
/** Override unit type (for "replace"). */
|
|
@@ -374,7 +383,7 @@ export interface HookStatusEntry {
|
|
|
374
383
|
/** Hook name. */
|
|
375
384
|
name: string;
|
|
376
385
|
/** Hook type: "post" or "pre". */
|
|
377
|
-
type:
|
|
386
|
+
type: "post" | "pre";
|
|
378
387
|
/** Whether hook is enabled. */
|
|
379
388
|
enabled: boolean;
|
|
380
389
|
/** What unit types it targets. */
|
|
@@ -386,36 +395,36 @@ export interface HookStatusEntry {
|
|
|
386
395
|
// ─── Database Types (Decisions & Requirements) ────────────────────────────
|
|
387
396
|
|
|
388
397
|
export interface Decision {
|
|
389
|
-
seq: number;
|
|
390
|
-
id: string;
|
|
391
|
-
when_context: string;
|
|
392
|
-
scope: string;
|
|
393
|
-
decision: string;
|
|
394
|
-
choice: string;
|
|
395
|
-
rationale: string;
|
|
396
|
-
revisable: string;
|
|
397
|
-
superseded_by: string | null;
|
|
398
|
+
seq: number; // auto-increment primary key
|
|
399
|
+
id: string; // e.g. "D001"
|
|
400
|
+
when_context: string; // when/context of the decision
|
|
401
|
+
scope: string; // scope (milestone, slice, global, etc.)
|
|
402
|
+
decision: string; // what was decided
|
|
403
|
+
choice: string; // the specific choice made
|
|
404
|
+
rationale: string; // why this choice
|
|
405
|
+
revisable: string; // whether/when revisable
|
|
406
|
+
superseded_by: string | null; // ID of superseding decision, or null
|
|
398
407
|
}
|
|
399
408
|
|
|
400
409
|
export interface Requirement {
|
|
401
|
-
id: string;
|
|
402
|
-
class: string;
|
|
403
|
-
status: string;
|
|
404
|
-
description: string;
|
|
405
|
-
why: string;
|
|
406
|
-
source: string;
|
|
407
|
-
primary_owner: string;
|
|
410
|
+
id: string; // e.g. "R001"
|
|
411
|
+
class: string; // requirement class (functional, non-functional, etc.)
|
|
412
|
+
status: string; // active, validated, deferred, etc.
|
|
413
|
+
description: string; // short description
|
|
414
|
+
why: string; // rationale
|
|
415
|
+
source: string; // origin (milestone, user, etc.)
|
|
416
|
+
primary_owner: string; // owning slice/milestone
|
|
408
417
|
supporting_slices: string; // other slices that touch this
|
|
409
|
-
validation: string;
|
|
410
|
-
notes: string;
|
|
411
|
-
full_content: string;
|
|
412
|
-
superseded_by: string | null;
|
|
418
|
+
validation: string; // how to validate
|
|
419
|
+
notes: string; // additional notes
|
|
420
|
+
full_content: string; // full requirement text
|
|
421
|
+
superseded_by: string | null; // ID of superseding requirement, or null
|
|
413
422
|
}
|
|
414
423
|
|
|
415
424
|
// ─── Parallel Orchestration Types ────────────────────────────────────────
|
|
416
425
|
|
|
417
|
-
export type CompressionStrategy =
|
|
418
|
-
export type ContextSelectionMode =
|
|
426
|
+
export type CompressionStrategy = "truncate" | "compress";
|
|
427
|
+
export type ContextSelectionMode = "full" | "smart";
|
|
419
428
|
|
|
420
429
|
export type MergeStrategy = "per-slice" | "per-milestone";
|
|
421
430
|
export type AutoMergeMode = "auto" | "confirm" | "manual";
|
|
@@ -9,46 +9,48 @@ import { deriveState } from "./state.js";
|
|
|
9
9
|
import { invalidateAllCaches } from "./cache.js";
|
|
10
10
|
import { gsdRoot, resolveTasksDir, resolveSlicePath, buildTaskFileName } from "./paths.js";
|
|
11
11
|
import { sendDesktopNotification } from "./notifications.js";
|
|
12
|
-
import { parseUnitId } from "./unit-id.js";
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
* Undo the last completed unit: revert git commits,
|
|
14
|
+
* Undo the last completed unit: revert git commits,
|
|
16
15
|
* delete summary artifacts, and uncheck the task in PLAN.
|
|
16
|
+
* deriveState() handles re-derivation after revert.
|
|
17
17
|
*/
|
|
18
18
|
export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi: ExtensionAPI, basePath: string): Promise<void> {
|
|
19
19
|
const force = args.includes("--force");
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
const
|
|
23
|
-
if (!existsSync(
|
|
24
|
-
ctx.ui.notify("Nothing to undo — no
|
|
21
|
+
// Find the last GSD-related commit from git activity logs
|
|
22
|
+
const activityDir = join(gsdRoot(basePath), "activity");
|
|
23
|
+
if (!existsSync(activityDir)) {
|
|
24
|
+
ctx.ui.notify("Nothing to undo — no activity logs found.", "info");
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
// Parse activity logs to find the most recent unit
|
|
29
|
+
const files = readdirSync(activityDir)
|
|
30
|
+
.filter(f => f.endsWith(".jsonl"))
|
|
31
|
+
.sort()
|
|
32
|
+
.reverse();
|
|
33
|
+
|
|
34
|
+
if (files.length === 0) {
|
|
35
|
+
ctx.ui.notify("Nothing to undo — no activity logs found.", "info");
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
// Extract unit type and ID from the most recent activity log filename
|
|
40
|
+
// Format: <seq>-<unitType>-<unitId>.jsonl
|
|
41
|
+
const match = files[0].match(/^\d+-(.+?)-(.+)\.jsonl$/);
|
|
42
|
+
if (!match) {
|
|
43
|
+
ctx.ui.notify("Nothing to undo — could not parse latest activity log.", "warning");
|
|
38
44
|
return;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
const sepIdx = lastKey.indexOf("/");
|
|
44
|
-
const unitType = sepIdx >= 0 ? lastKey.slice(0, sepIdx) : lastKey;
|
|
45
|
-
const unitId = sepIdx >= 0 ? lastKey.slice(sepIdx + 1) : lastKey;
|
|
47
|
+
const unitType = match[1];
|
|
48
|
+
const unitId = match[2].replace(/-/g, "/");
|
|
46
49
|
|
|
47
50
|
if (!force) {
|
|
48
51
|
ctx.ui.notify(
|
|
49
52
|
`Will undo: ${unitType} (${unitId})\n` +
|
|
50
53
|
`This will:\n` +
|
|
51
|
-
` - Remove from completed-units.json\n` +
|
|
52
54
|
` - Delete summary artifacts\n` +
|
|
53
55
|
` - Uncheck task in PLAN (if execute-task)\n` +
|
|
54
56
|
` - Attempt to revert associated git commits\n\n` +
|
|
@@ -58,15 +60,12 @@ export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi
|
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
writeFileSync(completedKeysFile, JSON.stringify(keys), "utf-8");
|
|
64
|
-
|
|
65
|
-
// 3. Delete summary artifact
|
|
66
|
-
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
63
|
+
// 1. Delete summary artifact
|
|
64
|
+
const parts = unitId.split("/");
|
|
67
65
|
let summaryRemoved = false;
|
|
68
|
-
if (
|
|
66
|
+
if (parts.length === 3) {
|
|
69
67
|
// Task-level: M001/S01/T01
|
|
68
|
+
const [mid, sid, tid] = parts;
|
|
70
69
|
const tasksDir = resolveTasksDir(basePath, mid, sid);
|
|
71
70
|
if (tasksDir) {
|
|
72
71
|
const summaryFile = join(tasksDir, buildTaskFileName(tid, "SUMMARY"));
|
|
@@ -75,11 +74,11 @@ export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi
|
|
|
75
74
|
summaryRemoved = true;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
} else if (
|
|
77
|
+
} else if (parts.length === 2) {
|
|
79
78
|
// Slice-level: M001/S01
|
|
79
|
+
const [mid, sid] = parts;
|
|
80
80
|
const slicePath = resolveSlicePath(basePath, mid, sid);
|
|
81
81
|
if (slicePath) {
|
|
82
|
-
// Try common summary filenames
|
|
83
82
|
for (const suffix of ["SUMMARY", "COMPLETE"]) {
|
|
84
83
|
const candidates = findFileWithPrefix(slicePath, sid, suffix);
|
|
85
84
|
for (const f of candidates) {
|
|
@@ -90,40 +89,37 @@ export async function handleUndo(args: string, ctx: ExtensionCommandContext, _pi
|
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
//
|
|
92
|
+
// 2. Uncheck task in PLAN if execute-task
|
|
94
93
|
let planUpdated = false;
|
|
95
|
-
if (unitType === "execute-task" &&
|
|
94
|
+
if (unitType === "execute-task" && parts.length === 3) {
|
|
95
|
+
const [mid, sid, tid] = parts;
|
|
96
96
|
planUpdated = uncheckTaskInPlan(basePath, mid, sid, tid);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
//
|
|
99
|
+
// 3. Try to revert git commits from activity log
|
|
100
100
|
let commitsReverted = 0;
|
|
101
|
-
const activityDir = join(gsdRoot(basePath), "activity");
|
|
102
101
|
try {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
102
|
+
const commits = findCommitsForUnit(activityDir, unitType, unitId);
|
|
103
|
+
if (commits.length > 0) {
|
|
104
|
+
for (const sha of commits.reverse()) {
|
|
105
|
+
try {
|
|
106
|
+
nativeRevertCommit(basePath, sha);
|
|
107
|
+
commitsReverted++;
|
|
108
|
+
} catch {
|
|
109
|
+
// Revert conflict or already reverted — skip
|
|
110
|
+
try { nativeRevertAbort(basePath); } catch { /* no-op */ }
|
|
111
|
+
break;
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
} finally {
|
|
119
|
-
//
|
|
116
|
+
// 4. Re-derive state — always invalidate caches even if git operations fail
|
|
120
117
|
invalidateAllCaches();
|
|
121
118
|
await deriveState(basePath);
|
|
122
119
|
}
|
|
123
120
|
|
|
124
121
|
// Build result message
|
|
125
122
|
const results: string[] = [`Undone: ${unitType} (${unitId})`];
|
|
126
|
-
results.push(` - Removed from completed-units.json`);
|
|
127
123
|
if (summaryRemoved) results.push(` - Deleted summary artifact`);
|
|
128
124
|
if (planUpdated) results.push(` - Unchecked task in PLAN`);
|
|
129
125
|
if (commitsReverted > 0) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import {
|
|
4
4
|
gsdRoot,
|
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
resolveTaskFile,
|
|
9
9
|
} from "./paths.js";
|
|
10
10
|
import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
|
|
11
|
-
import { loadJsonFileOrNull, saveJsonFile } from "./json-persistence.js";
|
|
12
|
-
import { parseUnitId } from "./unit-id.js";
|
|
13
11
|
|
|
14
12
|
export type UnitRuntimePhase =
|
|
15
13
|
| "dispatched"
|
|
@@ -48,23 +46,13 @@ export interface AutoUnitRuntimeRecord {
|
|
|
48
46
|
lastRecoveryReason?: "idle" | "hard";
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
function isAutoUnitRuntimeRecord(data: unknown): data is AutoUnitRuntimeRecord {
|
|
52
|
-
return (
|
|
53
|
-
typeof data === "object" &&
|
|
54
|
-
data !== null &&
|
|
55
|
-
(data as AutoUnitRuntimeRecord).version === 1 &&
|
|
56
|
-
typeof (data as AutoUnitRuntimeRecord).unitType === "string" &&
|
|
57
|
-
typeof (data as AutoUnitRuntimeRecord).unitId === "string"
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
49
|
function runtimeDir(basePath: string): string {
|
|
62
50
|
return join(gsdRoot(basePath), "runtime", "units");
|
|
63
51
|
}
|
|
64
52
|
|
|
65
53
|
function runtimePath(basePath: string, unitType: string, unitId: string): string {
|
|
66
|
-
const sanitizedUnitType = unitType.replace(/[
|
|
67
|
-
const sanitizedUnitId = unitId.replace(/[
|
|
54
|
+
const sanitizedUnitType = unitType.replace(/[\/]/g, "-");
|
|
55
|
+
const sanitizedUnitId = unitId.replace(/[\/]/g, "-");
|
|
68
56
|
return join(runtimeDir(basePath), `${sanitizedUnitType}-${sanitizedUnitId}.json`);
|
|
69
57
|
}
|
|
70
58
|
|
|
@@ -75,6 +63,8 @@ export function writeUnitRuntimeRecord(
|
|
|
75
63
|
startedAt: number,
|
|
76
64
|
updates: Partial<AutoUnitRuntimeRecord> = {},
|
|
77
65
|
): AutoUnitRuntimeRecord {
|
|
66
|
+
const dir = runtimeDir(basePath);
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
78
68
|
const path = runtimePath(basePath, unitType, unitId);
|
|
79
69
|
const prev = readUnitRuntimeRecord(basePath, unitType, unitId);
|
|
80
70
|
const next: AutoUnitRuntimeRecord = {
|
|
@@ -94,12 +84,18 @@ export function writeUnitRuntimeRecord(
|
|
|
94
84
|
recoveryAttempts: updates.recoveryAttempts ?? prev?.recoveryAttempts ?? 0,
|
|
95
85
|
lastRecoveryReason: updates.lastRecoveryReason ?? prev?.lastRecoveryReason,
|
|
96
86
|
};
|
|
97
|
-
|
|
87
|
+
writeFileSync(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
98
88
|
return next;
|
|
99
89
|
}
|
|
100
90
|
|
|
101
91
|
export function readUnitRuntimeRecord(basePath: string, unitType: string, unitId: string): AutoUnitRuntimeRecord | null {
|
|
102
|
-
|
|
92
|
+
const path = runtimePath(basePath, unitType, unitId);
|
|
93
|
+
if (!existsSync(path)) return null;
|
|
94
|
+
try {
|
|
95
|
+
return JSON.parse(readFileSync(path, "utf-8")) as AutoUnitRuntimeRecord;
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
103
99
|
}
|
|
104
100
|
|
|
105
101
|
export function clearUnitRuntimeRecord(basePath: string, unitType: string, unitId: string): void {
|
|
@@ -132,7 +128,7 @@ export async function inspectExecuteTaskDurability(
|
|
|
132
128
|
basePath: string,
|
|
133
129
|
unitId: string,
|
|
134
130
|
): Promise<ExecuteTaskRecoveryStatus | null> {
|
|
135
|
-
const
|
|
131
|
+
const [mid, sid, tid] = unitId.split("/");
|
|
136
132
|
if (!mid || !sid || !tid) return null;
|
|
137
133
|
|
|
138
134
|
const planAbs = resolveSliceFile(basePath, mid, sid, "PLAN");
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
-
import type { VerificationResult } from "./types.
|
|
14
|
+
import type { VerificationResult } from "./types.ts";
|
|
15
15
|
|
|
16
16
|
// ─── JSON Evidence Artifact ──────────────────────────────────────────────────
|
|
17
17
|
|
|
@@ -20,7 +20,6 @@ export interface EvidenceCheckJSON {
|
|
|
20
20
|
exitCode: number;
|
|
21
21
|
durationMs: number;
|
|
22
22
|
verdict: "pass" | "fail";
|
|
23
|
-
blocking: boolean;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export interface RuntimeErrorJSON {
|
|
@@ -81,7 +80,6 @@ export function writeVerificationJSON(
|
|
|
81
80
|
exitCode: check.exitCode,
|
|
82
81
|
durationMs: check.durationMs,
|
|
83
82
|
verdict: check.exitCode === 0 ? "pass" : "fail",
|
|
84
|
-
blocking: check.blocking,
|
|
85
83
|
})),
|
|
86
84
|
...(retryAttempt !== undefined ? { retryAttempt } : {}),
|
|
87
85
|
...(maxRetries !== undefined ? { maxRetries } : {}),
|