gsd-pi 2.82.0-dev.2841a1e44 → 2.82.0-dev.3a3c6509d
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 +3 -3
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +7 -0
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
- 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 +11 -0
- package/dist/resources/extensions/gsd/auto/phases.js +81 -31
- 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-direct-dispatch.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -10
- package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
- package/dist/resources/extensions/gsd/auto-start.js +87 -14
- package/dist/resources/extensions/gsd/auto-verification.js +17 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
- package/dist/resources/extensions/gsd/auto.js +37 -5
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -2
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +5 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -2
- package/dist/resources/extensions/gsd/commands/handlers/core.js +17 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
- package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
- package/dist/resources/extensions/gsd/doctor-git-checks.js +46 -1
- 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/forensics.js +3 -3
- package/dist/resources/extensions/gsd/git-service.js +45 -3
- package/dist/resources/extensions/gsd/gsd-db.js +21 -6
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
- package/dist/resources/extensions/gsd/guided-flow.js +101 -116
- package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
- package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
- 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/queue-reorder-ui.js +30 -13
- 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/state.js +1 -1
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- 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/unit-context-manifest.js +7 -8
- package/dist/resources/extensions/gsd/validation.js +23 -1
- package/dist/resources/extensions/gsd/verification-gate.js +68 -7
- package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +33 -8
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +2 -0
- package/dist/resources/extensions/visual-brief/prompts.js +29 -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 +11 -11
- 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/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/browse-directories/route.js +1 -1
- 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 +11 -11
- 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/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/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-6a95bc41e0f7ec89.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools.test.ts +1 -1
- package/packages/native/tsconfig.json +2 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
- package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
- 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/src/providers/google-gemini-cli.test.ts +49 -0
- package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
- 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/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/chat-controller-ordering.test.js +44 -3
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.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/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.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 +19 -8
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +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/chat-controller-ordering.test.ts +53 -3
- package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +14 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +23 -8
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
- package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
- package/packages/pi-tui/dist/terminal.d.ts +2 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +12 -0
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
- package/packages/pi-tui/src/terminal.ts +11 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +7 -0
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +14 -6
- 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 +11 -0
- package/src/resources/extensions/gsd/auto/phases.ts +90 -38
- 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-direct-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
- package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +78 -8
- package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
- package/src/resources/extensions/gsd/auto-start.ts +94 -12
- package/src/resources/extensions/gsd/auto-verification.ts +22 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
- package/src/resources/extensions/gsd/auto.ts +40 -5
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -2
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +17 -2
- package/src/resources/extensions/gsd/commands/handlers/core.ts +17 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
- package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
- package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
- package/src/resources/extensions/gsd/doctor-git-checks.ts +45 -1
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
- package/src/resources/extensions/gsd/doctor-types.ts +1 -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/forensics.ts +3 -3
- package/src/resources/extensions/gsd/git-service.ts +51 -4
- package/src/resources/extensions/gsd/gsd-db.ts +21 -6
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +134 -133
- package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
- package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
- 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/queue-reorder-ui.ts +31 -13
- 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/state.ts +1 -1
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- 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 +56 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +80 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +35 -7
- 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 +91 -6
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
- 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/crash-recovery-via-db.test.ts +86 -2
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -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 +66 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
- 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-runtime.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -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/pipeline-variant-dispatch.test.ts +2 -1
- 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-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/prefs-wizard-coverage.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
- 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-reconciliation-drift.test.ts +119 -23
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
- 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 +82 -7
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -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/write-gate-planning-unit.test.ts +38 -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/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-manifest.ts +12 -9
- package/src/resources/extensions/gsd/validation.ts +23 -1
- package/src/resources/extensions/gsd/verification-gate.ts +78 -6
- package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +41 -8
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +2 -0
- package/src/resources/extensions/visual-brief/prompts.ts +37 -1
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +40 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.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/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qgr2B_MRhPxC0z8fwv4vT → O6femb9LLl3nlgsDaYwS-}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Regression test for #5102: disabling thinking on one reasoning-capable
|
|
2
|
+
// model must not silently persist "off" as the global default.
|
|
3
|
+
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
9
|
+
|
|
10
|
+
import { Agent } from "@gsd/pi-agent-core";
|
|
11
|
+
import { getModel } from "@gsd/pi-ai";
|
|
12
|
+
import { AgentSession } from "./agent-session.js";
|
|
13
|
+
import { AuthStorage } from "./auth-storage.js";
|
|
14
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
15
|
+
import { DefaultResourceLoader } from "./resource-loader.js";
|
|
16
|
+
import { SessionManager } from "./session-manager.js";
|
|
17
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
18
|
+
|
|
19
|
+
let testDir: string;
|
|
20
|
+
|
|
21
|
+
async function createSession(): Promise<{ session: AgentSession; settingsManager: SettingsManager }> {
|
|
22
|
+
const agentDir = join(testDir, "agent-home");
|
|
23
|
+
const authStorage = AuthStorage.inMemory({});
|
|
24
|
+
const modelRegistry = new ModelRegistry(authStorage, join(agentDir, "models.json"));
|
|
25
|
+
const settingsManager = SettingsManager.inMemory({ defaultThinkingLevel: "high" });
|
|
26
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
27
|
+
cwd: testDir,
|
|
28
|
+
agentDir,
|
|
29
|
+
settingsManager,
|
|
30
|
+
noExtensions: true,
|
|
31
|
+
noPromptTemplates: true,
|
|
32
|
+
noThemes: true,
|
|
33
|
+
});
|
|
34
|
+
await resourceLoader.reload();
|
|
35
|
+
|
|
36
|
+
const session = new AgentSession({
|
|
37
|
+
agent: new Agent({
|
|
38
|
+
initialState: {
|
|
39
|
+
model: getModel("zai", "glm-5.1" as any),
|
|
40
|
+
thinkingLevel: "high",
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
sessionManager: SessionManager.inMemory(testDir),
|
|
44
|
+
settingsManager,
|
|
45
|
+
cwd: testDir,
|
|
46
|
+
resourceLoader,
|
|
47
|
+
modelRegistry,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return { session, settingsManager };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("AgentSession thinking level persistence", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
testDir = mkdtempSync(join(tmpdir(), "agent-session-thinking-level-"));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("does not persist off as the global default for reasoning-capable models", async () => {
|
|
63
|
+
const { session, settingsManager } = await createSession();
|
|
64
|
+
|
|
65
|
+
session.setThinkingLevel("off");
|
|
66
|
+
|
|
67
|
+
assert.equal(session.thinkingLevel, "off");
|
|
68
|
+
assert.equal(settingsManager.getDefaultThinkingLevel(), "high");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("still persists non-off thinking levels as the global default", async () => {
|
|
72
|
+
const { session, settingsManager } = await createSession();
|
|
73
|
+
|
|
74
|
+
session.setThinkingLevel("low");
|
|
75
|
+
|
|
76
|
+
assert.equal(session.thinkingLevel, "low");
|
|
77
|
+
assert.equal(settingsManager.getDefaultThinkingLevel(), "low");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -1945,7 +1945,7 @@ export class AgentSession {
|
|
|
1945
1945
|
|
|
1946
1946
|
if (isChanging) {
|
|
1947
1947
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
|
1948
|
-
if (
|
|
1948
|
+
if (effectiveLevel !== "off") {
|
|
1949
1949
|
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
|
1950
1950
|
}
|
|
1951
1951
|
this._emitSessionStateChanged("set_thinking_level");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Regression tests for streamed interactive chat ordering.
|
|
1
3
|
import assert from "node:assert/strict";
|
|
2
4
|
import { test } from "node:test";
|
|
3
5
|
|
|
@@ -97,9 +99,7 @@ function createHost() {
|
|
|
97
99
|
return host;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
// ToolExecutionComponent uses the global theme singleton.
|
|
102
|
-
// Install a minimal no-op theme implementation for this unit test.
|
|
102
|
+
function installTheme() {
|
|
103
103
|
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
104
104
|
fg: (_key: string, text: string) => text,
|
|
105
105
|
bg: (_key: string, text: string) => text,
|
|
@@ -107,6 +107,12 @@ test("chat-controller renders content blocks in content[] index order (tool-firs
|
|
|
107
107
|
italic: (text: string) => text,
|
|
108
108
|
truncate: (text: string) => text,
|
|
109
109
|
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
test("chat-controller renders content blocks in content[] index order (tool-first stream)", async () => {
|
|
113
|
+
// ToolExecutionComponent uses the global theme singleton.
|
|
114
|
+
// Install a minimal no-op theme implementation for this unit test.
|
|
115
|
+
installTheme();
|
|
110
116
|
|
|
111
117
|
const host = createHost();
|
|
112
118
|
const toolId = "mcp-tool-1";
|
|
@@ -168,6 +174,50 @@ test("chat-controller renders content blocks in content[] index order (tool-firs
|
|
|
168
174
|
assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
|
|
169
175
|
});
|
|
170
176
|
|
|
177
|
+
test("chat-controller skips empty GPT reasoning blocks before tool-only turns", async () => {
|
|
178
|
+
installTheme();
|
|
179
|
+
|
|
180
|
+
const host = createHost();
|
|
181
|
+
host.getMarkdownThemeWithSettings = () => ({});
|
|
182
|
+
const toolId = "gpt-tool-1";
|
|
183
|
+
const toolCall = {
|
|
184
|
+
type: "toolCall",
|
|
185
|
+
id: toolId,
|
|
186
|
+
name: "read",
|
|
187
|
+
arguments: { filePath: "todo.js" },
|
|
188
|
+
};
|
|
189
|
+
const content = [
|
|
190
|
+
{ type: "thinking", thinking: "", thinkingSignature: "encrypted" },
|
|
191
|
+
toolCall,
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
|
|
195
|
+
|
|
196
|
+
await handleAgentEvent(
|
|
197
|
+
host,
|
|
198
|
+
{
|
|
199
|
+
type: "message_update",
|
|
200
|
+
message: makeAssistant(content),
|
|
201
|
+
assistantMessageEvent: {
|
|
202
|
+
type: "toolcall_end",
|
|
203
|
+
contentIndex: 1,
|
|
204
|
+
toolCall: {
|
|
205
|
+
...toolCall,
|
|
206
|
+
externalResult: {
|
|
207
|
+
content: [{ type: "text", text: "todo contents" }],
|
|
208
|
+
details: {},
|
|
209
|
+
isError: false,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
partial: makeAssistant(content),
|
|
213
|
+
},
|
|
214
|
+
} as any,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
assert.equal(host.chatContainer.children.length, 1, "empty reasoning should not create a blank assistant block");
|
|
218
|
+
assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
|
|
219
|
+
});
|
|
220
|
+
|
|
171
221
|
test("chat-controller renders serverToolUse before trailing text matching content[] index order", async () => {
|
|
172
222
|
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
173
223
|
fg: (_key: string, text: string) => text,
|
|
@@ -573,7 +573,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
573
573
|
const removed = modelRegistry.authStorage.removeLegacyOAuthCredential(resolvedProvider);
|
|
574
574
|
if (removed) {
|
|
575
575
|
console.warn(
|
|
576
|
-
`[auth] Removed unsupported Anthropic OAuth credential from auth.json
|
|
576
|
+
`[auth] Removed unsupported Anthropic OAuth credential from auth.json.`,
|
|
577
577
|
);
|
|
578
578
|
}
|
|
579
579
|
if (isClaudeCodeBinaryInPath()) {
|
|
@@ -20,6 +20,17 @@ function sanitizeStatusText(text: string): string {
|
|
|
20
20
|
.trim();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function truncateFooterPath(text: string, width: number): string {
|
|
24
|
+
if (visibleWidth(text) <= width) return text;
|
|
25
|
+
const tailMatch = text.match(/( \([^)]+\)(?: • .*)?)$/);
|
|
26
|
+
if (!tailMatch) return truncateToWidth(text, width, "...");
|
|
27
|
+
const tail = tailMatch[1];
|
|
28
|
+
const tailWidth = visibleWidth(tail);
|
|
29
|
+
if (tailWidth >= width - 4) return truncateToWidth(text, width, "...");
|
|
30
|
+
const head = text.slice(0, -tail.length);
|
|
31
|
+
return `${truncateToWidth(head, width - tailWidth, "...")}${tail}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
/**
|
|
24
35
|
* Format token counts (similar to web-ui)
|
|
25
36
|
*/
|
|
@@ -222,10 +233,6 @@ export class FooterComponent implements Component {
|
|
|
222
233
|
}
|
|
223
234
|
}
|
|
224
235
|
|
|
225
|
-
// Apply dim to the stats group before handing it to the shared footer strip.
|
|
226
|
-
// statsLeft may contain color codes for context %, so keep coloring local to the group.
|
|
227
|
-
const dimStatsLeft = theme.fg("dim", statsLeft);
|
|
228
|
-
|
|
229
236
|
// Extension statuses right-aligned on the pwd line (sorted by key).
|
|
230
237
|
// Keeps the footer compact by avoiding a dedicated row when the content
|
|
231
238
|
// fits alongside pwd. Falls back to pwd-only if the combined line would
|
|
@@ -239,12 +246,21 @@ export class FooterComponent implements Component {
|
|
|
239
246
|
.join(" ")
|
|
240
247
|
: "";
|
|
241
248
|
|
|
249
|
+
const footerRight = [rightSide, extStatusText].filter(Boolean).join(" ");
|
|
250
|
+
const gsdSegment = theme.fg("accent", "● GSD");
|
|
251
|
+
const dimStatsLeft = theme.fg("dim", statsLeft);
|
|
252
|
+
const innerWidth = Math.max(1, width - 2);
|
|
253
|
+
const rightWidth = visibleWidth(footerRight);
|
|
254
|
+
const leftBudget = footerRight ? Math.max(1, innerWidth - rightWidth - 3) : innerWidth;
|
|
255
|
+
const sepWidth = visibleWidth(" │ ");
|
|
256
|
+
const pwdBudget = Math.max(1, leftBudget - visibleWidth(gsdSegment) - visibleWidth(dimStatsLeft) - sepWidth * 2);
|
|
257
|
+
const pwdSegment = theme.fg("dim", truncateFooterPath(pwd, pwdBudget));
|
|
258
|
+
|
|
242
259
|
const leftSegments = [
|
|
243
|
-
|
|
244
|
-
|
|
260
|
+
gsdSegment,
|
|
261
|
+
pwdSegment,
|
|
245
262
|
dimStatsLeft,
|
|
246
263
|
];
|
|
247
|
-
const footerRight = [rightSide, extStatusText].filter(Boolean).join(" ");
|
|
248
264
|
return renderFooterStrip(leftSegments, footerRight, width);
|
|
249
265
|
}
|
|
250
266
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// GSD-2
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Interactive TUI chat stream controller.
|
|
2
3
|
import { Loader, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
3
4
|
|
|
4
5
|
import type { InteractiveModeEvent, InteractiveModeStateHost } from "../interactive-mode-state.js";
|
|
@@ -31,18 +32,77 @@ type RenderedSegment =
|
|
|
31
32
|
| { kind: "tool"; contentIndex: number; component: ToolExecutionComponent }
|
|
32
33
|
| { kind: "tool-summary"; component: ToolPhaseSummaryComponent; phases: ToolExecutionPhase[] };
|
|
33
34
|
|
|
35
|
+
type DesiredSegment =
|
|
36
|
+
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
37
|
+
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
38
|
+
|
|
34
39
|
let renderedSegments: RenderedSegment[] = [];
|
|
35
40
|
// When providers reuse one assistant lifecycle across internal sub-turns,
|
|
36
41
|
// a content[] shrink resets renderedSegments. Keep the displaced segments so
|
|
37
42
|
// claude-code MCP pruning can remove stale provisional text later.
|
|
38
43
|
let orphanedSegments: RenderedSegment[] = [];
|
|
39
44
|
|
|
45
|
+
function getVisibleTextLikeBlockType(block: any): "text" | "thinking" | undefined {
|
|
46
|
+
if (block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0) return "text";
|
|
47
|
+
if (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0) return "thinking";
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildDesiredSegments(
|
|
52
|
+
blocks: Array<any>,
|
|
53
|
+
options: { shouldSkipTextBlock?: (block: any, index: number) => boolean } = {},
|
|
54
|
+
): DesiredSegment[] {
|
|
55
|
+
const desired: DesiredSegment[] = [];
|
|
56
|
+
let runStart = -1;
|
|
57
|
+
let runEnd = -1;
|
|
58
|
+
let runType: "text" | "thinking" | undefined;
|
|
59
|
+
const closeRun = () => {
|
|
60
|
+
if (runStart !== -1 && runType) {
|
|
61
|
+
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
62
|
+
runStart = -1;
|
|
63
|
+
runEnd = -1;
|
|
64
|
+
runType = undefined;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
69
|
+
const block = blocks[i];
|
|
70
|
+
const blockType = getVisibleTextLikeBlockType(block);
|
|
71
|
+
const isInvisibleTextLike = blockType === undefined && (block?.type === "text" || block?.type === "thinking");
|
|
72
|
+
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
73
|
+
|
|
74
|
+
if (blockType) {
|
|
75
|
+
if (options.shouldSkipTextBlock?.(block, i)) {
|
|
76
|
+
closeRun();
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (runStart === -1) {
|
|
80
|
+
runStart = i;
|
|
81
|
+
runEnd = i;
|
|
82
|
+
runType = blockType;
|
|
83
|
+
} else if (runType !== blockType) {
|
|
84
|
+
closeRun();
|
|
85
|
+
runStart = i;
|
|
86
|
+
runEnd = i;
|
|
87
|
+
runType = blockType;
|
|
88
|
+
} else {
|
|
89
|
+
runEnd = i;
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (isInvisibleTextLike) continue;
|
|
93
|
+
closeRun();
|
|
94
|
+
if (isTool) {
|
|
95
|
+
desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
closeRun();
|
|
100
|
+
|
|
101
|
+
return desired;
|
|
102
|
+
}
|
|
103
|
+
|
|
40
104
|
function hasVisibleAssistantContent(message: { content: Array<any> }): boolean {
|
|
41
|
-
return message.content.some(
|
|
42
|
-
(c) =>
|
|
43
|
-
(c.type === "text" && typeof c.text === "string" && c.text.trim().length > 0)
|
|
44
|
-
|| (c.type === "thinking" && typeof c.thinking === "string" && c.thinking.trim().length > 0),
|
|
45
|
-
);
|
|
105
|
+
return message.content.some((c) => getVisibleTextLikeBlockType(c) !== undefined);
|
|
46
106
|
}
|
|
47
107
|
|
|
48
108
|
function hasAssistantToolBlocks(message: { content: Array<any> }): boolean {
|
|
@@ -470,59 +530,14 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
470
530
|
// Only prune provisional pre-tool prose after post-tool prose exists,
|
|
471
531
|
// so MCP tool-only windows do not blank the assistant content.
|
|
472
532
|
const shouldDropPreToolProse = isClaudeCodeProvider && hasMcpToolBlock && hasPostToolText;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (runStart !== -1 && runType) {
|
|
482
|
-
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
483
|
-
runStart = -1;
|
|
484
|
-
runEnd = -1;
|
|
485
|
-
runType = undefined;
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
489
|
-
const b = blocks[i];
|
|
490
|
-
const blockType = b.type === "text" || b.type === "thinking" ? b.type : undefined;
|
|
491
|
-
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
492
|
-
const isTool = b.type === "toolCall" || b.type === "serverToolUse";
|
|
493
|
-
// For Claude Code MCP turns, prune only pre-tool prose, never thinking.
|
|
494
|
-
const textValue = blockType === "text" && typeof b?.text === "string" ? b.text : "";
|
|
495
|
-
const isLikelyQuestion = blockType === "text" && typeof textValue === "string" && /\?\s*$/.test(textValue.trim());
|
|
496
|
-
const shouldSkipProse = shouldDropPreToolProse
|
|
497
|
-
&& firstToolIdx >= 0
|
|
498
|
-
&& i < firstToolIdx
|
|
499
|
-
&& blockType === "text"
|
|
500
|
-
&& !isLikelyQuestion;
|
|
501
|
-
if (shouldSkipProse) {
|
|
502
|
-
closeRun();
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
if (isTextLike) {
|
|
506
|
-
if (runStart === -1) {
|
|
507
|
-
runStart = i;
|
|
508
|
-
runEnd = i;
|
|
509
|
-
runType = blockType;
|
|
510
|
-
} else if (runType !== blockType) {
|
|
511
|
-
closeRun();
|
|
512
|
-
runStart = i;
|
|
513
|
-
runEnd = i;
|
|
514
|
-
runType = blockType;
|
|
515
|
-
} else {
|
|
516
|
-
runEnd = i;
|
|
517
|
-
}
|
|
518
|
-
} else {
|
|
519
|
-
closeRun();
|
|
520
|
-
if (isTool) {
|
|
521
|
-
desired.push({ kind: "tool", contentIndex: i, toolId: b.id });
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
closeRun();
|
|
533
|
+
const desired = buildDesiredSegments(blocks, {
|
|
534
|
+
shouldSkipTextBlock: (block: any, index: number) => {
|
|
535
|
+
if (!shouldDropPreToolProse || firstToolIdx < 0 || index >= firstToolIdx) return false;
|
|
536
|
+
if (getVisibleTextLikeBlockType(block) !== "text") return false;
|
|
537
|
+
const textValue = typeof block?.text === "string" ? block.text : "";
|
|
538
|
+
return !/\?\s*$/.test(textValue.trim());
|
|
539
|
+
},
|
|
540
|
+
});
|
|
526
541
|
|
|
527
542
|
// Claude Code MCP can emit provisional pre-tool prose that gets
|
|
528
543
|
// superseded by post-tool output. Prune stale text-run segments so
|
|
@@ -742,49 +757,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
742
757
|
// ranges/components don't keep stale partial indices.
|
|
743
758
|
if (renderedSegments.length > 0) {
|
|
744
759
|
const finalBlocks = host.streamingMessage.content;
|
|
745
|
-
|
|
746
|
-
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
747
|
-
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
748
|
-
const desired: DesiredSegment[] = [];
|
|
749
|
-
let runStart = -1;
|
|
750
|
-
let runEnd = -1;
|
|
751
|
-
let runType: "text" | "thinking" | undefined;
|
|
752
|
-
const closeRun = () => {
|
|
753
|
-
if (runStart !== -1 && runType) {
|
|
754
|
-
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
755
|
-
runStart = -1;
|
|
756
|
-
runEnd = -1;
|
|
757
|
-
runType = undefined;
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
for (let i = 0; i < finalBlocks.length; i++) {
|
|
762
|
-
const block = finalBlocks[i] as any;
|
|
763
|
-
const blockType = block?.type === "text" || block?.type === "thinking" ? block.type : undefined;
|
|
764
|
-
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
765
|
-
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
766
|
-
|
|
767
|
-
if (isTextLike) {
|
|
768
|
-
if (runStart === -1) {
|
|
769
|
-
runStart = i;
|
|
770
|
-
runEnd = i;
|
|
771
|
-
runType = blockType;
|
|
772
|
-
} else if (runType !== blockType) {
|
|
773
|
-
closeRun();
|
|
774
|
-
runStart = i;
|
|
775
|
-
runEnd = i;
|
|
776
|
-
runType = blockType;
|
|
777
|
-
} else {
|
|
778
|
-
runEnd = i;
|
|
779
|
-
}
|
|
780
|
-
} else {
|
|
781
|
-
closeRun();
|
|
782
|
-
if (isTool) {
|
|
783
|
-
desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
closeRun();
|
|
760
|
+
const desired = buildDesiredSegments(finalBlocks);
|
|
788
761
|
|
|
789
762
|
const toolComponentsById = new Map<string, ToolExecutionComponent>();
|
|
790
763
|
for (const [toolId, component] of host.pendingTools.entries()) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Regression tests for interactive assistant replay ordering.
|
|
1
3
|
import assert from "node:assert/strict";
|
|
2
4
|
import { test } from "node:test";
|
|
3
5
|
|
|
@@ -42,3 +44,15 @@ test("buildAssistantReplaySegments ignores non-rendered non-tool blocks", () =>
|
|
|
42
44
|
{ kind: "assistant", startIndex: 2, endIndex: 2 },
|
|
43
45
|
]);
|
|
44
46
|
});
|
|
47
|
+
|
|
48
|
+
test("buildAssistantReplaySegments skips empty GPT reasoning blocks before tools", () => {
|
|
49
|
+
const segments = buildAssistantReplaySegments([
|
|
50
|
+
{ type: "thinking", thinking: "", thinkingSignature: "encrypted" },
|
|
51
|
+
{ type: "text", text: " " },
|
|
52
|
+
{ type: "toolCall", id: "t1", name: "read", arguments: { filePath: "todo.js" } },
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
assert.deepEqual(segments, [
|
|
56
|
+
{ kind: "tool", contentIndex: 2 },
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
@@ -134,6 +134,13 @@ export type AssistantReplaySegment =
|
|
|
134
134
|
| { kind: "assistant"; startIndex: number; endIndex: number }
|
|
135
135
|
| { kind: "tool"; contentIndex: number };
|
|
136
136
|
|
|
137
|
+
function isVisibleAssistantReplayText(block: any): boolean {
|
|
138
|
+
return (
|
|
139
|
+
(block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0)
|
|
140
|
+
|| (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
137
144
|
/**
|
|
138
145
|
* Build replay segments for historical assistant messages so rebuild paths
|
|
139
146
|
* preserve the original content[] ordering between assistant prose and tools.
|
|
@@ -141,30 +148,38 @@ export type AssistantReplaySegment =
|
|
|
141
148
|
export function buildAssistantReplaySegments(contentBlocks: Array<any>): AssistantReplaySegment[] {
|
|
142
149
|
const segments: AssistantReplaySegment[] = [];
|
|
143
150
|
let runStart = -1;
|
|
151
|
+
let runEnd = -1;
|
|
152
|
+
|
|
153
|
+
const closeRun = () => {
|
|
154
|
+
if (runStart !== -1) {
|
|
155
|
+
segments.push({ kind: "assistant", startIndex: runStart, endIndex: runEnd });
|
|
156
|
+
runStart = -1;
|
|
157
|
+
runEnd = -1;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
144
160
|
|
|
145
161
|
for (let i = 0; i < contentBlocks.length; i++) {
|
|
146
162
|
const block = contentBlocks[i];
|
|
147
|
-
const isAssistantText = block
|
|
163
|
+
const isAssistantText = isVisibleAssistantReplayText(block);
|
|
164
|
+
const isInvisibleAssistantText = block?.type === "text" || block?.type === "thinking";
|
|
148
165
|
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
149
166
|
|
|
150
167
|
if (isAssistantText) {
|
|
151
168
|
if (runStart === -1) runStart = i;
|
|
169
|
+
runEnd = i;
|
|
152
170
|
continue;
|
|
153
171
|
}
|
|
154
172
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
173
|
+
if (isInvisibleAssistantText) continue;
|
|
174
|
+
|
|
175
|
+
closeRun();
|
|
159
176
|
|
|
160
177
|
if (isTool) {
|
|
161
178
|
segments.push({ kind: "tool", contentIndex: i });
|
|
162
179
|
}
|
|
163
180
|
}
|
|
164
181
|
|
|
165
|
-
|
|
166
|
-
segments.push({ kind: "assistant", startIndex: runStart, endIndex: contentBlocks.length - 1 });
|
|
167
|
-
}
|
|
182
|
+
closeRun();
|
|
168
183
|
|
|
169
184
|
return segments;
|
|
170
185
|
}
|