gsd-pi 2.73.1-dev.d987996 → 2.74.0-dev.0306a2e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +184 -206
- package/dist/headless-query.js +4 -1
- package/dist/help-text.js +23 -0
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
- package/dist/resources/extensions/gsd/activity-log.js +16 -0
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
- package/dist/resources/extensions/gsd/auto/loop.js +147 -10
- package/dist/resources/extensions/gsd/auto/phases.js +173 -13
- package/dist/resources/extensions/gsd/auto/session.js +10 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +22 -4
- package/dist/resources/extensions/gsd/auto-model-selection.js +105 -16
- package/dist/resources/extensions/gsd/auto-post-unit.js +254 -15
- package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
- package/dist/resources/extensions/gsd/auto-start.js +23 -6
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
- package/dist/resources/extensions/gsd/auto-verification.js +186 -3
- package/dist/resources/extensions/gsd/auto.js +65 -12
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +30 -8
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
- package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
- package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
- package/dist/resources/extensions/gsd/commands-do.js +79 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
- package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
- package/dist/resources/extensions/gsd/commands-ship.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +3 -5
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +15 -2
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +144 -0
- package/dist/resources/extensions/gsd/ecosystem/loader.js +145 -0
- package/dist/resources/extensions/gsd/git-service.js +49 -1
- package/dist/resources/extensions/gsd/graph-context.js +157 -0
- package/dist/resources/extensions/gsd/gsd-db.js +581 -2
- package/dist/resources/extensions/gsd/guided-flow.js +23 -0
- package/dist/resources/extensions/gsd/index.js +15 -2
- package/dist/resources/extensions/gsd/init-wizard.js +1 -0
- package/dist/resources/extensions/gsd/journal.js +27 -0
- package/dist/resources/extensions/gsd/md-importer.js +3 -4
- package/dist/resources/extensions/gsd/memory-store.js +19 -51
- package/dist/resources/extensions/gsd/metrics.js +19 -0
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
- package/dist/resources/extensions/gsd/preferences-models.js +63 -3
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +130 -2
- package/dist/resources/extensions/gsd/preferences.js +26 -0
- package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
- package/dist/resources/extensions/gsd/state.js +66 -15
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
- package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
- package/dist/resources/extensions/gsd/uok/audit.js +40 -0
- package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
- package/dist/resources/extensions/gsd/uok/flags.js +29 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
- package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
- package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
- package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
- package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
- package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -0
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +13 -5
- package/dist/update-cmd.js +4 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/index.d.ts +3 -0
- package/packages/mcp-server/dist/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/index.js +3 -0
- package/packages/mcp-server/dist/index.js.map +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
- package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/graph.js +655 -0
- package/packages/mcp-server/dist/readers/graph.js.map +1 -0
- package/packages/mcp-server/dist/readers/index.d.ts +2 -0
- package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/readers/index.js +1 -0
- package/packages/mcp-server/dist/readers/index.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +65 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +15 -0
- package/packages/mcp-server/src/readers/graph.test.ts +604 -0
- package/packages/mcp-server/src/readers/graph.ts +855 -0
- package/packages/mcp-server/src/readers/index.ts +12 -0
- package/packages/mcp-server/src/server.ts +83 -0
- package/packages/mcp-server/tsconfig.json +1 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
- package/packages/native/package.json +2 -2
- package/packages/native/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.json +1 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-ai/dist/index.d.ts +2 -9
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -9
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts +19 -0
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/capability-patches.js +36 -0
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -0
- package/packages/pi-ai/dist/{models.custom.d.ts → models/custom.d.ts} +1 -1
- package/packages/pi-ai/dist/models/custom.d.ts.map +1 -0
- package/packages/pi-ai/dist/{models.custom.js → models/custom.js} +4 -4
- package/packages/pi-ai/dist/models/custom.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts +1482 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js +1484 -0
- package/packages/pi-ai/dist/models/generated/amazon-bedrock.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts +377 -0
- package/packages/pi-ai/dist/models/generated/anthropic.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js +379 -0
- package/packages/pi-ai/dist/models/generated/anthropic.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js +702 -0
- package/packages/pi-ai/dist/models/generated/azure-openai-responses.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts +71 -0
- package/packages/pi-ai/dist/models/generated/cerebras.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js +73 -0
- package/packages/pi-ai/dist/models/generated/cerebras.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts +590 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js +444 -0
- package/packages/pi-ai/dist/models/generated/github-copilot.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts +156 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js +158 -0
- package/packages/pi-ai/dist/models/generated/google-antigravity.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js +107 -0
- package/packages/pi-ai/dist/models/generated/google-gemini-cli.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts +207 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js +209 -0
- package/packages/pi-ai/dist/models/generated/google-vertex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts +462 -0
- package/packages/pi-ai/dist/models/generated/google.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/google.js +464 -0
- package/packages/pi-ai/dist/models/generated/google.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts +309 -0
- package/packages/pi-ai/dist/models/generated/groq.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/groq.js +311 -0
- package/packages/pi-ai/dist/models/generated/groq.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts +383 -0
- package/packages/pi-ai/dist/models/generated/huggingface.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js +347 -0
- package/packages/pi-ai/dist/models/generated/huggingface.js.map +1 -0
- package/packages/pi-ai/dist/{models.generated.d.ts → models/generated/index.d.ts} +1 -1
- package/packages/pi-ai/dist/{models.generated.d.ts.map → models/generated/index.d.ts.map} +1 -1
- package/packages/pi-ai/dist/models/generated/index.js +51 -0
- package/packages/pi-ai/dist/models/generated/index.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts +37 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js +39 -0
- package/packages/pi-ai/dist/models/generated/kimi-coding.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax-cn.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts +105 -0
- package/packages/pi-ai/dist/models/generated/minimax.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/minimax.js +107 -0
- package/packages/pi-ai/dist/models/generated/minimax.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts +445 -0
- package/packages/pi-ai/dist/models/generated/mistral.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/mistral.js +447 -0
- package/packages/pi-ai/dist/models/generated/mistral.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +139 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js +141 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts +700 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openai.js +702 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts +122 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js +124 -0
- package/packages/pi-ai/dist/models/generated/opencode-go.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts +530 -0
- package/packages/pi-ai/dist/models/generated/opencode.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/opencode.js +532 -0
- package/packages/pi-ai/dist/models/generated/opencode.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts +4270 -0
- package/packages/pi-ai/dist/models/generated/openrouter.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js +4272 -0
- package/packages/pi-ai/dist/models/generated/openrouter.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts +2604 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js +2606 -0
- package/packages/pi-ai/dist/models/generated/vercel-ai-gateway.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts +411 -0
- package/packages/pi-ai/dist/models/generated/xai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/xai.js +413 -0
- package/packages/pi-ai/dist/models/generated/xai.js.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts +276 -0
- package/packages/pi-ai/dist/models/generated/zai.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/generated/zai.js +239 -0
- package/packages/pi-ai/dist/models/generated/zai.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts +27 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/index.js +80 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -0
- package/packages/pi-ai/dist/models.d.ts +1 -36
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +1 -2
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.js +3 -112
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +6 -5
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +12 -0
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +74 -40
- package/packages/pi-ai/src/index.ts +5 -9
- package/packages/pi-ai/src/models/capability-patches.ts +40 -0
- package/packages/pi-ai/src/{models.custom.ts → models/custom.ts} +4 -4
- package/packages/pi-ai/src/models/generated/amazon-bedrock.ts +1486 -0
- package/packages/pi-ai/src/models/generated/anthropic.ts +381 -0
- package/packages/pi-ai/src/models/generated/azure-openai-responses.ts +704 -0
- package/packages/pi-ai/src/models/generated/cerebras.ts +75 -0
- package/packages/pi-ai/src/models/generated/github-copilot.ts +446 -0
- package/packages/pi-ai/src/models/generated/google-antigravity.ts +160 -0
- package/packages/pi-ai/src/models/generated/google-gemini-cli.ts +109 -0
- package/packages/pi-ai/src/models/generated/google-vertex.ts +211 -0
- package/packages/pi-ai/src/models/generated/google.ts +466 -0
- package/packages/pi-ai/src/models/generated/groq.ts +313 -0
- package/packages/pi-ai/src/models/generated/huggingface.ts +349 -0
- package/packages/pi-ai/src/models/generated/index.ts +52 -0
- package/packages/pi-ai/src/models/generated/kimi-coding.ts +41 -0
- package/packages/pi-ai/src/models/generated/minimax-cn.ts +109 -0
- package/packages/pi-ai/src/models/generated/minimax.ts +109 -0
- package/packages/pi-ai/src/models/generated/mistral.ts +449 -0
- package/packages/pi-ai/src/models/generated/openai-codex.ts +143 -0
- package/packages/pi-ai/src/models/generated/openai.ts +704 -0
- package/packages/pi-ai/src/models/generated/opencode-go.ts +126 -0
- package/packages/pi-ai/src/models/generated/opencode.ts +534 -0
- package/packages/pi-ai/src/models/generated/openrouter.ts +4274 -0
- package/packages/pi-ai/src/models/generated/vercel-ai-gateway.ts +2608 -0
- package/packages/pi-ai/src/models/generated/xai.ts +415 -0
- package/packages/pi-ai/src/models/generated/zai.ts +241 -0
- package/packages/pi-ai/src/models/index.ts +106 -0
- package/packages/pi-ai/src/models.generated.test.ts +1 -2
- package/packages/pi-ai/src/models.test.ts +6 -5
- package/packages/pi-ai/src/models.ts +3 -153
- package/packages/pi-ai/src/utils/overflow.ts +14 -1
- package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
- package/packages/pi-ai/tsconfig.json +1 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +721 -8
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +65 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- 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 +305 -20
- 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.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +38 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +13 -0
- 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 +59 -6
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +884 -8
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +78 -32
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +381 -39
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +44 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +79 -6
- package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
- package/packages/pi-coding-agent/tsconfig.json +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +32 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/packages/pi-tui/tsconfig.json +1 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.json +1 -0
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
- package/src/resources/extensions/gsd/activity-log.ts +21 -0
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
- package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
- package/src/resources/extensions/gsd/auto/loop.ts +159 -10
- package/src/resources/extensions/gsd/auto/phases.ts +213 -13
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +26 -10
- package/src/resources/extensions/gsd/auto-model-selection.ts +151 -16
- package/src/resources/extensions/gsd/auto-post-unit.ts +278 -16
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
- package/src/resources/extensions/gsd/auto-start.ts +30 -6
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
- package/src/resources/extensions/gsd/auto-verification.ts +225 -3
- package/src/resources/extensions/gsd/auto.ts +72 -16
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +38 -8
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +52 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
- package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
- package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
- package/src/resources/extensions/gsd/commands-do.ts +109 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
- package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
- package/src/resources/extensions/gsd/commands-ship.ts +219 -0
- package/src/resources/extensions/gsd/db-writer.ts +3 -5
- package/src/resources/extensions/gsd/docs/preferences-reference.md +15 -2
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +228 -0
- package/src/resources/extensions/gsd/ecosystem/loader.ts +201 -0
- package/src/resources/extensions/gsd/git-service.ts +68 -0
- package/src/resources/extensions/gsd/graph-context.ts +212 -0
- package/src/resources/extensions/gsd/gsd-db.ts +788 -3
- package/src/resources/extensions/gsd/guided-flow.ts +32 -0
- package/src/resources/extensions/gsd/index.ts +18 -2
- package/src/resources/extensions/gsd/init-wizard.ts +3 -2
- package/src/resources/extensions/gsd/journal.ts +30 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -5
- package/src/resources/extensions/gsd/memory-store.ts +31 -62
- package/src/resources/extensions/gsd/metrics.ts +26 -0
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
- package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
- package/src/resources/extensions/gsd/preferences-models.ts +61 -3
- package/src/resources/extensions/gsd/preferences-types.ts +44 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +130 -2
- package/src/resources/extensions/gsd/preferences.ts +28 -0
- package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/src/resources/extensions/gsd/session-lock.ts +14 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
- package/src/resources/extensions/gsd/state.ts +80 -17
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +9 -5
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
- package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +9 -6
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
- package/src/resources/extensions/gsd/types.ts +14 -1
- package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
- package/src/resources/extensions/gsd/uok/audit.ts +51 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
- package/src/resources/extensions/gsd/uok/flags.ts +45 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
- package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
- package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
- package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +27 -1
- package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
- package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
- package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
- package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
- package/packages/pi-ai/dist/models.custom.d.ts.map +0 -1
- package/packages/pi-ai/dist/models.custom.js.map +0 -1
- package/packages/pi-ai/dist/models.generated.js +0 -14343
- package/packages/pi-ai/dist/models.generated.js.map +0 -1
- package/packages/pi-ai/src/models.generated.ts +0 -14345
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → tqdo0yKKYz6fJXQnIgbdx}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → tqdo0yKKYz6fJXQnIgbdx}/_ssgManifest.js +0 -0
|
@@ -10,6 +10,27 @@ import { appKey } from "../components/keybinding-hints.js";
|
|
|
10
10
|
// Tracks the last processed content index to avoid re-scanning all blocks on every message_update
|
|
11
11
|
let lastProcessedContentIndex = 0;
|
|
12
12
|
|
|
13
|
+
// Tracks the previous content[] length so we can detect when an adapter resets
|
|
14
|
+
// the assistant content array for a new provider sub-turn within one lifecycle.
|
|
15
|
+
let lastContentLength = 0;
|
|
16
|
+
|
|
17
|
+
// --- Segment walker state (per streaming assistant turn) ---
|
|
18
|
+
type RenderedSegment =
|
|
19
|
+
| {
|
|
20
|
+
kind: "text-run";
|
|
21
|
+
startIndex: number;
|
|
22
|
+
endIndex: number;
|
|
23
|
+
contentType: "text" | "thinking";
|
|
24
|
+
component: AssistantMessageComponent;
|
|
25
|
+
}
|
|
26
|
+
| { kind: "tool"; contentIndex: number; component: ToolExecutionComponent };
|
|
27
|
+
|
|
28
|
+
let renderedSegments: RenderedSegment[] = [];
|
|
29
|
+
// When providers reuse one assistant lifecycle across internal sub-turns,
|
|
30
|
+
// a content[] shrink resets renderedSegments. Keep the displaced segments so
|
|
31
|
+
// claude-code MCP pruning can remove stale provisional text later.
|
|
32
|
+
let orphanedSegments: RenderedSegment[] = [];
|
|
33
|
+
|
|
13
34
|
function hasVisibleAssistantContent(message: { content: Array<any> }): boolean {
|
|
14
35
|
return message.content.some(
|
|
15
36
|
(c) =>
|
|
@@ -78,8 +99,11 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
78
99
|
// Reset content index tracker and pinned state when a new assistant message starts
|
|
79
100
|
if (event.type === "message_start" && event.message.role === "assistant") {
|
|
80
101
|
lastProcessedContentIndex = 0;
|
|
102
|
+
lastContentLength = 0;
|
|
81
103
|
lastPinnedText = "";
|
|
82
104
|
hasToolsInTurn = false;
|
|
105
|
+
renderedSegments = [];
|
|
106
|
+
orphanedSegments = [];
|
|
83
107
|
if (pinnedBorder) pinnedBorder.stopSpinner();
|
|
84
108
|
pinnedBorder = undefined;
|
|
85
109
|
pinnedTextComponent = undefined;
|
|
@@ -99,6 +123,9 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
99
123
|
host.pinnedMessageContainer.clear();
|
|
100
124
|
lastPinnedText = "";
|
|
101
125
|
hasToolsInTurn = false;
|
|
126
|
+
renderedSegments = [];
|
|
127
|
+
orphanedSegments = [];
|
|
128
|
+
lastContentLength = 0;
|
|
102
129
|
if (pinnedBorder) pinnedBorder.stopSpinner();
|
|
103
130
|
pinnedBorder = undefined;
|
|
104
131
|
pinnedTextComponent = undefined;
|
|
@@ -202,12 +229,26 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
202
229
|
}
|
|
203
230
|
|
|
204
231
|
const contentBlocks = host.streamingMessage.content;
|
|
205
|
-
// Some adapters reuse a single assistant
|
|
206
|
-
// spanning multiple provider turns.
|
|
207
|
-
//
|
|
208
|
-
|
|
232
|
+
// Some adapters (notably claude-code) reuse a single assistant
|
|
233
|
+
// lifecycle while internally spanning multiple provider sub-turns.
|
|
234
|
+
// When a new sub-turn starts, content[] length shrinks back to 0/1.
|
|
235
|
+
// The scan loop needs its index reset, AND the segment walker's
|
|
236
|
+
// renderedSegments map must be cleared so existing text-run
|
|
237
|
+
// components don't get overwritten in place with new sub-turn
|
|
238
|
+
// content (#4144 regression). Prior sub-turn children stay in
|
|
239
|
+
// chatContainer as frozen history; new segments append after them.
|
|
240
|
+
if (contentBlocks.length < lastContentLength) {
|
|
241
|
+
// Accumulate across successive shrinks — overwriting would drop
|
|
242
|
+
// segments displaced by an earlier shrink, leaving them stranded
|
|
243
|
+
// in chatContainer once the prune pass finally runs.
|
|
244
|
+
orphanedSegments = [...orphanedSegments, ...renderedSegments];
|
|
245
|
+
renderedSegments = [];
|
|
246
|
+
lastPinnedText = "";
|
|
247
|
+
lastProcessedContentIndex = 0;
|
|
248
|
+
} else if (lastProcessedContentIndex >= contentBlocks.length) {
|
|
209
249
|
lastProcessedContentIndex = 0;
|
|
210
250
|
}
|
|
251
|
+
lastContentLength = contentBlocks.length;
|
|
211
252
|
for (let i = lastProcessedContentIndex; i < contentBlocks.length; i++) {
|
|
212
253
|
const content = contentBlocks[i];
|
|
213
254
|
if (content.type === "toolCall") {
|
|
@@ -273,24 +314,191 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
273
314
|
}
|
|
274
315
|
}
|
|
275
316
|
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
host.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
317
|
+
// Segment walker: render content blocks in stream order, append-only.
|
|
318
|
+
// Build desired segment plan from content[].
|
|
319
|
+
{
|
|
320
|
+
const blocks = host.streamingMessage.content;
|
|
321
|
+
const isClaudeCodeProvider = host.streamingMessage.provider === "claude-code";
|
|
322
|
+
const hasMcpToolBlock = blocks.some((b: any) => {
|
|
323
|
+
if (b?.type === "toolCall") {
|
|
324
|
+
return typeof b?.mcpServer === "string" || String(b?.name ?? "").startsWith("mcp__");
|
|
325
|
+
}
|
|
326
|
+
if (b?.type === "serverToolUse") {
|
|
327
|
+
return typeof b?.mcpServer === "string" || String(b?.name ?? "").startsWith("mcp__");
|
|
328
|
+
}
|
|
329
|
+
return false;
|
|
330
|
+
});
|
|
331
|
+
const firstToolIdx = blocks.findIndex((b: any) => b.type === "toolCall" || b.type === "serverToolUse");
|
|
332
|
+
const hasPostToolText = firstToolIdx >= 0
|
|
333
|
+
&& blocks.some(
|
|
334
|
+
(b: any, idx: number) => (
|
|
335
|
+
idx > firstToolIdx
|
|
336
|
+
&& b?.type === "text"
|
|
337
|
+
&& typeof b?.text === "string"
|
|
338
|
+
&& b.text.trim().length > 0
|
|
339
|
+
),
|
|
340
|
+
);
|
|
341
|
+
// Only prune provisional pre-tool prose after post-tool prose exists,
|
|
342
|
+
// so MCP tool-only windows do not blank the assistant content.
|
|
343
|
+
const shouldDropPreToolProse = isClaudeCodeProvider && hasMcpToolBlock && hasPostToolText;
|
|
344
|
+
type DesiredSegment =
|
|
345
|
+
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
346
|
+
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
347
|
+
const desired: DesiredSegment[] = [];
|
|
348
|
+
let runStart = -1;
|
|
349
|
+
let runEnd = -1;
|
|
350
|
+
let runType: "text" | "thinking" | undefined;
|
|
351
|
+
const closeRun = () => {
|
|
352
|
+
if (runStart !== -1 && runType) {
|
|
353
|
+
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
354
|
+
runStart = -1;
|
|
355
|
+
runEnd = -1;
|
|
356
|
+
runType = undefined;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
360
|
+
const b = blocks[i];
|
|
361
|
+
const blockType = b.type === "text" || b.type === "thinking" ? b.type : undefined;
|
|
362
|
+
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
363
|
+
const isTool = b.type === "toolCall" || b.type === "serverToolUse";
|
|
364
|
+
// For Claude Code MCP turns, prune only pre-tool prose, never thinking.
|
|
365
|
+
const shouldSkipProse = shouldDropPreToolProse && firstToolIdx >= 0 && i < firstToolIdx && blockType === "text";
|
|
366
|
+
if (shouldSkipProse) {
|
|
367
|
+
closeRun();
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (isTextLike) {
|
|
371
|
+
if (runStart === -1) {
|
|
372
|
+
runStart = i;
|
|
373
|
+
runEnd = i;
|
|
374
|
+
runType = blockType;
|
|
375
|
+
} else if (runType !== blockType) {
|
|
376
|
+
closeRun();
|
|
377
|
+
runStart = i;
|
|
378
|
+
runEnd = i;
|
|
379
|
+
runType = blockType;
|
|
380
|
+
} else {
|
|
381
|
+
runEnd = i;
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
closeRun();
|
|
385
|
+
if (isTool) {
|
|
386
|
+
desired.push({ kind: "tool", contentIndex: i, toolId: b.id });
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
closeRun();
|
|
391
|
+
|
|
392
|
+
// Claude Code MCP can emit provisional pre-tool prose that gets
|
|
393
|
+
// superseded by post-tool output. Prune stale text-run segments so
|
|
394
|
+
// the final assistant output remains below tool output.
|
|
395
|
+
if (shouldDropPreToolProse && firstToolIdx >= 0) {
|
|
396
|
+
if (orphanedSegments.length > 0) {
|
|
397
|
+
const remainingOrphans: RenderedSegment[] = [];
|
|
398
|
+
for (const orphan of orphanedSegments) {
|
|
399
|
+
if (orphan.kind === "text-run" && orphan.contentType === "text") {
|
|
400
|
+
host.chatContainer.removeChild(orphan.component);
|
|
401
|
+
if (host.streamingComponent === orphan.component) {
|
|
402
|
+
host.streamingComponent = undefined;
|
|
403
|
+
}
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
remainingOrphans.push(orphan);
|
|
407
|
+
}
|
|
408
|
+
orphanedSegments = remainingOrphans;
|
|
409
|
+
}
|
|
410
|
+
const desiredTextKeys = new Set(
|
|
411
|
+
desired
|
|
412
|
+
.filter((seg): seg is Extract<DesiredSegment, { kind: "text-run" }> => seg.kind === "text-run")
|
|
413
|
+
.map((seg) => `${seg.contentType}:${seg.startIndex}`),
|
|
414
|
+
);
|
|
415
|
+
const desiredToolIndices = new Set(
|
|
416
|
+
desired
|
|
417
|
+
.filter((seg): seg is Extract<DesiredSegment, { kind: "tool" }> => seg.kind === "tool")
|
|
418
|
+
.map((seg) => seg.contentIndex),
|
|
419
|
+
);
|
|
420
|
+
const nextRendered: RenderedSegment[] = [];
|
|
421
|
+
for (const seg of renderedSegments) {
|
|
422
|
+
if (
|
|
423
|
+
seg.kind === "text-run"
|
|
424
|
+
&& seg.contentType === "text"
|
|
425
|
+
&& !desiredTextKeys.has(`${seg.contentType}:${seg.startIndex}`)
|
|
426
|
+
) {
|
|
427
|
+
host.chatContainer.removeChild(seg.component);
|
|
428
|
+
if (host.streamingComponent === seg.component) {
|
|
429
|
+
host.streamingComponent = undefined;
|
|
430
|
+
}
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (seg.kind === "tool" && !desiredToolIndices.has(seg.contentIndex)) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
nextRendered.push(seg);
|
|
437
|
+
}
|
|
438
|
+
renderedSegments = nextRendered;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Append any newly needed segments (never reorder existing ones).
|
|
442
|
+
for (const seg of desired) {
|
|
443
|
+
if (seg.kind === "tool") {
|
|
444
|
+
// Tool segments are already handled above via pendingTools; just
|
|
445
|
+
// register them in renderedSegments if not yet tracked.
|
|
446
|
+
const existing = renderedSegments.find(
|
|
447
|
+
(s) => s.kind === "tool" && s.contentIndex === seg.contentIndex,
|
|
448
|
+
);
|
|
449
|
+
if (!existing) {
|
|
450
|
+
const comp = host.pendingTools.get(seg.toolId);
|
|
451
|
+
if (comp) {
|
|
452
|
+
renderedSegments.push({ kind: "tool", contentIndex: seg.contentIndex, component: comp });
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
// text-run segment
|
|
457
|
+
const existing = renderedSegments.find(
|
|
458
|
+
(s) => s.kind === "text-run" && s.startIndex === seg.startIndex && s.contentType === seg.contentType,
|
|
459
|
+
);
|
|
460
|
+
if (!existing) {
|
|
461
|
+
const comp = new AssistantMessageComponent(
|
|
462
|
+
undefined,
|
|
463
|
+
host.hideThinkingBlock,
|
|
464
|
+
host.getMarkdownThemeWithSettings(),
|
|
465
|
+
host.settingsManager.getTimestampFormat(),
|
|
466
|
+
{ startIndex: seg.startIndex, endIndex: seg.endIndex },
|
|
467
|
+
);
|
|
468
|
+
host.chatContainer.addChild(comp);
|
|
469
|
+
renderedSegments.push({
|
|
470
|
+
kind: "text-run",
|
|
471
|
+
startIndex: seg.startIndex,
|
|
472
|
+
endIndex: seg.endIndex,
|
|
473
|
+
contentType: seg.contentType,
|
|
474
|
+
component: comp,
|
|
475
|
+
});
|
|
476
|
+
host.streamingComponent = comp;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Update all trailing text-run segments with the latest message so
|
|
482
|
+
// streaming text grows in place.
|
|
483
|
+
for (const seg of renderedSegments) {
|
|
484
|
+
if (seg.kind === "text-run") {
|
|
485
|
+
// Find corresponding desired segment to get current endIndex
|
|
486
|
+
const d = desired.find(
|
|
487
|
+
(ds) => ds.kind === "text-run" && ds.startIndex === seg.startIndex && ds.contentType === seg.contentType,
|
|
488
|
+
);
|
|
489
|
+
if (d && d.kind === "text-run" && d.endIndex !== seg.endIndex) {
|
|
490
|
+
seg.endIndex = d.endIndex;
|
|
491
|
+
seg.component.setRange({ startIndex: seg.startIndex, endIndex: seg.endIndex });
|
|
492
|
+
}
|
|
493
|
+
seg.component.updateContent(host.streamingMessage);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Keep streamingComponent pointing at the last text-run for message_end compatibility.
|
|
498
|
+
const lastTextSeg = [...renderedSegments].reverse().find((s) => s.kind === "text-run");
|
|
499
|
+
if (lastTextSeg && lastTextSeg.kind === "text-run") {
|
|
500
|
+
host.streamingComponent = lastTextSeg.component;
|
|
292
501
|
}
|
|
293
|
-
host.streamingComponent.updateContent(host.streamingMessage);
|
|
294
502
|
}
|
|
295
503
|
|
|
296
504
|
// Update index: fully processed blocks won't need re-scanning.
|
|
@@ -348,11 +556,11 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
348
556
|
}
|
|
349
557
|
break;
|
|
350
558
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
559
|
+
case "message_end":
|
|
560
|
+
if (event.message.role === "user") break;
|
|
561
|
+
if (event.message.role === "assistant") {
|
|
562
|
+
host.streamingMessage = event.message;
|
|
563
|
+
let errorMessage: string | undefined;
|
|
356
564
|
if (host.streamingMessage.stopReason === "aborted") {
|
|
357
565
|
const retryAttempt = host.session.retryAttempt;
|
|
358
566
|
errorMessage = retryAttempt > 0
|
|
@@ -361,21 +569,148 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
361
569
|
host.streamingMessage.errorMessage = errorMessage;
|
|
362
570
|
}
|
|
363
571
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
572
|
+
const shouldRenderAssistant = hasVisibleAssistantContent(host.streamingMessage)
|
|
573
|
+
|| (
|
|
574
|
+
(host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error")
|
|
575
|
+
&& !hasAssistantToolBlocks(host.streamingMessage)
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
// The final message_end payload can contain additional text/thinking
|
|
579
|
+
// blocks that never arrived via message_update (e.g. SDK result
|
|
580
|
+
// aggregation). Rebuild this in-flight turn from final content so
|
|
581
|
+
// ranges/components don't keep stale partial indices.
|
|
582
|
+
if (renderedSegments.length > 0) {
|
|
583
|
+
const finalBlocks = host.streamingMessage.content;
|
|
584
|
+
type DesiredSegment =
|
|
585
|
+
| { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
|
|
586
|
+
| { kind: "tool"; contentIndex: number; toolId: string };
|
|
587
|
+
const desired: DesiredSegment[] = [];
|
|
588
|
+
let runStart = -1;
|
|
589
|
+
let runEnd = -1;
|
|
590
|
+
let runType: "text" | "thinking" | undefined;
|
|
591
|
+
const closeRun = () => {
|
|
592
|
+
if (runStart !== -1 && runType) {
|
|
593
|
+
desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
|
|
594
|
+
runStart = -1;
|
|
595
|
+
runEnd = -1;
|
|
596
|
+
runType = undefined;
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
for (let i = 0; i < finalBlocks.length; i++) {
|
|
601
|
+
const block = finalBlocks[i] as any;
|
|
602
|
+
const blockType = block?.type === "text" || block?.type === "thinking" ? block.type : undefined;
|
|
603
|
+
const isTextLike = blockType === "text" || blockType === "thinking";
|
|
604
|
+
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
605
|
+
|
|
606
|
+
if (isTextLike) {
|
|
607
|
+
if (runStart === -1) {
|
|
608
|
+
runStart = i;
|
|
609
|
+
runEnd = i;
|
|
610
|
+
runType = blockType;
|
|
611
|
+
} else if (runType !== blockType) {
|
|
612
|
+
closeRun();
|
|
613
|
+
runStart = i;
|
|
614
|
+
runEnd = i;
|
|
615
|
+
runType = blockType;
|
|
616
|
+
} else {
|
|
617
|
+
runEnd = i;
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
closeRun();
|
|
621
|
+
if (isTool) {
|
|
622
|
+
desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
closeRun();
|
|
627
|
+
|
|
628
|
+
const toolComponentsById = new Map<string, ToolExecutionComponent>();
|
|
629
|
+
for (const [toolId, component] of host.pendingTools.entries()) {
|
|
630
|
+
toolComponentsById.set(toolId, component);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
for (const seg of renderedSegments) {
|
|
634
|
+
host.chatContainer.removeChild(seg.component);
|
|
635
|
+
if (seg.kind === "tool") {
|
|
636
|
+
const priorBlocks = host.streamingMessage.content;
|
|
637
|
+
const priorBlock = priorBlocks[seg.contentIndex] as any;
|
|
638
|
+
if (priorBlock?.id && !toolComponentsById.has(priorBlock.id)) {
|
|
639
|
+
toolComponentsById.set(priorBlock.id, seg.component);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
renderedSegments = [];
|
|
644
|
+
host.streamingComponent = undefined;
|
|
645
|
+
|
|
646
|
+
for (const seg of desired) {
|
|
647
|
+
if (seg.kind === "tool") {
|
|
648
|
+
const finalBlock = finalBlocks[seg.contentIndex] as any;
|
|
649
|
+
let component = toolComponentsById.get(seg.toolId);
|
|
650
|
+
if (!component && finalBlock?.id) {
|
|
651
|
+
component = host.pendingTools.get(finalBlock.id);
|
|
652
|
+
}
|
|
653
|
+
if (!component && finalBlock?.type === "toolCall") {
|
|
654
|
+
component = new ToolExecutionComponent(
|
|
655
|
+
finalBlock.name,
|
|
656
|
+
finalBlock.arguments,
|
|
657
|
+
{ showImages: host.settingsManager.getShowImages() },
|
|
658
|
+
host.getRegisteredToolDefinition(finalBlock.name),
|
|
659
|
+
host.ui,
|
|
660
|
+
);
|
|
661
|
+
component.setExpanded(host.toolOutputExpanded);
|
|
662
|
+
host.pendingTools.set(finalBlock.id, component);
|
|
663
|
+
toolComponentsById.set(finalBlock.id, component);
|
|
664
|
+
} else if (!component && finalBlock?.type === "serverToolUse") {
|
|
665
|
+
component = new ToolExecutionComponent(
|
|
666
|
+
finalBlock.name,
|
|
667
|
+
finalBlock.input ?? {},
|
|
668
|
+
{ showImages: host.settingsManager.getShowImages() },
|
|
669
|
+
undefined,
|
|
670
|
+
host.ui,
|
|
671
|
+
);
|
|
672
|
+
component.setExpanded(host.toolOutputExpanded);
|
|
673
|
+
host.pendingTools.set(finalBlock.id, component);
|
|
674
|
+
toolComponentsById.set(finalBlock.id, component);
|
|
675
|
+
}
|
|
676
|
+
if (component) {
|
|
677
|
+
host.chatContainer.addChild(component);
|
|
678
|
+
renderedSegments.push({ kind: "tool", contentIndex: seg.contentIndex, component });
|
|
679
|
+
}
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const comp = new AssistantMessageComponent(
|
|
684
|
+
undefined,
|
|
685
|
+
host.hideThinkingBlock,
|
|
686
|
+
host.getMarkdownThemeWithSettings(),
|
|
687
|
+
host.settingsManager.getTimestampFormat(),
|
|
688
|
+
{ startIndex: seg.startIndex, endIndex: seg.endIndex },
|
|
689
|
+
);
|
|
690
|
+
comp.updateContent(host.streamingMessage);
|
|
691
|
+
host.chatContainer.addChild(comp);
|
|
692
|
+
renderedSegments.push({
|
|
693
|
+
kind: "text-run",
|
|
694
|
+
startIndex: seg.startIndex,
|
|
695
|
+
endIndex: seg.endIndex,
|
|
696
|
+
contentType: seg.contentType,
|
|
697
|
+
component: comp,
|
|
698
|
+
});
|
|
699
|
+
host.streamingComponent = comp;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (!host.streamingComponent && shouldRenderAssistant) {
|
|
704
|
+
host.streamingComponent = new AssistantMessageComponent(
|
|
705
|
+
undefined,
|
|
706
|
+
host.hideThinkingBlock,
|
|
373
707
|
host.getMarkdownThemeWithSettings(),
|
|
374
708
|
host.settingsManager.getTimestampFormat(),
|
|
375
709
|
);
|
|
376
710
|
host.chatContainer.addChild(host.streamingComponent);
|
|
377
711
|
}
|
|
378
712
|
if (host.streamingComponent) {
|
|
713
|
+
host.streamingComponent.setShowMetadata(true);
|
|
379
714
|
host.streamingComponent.updateContent(host.streamingMessage);
|
|
380
715
|
}
|
|
381
716
|
|
|
@@ -399,6 +734,9 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
399
734
|
}
|
|
400
735
|
host.streamingComponent = undefined;
|
|
401
736
|
host.streamingMessage = undefined;
|
|
737
|
+
renderedSegments = [];
|
|
738
|
+
orphanedSegments = [];
|
|
739
|
+
lastContentLength = 0;
|
|
402
740
|
// Clear pinned output once the message is finalized in the chat
|
|
403
741
|
// container — prevents duplicate display when the agent continues
|
|
404
742
|
// (e.g. form elicitation) after the assistant message ends.
|
|
@@ -454,11 +792,15 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
454
792
|
host.loadingAnimation = undefined;
|
|
455
793
|
host.statusContainer.clear();
|
|
456
794
|
}
|
|
457
|
-
if (host.streamingComponent) {
|
|
458
|
-
host.
|
|
459
|
-
host.streamingComponent
|
|
460
|
-
host.streamingMessage = undefined;
|
|
795
|
+
if (host.streamingComponent && host.streamingMessage) {
|
|
796
|
+
host.streamingComponent.setShowMetadata(true);
|
|
797
|
+
host.streamingComponent.updateContent(host.streamingMessage);
|
|
461
798
|
}
|
|
799
|
+
host.streamingComponent = undefined;
|
|
800
|
+
host.streamingMessage = undefined;
|
|
801
|
+
renderedSegments = [];
|
|
802
|
+
orphanedSegments = [];
|
|
803
|
+
lastContentLength = 0;
|
|
462
804
|
host.pendingTools.clear();
|
|
463
805
|
// Pinned output is only useful while work is actively streaming.
|
|
464
806
|
// Keep chat history as the single source after completion.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import { buildAssistantReplaySegments } from "./interactive-mode.js";
|
|
5
|
+
|
|
6
|
+
test("buildAssistantReplaySegments preserves tool-first ordering", () => {
|
|
7
|
+
const segments = buildAssistantReplaySegments([
|
|
8
|
+
{ type: "toolCall", id: "t1", name: "read", arguments: {} },
|
|
9
|
+
{ type: "text", text: "Done." },
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
assert.deepEqual(segments, [
|
|
13
|
+
{ kind: "tool", contentIndex: 0 },
|
|
14
|
+
{ kind: "assistant", startIndex: 1, endIndex: 1 },
|
|
15
|
+
]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("buildAssistantReplaySegments preserves interleaved assistant-tool-assistant runs", () => {
|
|
19
|
+
const segments = buildAssistantReplaySegments([
|
|
20
|
+
{ type: "text", text: "Let me check." },
|
|
21
|
+
{ type: "serverToolUse", id: "s1", name: "mcp__fs__glob", input: {} },
|
|
22
|
+
{ type: "thinking", thinking: "Tool result looks good." },
|
|
23
|
+
{ type: "text", text: "Here is the answer." },
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
assert.deepEqual(segments, [
|
|
27
|
+
{ kind: "assistant", startIndex: 0, endIndex: 0 },
|
|
28
|
+
{ kind: "tool", contentIndex: 1 },
|
|
29
|
+
{ kind: "assistant", startIndex: 2, endIndex: 3 },
|
|
30
|
+
]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("buildAssistantReplaySegments ignores non-rendered non-tool blocks", () => {
|
|
34
|
+
const segments = buildAssistantReplaySegments([
|
|
35
|
+
{ type: "text", text: "before" },
|
|
36
|
+
{ type: "webSearchResult", toolUseId: "s1", content: {} },
|
|
37
|
+
{ type: "text", text: "after" },
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(segments, [
|
|
41
|
+
{ kind: "assistant", startIndex: 0, endIndex: 0 },
|
|
42
|
+
{ kind: "assistant", startIndex: 2, endIndex: 2 },
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
@@ -127,6 +127,45 @@ function isExpandable(obj: unknown): obj is Expandable {
|
|
|
127
127
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
export type AssistantReplaySegment =
|
|
131
|
+
| { kind: "assistant"; startIndex: number; endIndex: number }
|
|
132
|
+
| { kind: "tool"; contentIndex: number };
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Build replay segments for historical assistant messages so rebuild paths
|
|
136
|
+
* preserve the original content[] ordering between assistant prose and tools.
|
|
137
|
+
*/
|
|
138
|
+
export function buildAssistantReplaySegments(contentBlocks: Array<any>): AssistantReplaySegment[] {
|
|
139
|
+
const segments: AssistantReplaySegment[] = [];
|
|
140
|
+
let runStart = -1;
|
|
141
|
+
|
|
142
|
+
for (let i = 0; i < contentBlocks.length; i++) {
|
|
143
|
+
const block = contentBlocks[i];
|
|
144
|
+
const isAssistantText = block?.type === "text" || block?.type === "thinking";
|
|
145
|
+
const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
|
|
146
|
+
|
|
147
|
+
if (isAssistantText) {
|
|
148
|
+
if (runStart === -1) runStart = i;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (runStart !== -1) {
|
|
153
|
+
segments.push({ kind: "assistant", startIndex: runStart, endIndex: i - 1 });
|
|
154
|
+
runStart = -1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (isTool) {
|
|
158
|
+
segments.push({ kind: "tool", contentIndex: i });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (runStart !== -1) {
|
|
163
|
+
segments.push({ kind: "assistant", startIndex: runStart, endIndex: contentBlocks.length - 1 });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return segments;
|
|
167
|
+
}
|
|
168
|
+
|
|
130
169
|
type CompactionQueuedMessage = {
|
|
131
170
|
text: string;
|
|
132
171
|
mode: "steer" | "followUp";
|
|
@@ -1402,7 +1441,9 @@ export class InteractiveMode {
|
|
|
1402
1441
|
|
|
1403
1442
|
// widgetContainerAbove: spacer collapses when pinned content is visible
|
|
1404
1443
|
// so there's no extra blank line between pinned output and the editor border.
|
|
1405
|
-
|
|
1444
|
+
// Use detachChildren() (not clear()) — the extensionWidgetsAbove map owns
|
|
1445
|
+
// disposal; clear() would dispose every mounted widget on every re-render.
|
|
1446
|
+
this.widgetContainerAbove.detachChildren();
|
|
1406
1447
|
const pinned = this.pinnedMessageContainer;
|
|
1407
1448
|
this.widgetContainerAbove.addChild({
|
|
1408
1449
|
render: () => pinned.children.length > 0 ? [] : [""],
|
|
@@ -1422,7 +1463,9 @@ export class InteractiveMode {
|
|
|
1422
1463
|
spacerWhenEmpty: boolean,
|
|
1423
1464
|
leadingSpacer: boolean,
|
|
1424
1465
|
): void {
|
|
1425
|
-
|
|
1466
|
+
// Detach without disposing — the widgets map owns lifecycle; disposing
|
|
1467
|
+
// here would kill refresh timers and subscriptions on every re-render.
|
|
1468
|
+
container.detachChildren();
|
|
1426
1469
|
|
|
1427
1470
|
if (widgets.size === 0) {
|
|
1428
1471
|
if (spacerWhenEmpty) {
|
|
@@ -2197,9 +2240,30 @@ export class InteractiveMode {
|
|
|
2197
2240
|
for (const message of sessionContext.messages) {
|
|
2198
2241
|
// Assistant messages need special handling for tool calls
|
|
2199
2242
|
if (message.role === "assistant") {
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2243
|
+
const hasToolBlocks = message.content.some((c) => c.type === "toolCall" || c.type === "serverToolUse");
|
|
2244
|
+
if (!hasToolBlocks) {
|
|
2245
|
+
this.addMessageToChat(message);
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
const assistantSegments: AssistantMessageComponent[] = [];
|
|
2250
|
+
const replaySegments = buildAssistantReplaySegments(message.content);
|
|
2251
|
+
|
|
2252
|
+
for (const segment of replaySegments) {
|
|
2253
|
+
if (segment.kind === "assistant") {
|
|
2254
|
+
const assistantComponent = new AssistantMessageComponent(
|
|
2255
|
+
message,
|
|
2256
|
+
this.hideThinkingBlock,
|
|
2257
|
+
this.getMarkdownThemeWithSettings(),
|
|
2258
|
+
this.settingsManager.getTimestampFormat(),
|
|
2259
|
+
{ startIndex: segment.startIndex, endIndex: segment.endIndex },
|
|
2260
|
+
);
|
|
2261
|
+
this.chatContainer.addChild(assistantComponent);
|
|
2262
|
+
assistantSegments.push(assistantComponent);
|
|
2263
|
+
continue;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
const content = message.content[segment.contentIndex];
|
|
2203
2267
|
if (content.type === "toolCall") {
|
|
2204
2268
|
const component = new ToolExecutionComponent(
|
|
2205
2269
|
content.name,
|
|
@@ -2255,6 +2319,11 @@ export class InteractiveMode {
|
|
|
2255
2319
|
}
|
|
2256
2320
|
}
|
|
2257
2321
|
}
|
|
2322
|
+
|
|
2323
|
+
// Match streaming-mode behavior: show metadata once on the final
|
|
2324
|
+
// assistant prose segment for this message.
|
|
2325
|
+
const lastAssistantSegment = assistantSegments[assistantSegments.length - 1];
|
|
2326
|
+
lastAssistantSegment?.setShowMetadata(true);
|
|
2258
2327
|
} else if (message.role === "toolResult") {
|
|
2259
2328
|
// Match tool results to pending tool components
|
|
2260
2329
|
const component = this.pendingTools.get(message.toolCallId);
|
|
@@ -2302,9 +2371,13 @@ export class InteractiveMode {
|
|
|
2302
2371
|
|
|
2303
2372
|
private rebuildChatFromMessages(): void {
|
|
2304
2373
|
this.chatContainer.clear();
|
|
2374
|
+
this.pinnedMessageContainer.clear();
|
|
2305
2375
|
const context = this.sessionManager.buildSessionContext();
|
|
2306
2376
|
this.renderSessionContext(context);
|
|
2307
|
-
|
|
2377
|
+
// Pinned content NOT re-populated here — the streaming lifecycle in
|
|
2378
|
+
// chat-controller.ts manages the pinned zone during active work.
|
|
2379
|
+
// populatePinnedFromMessages() remains in renderInitialMessages()
|
|
2380
|
+
// for the session-resume case at startup.
|
|
2308
2381
|
}
|
|
2309
2382
|
|
|
2310
2383
|
/**
|