gsd-pi 2.38.0-dev.8f5c161 → 2.38.0-dev.98b44dc
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 +15 -11
- package/dist/resource-loader.js +34 -1
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto-loop.js +538 -469
- package/dist/resources/extensions/gsd/auto-post-unit.js +28 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +197 -19
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/commands.js +2 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +3 -0
- package/dist/resources/extensions/gsd/doctor.js +20 -1
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/files.js +46 -7
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +3 -86
- package/dist/resources/extensions/gsd/index.js +22 -19
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +58 -0
- package/dist/resources/extensions/gsd/preferences.js +20 -9
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +41 -22
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -2
- package/dist/resources/extensions/remote-questions/store.js +4 -2
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +6 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/skills.ts +9 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto-loop.ts +342 -304
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +242 -19
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/commands.ts +2 -2
- package/src/resources/extensions/gsd/doctor-providers.ts +4 -0
- package/src/resources/extensions/gsd/doctor.ts +22 -1
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/files.ts +49 -9
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +3 -89
- package/src/resources/extensions/gsd/index.ts +21 -16
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-types.ts +4 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +50 -0
- package/src/resources/extensions/gsd/preferences.ts +23 -9
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +38 -20
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +106 -31
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/types.ts +18 -0
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +4 -2
- package/src/resources/extensions/remote-questions/store.ts +4 -2
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
|
@@ -11,12 +11,10 @@ import { runProviderChecks, summariseProviderIssues } from "./doctor-providers.j
|
|
|
11
11
|
import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
12
12
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
13
13
|
import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
|
|
14
|
-
import { describeNextUnit, estimateTimeRemaining, updateSliceProgressCache } from "./auto-dashboard.js";
|
|
15
14
|
import { projectRoot } from "./commands.js";
|
|
16
|
-
import { deriveState, invalidateStateCache } from "./state.js";
|
|
17
15
|
import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
|
|
18
16
|
// ── Data loader ────────────────────────────────────────────────────────────────
|
|
19
|
-
function
|
|
17
|
+
function loadHealthWidgetData(basePath) {
|
|
20
18
|
let budgetCeiling;
|
|
21
19
|
let budgetSpent = 0;
|
|
22
20
|
let providerIssue = null;
|
|
@@ -58,86 +56,6 @@ function loadBaseHealthWidgetData(basePath) {
|
|
|
58
56
|
lastRefreshed: Date.now(),
|
|
59
57
|
};
|
|
60
58
|
}
|
|
61
|
-
function compactText(text, max = 64) {
|
|
62
|
-
const trimmed = text.replace(/\s+/g, " ").trim();
|
|
63
|
-
if (trimmed.length <= max)
|
|
64
|
-
return trimmed;
|
|
65
|
-
return `${trimmed.slice(0, max - 1).trimEnd()}…`;
|
|
66
|
-
}
|
|
67
|
-
function summarizeExecutionStatus(state) {
|
|
68
|
-
switch (state.phase) {
|
|
69
|
-
case "blocked": return "Blocked";
|
|
70
|
-
case "paused": return "Paused";
|
|
71
|
-
case "complete": return "Complete";
|
|
72
|
-
case "executing": return "Executing";
|
|
73
|
-
case "planning": return "Planning";
|
|
74
|
-
case "pre-planning": return "Pre-planning";
|
|
75
|
-
case "summarizing": return "Summarizing";
|
|
76
|
-
case "validating-milestone": return "Validating";
|
|
77
|
-
case "completing-milestone": return "Completing";
|
|
78
|
-
case "needs-discussion": return "Needs discussion";
|
|
79
|
-
case "replanning-slice": return "Replanning";
|
|
80
|
-
default: return "Active";
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function summarizeExecutionTarget(state) {
|
|
84
|
-
switch (state.phase) {
|
|
85
|
-
case "needs-discussion":
|
|
86
|
-
return state.activeMilestone ? `Discuss ${state.activeMilestone.id}` : "Discuss milestone draft";
|
|
87
|
-
case "pre-planning":
|
|
88
|
-
return state.activeMilestone ? `Plan ${state.activeMilestone.id}` : "Research & plan milestone";
|
|
89
|
-
case "planning":
|
|
90
|
-
return state.activeSlice ? `Plan ${state.activeSlice.id}` : "Plan next slice";
|
|
91
|
-
case "executing":
|
|
92
|
-
return state.activeTask ? `Execute ${state.activeTask.id}` : "Execute next task";
|
|
93
|
-
case "summarizing":
|
|
94
|
-
return state.activeSlice ? `Complete ${state.activeSlice.id}` : "Complete current slice";
|
|
95
|
-
case "validating-milestone":
|
|
96
|
-
return state.activeMilestone ? `Validate ${state.activeMilestone.id}` : "Validate milestone";
|
|
97
|
-
case "completing-milestone":
|
|
98
|
-
return state.activeMilestone ? `Complete ${state.activeMilestone.id}` : "Complete milestone";
|
|
99
|
-
case "replanning-slice":
|
|
100
|
-
return state.activeSlice ? `Replan ${state.activeSlice.id}` : "Replan current slice";
|
|
101
|
-
case "blocked":
|
|
102
|
-
return `waiting on ${compactText(state.blockers[0] ?? state.nextAction, 56)}`;
|
|
103
|
-
case "paused":
|
|
104
|
-
return compactText(state.nextAction || "waiting to resume", 56);
|
|
105
|
-
case "complete":
|
|
106
|
-
return "All milestones complete";
|
|
107
|
-
default:
|
|
108
|
-
return compactText(describeNextUnit(state).label, 56);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
async function enrichHealthWidgetData(basePath, baseData) {
|
|
112
|
-
if (baseData.projectState !== "active")
|
|
113
|
-
return baseData;
|
|
114
|
-
try {
|
|
115
|
-
invalidateStateCache();
|
|
116
|
-
const state = await deriveState(basePath);
|
|
117
|
-
if (state.activeMilestone) {
|
|
118
|
-
// Warm the slice-progress cache so estimateTimeRemaining() has data
|
|
119
|
-
updateSliceProgressCache(basePath, state.activeMilestone.id, state.activeSlice?.id);
|
|
120
|
-
}
|
|
121
|
-
return {
|
|
122
|
-
...baseData,
|
|
123
|
-
executionPhase: state.phase,
|
|
124
|
-
executionStatus: summarizeExecutionStatus(state),
|
|
125
|
-
executionTarget: summarizeExecutionTarget(state),
|
|
126
|
-
nextAction: state.nextAction,
|
|
127
|
-
blocker: state.blockers[0] ?? null,
|
|
128
|
-
activeMilestoneId: state.activeMilestone?.id,
|
|
129
|
-
activeSliceId: state.activeSlice?.id,
|
|
130
|
-
activeTaskId: state.activeTask?.id,
|
|
131
|
-
progress: state.progress,
|
|
132
|
-
eta: state.phase === "blocked" || state.phase === "paused" || state.phase === "complete"
|
|
133
|
-
? null
|
|
134
|
-
: estimateTimeRemaining(),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
return baseData;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
59
|
// ── Widget init ────────────────────────────────────────────────────────────────
|
|
142
60
|
const REFRESH_INTERVAL_MS = 60_000;
|
|
143
61
|
/**
|
|
@@ -149,7 +67,7 @@ export function initHealthWidget(ctx) {
|
|
|
149
67
|
return;
|
|
150
68
|
const basePath = projectRoot();
|
|
151
69
|
// String-array fallback — used in RPC mode (factory is a no-op there)
|
|
152
|
-
const initialData =
|
|
70
|
+
const initialData = loadHealthWidgetData(basePath);
|
|
153
71
|
ctx.ui.setWidget("gsd-health", buildHealthLines(initialData), { placement: "belowEditor" });
|
|
154
72
|
// Factory-based widget for TUI mode — replaces the string-array above
|
|
155
73
|
ctx.ui.setWidget("gsd-health", (_tui, _theme) => {
|
|
@@ -161,8 +79,7 @@ export function initHealthWidget(ctx) {
|
|
|
161
79
|
return;
|
|
162
80
|
refreshInFlight = true;
|
|
163
81
|
try {
|
|
164
|
-
|
|
165
|
-
data = await enrichHealthWidgetData(basePath, baseData);
|
|
82
|
+
data = loadHealthWidgetData(basePath);
|
|
166
83
|
cachedLines = undefined;
|
|
167
84
|
_tui.requestRender();
|
|
168
85
|
}
|
|
@@ -66,6 +66,24 @@ function warnDeprecatedAgentInstructions() {
|
|
|
66
66
|
}
|
|
67
67
|
// ── Depth verification state ──────────────────────────────────────────────
|
|
68
68
|
let depthVerificationDone = false;
|
|
69
|
+
// ── DB lazy-open helper ───────────────────────────────────────────────────
|
|
70
|
+
// In manual sessions (no auto-mode), the DB is never opened by bootstrapAutoSession.
|
|
71
|
+
// This helper ensures the DB is lazily opened on first tool call that needs it.
|
|
72
|
+
async function ensureDbOpen() {
|
|
73
|
+
try {
|
|
74
|
+
const db = await import("./gsd-db.js");
|
|
75
|
+
if (db.isDbAvailable())
|
|
76
|
+
return true;
|
|
77
|
+
const dbPath = join(process.cwd(), ".gsd", "gsd.db");
|
|
78
|
+
if (existsSync(dbPath)) {
|
|
79
|
+
return db.openDatabase(dbPath);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
69
87
|
// ── Queue phase tracking ──────────────────────────────────────────────────
|
|
70
88
|
// When true, the LLM is in a queue flow writing CONTEXT.md files.
|
|
71
89
|
// The write-gate applies during queue flows just like discussion flows.
|
|
@@ -228,13 +246,8 @@ export default function (pi) {
|
|
|
228
246
|
when_context: Type.Optional(Type.String({ description: "When/context for the decision (e.g. milestone ID)" })),
|
|
229
247
|
}),
|
|
230
248
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const db = await import("./gsd-db.js");
|
|
235
|
-
dbAvailable = db.isDbAvailable();
|
|
236
|
-
}
|
|
237
|
-
catch { /* dynamic import failed */ }
|
|
249
|
+
// Ensure DB is open (lazy-open on first tool call in manual sessions)
|
|
250
|
+
const dbAvailable = await ensureDbOpen();
|
|
238
251
|
if (!dbAvailable) {
|
|
239
252
|
return {
|
|
240
253
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot save decision." }],
|
|
@@ -290,12 +303,7 @@ export default function (pi) {
|
|
|
290
303
|
supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
|
|
291
304
|
}),
|
|
292
305
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
293
|
-
|
|
294
|
-
try {
|
|
295
|
-
const db = await import("./gsd-db.js");
|
|
296
|
-
dbAvailable = db.isDbAvailable();
|
|
297
|
-
}
|
|
298
|
-
catch { /* dynamic import failed */ }
|
|
306
|
+
const dbAvailable = await ensureDbOpen();
|
|
299
307
|
if (!dbAvailable) {
|
|
300
308
|
return {
|
|
301
309
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot update requirement." }],
|
|
@@ -365,12 +373,7 @@ export default function (pi) {
|
|
|
365
373
|
content: Type.String({ description: "The full markdown content of the artifact" }),
|
|
366
374
|
}),
|
|
367
375
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
368
|
-
|
|
369
|
-
try {
|
|
370
|
-
const db = await import("./gsd-db.js");
|
|
371
|
-
dbAvailable = db.isDbAvailable();
|
|
372
|
-
}
|
|
373
|
-
catch { /* dynamic import failed */ }
|
|
376
|
+
const dbAvailable = await ensureDbOpen();
|
|
374
377
|
if (!dbAvailable) {
|
|
375
378
|
return {
|
|
376
379
|
content: [{ type: "text", text: "Error: GSD database is not available. Cannot save artifact." }],
|
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* `~/.gsd/projects/<hash>/` state directory. After migration, a
|
|
6
6
|
* symlink replaces the original directory so all paths remain valid.
|
|
7
7
|
*/
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
8
9
|
import { existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, renameSync, cpSync, rmSync, symlinkSync } from "node:fs";
|
|
9
10
|
import { join } from "node:path";
|
|
10
11
|
import { externalGsdRoot } from "./repo-identity.js";
|
|
11
12
|
import { getErrorMessage } from "./error-utils.js";
|
|
12
13
|
import { hasGitTrackedGsdFiles } from "./gitignore.js";
|
|
14
|
+
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
13
15
|
/**
|
|
14
16
|
* Migrate a legacy in-project `.gsd/` directory to external storage.
|
|
15
17
|
*
|
|
@@ -142,7 +144,22 @@ export function migrateToExternalState(basePath) {
|
|
|
142
144
|
catch { /* best-effort restore */ }
|
|
143
145
|
return { migrated: false, error: `Migration verification failed: ${getErrorMessage(verifyErr)}` };
|
|
144
146
|
}
|
|
145
|
-
//
|
|
147
|
+
// Clean the git index — any .gsd/* files tracked before migration now
|
|
148
|
+
// sit behind the symlink and git can't follow it, causing them to show
|
|
149
|
+
// as deleted. Remove them from the index so the working tree stays clean.
|
|
150
|
+
// --ignore-unmatch makes this a no-op on fresh projects with no tracked .gsd/.
|
|
151
|
+
try {
|
|
152
|
+
execFileSync("git", ["rm", "-r", "--cached", "--ignore-unmatch", ".gsd"], {
|
|
153
|
+
cwd: basePath,
|
|
154
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
155
|
+
env: GIT_NO_PROMPT_ENV,
|
|
156
|
+
timeout: 10_000,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Non-fatal — git may be unavailable or nothing was tracked
|
|
161
|
+
}
|
|
162
|
+
// Remove .gsd.migrating only after symlink is verified and index is clean
|
|
146
163
|
rmSync(migratingPath, { recursive: true, force: true });
|
|
147
164
|
return { migrated: true };
|
|
148
165
|
}
|
|
@@ -518,6 +518,43 @@ export function nativeAddAll(basePath) {
|
|
|
518
518
|
}
|
|
519
519
|
gitFileExec(basePath, ["add", "-A"]);
|
|
520
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* Stage all files with pathspec exclusions (git add -A -- ':!pattern' ...).
|
|
523
|
+
* Excluded paths are never hashed by git, preventing hangs on large
|
|
524
|
+
* untracked artifact trees (57GB+, 11K+ files). See #1605.
|
|
525
|
+
*
|
|
526
|
+
* Falls back to plain `git add -A` when no exclusions are provided.
|
|
527
|
+
* Always uses the CLI path (not libgit2) because libgit2's add_all
|
|
528
|
+
* does not support pathspec exclusion syntax.
|
|
529
|
+
*
|
|
530
|
+
* When excluded paths are already covered by .gitignore, git may exit
|
|
531
|
+
* with code 1 and an "ignored by .gitignore" warning. This is harmless
|
|
532
|
+
* (the staging succeeds for all non-ignored files) and is suppressed.
|
|
533
|
+
*/
|
|
534
|
+
export function nativeAddAllWithExclusions(basePath, exclusions) {
|
|
535
|
+
if (exclusions.length === 0) {
|
|
536
|
+
nativeAddAll(basePath);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const pathspecs = exclusions.map(e => `:!${e}`);
|
|
540
|
+
try {
|
|
541
|
+
execFileSync("git", ["add", "-A", "--", ...pathspecs], {
|
|
542
|
+
cwd: basePath,
|
|
543
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
544
|
+
encoding: "utf-8",
|
|
545
|
+
env: GIT_NO_PROMPT_ENV,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
catch (err) {
|
|
549
|
+
// git exits 1 when pathspec exclusions reference paths already covered
|
|
550
|
+
// by .gitignore. The staging itself succeeds — only suppress that case.
|
|
551
|
+
const stderr = err?.stderr ?? "";
|
|
552
|
+
if (stderr.includes("ignored by one of your .gitignore files")) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
throw new GSDError(GSD_GIT_ERROR, `git add -A with exclusions failed in ${basePath}: ${getErrorMessage(err)}`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
521
558
|
/**
|
|
522
559
|
* Stage specific files.
|
|
523
560
|
* Native: libgit2 index add.
|
|
@@ -343,6 +343,9 @@ function probeGsdRoot(rawBasePath) {
|
|
|
343
343
|
export function milestonesDir(basePath) {
|
|
344
344
|
return join(gsdRoot(basePath), "milestones");
|
|
345
345
|
}
|
|
346
|
+
export function resolveRuntimeFile(basePath) {
|
|
347
|
+
return join(gsdRoot(basePath), "RUNTIME.md");
|
|
348
|
+
}
|
|
346
349
|
export function resolveGsdRootFile(basePath, key) {
|
|
347
350
|
const root = gsdRoot(basePath);
|
|
348
351
|
const canonical = join(root, GSD_ROOT_FILES[key]);
|
|
@@ -717,5 +717,63 @@ export function validatePreferences(preferences) {
|
|
|
717
717
|
errors.push(`context_selection must be one of: full, smart`);
|
|
718
718
|
}
|
|
719
719
|
}
|
|
720
|
+
// ─── GitHub Sync ────────────────────────────────────────────────────────
|
|
721
|
+
if (preferences.github !== undefined) {
|
|
722
|
+
if (typeof preferences.github === "object" && preferences.github !== null) {
|
|
723
|
+
const gh = preferences.github;
|
|
724
|
+
const validGh = {};
|
|
725
|
+
if (gh.enabled !== undefined) {
|
|
726
|
+
if (typeof gh.enabled === "boolean")
|
|
727
|
+
validGh.enabled = gh.enabled;
|
|
728
|
+
else
|
|
729
|
+
errors.push("github.enabled must be a boolean");
|
|
730
|
+
}
|
|
731
|
+
if (gh.repo !== undefined) {
|
|
732
|
+
if (typeof gh.repo === "string" && gh.repo.includes("/"))
|
|
733
|
+
validGh.repo = gh.repo;
|
|
734
|
+
else
|
|
735
|
+
errors.push('github.repo must be a string in "owner/repo" format');
|
|
736
|
+
}
|
|
737
|
+
if (gh.project !== undefined) {
|
|
738
|
+
const p = typeof gh.project === "number" ? gh.project : Number(gh.project);
|
|
739
|
+
if (Number.isFinite(p) && p > 0)
|
|
740
|
+
validGh.project = Math.floor(p);
|
|
741
|
+
else
|
|
742
|
+
errors.push("github.project must be a positive number");
|
|
743
|
+
}
|
|
744
|
+
if (gh.labels !== undefined) {
|
|
745
|
+
if (Array.isArray(gh.labels) && gh.labels.every((l) => typeof l === "string")) {
|
|
746
|
+
validGh.labels = gh.labels;
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
errors.push("github.labels must be an array of strings");
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
if (gh.auto_link_commits !== undefined) {
|
|
753
|
+
if (typeof gh.auto_link_commits === "boolean")
|
|
754
|
+
validGh.auto_link_commits = gh.auto_link_commits;
|
|
755
|
+
else
|
|
756
|
+
errors.push("github.auto_link_commits must be a boolean");
|
|
757
|
+
}
|
|
758
|
+
if (gh.slice_prs !== undefined) {
|
|
759
|
+
if (typeof gh.slice_prs === "boolean")
|
|
760
|
+
validGh.slice_prs = gh.slice_prs;
|
|
761
|
+
else
|
|
762
|
+
errors.push("github.slice_prs must be a boolean");
|
|
763
|
+
}
|
|
764
|
+
const knownGhKeys = new Set(["enabled", "repo", "project", "labels", "auto_link_commits", "slice_prs"]);
|
|
765
|
+
for (const key of Object.keys(gh)) {
|
|
766
|
+
if (!knownGhKeys.has(key)) {
|
|
767
|
+
warnings.push(`unknown github key "${key}" — ignored`);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (Object.keys(validGh).length > 0) {
|
|
771
|
+
validated.github = validGh;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
errors.push("github must be an object");
|
|
776
|
+
}
|
|
777
|
+
}
|
|
720
778
|
return { preferences: validated, errors, warnings };
|
|
721
779
|
}
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
import { existsSync, readFileSync } from "node:fs";
|
|
13
13
|
import { homedir } from "node:os";
|
|
14
14
|
import { join } from "node:path";
|
|
15
|
-
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
16
15
|
import { gsdRoot } from "./paths.js";
|
|
17
16
|
import { parse as parseYaml } from "yaml";
|
|
18
17
|
import { normalizeStringArray } from "../shared/format-utils.js";
|
|
@@ -27,31 +26,40 @@ export { resolveAllSkillReferences, resolveSkillDiscoveryMode, resolveSkillStale
|
|
|
27
26
|
// ─── Re-exports: models ─────────────────────────────────────────────────────
|
|
28
27
|
export { resolveModelForUnit, resolveModelWithFallbacksForUnit, getNextFallbackModel, isTransientNetworkError, validateModelId, updatePreferencesModels, resolveDynamicRoutingConfig, resolveAutoSupervisorConfig, resolveProfileDefaults, resolveEffectiveProfile, resolveInlineLevel, resolveContextSelection, resolveSearchProviderFromPreferences, } from "./preferences-models.js";
|
|
29
28
|
// ─── Path Constants & Getters ───────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
function gsdHome() {
|
|
30
|
+
return process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
31
|
+
}
|
|
32
|
+
function globalPreferencesPath() {
|
|
33
|
+
return join(gsdHome(), "preferences.md");
|
|
34
|
+
}
|
|
35
|
+
function legacyGlobalPreferencesPath() {
|
|
36
|
+
return join(homedir(), ".pi", "agent", "gsd-preferences.md");
|
|
37
|
+
}
|
|
32
38
|
function projectPreferencesPath() {
|
|
33
39
|
return join(gsdRoot(process.cwd()), "preferences.md");
|
|
34
40
|
}
|
|
35
41
|
// Bootstrap in gitignore.ts historically created PREFERENCES.md (uppercase) by mistake.
|
|
36
42
|
// Check uppercase as a fallback so those files aren't silently ignored.
|
|
37
|
-
|
|
43
|
+
function globalPreferencesPathUppercase() {
|
|
44
|
+
return join(gsdHome(), "PREFERENCES.md");
|
|
45
|
+
}
|
|
38
46
|
function projectPreferencesPathUppercase() {
|
|
39
47
|
return join(gsdRoot(process.cwd()), "PREFERENCES.md");
|
|
40
48
|
}
|
|
41
49
|
export function getGlobalGSDPreferencesPath() {
|
|
42
|
-
return
|
|
50
|
+
return globalPreferencesPath();
|
|
43
51
|
}
|
|
44
52
|
export function getLegacyGlobalGSDPreferencesPath() {
|
|
45
|
-
return
|
|
53
|
+
return legacyGlobalPreferencesPath();
|
|
46
54
|
}
|
|
47
55
|
export function getProjectGSDPreferencesPath() {
|
|
48
56
|
return projectPreferencesPath();
|
|
49
57
|
}
|
|
50
58
|
// ─── Loading ────────────────────────────────────────────────────────────────
|
|
51
59
|
export function loadGlobalGSDPreferences() {
|
|
52
|
-
return loadPreferencesFile(
|
|
53
|
-
?? loadPreferencesFile(
|
|
54
|
-
?? loadPreferencesFile(
|
|
60
|
+
return loadPreferencesFile(globalPreferencesPath(), "global")
|
|
61
|
+
?? loadPreferencesFile(globalPreferencesPathUppercase(), "global")
|
|
62
|
+
?? loadPreferencesFile(legacyGlobalPreferencesPath(), "global");
|
|
55
63
|
}
|
|
56
64
|
export function loadProjectGSDPreferences() {
|
|
57
65
|
return loadPreferencesFile(projectPreferencesPath(), "project")
|
|
@@ -203,6 +211,9 @@ function mergePreferences(base, override) {
|
|
|
203
211
|
context_selection: override.context_selection ?? base.context_selection,
|
|
204
212
|
auto_visualize: override.auto_visualize ?? base.auto_visualize,
|
|
205
213
|
auto_report: override.auto_report ?? base.auto_report,
|
|
214
|
+
github: (base.github || override.github)
|
|
215
|
+
? { ...(base.github ?? {}), ...(override.github ?? {}) }
|
|
216
|
+
: undefined,
|
|
206
217
|
};
|
|
207
218
|
}
|
|
208
219
|
function mergeStringLists(base, override) {
|
|
@@ -74,6 +74,10 @@ export function loadPrompt(name, vars = {}) {
|
|
|
74
74
|
content = readFileSync(path, "utf-8");
|
|
75
75
|
templateCache.set(name, content);
|
|
76
76
|
}
|
|
77
|
+
const effectiveVars = {
|
|
78
|
+
skillActivation: "If a `GSD Skill Preferences` block is present in system context, use it and the `<available_skills>` catalog in your system prompt to decide which skills to load and follow for this unit, without relaxing required verification or artifact rules.",
|
|
79
|
+
...vars,
|
|
80
|
+
};
|
|
77
81
|
// Check BEFORE substitution: find all {{varName}} placeholders the template
|
|
78
82
|
// declares and verify every one has a value in vars. Checking after substitution
|
|
79
83
|
// would also flag {{...}} patterns injected by inlined content (e.g. template
|
|
@@ -82,14 +86,14 @@ export function loadPrompt(name, vars = {}) {
|
|
|
82
86
|
if (declared) {
|
|
83
87
|
const missing = [...new Set(declared)]
|
|
84
88
|
.map(m => m.slice(2, -2))
|
|
85
|
-
.filter(key => !(key in
|
|
89
|
+
.filter(key => !(key in effectiveVars));
|
|
86
90
|
if (missing.length > 0) {
|
|
87
91
|
throw new GSDError(GSD_PARSE_ERROR, `loadPrompt("${name}"): template declares {{${missing.join("}}, {{")}}}} but no value was provided. ` +
|
|
88
92
|
`This usually means the extension code in memory is older than the template on disk. ` +
|
|
89
93
|
`Restart pi to reload the extension.`);
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
|
-
for (const [key, value] of Object.entries(
|
|
96
|
+
for (const [key, value] of Object.entries(effectiveVars)) {
|
|
93
97
|
content = content.replaceAll(`{{${key}}}`, value);
|
|
94
98
|
}
|
|
95
99
|
return content.trim();
|
|
@@ -16,7 +16,7 @@ All relevant context has been preloaded below — the roadmap, all slice summari
|
|
|
16
16
|
|
|
17
17
|
Then:
|
|
18
18
|
1. Use the **Milestone Summary** output template from the inlined context above
|
|
19
|
-
2.
|
|
19
|
+
2. {{skillActivation}}
|
|
20
20
|
3. Verify each **success criterion** from the milestone definition in `{{roadmapPath}}`. For each criterion, confirm it was met with specific evidence from slice summaries, test results, or observable behavior. List any criterion that was NOT met.
|
|
21
21
|
4. Verify the milestone's **definition of done** — all slices are `[x]`, all slice summaries exist, and any cross-slice integration points work correctly.
|
|
22
22
|
5. Validate **requirement status transitions**. For each requirement that changed status during this milestone, confirm the transition is supported by evidence. Requirements can move between Active, Validated, Deferred, Blocked, or Out of Scope — but only with proof.
|
|
@@ -20,7 +20,7 @@ All relevant context has been preloaded below — the slice plan, all task summa
|
|
|
20
20
|
|
|
21
21
|
Then:
|
|
22
22
|
1. Use the **Slice Summary** and **UAT** output templates from the inlined context above
|
|
23
|
-
2.
|
|
23
|
+
2. {{skillActivation}}
|
|
24
24
|
3. Run all slice-level verification checks defined in the slice plan. All must pass before marking the slice done. If any fail, fix them first.
|
|
25
25
|
4. If the slice plan includes observability/diagnostic surfaces, confirm they work. Skip this for simple slices that don't have observability sections.
|
|
26
26
|
5. If `.gsd/REQUIREMENTS.md` exists, update it based on what this slice actually proved. Move requirements between Active, Validated, Deferred, Blocked, or Out of Scope only when the evidence from execution supports that change.
|
|
@@ -10,6 +10,8 @@ A researcher explored the codebase and a planner decomposed the work — you are
|
|
|
10
10
|
|
|
11
11
|
{{overridesSection}}
|
|
12
12
|
|
|
13
|
+
{{runtimeContext}}
|
|
14
|
+
|
|
13
15
|
{{resumeSection}}
|
|
14
16
|
|
|
15
17
|
{{carryForwardSection}}
|
|
@@ -26,7 +28,7 @@ A researcher explored the codebase and a planner decomposed the work — you are
|
|
|
26
28
|
|
|
27
29
|
Then:
|
|
28
30
|
0. Narrate step transitions, key implementation decisions, and verification outcomes as you work. Keep it terse — one line between tool-call clusters, not between every call — but write complete sentences in user-facing prose, not shorthand notes or scratchpad fragments.
|
|
29
|
-
1.
|
|
31
|
+
1. {{skillActivation}} Follow any activated skills before writing code. If no skills match this task, skip this step.
|
|
30
32
|
2. Execute the steps in the inlined task plan, adapting minor local mismatches when the surrounding code differs from the planner's snapshot
|
|
31
33
|
3. Build the real thing. If the task plan says "create login endpoint", build an endpoint that actually authenticates against a real store, not one that returns a hardcoded success response. If the task plan says "create dashboard page", build a page that renders real data from the API, not a component with hardcoded props. Stubs and mocks are for tests, not for the shipped feature.
|
|
32
34
|
4. Write or update tests as part of execution — tests are verification, not an afterthought. If the slice plan defines test files in its Verification section and this is the first task, create them (they should initially fail).
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Complete slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Your working directory is `{{workingDirectory}}` — all file operations must use this path. All tasks are done. Your slice summary is the primary record of what was built — downstream agents (reassess-roadmap, future slice researchers) read it to understand what this slice delivered and what to watch out for. Use the **Slice Summary** and **UAT** output templates below.
|
|
1
|
+
Complete slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Your working directory is `{{workingDirectory}}` — all file operations must use this path. All tasks are done. Your slice summary is the primary record of what was built — downstream agents (reassess-roadmap, future slice researchers) read it to understand what this slice delivered and what to watch out for. Use the **Slice Summary** and **UAT** output templates below. {{skillActivation}} Write `{{sliceId}}-SUMMARY.md` (compress task summaries), write `{{sliceId}}-UAT.md`, and fill the `UAT Type` plus `Not Proven By This UAT` sections explicitly so the artifact states what class of acceptance it covers and what still remains unproven. Review task summaries for `key_decisions` and ensure any significant ones are in `.gsd/DECISIONS.md`. Mark the slice checkbox done in the roadmap, update milestone summary, Do not commit or merge manually — the system handles this after the unit completes.
|
|
2
2
|
|
|
3
3
|
{{inlinedTemplates}}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Execute the next task: {{taskId}} ("{{taskTitle}}") in slice {{sliceId}} of milestone {{milestoneId}}. Read the task plan (`{{taskId}}-PLAN.md`), load relevant summaries from prior tasks, and execute each step. Verify must-haves when done. If the task touches UI, browser flows, DOM behavior, or user-visible web state, exercise the real flow in the browser, prefer `browser_batch` for obvious sequences, prefer `browser_assert` for explicit pass/fail verification, use `browser_diff` when an action's effect is ambiguous, and use browser diagnostics when validating async or failure-prone UI. If you made an architectural, pattern, or library decision, append it to `.gsd/DECISIONS.md`. Use the **Task Summary** output template below. Write `{{taskId}}-SUMMARY.md`, mark it done, commit, and advance.
|
|
1
|
+
Execute the next task: {{taskId}} ("{{taskTitle}}") in slice {{sliceId}} of milestone {{milestoneId}}. Read the task plan (`{{taskId}}-PLAN.md`), load relevant summaries from prior tasks, and execute each step. Verify must-haves when done. If the task touches UI, browser flows, DOM behavior, or user-visible web state, exercise the real flow in the browser, prefer `browser_batch` for obvious sequences, prefer `browser_assert` for explicit pass/fail verification, use `browser_diff` when an action's effect is ambiguous, and use browser diagnostics when validating async or failure-prone UI. If you made an architectural, pattern, or library decision, append it to `.gsd/DECISIONS.md`. Use the **Task Summary** output template below. Write `{{taskId}}-SUMMARY.md`, mark it done, commit, and advance. {{skillActivation}} If running long and not all steps are finished, stop implementing and prioritize writing a clean partial summary over attempting one more step — a recoverable handoff is more valuable than a half-finished step with no documentation. If verification fails, debug methodically: form a hypothesis and test that specific theory before changing anything, change one variable at a time, read entire functions not just the suspect line, distinguish observable facts from assumptions, and if 3+ fixes fail without progress stop and reassess your mental model — list what you know for certain, what you've ruled out, and form fresh hypotheses. Don't fix symptoms — understand why something fails before changing code.
|
|
2
2
|
|
|
3
3
|
{{inlinedTemplates}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Plan milestone {{milestoneId}} ("{{milestoneTitle}}"). Read `.gsd/DECISIONS.md` if it exists — respect existing decisions. Read `.gsd/REQUIREMENTS.md` if it exists and treat Active requirements as the capability contract. If `REQUIREMENTS.md` is missing, continue in legacy compatibility mode but explicitly note missing requirement coverage. Use the **Roadmap** output template below. Create `{{milestoneId}}-ROADMAP.md` in the milestone directory with slices, risk levels, dependencies, demo sentences, verification classes, milestone definition of done, requirement coverage, and a boundary map. Write success criteria as observable truths, not implementation tasks. If the milestone crosses multiple runtime boundaries, include an explicit final integration slice that proves the assembled system works end-to-end in a real environment. If planning produces structural decisions, append them to `.gsd/DECISIONS.md`.
|
|
1
|
+
Plan milestone {{milestoneId}} ("{{milestoneTitle}}"). Read `.gsd/DECISIONS.md` if it exists — respect existing decisions. Read `.gsd/REQUIREMENTS.md` if it exists and treat Active requirements as the capability contract. If `REQUIREMENTS.md` is missing, continue in legacy compatibility mode but explicitly note missing requirement coverage. Use the **Roadmap** output template below. Create `{{milestoneId}}-ROADMAP.md` in the milestone directory with slices, risk levels, dependencies, demo sentences, verification classes, milestone definition of done, requirement coverage, and a boundary map. Write success criteria as observable truths, not implementation tasks. If the milestone crosses multiple runtime boundaries, include an explicit final integration slice that proves the assembled system works end-to-end in a real environment. If planning produces structural decisions, append them to `.gsd/DECISIONS.md`. {{skillActivation}}
|
|
2
2
|
|
|
3
3
|
## Requirement Rules
|
|
4
4
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Plan slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements the roadmap says this slice owns or supports, and ensure the plan delivers them. Read the roadmap boundary map, any existing context/research files, and dependency summaries. Use the **Slice Plan** and **Task Plan** output templates below. Decompose into tasks with must-haves. Fill the `Proof Level` and `Integration Closure` sections truthfully so the plan says what class of proof this slice really delivers and what end-to-end wiring still remains. Write `{{sliceId}}-PLAN.md` and individual `T##-PLAN.md` files in the `tasks/` subdirectory. If planning produces structural decisions, append them to `.gsd/DECISIONS.md`.
|
|
1
|
+
Plan slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements the roadmap says this slice owns or supports, and ensure the plan delivers them. Read the roadmap boundary map, any existing context/research files, and dependency summaries. Use the **Slice Plan** and **Task Plan** output templates below. Decompose into tasks with must-haves. Fill the `Proof Level` and `Integration Closure` sections truthfully so the plan says what class of proof this slice really delivers and what end-to-end wiring still remains. Write `{{sliceId}}-PLAN.md` and individual `T##-PLAN.md` files in the `tasks/` subdirectory. If planning produces structural decisions, append them to `.gsd/DECISIONS.md`. {{skillActivation}} Before committing, self-audit the plan: every must-have maps to at least one task, every task has complete sections (steps, must-haves, verification, observability impact, inputs, and expected output), task ordering is consistent with no circular references, every pair of artifacts that must connect has an explicit wiring step, task scope targets 2–5 steps and 3–8 files (6–8 steps or 8–10 files — consider splitting; 10+ steps or 12+ files — must split), the plan honors locked decisions from context/research/decisions artifacts, the proof-level wording does not overclaim live integration if only fixture/contract proof is planned, every Active requirement this slice owns has at least one task with verification that proves it is met, and every task produces real user-facing progress — if the slice has a UI surface at least one task builds the real UI, if it has an API at least one task connects it to a real data source, and showing the completed result to a non-technical stakeholder would demonstrate real product progress rather than developer artifacts.
|
|
2
2
|
|
|
3
3
|
{{inlinedTemplates}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Research slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions, don't contradict them. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements this slice owns or supports and target research toward risks, unknowns, and constraints that could affect delivery of those requirements.
|
|
1
|
+
Research slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions, don't contradict them. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements this slice owns or supports and target research toward risks, unknowns, and constraints that could affect delivery of those requirements. {{skillActivation}} Explore the relevant code — use `rg`/`find` for targeted reads, or `scout` if the area is broad or unfamiliar. Check libraries with `resolve_library`/`get_library_docs` — skip this for libraries already used in the codebase. Use the **Research** output template below. Write `{{sliceId}}-RESEARCH.md` in the slice directory.
|
|
2
2
|
|
|
3
3
|
**You are the scout.** A planner agent reads your output in a fresh context to decompose this slice into tasks. Write for the planner — surface key files, where the work divides naturally, what to build first, and how to verify. If the research doc is vague, the planner re-explores code you already read. If it's precise, the planner decomposes immediately.
|
|
4
4
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Resume interrupted work. Find the continue file (`{{sliceId}}-CONTINUE.md` or `continue.md`) in slice {{sliceId}} of milestone {{milestoneId}}, read it, and use it as the recovery contract for where to pick up. Do **not** delete the continue file immediately. Keep it until the task is successfully completed or you have written a newer summary/continue artifact that clearly supersedes it. If the resumed attempt fails again, update or replace the continue file so no recovery context is lost.
|
|
1
|
+
Resume interrupted work. Find the continue file (`{{sliceId}}-CONTINUE.md` or `continue.md`) in slice {{sliceId}} of milestone {{milestoneId}}, read it, and use it as the recovery contract for where to pick up. Do **not** delete the continue file immediately. Keep it until the task is successfully completed or you have written a newer summary/continue artifact that clearly supersedes it. If the resumed attempt fails again, update or replace the continue file so no recovery context is lost. {{skillActivation}}
|
|
@@ -44,7 +44,7 @@ Narrate your decomposition reasoning — why you're grouping work this way, what
|
|
|
44
44
|
|
|
45
45
|
Then:
|
|
46
46
|
1. Use the **Roadmap** output template from the inlined context above
|
|
47
|
-
2.
|
|
47
|
+
2. {{skillActivation}}
|
|
48
48
|
3. Create the roadmap: decompose into demoable vertical slices — as many as the work genuinely needs, no more. A simple feature might be 1 slice. Don't decompose for decomposition's sake.
|
|
49
49
|
4. Order by risk (high-risk first)
|
|
50
50
|
5. Write `{{outputPath}}` with checkboxes, risk, depends, demo sentences, proof strategy, verification classes, milestone definition of done, **requirement coverage**, and a boundary map. Write success criteria as observable truths, not implementation tasks. If the milestone crosses multiple runtime boundaries, include an explicit final integration slice that proves the assembled system works end-to-end in a real environment
|
|
@@ -47,7 +47,7 @@ Then:
|
|
|
47
47
|
1. Read the templates:
|
|
48
48
|
- `~/.gsd/agent/extensions/gsd/templates/plan.md`
|
|
49
49
|
- `~/.gsd/agent/extensions/gsd/templates/task-plan.md`
|
|
50
|
-
2.
|
|
50
|
+
2. {{skillActivation}} Record the installed skills you expect executors to use in each task plan's `skills_used` frontmatter.
|
|
51
51
|
3. Define slice-level verification — the objective stopping condition for this slice:
|
|
52
52
|
- For non-trivial slices: plan actual test files with real assertions. Name the files.
|
|
53
53
|
- For simple slices: executable commands or script assertions are fine.
|
|
@@ -22,7 +22,7 @@ The following user thoughts were captured during execution and deferred to futur
|
|
|
22
22
|
|
|
23
23
|
{{deferredCaptures}}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
{{skillActivation}}
|
|
26
26
|
|
|
27
27
|
Then assess whether the remaining roadmap still makes sense given what was just built.
|
|
28
28
|
|
|
@@ -21,7 +21,7 @@ Write for the roadmap planner. It needs to understand: what exists in the codeba
|
|
|
21
21
|
A milestone adding a small feature to an established codebase needs targeted research — check the relevant code, confirm the approach, note constraints. A milestone introducing new technology, building a new system, or spanning multiple unfamiliar subsystems needs deep research — explore broadly, look up docs, investigate alternatives. Match your effort to the actual uncertainty, not the template's section count. Include only sections that have real content.
|
|
22
22
|
|
|
23
23
|
Then research the codebase and relevant technologies. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach.
|
|
24
|
-
1.
|
|
24
|
+
1. {{skillActivation}}
|
|
25
25
|
2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
|
|
26
26
|
3. Explore relevant code. For small/familiar codebases, use `rg`, `find`, and targeted reads. For large or unfamiliar codebases, use `scout` to build a broad map efficiently before diving in.
|
|
27
27
|
4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase
|
|
@@ -42,7 +42,7 @@ An honest "this is straightforward, here's the pattern to follow" is more valuab
|
|
|
42
42
|
|
|
43
43
|
Research what this slice needs. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach.
|
|
44
44
|
0. If `REQUIREMENTS.md` was preloaded above, identify which Active requirements this slice owns or supports. Research should target these requirements — surfacing risks, unknowns, and implementation constraints that could affect whether the slice actually delivers them.
|
|
45
|
-
1.
|
|
45
|
+
1. {{skillActivation}} Reference specific rules from loaded skills in your findings where they inform the implementation approach.
|
|
46
46
|
2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}}
|
|
47
47
|
3. Explore relevant code for this slice's scope. For targeted exploration, use `rg`, `find`, and reads. For broad or unfamiliar subsystems, use `scout` to map the relevant area first.
|
|
48
48
|
4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase
|
|
@@ -10,7 +10,7 @@ All relevant context has been preloaded below. Start working immediately without
|
|
|
10
10
|
|
|
11
11
|
{{inlinedContext}}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
{{skillActivation}}
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -25,6 +25,8 @@ You are the UAT runner. Execute every check defined in `{{uatPath}}` as deeply a
|
|
|
25
25
|
### Automation rules by mode
|
|
26
26
|
|
|
27
27
|
- `artifact-driven` — verify with shell commands, scripts, file reads, and artifact structure checks.
|
|
28
|
+
- `browser-executable` — use browser tools to navigate to the target URL and verify expected behavior. Capture screenshots as evidence. Record pass/fail with specific assertions.
|
|
29
|
+
- `runtime-executable` — execute the specified command or script. Capture stdout/stderr as evidence. Record pass/fail based on exit code and output.
|
|
28
30
|
- `live-runtime` — exercise the real runtime path. Start or connect to the app/service if needed, use browser/runtime/network checks, and verify observable behavior.
|
|
29
31
|
- `mixed` — run all automatable artifact-driven and live-runtime checks. Separate any remaining human-only checks explicitly.
|
|
30
32
|
- `human-experience` — automate setup, preconditions, screenshots, logs, and objective checks, but do **not** invent subjective PASS results. Mark taste-based, experiential, or purely human-judgment checks as `NEEDS-HUMAN` and use an overall verdict of `PARTIAL` unless every required check was objective and passed.
|