gsd-pi 2.76.0-dev.82e249f7b → 2.76.0-dev.97f5583d9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-cli-check.js +32 -3
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +35 -1
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +2 -8
- package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
- package/dist/resources/extensions/gsd/auto/phases.js +42 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +27 -0
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-start.js +27 -18
- package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
- package/dist/resources/extensions/gsd/auto.js +55 -27
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +51 -5
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
- package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
- package/dist/resources/extensions/gsd/error-classifier.js +10 -3
- package/dist/resources/extensions/gsd/exec-history.js +120 -0
- package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
- package/dist/resources/extensions/gsd/gsd-db.js +115 -7
- package/dist/resources/extensions/gsd/guided-flow.js +189 -0
- package/dist/resources/extensions/gsd/health-widget.js +4 -1
- package/dist/resources/extensions/gsd/init-wizard.js +15 -1
- package/dist/resources/extensions/gsd/key-manager.js +6 -0
- package/dist/resources/extensions/gsd/model-router.js +36 -3
- package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -9
- package/dist/resources/extensions/gsd/preferences-types.js +9 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
- package/dist/resources/extensions/gsd/preferences.js +17 -17
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
- package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
- package/dist/resources/extensions/gsd/token-counter.js +22 -5
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
- package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
- package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/dist/resources/skills/write-docs/SKILL.md +2 -1
- 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 +10 -10
- 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/required-server-files.json +1 -1
- 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 +10 -10
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
- package/packages/mcp-server/dist/remote-questions.js +732 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts +7 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +41 -4
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +64 -25
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -1
- package/packages/mcp-server/src/mcp-server.test.ts +30 -0
- package/packages/mcp-server/src/remote-questions.test.ts +294 -0
- package/packages/mcp-server/src/remote-questions.ts +916 -0
- package/packages/mcp-server/src/server.ts +62 -10
- package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
- package/packages/mcp-server/src/workflow-tools.ts +84 -43
- package/packages/mcp-server/tsconfig.test.json +19 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
- package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
- package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +8 -3
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
- package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +16 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
- package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
- package/packages/pi-ai/src/providers/anthropic.ts +9 -3
- package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
- package/packages/pi-ai/src/providers/simple-options.ts +17 -1
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
- package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +9 -5
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +25 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
- package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +36 -1
- package/packages/pi-coding-agent/src/core/session-manager.ts +9 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
- package/src/resources/extensions/gsd/auto/loop-deps.ts +13 -0
- package/src/resources/extensions/gsd/auto/phases.ts +66 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +29 -0
- package/src/resources/extensions/gsd/auto/session.ts +22 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +15 -0
- package/src/resources/extensions/gsd/auto-start.ts +29 -19
- package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
- package/src/resources/extensions/gsd/auto.ts +58 -27
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +53 -5
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
- package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
- package/src/resources/extensions/gsd/error-classifier.ts +10 -3
- package/src/resources/extensions/gsd/exec-history.ts +153 -0
- package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
- package/src/resources/extensions/gsd/gsd-db.ts +122 -7
- package/src/resources/extensions/gsd/guided-flow.ts +221 -0
- package/src/resources/extensions/gsd/health-widget.ts +3 -1
- package/src/resources/extensions/gsd/init-wizard.ts +15 -1
- package/src/resources/extensions/gsd/journal.ts +2 -1
- package/src/resources/extensions/gsd/key-manager.ts +6 -0
- package/src/resources/extensions/gsd/model-router.ts +42 -1
- package/src/resources/extensions/gsd/pre-execution-checks.ts +36 -10
- package/src/resources/extensions/gsd/preferences-types.ts +46 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
- package/src/resources/extensions/gsd/preferences.ts +17 -17
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
- package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +119 -1
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +152 -1
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
- package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
- package/src/resources/extensions/gsd/token-counter.ts +22 -5
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
- package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
- package/src/resources/skills/write-docs/SKILL.md +2 -1
- /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_ssgManifest.js +0 -0
|
@@ -126,8 +126,9 @@ import {
|
|
|
126
126
|
formatTokenCount,
|
|
127
127
|
} from "./metrics.js";
|
|
128
128
|
import { setLogBasePath, logWarning, logError } from "./workflow-logger.js";
|
|
129
|
+
import { preflightCleanRoot, postflightPopStash } from "./clean-root-preflight.js";
|
|
129
130
|
import { homedir } from "node:os";
|
|
130
|
-
import { join } from "node:path";
|
|
131
|
+
import { isAbsolute, join } from "node:path";
|
|
131
132
|
import { pathToFileURL } from "node:url";
|
|
132
133
|
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
133
134
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -182,7 +183,6 @@ import {
|
|
|
182
183
|
unitVerb,
|
|
183
184
|
formatAutoElapsed as _formatAutoElapsed,
|
|
184
185
|
formatWidgetTokens,
|
|
185
|
-
hideFooter,
|
|
186
186
|
type WidgetStateAccessors,
|
|
187
187
|
} from "./auto-dashboard.js";
|
|
188
188
|
import {
|
|
@@ -310,6 +310,21 @@ function restoreMilestoneLockEnv(): void {
|
|
|
310
310
|
s.milestoneLockEnvCaptured = false;
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
+
function normalizeSessionFilePath(raw: unknown): string | null {
|
|
314
|
+
if (typeof raw !== "string") return null;
|
|
315
|
+
const trimmed = raw.trim();
|
|
316
|
+
if (!trimmed) return null;
|
|
317
|
+
const firstLine = trimmed.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
318
|
+
if (!firstLine) return null;
|
|
319
|
+
|
|
320
|
+
// Guard against accidental message concatenation by trimming to .jsonl.
|
|
321
|
+
const jsonlIndex = firstLine.toLowerCase().indexOf(".jsonl");
|
|
322
|
+
const candidate = jsonlIndex >= 0 ? firstLine.slice(0, jsonlIndex + ".jsonl".length) : firstLine;
|
|
323
|
+
if (!isAbsolute(candidate)) return null;
|
|
324
|
+
if (!candidate.toLowerCase().endsWith(".jsonl")) return null;
|
|
325
|
+
return candidate;
|
|
326
|
+
}
|
|
327
|
+
|
|
313
328
|
export function startAutoDetached(
|
|
314
329
|
ctx: ExtensionCommandContext,
|
|
315
330
|
pi: ExtensionAPI,
|
|
@@ -330,8 +345,8 @@ export function startAutoDetached(
|
|
|
330
345
|
}
|
|
331
346
|
|
|
332
347
|
/** Returns true if the project is configured for `isolation:worktree` mode. */
|
|
333
|
-
export function shouldUseWorktreeIsolation(): boolean {
|
|
334
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences?.git;
|
|
348
|
+
export function shouldUseWorktreeIsolation(basePath?: string): boolean {
|
|
349
|
+
const prefs = loadEffectiveGSDPreferences(basePath)?.preferences?.git;
|
|
335
350
|
if (prefs?.isolation === "worktree") return true;
|
|
336
351
|
// Default is false — worktree isolation requires explicit opt-in
|
|
337
352
|
return false;
|
|
@@ -424,7 +439,7 @@ export function getAutoDashboardData(): AutoDashboardData {
|
|
|
424
439
|
const rtkSavings = sessionId && s.basePath
|
|
425
440
|
? getRtkSessionSavings(s.basePath, sessionId)
|
|
426
441
|
: null;
|
|
427
|
-
const rtkEnabled = loadEffectiveGSDPreferences()?.preferences.experimental?.rtk === true;
|
|
442
|
+
const rtkEnabled = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences.experimental?.rtk === true;
|
|
428
443
|
// Pending capture count — lazy check, non-fatal
|
|
429
444
|
let pendingCaptureCount = 0;
|
|
430
445
|
try {
|
|
@@ -648,7 +663,7 @@ function buildSnapshotOpts(
|
|
|
648
663
|
gitStatus?: "ok" | "failed";
|
|
649
664
|
gitError?: string;
|
|
650
665
|
} & Record<string, unknown> {
|
|
651
|
-
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
666
|
+
const prefs = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
652
667
|
const uokFlags = resolveUokFlags(prefs);
|
|
653
668
|
return {
|
|
654
669
|
...(s.autoStartTime > 0 ? { autoSessionKey: String(s.autoStartTime) } : {}),
|
|
@@ -686,7 +701,7 @@ function handleLostSessionLock(
|
|
|
686
701
|
restoreProjectRootEnv();
|
|
687
702
|
restoreMilestoneLockEnv();
|
|
688
703
|
deregisterSigtermHandler();
|
|
689
|
-
clearCmuxSidebar(loadEffectiveGSDPreferences()?.preferences);
|
|
704
|
+
clearCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences);
|
|
690
705
|
const base = lockBase();
|
|
691
706
|
const lockFilePath = base ? join(gsdRoot(base), "auto.lock") : "unknown";
|
|
692
707
|
const recoverySuggestion = "\nTo recover, run: gsd doctor --fix";
|
|
@@ -706,7 +721,6 @@ function handleLostSessionLock(
|
|
|
706
721
|
);
|
|
707
722
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
708
723
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
709
|
-
ctx?.ui.setFooter(undefined);
|
|
710
724
|
if (ctx) initHealthWidget(ctx);
|
|
711
725
|
}
|
|
712
726
|
|
|
@@ -742,7 +756,6 @@ function cleanupAfterLoopExit(ctx: ExtensionContext): void {
|
|
|
742
756
|
if (!s.paused) {
|
|
743
757
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
744
758
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
745
|
-
ctx.ui.setFooter(undefined);
|
|
746
759
|
initHealthWidget(ctx);
|
|
747
760
|
}
|
|
748
761
|
|
|
@@ -764,7 +777,7 @@ export async function stopAuto(
|
|
|
764
777
|
reason?: string,
|
|
765
778
|
): Promise<void> {
|
|
766
779
|
if (!s.active && !s.paused) return;
|
|
767
|
-
const loadedPreferences = loadEffectiveGSDPreferences()?.preferences;
|
|
780
|
+
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
768
781
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
769
782
|
|
|
770
783
|
try {
|
|
@@ -1018,7 +1031,6 @@ export async function stopAuto(
|
|
|
1018
1031
|
// UI cleanup
|
|
1019
1032
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
1020
1033
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1021
|
-
ctx?.ui.setFooter(undefined);
|
|
1022
1034
|
if (ctx) initHealthWidget(ctx);
|
|
1023
1035
|
restoreProjectRootEnv();
|
|
1024
1036
|
restoreMilestoneLockEnv();
|
|
@@ -1059,7 +1071,7 @@ export async function pauseAuto(
|
|
|
1059
1071
|
// from provider-error pause and avoid hard-stopping (#2762).
|
|
1060
1072
|
resolveAgentEndCancelled(_errorContext);
|
|
1061
1073
|
|
|
1062
|
-
s.pausedSessionFile = ctx?.sessionManager?.getSessionFile() ?? null;
|
|
1074
|
+
s.pausedSessionFile = normalizeSessionFilePath(ctx?.sessionManager?.getSessionFile() ?? null);
|
|
1063
1075
|
|
|
1064
1076
|
// Persist paused-session metadata so resume survives /exit (#1383).
|
|
1065
1077
|
// The fresh-start bootstrap checks for this file and restores worktree context.
|
|
@@ -1121,7 +1133,6 @@ export async function pauseAuto(
|
|
|
1121
1133
|
s.verificationRetryCount.clear();
|
|
1122
1134
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
1123
1135
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1124
|
-
ctx?.ui.setFooter(undefined);
|
|
1125
1136
|
if (ctx) initHealthWidget(ctx);
|
|
1126
1137
|
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
1127
1138
|
ctx?.ui.notify(
|
|
@@ -1292,6 +1303,10 @@ function buildLoopDeps(): LoopDeps {
|
|
|
1292
1303
|
|
|
1293
1304
|
// Journal
|
|
1294
1305
|
emitJournalEvent: (entry: JournalEntry) => _emitJournalEvent(s.basePath, entry),
|
|
1306
|
+
|
|
1307
|
+
// Clean-root preflight gate (#2909)
|
|
1308
|
+
preflightCleanRoot,
|
|
1309
|
+
postflightPopStash,
|
|
1295
1310
|
} as unknown as LoopDeps;
|
|
1296
1311
|
}
|
|
1297
1312
|
|
|
@@ -1364,7 +1379,11 @@ export async function startAuto(
|
|
|
1364
1379
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
1365
1380
|
s.sessionMilestoneLock = meta.milestoneLock ?? null;
|
|
1366
1381
|
s.paused = true;
|
|
1367
|
-
try { unlinkSync(pausedPath); } catch (e) {
|
|
1382
|
+
try { unlinkSync(pausedPath); } catch (e) {
|
|
1383
|
+
if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1384
|
+
logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1368
1387
|
ctx.ui.notify(
|
|
1369
1388
|
`Resuming paused custom workflow${meta.activeRunDir ? ` (${meta.activeRunDir})` : ""}.`,
|
|
1370
1389
|
"info",
|
|
@@ -1383,7 +1402,9 @@ export async function startAuto(
|
|
|
1383
1402
|
const summaryFile = resolveMilestoneFile(base, meta.milestoneId, "SUMMARY");
|
|
1384
1403
|
if (!mDir || summaryFile) {
|
|
1385
1404
|
try { unlinkSync(pausedPath); } catch (err) {
|
|
1386
|
-
|
|
1405
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1406
|
+
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1407
|
+
}
|
|
1387
1408
|
}
|
|
1388
1409
|
ctx.ui.notify(
|
|
1389
1410
|
`Paused milestone ${meta.milestoneId} is ${!mDir ? "missing" : "already complete"}. Starting fresh.`,
|
|
@@ -1393,20 +1414,28 @@ export async function startAuto(
|
|
|
1393
1414
|
s.currentMilestoneId = meta.milestoneId;
|
|
1394
1415
|
s.originalBasePath = meta.originalBasePath || base;
|
|
1395
1416
|
s.stepMode = meta.stepMode ?? requestedStepMode;
|
|
1396
|
-
s.pausedSessionFile = meta.sessionFile ?? null;
|
|
1417
|
+
s.pausedSessionFile = normalizeSessionFilePath(meta.sessionFile ?? null);
|
|
1397
1418
|
s.pausedUnitType = meta.unitType ?? null;
|
|
1398
1419
|
s.pausedUnitId = meta.unitId ?? null;
|
|
1399
1420
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
1400
1421
|
s.sessionMilestoneLock = meta.milestoneLock ?? null;
|
|
1401
1422
|
s.paused = true;
|
|
1402
|
-
try { unlinkSync(pausedPath); } catch (e) {
|
|
1423
|
+
try { unlinkSync(pausedPath); } catch (e) {
|
|
1424
|
+
if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1425
|
+
logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1403
1428
|
ctx.ui.notify(
|
|
1404
1429
|
`Resuming paused session for ${meta.milestoneId}${meta.worktreePath && existsSync(meta.worktreePath) ? ` (worktree)` : ""}.`,
|
|
1405
1430
|
"info",
|
|
1406
1431
|
);
|
|
1407
1432
|
}
|
|
1408
1433
|
} else if (existsSync(pausedPath)) {
|
|
1409
|
-
try { unlinkSync(pausedPath); } catch (e) {
|
|
1434
|
+
try { unlinkSync(pausedPath); } catch (e) {
|
|
1435
|
+
if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1436
|
+
logWarning("session", `stale pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1410
1439
|
}
|
|
1411
1440
|
}
|
|
1412
1441
|
} catch (err) {
|
|
@@ -1465,7 +1494,9 @@ export async function startAuto(
|
|
|
1465
1494
|
// Lock acquired — now safe to delete the pause file
|
|
1466
1495
|
if (s.pausedSessionFile) {
|
|
1467
1496
|
try { unlinkSync(s.pausedSessionFile); } catch (err) {
|
|
1468
|
-
|
|
1497
|
+
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1498
|
+
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1499
|
+
}
|
|
1469
1500
|
}
|
|
1470
1501
|
s.pausedSessionFile = null;
|
|
1471
1502
|
}
|
|
@@ -1495,7 +1526,7 @@ export async function startAuto(
|
|
|
1495
1526
|
// ── Auto-worktree / branch-mode: re-enter on resume ──
|
|
1496
1527
|
if (
|
|
1497
1528
|
s.currentMilestoneId &&
|
|
1498
|
-
getIsolationMode() !== "none" &&
|
|
1529
|
+
getIsolationMode(s.originalBasePath || s.basePath) !== "none" &&
|
|
1499
1530
|
s.originalBasePath &&
|
|
1500
1531
|
!isInAutoWorktree(s.basePath) &&
|
|
1501
1532
|
!detectWorktreeName(s.basePath) &&
|
|
@@ -1509,7 +1540,7 @@ export async function startAuto(
|
|
|
1509
1540
|
registerSigtermHandler(lockBase());
|
|
1510
1541
|
|
|
1511
1542
|
ctx.ui.setStatus("gsd-auto", s.stepMode ? "next" : "auto");
|
|
1512
|
-
ctx.ui.
|
|
1543
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
1513
1544
|
ctx.ui.notify(
|
|
1514
1545
|
s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.",
|
|
1515
1546
|
"info",
|
|
@@ -1534,7 +1565,7 @@ export async function startAuto(
|
|
|
1534
1565
|
await openProjectDbIfPresent(s.basePath);
|
|
1535
1566
|
try {
|
|
1536
1567
|
await rebuildState(s.basePath);
|
|
1537
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1568
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1538
1569
|
} catch (e) {
|
|
1539
1570
|
debugLog("resume-rebuild-state-failed", {
|
|
1540
1571
|
error: e instanceof Error ? e.message : String(e),
|
|
@@ -1584,7 +1615,7 @@ export async function startAuto(
|
|
|
1584
1615
|
"resuming",
|
|
1585
1616
|
s.currentMilestoneId ?? "unknown",
|
|
1586
1617
|
);
|
|
1587
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1618
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "progress");
|
|
1588
1619
|
|
|
1589
1620
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1590
1621
|
startAutoCommandPolling(s.basePath);
|
|
@@ -1622,12 +1653,12 @@ export async function startAuto(
|
|
|
1622
1653
|
|
|
1623
1654
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1624
1655
|
try {
|
|
1625
|
-
syncCmuxSidebar(loadEffectiveGSDPreferences()?.preferences, await deriveState(s.basePath));
|
|
1656
|
+
syncCmuxSidebar(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, await deriveState(s.basePath));
|
|
1626
1657
|
} catch (err) {
|
|
1627
1658
|
// Best-effort only — sidebar sync must never block auto-mode startup
|
|
1628
1659
|
logWarning("engine", `cmux sync failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1629
1660
|
}
|
|
1630
|
-
logCmuxEvent(loadEffectiveGSDPreferences()?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1661
|
+
logCmuxEvent(loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, requestedStepMode ? "Step-mode started." : "Auto-mode started.", "progress");
|
|
1631
1662
|
|
|
1632
1663
|
startAutoCommandPolling(s.basePath);
|
|
1633
1664
|
|
|
@@ -1776,12 +1807,12 @@ export async function dispatchHookUnit(
|
|
|
1776
1807
|
}
|
|
1777
1808
|
}
|
|
1778
1809
|
|
|
1779
|
-
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
1810
|
+
const sessionFile = normalizeSessionFilePath(ctx.sessionManager.getSessionFile());
|
|
1780
1811
|
writeLock(
|
|
1781
1812
|
lockBase(),
|
|
1782
1813
|
hookUnitType,
|
|
1783
1814
|
triggerUnitId,
|
|
1784
|
-
sessionFile,
|
|
1815
|
+
sessionFile ?? undefined,
|
|
1785
1816
|
);
|
|
1786
1817
|
|
|
1787
1818
|
clearUnitTimeout();
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
import { logWarning } from "../workflow-logger.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
checkAutoStartAfterDiscuss,
|
|
6
|
+
maybeHandleReadyPhraseWithoutFiles,
|
|
7
|
+
maybeHandleEmptyIntentTurn,
|
|
8
|
+
resetEmptyTurnCounter,
|
|
9
|
+
} from "../guided-flow.js";
|
|
5
10
|
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
|
|
6
11
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
7
12
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
@@ -75,6 +80,20 @@ export async function handleAgentEnd(
|
|
|
75
80
|
clearDiscussionFlowState();
|
|
76
81
|
return;
|
|
77
82
|
}
|
|
83
|
+
|
|
84
|
+
// #4573 — When the LLM emits "Milestone X ready." but the required files
|
|
85
|
+
// are missing, `checkAutoStartAfterDiscuss` returns false silently. Surface
|
|
86
|
+
// that and nudge the LLM to complete the writes before the user hits the
|
|
87
|
+
// downstream "All milestones complete" warning loop.
|
|
88
|
+
if (maybeHandleReadyPhraseWithoutFiles(event)) return;
|
|
89
|
+
|
|
90
|
+
// #4573 — Empty-turn recovery: if the LLM announced intent in prose but
|
|
91
|
+
// emitted no tool calls, nudge it to execute. Fires only when auto-mode is
|
|
92
|
+
// active or a discussion autostart is pending (non-auto interactive discuss
|
|
93
|
+
// is user-driven). Runs before `isAutoActive` early return so pending
|
|
94
|
+
// discussions (where isAutoActive may be false) still get recovered.
|
|
95
|
+
if (maybeHandleEmptyIntentTurn(event, isAutoActive())) return;
|
|
96
|
+
|
|
78
97
|
if (!isAutoActive()) return;
|
|
79
98
|
if (isSessionSwitchInFlight()) return;
|
|
80
99
|
|
|
@@ -336,6 +355,9 @@ export async function handleAgentEnd(
|
|
|
336
355
|
// ── Success path ─────────────────────────────────────────────────────────
|
|
337
356
|
try {
|
|
338
357
|
resetRetryState(retryState);
|
|
358
|
+
// #4573 — Reset the empty-turn counter on any successful agent turn so
|
|
359
|
+
// transient stalls don't accumulate across independent units.
|
|
360
|
+
resetEmptyTurnCounter();
|
|
339
361
|
resolveAgentEnd(event);
|
|
340
362
|
} catch (err) {
|
|
341
363
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -35,6 +35,19 @@ function registerAlias(pi: ExtensionAPI, toolDef: any, aliasName: string, canoni
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Read a tool result's structured payload, accommodating MCP's `details` →
|
|
40
|
+
* `structuredContent` rename (#4472, #4477). In-process executions still
|
|
41
|
+
* deliver the payload on `result.details`; MCP-routed executions deliver it
|
|
42
|
+
* on `result.structuredContent` (post `adaptExecutorResult` transform). All
|
|
43
|
+
* `renderResult` callbacks in this file route through this helper so a future
|
|
44
|
+
* field rename only needs to be applied in one place.
|
|
45
|
+
*/
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- result shape varies by tool
|
|
47
|
+
function readDetails(result: any): any {
|
|
48
|
+
return result?.details ?? result?.structuredContent;
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
export function registerDbTools(pi: ExtensionAPI): void {
|
|
39
52
|
// ─── gsd_decision_save (formerly gsd_save_decision) ─────────────────────
|
|
40
53
|
|
|
@@ -110,7 +123,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
110
123
|
return new Text(text, 0, 0);
|
|
111
124
|
},
|
|
112
125
|
renderResult(result: any, _options: any, theme: any) {
|
|
113
|
-
const d = result
|
|
126
|
+
const d = readDetails(result);
|
|
114
127
|
if (result.isError || d?.error) {
|
|
115
128
|
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
116
129
|
}
|
|
@@ -188,7 +201,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
188
201
|
return new Text(text, 0, 0);
|
|
189
202
|
},
|
|
190
203
|
renderResult(result: any, _options: any, theme: any) {
|
|
191
|
-
const d = result
|
|
204
|
+
const d = readDetails(result);
|
|
192
205
|
if (result.isError || d?.error) {
|
|
193
206
|
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
194
207
|
}
|
|
@@ -273,7 +286,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
273
286
|
return new Text(text, 0, 0);
|
|
274
287
|
},
|
|
275
288
|
renderResult(result: any, _options: any, theme: any) {
|
|
276
|
-
const d = result
|
|
289
|
+
const d = readDetails(result);
|
|
277
290
|
if (result.isError || d?.error) {
|
|
278
291
|
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
279
292
|
}
|
|
@@ -322,7 +335,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
322
335
|
return new Text(text, 0, 0);
|
|
323
336
|
},
|
|
324
337
|
renderResult(result: any, _options: any, theme: any) {
|
|
325
|
-
const d = result
|
|
338
|
+
const d = readDetails(result);
|
|
326
339
|
if (result.isError || d?.error) {
|
|
327
340
|
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
328
341
|
}
|
|
@@ -406,7 +419,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
406
419
|
return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
|
|
407
420
|
},
|
|
408
421
|
renderResult(result: any, _options: any, theme: any) {
|
|
409
|
-
const d = result
|
|
422
|
+
const d = readDetails(result);
|
|
410
423
|
if (result.isError || d?.error) {
|
|
411
424
|
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
412
425
|
}
|
|
@@ -1074,13 +1087,31 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
1074
1087
|
text += theme.fg("dim", ` → ${args.verdict ?? ""}`);
|
|
1075
1088
|
return new Text(text, 0, 0);
|
|
1076
1089
|
},
|
|
1090
|
+
/**
|
|
1091
|
+
* Render the save_gate_result tool output for the TUI.
|
|
1092
|
+
*
|
|
1093
|
+
* Prefers structured fields, but falls back to `content[0].text` when the
|
|
1094
|
+
* structured payload is empty. Defensive: the structural fix on this
|
|
1095
|
+
* branch plumbs `details` through MCP via `structuredContent`, but older
|
|
1096
|
+
* hosts, a future handler that forgets `structuredContent`, or any drop
|
|
1097
|
+
* of non-standard return fields would otherwise render as
|
|
1098
|
+
* "undefined: undefined". Same fallback applies to error rendering, and
|
|
1099
|
+
* we strip a leading `Error:` from the fallback text to avoid producing
|
|
1100
|
+
* `Error: Error: ...`.
|
|
1101
|
+
*/
|
|
1077
1102
|
renderResult(result: any, _options: any, theme: any) {
|
|
1078
|
-
const d = result
|
|
1103
|
+
const d = readDetails(result);
|
|
1079
1104
|
if (result.isError || d?.error) {
|
|
1080
|
-
|
|
1105
|
+
const rawMsg = d?.error ?? result.content?.[0]?.text ?? "unknown";
|
|
1106
|
+
const msg = rawMsg.replace(/^\s*Error:\s*/i, "");
|
|
1107
|
+
return new Text(theme.fg("error", `Error: ${msg}`), 0, 0);
|
|
1108
|
+
}
|
|
1109
|
+
if (!d?.gateId || !d?.verdict) {
|
|
1110
|
+
const text = result.content?.[0]?.text ?? "Gate result saved";
|
|
1111
|
+
return new Text(theme.fg("success", text), 0, 0);
|
|
1081
1112
|
}
|
|
1082
|
-
const color = d
|
|
1083
|
-
return new Text(theme.fg(color, `${d
|
|
1113
|
+
const color = d.verdict === "flag" ? "warning" : "success";
|
|
1114
|
+
return new Text(theme.fg(color, `${d.gateId}: ${d.verdict}`), 0, 0);
|
|
1084
1115
|
},
|
|
1085
1116
|
};
|
|
1086
1117
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// GSD2 — Exec (context-mode) tool registration.
|
|
2
|
+
//
|
|
3
|
+
// Exposes the `gsd_exec` tool over MCP. Opt-in: disabled unless
|
|
4
|
+
// `context_mode.enabled: true` is set in preferences.
|
|
5
|
+
|
|
6
|
+
import { Type } from "@sinclair/typebox";
|
|
7
|
+
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
8
|
+
|
|
9
|
+
import { executeGsdExec } from "../tools/exec-tool.js";
|
|
10
|
+
import { executeExecSearch } from "../tools/exec-search-tool.js";
|
|
11
|
+
import { executeResume } from "../tools/resume-tool.js";
|
|
12
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
13
|
+
import { logWarning } from "../workflow-logger.js";
|
|
14
|
+
|
|
15
|
+
export function registerExecTools(pi: ExtensionAPI): void {
|
|
16
|
+
pi.registerTool({
|
|
17
|
+
name: "gsd_exec",
|
|
18
|
+
label: "Exec (Sandboxed)",
|
|
19
|
+
description:
|
|
20
|
+
"Run a short script (bash/node/python) in a subprocess. Full stdout/stderr persist to " +
|
|
21
|
+
".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
|
|
22
|
+
"this instead of reading many files or emitting large tool outputs — e.g. have the script " +
|
|
23
|
+
"count/grep/summarize and log the finding. Enabled by default; opt out via " +
|
|
24
|
+
"preferences.context_mode.enabled=false.",
|
|
25
|
+
promptSnippet:
|
|
26
|
+
"Run a bash/node/python script in a sandbox; full output is saved to disk and only a digest returns",
|
|
27
|
+
promptGuidelines: [
|
|
28
|
+
"Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
|
|
29
|
+
"Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
|
|
30
|
+
"The digest is the last ~300 chars of stdout — size your log output accordingly.",
|
|
31
|
+
"Need the full output? Read the stdout_path returned in details (file on local disk).",
|
|
32
|
+
],
|
|
33
|
+
parameters: Type.Object({
|
|
34
|
+
runtime: Type.Union(
|
|
35
|
+
[Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")],
|
|
36
|
+
{ description: "Interpreter: bash (-c), node (-e), or python3 (-c)." },
|
|
37
|
+
),
|
|
38
|
+
script: Type.String({ description: "Script body. Keep output small (log the finding, not the data)." }),
|
|
39
|
+
purpose: Type.Optional(Type.String({ description: "Short label recorded in meta.json for later review." })),
|
|
40
|
+
timeout_ms: Type.Optional(
|
|
41
|
+
Type.Number({
|
|
42
|
+
description: "Per-invocation timeout (ms). Capped at 600000. Default from preferences.",
|
|
43
|
+
minimum: 1_000,
|
|
44
|
+
maximum: 600_000,
|
|
45
|
+
}),
|
|
46
|
+
),
|
|
47
|
+
}),
|
|
48
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
49
|
+
let prefs: Awaited<ReturnType<typeof loadEffectiveGSDPreferences>> | null = null;
|
|
50
|
+
try {
|
|
51
|
+
prefs = loadEffectiveGSDPreferences();
|
|
52
|
+
} catch (err) {
|
|
53
|
+
logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
|
|
54
|
+
}
|
|
55
|
+
return executeGsdExec(params as Parameters<typeof executeGsdExec>[0], {
|
|
56
|
+
baseDir: process.cwd(),
|
|
57
|
+
preferences: prefs?.preferences ?? null,
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
pi.registerTool({
|
|
63
|
+
name: "gsd_exec_search",
|
|
64
|
+
label: "Search gsd_exec History",
|
|
65
|
+
description:
|
|
66
|
+
"List prior gsd_exec runs (most recent first) from .gsd/exec/*.meta.json. Useful for " +
|
|
67
|
+
"rediscovering the stdout_path of an earlier run without re-executing it. Read-only.",
|
|
68
|
+
promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
|
|
69
|
+
promptGuidelines: [
|
|
70
|
+
"Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
|
|
71
|
+
"The preview shows the trailing ~300 chars of stdout; read stdout_path for the full transcript.",
|
|
72
|
+
],
|
|
73
|
+
parameters: Type.Object({
|
|
74
|
+
query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
|
|
75
|
+
runtime: Type.Optional(
|
|
76
|
+
Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], {
|
|
77
|
+
description: "Restrict to one runtime.",
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
failing_only: Type.Optional(Type.Boolean({ description: "Only non-zero exit codes and timeouts." })),
|
|
81
|
+
limit: Type.Optional(Type.Number({ description: "Max results (default 20, cap 200)", minimum: 1, maximum: 200 })),
|
|
82
|
+
}),
|
|
83
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
84
|
+
return executeExecSearch(params as Parameters<typeof executeExecSearch>[0], {
|
|
85
|
+
baseDir: process.cwd(),
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
pi.registerTool({
|
|
91
|
+
name: "gsd_resume",
|
|
92
|
+
label: "Resume (Read Snapshot)",
|
|
93
|
+
description:
|
|
94
|
+
"Return the contents of .gsd/last-snapshot.md — a ≤2 KB digest of top memories, recent " +
|
|
95
|
+
"gsd_exec runs, and active context, written automatically on session_before_compact. Use " +
|
|
96
|
+
"this after compaction or session resume to re-orient quickly.",
|
|
97
|
+
promptSnippet: "Read the pre-compaction snapshot to re-orient after context loss",
|
|
98
|
+
promptGuidelines: [
|
|
99
|
+
"Call this right after a session resumes if you feel you've lost durable context.",
|
|
100
|
+
"The snapshot is a summary — use memory_query or gsd_exec_search for detail.",
|
|
101
|
+
],
|
|
102
|
+
parameters: Type.Object({}),
|
|
103
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
104
|
+
return executeResume(params as Parameters<typeof executeResume>[0], {
|
|
105
|
+
baseDir: process.cwd(),
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -8,6 +8,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
|
|
|
8
8
|
import { loadEcosystemExtensions } from "../ecosystem/loader.js";
|
|
9
9
|
import { registerDbTools } from "./db-tools.js";
|
|
10
10
|
import { registerDynamicTools } from "./dynamic-tools.js";
|
|
11
|
+
import { registerExecTools } from "./exec-tools.js";
|
|
11
12
|
import { registerJournalTools } from "./journal-tools.js";
|
|
12
13
|
import { registerMemoryTools } from "./memory-tools.js";
|
|
13
14
|
import { registerQueryTools } from "./query-tools.js";
|
|
@@ -100,6 +101,7 @@ export function registerGsdExtension(pi: ExtensionAPI): void {
|
|
|
100
101
|
["journal-tools", () => registerJournalTools(pi)],
|
|
101
102
|
["query-tools", () => registerQueryTools(pi)],
|
|
102
103
|
["memory-tools", () => registerMemoryTools(pi)],
|
|
104
|
+
["exec-tools", () => registerExecTools(pi)],
|
|
103
105
|
["shortcuts", () => registerShortcuts(pi)],
|
|
104
106
|
["hooks", () => registerHooks(pi, ecosystemHandlers)],
|
|
105
107
|
["ecosystem", () => {
|
|
@@ -18,12 +18,13 @@ import { loadToolApiKeys } from "../commands-config.js";
|
|
|
18
18
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
19
19
|
import { deriveState } from "../state.js";
|
|
20
20
|
import { getAutoDashboardData, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto.js";
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
import { isParallelActive, shutdownParallel } from "../parallel-orchestrator.js";
|
|
23
23
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
24
24
|
import { saveActivityLog } from "../activity-log.js";
|
|
25
25
|
import { resetAskUserQuestionsCache } from "../../ask-user-questions.js";
|
|
26
|
-
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult } from "../safety/evidence-collector.js";
|
|
26
|
+
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
27
|
+
import { parseUnitId } from "../unit-id.js";
|
|
27
28
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
28
29
|
import { logWarning as safetyLogWarning } from "../workflow-logger.js";
|
|
29
30
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
@@ -48,7 +49,9 @@ export function registerHooks(
|
|
|
48
49
|
initNotificationStore(process.cwd());
|
|
49
50
|
installNotifyInterceptor(ctx);
|
|
50
51
|
initNotificationWidget(ctx);
|
|
51
|
-
|
|
52
|
+
if (!isAutoActive()) {
|
|
53
|
+
initHealthWidget(ctx);
|
|
54
|
+
}
|
|
52
55
|
resetWriteGateState();
|
|
53
56
|
resetToolCallLoopGuard();
|
|
54
57
|
resetAskUserQuestionsCache();
|
|
@@ -90,7 +93,7 @@ export function registerHooks(
|
|
|
90
93
|
}
|
|
91
94
|
loadToolApiKeys();
|
|
92
95
|
if (isAutoActive()) {
|
|
93
|
-
ctx.ui.
|
|
96
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
94
97
|
}
|
|
95
98
|
});
|
|
96
99
|
|
|
@@ -113,7 +116,7 @@ export function registerHooks(
|
|
|
113
116
|
}
|
|
114
117
|
loadToolApiKeys();
|
|
115
118
|
if (isAutoActive()) {
|
|
116
|
-
ctx.ui.
|
|
119
|
+
ctx.ui.setWidget("gsd-health", undefined);
|
|
117
120
|
}
|
|
118
121
|
});
|
|
119
122
|
|
|
@@ -225,6 +228,42 @@ export function registerHooks(
|
|
|
225
228
|
}));
|
|
226
229
|
});
|
|
227
230
|
|
|
231
|
+
// Context-mode snapshot: write .gsd/last-snapshot.md before compaction so
|
|
232
|
+
// agents can call gsd_resume (or Read the file) to re-orient. Opt-in via
|
|
233
|
+
// preferences.context_mode.enabled. Runs after the auto-cancel handler
|
|
234
|
+
// above — if that one returned cancel:true, pi still fires us but the
|
|
235
|
+
// compaction won't actually happen; the snapshot is still useful then,
|
|
236
|
+
// since auto may pause and resume later.
|
|
237
|
+
pi.on("session_before_compact", async () => {
|
|
238
|
+
try {
|
|
239
|
+
const { loadEffectiveGSDPreferences } = await import("../preferences.js");
|
|
240
|
+
const { isContextModeEnabled } = await import("../preferences-types.js");
|
|
241
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
242
|
+
if (!isContextModeEnabled(prefs?.preferences)) return;
|
|
243
|
+
const { writeCompactionSnapshot } = await import("../compaction-snapshot.js");
|
|
244
|
+
const { ensureDbOpen } = await import("./dynamic-tools.js");
|
|
245
|
+
await ensureDbOpen();
|
|
246
|
+
const basePath = process.cwd();
|
|
247
|
+
let activeContext: string | null = null;
|
|
248
|
+
try {
|
|
249
|
+
const state = await deriveState(basePath);
|
|
250
|
+
if (state.activeMilestone && state.activeSlice && state.activeTask) {
|
|
251
|
+
activeContext =
|
|
252
|
+
`Active: ${state.activeMilestone.id} / ${state.activeSlice.id} / ${state.activeTask.id}` +
|
|
253
|
+
(state.activeTask.title ? ` — ${state.activeTask.title}` : "");
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
/* non-fatal */
|
|
257
|
+
}
|
|
258
|
+
writeCompactionSnapshot(basePath, { activeContext });
|
|
259
|
+
} catch (err) {
|
|
260
|
+
safetyLogWarning(
|
|
261
|
+
"context-mode",
|
|
262
|
+
`failed to write compaction snapshot: ${err instanceof Error ? err.message : String(err)}`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
228
267
|
pi.on("session_shutdown", async (_event, ctx: ExtensionContext) => {
|
|
229
268
|
if (isParallelActive()) {
|
|
230
269
|
try {
|
|
@@ -461,6 +500,15 @@ export function registerHooks(
|
|
|
461
500
|
// Safety harness: record tool execution results for evidence cross-referencing
|
|
462
501
|
if (isAutoActive()) {
|
|
463
502
|
safetyRecordToolResult(event.toolCallId, event.toolName, event.result, event.isError);
|
|
503
|
+
// Persist evidence to disk after each tool result so it survives a session
|
|
504
|
+
// restart mid-unit (Bug #4385 — non-persisted evidence false positives).
|
|
505
|
+
const dash = getAutoDashboardData();
|
|
506
|
+
if (dash.basePath && dash.currentUnit?.type === "execute-task") {
|
|
507
|
+
const { milestone: pMid, slice: pSid, task: pTid } = parseUnitId(dash.currentUnit.id);
|
|
508
|
+
if (pMid && pSid && pTid) {
|
|
509
|
+
saveEvidenceToDisk(dash.basePath, pMid, pSid, pTid);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
464
512
|
}
|
|
465
513
|
});
|
|
466
514
|
|