gsd-pi 2.74.0-dev.28a6415 → 2.74.0-dev.658744a
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/resources/extensions/gsd/auto/phases.js +51 -6
- package/dist/resources/extensions/gsd/auto-model-selection.js +3 -3
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -3
- package/dist/resources/extensions/gsd/auto-recovery.js +24 -10
- package/dist/resources/extensions/gsd/auto-worktree.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -3
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +10 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +61 -9
- package/dist/resources/extensions/gsd/cache.js +16 -5
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +5 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +50 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -0
- 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/guided-flow.js +8 -6
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +10 -0
- package/dist/resources/extensions/gsd/preferences.js +5 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +15 -30
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -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 +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 +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +88 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.ts +95 -10
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -9
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -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/scripts/generate-models.ts +74 -40
- package/packages/pi-ai/src/index.ts +1 -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/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -2
- 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 +214 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -0
- 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 +18 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +8 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +68 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +22 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.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 +115 -4
- 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 +14 -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 +70 -6
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +12 -6
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +273 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +20 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +67 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +83 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +23 -26
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +176 -40
- 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 +92 -6
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/phases.ts +70 -6
- package/src/resources/extensions/gsd/auto-model-selection.ts +3 -3
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -3
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +5 -3
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +15 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +72 -8
- package/src/resources/extensions/gsd/cache.ts +16 -5
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +5 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +57 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -0
- 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/guided-flow.ts +4 -2
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +10 -0
- package/src/resources/extensions/gsd/preferences.ts +6 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +15 -31
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +272 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/preferences.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +57 -2
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +1 -1
- package/src/resources/extensions/gsd/types.ts +13 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- 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/{fMaWScj7m6EsI3DbaNv2_ → Es_JWCfFZjIvYZShmjyye}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{fMaWScj7m6EsI3DbaNv2_ → Es_JWCfFZjIvYZShmjyye}/_ssgManifest.js +0 -0
|
@@ -1558,9 +1558,12 @@ export class AgentSession {
|
|
|
1558
1558
|
}
|
|
1559
1559
|
}
|
|
1560
1560
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1561
|
+
// #4243: Must call abort() BEFORE _disconnectFromAgent() so that
|
|
1562
|
+
// message_end/agent_end events fire and the #4216 finalization code
|
|
1563
|
+
// can run before we unsubscribe from the event bus.
|
|
1564
|
+
await this.abort();
|
|
1565
|
+
this._disconnectFromAgent();
|
|
1566
|
+
this.agent.reset();
|
|
1564
1567
|
// Update cwd to current process directory — auto-mode may have chdir'd
|
|
1565
1568
|
// into a worktree since the original session was created.
|
|
1566
1569
|
const previousCwd = this._cwd;
|
|
@@ -2411,9 +2414,12 @@ export class AgentSession {
|
|
|
2411
2414
|
}
|
|
2412
2415
|
}
|
|
2413
2416
|
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
+
// #4243: Must call abort() BEFORE _disconnectFromAgent() so that
|
|
2418
|
+
// message_end/agent_end events fire and the #4216 finalization code
|
|
2419
|
+
// can run before we unsubscribe from the event bus.
|
|
2420
|
+
await this.abort();
|
|
2421
|
+
this._disconnectFromAgent();
|
|
2422
|
+
this._steeringMessages = [];
|
|
2417
2423
|
this._followUpMessages = [];
|
|
2418
2424
|
this._pendingNextTurnMessages = [];
|
|
2419
2425
|
|
|
@@ -234,6 +234,64 @@ test("chat-controller renders serverToolUse before trailing text matching conten
|
|
|
234
234
|
assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
test("chat-controller replays final message_end content when result adds unstreamed trailing text", async () => {
|
|
238
|
+
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
239
|
+
fg: (_key: string, text: string) => text,
|
|
240
|
+
bg: (_key: string, text: string) => text,
|
|
241
|
+
bold: (text: string) => text,
|
|
242
|
+
italic: (text: string) => text,
|
|
243
|
+
truncate: (text: string) => text,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const host = createHost();
|
|
247
|
+
host.getMarkdownThemeWithSettings = () => ({});
|
|
248
|
+
|
|
249
|
+
const tool = {
|
|
250
|
+
type: "toolCall",
|
|
251
|
+
id: "mcp-end-replay-1",
|
|
252
|
+
name: "read",
|
|
253
|
+
mcpServer: "filesystem",
|
|
254
|
+
arguments: { filePath: "/tmp/demo.txt" },
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
|
|
258
|
+
|
|
259
|
+
const streamedContent = [
|
|
260
|
+
tool,
|
|
261
|
+
{ type: "thinking", thinking: "I am analyzing tool output..." },
|
|
262
|
+
];
|
|
263
|
+
await handleAgentEvent(
|
|
264
|
+
host,
|
|
265
|
+
{
|
|
266
|
+
type: "message_update",
|
|
267
|
+
message: makeAssistant(streamedContent),
|
|
268
|
+
assistantMessageEvent: {
|
|
269
|
+
type: "thinking_delta",
|
|
270
|
+
contentIndex: 1,
|
|
271
|
+
delta: "I am analyzing tool output...",
|
|
272
|
+
partial: makeAssistant(streamedContent),
|
|
273
|
+
},
|
|
274
|
+
} as any,
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
assert.equal(host.chatContainer.children.length, 2, "streaming shows tool + thinking only");
|
|
278
|
+
assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
|
|
279
|
+
assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
|
|
280
|
+
|
|
281
|
+
// Final payload includes trailing text that never arrived as message_update.
|
|
282
|
+
const finalContent = [
|
|
283
|
+
tool,
|
|
284
|
+
{ type: "thinking", thinking: "I am analyzing tool output..." },
|
|
285
|
+
{ type: "text", text: "Correct anything important I missed?" },
|
|
286
|
+
];
|
|
287
|
+
await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) } as any);
|
|
288
|
+
|
|
289
|
+
assert.equal(host.chatContainer.children.length, 3, "message_end should replay and include trailing text segment");
|
|
290
|
+
assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
|
|
291
|
+
assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
|
|
292
|
+
assert.equal(host.chatContainer.children[2]?.constructor?.name, "AssistantMessageComponent");
|
|
293
|
+
});
|
|
294
|
+
|
|
237
295
|
test("chat-controller keeps pre-tool prose visible until post-tool prose arrives, then prunes it", async () => {
|
|
238
296
|
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
239
297
|
fg: (_key: string, text: string) => text,
|
|
@@ -392,6 +450,89 @@ test("chat-controller keeps pre-tool thinking visible for claude-code MCP turns
|
|
|
392
450
|
await handleAgentEvent(host, { type: "message_end", message: makeAssistant([thinkingOnly[0], mcpTool]) } as any);
|
|
393
451
|
});
|
|
394
452
|
|
|
453
|
+
test("chat-controller keeps pre-tool question text for claude-code MCP when post-tool prose exists", async () => {
|
|
454
|
+
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
455
|
+
fg: (_key: string, text: string) => text,
|
|
456
|
+
bg: (_key: string, text: string) => text,
|
|
457
|
+
bold: (text: string) => text,
|
|
458
|
+
italic: (text: string) => text,
|
|
459
|
+
truncate: (text: string) => text,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
const host = createHost();
|
|
463
|
+
host.getMarkdownThemeWithSettings = () => ({});
|
|
464
|
+
|
|
465
|
+
const mcpTool = {
|
|
466
|
+
type: "toolCall",
|
|
467
|
+
id: "mcp-tool-question-1",
|
|
468
|
+
name: "glob",
|
|
469
|
+
mcpServer: "filesystem",
|
|
470
|
+
arguments: { pattern: "**/*" },
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
|
|
474
|
+
|
|
475
|
+
const questionText = { type: "text", text: "Which file should I inspect?" };
|
|
476
|
+
|
|
477
|
+
await handleAgentEvent(
|
|
478
|
+
host,
|
|
479
|
+
{
|
|
480
|
+
type: "message_update",
|
|
481
|
+
message: makeAssistant([questionText]),
|
|
482
|
+
assistantMessageEvent: {
|
|
483
|
+
type: "text_delta",
|
|
484
|
+
contentIndex: 0,
|
|
485
|
+
delta: questionText.text,
|
|
486
|
+
partial: makeAssistant([questionText]),
|
|
487
|
+
},
|
|
488
|
+
} as any,
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
await handleAgentEvent(
|
|
492
|
+
host,
|
|
493
|
+
{
|
|
494
|
+
type: "message_update",
|
|
495
|
+
message: makeAssistant([questionText, mcpTool]),
|
|
496
|
+
assistantMessageEvent: {
|
|
497
|
+
type: "toolcall_end",
|
|
498
|
+
contentIndex: 1,
|
|
499
|
+
toolCall: {
|
|
500
|
+
...mcpTool,
|
|
501
|
+
externalResult: {
|
|
502
|
+
content: [{ type: "text", text: "glob output" }],
|
|
503
|
+
details: {},
|
|
504
|
+
isError: false,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
partial: makeAssistant([questionText, mcpTool]),
|
|
508
|
+
},
|
|
509
|
+
} as any,
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
const postTool = { type: "text", text: "I'll review that next." };
|
|
513
|
+
const finalContent = [questionText, mcpTool, postTool];
|
|
514
|
+
await handleAgentEvent(
|
|
515
|
+
host,
|
|
516
|
+
{
|
|
517
|
+
type: "message_update",
|
|
518
|
+
message: makeAssistant(finalContent),
|
|
519
|
+
assistantMessageEvent: {
|
|
520
|
+
type: "text_delta",
|
|
521
|
+
contentIndex: 2,
|
|
522
|
+
delta: postTool.text,
|
|
523
|
+
partial: makeAssistant(finalContent),
|
|
524
|
+
},
|
|
525
|
+
} as any,
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
assert.equal(host.chatContainer.children.length, 3, "question text should remain alongside MCP tool and post-tool prose");
|
|
529
|
+
assert.equal(host.chatContainer.children[0]?.constructor?.name, "AssistantMessageComponent", "pre-tool question stays visible");
|
|
530
|
+
assert.equal(host.chatContainer.children[1]?.constructor?.name, "ToolExecutionComponent", "tool renders in the middle");
|
|
531
|
+
assert.equal(host.chatContainer.children[2]?.constructor?.name, "AssistantMessageComponent", "post-tool prose renders last");
|
|
532
|
+
|
|
533
|
+
await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) } as any);
|
|
534
|
+
});
|
|
535
|
+
|
|
395
536
|
test("chat-controller prunes orphaned provisional text after claude-code sub-turn shrink when MCP tools appear", async () => {
|
|
396
537
|
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
397
538
|
fg: (_key: string, text: string) => text,
|
|
@@ -493,6 +634,138 @@ test("chat-controller prunes orphaned provisional text after claude-code sub-tur
|
|
|
493
634
|
await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) } as any);
|
|
494
635
|
});
|
|
495
636
|
|
|
637
|
+
test("chat-controller prunes orphans from multiple sub-turn shrinks before MCP post-tool prose", async () => {
|
|
638
|
+
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
639
|
+
fg: (_key: string, text: string) => text,
|
|
640
|
+
bg: (_key: string, text: string) => text,
|
|
641
|
+
bold: (text: string) => text,
|
|
642
|
+
italic: (text: string) => text,
|
|
643
|
+
truncate: (text: string) => text,
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
const host = createHost();
|
|
647
|
+
host.getMarkdownThemeWithSettings = () => ({});
|
|
648
|
+
|
|
649
|
+
const mcpTool = {
|
|
650
|
+
type: "toolCall",
|
|
651
|
+
id: "mcp-tool-multi-shrink-1",
|
|
652
|
+
name: "glob",
|
|
653
|
+
mcpServer: "filesystem",
|
|
654
|
+
arguments: { pattern: "**/*" },
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
|
|
658
|
+
|
|
659
|
+
// Sub-turn 1: 3 text blocks (merged into one text-run).
|
|
660
|
+
const subTurn1 = [
|
|
661
|
+
{ type: "text", text: "First provisional A." },
|
|
662
|
+
{ type: "text", text: "First provisional B." },
|
|
663
|
+
{ type: "text", text: "First provisional C." },
|
|
664
|
+
];
|
|
665
|
+
await handleAgentEvent(
|
|
666
|
+
host,
|
|
667
|
+
{
|
|
668
|
+
type: "message_update",
|
|
669
|
+
message: makeAssistant(subTurn1),
|
|
670
|
+
assistantMessageEvent: {
|
|
671
|
+
type: "text_delta",
|
|
672
|
+
contentIndex: 2,
|
|
673
|
+
delta: "First provisional C.",
|
|
674
|
+
partial: makeAssistant(subTurn1),
|
|
675
|
+
},
|
|
676
|
+
} as any,
|
|
677
|
+
);
|
|
678
|
+
assert.equal(host.chatContainer.children.length, 1, "first sub-turn renders 1 text-run");
|
|
679
|
+
|
|
680
|
+
// Sub-turn 2 (first shrink 3 → 2 blocks).
|
|
681
|
+
const subTurn2 = [
|
|
682
|
+
{ type: "text", text: "Second provisional A." },
|
|
683
|
+
{ type: "text", text: "Second provisional B." },
|
|
684
|
+
];
|
|
685
|
+
await handleAgentEvent(
|
|
686
|
+
host,
|
|
687
|
+
{
|
|
688
|
+
type: "message_update",
|
|
689
|
+
message: makeAssistant(subTurn2),
|
|
690
|
+
assistantMessageEvent: {
|
|
691
|
+
type: "text_delta",
|
|
692
|
+
contentIndex: 1,
|
|
693
|
+
delta: "Second provisional B.",
|
|
694
|
+
partial: makeAssistant(subTurn2),
|
|
695
|
+
},
|
|
696
|
+
} as any,
|
|
697
|
+
);
|
|
698
|
+
assert.equal(host.chatContainer.children.length, 2, "first shrink appends, keeps prior text as frozen history");
|
|
699
|
+
|
|
700
|
+
// Sub-turn 3 (second shrink 2 → 1 block). This is the critical step —
|
|
701
|
+
// without orphan accumulation, sub-turn 1's orphaned segment would be
|
|
702
|
+
// dropped from tracking here and later strand in the container.
|
|
703
|
+
const subTurn3 = [{ type: "text", text: "Third provisional." }];
|
|
704
|
+
await handleAgentEvent(
|
|
705
|
+
host,
|
|
706
|
+
{
|
|
707
|
+
type: "message_update",
|
|
708
|
+
message: makeAssistant(subTurn3),
|
|
709
|
+
assistantMessageEvent: {
|
|
710
|
+
type: "text_delta",
|
|
711
|
+
contentIndex: 0,
|
|
712
|
+
delta: "Third provisional.",
|
|
713
|
+
partial: makeAssistant(subTurn3),
|
|
714
|
+
},
|
|
715
|
+
} as any,
|
|
716
|
+
);
|
|
717
|
+
assert.equal(host.chatContainer.children.length, 3, "second shrink appends again, still no prune (no post-tool text)");
|
|
718
|
+
|
|
719
|
+
// MCP tool appears — tool-only window still keeps provisional prose visible.
|
|
720
|
+
await handleAgentEvent(
|
|
721
|
+
host,
|
|
722
|
+
{
|
|
723
|
+
type: "message_update",
|
|
724
|
+
message: makeAssistant([{ type: "text", text: "Third provisional." }, mcpTool]),
|
|
725
|
+
assistantMessageEvent: {
|
|
726
|
+
type: "toolcall_end",
|
|
727
|
+
contentIndex: 1,
|
|
728
|
+
toolCall: {
|
|
729
|
+
...mcpTool,
|
|
730
|
+
externalResult: {
|
|
731
|
+
content: [{ type: "text", text: "glob output" }],
|
|
732
|
+
details: {},
|
|
733
|
+
isError: false,
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
partial: makeAssistant([{ type: "text", text: "Third provisional." }, mcpTool]),
|
|
737
|
+
},
|
|
738
|
+
} as any,
|
|
739
|
+
);
|
|
740
|
+
assert.equal(host.chatContainer.children.length, 4, "tool-only window keeps all three provisional text-runs");
|
|
741
|
+
|
|
742
|
+
// Final post-tool text arrives — prune must drop ALL three pre-tool
|
|
743
|
+
// provisional text-runs across both shrinks, leaving only tool + final text.
|
|
744
|
+
const finalContent = [mcpTool, { type: "text", text: "Final answer." }];
|
|
745
|
+
await handleAgentEvent(
|
|
746
|
+
host,
|
|
747
|
+
{
|
|
748
|
+
type: "message_update",
|
|
749
|
+
message: makeAssistant(finalContent),
|
|
750
|
+
assistantMessageEvent: {
|
|
751
|
+
type: "text_delta",
|
|
752
|
+
contentIndex: 1,
|
|
753
|
+
delta: "Final answer.",
|
|
754
|
+
partial: makeAssistant(finalContent),
|
|
755
|
+
},
|
|
756
|
+
} as any,
|
|
757
|
+
);
|
|
758
|
+
assert.equal(
|
|
759
|
+
host.chatContainer.children.length,
|
|
760
|
+
2,
|
|
761
|
+
"all pre-tool provisional segments from every shrink must be pruned once post-tool prose arrives",
|
|
762
|
+
);
|
|
763
|
+
assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
|
|
764
|
+
assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
|
|
765
|
+
|
|
766
|
+
await handleAgentEvent(host, { type: "message_end", message: makeAssistant(finalContent) } as any);
|
|
767
|
+
});
|
|
768
|
+
|
|
496
769
|
test("chat-controller pins latest assistant text above editor when tool calls are present", async () => {
|
|
497
770
|
(globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
|
|
498
771
|
fg: (_key: string, text: string) => text,
|
package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts
CHANGED
|
@@ -48,6 +48,25 @@ function renderToolCollapsed(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
describe("ToolExecutionComponent", () => {
|
|
51
|
+
test("renders framed header with Running status while tool is partial", () => {
|
|
52
|
+
const rendered = renderToolCollapsed("mcp__demo__do_thing", { ok: true });
|
|
53
|
+
|
|
54
|
+
assert.match(rendered, /Tool demo\u00b7do_thing/);
|
|
55
|
+
assert.match(rendered, /Running/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("renders framed header with Error status for failed tool result", () => {
|
|
59
|
+
const rendered = renderTool(
|
|
60
|
+
"mcp__demo__do_thing",
|
|
61
|
+
{ ok: true },
|
|
62
|
+
{ content: [{ type: "text", text: "boom" }], isError: true },
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
assert.match(rendered, /Tool demo\u00b7do_thing/);
|
|
66
|
+
assert.match(rendered, /Error/);
|
|
67
|
+
assert.match(rendered, /boom/);
|
|
68
|
+
});
|
|
69
|
+
|
|
51
70
|
test("renders capitalized Claude Code Bash tool names with bash output instead of generic args JSON", () => {
|
|
52
71
|
const rendered = renderTool(
|
|
53
72
|
"Bash",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
2
2
|
import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
|
|
3
3
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
4
|
-
import {
|
|
4
|
+
import { type TimestampFormat } from "./timestamp.js";
|
|
5
|
+
import { renderChatFrame } from "./chat-frame.js";
|
|
5
6
|
|
|
6
7
|
export interface ContentRange {
|
|
7
8
|
startIndex: number;
|
|
@@ -94,10 +95,6 @@ export class AssistantMessageComponent extends Container {
|
|
|
94
95
|
// manual thinking toggle every turn.
|
|
95
96
|
const shouldCapThinking = hasTextContent || hasToolContent || message.provider === "claude-code";
|
|
96
97
|
|
|
97
|
-
if (hasVisibleContent) {
|
|
98
|
-
this.contentContainer.addChild(new Spacer(1));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
98
|
// Render content in order; non-text/thinking blocks are silently skipped
|
|
102
99
|
for (let i = 0; i < slice.length; i++) {
|
|
103
100
|
const content = slice[i];
|
|
@@ -160,10 +157,24 @@ export class AssistantMessageComponent extends Container {
|
|
|
160
157
|
}
|
|
161
158
|
}
|
|
162
159
|
|
|
163
|
-
if (message.stopReason && message.timestamp) {
|
|
164
|
-
const timeStr = formatTimestamp(message.timestamp, this.timestampFormat);
|
|
165
|
-
this.contentContainer.addChild(new Text(theme.fg("dim", timeStr), 1, 0));
|
|
166
|
-
}
|
|
167
160
|
}
|
|
168
161
|
}
|
|
162
|
+
|
|
163
|
+
override render(width: number): string[] {
|
|
164
|
+
const frameWidth = Math.max(20, width);
|
|
165
|
+
const contentWidth = Math.max(1, frameWidth - 4);
|
|
166
|
+
const lines = super.render(contentWidth);
|
|
167
|
+
const headerLabel = this.lastMessage?.model ? `GSD - ${this.lastMessage.model}` : "GSD";
|
|
168
|
+
const framed = renderChatFrame(lines, frameWidth, {
|
|
169
|
+
label: headerLabel,
|
|
170
|
+
tone: "assistant",
|
|
171
|
+
timestamp: this.lastMessage?.timestamp,
|
|
172
|
+
timestampFormat: this.timestampFormat,
|
|
173
|
+
showTimestamp: this.showMetadata,
|
|
174
|
+
});
|
|
175
|
+
if (framed.length === 0) {
|
|
176
|
+
return framed;
|
|
177
|
+
}
|
|
178
|
+
return ["", ...framed];
|
|
179
|
+
}
|
|
169
180
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
2
|
+
import { theme } from "../theme/theme.js";
|
|
3
|
+
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
4
|
+
|
|
5
|
+
type FrameTone = "assistant" | "user";
|
|
6
|
+
|
|
7
|
+
function trimOuterBlankLines(lines: string[]): string[] {
|
|
8
|
+
let start = 0;
|
|
9
|
+
let end = lines.length;
|
|
10
|
+
while (start < end && lines[start].trim().length === 0) start++;
|
|
11
|
+
while (end > start && lines[end - 1].trim().length === 0) end--;
|
|
12
|
+
return lines.slice(start, end);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function renderChatFrame(
|
|
16
|
+
contentLines: string[],
|
|
17
|
+
width: number,
|
|
18
|
+
opts: {
|
|
19
|
+
label: string;
|
|
20
|
+
tone: FrameTone;
|
|
21
|
+
timestamp?: number;
|
|
22
|
+
timestampFormat: TimestampFormat;
|
|
23
|
+
showTimestamp?: boolean;
|
|
24
|
+
},
|
|
25
|
+
): string[] {
|
|
26
|
+
const outerWidth = Math.max(20, width);
|
|
27
|
+
const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
|
|
28
|
+
const borderColor = opts.tone === "user" ? "borderAccent" : "border";
|
|
29
|
+
const borderMuted = opts.tone === "user" ? "borderMuted" : "borderMuted";
|
|
30
|
+
const border = (s: string) => theme.fg(borderColor, s);
|
|
31
|
+
const leftRaw = `• ${opts.label}`;
|
|
32
|
+
const rightRaw =
|
|
33
|
+
opts.showTimestamp === false || !opts.timestamp
|
|
34
|
+
? ""
|
|
35
|
+
: formatTimestamp(opts.timestamp, opts.timestampFormat);
|
|
36
|
+
|
|
37
|
+
const leftBudget = rightRaw
|
|
38
|
+
? Math.max(1, outerWidth - visibleWidth(rightRaw) - 1)
|
|
39
|
+
: outerWidth;
|
|
40
|
+
const left = truncateToWidth(leftRaw, leftBudget, "");
|
|
41
|
+
const leftStyled =
|
|
42
|
+
opts.tone === "user"
|
|
43
|
+
? theme.fg("accent", theme.bold(left))
|
|
44
|
+
: theme.fg("muted", theme.bold(left));
|
|
45
|
+
const rightStyled = rightRaw ? theme.fg("dim", rightRaw) : "";
|
|
46
|
+
const gap =
|
|
47
|
+
rightRaw.length > 0
|
|
48
|
+
? Math.max(
|
|
49
|
+
1,
|
|
50
|
+
outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled),
|
|
51
|
+
)
|
|
52
|
+
: Math.max(0, outerWidth - visibleWidth(leftStyled));
|
|
53
|
+
const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
|
|
54
|
+
const headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));
|
|
55
|
+
|
|
56
|
+
const sourceLines = trimOuterBlankLines(contentLines);
|
|
57
|
+
const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
|
|
58
|
+
const clipped = truncateToWidth(line, contentWidth, "");
|
|
59
|
+
return border("│ ") + clipped;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return [
|
|
63
|
+
theme.fg(borderMuted, "─".repeat(outerWidth)),
|
|
64
|
+
headerRow + " ".repeat(headerPad),
|
|
65
|
+
...bodyLines,
|
|
66
|
+
];
|
|
67
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Text,
|
|
10
10
|
type TUI,
|
|
11
11
|
truncateToWidth,
|
|
12
|
+
visibleWidth,
|
|
12
13
|
} from "@gsd/pi-tui";
|
|
13
14
|
import stripAnsi from "strip-ansi";
|
|
14
15
|
import type { ToolDefinition } from "../../../core/extensions/types.js";
|
|
@@ -65,6 +66,53 @@ function parseMcpToolName(name: string): { server: string; tool: string } | null
|
|
|
65
66
|
return { server: rest.slice(0, delim), tool: rest.slice(delim + 2) };
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
type ToolFrameTone = "pending" | "success" | "error";
|
|
70
|
+
|
|
71
|
+
function trimOuterBlankLines(lines: string[]): string[] {
|
|
72
|
+
let start = 0;
|
|
73
|
+
let end = lines.length;
|
|
74
|
+
while (start < end && lines[start].trim().length === 0) start++;
|
|
75
|
+
while (end > start && lines[end - 1].trim().length === 0) end--;
|
|
76
|
+
return lines.slice(start, end);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function renderToolFrame(
|
|
80
|
+
contentLines: string[],
|
|
81
|
+
width: number,
|
|
82
|
+
opts: {
|
|
83
|
+
label: string;
|
|
84
|
+
status: string;
|
|
85
|
+
tone: ToolFrameTone;
|
|
86
|
+
},
|
|
87
|
+
): string[] {
|
|
88
|
+
const outerWidth = Math.max(20, width);
|
|
89
|
+
const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
|
|
90
|
+
|
|
91
|
+
const borderColor = opts.tone === "error" ? "error" : "toolTitle";
|
|
92
|
+
const topColor = opts.tone === "error" ? "error" : "toolTitle";
|
|
93
|
+
const labelColor = opts.tone === "error" ? "error" : "toolTitle";
|
|
94
|
+
const statusColor = opts.tone === "error" ? "error" : opts.tone === "pending" ? "warning" : "success";
|
|
95
|
+
const border = (s: string) => theme.fg(borderColor, s);
|
|
96
|
+
|
|
97
|
+
const leftStyled = theme.fg(labelColor, theme.bold(`• ${opts.label}`));
|
|
98
|
+
const rightStyled = theme.fg(statusColor, opts.status);
|
|
99
|
+
const gap = Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
|
|
100
|
+
const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
|
|
101
|
+
const headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));
|
|
102
|
+
|
|
103
|
+
const sourceLines = trimOuterBlankLines(contentLines);
|
|
104
|
+
const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
|
|
105
|
+
const clipped = truncateToWidth(line, contentWidth, "");
|
|
106
|
+
return border("│ ") + clipped;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return [
|
|
110
|
+
theme.fg(topColor, "─".repeat(outerWidth)),
|
|
111
|
+
headerRow + " ".repeat(headerPad),
|
|
112
|
+
...bodyLines,
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
|
|
68
116
|
const COMPACT_ARG_VALUE_LIMIT = 60;
|
|
69
117
|
const GENERIC_OUTPUT_PREVIEW_LINES = 10;
|
|
70
118
|
const GENERIC_ARGS_JSON_PREVIEW_LINES = 10;
|
|
@@ -379,6 +427,23 @@ export class ToolExecutionComponent extends Container {
|
|
|
379
427
|
this.maybeConvertImagesForKitty();
|
|
380
428
|
}
|
|
381
429
|
|
|
430
|
+
/**
|
|
431
|
+
* Mark a tool call as historical when replaying from session context and
|
|
432
|
+
* no matching tool result is available. Happens after compaction squashes
|
|
433
|
+
* tool_result messages out of history — the tool call block survives but
|
|
434
|
+
* the result is gone. Without this, the component stays in "Running" state
|
|
435
|
+
* forever even though the tool completed long ago.
|
|
436
|
+
*/
|
|
437
|
+
markHistoricalNoResult(): void {
|
|
438
|
+
if (this.result) return; // real result already set, nothing to do
|
|
439
|
+
this.isPartial = false;
|
|
440
|
+
this.result = {
|
|
441
|
+
content: [],
|
|
442
|
+
isError: false,
|
|
443
|
+
};
|
|
444
|
+
this.updateDisplay();
|
|
445
|
+
}
|
|
446
|
+
|
|
382
447
|
/**
|
|
383
448
|
* Finalize a pending tool call as failed/interrupted while preserving any streamed partial output.
|
|
384
449
|
*/
|
|
@@ -452,16 +517,27 @@ export class ToolExecutionComponent extends Container {
|
|
|
452
517
|
if (this.hideComponent) {
|
|
453
518
|
return [];
|
|
454
519
|
}
|
|
455
|
-
|
|
520
|
+
const frameWidth = Math.max(20, width);
|
|
521
|
+
const contentWidth = Math.max(1, frameWidth - 4);
|
|
522
|
+
const lines = super.render(contentWidth);
|
|
523
|
+
const frameTone: ToolFrameTone =
|
|
524
|
+
this.result?.isError ? "error" : this.isPartial || !this.result ? "pending" : "success";
|
|
525
|
+
const frameStatus = this.isPartial || !this.result ? "Running" : this.result.isError ? "Error" : "Done";
|
|
526
|
+
const parsed = parseMcpToolName(this.toolName);
|
|
527
|
+
const frameLabel = parsed
|
|
528
|
+
? `Tool ${parsed.server}·${parsed.tool}`
|
|
529
|
+
: `Tool ${this.normalizedToolName || this.toolName || "unknown"}`;
|
|
530
|
+
const framed = renderToolFrame(lines, frameWidth, {
|
|
531
|
+
label: frameLabel,
|
|
532
|
+
status: frameStatus,
|
|
533
|
+
tone: frameTone,
|
|
534
|
+
});
|
|
535
|
+
return framed.length > 0 ? ["", ...framed] : framed;
|
|
456
536
|
}
|
|
457
537
|
|
|
458
538
|
private updateDisplay(): void {
|
|
459
|
-
//
|
|
460
|
-
const bgFn =
|
|
461
|
-
? (text: string) => theme.bg("toolPendingBg", text)
|
|
462
|
-
: this.result?.isError
|
|
463
|
-
? (text: string) => theme.bg("toolErrorBg", text)
|
|
464
|
-
: (text: string) => theme.bg("toolSuccessBg", text);
|
|
539
|
+
// Tool body now uses transparent background; status is conveyed in the frame header.
|
|
540
|
+
const bgFn = (text: string) => text;
|
|
465
541
|
|
|
466
542
|
const useBuiltInRenderer = this.shouldUseBuiltInRenderer();
|
|
467
543
|
let customRendererHasContent = false;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Container, Markdown, type MarkdownTheme
|
|
2
|
-
import { getMarkdownTheme
|
|
3
|
-
import {
|
|
1
|
+
import { Container, Markdown, type MarkdownTheme } from "@gsd/pi-tui";
|
|
2
|
+
import { getMarkdownTheme } from "../theme/theme.js";
|
|
3
|
+
import { type TimestampFormat } from "./timestamp.js";
|
|
4
|
+
import { renderChatFrame } from "./chat-frame.js";
|
|
4
5
|
|
|
5
6
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
6
7
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
@@ -16,32 +17,28 @@ export class UserMessageComponent extends Container {
|
|
|
16
17
|
super();
|
|
17
18
|
this.timestamp = timestamp;
|
|
18
19
|
this.timestampFormat = timestampFormat;
|
|
19
|
-
this.addChild(new
|
|
20
|
-
this.addChild(
|
|
21
|
-
new Markdown(text, 1, 1, markdownTheme, {
|
|
22
|
-
bgColor: (text: string) => theme.bg("userMessageBg", text),
|
|
23
|
-
color: (text: string) => theme.fg("userMessageText", text),
|
|
24
|
-
}),
|
|
25
|
-
);
|
|
20
|
+
this.addChild(new Markdown(text, 0, 0, markdownTheme));
|
|
26
21
|
}
|
|
27
22
|
|
|
28
23
|
override render(width: number): string[] {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
const frameWidth = Math.max(20, width);
|
|
25
|
+
const contentWidth = Math.max(1, frameWidth - 4);
|
|
26
|
+
const lines = super.render(contentWidth);
|
|
27
|
+
const framed = renderChatFrame(lines, frameWidth, {
|
|
28
|
+
label: "You",
|
|
29
|
+
tone: "user",
|
|
30
|
+
timestamp: this.timestamp,
|
|
31
|
+
timestampFormat: this.timestampFormat,
|
|
32
|
+
showTimestamp: true,
|
|
33
|
+
});
|
|
34
|
+
if (framed.length === 0) {
|
|
35
|
+
return framed;
|
|
32
36
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const timestampLine = " ".repeat(padding) + label;
|
|
40
|
-
lines.splice(0, 0, timestampLine);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
lines[0] = OSC133_ZONE_START + lines[0];
|
|
44
|
-
lines[lines.length - 1] = lines[lines.length - 1] + OSC133_ZONE_END;
|
|
45
|
-
return lines;
|
|
37
|
+
const out = ["", ...framed];
|
|
38
|
+
const firstFrameLine = 1;
|
|
39
|
+
const lastFrameLine = out.length - 1;
|
|
40
|
+
out[firstFrameLine] = OSC133_ZONE_START + out[firstFrameLine];
|
|
41
|
+
out[lastFrameLine] = out[lastFrameLine] + OSC133_ZONE_END;
|
|
42
|
+
return out;
|
|
46
43
|
}
|
|
47
44
|
}
|