gsd-pi 2.80.0-dev.c5c38454b → 2.80.0-dev.cf9433f56
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 +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +66 -45
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto.js +77 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +21 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +80 -14
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +7 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
- 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 +7 -7
- 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 +7 -7
- 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 +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.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 +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +38 -0
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +77 -48
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +18 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +96 -14
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +7 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +72 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{TCSim36ZpcPu2WgeoC45g → -5nHJWzSdG-WkPMul_khA}/_ssgManifest.js +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* utility.
|
|
7
7
|
*/
|
|
8
8
|
import { loadFile, parseContinue, parseSummary, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
|
|
9
|
-
import { hasVerdict, getUatType } from "./verdict-parser.js";
|
|
9
|
+
import { hasVerdict, getUatType, extractVerdict } from "./verdict-parser.js";
|
|
10
10
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
11
11
|
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
|
|
12
12
|
import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
|
|
@@ -21,10 +21,12 @@ import { assertGateCoverage, getGatesForTurn, } from "./gate-registry.js";
|
|
|
21
21
|
import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
|
|
22
22
|
import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
|
|
23
23
|
import { composeContextModeInstructions, composeInlinedContext } from "./unit-context-composer.js";
|
|
24
|
+
import { readCompactionSnapshot } from "./compaction-snapshot.js";
|
|
24
25
|
import { logWarning } from "./workflow-logger.js";
|
|
25
26
|
import { inlineGraphSubgraph } from "./graph-context.js";
|
|
26
27
|
import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
|
|
27
28
|
import { resolveSkillManifest, warnIfManifestHasMissingSkills } from "./skill-manifest.js";
|
|
29
|
+
import { classifyProject } from "./detection.js";
|
|
28
30
|
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
|
29
31
|
/**
|
|
30
32
|
* Historical static ceiling for the preamble cap. Kept as an upper bound even
|
|
@@ -62,6 +64,104 @@ function resolvePromptBudgets() {
|
|
|
62
64
|
function resolveSummaryBudgetChars() {
|
|
63
65
|
return resolvePromptBudgets().summaryBudgetChars;
|
|
64
66
|
}
|
|
67
|
+
function formatProjectClassificationForPlanning(classification) {
|
|
68
|
+
const sampleFiles = classification.contentFiles.slice(0, 8);
|
|
69
|
+
const sample = sampleFiles.length > 0 ? sampleFiles.map((file) => `\`${file}\``).join(", ") : "(none)";
|
|
70
|
+
const lines = [
|
|
71
|
+
"### Project Classification",
|
|
72
|
+
"",
|
|
73
|
+
`- **Kind:** ${classification.kind}`,
|
|
74
|
+
`- **Content files:** ${classification.contentFiles.length}`,
|
|
75
|
+
`- **Sample files:** ${sample}`,
|
|
76
|
+
`- **Reason:** ${classification.reason}`,
|
|
77
|
+
"",
|
|
78
|
+
];
|
|
79
|
+
if (classification.kind === "untyped-existing") {
|
|
80
|
+
if (classification.contentFiles.length <= 2) {
|
|
81
|
+
lines.push("**Workflow sizing:** This is a tiny existing untyped project. Prefer exactly one slice unless the milestone request clearly spans multiple independent user-visible capabilities.");
|
|
82
|
+
}
|
|
83
|
+
else if (classification.contentFiles.length <= 5) {
|
|
84
|
+
lines.push("**Workflow sizing:** This is a small existing untyped project. Prefer 1-2 slices unless the milestone request clearly spans multiple independent user-visible capabilities.");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push("**Workflow sizing:** Existing untyped project. Use generic file-level workflow guidance and size slices by real capability boundaries, not by missing tooling markers.");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (classification.kind === "greenfield") {
|
|
91
|
+
lines.push("**Workflow sizing:** No project content exists yet. Use normal greenfield sizing for the requested scope.");
|
|
92
|
+
}
|
|
93
|
+
else if (classification.kind === "typed-existing") {
|
|
94
|
+
lines.push("**Workflow sizing:** Known project markers exist. Use normal ecosystem-aware planning guidance.");
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
lines.push("**Workflow sizing:** Invalid repository state. Planning should surface this as a blocker rather than inventing project structure.");
|
|
98
|
+
}
|
|
99
|
+
return lines.join("\n");
|
|
100
|
+
}
|
|
101
|
+
function normalizeArtifactRef(value) {
|
|
102
|
+
return value.trim().replace(/^[-\s]+/, "").replace(/^["'`]+|["'`]+$/g, "").replaceAll("\\", "/").replace(/^\.\//, "");
|
|
103
|
+
}
|
|
104
|
+
function parseCoveredArtifacts(validationContent) {
|
|
105
|
+
const covered = new Set();
|
|
106
|
+
const lines = validationContent.split(/\r?\n/);
|
|
107
|
+
let inCoveredArtifacts = false;
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
if (/^\s*covered[-_]?artifacts\s*:/i.test(line)) {
|
|
110
|
+
inCoveredArtifacts = true;
|
|
111
|
+
const inline = line.split(/covered[-_]?artifacts\s*:/i)[1]?.trim();
|
|
112
|
+
if (inline && inline !== "[]") {
|
|
113
|
+
inline.replace(/^\[|\]$/g, "").split(",").map(normalizeArtifactRef).filter(Boolean).forEach((item) => covered.add(item));
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!inCoveredArtifacts)
|
|
118
|
+
continue;
|
|
119
|
+
if (/^\S/.test(line) && !/^\s*-/.test(line))
|
|
120
|
+
break;
|
|
121
|
+
const item = line.match(/^\s*-\s*(.+)$/)?.[1];
|
|
122
|
+
if (item)
|
|
123
|
+
covered.add(normalizeArtifactRef(item));
|
|
124
|
+
}
|
|
125
|
+
return covered;
|
|
126
|
+
}
|
|
127
|
+
function isValidationFreshOrApplicable(validationContent, currentArtifacts) {
|
|
128
|
+
if (!validationContent)
|
|
129
|
+
return false;
|
|
130
|
+
if (!/validation_metadata:/i.test(validationContent))
|
|
131
|
+
return false;
|
|
132
|
+
const coveredArtifacts = parseCoveredArtifacts(validationContent);
|
|
133
|
+
if (coveredArtifacts.size === 0)
|
|
134
|
+
return false;
|
|
135
|
+
return currentArtifacts
|
|
136
|
+
.map(normalizeArtifactRef)
|
|
137
|
+
.filter(Boolean)
|
|
138
|
+
.every((artifact) => coveredArtifacts.has(artifact));
|
|
139
|
+
}
|
|
140
|
+
function formatCloseoutReviewInstructions(validationContent, validationRel, currentArtifacts) {
|
|
141
|
+
const verdict = validationContent ? extractVerdict(validationContent) : null;
|
|
142
|
+
const validationFresh = isValidationFreshOrApplicable(validationContent, currentArtifacts);
|
|
143
|
+
if (verdict === "pass" && validationFresh) {
|
|
144
|
+
return [
|
|
145
|
+
"### Passing Validation Artifact",
|
|
146
|
+
"",
|
|
147
|
+
`A passing validation artifact is present at \`${validationRel}\`. Treat it as authoritative for success criteria, requirement coverage, verification classes, and cross-slice integration.`,
|
|
148
|
+
"",
|
|
149
|
+
"Do not delegate fresh reviewer/security/tester audits and do not redo the validation evidence review unless the artifact is internally inconsistent with the inlined summaries. Focus this unit on final milestone narrative, learnings, PROJECT/requirements updates, and `gsd_complete_milestone`.",
|
|
150
|
+
].join("\n");
|
|
151
|
+
}
|
|
152
|
+
if (verdict) {
|
|
153
|
+
return [
|
|
154
|
+
"### Validation Requires Attention",
|
|
155
|
+
"",
|
|
156
|
+
`A validation artifact is present at \`${validationRel}\` with verdict \`${verdict}\`, but it is missing freshness metadata or does not cover current milestone artifacts. Do not treat the milestone as complete unless the issues are resolved and evidence supports completion.`,
|
|
157
|
+
].join("\n");
|
|
158
|
+
}
|
|
159
|
+
return [
|
|
160
|
+
"### No Passing Validation Artifact",
|
|
161
|
+
"",
|
|
162
|
+
`No passing validation artifact was found at \`${validationRel}\`. Use the full closeout review path before completion.`,
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
65
165
|
function capPreamble(preamble) {
|
|
66
166
|
// Cap inlined context at min(historical 30K ceiling, scaled inline budget).
|
|
67
167
|
// The ceiling preserves pre-fix behavior for large-window users; the scaled
|
|
@@ -79,8 +179,19 @@ function renderContextModeForPrompt(unitType, base, renderMode = "standalone") {
|
|
|
79
179
|
renderMode,
|
|
80
180
|
});
|
|
81
181
|
}
|
|
82
|
-
function
|
|
182
|
+
function renderContextModeBlockForPrompt(unitType, base, renderMode = "standalone") {
|
|
83
183
|
const contextMode = renderContextModeForPrompt(unitType, base, renderMode);
|
|
184
|
+
if (!contextMode)
|
|
185
|
+
return "";
|
|
186
|
+
if (renderMode === "nested")
|
|
187
|
+
return contextMode;
|
|
188
|
+
const snapshot = readCompactionSnapshot(base);
|
|
189
|
+
if (!snapshot?.trim())
|
|
190
|
+
return contextMode;
|
|
191
|
+
return `${contextMode}\n\n## Context Snapshot\nSource: \`.gsd/last-snapshot.md\`\n\n${snapshot.trimEnd()}`;
|
|
192
|
+
}
|
|
193
|
+
function prependContextModeToBlock(unitType, base, block, renderMode = "standalone") {
|
|
194
|
+
const contextMode = renderContextModeBlockForPrompt(unitType, base, renderMode);
|
|
84
195
|
if (!contextMode)
|
|
85
196
|
return block;
|
|
86
197
|
if (!block.trim())
|
|
@@ -1465,6 +1576,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
|
|
|
1465
1576
|
const researchAnchor = readPhaseAnchor(base, mid, "research-milestone");
|
|
1466
1577
|
if (researchAnchor)
|
|
1467
1578
|
inlined.push(formatAnchorForPrompt(researchAnchor));
|
|
1579
|
+
inlined.push(formatProjectClassificationForPlanning(classifyProject(base)));
|
|
1468
1580
|
inlined.push(await inlineFile(contextPath, contextRel, "Milestone Context"));
|
|
1469
1581
|
const researchInline = await inlineFileOptional(researchPath, researchRel, "Milestone Research");
|
|
1470
1582
|
if (researchInline)
|
|
@@ -2017,6 +2129,9 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
2017
2129
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
2018
2130
|
const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
|
|
2019
2131
|
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
|
2132
|
+
const validationPath = resolveMilestoneFile(base, mid, "VALIDATION");
|
|
2133
|
+
const validationRel = relMilestoneFile(base, mid, "VALIDATION");
|
|
2134
|
+
const validationContent = validationPath ? await loadFile(validationPath) : null;
|
|
2020
2135
|
const inlined = [];
|
|
2021
2136
|
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
|
2022
2137
|
// Inline all slice summaries (deduplicated by slice ID)
|
|
@@ -2056,6 +2171,13 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|
|
2056
2171
|
const pathList = summaryRelPaths.map(p => `- \`${p}\``).join("\n");
|
|
2057
2172
|
inlined.push(`### On-demand Slice Summaries\n\nExcerpted above. Read the full file for any slice when the excerpt's section heads don't carry enough narrative for the milestone summary you're drafting:\n\n${pathList}`);
|
|
2058
2173
|
}
|
|
2174
|
+
const validationContext = [
|
|
2175
|
+
formatCloseoutReviewInstructions(validationContent, validationRel, [validationRel, roadmapRel, ...summaryRelPaths]),
|
|
2176
|
+
];
|
|
2177
|
+
if (validationContent) {
|
|
2178
|
+
validationContext.push(`### Milestone Validation\nSource: \`${validationRel}\`\n\n${validationContent.trim()}`);
|
|
2179
|
+
}
|
|
2180
|
+
inlined.unshift(...validationContext);
|
|
2059
2181
|
// Inline root GSD files (skip for minimal — completion can read these if needed)
|
|
2060
2182
|
if (inlineLevel !== "minimal") {
|
|
2061
2183
|
const requirementsInline = await inlineRequirementsFromDb(base, mid, undefined, inlineLevel);
|
|
@@ -30,7 +30,49 @@ import { getProjectResearchStatus } from "./project-research-policy.js";
|
|
|
30
30
|
// Re-export so existing consumers of auto-recovery.ts keep working.
|
|
31
31
|
export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
|
|
32
32
|
export { classifyMilestoneSummaryContent, } from "./milestone-summary-classifier.js";
|
|
33
|
-
|
|
33
|
+
export function refreshRecoveryDbForArtifact(unitType, unitId) {
|
|
34
|
+
if (unitType !== "plan-slice" && unitType !== "execute-task")
|
|
35
|
+
return { ok: true };
|
|
36
|
+
if (!isDbAvailable())
|
|
37
|
+
return { ok: true };
|
|
38
|
+
if (!refreshOpenDatabaseFromDisk()) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
fatal: unitType === "execute-task",
|
|
42
|
+
reason: `${unitType}-db-refresh-failed`,
|
|
43
|
+
message: `Stuck recovery found ${unitType} ${unitId} artifacts, but the DB refresh failed.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (unitType !== "execute-task")
|
|
47
|
+
return { ok: true };
|
|
48
|
+
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
|
49
|
+
if (!mid || !sid || !tid) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
fatal: true,
|
|
53
|
+
reason: "execute-task-invalid-unit-id",
|
|
54
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the unit id could not be parsed for DB verification.`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const task = getTask(mid, sid, tid);
|
|
58
|
+
if (!task) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
fatal: true,
|
|
62
|
+
reason: "execute-task-artifact-db-missing",
|
|
63
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but no matching DB task row exists after refresh.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (!isClosedStatus(task.status)) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
fatal: true,
|
|
70
|
+
reason: "execute-task-artifact-db-mismatch",
|
|
71
|
+
message: `Stuck recovery found execute-task ${unitId} artifacts, but the DB task status is still '${task.status}' after refresh.`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { ok: true };
|
|
75
|
+
}
|
|
34
76
|
function hasCapturedWorkflowPrefs(base) {
|
|
35
77
|
const prefsPath = resolveExpectedArtifactPath("workflow-preferences", "WORKFLOW-PREFS", base);
|
|
36
78
|
if (!prefsPath || !existsSync(prefsPath))
|
|
@@ -24,7 +24,7 @@ let _currentSigtermHandler = null;
|
|
|
24
24
|
*
|
|
25
25
|
* Returns the new handler so the caller can store and deregister it later.
|
|
26
26
|
*/
|
|
27
|
-
export function registerSigtermHandler(currentBasePath, previousHandler) {
|
|
27
|
+
export function registerSigtermHandler(currentBasePath, previousHandler, onSignalCleanup) {
|
|
28
28
|
// Remove the explicitly-passed previous handler
|
|
29
29
|
if (previousHandler) {
|
|
30
30
|
for (const sig of CLEANUP_SIGNALS)
|
|
@@ -37,6 +37,13 @@ export function registerSigtermHandler(currentBasePath, previousHandler) {
|
|
|
37
37
|
process.off(sig, _currentSigtermHandler);
|
|
38
38
|
}
|
|
39
39
|
const handler = () => {
|
|
40
|
+
try {
|
|
41
|
+
onSignalCleanup?.();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
void 0;
|
|
45
|
+
// Signal cleanup is best-effort; lock cleanup and process exit still run.
|
|
46
|
+
}
|
|
40
47
|
clearLock(currentBasePath);
|
|
41
48
|
releaseSessionLock(currentBasePath);
|
|
42
49
|
process.exit(0);
|
|
@@ -35,13 +35,13 @@ export async function recoverTimedOutUnit(ctx, pi, unitType, unitId, reason, rct
|
|
|
35
35
|
writeUnitRuntimeRecord(basePath, unitType, unitId, currentUnitStartedAt, {
|
|
36
36
|
recovery: status,
|
|
37
37
|
});
|
|
38
|
-
const durableComplete = status.summaryExists && status.taskChecked && status.nextActionAdvanced;
|
|
38
|
+
const durableComplete = status.dbComplete || (status.summaryExists && status.taskChecked && status.nextActionAdvanced);
|
|
39
39
|
if (durableComplete) {
|
|
40
40
|
writeUnitRuntimeRecord(basePath, unitType, unitId, currentUnitStartedAt, {
|
|
41
41
|
phase: "finalized",
|
|
42
42
|
recovery: status,
|
|
43
43
|
});
|
|
44
|
-
ctx.ui.notify(`${reason === "idle" ? "Idle" : "Timeout"} recovery: ${unitType} ${unitId} already completed
|
|
44
|
+
ctx.ui.notify(`${reason === "idle" ? "Idle" : "Timeout"} recovery: ${unitType} ${unitId} already completed. Continuing auto-mode. (attempt ${attemptNumber})`, "info");
|
|
45
45
|
unitRecoveryCount.delete(recoveryKey);
|
|
46
46
|
bumpAndResolveSynthetic(`timeout-recovery:${reason}:${unitType}/${unitId}`);
|
|
47
47
|
return "recovered";
|
|
@@ -20,7 +20,7 @@ import { gsdRoot, resolveMilestoneFile, resolveMilestonePath, resolveDir, milest
|
|
|
20
20
|
import { invalidateAllCaches } from "./cache.js";
|
|
21
21
|
import { clearActivityLogState } from "./activity-log.js";
|
|
22
22
|
import { synthesizeCrashRecovery, getDeepDiagnostic, readActiveMilestoneId, } from "./session-forensics.js";
|
|
23
|
-
import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, emitCrashRecoveredUnitEnd, } from "./crash-recovery.js";
|
|
23
|
+
import { writeLock, clearLock, readCrashLock, isLockProcessAlive, formatCrashInfo, emitCrashRecoveredUnitEnd, emitOpenUnitEndForUnit, } from "./crash-recovery.js";
|
|
24
24
|
import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSessionLock, } from "./session-lock.js";
|
|
25
25
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, getIsolationMode, } from "./preferences.js";
|
|
26
26
|
import { sendDesktopNotification } from "./notifications.js";
|
|
@@ -61,6 +61,8 @@ import { isClosedStatus } from "./status-guards.js";
|
|
|
61
61
|
import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, } from "./auto-dashboard.js";
|
|
62
62
|
import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
|
|
63
63
|
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
64
|
+
import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
65
|
+
import { writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
64
66
|
import { countPendingCaptures } from "./captures.js";
|
|
65
67
|
import { CMUX_CHANNELS } from "../shared/cmux-events.js";
|
|
66
68
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
@@ -85,6 +87,16 @@ import { validateDirectory } from "./validate-directory.js";
|
|
|
85
87
|
import { createAutoOrchestrator } from "./auto/orchestrator.js";
|
|
86
88
|
import { WorktreeResolver, } from "./worktree-resolver.js";
|
|
87
89
|
import { reorderForCaching } from "./prompt-ordering.js";
|
|
90
|
+
import { initTokenCounter } from "./token-counter.js";
|
|
91
|
+
// Warm the tiktoken encoder at extension startup so context-budget computations
|
|
92
|
+
// can use accurate token counts via countTokensSync without paying the load
|
|
93
|
+
// cost mid-prompt-build. Fire-and-forget — failure falls back to the
|
|
94
|
+
// provider-aware char-ratio estimator already used by getCharsPerToken().
|
|
95
|
+
// Catch rejections explicitly: an unhandled rejection at module-import time
|
|
96
|
+
// can destabilize startup before the engine logger is configured.
|
|
97
|
+
void initTokenCounter().catch((err) => {
|
|
98
|
+
logWarning("engine", `token counter warm-up failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
99
|
+
});
|
|
88
100
|
export { STUB_RECOVERY_THRESHOLD, NEW_SESSION_TIMEOUT_MS, } from "./auto/session.js";
|
|
89
101
|
import { autoSession as s } from "./auto-runtime-state.js";
|
|
90
102
|
import { gsdHome } from "./gsd-home.js";
|
|
@@ -112,11 +124,12 @@ const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
|
112
124
|
* the DB is unavailable (e.g. fresh project before init) we skip registration
|
|
113
125
|
* silently rather than blocking session start.
|
|
114
126
|
*/
|
|
115
|
-
function registerAutoWorkerForSession(session) {
|
|
127
|
+
function registerAutoWorkerForSession(session, projectRootOverride) {
|
|
116
128
|
if (session.workerId)
|
|
117
129
|
return; // already registered (e.g. resume re-runs)
|
|
118
130
|
try {
|
|
119
|
-
const projectRootRealpath = normalizeRealPath(
|
|
131
|
+
const projectRootRealpath = normalizeRealPath(projectRootOverride
|
|
132
|
+
?? session.scope?.workspace.projectRoot
|
|
120
133
|
?? (session.originalBasePath || session.basePath));
|
|
121
134
|
session.workerId = registerAutoWorker({ projectRootRealpath });
|
|
122
135
|
}
|
|
@@ -225,8 +238,16 @@ function synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile
|
|
|
225
238
|
export function _synthesizePausedSessionRecoveryForTest(basePath, unitType, unitId, sessionFile) {
|
|
226
239
|
return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
|
|
227
240
|
}
|
|
241
|
+
const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
|
|
242
|
+
function withDetachedAutoKeepalive(run) {
|
|
243
|
+
const keepAlive = setInterval(() => { }, DETACHED_AUTO_KEEPALIVE_INTERVAL_MS);
|
|
244
|
+
return run.finally(() => {
|
|
245
|
+
clearInterval(keepAlive);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
export const _withDetachedAutoKeepaliveForTest = withDetachedAutoKeepalive;
|
|
228
249
|
export function startAutoDetached(ctx, pi, base, verboseMode, options) {
|
|
229
|
-
void startAuto(ctx, pi, base, verboseMode, options).catch((err) => {
|
|
250
|
+
void withDetachedAutoKeepalive(startAuto(ctx, pi, base, verboseMode, options)).catch((err) => {
|
|
230
251
|
const message = getErrorMessage(err);
|
|
231
252
|
ctx.ui.notify(`Auto-start failed: ${message}`, "error");
|
|
232
253
|
logWarning("engine", `auto start error: ${message}`, { file: "auto.ts" });
|
|
@@ -264,9 +285,50 @@ export function shouldUseWorktreeIsolation(basePath) {
|
|
|
264
285
|
*/
|
|
265
286
|
// Re-export budget utilities for external consumers
|
|
266
287
|
export { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, } from "./auto-budget.js";
|
|
288
|
+
function closeOutSignalInterruptedUnit(currentBasePath) {
|
|
289
|
+
const currentUnit = s.currentUnit;
|
|
290
|
+
if (!currentUnit)
|
|
291
|
+
return;
|
|
292
|
+
const reason = "Auto-mode process received a termination signal";
|
|
293
|
+
const errorContext = {
|
|
294
|
+
message: reason,
|
|
295
|
+
category: "aborted",
|
|
296
|
+
isTransient: false,
|
|
297
|
+
};
|
|
298
|
+
const basePath = s.basePath || currentBasePath;
|
|
299
|
+
try {
|
|
300
|
+
emitOpenUnitEndForUnit(basePath, currentUnit.type, currentUnit.id, "cancelled", errorContext);
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
logWarning("engine", `signal unit-end cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
writeUnitRuntimeRecord(basePath, currentUnit.type, currentUnit.id, currentUnit.startedAt, {
|
|
307
|
+
phase: "crashed",
|
|
308
|
+
lastProgressAt: Date.now(),
|
|
309
|
+
lastProgressKind: "signal",
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
logWarning("engine", `signal runtime cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
if (s.workerId)
|
|
317
|
+
markLatestActiveForWorkerCanceled(s.workerId, "signal-exit");
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
logWarning("engine", `signal dispatch cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
resolveAgentEndCancelled(errorContext);
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
logWarning("engine", `signal resolve cleanup failed: ${getErrorMessage(err)}`, { file: "auto.ts" });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
267
329
|
/** Wrapper: register SIGTERM handler and store reference. */
|
|
268
330
|
function registerSigtermHandler(currentBasePath) {
|
|
269
|
-
s.sigtermHandler = _registerSigtermHandler(currentBasePath, s.sigtermHandler);
|
|
331
|
+
s.sigtermHandler = _registerSigtermHandler(currentBasePath, s.sigtermHandler, () => closeOutSignalInterruptedUnit(currentBasePath));
|
|
270
332
|
}
|
|
271
333
|
/** Wrapper: deregister SIGTERM handler and clear reference. */
|
|
272
334
|
function deregisterSigtermHandler() {
|
|
@@ -658,6 +720,8 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
658
720
|
if (s.workerId) {
|
|
659
721
|
markWorkerStopping(s.workerId);
|
|
660
722
|
}
|
|
723
|
+
s.workerId = null;
|
|
724
|
+
s.milestoneLeaseToken = null;
|
|
661
725
|
}
|
|
662
726
|
catch (e) {
|
|
663
727
|
debugLog("stop-cleanup-coordination", { error: e instanceof Error ? e.message : String(e) });
|
|
@@ -1558,6 +1622,10 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1558
1622
|
: new URL("../../../resource-loader.js", import.meta.url).href;
|
|
1559
1623
|
const { initResources } = await import(resourceLoaderPath);
|
|
1560
1624
|
initResources(agentDir);
|
|
1625
|
+
// initResources() uses synchronous fs APIs, so the prompt-template cache
|
|
1626
|
+
// can be primed immediately — no need for the legacy 1s setTimeout deferral.
|
|
1627
|
+
const { primeCache } = await import("./prompt-loader.js");
|
|
1628
|
+
primeCache();
|
|
1561
1629
|
// Open the project DB before rebuild/derive so resume uses DB-backed
|
|
1562
1630
|
// state instead of falling back to stale markdown parsing (#2940).
|
|
1563
1631
|
await openProjectDbIfPresent(s.basePath);
|
|
@@ -1623,6 +1691,10 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1623
1691
|
lockBase,
|
|
1624
1692
|
buildResolver,
|
|
1625
1693
|
};
|
|
1694
|
+
// Register the worker before bootstrap enters a milestone worktree.
|
|
1695
|
+
// This ensures enterMilestone can claim a lease and seed dispatch claims
|
|
1696
|
+
// for crash-recovery fidelity (#5405).
|
|
1697
|
+
registerAutoWorkerForSession(s, base);
|
|
1626
1698
|
const ready = await bootstrapAutoSession(s, ctx, pi, base, verboseMode, requestedStepMode, bootstrapDeps, freshStartAssessment);
|
|
1627
1699
|
if (!ready)
|
|
1628
1700
|
return;
|
|
@@ -118,9 +118,28 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
118
118
|
return;
|
|
119
119
|
if (!isAutoActive())
|
|
120
120
|
return;
|
|
121
|
-
if (isSessionSwitchInFlight())
|
|
122
|
-
return;
|
|
123
121
|
const lastMsg = event.messages[event.messages.length - 1];
|
|
122
|
+
if (isSessionSwitchInFlight()) {
|
|
123
|
+
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
|
|
124
|
+
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
125
|
+
if (isUserInitiatedAbortMessage(rawErrorMsg)) {
|
|
126
|
+
resolveAgentEndCancelled({
|
|
127
|
+
message: rawErrorMsg,
|
|
128
|
+
category: "aborted",
|
|
129
|
+
isTransient: false,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
|
|
134
|
+
const content = "content" in lastMsg ? lastMsg.content : undefined;
|
|
135
|
+
const hasEmptyContent = Array.isArray(content) && content.length === 0;
|
|
136
|
+
const hasErrorMessage = "errorMessage" in lastMsg && !!lastMsg.errorMessage;
|
|
137
|
+
if (!hasEmptyContent || hasErrorMessage) {
|
|
138
|
+
resolveAgentEndCancelled(_buildAbortedPauseContext(lastMsg));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
124
143
|
if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
|
|
125
144
|
// Empty content with aborted stopReason is a non-fatal agent stop (the LLM
|
|
126
145
|
// chose to end without producing output). Only pause on genuine fatal aborts
|
|
@@ -3,21 +3,34 @@
|
|
|
3
3
|
// Exposes the Context Mode runtime tools in-process. Default-on; opt out with
|
|
4
4
|
// `context_mode.enabled: false` in preferences.
|
|
5
5
|
import { Type } from "@sinclair/typebox";
|
|
6
|
+
async function loadContextModePreferences(baseDir) {
|
|
7
|
+
const [{ loadEffectiveGSDPreferences }, { logWarning }] = await Promise.all([
|
|
8
|
+
import("../preferences.js"),
|
|
9
|
+
import("../workflow-logger.js"),
|
|
10
|
+
]);
|
|
11
|
+
try {
|
|
12
|
+
return loadEffectiveGSDPreferences(baseDir)?.preferences ?? null;
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
logWarning("tool", `Context Mode tool could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
6
19
|
export function registerExecTools(pi) {
|
|
7
20
|
pi.registerTool({
|
|
8
21
|
name: "gsd_exec",
|
|
9
22
|
label: "Exec (Sandboxed)",
|
|
10
|
-
description: "Run a short script (bash/node/python) in a subprocess.
|
|
23
|
+
description: "Run a short script (bash/node/python) in a subprocess. Capped stdout/stderr and metadata persist to " +
|
|
11
24
|
".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
|
|
12
25
|
"this instead of reading many files or emitting large tool outputs — e.g. have the script " +
|
|
13
26
|
"count/grep/summarize and log the finding. Enabled by default; opt out via " +
|
|
14
27
|
"preferences.context_mode.enabled=false.",
|
|
15
|
-
promptSnippet: "Run a bash/node/python script in a sandbox;
|
|
28
|
+
promptSnippet: "Run a bash/node/python script in a sandbox; capped output is saved to disk and only a digest returns",
|
|
16
29
|
promptGuidelines: [
|
|
17
30
|
"Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
|
|
18
31
|
"Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
|
|
19
32
|
"The digest is the last ~300 chars of stdout — size your log output accordingly.",
|
|
20
|
-
"Need
|
|
33
|
+
"Need persisted output? Read the stdout_path returned in details (file on local disk).",
|
|
21
34
|
],
|
|
22
35
|
parameters: Type.Object({
|
|
23
36
|
runtime: Type.Union([Type.Literal("bash"), Type.Literal("node"), Type.Literal("python")], { description: "Interpreter: bash (-c), node (-e), or python3 (-c)." }),
|
|
@@ -30,21 +43,11 @@ export function registerExecTools(pi) {
|
|
|
30
43
|
})),
|
|
31
44
|
}),
|
|
32
45
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
import("../preferences.js"),
|
|
36
|
-
import("../workflow-logger.js"),
|
|
37
|
-
]);
|
|
38
|
-
let prefs = null;
|
|
39
|
-
try {
|
|
40
|
-
prefs = loadEffectiveGSDPreferences();
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
|
|
44
|
-
}
|
|
46
|
+
const { executeGsdExec } = await import("../tools/exec-tool.js");
|
|
47
|
+
const baseDir = process.cwd();
|
|
45
48
|
return executeGsdExec(params, {
|
|
46
|
-
baseDir
|
|
47
|
-
preferences:
|
|
49
|
+
baseDir,
|
|
50
|
+
preferences: await loadContextModePreferences(baseDir),
|
|
48
51
|
});
|
|
49
52
|
},
|
|
50
53
|
});
|
|
@@ -56,7 +59,7 @@ export function registerExecTools(pi) {
|
|
|
56
59
|
promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
|
|
57
60
|
promptGuidelines: [
|
|
58
61
|
"Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
|
|
59
|
-
"The preview shows the trailing ~300 chars of stdout; read stdout_path for
|
|
62
|
+
"The preview shows the trailing ~300 chars of stdout; read stdout_path for persisted output.",
|
|
60
63
|
],
|
|
61
64
|
parameters: Type.Object({
|
|
62
65
|
query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
|
|
@@ -68,8 +71,10 @@ export function registerExecTools(pi) {
|
|
|
68
71
|
}),
|
|
69
72
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
70
73
|
const { executeExecSearch } = await import("../tools/exec-search-tool.js");
|
|
74
|
+
const baseDir = process.cwd();
|
|
71
75
|
return executeExecSearch(params, {
|
|
72
|
-
baseDir
|
|
76
|
+
baseDir,
|
|
77
|
+
preferences: await loadContextModePreferences(baseDir),
|
|
73
78
|
});
|
|
74
79
|
},
|
|
75
80
|
});
|
|
@@ -87,8 +92,10 @@ export function registerExecTools(pi) {
|
|
|
87
92
|
parameters: Type.Object({}),
|
|
88
93
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
89
94
|
const { executeResume } = await import("../tools/resume-tool.js");
|
|
95
|
+
const baseDir = process.cwd();
|
|
90
96
|
return executeResume(params, {
|
|
91
|
-
baseDir
|
|
97
|
+
baseDir,
|
|
98
|
+
preferences: await loadContextModePreferences(baseDir),
|
|
92
99
|
});
|
|
93
100
|
},
|
|
94
101
|
});
|
|
@@ -52,6 +52,25 @@ async function applyDisabledModelProviderPolicy(ctx) {
|
|
|
52
52
|
// Non-fatal: keep default provider visibility if preferences cannot be loaded.
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Bridge `context_management.compaction_threshold_percent` from GSD preferences
|
|
57
|
+
* into the agent's runtime compaction settings (#5475). The preference is
|
|
58
|
+
* validated to (0.5, 0.95) at load time, but defense-in-depth normalization
|
|
59
|
+
* here protects against a stale or hand-edited prefs file. Calling with
|
|
60
|
+
* `undefined` clears any prior override so a removed preference does not leak.
|
|
61
|
+
*/
|
|
62
|
+
async function applyCompactionThresholdOverride(ctx) {
|
|
63
|
+
try {
|
|
64
|
+
const { loadEffectiveGSDPreferences } = await import("../preferences.js");
|
|
65
|
+
const prefs = loadEffectiveGSDPreferences();
|
|
66
|
+
const raw = prefs?.preferences.context_management?.compaction_threshold_percent;
|
|
67
|
+
const value = typeof raw === "number" && Number.isFinite(raw) && raw > 0 && raw < 1 ? raw : undefined;
|
|
68
|
+
ctx.setCompactionThresholdOverride(value);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Non-fatal: leave any existing override in place.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
55
74
|
export function resolveNotificationStoreBasePath(cwd = process.cwd()) {
|
|
56
75
|
return resolveWorktreeProjectRoot(cwd);
|
|
57
76
|
}
|
|
@@ -101,6 +120,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
101
120
|
await resetAskUserQuestionsTurnCache();
|
|
102
121
|
await syncServiceTierStatus(ctx);
|
|
103
122
|
await applyDisabledModelProviderPolicy(ctx);
|
|
123
|
+
await applyCompactionThresholdOverride(ctx);
|
|
104
124
|
// Skip MCP auto-prep when running inside an auto-worktree (see session_switch below).
|
|
105
125
|
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
106
126
|
if (!isInAutoWorktree(process.cwd())) {
|
|
@@ -149,6 +169,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
149
169
|
clearDiscussionFlowState(process.cwd());
|
|
150
170
|
await syncServiceTierStatus(ctx);
|
|
151
171
|
await applyDisabledModelProviderPolicy(ctx);
|
|
172
|
+
await applyCompactionThresholdOverride(ctx);
|
|
152
173
|
// Skip MCP auto-prep when running inside an auto-worktree. The worktree
|
|
153
174
|
// already has .mcp.json from createAutoWorktree, and re-running the writer
|
|
154
175
|
// post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
|