gsd-pi 2.46.1-dev.9d471d1 → 2.46.1-dev.eee1457
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 +46 -29
- package/dist/resources/extensions/claude-code-cli/index.js +25 -0
- package/dist/resources/extensions/claude-code-cli/models.js +40 -0
- package/dist/resources/extensions/claude-code-cli/package.json +11 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +223 -0
- package/dist/resources/extensions/claude-code-cli/readiness.js +26 -0
- package/dist/resources/extensions/claude-code-cli/sdk-types.js +8 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +309 -0
- package/dist/resources/extensions/gsd/auto-start.js +9 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +5 -2
- package/dist/resources/extensions/gsd/state.js +29 -2
- package/dist/resources/extensions/gsd/workflow-events.js +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -1
- package/packages/pi-agent-core/dist/agent-loop.js +26 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +7 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +9 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +25 -1
- package/packages/pi-agent-core/src/agent.ts +10 -0
- package/packages/pi-agent-core/src/types.ts +10 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +27 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +27 -2
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -0
- package/src/resources/extensions/claude-code-cli/index.ts +28 -0
- package/src/resources/extensions/claude-code-cli/models.ts +42 -0
- package/src/resources/extensions/claude-code-cli/package.json +11 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +258 -0
- package/src/resources/extensions/claude-code-cli/readiness.ts +30 -0
- package/src/resources/extensions/claude-code-cli/sdk-types.ts +149 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +370 -0
- package/src/resources/extensions/gsd/auto-start.ts +8 -7
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +5 -2
- package/src/resources/extensions/gsd/state.ts +33 -1
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +25 -0
- package/src/resources/extensions/gsd/workflow-events.ts +1 -1
- /package/dist/web/standalone/.next/static/{_zz1oqjzv1VmV-zmxlJPF → MN4KAhNleSmucaEc-vzTu}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{_zz1oqjzv1VmV-zmxlJPF → MN4KAhNleSmucaEc-vzTu}/_ssgManifest.js +0 -0
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
getReplanHistory,
|
|
50
50
|
getSlice,
|
|
51
51
|
insertMilestone,
|
|
52
|
+
updateTaskStatus,
|
|
52
53
|
type MilestoneRow,
|
|
53
54
|
type SliceRow,
|
|
54
55
|
type TaskRow,
|
|
@@ -629,7 +630,38 @@ export async function deriveStateFromDb(basePath: string): Promise<GSDState> {
|
|
|
629
630
|
}
|
|
630
631
|
|
|
631
632
|
// ── Get tasks from DB ────────────────────────────────────────────────
|
|
632
|
-
|
|
633
|
+
let tasks = getSliceTasks(activeMilestone.id, activeSlice.id);
|
|
634
|
+
|
|
635
|
+
// ── Reconcile stale task status (#2514) ──────────────────────────────
|
|
636
|
+
// When a session disconnects after the agent writes SUMMARY + VERIFY
|
|
637
|
+
// artifacts but before postUnitPostVerification updates the DB, tasks
|
|
638
|
+
// remain "pending" in the DB despite being complete on disk. Without
|
|
639
|
+
// reconciliation, deriveState keeps returning the stale task as active,
|
|
640
|
+
// causing the dispatcher to re-dispatch the same completed task forever.
|
|
641
|
+
let reconciled = false;
|
|
642
|
+
for (const t of tasks) {
|
|
643
|
+
if (isStatusDone(t.status)) continue;
|
|
644
|
+
const summaryPath = resolveTaskFile(basePath, activeMilestone.id, activeSlice.id, t.id, "SUMMARY");
|
|
645
|
+
if (summaryPath && existsSync(summaryPath)) {
|
|
646
|
+
try {
|
|
647
|
+
updateTaskStatus(activeMilestone.id, activeSlice.id, t.id, "complete");
|
|
648
|
+
process.stderr.write(
|
|
649
|
+
`gsd-reconcile: task ${activeMilestone.id}/${activeSlice.id}/${t.id} had SUMMARY on disk but DB status was "${t.status}" — updated to "complete" (#2514)\n`,
|
|
650
|
+
);
|
|
651
|
+
reconciled = true;
|
|
652
|
+
} catch (e) {
|
|
653
|
+
// DB write failed — continue with stale status rather than crash
|
|
654
|
+
process.stderr.write(
|
|
655
|
+
`gsd-reconcile: failed to update task ${t.id}: ${(e as Error).message}\n`,
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
// Re-fetch tasks if any were reconciled so downstream logic sees fresh status
|
|
661
|
+
if (reconciled) {
|
|
662
|
+
tasks = getSliceTasks(activeMilestone.id, activeSlice.id);
|
|
663
|
+
}
|
|
664
|
+
|
|
633
665
|
const taskProgress = {
|
|
634
666
|
done: tasks.filter(t => isStatusDone(t.status)).length,
|
|
635
667
|
total: tasks.length,
|
|
@@ -119,3 +119,73 @@ describe("isInheritedRepo when git root is HOME (#2393)", () => {
|
|
|
119
119
|
);
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
|
+
|
|
123
|
+
describe("isInheritedRepo with stale .gsd at parent git root", () => {
|
|
124
|
+
let parentRepo: string;
|
|
125
|
+
|
|
126
|
+
beforeEach(() => {
|
|
127
|
+
parentRepo = realpathSync(mkdtempSync(join(tmpdir(), "gsd-stale-parent-")));
|
|
128
|
+
run("git", ["init", "-b", "main"], parentRepo);
|
|
129
|
+
run("git", ["config", "user.name", "Test"], parentRepo);
|
|
130
|
+
run("git", ["config", "user.email", "test@example.com"], parentRepo);
|
|
131
|
+
writeFileSync(join(parentRepo, "README.md"), "# Parent\n", "utf-8");
|
|
132
|
+
run("git", ["add", "README.md"], parentRepo);
|
|
133
|
+
run("git", ["commit", "-m", "init"], parentRepo);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
afterEach(() => {
|
|
137
|
+
rmSync(parentRepo, { recursive: true, force: true });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("stale .gsd dir at parent git root does not suppress inherited detection", () => {
|
|
141
|
+
// Simulate a stale .gsd directory at the parent git root (e.g. from a
|
|
142
|
+
// prior doctor run or accidental init). This is a real directory, NOT
|
|
143
|
+
// a symlink, and NOT the global GSD home.
|
|
144
|
+
mkdirSync(join(parentRepo, ".gsd"), { recursive: true });
|
|
145
|
+
|
|
146
|
+
const projectDir = join(parentRepo, "my-project");
|
|
147
|
+
mkdirSync(projectDir, { recursive: true });
|
|
148
|
+
|
|
149
|
+
// Without fix: isProjectGsd(join(root, ".gsd")) returns true because
|
|
150
|
+
// the stale .gsd is a real directory that isn't the global GSD home,
|
|
151
|
+
// causing isInheritedRepo to return false (false negative).
|
|
152
|
+
//
|
|
153
|
+
// The stale .gsd at parent is still treated as a "project .gsd" by
|
|
154
|
+
// isProjectGsd(), so the git root check at line 128 returns false.
|
|
155
|
+
// This is the expected behavior for that check — the defense-in-depth
|
|
156
|
+
// fix in auto-start.ts handles this case by checking for local .git.
|
|
157
|
+
//
|
|
158
|
+
// Verify the function behavior is consistent:
|
|
159
|
+
assert.strictEqual(
|
|
160
|
+
isInheritedRepo(projectDir),
|
|
161
|
+
false,
|
|
162
|
+
"stale .gsd dir at git root still causes isInheritedRepo to return false " +
|
|
163
|
+
"(defense-in-depth in auto-start.ts handles this case)",
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("basePath's own .gsd symlink does not suppress inherited detection", () => {
|
|
168
|
+
// Create a project subdir with its own .gsd symlink (set up during
|
|
169
|
+
// the discuss phase, before auto-mode bootstrap runs).
|
|
170
|
+
const projectDir = join(parentRepo, "my-project");
|
|
171
|
+
mkdirSync(projectDir, { recursive: true });
|
|
172
|
+
|
|
173
|
+
const externalState = mkdtempSync(join(tmpdir(), "gsd-ext-state-"));
|
|
174
|
+
symlinkSync(externalState, join(projectDir, ".gsd"));
|
|
175
|
+
|
|
176
|
+
// Before fix: the walk-up loop started at normalizedBase (projectDir),
|
|
177
|
+
// found .gsd at projectDir, and returned false — even though projectDir
|
|
178
|
+
// has no .git of its own. The .gsd at basePath is irrelevant to whether
|
|
179
|
+
// the git repo is inherited from a parent.
|
|
180
|
+
//
|
|
181
|
+
// After fix: the walk-up starts at dirname(normalizedBase), skipping
|
|
182
|
+
// basePath's own .gsd.
|
|
183
|
+
assert.strictEqual(
|
|
184
|
+
isInheritedRepo(projectDir),
|
|
185
|
+
true,
|
|
186
|
+
"project's own .gsd symlink must not suppress inherited repo detection",
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
rmSync(externalState, { recursive: true, force: true });
|
|
190
|
+
});
|
|
191
|
+
});
|
|
@@ -61,6 +61,18 @@ test("plan-slice prompt: DB-backed tool names survive template substitution", ()
|
|
|
61
61
|
assert.ok(result.includes("canonical write path"), "canonical write path language should survive substitution");
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
test("plan-slice prompt: footer references gsd_plan_slice tool, not direct write", () => {
|
|
65
|
+
const result = loadPrompt("plan-slice", { ...BASE_VARS, commitInstruction: "Do not commit." });
|
|
66
|
+
assert.ok(
|
|
67
|
+
result.includes("MUST call `gsd_plan_slice`"),
|
|
68
|
+
"footer should instruct calling gsd_plan_slice tool",
|
|
69
|
+
);
|
|
70
|
+
assert.ok(
|
|
71
|
+
!result.includes("MUST write the file"),
|
|
72
|
+
"footer should not instruct direct file write",
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
64
76
|
test("domain-work prompts use skillActivation placeholder", () => {
|
|
65
77
|
const prompts = [
|
|
66
78
|
"research-milestone",
|
|
@@ -174,6 +186,34 @@ test("research-milestone prompt substitutes skillActivation", () => {
|
|
|
174
186
|
assert.ok(!result.includes("{{skillActivation}}"));
|
|
175
187
|
});
|
|
176
188
|
|
|
189
|
+
test("research-milestone prompt references gsd_summary_save, not direct write", () => {
|
|
190
|
+
const result = loadPrompt("research-milestone", {
|
|
191
|
+
workingDirectory: "/tmp/test-project",
|
|
192
|
+
milestoneId: "M001",
|
|
193
|
+
milestoneTitle: "Test Milestone",
|
|
194
|
+
milestonePath: ".gsd/milestones/M001",
|
|
195
|
+
contextPath: ".gsd/milestones/M001/M001-CONTEXT.md",
|
|
196
|
+
outputPath: "/tmp/test-project/.gsd/milestones/M001/M001-RESEARCH.md",
|
|
197
|
+
inlinedContext: "Context",
|
|
198
|
+
skillDiscoveryMode: "manual",
|
|
199
|
+
skillDiscoveryInstructions: " Discover skills manually.",
|
|
200
|
+
skillActivation: "Load research skills first.",
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
assert.ok(
|
|
204
|
+
result.includes("gsd_summary_save"),
|
|
205
|
+
"research-milestone should reference gsd_summary_save tool",
|
|
206
|
+
);
|
|
207
|
+
assert.ok(
|
|
208
|
+
result.includes('artifact_type: "RESEARCH"'),
|
|
209
|
+
"research-milestone should specify RESEARCH artifact type",
|
|
210
|
+
);
|
|
211
|
+
assert.ok(
|
|
212
|
+
!result.includes("MUST write the file"),
|
|
213
|
+
"research-milestone should not instruct direct file write",
|
|
214
|
+
);
|
|
215
|
+
});
|
|
216
|
+
|
|
177
217
|
test("research-slice prompt substitutes skillActivation", () => {
|
|
178
218
|
const result = loadPrompt("research-slice", {
|
|
179
219
|
workingDirectory: "/tmp/test-project",
|
|
@@ -228,6 +228,31 @@ test('(k) run-uat prompt template', () => {
|
|
|
228
228
|
);
|
|
229
229
|
});
|
|
230
230
|
|
|
231
|
+
test('(k2) run-uat prompt references gsd_summary_save, not direct write', () => {
|
|
232
|
+
const promptResult = loadPromptFromWorktree('run-uat', {
|
|
233
|
+
workingDirectory: '/tmp/test-project',
|
|
234
|
+
milestoneId: 'M001',
|
|
235
|
+
sliceId: 'S01',
|
|
236
|
+
uatPath: '.gsd/milestones/M001/slices/S01/S01-UAT.md',
|
|
237
|
+
uatResultPath: '.gsd/milestones/M001/slices/S01/S01-UAT-RESULT.md',
|
|
238
|
+
uatType: 'artifact-driven',
|
|
239
|
+
inlinedContext: '<!-- no context -->',
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
assert.ok(
|
|
243
|
+
promptResult.includes('gsd_summary_save'),
|
|
244
|
+
'run-uat prompt should reference gsd_summary_save tool',
|
|
245
|
+
);
|
|
246
|
+
assert.ok(
|
|
247
|
+
promptResult.includes('artifact_type: "ASSESSMENT"'),
|
|
248
|
+
'run-uat prompt should specify ASSESSMENT artifact type',
|
|
249
|
+
);
|
|
250
|
+
assert.ok(
|
|
251
|
+
!promptResult.includes('MUST write'),
|
|
252
|
+
'run-uat prompt should not instruct direct file write in footer',
|
|
253
|
+
);
|
|
254
|
+
});
|
|
255
|
+
|
|
231
256
|
test('(l) dispatch preconditions via resolveSliceFile', () => {
|
|
232
257
|
const base = createFixtureBase();
|
|
233
258
|
const uatContent = makeUatContent('artifact-driven');
|
|
@@ -40,7 +40,7 @@ export function appendEvent(
|
|
|
40
40
|
event: Omit<WorkflowEvent, "hash" | "session_id"> & { actor_name?: string; trigger_reason?: string },
|
|
41
41
|
): void {
|
|
42
42
|
const hash = createHash("sha256")
|
|
43
|
-
.update(JSON.stringify({ cmd: event.cmd, params: event.params
|
|
43
|
+
.update(JSON.stringify({ cmd: event.cmd, params: event.params }))
|
|
44
44
|
.digest("hex")
|
|
45
45
|
.slice(0, 16);
|
|
46
46
|
|
|
File without changes
|
|
File without changes
|