@opengsd/gsd-pi 1.3.0-dev.72e3af2a → 1.3.0-dev.738160b9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +17 -4
- package/dist/headless-answers.js +1 -1
- package/dist/headless-ui.d.ts +1 -1
- package/dist/headless-ui.js +1 -1
- package/dist/headless.js +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +1 -1
- package/dist/resources/extensions/gsd/auto-budget.js +5 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +14 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +1 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +3 -3
- package/dist/resources/extensions/gsd/auto-recovery.js +3 -3
- package/dist/resources/extensions/gsd/auto-verification.js +5 -2
- package/dist/resources/extensions/gsd/auto.js +19 -10
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +1 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +5 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -2
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +32 -4
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +3 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands-usage.js +1 -1
- package/dist/resources/extensions/gsd/db/engine.js +4 -1
- package/dist/resources/extensions/gsd/db-memory-fts-schema.js +34 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +1 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +192 -4
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +3 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +8 -2
- package/dist/resources/extensions/gsd/flat-phase-migration.js +45 -0
- package/dist/resources/extensions/gsd/git-service.js +57 -0
- package/dist/resources/extensions/gsd/gitignore.js +4 -1
- package/dist/resources/extensions/gsd/json-persistence.js +20 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +18 -11
- package/dist/resources/extensions/gsd/memory-backfill.js +28 -21
- package/dist/resources/extensions/gsd/metrics.js +4 -4
- package/dist/resources/extensions/gsd/migrate-external.js +11 -2
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +92 -16
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +7 -1
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +8 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +16 -1
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +5 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +4 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +59 -44
- package/dist/resources/extensions/gsd/tools/plan-task.js +28 -5
- package/dist/resources/extensions/gsd/undo.js +43 -6
- package/dist/resources/extensions/gsd/unit-registry.js +4 -2
- package/dist/resources/extensions/gsd/verification-gate.js +7 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +126 -13
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- 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 +1 -1
- 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 +9 -9
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +23 -5
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +3 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +46 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +38 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/tests/index.test.ts +14 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/session.ts +9 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +3 -1
- package/src/resources/extensions/gsd/auto-budget.ts +12 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +3 -3
- package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
- package/src/resources/extensions/gsd/auto-verification.ts +5 -1
- package/src/resources/extensions/gsd/auto.ts +23 -8
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -2
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +34 -4
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands-usage.ts +1 -1
- package/src/resources/extensions/gsd/db/engine.ts +8 -1
- package/src/resources/extensions/gsd/db-memory-fts-schema.ts +45 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +1 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +233 -5
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +3 -0
- package/src/resources/extensions/gsd/doctor-types.ts +3 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +7 -2
- package/src/resources/extensions/gsd/flat-phase-migration.ts +44 -0
- package/src/resources/extensions/gsd/git-service.ts +64 -0
- package/src/resources/extensions/gsd/gitignore.ts +4 -1
- package/src/resources/extensions/gsd/json-persistence.ts +20 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +16 -10
- package/src/resources/extensions/gsd/memory-backfill.ts +26 -20
- package/src/resources/extensions/gsd/metrics.ts +4 -4
- package/src/resources/extensions/gsd/migrate-external.ts +8 -2
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +108 -20
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +3 -3
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +13 -1
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +9 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +16 -1
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +8 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +14 -5
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +182 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/complete-slice-reopen-handoff.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +58 -3
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +143 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +239 -2
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +37 -2
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/json-persistence-atomic.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +91 -7
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +103 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +44 -1
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -3
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +62 -5
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/undo.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +69 -4
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +96 -15
- package/src/resources/extensions/gsd/tests/workflow-mcp-preflight.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +6 -5
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +60 -47
- package/src/resources/extensions/gsd/tools/plan-task.ts +30 -5
- package/src/resources/extensions/gsd/undo.ts +47 -6
- package/src/resources/extensions/gsd/unit-registry.ts +4 -2
- package/src/resources/extensions/gsd/verification-gate.ts +8 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +141 -7
- /package/dist/web/standalone/.next/static/{O7xDYXO0r4zFhIzY1hrWV → 2A_WqqCS-EoYZxN9_v3d2}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{O7xDYXO0r4zFhIzY1hrWV → 2A_WqqCS-EoYZxN9_v3d2}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-coding-agent",
|
|
3
|
-
"version": "1.3.0-dev.
|
|
3
|
+
"version": "1.3.0-dev.738160b9",
|
|
4
4
|
"description": "Coding agent CLI (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"copy-assets": "node scripts/copy-assets.cjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@opengsd/contracts": "^1.3.0-dev.
|
|
36
|
+
"@opengsd/contracts": "^1.3.0-dev.738160b9",
|
|
37
37
|
"@mariozechner/jiti": "^2.6.2",
|
|
38
38
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
39
39
|
"chalk": "5.6.2",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"typebox": "1.1.38",
|
|
54
54
|
"undici": "7.28.0",
|
|
55
55
|
"yaml": "2.9.0",
|
|
56
|
-
"@gsd/agent-core": "^1.3.0-dev.
|
|
57
|
-
"@gsd/native": "^1.3.0-dev.
|
|
58
|
-
"@gsd/pi-agent-core": "^1.3.0-dev.
|
|
59
|
-
"@gsd/pi-ai": "^1.3.0-dev.
|
|
60
|
-
"@gsd/pi-tui": "^1.3.0-dev.
|
|
56
|
+
"@gsd/agent-core": "^1.3.0-dev.738160b9",
|
|
57
|
+
"@gsd/native": "^1.3.0-dev.738160b9",
|
|
58
|
+
"@gsd/pi-agent-core": "^1.3.0-dev.738160b9",
|
|
59
|
+
"@gsd/pi-ai": "^1.3.0-dev.738160b9",
|
|
60
|
+
"@gsd/pi-tui": "^1.3.0-dev.738160b9",
|
|
61
61
|
"@sinclair/typebox": "^0.34.41"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-tui",
|
|
3
|
-
"version": "1.3.0-dev.
|
|
3
|
+
"version": "1.3.0-dev.738160b9",
|
|
4
4
|
"description": "Terminal UI library (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "node ../../scripts/clean-package-dist.cjs && tsc -p tsconfig.json --incremental false"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@gsd/native": "^1.3.0-dev.
|
|
24
|
+
"@gsd/native": "^1.3.0-dev.738160b9",
|
|
25
25
|
"get-east-asian-width": "1.6.0",
|
|
26
26
|
"marked": "15.0.12",
|
|
27
27
|
"@sinclair/typebox": "^0.34.41"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/rpc-client",
|
|
3
|
-
"version": "1.3.0-dev.
|
|
3
|
+
"version": "1.3.0-dev.738160b9",
|
|
4
4
|
"description": "Standalone RPC client SDK for GSD — zero internal dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"gsd": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test dist/rpc-client.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@opengsd/contracts": "^1.3.0-dev.
|
|
37
|
+
"@opengsd/contracts": "^1.3.0-dev.738160b9"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/pkg/package.json
CHANGED
|
@@ -48,6 +48,15 @@ export const CLAUDE_CODE_MODELS = [
|
|
|
48
48
|
contextWindow: 1_000_000,
|
|
49
49
|
maxTokens: 128_000,
|
|
50
50
|
},
|
|
51
|
+
{
|
|
52
|
+
id: "claude-sonnet-5",
|
|
53
|
+
name: "Claude Sonnet 5 (via Claude Code)",
|
|
54
|
+
reasoning: true,
|
|
55
|
+
input: ["text", "image"] as ("text" | "image")[],
|
|
56
|
+
cost: ZERO_COST,
|
|
57
|
+
contextWindow: 1_000_000,
|
|
58
|
+
maxTokens: 128_000,
|
|
59
|
+
},
|
|
51
60
|
{
|
|
52
61
|
id: "claude-sonnet-4-6",
|
|
53
62
|
name: "Claude Sonnet 4.6 (via Claude Code)",
|
|
@@ -30,6 +30,20 @@ test("registers the claude-code provider with a streamSimple delegate", () => {
|
|
|
30
30
|
assert.equal(typeof providers[0].config.streamSimple, "function");
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
test("registers Claude Sonnet 5 as a Claude Code CLI model", () => {
|
|
34
|
+
const { pi, providers } = makeMockPi();
|
|
35
|
+
claudeCodeCli(pi as never);
|
|
36
|
+
|
|
37
|
+
const models = providers[0].config.models as Array<Record<string, unknown>>;
|
|
38
|
+
const sonnet5 = models.find((model) => model.id === "claude-sonnet-5");
|
|
39
|
+
|
|
40
|
+
assert.ok(sonnet5, "claude-sonnet-5 must be selectable via the claude-code provider");
|
|
41
|
+
assert.equal(sonnet5.name, "Claude Sonnet 5 (via Claude Code)");
|
|
42
|
+
assert.equal(sonnet5.reasoning, true);
|
|
43
|
+
assert.equal(sonnet5.contextWindow, 1_000_000);
|
|
44
|
+
assert.equal(sonnet5.maxTokens, 128_000);
|
|
45
|
+
});
|
|
46
|
+
|
|
33
47
|
test("registers a before_provider_request hook to capture the UI context", () => {
|
|
34
48
|
const { pi, handlers } = makeMockPi();
|
|
35
49
|
claudeCodeCli(pi as never);
|
|
@@ -56,6 +56,7 @@ export type ThinkingLevelSnapshot = ReturnType<ExtensionAPI["getThinkingLevel"]>
|
|
|
56
56
|
export interface PendingVerificationRetry {
|
|
57
57
|
unitId: string;
|
|
58
58
|
failureContext: string;
|
|
59
|
+
signature?: string;
|
|
59
60
|
attempt: number;
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -211,6 +212,13 @@ export class AutoSession {
|
|
|
211
212
|
* the issues after MAX_PRE_EXEC_RETRIES re-attempts.
|
|
212
213
|
*/
|
|
213
214
|
readonly preExecRetryCount: Map<string, number> = new Map();
|
|
215
|
+
/**
|
|
216
|
+
* Tracks how many times each slice unit has been re-dispatched to plan-slice
|
|
217
|
+
* because task plan files were missing. Keyed by unitId (e.g. "M001/S01").
|
|
218
|
+
* Separate from preExecRetryCount so pre-exec gate failures do not block or
|
|
219
|
+
* conflate with missing-task-plan recovery.
|
|
220
|
+
*/
|
|
221
|
+
readonly missingTaskPlanRetryCount: Map<string, number> = new Map();
|
|
214
222
|
|
|
215
223
|
// ── Tool invocation errors (#2883) ──────────────────────────────────
|
|
216
224
|
/** Set when a GSD tool execution ends with isError due to malformed/truncated
|
|
@@ -412,6 +420,7 @@ export class AutoSession {
|
|
|
412
420
|
this.consecutiveCompleteBootstraps = 0;
|
|
413
421
|
this.lastPreExecFailure = null;
|
|
414
422
|
this.preExecRetryCount.clear();
|
|
423
|
+
this.missingTaskPlanRetryCount.clear();
|
|
415
424
|
this.lastToolInvocationError = null;
|
|
416
425
|
this.toolUnavailableRetries = 0;
|
|
417
426
|
this.lastUnitAgentEndMessages = null;
|
|
@@ -63,7 +63,9 @@ export function decideVerificationRetry(input: {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const key = verificationRetryKey(unitType, retryInfo.unitId);
|
|
66
|
-
const failureHash = hashVerificationFailureContext(
|
|
66
|
+
const failureHash = hashVerificationFailureContext(
|
|
67
|
+
retryInfo.signature ?? retryInfo.failureContext,
|
|
68
|
+
);
|
|
67
69
|
if (input.previousFailureHash === failureHash) {
|
|
68
70
|
return {
|
|
69
71
|
action: "pause",
|
|
@@ -79,7 +79,9 @@ export function resolveCompactionThresholdPercent(raw: number | undefined): numb
|
|
|
79
79
|
return value <= 1 ? value * 100 : value;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
export
|
|
82
|
+
export const HARD_CONTEXT_REROOT_THRESHOLD_PERCENT = 90;
|
|
83
|
+
|
|
84
|
+
export function shouldWarnStepSessionForContext(
|
|
83
85
|
contextPercent: number | null | undefined,
|
|
84
86
|
compactionThresholdPercent?: number,
|
|
85
87
|
): boolean {
|
|
@@ -88,3 +90,12 @@ export function shouldRerootStepSessionForContext(
|
|
|
88
90
|
resolveCompactionThresholdPercent(compactionThresholdPercent),
|
|
89
91
|
) === "pause";
|
|
90
92
|
}
|
|
93
|
+
|
|
94
|
+
export function shouldRerootStepSessionForContext(
|
|
95
|
+
contextPercent: number | null | undefined,
|
|
96
|
+
): boolean {
|
|
97
|
+
return getContextPauseAction(
|
|
98
|
+
contextPercent,
|
|
99
|
+
HARD_CONTEXT_REROOT_THRESHOLD_PERCENT,
|
|
100
|
+
) === "pause";
|
|
101
|
+
}
|
|
@@ -1523,6 +1523,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1523
1523
|
const sid = state.activeSlice!.id;
|
|
1524
1524
|
const sTitle = state.activeSlice!.title;
|
|
1525
1525
|
const tid = state.activeTask.id;
|
|
1526
|
+
const unitId = `${mid}/${sid}`;
|
|
1526
1527
|
const artifactBasePath = resolveArtifactBasePath(basePath, mid, session);
|
|
1527
1528
|
|
|
1528
1529
|
// Guard: if the slice plan exists but the individual task plan files are
|
|
@@ -1562,6 +1563,17 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1562
1563
|
!existsSync(projectionTaskPlanPath) &&
|
|
1563
1564
|
!tasksEmbeddedInSlicePlan
|
|
1564
1565
|
) {
|
|
1566
|
+
const MAX_MISSING_TASK_PLAN_RETRIES = 2;
|
|
1567
|
+
const retryCount = session?.missingTaskPlanRetryCount?.get(unitId) ?? 0;
|
|
1568
|
+
if (retryCount >= MAX_MISSING_TASK_PLAN_RETRIES) {
|
|
1569
|
+
session?.missingTaskPlanRetryCount?.delete(unitId);
|
|
1570
|
+
return {
|
|
1571
|
+
action: "stop",
|
|
1572
|
+
reason: `Missing task-plan recovery failed ${retryCount} times for ${unitId} - manual intervention required. Task plan ${tid} is still missing after regenerating the slice plan. Fix the task-plan files manually, then run /gsd auto to resume.`,
|
|
1573
|
+
level: "error",
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
session?.missingTaskPlanRetryCount?.set(unitId, retryCount + 1);
|
|
1565
1577
|
if (isDebugEnabled()) {
|
|
1566
1578
|
const expectedTaskPlanPath = join(artifactBasePath, relTaskFile(artifactBasePath, mid, sid, tid, "PLAN"));
|
|
1567
1579
|
const originalProjectRoot = session?.originalBasePath || basePath;
|
|
@@ -1585,7 +1597,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1585
1597
|
return {
|
|
1586
1598
|
action: "dispatch",
|
|
1587
1599
|
unitType: "plan-slice",
|
|
1588
|
-
unitId
|
|
1600
|
+
unitId,
|
|
1589
1601
|
prompt: await buildPlanSlicePrompt(
|
|
1590
1602
|
mid,
|
|
1591
1603
|
midTitle,
|
|
@@ -1598,6 +1610,7 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1598
1610
|
};
|
|
1599
1611
|
}
|
|
1600
1612
|
|
|
1613
|
+
session?.missingTaskPlanRetryCount?.delete(unitId);
|
|
1601
1614
|
return null;
|
|
1602
1615
|
},
|
|
1603
1616
|
},
|
|
@@ -2212,7 +2212,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
2212
2212
|
saveCustomVerifyRetryCounts(s, { logFailure: err => debugLog("postUnit", { phase: "save-verify-retries-failed", error: err instanceof Error ? err.message : String(err) }) });
|
|
2213
2213
|
s.pendingVerificationRetry = {
|
|
2214
2214
|
unitId: s.currentUnit.id,
|
|
2215
|
-
failureContext:
|
|
2215
|
+
failureContext: failureDetails,
|
|
2216
2216
|
attempt,
|
|
2217
2217
|
};
|
|
2218
2218
|
debugLog("postUnit", { phase: "artifact-verify-retry", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
resolveMilestoneFile, resolveSliceFile, resolveSlicePath,
|
|
18
18
|
resolveTasksDir, resolveTaskFiles, resolveTaskFile,
|
|
19
19
|
relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath,
|
|
20
|
-
resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile,
|
|
20
|
+
relTaskFile, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile,
|
|
21
21
|
} from "./paths.js";
|
|
22
22
|
import { resolveInlineLevel, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
23
23
|
import { isContextModeEnabled } from "./preferences-types.js";
|
|
@@ -2662,7 +2662,7 @@ export async function buildExecuteTaskPrompt(
|
|
|
2662
2662
|
|
|
2663
2663
|
const taskPlanPath = resolveTaskFile(base, mid, sid, tid, "PLAN");
|
|
2664
2664
|
const taskPlanContent = taskPlanPath ? await loadFile(taskPlanPath) : null;
|
|
2665
|
-
const taskPlanRelPath =
|
|
2665
|
+
const taskPlanRelPath = relTaskFile(base, mid, sid, tid, "PLAN");
|
|
2666
2666
|
const taskPlanContext = taskPlanContent
|
|
2667
2667
|
? [
|
|
2668
2668
|
"## Inlined Task Plan (authoritative local execution contract)",
|
|
@@ -3901,7 +3901,7 @@ export async function buildReactiveExecutePrompt(
|
|
|
3901
3901
|
|
|
3902
3902
|
const taskPlanPath = resolveTaskFile(base, mid, sid, tid, "PLAN");
|
|
3903
3903
|
const taskPlanContent = taskPlanPath ? await loadFile(taskPlanPath) : null;
|
|
3904
|
-
const taskPlanRelPath =
|
|
3904
|
+
const taskPlanRelPath = relTaskFile(base, mid, sid, tid, "PLAN");
|
|
3905
3905
|
const taskPlanInline = taskPlanContent
|
|
3906
3906
|
? [
|
|
3907
3907
|
"## Inlined Task Plan (authoritative local execution contract)",
|
|
@@ -35,7 +35,7 @@ import { isValidationTerminal } from "./state.js";
|
|
|
35
35
|
import { getErrorMessage } from "./error-utils.js";
|
|
36
36
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
37
37
|
import { readIntegrationBranch } from "./git-service.js";
|
|
38
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
38
|
+
import { isClosedStatus, isInactiveStatus } from "./status-guards.js";
|
|
39
39
|
import {
|
|
40
40
|
resolveSlicePath,
|
|
41
41
|
resolveSliceFile,
|
|
@@ -295,7 +295,7 @@ export function writeReactiveExecuteBlocker(
|
|
|
295
295
|
transaction(() => {
|
|
296
296
|
for (const tid of summaryPresent) {
|
|
297
297
|
const task = getTask(mid, sid, tid);
|
|
298
|
-
if (!task ||
|
|
298
|
+
if (!task || isInactiveStatus(task.status)) {
|
|
299
299
|
unchangedTaskIds.push(tid);
|
|
300
300
|
continue;
|
|
301
301
|
}
|
|
@@ -304,7 +304,7 @@ export function writeReactiveExecuteBlocker(
|
|
|
304
304
|
}
|
|
305
305
|
for (const tid of summaryMissing) {
|
|
306
306
|
const task = getTask(mid, sid, tid);
|
|
307
|
-
if (!task ||
|
|
307
|
+
if (!task || isInactiveStatus(task.status)) {
|
|
308
308
|
unchangedTaskIds.push(tid);
|
|
309
309
|
continue;
|
|
310
310
|
}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
runVerificationGate,
|
|
30
30
|
runVerificationGateForTargets,
|
|
31
31
|
formatFailureContext,
|
|
32
|
+
formatFailureSignature,
|
|
32
33
|
captureRuntimeErrors,
|
|
33
34
|
runDependencyAudit,
|
|
34
35
|
} from "./verification-gate.js";
|
|
@@ -871,10 +872,13 @@ export async function runPostUnitVerification(
|
|
|
871
872
|
);
|
|
872
873
|
}
|
|
873
874
|
const nextAttempt = attempt + 1;
|
|
875
|
+
const failureContext = verdict.failureContext || formatFailureContext(result);
|
|
876
|
+
const failureSignature = formatFailureSignature(result);
|
|
874
877
|
s.verificationRetryCount.set(retryKey, nextAttempt);
|
|
875
878
|
s.pendingVerificationRetry = {
|
|
876
879
|
unitId: s.currentUnit.id,
|
|
877
|
-
failureContext
|
|
880
|
+
failureContext,
|
|
881
|
+
...(failureSignature ? { signature: failureSignature } : {}),
|
|
878
882
|
attempt: nextAttempt,
|
|
879
883
|
};
|
|
880
884
|
const failedCmds = result.checks
|
|
@@ -97,8 +97,10 @@ import {
|
|
|
97
97
|
getNewBudgetAlertLevel,
|
|
98
98
|
getBudgetEnforcementAction,
|
|
99
99
|
getContextPauseAction,
|
|
100
|
+
HARD_CONTEXT_REROOT_THRESHOLD_PERCENT,
|
|
100
101
|
resolveCompactionThresholdPercent,
|
|
101
102
|
shouldRerootStepSessionForContext,
|
|
103
|
+
shouldWarnStepSessionForContext,
|
|
102
104
|
} from "./auto-budget.js";
|
|
103
105
|
import {
|
|
104
106
|
markToolStart as _markToolStart,
|
|
@@ -701,6 +703,7 @@ export {
|
|
|
701
703
|
getContextPauseAction,
|
|
702
704
|
resolveCompactionThresholdPercent,
|
|
703
705
|
shouldRerootStepSessionForContext,
|
|
706
|
+
shouldWarnStepSessionForContext,
|
|
704
707
|
} from "./auto-budget.js";
|
|
705
708
|
|
|
706
709
|
function closeOutSignalInterruptedUnit(currentBasePath: string): void {
|
|
@@ -1375,9 +1378,10 @@ export async function rerootCommandSession(
|
|
|
1375
1378
|
}
|
|
1376
1379
|
|
|
1377
1380
|
/**
|
|
1378
|
-
* After a completed step-mode unit,
|
|
1379
|
-
*
|
|
1380
|
-
* re-
|
|
1381
|
+
* After a completed step-mode unit, warn when usage reaches the configurable
|
|
1382
|
+
* soft context threshold. At the fixed hard boundary, write a context-mode
|
|
1383
|
+
* snapshot and re-root the visible command session while leaving the NEXT
|
|
1384
|
+
* progress surface.
|
|
1381
1385
|
*/
|
|
1382
1386
|
export async function maybeRerootStepSessionForHighContext(
|
|
1383
1387
|
ctx: ExtensionContext,
|
|
@@ -1392,7 +1396,19 @@ export async function maybeRerootStepSessionForHighContext(
|
|
|
1392
1396
|
const prefs = loadEffectiveGSDPreferences(workspaceRoot);
|
|
1393
1397
|
const compactionThreshold = prefs?.preferences.context_management?.compaction_threshold_percent;
|
|
1394
1398
|
|
|
1395
|
-
|
|
1399
|
+
const shouldWarn = shouldWarnStepSessionForContext(contextPercent, compactionThreshold);
|
|
1400
|
+
const shouldReroot = shouldRerootStepSessionForContext(contextPercent);
|
|
1401
|
+
if (!shouldWarn && !shouldReroot) {
|
|
1402
|
+
return { rerooted: false };
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
const displayPercent = (contextPercent as number).toFixed(1);
|
|
1406
|
+
const thresholdDisplay = resolveCompactionThresholdPercent(compactionThreshold).toFixed(0);
|
|
1407
|
+
if (!shouldReroot) {
|
|
1408
|
+
ctx.ui.notify(
|
|
1409
|
+
`Step complete — context at ${displayPercent}% (soft threshold: ${thresholdDisplay}%). Use /compact when convenient; continuing in this session is still safe.`,
|
|
1410
|
+
"info",
|
|
1411
|
+
);
|
|
1396
1412
|
return { rerooted: false };
|
|
1397
1413
|
}
|
|
1398
1414
|
|
|
@@ -1401,12 +1417,10 @@ export async function maybeRerootStepSessionForHighContext(
|
|
|
1401
1417
|
const { writeContextModeCompactionSnapshot } = await import("./context-mode-snapshot.js");
|
|
1402
1418
|
await writeContextModeCompactionSnapshot(snapshotBase);
|
|
1403
1419
|
|
|
1404
|
-
const displayPercent = (contextPercent as number).toFixed(1);
|
|
1405
|
-
const thresholdDisplay = resolveCompactionThresholdPercent(compactionThreshold).toFixed(0);
|
|
1406
1420
|
const result = await rerootCommandSession(cmdCtx, workspaceRoot);
|
|
1407
1421
|
if (result.status === "ok") {
|
|
1408
1422
|
ctx.ui.notify(
|
|
1409
|
-
`Step complete — context at ${displayPercent}% (threshold: ${
|
|
1423
|
+
`Step complete — context at ${displayPercent}% (hard threshold: ${HARD_CONTEXT_REROOT_THRESHOLD_PERCENT}%). Fresh session ready for /gsd next.`,
|
|
1410
1424
|
"info",
|
|
1411
1425
|
);
|
|
1412
1426
|
return { rerooted: true };
|
|
@@ -2102,7 +2116,7 @@ export function _selectStopAutoWorktreeExit(args: {
|
|
|
2102
2116
|
/**
|
|
2103
2117
|
* Pause auto-mode without destroying state. Context is preserved.
|
|
2104
2118
|
* The user can interact with the agent, then `/gsd auto` resumes
|
|
2105
|
-
* from disk state. Called when the user presses Escape
|
|
2119
|
+
* from disk state. Called when the user presses Escape or runs `/gsd pause`.
|
|
2106
2120
|
*/
|
|
2107
2121
|
export async function pauseAuto(
|
|
2108
2122
|
ctx?: ExtensionContext,
|
|
@@ -2129,6 +2143,7 @@ export async function pauseAuto(
|
|
|
2129
2143
|
|
|
2130
2144
|
s.active = false;
|
|
2131
2145
|
s.paused = true;
|
|
2146
|
+
if (options.abortActiveTurn && ctx && !ctx.isIdle()) ctx.abort();
|
|
2132
2147
|
clearUnitTimeout();
|
|
2133
2148
|
stopAutoCommandPolling();
|
|
2134
2149
|
|
|
@@ -28,6 +28,7 @@ const NON_REPEATABLE_FROM_MINIMAL_BASE = new Set<string>([
|
|
|
28
28
|
|
|
29
29
|
/** Additional core tools not in MINIMAL_AUTO_BASE but routinely multi-called per turn. */
|
|
30
30
|
const EXTRA_INHERENTLY_REPEATABLE = [
|
|
31
|
+
"gsd_exec",
|
|
31
32
|
"multi_edit",
|
|
32
33
|
"todo_write",
|
|
33
34
|
"notebook_edit",
|
|
@@ -690,8 +690,9 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
690
690
|
promptSnippet: "Plan a slice via DB write + PLAN render + cache invalidation",
|
|
691
691
|
promptGuidelines: [
|
|
692
692
|
"Use gsd_plan_slice for slice planning instead of writing S##-PLAN.md or task PLAN files directly.",
|
|
693
|
-
"
|
|
694
|
-
"
|
|
693
|
+
"For incremental planning, call gsd_plan_slice with slice metadata only, then call gsd_plan_task once per task.",
|
|
694
|
+
"When tasks is omitted or empty, the tool writes only slice planning metadata and preserves existing tasks.",
|
|
695
|
+
"When tasks is non-empty, the tool validates input, requires an existing parent slice, writes slice/task planning data, renders PLAN.md and task plan files from DB, and clears both state and parse caches after success.",
|
|
695
696
|
"Use the canonical name gsd_plan_slice; gsd_slice_plan is only an alias.",
|
|
696
697
|
],
|
|
697
698
|
parameters: Type.Object({
|
|
@@ -699,7 +700,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
699
700
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
700
701
|
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
701
702
|
goal: Type.String({ description: "Slice goal" }),
|
|
702
|
-
tasks: Type.Array(Type.Object({
|
|
703
|
+
tasks: Type.Optional(Type.Array(Type.Object({
|
|
703
704
|
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
704
705
|
title: Type.String({ description: "Task title" }),
|
|
705
706
|
description: Type.String({ description: "Task description / steps block" }),
|
|
@@ -709,7 +710,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
709
710
|
inputs: Type.Array(Type.String(), { description: "Array<string> of input files or references; pass [\"path\"] or [], never a single string" }),
|
|
710
711
|
expectedOutput: Type.Array(Type.String(), { description: "Array<string> of files this task creates or overwrites; pass [\"path\"] or [], never prose or a single string" }),
|
|
711
712
|
observabilityImpact: Type.Optional(Type.String({ description: "Task observability impact" })),
|
|
712
|
-
}), { description: "
|
|
713
|
+
}), { description: "Optional full task replacement for the slice. Omit for incremental planning, then call gsd_plan_task once per task." })),
|
|
713
714
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
714
715
|
successCriteria: Type.Optional(Type.String({ description: "Slice success criteria block" })),
|
|
715
716
|
proofLevel: Type.Optional(Type.String({ description: "Slice proof level" })),
|
|
@@ -18,6 +18,7 @@ import { registerShortcuts } from "./register-shortcuts.js";
|
|
|
18
18
|
import { writeCrashLog } from "./crash-log.js";
|
|
19
19
|
import { logWarning, isGsdExtensionStderrEnabled } from "../workflow-logger.js";
|
|
20
20
|
import { UNIT_TOOL_CONTRACTS } from "../unit-tool-contracts.js";
|
|
21
|
+
import { installManifestFlushOnProcessTeardown } from "../workflow-manifest.js";
|
|
21
22
|
// Static import so cmux event listeners are registered synchronously during
|
|
22
23
|
// extension bootstrap. Prior implementation used `void import().then()` which
|
|
23
24
|
// queued listener registration as a microtask — any CMUX_CHANNELS emit fired
|
|
@@ -196,6 +197,7 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
196
197
|
});
|
|
197
198
|
|
|
198
199
|
installEpipeGuard();
|
|
200
|
+
installManifestFlushOnProcessTeardown();
|
|
199
201
|
|
|
200
202
|
// Ecosystem handlers captured by the GSDExtensionAPI wrapper for the
|
|
201
203
|
// GSD-owned `before_agent_start` dispatch step (#3338).
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from "../auto-runtime-state.js";
|
|
35
35
|
import { applyProviderPayloadPolicy } from "../provider-payload-policy.js";
|
|
36
36
|
|
|
37
|
-
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
37
|
+
import { checkToolCallLoop, recordToolCallLoopMutation, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
38
38
|
import { MINIMAL_AUTO_BASE_TOOL_NAMES } from "./core-session-tools.js";
|
|
39
39
|
import { maybePauseAutoForApprovalGate, resetPendingGatePauseGuard } from "./pending-gate-pause.js";
|
|
40
40
|
import { saveActivityLog } from "../activity-log.js";
|
|
@@ -76,6 +76,7 @@ import { supportsSourceObservationsForUnit } from "../source-observations.js";
|
|
|
76
76
|
import { clearPendingAutoStart } from "../pending-auto-start.js";
|
|
77
77
|
import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
|
|
78
78
|
import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
|
|
79
|
+
import { flushAllManifests } from "../workflow-manifest.js";
|
|
79
80
|
|
|
80
81
|
let approvalQuestionAbortInFlight = false;
|
|
81
82
|
|
|
@@ -583,6 +584,21 @@ function contextBasePath(ctx?: { cwd?: string }): string {
|
|
|
583
584
|
return typeof ctx?.cwd === "string" ? ctx.cwd : process.cwd();
|
|
584
585
|
}
|
|
585
586
|
|
|
587
|
+
const LOOP_GUARD_INTERACTIVE_INSTRUCTIONS = [
|
|
588
|
+
"Do not retry this tool or call other tools this turn — stop and respond to the user in text.",
|
|
589
|
+
"Do not retry this tool or pivot to other tools this turn — stop and respond to the user in text.",
|
|
590
|
+
];
|
|
591
|
+
const LOOP_GUARD_AUTO_INSTRUCTION =
|
|
592
|
+
"Do not re-issue this blocked tool. In /gsd auto, stop tool calls for this turn and return control to the auto-mode recovery/replan path.";
|
|
593
|
+
|
|
594
|
+
function formatLoopGuardBlockReason(reason: string | undefined): string | undefined {
|
|
595
|
+
if (!reason || !getAutoRuntimeSnapshot().active) return reason;
|
|
596
|
+
return LOOP_GUARD_INTERACTIVE_INSTRUCTIONS.reduce(
|
|
597
|
+
(formatted, instruction) => formatted.replace(instruction, LOOP_GUARD_AUTO_INSTRUCTION),
|
|
598
|
+
reason,
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
586
602
|
function beginSourceObservationStoreForCurrentUnit(
|
|
587
603
|
ctx?: { cwd?: string },
|
|
588
604
|
): ReturnType<typeof getSourceObservationStore> | null {
|
|
@@ -906,6 +922,15 @@ export function registerHooks(
|
|
|
906
922
|
}
|
|
907
923
|
}
|
|
908
924
|
}
|
|
925
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
926
|
+
const { pruneStaleFlatPhaseBackups } = await import("../flat-phase-migration.js");
|
|
927
|
+
const pruned = pruneStaleFlatPhaseBackups(projectRoot);
|
|
928
|
+
if (pruned > 0) {
|
|
929
|
+
safetyLogWarning(
|
|
930
|
+
"bootstrap",
|
|
931
|
+
`pruned ${pruned} stale flat-phase migration backup(s) from .gsd-backups/ (retention exceeded)`,
|
|
932
|
+
);
|
|
933
|
+
}
|
|
909
934
|
} catch (err) {
|
|
910
935
|
safetyLogWarning("bootstrap", `flat-phase migration: ${err instanceof Error ? err.message : String(err)}`);
|
|
911
936
|
}
|
|
@@ -1071,6 +1096,19 @@ export function registerHooks(
|
|
|
1071
1096
|
const { handleAgentEnd } = await import("./agent-end-recovery.js");
|
|
1072
1097
|
const agentEndBasePath = contextBasePath(ctx);
|
|
1073
1098
|
try {
|
|
1099
|
+
// The manifest is a non-critical projection (the append-only event log is
|
|
1100
|
+
// the authoritative recovery source), so a flush failure must not skip
|
|
1101
|
+
// agent_end recovery. drainManifestWrites still propagates write failures
|
|
1102
|
+
// to explicit flush callers; here we deliberately log and continue so
|
|
1103
|
+
// handleAgentEnd (and the finally below) always run.
|
|
1104
|
+
try {
|
|
1105
|
+
await flushAllManifests();
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
safetyLogWarning(
|
|
1108
|
+
"manifest",
|
|
1109
|
+
`flushAllManifests on agent_end failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1074
1112
|
await handleAgentEnd(pi, event, ctx);
|
|
1075
1113
|
} finally {
|
|
1076
1114
|
activateDeferredApprovalGate(agentEndBasePath);
|
|
@@ -1277,7 +1315,7 @@ export function registerHooks(
|
|
|
1277
1315
|
// ── Loop guard: block repeated identical tool calls ──
|
|
1278
1316
|
const loopCheck = checkToolCallLoop(toolName, event.input as Record<string, unknown>);
|
|
1279
1317
|
if (loopCheck.block) {
|
|
1280
|
-
return { block: true, reason: loopCheck.reason };
|
|
1318
|
+
return { block: true, reason: formatLoopGuardBlockReason(loopCheck.reason) };
|
|
1281
1319
|
}
|
|
1282
1320
|
|
|
1283
1321
|
const deferredGateGuard = shouldBlockDeferredApprovalTool(
|
|
@@ -1549,6 +1587,7 @@ export function registerHooks(
|
|
|
1549
1587
|
}
|
|
1550
1588
|
}
|
|
1551
1589
|
if (!event.isError) {
|
|
1590
|
+
recordToolCallLoopMutation(toolName);
|
|
1552
1591
|
refreshSourceObservationAfterMutation(toolName, event.input, ctx);
|
|
1553
1592
|
clearSourceObservationsAfterShell(toolName);
|
|
1554
1593
|
}
|