gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.20138ae42
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 +50 -31
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +10 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
- package/dist/resources/extensions/gsd/auto/loop.js +5 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
- package/dist/resources/extensions/gsd/auto/phases.js +30 -1
- package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +233 -127
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +85 -12
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +158 -55
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +25 -6
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +9 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +38 -1
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +31 -5
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor.js +2 -28
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/git-service.js +39 -1
- package/dist/resources/extensions/gsd/gsd-db.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +93 -111
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
- package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
- package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
- package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
- package/dist/resources/extensions/gsd/status-guards.js +4 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/templates/plan.md +8 -5
- package/dist/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
- package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +89 -14
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -0
- 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 +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +6 -5
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
- package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +5 -6
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
- package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
- package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
- package/packages/pi-ai/src/providers/simple-options.ts +5 -6
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
- package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- 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 +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +10 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
- package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
- package/src/resources/extensions/gsd/auto/loop.ts +8 -5
- package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
- package/src/resources/extensions/gsd/auto/phases.ts +36 -1
- package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +266 -139
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +92 -9
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +119 -1
- package/src/resources/extensions/gsd/auto.ts +167 -53
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +33 -6
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +9 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +41 -1
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +30 -4
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -27
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/git-service.ts +45 -1
- package/src/resources/extensions/gsd/gsd-db.ts +3 -0
- package/src/resources/extensions/gsd/guided-flow.ts +126 -128
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
- package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
- package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/queue.md +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
- package/src/resources/extensions/gsd/status-guards.ts +5 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/templates/plan.md +8 -5
- package/src/resources/extensions/gsd/templates/task-plan.md +4 -2
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +129 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +12 -11
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +43 -2
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
- package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +103 -1
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +225 -1
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
- package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
- package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
- package/src/resources/extensions/gsd/tools/plan-slice.ts +98 -12
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → xRy4LqKSNKdT7y6ATYyEl}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { describe, test } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { mapContentBlock, parseMcpToolName, PartialMessageBuilder } from "../partial-builder.ts";
|
|
4
|
-
import type { BetaContentBlock, BetaRawMessageStreamEvent } from "../sdk-types.ts";
|
|
3
|
+
import { mapContentBlock, mapUsage, parseMcpToolName, PartialMessageBuilder } from "../partial-builder.ts";
|
|
4
|
+
import type { BetaContentBlock, BetaRawMessageStreamEvent, NonNullableUsage } from "../sdk-types.ts";
|
|
5
|
+
|
|
6
|
+
describe("mapUsage", () => {
|
|
7
|
+
test("excludes cumulative cache reads from context-sized totalTokens (#5243)", () => {
|
|
8
|
+
const usage: NonNullableUsage = {
|
|
9
|
+
input_tokens: 150_000,
|
|
10
|
+
output_tokens: 2_000,
|
|
11
|
+
cache_read_input_tokens: 900_000,
|
|
12
|
+
cache_creation_input_tokens: 3_000,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const mapped = mapUsage(usage, 1.23);
|
|
16
|
+
|
|
17
|
+
assert.equal(mapped.cacheRead, 900_000);
|
|
18
|
+
assert.equal(mapped.totalTokens, 155_000);
|
|
19
|
+
assert.equal(mapped.cost.total, 1.23);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
5
22
|
|
|
6
23
|
describe("PartialMessageBuilder — malformed tool arguments (#2574)", () => {
|
|
7
24
|
/**
|
|
@@ -374,6 +374,12 @@ export class CmuxClient {
|
|
|
374
374
|
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, payload]);
|
|
375
375
|
return stdout !== null;
|
|
376
376
|
}
|
|
377
|
+
|
|
378
|
+
// Send Ctrl-C (ETX) to a surface to interrupt the running command.
|
|
379
|
+
async sendInterrupt(surfaceId: string): Promise<boolean> {
|
|
380
|
+
const stdout = await this.runAsync(["send-surface", "--surface", surfaceId, "\x03"]);
|
|
381
|
+
return stdout !== null;
|
|
382
|
+
}
|
|
377
383
|
}
|
|
378
384
|
|
|
379
385
|
export function syncCmuxSidebar(preferences: CmuxPreferences | undefined, state: CmuxState): void {
|
|
@@ -2,27 +2,31 @@
|
|
|
2
2
|
// File Purpose: Auto Orchestration module interfaces and ADR-015 invariant adapter contracts.
|
|
3
3
|
|
|
4
4
|
import type { GSDState } from "../types.js";
|
|
5
|
+
import type { MinimalModelRegistry } from "../context-budget.js";
|
|
5
6
|
|
|
6
7
|
export interface AutoSessionContext {
|
|
7
8
|
basePath: string;
|
|
8
9
|
trigger: "guided-flow" | "resume" | "auto-loop" | "manual";
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
export interface UnitRef {
|
|
13
|
+
unitType: string;
|
|
14
|
+
unitId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export interface AutoStatus {
|
|
12
18
|
phase: "idle" | "running" | "paused" | "stopped" | "error";
|
|
13
|
-
activeUnit?:
|
|
14
|
-
unitType: string;
|
|
15
|
-
unitId: string;
|
|
16
|
-
};
|
|
19
|
+
activeUnit?: UnitRef;
|
|
17
20
|
lastTransitionAt?: number;
|
|
18
21
|
transitionCount: number;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
export
|
|
22
|
-
kind: "advanced"
|
|
23
|
-
reason
|
|
24
|
-
stateSnapshot?: GSDState
|
|
25
|
-
}
|
|
24
|
+
export type AutoAdvanceResult =
|
|
25
|
+
| { kind: "advanced"; unit: UnitRef; stateSnapshot: GSDState }
|
|
26
|
+
| { kind: "blocked"; reason: string; action: "pause" | "stop"; stateSnapshot?: GSDState }
|
|
27
|
+
| { kind: "stopped"; reason: string; stateSnapshot?: GSDState }
|
|
28
|
+
| { kind: "paused"; reason: string }
|
|
29
|
+
| { kind: "error"; reason: string };
|
|
26
30
|
|
|
27
31
|
export interface AutoOrchestrationModule {
|
|
28
32
|
start(sessionContext: AutoSessionContext): Promise<AutoAdvanceResult>;
|
|
@@ -33,12 +37,30 @@ export interface AutoOrchestrationModule {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export interface DispatchAdapter {
|
|
36
|
-
decideNextUnit(input: {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
decideNextUnit(input: {
|
|
41
|
+
stateSnapshot: GSDState;
|
|
42
|
+
/** Mirrors `DispatchContext.structuredQuestionsAvailable` — "true"/"false" string per the dispatch contract. */
|
|
43
|
+
structuredQuestionsAvailable?: "true" | "false";
|
|
44
|
+
/** Session model context window in tokens, forwarded to the budget engine. */
|
|
45
|
+
sessionContextWindow?: number;
|
|
46
|
+
/** Session model provider, used for provider-specific effective context windows. */
|
|
47
|
+
sessionProvider?: string;
|
|
48
|
+
/** Model registry for executor-model lookups inside the budget engine. */
|
|
49
|
+
modelRegistry?: MinimalModelRegistry;
|
|
50
|
+
}): Promise<
|
|
51
|
+
| {
|
|
52
|
+
kind: "blocked";
|
|
53
|
+
reason: string;
|
|
54
|
+
action: "pause" | "stop";
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
unitType: string;
|
|
58
|
+
unitId: string;
|
|
59
|
+
reason: string;
|
|
60
|
+
preconditions: string[];
|
|
61
|
+
}
|
|
62
|
+
| null
|
|
63
|
+
>;
|
|
42
64
|
}
|
|
43
65
|
|
|
44
66
|
export interface RecoveryAdapter {
|
|
@@ -70,11 +92,31 @@ export interface WorktreeAdapter {
|
|
|
70
92
|
cleanupOnStop(reason: string): Promise<void>;
|
|
71
93
|
}
|
|
72
94
|
|
|
95
|
+
export type HealthGateResult =
|
|
96
|
+
| { kind: "pass"; fixesApplied?: readonly string[] }
|
|
97
|
+
| { kind: "fail"; reason: string }
|
|
98
|
+
| { kind: "threw"; error: unknown };
|
|
99
|
+
|
|
73
100
|
export interface HealthAdapter {
|
|
74
|
-
|
|
101
|
+
checkResourcesStale(): string | null;
|
|
102
|
+
preAdvanceGate(): Promise<HealthGateResult>;
|
|
75
103
|
postAdvanceRecord(result: AutoAdvanceResult): Promise<void>;
|
|
76
104
|
}
|
|
77
105
|
|
|
106
|
+
export interface UokGateInput {
|
|
107
|
+
gateId: string;
|
|
108
|
+
gateType: "policy" | "execution";
|
|
109
|
+
outcome: "pass" | "fail" | "manual-attention";
|
|
110
|
+
failureClass: "none" | "policy" | "manual-attention";
|
|
111
|
+
rationale: string;
|
|
112
|
+
findings?: string;
|
|
113
|
+
milestoneId?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface UokGateAdapter {
|
|
117
|
+
emit(input: UokGateInput): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
78
120
|
export interface RuntimePersistenceAdapter {
|
|
79
121
|
ensureLockOwnership(): Promise<void>;
|
|
80
122
|
journalTransition(event: {
|
|
@@ -101,4 +143,5 @@ export interface AutoOrchestratorDeps {
|
|
|
101
143
|
health: HealthAdapter;
|
|
102
144
|
runtime: RuntimePersistenceAdapter;
|
|
103
145
|
notifications: NotificationAdapter;
|
|
146
|
+
uokGate: UokGateAdapter;
|
|
104
147
|
}
|
|
@@ -7,9 +7,14 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Error codes indicating infrastructure failures
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Error codes indicating infrastructure-level failures from the OS,
|
|
11
|
+
* filesystem, or network. This set includes permanent resource failures
|
|
12
|
+
* (ENOSPC, ENOMEM, EROFS), transient resource exhaustion (EAGAIN, ENOBUFS),
|
|
13
|
+
* and network/offline errors (ECONNREFUSED, ENOTFOUND, ENETUNREACH).
|
|
14
|
+
*
|
|
15
|
+
* Transient git failures are retried separately through
|
|
16
|
+
* TRANSIENT_GIT_RETRY_CODES in native-git-bridge.ts before escalating to the
|
|
17
|
+
* auto-loop.
|
|
13
18
|
*/
|
|
14
19
|
export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
|
|
15
20
|
"ENOSPC", // disk full
|
|
@@ -19,6 +24,7 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
|
|
|
19
24
|
"EMFILE", // too many open files (process)
|
|
20
25
|
"ENFILE", // too many open files (system)
|
|
21
26
|
"EAGAIN", // resource temporarily unavailable (resource exhaustion)
|
|
27
|
+
"ENOBUFS", // no buffer space available (transient pipe exhaustion)
|
|
22
28
|
"ECONNREFUSED", // connection refused (offline / local server down)
|
|
23
29
|
"ENOTFOUND", // DNS lookup failed (offline / no network)
|
|
24
30
|
"ENETUNREACH", // network unreachable (offline / no route)
|
|
@@ -78,7 +78,10 @@ import { createWorkflowTurnReporter } from "./workflow-turn-reporter.js";
|
|
|
78
78
|
import { validateWorkflowSessionLock } from "./workflow-session-lock.js";
|
|
79
79
|
import { dequeueSidecarItem } from "./workflow-sidecar-queue.js";
|
|
80
80
|
import { maintainWorkerHeartbeat } from "./workflow-worker-heartbeat.js";
|
|
81
|
-
import {
|
|
81
|
+
import {
|
|
82
|
+
measureMemoryPressure,
|
|
83
|
+
shouldCheckMemoryPressure,
|
|
84
|
+
} from "./workflow-memory-pressure.js";
|
|
82
85
|
import { buildSidecarIterationData } from "./workflow-sidecar-iteration.js";
|
|
83
86
|
import {
|
|
84
87
|
createExecutionGraphUnitDispatchDeps,
|
|
@@ -203,9 +206,9 @@ function logCustomVerifyRetrySaveFailure(err: unknown): void {
|
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
// ── Memory pressure monitoring (#3331) ──────────────────────────────────
|
|
206
|
-
// Check heap usage every N iterations and trigger
|
|
207
|
-
// the OS OOM killer sends SIGKILL. The threshold is
|
|
208
|
-
// limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
209
|
+
// Check heap usage on session startup, then every N iterations, and trigger
|
|
210
|
+
// graceful shutdown before the OS OOM killer sends SIGKILL. The threshold is
|
|
211
|
+
// 90% of the V8 heap limit (--max-old-space-size or default ~1.5-4GB depending on platform).
|
|
209
212
|
const MEMORY_CHECK_INTERVAL = 5; // check every 5 iterations
|
|
210
213
|
const MAX_CUSTOM_ENGINE_VERIFY_RETRIES = 3;
|
|
211
214
|
|
|
@@ -372,7 +375,7 @@ export async function autoLoop(
|
|
|
372
375
|
|
|
373
376
|
// ── Memory pressure check (#3331) ──
|
|
374
377
|
// Graceful shutdown before OOM killer sends SIGKILL.
|
|
375
|
-
if (iteration
|
|
378
|
+
if (shouldCheckMemoryPressure(iteration, MEMORY_CHECK_INTERVAL)) {
|
|
376
379
|
const mem = measureMemoryPressure();
|
|
377
380
|
debugLog("autoLoop", { phase: "memory-check", ...mem });
|
|
378
381
|
const memoryDecision = decideMemoryPressure({ ...mem, iteration });
|
|
@@ -7,6 +7,16 @@ function now(): number {
|
|
|
7
7
|
return Date.now();
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Size of the dispatch-decision ring buffer used by the Auto Orchestration
|
|
12
|
+
* module's stuck-loop detector. When the same `${unitType}:${unitId}` key
|
|
13
|
+
* fills the window, advance() blocks with `action: "stop"`.
|
|
14
|
+
*
|
|
15
|
+
* Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
|
|
16
|
+
* preserved across the eventual cutover (issue #5791).
|
|
17
|
+
*/
|
|
18
|
+
export const STUCK_WINDOW_SIZE = 6;
|
|
19
|
+
|
|
10
20
|
export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
11
21
|
private status: AutoStatus = {
|
|
12
22
|
phase: "idle",
|
|
@@ -14,6 +24,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
14
24
|
};
|
|
15
25
|
private readonly deps: AutoOrchestratorDeps;
|
|
16
26
|
private lastAdvanceKey: string | null = null;
|
|
27
|
+
private dispatchKeyWindow: string[] = [];
|
|
17
28
|
|
|
18
29
|
public constructor(deps: AutoOrchestratorDeps) {
|
|
19
30
|
this.deps = deps;
|
|
@@ -21,6 +32,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
21
32
|
|
|
22
33
|
public async start(_sessionContext: AutoSessionContext): Promise<AutoAdvanceResult> {
|
|
23
34
|
this.lastAdvanceKey = null;
|
|
35
|
+
this.dispatchKeyWindow = [];
|
|
24
36
|
this.status.phase = "running";
|
|
25
37
|
this.bumpTransition();
|
|
26
38
|
await this.deps.runtime.journalTransition({ name: "start" });
|
|
@@ -31,19 +43,72 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
31
43
|
public async advance(): Promise<AutoAdvanceResult> {
|
|
32
44
|
try {
|
|
33
45
|
await this.deps.runtime.ensureLockOwnership();
|
|
46
|
+
|
|
47
|
+
const staleMsg = this.deps.health.checkResourcesStale();
|
|
48
|
+
if (staleMsg) {
|
|
49
|
+
await this.deps.uokGate.emit({
|
|
50
|
+
gateId: "resource-version-guard",
|
|
51
|
+
gateType: "policy",
|
|
52
|
+
outcome: "fail",
|
|
53
|
+
failureClass: "policy",
|
|
54
|
+
rationale: "resource version guard blocked dispatch",
|
|
55
|
+
findings: staleMsg,
|
|
56
|
+
});
|
|
57
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: staleMsg, action: "stop" };
|
|
58
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
59
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
60
|
+
return blocked;
|
|
61
|
+
}
|
|
62
|
+
await this.deps.uokGate.emit({
|
|
63
|
+
gateId: "resource-version-guard",
|
|
64
|
+
gateType: "policy",
|
|
65
|
+
outcome: "pass",
|
|
66
|
+
failureClass: "none",
|
|
67
|
+
rationale: "resource version guard passed",
|
|
68
|
+
});
|
|
69
|
+
|
|
34
70
|
const gate = await this.deps.health.preAdvanceGate();
|
|
35
|
-
if (
|
|
36
|
-
|
|
71
|
+
if (gate.kind === "fail") {
|
|
72
|
+
await this.deps.uokGate.emit({
|
|
73
|
+
gateId: "pre-dispatch-health-gate",
|
|
74
|
+
gateType: "execution",
|
|
75
|
+
outcome: "manual-attention",
|
|
76
|
+
failureClass: "manual-attention",
|
|
77
|
+
rationale: "pre-dispatch health gate blocked dispatch",
|
|
78
|
+
findings: gate.reason,
|
|
79
|
+
});
|
|
80
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason, action: "pause" };
|
|
37
81
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
38
82
|
await this.deps.health.postAdvanceRecord(blocked);
|
|
39
83
|
return blocked;
|
|
40
84
|
}
|
|
85
|
+
if (gate.kind === "threw") {
|
|
86
|
+
await this.deps.uokGate.emit({
|
|
87
|
+
gateId: "pre-dispatch-health-gate",
|
|
88
|
+
gateType: "execution",
|
|
89
|
+
outcome: "manual-attention",
|
|
90
|
+
failureClass: "manual-attention",
|
|
91
|
+
rationale: "pre-dispatch health gate threw unexpectedly",
|
|
92
|
+
findings: String(gate.error),
|
|
93
|
+
});
|
|
94
|
+
// intentional fall-through: matches runPreDispatch behaviour
|
|
95
|
+
} else {
|
|
96
|
+
await this.deps.uokGate.emit({
|
|
97
|
+
gateId: "pre-dispatch-health-gate",
|
|
98
|
+
gateType: "execution",
|
|
99
|
+
outcome: "pass",
|
|
100
|
+
failureClass: "none",
|
|
101
|
+
rationale: "pre-dispatch health gate passed",
|
|
102
|
+
findings: gate.fixesApplied?.join(", ") ?? "",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
41
105
|
|
|
42
106
|
const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
|
|
43
107
|
if (!reconciliation.ok || !reconciliation.stateSnapshot) {
|
|
44
108
|
const blocked: AutoAdvanceResult = {
|
|
45
109
|
kind: "blocked",
|
|
46
|
-
reason: reconciliation.reason,
|
|
110
|
+
reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
|
|
111
|
+
action: "pause",
|
|
47
112
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
48
113
|
};
|
|
49
114
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
@@ -57,15 +122,64 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
57
122
|
this.status.phase = "stopped";
|
|
58
123
|
this.status.activeUnit = undefined;
|
|
59
124
|
this.lastAdvanceKey = null;
|
|
125
|
+
this.dispatchKeyWindow = [];
|
|
60
126
|
this.bumpTransition();
|
|
61
127
|
await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
|
|
62
128
|
await this.deps.health.postAdvanceRecord(stopped);
|
|
63
129
|
return stopped;
|
|
64
130
|
}
|
|
131
|
+
if (!("unitType" in decision)) {
|
|
132
|
+
const blocked: AutoAdvanceResult = {
|
|
133
|
+
kind: "blocked",
|
|
134
|
+
reason: decision.reason,
|
|
135
|
+
action: decision.action,
|
|
136
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
137
|
+
};
|
|
138
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
139
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
140
|
+
return blocked;
|
|
141
|
+
}
|
|
65
142
|
|
|
66
143
|
const nextKey = `${decision.unitType}:${decision.unitId}`;
|
|
67
|
-
|
|
68
|
-
|
|
144
|
+
|
|
145
|
+
// Record every dispatch decision in the ring buffer before pre-flight
|
|
146
|
+
// checks so the stuck-loop detector observes the full decision history
|
|
147
|
+
// (including decisions that idempotency would otherwise short-circuit).
|
|
148
|
+
// The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
|
|
149
|
+
this.dispatchKeyWindow.push(nextKey);
|
|
150
|
+
if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
|
|
151
|
+
this.dispatchKeyWindow.shift();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Idempotency: same key as immediately previous successful advance.
|
|
155
|
+
// This is the soft, fast-path block kept from #5786. It only fires when
|
|
156
|
+
// the ring is NOT yet saturated for this key — once the ring is full of
|
|
157
|
+
// `nextKey`, the stuck-loop verdict takes precedence (see below). Both
|
|
158
|
+
// checks coexist: idempotency for the common immediate-repeat case,
|
|
159
|
+
// stuck-loop for the saturated-window case.
|
|
160
|
+
const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
|
|
161
|
+
if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
|
|
162
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
|
|
163
|
+
await this.deps.runtime.journalTransition({
|
|
164
|
+
name: "advance-blocked",
|
|
165
|
+
reason: blocked.reason,
|
|
166
|
+
unitType: decision.unitType,
|
|
167
|
+
unitId: decision.unitId,
|
|
168
|
+
});
|
|
169
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
170
|
+
return blocked;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Stuck-loop detection: when the ring is saturated with copies of
|
|
174
|
+
// `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
|
|
175
|
+
// picking the same unit across the whole window and must hard-stop with
|
|
176
|
+
// a diagnosable reason.
|
|
177
|
+
if (matchingCount >= STUCK_WINDOW_SIZE) {
|
|
178
|
+
const blocked: AutoAdvanceResult = {
|
|
179
|
+
kind: "blocked",
|
|
180
|
+
reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
|
|
181
|
+
action: "stop",
|
|
182
|
+
};
|
|
69
183
|
await this.deps.runtime.journalTransition({
|
|
70
184
|
name: "advance-blocked",
|
|
71
185
|
reason: blocked.reason,
|
|
@@ -81,6 +195,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
81
195
|
const blocked: AutoAdvanceResult = {
|
|
82
196
|
kind: "blocked",
|
|
83
197
|
reason: contract.reason,
|
|
198
|
+
action: "pause",
|
|
84
199
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
85
200
|
};
|
|
86
201
|
await this.deps.runtime.journalTransition({
|
|
@@ -98,6 +213,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
98
213
|
const blocked: AutoAdvanceResult = {
|
|
99
214
|
kind: "blocked",
|
|
100
215
|
reason: worktree.reason,
|
|
216
|
+
action: "pause",
|
|
101
217
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
102
218
|
};
|
|
103
219
|
await this.deps.runtime.journalTransition({
|
|
@@ -123,7 +239,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
123
239
|
});
|
|
124
240
|
await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
|
|
125
241
|
|
|
126
|
-
const advanced: AutoAdvanceResult = {
|
|
242
|
+
const advanced: AutoAdvanceResult = {
|
|
243
|
+
kind: "advanced",
|
|
244
|
+
unit: { unitType: decision.unitType, unitId: decision.unitId },
|
|
245
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
246
|
+
};
|
|
127
247
|
await this.deps.health.postAdvanceRecord(advanced);
|
|
128
248
|
return advanced;
|
|
129
249
|
} catch (error) {
|
|
@@ -148,6 +268,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
148
268
|
|
|
149
269
|
if (result.kind === "stopped") {
|
|
150
270
|
this.lastAdvanceKey = null;
|
|
271
|
+
this.dispatchKeyWindow = [];
|
|
151
272
|
this.status.activeUnit = undefined;
|
|
152
273
|
}
|
|
153
274
|
this.bumpTransition();
|
|
@@ -173,6 +294,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
173
294
|
|
|
174
295
|
public async resume(): Promise<AutoAdvanceResult> {
|
|
175
296
|
this.lastAdvanceKey = null;
|
|
297
|
+
this.dispatchKeyWindow = [];
|
|
176
298
|
this.status.phase = "running";
|
|
177
299
|
this.bumpTransition();
|
|
178
300
|
await this.deps.runtime.journalTransition({ name: "resume" });
|
|
@@ -188,6 +310,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
188
310
|
this.status.phase = "stopped";
|
|
189
311
|
this.status.activeUnit = undefined;
|
|
190
312
|
this.lastAdvanceKey = null;
|
|
313
|
+
this.dispatchKeyWindow = [];
|
|
191
314
|
this.bumpTransition();
|
|
192
315
|
await this.deps.runtime.journalTransition({ name: "stop", reason });
|
|
193
316
|
await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
|
|
@@ -77,6 +77,7 @@ import { resolveManifest } from "../unit-context-manifest.js";
|
|
|
77
77
|
import { createWorktreeSafetyModule, type WorktreeSafetyResult } from "../worktree-safety.js";
|
|
78
78
|
import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
|
|
79
79
|
import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
|
|
80
|
+
import { buildPhaseHandoffOutcome, setAutoOutcomeWidget } from "../auto-dashboard.js";
|
|
80
81
|
|
|
81
82
|
// ─── Path Comparison Helper ───────────────────────────────────────────────
|
|
82
83
|
/** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
|
|
@@ -1327,9 +1328,15 @@ export async function runDispatch(
|
|
|
1327
1328
|
}
|
|
1328
1329
|
|
|
1329
1330
|
const guardBasePath = _resolveDispatchGuardBasePath(s);
|
|
1331
|
+
let mainBranch = "main";
|
|
1332
|
+
try {
|
|
1333
|
+
mainBranch = deps.getMainBranch(guardBasePath);
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
debugLog("autoLoop", { phase: "getMainBranch-failed", error: String(err) });
|
|
1336
|
+
}
|
|
1330
1337
|
const priorSliceBlocker = deps.getPriorSliceCompletionBlocker(
|
|
1331
1338
|
guardBasePath,
|
|
1332
|
-
|
|
1339
|
+
mainBranch,
|
|
1333
1340
|
unitType,
|
|
1334
1341
|
unitId,
|
|
1335
1342
|
);
|
|
@@ -2233,6 +2240,20 @@ export async function runUnitPhase(
|
|
|
2233
2240
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
2234
2241
|
return { action: "break", reason: "session-timeout" };
|
|
2235
2242
|
}
|
|
2243
|
+
if (
|
|
2244
|
+
unitResult.errorContext?.isTransient &&
|
|
2245
|
+
errorCategory === "aborted"
|
|
2246
|
+
) {
|
|
2247
|
+
ctx.ui.notify(
|
|
2248
|
+
`Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`,
|
|
2249
|
+
"warning",
|
|
2250
|
+
);
|
|
2251
|
+
debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
|
|
2252
|
+
await deps.pauseAuto(ctx, pi);
|
|
2253
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
2254
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
2255
|
+
return { action: "break", reason: "unit-aborted-pause" };
|
|
2256
|
+
}
|
|
2236
2257
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
2237
2258
|
if (s.currentUnit) {
|
|
2238
2259
|
await deps.closeoutUnit(
|
|
@@ -2582,6 +2603,20 @@ export async function runFinalize(
|
|
|
2582
2603
|
lastProgressAt: Date.now(),
|
|
2583
2604
|
lastProgressKind: "finalize-success",
|
|
2584
2605
|
});
|
|
2606
|
+
if (
|
|
2607
|
+
!preUnitSnapshot.type.startsWith("hook/") &&
|
|
2608
|
+
preUnitSnapshot.type !== "custom-step" &&
|
|
2609
|
+
preUnitSnapshot.type !== "complete-milestone"
|
|
2610
|
+
) {
|
|
2611
|
+
setAutoOutcomeWidget(ctx, {
|
|
2612
|
+
...buildPhaseHandoffOutcome({
|
|
2613
|
+
unitType: preUnitSnapshot.type,
|
|
2614
|
+
unitId: preUnitSnapshot.id,
|
|
2615
|
+
agentEndMessages: s.lastUnitAgentEndMessages,
|
|
2616
|
+
}),
|
|
2617
|
+
startedAt: s.autoStartTime,
|
|
2618
|
+
});
|
|
2619
|
+
}
|
|
2585
2620
|
}
|
|
2586
2621
|
s.currentUnit = null;
|
|
2587
2622
|
clearCurrentPhase();
|
|
@@ -19,6 +19,19 @@ export interface MeasureMemoryPressureDeps {
|
|
|
19
19
|
heapLimitBytes: () => number;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Returns true on auto-mode startup, then every configured interval.
|
|
24
|
+
*
|
|
25
|
+
* Iteration 1 is checked explicitly so early session memory pressure cannot
|
|
26
|
+
* bypass the periodic interval guard.
|
|
27
|
+
*/
|
|
28
|
+
export function shouldCheckMemoryPressure(iteration: number, interval: number): boolean {
|
|
29
|
+
if (!Number.isInteger(interval) || interval <= 0) {
|
|
30
|
+
throw new Error("Memory pressure check interval must be a positive integer");
|
|
31
|
+
}
|
|
32
|
+
return iteration === 1 || iteration % interval === 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
function defaultHeapLimitBytes(): number {
|
|
23
36
|
const v8 = require("node:v8") as {
|
|
24
37
|
getHeapStatistics?: () => { heap_size_limit?: number };
|
|
@@ -120,6 +120,26 @@ export interface AutoOutcomeSurfaceSnapshot {
|
|
|
120
120
|
startedAt?: number;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
export function buildPhaseHandoffOutcome(input: {
|
|
124
|
+
unitType: string;
|
|
125
|
+
unitId: string;
|
|
126
|
+
agentEndMessages?: unknown[] | null;
|
|
127
|
+
}): AutoOutcomeSurfaceSnapshot {
|
|
128
|
+
const phase = unitPhaseLabel(input.unitType);
|
|
129
|
+
const detail =
|
|
130
|
+
extractLastAssistantSummary(input.agentEndMessages) ??
|
|
131
|
+
`Completed ${unitVerb(input.unitType)} ${input.unitId}.`;
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
status: "complete",
|
|
135
|
+
title: `${phase} complete`,
|
|
136
|
+
detail,
|
|
137
|
+
unitLabel: `${unitVerb(input.unitType)} ${input.unitId}`,
|
|
138
|
+
nextAction: "Preparing the next phase. Review this handoff while the next session starts.",
|
|
139
|
+
commands: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history"],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
123
143
|
// ─── Unit Description Helpers ─────────────────────────────────────────────────
|
|
124
144
|
|
|
125
145
|
export function unitVerb(unitType: string): string {
|
|
@@ -631,7 +651,6 @@ export function updateProgressWidget(
|
|
|
631
651
|
tierBadge?: string,
|
|
632
652
|
): void {
|
|
633
653
|
if (!ctx.hasUI) return;
|
|
634
|
-
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
635
654
|
|
|
636
655
|
// Welcome header is a startup-only banner — permanently suppress it once
|
|
637
656
|
// auto-mode activates. The dashboard widget owns all status from here.
|
|
@@ -1145,3 +1164,55 @@ function normalizeRollupText(value: string | null | undefined): string | null {
|
|
|
1145
1164
|
if (!clean || clean === "(none)" || clean === "None." || clean === "Not provided.") return null;
|
|
1146
1165
|
return clean;
|
|
1147
1166
|
}
|
|
1167
|
+
|
|
1168
|
+
function isAssistantMessage(value: unknown): boolean {
|
|
1169
|
+
if (!value || typeof value !== "object") return false;
|
|
1170
|
+
const record = value as Record<string, unknown>;
|
|
1171
|
+
if (record.role === "assistant") return true;
|
|
1172
|
+
|
|
1173
|
+
const message = record.message;
|
|
1174
|
+
if (message && typeof message === "object") {
|
|
1175
|
+
return (message as Record<string, unknown>).role === "assistant";
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function extractLastAssistantSummary(messages: unknown[] | null | undefined): string | null {
|
|
1182
|
+
if (!messages || messages.length === 0) return null;
|
|
1183
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1184
|
+
if (!isAssistantMessage(messages[i])) continue;
|
|
1185
|
+
const text = extractMessageText(messages[i]);
|
|
1186
|
+
const clean = normalizeRollupText(text);
|
|
1187
|
+
if (clean) return truncateToWidth(clean, 220, "…");
|
|
1188
|
+
}
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
function extractMessageText(value: unknown): string | null {
|
|
1193
|
+
if (typeof value === "string") return value;
|
|
1194
|
+
if (!value || typeof value !== "object") return null;
|
|
1195
|
+
|
|
1196
|
+
const record = value as Record<string, unknown>;
|
|
1197
|
+
if (typeof record.content === "string") return record.content;
|
|
1198
|
+
|
|
1199
|
+
const message = record.message;
|
|
1200
|
+
if (message && typeof message === "object") {
|
|
1201
|
+
return extractMessageText(message);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const content = record.content;
|
|
1205
|
+
if (Array.isArray(content)) {
|
|
1206
|
+
const parts = content
|
|
1207
|
+
.map((part) => {
|
|
1208
|
+
if (typeof part === "string") return part;
|
|
1209
|
+
if (!part || typeof part !== "object") return "";
|
|
1210
|
+
const partRecord = part as Record<string, unknown>;
|
|
1211
|
+
return typeof partRecord.text === "string" ? partRecord.text : "";
|
|
1212
|
+
})
|
|
1213
|
+
.filter(Boolean);
|
|
1214
|
+
return parts.length > 0 ? parts.join(" ") : null;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|