gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.f55d16d13
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/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/github-sync/templates.js +39 -8
- package/dist/resources/extensions/gsd/auto/loop.js +16 -9
- package/dist/resources/extensions/gsd/auto/phases.js +37 -30
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
- package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
- package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +111 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +154 -8
- package/dist/resources/extensions/gsd/auto-start.js +2 -3
- package/dist/resources/extensions/gsd/auto.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +15 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
- package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
- package/dist/resources/extensions/gsd/db-base-schema.js +14 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +16 -0
- package/dist/resources/extensions/gsd/detection.js +106 -0
- package/dist/resources/extensions/gsd/graph.js +9 -3
- package/dist/resources/extensions/gsd/gsd-db.js +102 -2
- package/dist/resources/extensions/gsd/guided-flow.js +2 -2
- package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.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/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 +11 -11
- 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-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
- package/package.json +10 -6
- package/packages/contracts/package.json +1 -1
- package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
- package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
- package/packages/pi-ai/dist/models/fake-model.js +27 -0
- package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
- package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/index.js +8 -0
- package/packages/pi-ai/dist/models/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
- package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/fake.js +319 -0
- package/packages/pi-ai/dist/providers/fake.js.map +1 -0
- package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
- package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
- package/packages/pi-ai/src/models/fake-model.ts +30 -0
- package/packages/pi-ai/src/models/index.ts +9 -0
- package/packages/pi-ai/src/providers/fake.ts +376 -0
- package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +74 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
- 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/adaptive-layout.d.ts +26 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +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.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -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 +106 -17
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +60 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -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 +23 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
- package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +118 -17
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +25 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
- package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
- package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
- package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/index.d.ts +1 -0
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -0
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/style.d.ts +41 -0
- package/packages/pi-tui/dist/style.d.ts.map +1 -0
- package/packages/pi-tui/dist/style.js +158 -0
- package/packages/pi-tui/dist/style.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts +0 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +3 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
- package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
- package/packages/pi-tui/src/index.ts +9 -0
- package/packages/pi-tui/src/style.ts +225 -0
- package/packages/pi-tui/src/tui.ts +3 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
- package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +18 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +36 -27
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/github-sync/templates.ts +38 -8
- package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +17 -10
- package/src/resources/extensions/gsd/auto/phases.ts +42 -28
- package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
- package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
- package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +153 -7
- package/src/resources/extensions/gsd/auto-start.ts +7 -6
- package/src/resources/extensions/gsd/auto.ts +12 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
- package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
- package/src/resources/extensions/gsd/db-base-schema.ts +15 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +17 -0
- package/src/resources/extensions/gsd/detection.ts +128 -0
- package/src/resources/extensions/gsd/graph.ts +12 -5
- package/src/resources/extensions/gsd/gsd-db.ts +119 -1
- package/src/resources/extensions/gsd/guided-flow.ts +2 -2
- package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +84 -5
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +170 -1
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
- package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
- package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
- package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
- package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
- package/packages/contracts/tsconfig.tsbuildinfo +0 -1
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → mPZbi5BH9dwokaPZlrYuQ}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// GSD2 - Adaptive terminal mode dashboard for the interactive TUI
|
|
2
|
+
|
|
3
|
+
import { style, truncateToWidth, visibleWidth, type Component } from "@gsd/pi-tui";
|
|
4
|
+
import type { TuiAdaptiveMode, TuiMode } from "../tui-mode.js";
|
|
5
|
+
import { resolveTuiMode } from "../tui-mode.js";
|
|
6
|
+
import { theme, type ThemeColor } from "../theme/theme.js";
|
|
7
|
+
|
|
8
|
+
export interface AdaptiveLayoutState {
|
|
9
|
+
override: TuiAdaptiveMode;
|
|
10
|
+
activeToolCount: number;
|
|
11
|
+
gsdPhase?: string;
|
|
12
|
+
lastError?: string;
|
|
13
|
+
sessionName?: string;
|
|
14
|
+
cwd: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class AdaptiveLayoutComponent implements Component {
|
|
18
|
+
constructor(private readonly getState: () => AdaptiveLayoutState) {}
|
|
19
|
+
|
|
20
|
+
invalidate(): void {}
|
|
21
|
+
|
|
22
|
+
render(width: number): string[] {
|
|
23
|
+
const state = this.getState();
|
|
24
|
+
const mode = resolveTuiMode({
|
|
25
|
+
terminalWidth: width,
|
|
26
|
+
override: state.override,
|
|
27
|
+
activeToolCount: state.activeToolCount,
|
|
28
|
+
gsdPhase: state.gsdPhase,
|
|
29
|
+
hasBlockingError: !!state.lastError,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (state.override === "auto" && mode === "chat" && !state.gsdPhase && !state.lastError && state.activeToolCount === 0) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (mode === "compact" || width < 72) return this.renderCompact(width, mode, state);
|
|
37
|
+
if (mode === "debug") return this.renderDebug(width, state);
|
|
38
|
+
if (mode === "validation") return this.renderValidation(width, state);
|
|
39
|
+
if (mode === "workflow") return this.renderWorkflow(width, state);
|
|
40
|
+
return this.renderChat(width, state);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private renderWorkflow(width: number, state: AdaptiveLayoutState): string[] {
|
|
44
|
+
if (width < 112) return this.renderCompact(width, "workflow", state);
|
|
45
|
+
|
|
46
|
+
const leftWidth = Math.max(44, Math.floor(width * 0.56));
|
|
47
|
+
const rightWidth = Math.max(32, width - leftWidth - 2);
|
|
48
|
+
const phase = state.gsdPhase ?? "Ready";
|
|
49
|
+
const left = this.frame(
|
|
50
|
+
[
|
|
51
|
+
this.metric("Active", phase, "modeWorkflow"),
|
|
52
|
+
this.metric("Tools", state.activeToolCount > 0 ? `${state.activeToolCount} running` : "idle", "toolRunning"),
|
|
53
|
+
this.metric("Mode", state.override === "auto" ? "auto workflow" : state.override, "modeWorkflow"),
|
|
54
|
+
],
|
|
55
|
+
leftWidth,
|
|
56
|
+
"GSD Command Center",
|
|
57
|
+
"workflow",
|
|
58
|
+
"modeWorkflow",
|
|
59
|
+
);
|
|
60
|
+
const right = this.frame(
|
|
61
|
+
[
|
|
62
|
+
`Session ${state.sessionName ?? "current"}`,
|
|
63
|
+
`Path ${this.basename(state.cwd)}`,
|
|
64
|
+
`Next ${state.activeToolCount > 0 ? "watch tool output" : "continue from prompt"}`,
|
|
65
|
+
],
|
|
66
|
+
rightWidth,
|
|
67
|
+
"signals",
|
|
68
|
+
"inspector",
|
|
69
|
+
"surfaceAccent",
|
|
70
|
+
);
|
|
71
|
+
return this.columns(left, right, leftWidth);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private renderValidation(width: number, state: AdaptiveLayoutState): string[] {
|
|
75
|
+
const phase = state.gsdPhase ?? "Validation pending";
|
|
76
|
+
return this.frame(
|
|
77
|
+
[
|
|
78
|
+
this.metric("Focus", phase, "modeValidation"),
|
|
79
|
+
this.metric("Checks", state.activeToolCount > 0 ? `${state.activeToolCount} active` : "waiting", "toolRunning"),
|
|
80
|
+
this.metric("Timeline", state.lastError ? "blocked" : "ready for completion evidence", state.lastError ? "toolError" : "toolSuccess"),
|
|
81
|
+
],
|
|
82
|
+
width,
|
|
83
|
+
"validation",
|
|
84
|
+
state.override === "auto" ? "auto" : state.override,
|
|
85
|
+
"modeValidation",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private renderDebug(width: number, state: AdaptiveLayoutState): string[] {
|
|
90
|
+
const error = state.lastError ?? "Blocking error detected";
|
|
91
|
+
return this.frame(
|
|
92
|
+
[
|
|
93
|
+
this.metric("Failure", truncateToWidth(error, Math.max(20, width - 20), ""), "toolError"),
|
|
94
|
+
this.metric("Tools", state.activeToolCount > 0 ? `${state.activeToolCount} still running` : "none running", "toolRunning"),
|
|
95
|
+
this.metric("Next", "inspect the failed output, then retry the smallest step", "modeDebug"),
|
|
96
|
+
],
|
|
97
|
+
width,
|
|
98
|
+
"blocking failure",
|
|
99
|
+
"debug",
|
|
100
|
+
"modeDebug",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private renderChat(width: number, state: AdaptiveLayoutState): string[] {
|
|
105
|
+
return this.frame(
|
|
106
|
+
[
|
|
107
|
+
this.metric("Mode", state.override === "auto" ? "auto chat" : state.override, "surfaceAccent"),
|
|
108
|
+
this.metric("Tools", state.activeToolCount > 0 ? `${state.activeToolCount} active` : "compact rows", "toolMuted"),
|
|
109
|
+
],
|
|
110
|
+
width,
|
|
111
|
+
"chat",
|
|
112
|
+
state.sessionName ?? "conversation",
|
|
113
|
+
"surfaceAccent",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private renderCompact(width: number, mode: TuiMode, state: AdaptiveLayoutState): string[] {
|
|
118
|
+
const phase = state.lastError ?? state.gsdPhase ?? (state.activeToolCount > 0 ? `${state.activeToolCount} tools` : "ready");
|
|
119
|
+
const line = `${theme.fg("modeCompact", "GSD compact")} ${theme.fg("surfaceMuted", `${mode} · ${phase}`)}`;
|
|
120
|
+
return style()
|
|
121
|
+
.border("minimal")
|
|
122
|
+
.borderColor((text) => theme.fg("surfaceBorder", text))
|
|
123
|
+
.bodyGutter(" ")
|
|
124
|
+
.render([line], width);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private frame(lines: string[], width: number, title: string, rightTitle: string, accent: ThemeColor): string[] {
|
|
128
|
+
return style()
|
|
129
|
+
.border("rule")
|
|
130
|
+
.density("compact")
|
|
131
|
+
.toneColor((text) => theme.fg("surfaceMuted", text))
|
|
132
|
+
.borderColor((text) => theme.fg("surfaceBorder", text))
|
|
133
|
+
.title(theme.fg("surfaceTitle", title))
|
|
134
|
+
.rightTitle(theme.fg(accent, rightTitle))
|
|
135
|
+
.bodyGutter(theme.fg(accent, "│ "))
|
|
136
|
+
.render(lines, width);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private metric(label: string, value: string, color: ThemeColor): string {
|
|
140
|
+
return `${theme.fg("surfaceMuted", `${label.padEnd(8)} `)}${theme.fg(color, value)}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private columns(left: string[], right: string[], leftWidth: number): string[] {
|
|
144
|
+
const rows = Math.max(left.length, right.length);
|
|
145
|
+
const output: string[] = [];
|
|
146
|
+
for (let i = 0; i < rows; i++) {
|
|
147
|
+
const leftLine = left[i] ?? "";
|
|
148
|
+
const rightLine = right[i] ?? "";
|
|
149
|
+
const gap = " ".repeat(Math.max(2, leftWidth - visibleWidth(leftLine) + 2));
|
|
150
|
+
output.push(`${leftLine}${gap}${rightLine}`);
|
|
151
|
+
}
|
|
152
|
+
return output;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private basename(cwd: string): string {
|
|
156
|
+
const trimmed = cwd.replace(/\/+$/, "");
|
|
157
|
+
const slash = trimmed.lastIndexOf("/");
|
|
158
|
+
return slash === -1 ? trimmed : trimmed.slice(slash + 1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// GSD2 TUI - Assistant message card renderer for interactive terminal sessions.
|
|
1
2
|
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
2
3
|
import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
|
|
3
4
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// GSD2 TUI - Shared chat frame renderer for assistant, user, and system cards.
|
|
2
|
+
import { style, truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
2
3
|
import { theme } from "../theme/theme.js";
|
|
3
4
|
import { formatTimestamp, type TimestampFormat } from "./timestamp.js";
|
|
4
5
|
|
|
@@ -34,7 +35,7 @@ export function renderChatFrame(
|
|
|
34
35
|
: "borderAccent";
|
|
35
36
|
const borderMuted = isPurple ? "customMessageLabel" : "borderMuted";
|
|
36
37
|
const border = (s: string) => theme.fg(borderColor, s);
|
|
37
|
-
const leftRaw =
|
|
38
|
+
const leftRaw = opts.label;
|
|
38
39
|
const rightRaw =
|
|
39
40
|
opts.showTimestamp === false || !opts.timestamp
|
|
40
41
|
? ""
|
|
@@ -67,21 +68,21 @@ export function renderChatFrame(
|
|
|
67
68
|
const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
|
|
68
69
|
const headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));
|
|
69
70
|
|
|
70
|
-
const sourceLines = trimOuterBlankLines(contentLines);
|
|
71
71
|
const bodyColor =
|
|
72
72
|
opts.tone === "user"
|
|
73
73
|
? "userMessageText"
|
|
74
74
|
: isPurple
|
|
75
75
|
? "customMessageText"
|
|
76
76
|
: "assistantMessageText";
|
|
77
|
+
const sourceLines = trimOuterBlankLines(contentLines);
|
|
77
78
|
const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
|
|
78
79
|
const clipped = truncateToWidth(line, contentWidth, "");
|
|
79
|
-
return
|
|
80
|
+
return theme.fg(bodyColor, clipped);
|
|
80
81
|
});
|
|
81
82
|
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
return style()
|
|
84
|
+
.border("rule")
|
|
85
|
+
.borderColor((line) => (line.startsWith("─") ? theme.fg(borderMuted, line) : border(line)))
|
|
86
|
+
.title(headerRow + " ".repeat(headerPad))
|
|
87
|
+
.render(bodyLines, outerWidth);
|
|
87
88
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@gsd/pi-agent-core";
|
|
2
2
|
import type { Transport } from "@gsd/pi-ai";
|
|
3
|
+
import type { AdaptiveTuiMode } from "../../../core/settings-manager.js";
|
|
3
4
|
import {
|
|
4
5
|
Container,
|
|
5
6
|
getCapabilities,
|
|
@@ -46,6 +47,7 @@ export interface SettingsConfig {
|
|
|
46
47
|
quietStartup: boolean;
|
|
47
48
|
clearOnShrink: boolean;
|
|
48
49
|
timestampFormat: "date-time-iso" | "date-time-us";
|
|
50
|
+
adaptiveMode: AdaptiveTuiMode;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
export interface SettingsCallbacks {
|
|
@@ -71,6 +73,7 @@ export interface SettingsCallbacks {
|
|
|
71
73
|
onQuietStartupChange: (enabled: boolean) => void;
|
|
72
74
|
onClearOnShrinkChange: (enabled: boolean) => void;
|
|
73
75
|
onTimestampFormatChange: (format: "date-time-iso" | "date-time-us") => void;
|
|
76
|
+
onAdaptiveModeChange: (mode: AdaptiveTuiMode) => void;
|
|
74
77
|
onCancel: () => void;
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -367,6 +370,15 @@ export class SettingsSelectorComponent extends Container {
|
|
|
367
370
|
values: ["date-time-iso", "date-time-us"],
|
|
368
371
|
});
|
|
369
372
|
|
|
373
|
+
const timestampIndex = items.findIndex((item) => item.id === "timestamp-format");
|
|
374
|
+
items.splice(timestampIndex + 1, 0, {
|
|
375
|
+
id: "adaptive-mode",
|
|
376
|
+
label: "TUI adaptive mode",
|
|
377
|
+
description: "Auto-select or force the terminal layout mode",
|
|
378
|
+
currentValue: config.adaptiveMode,
|
|
379
|
+
values: ["auto", "chat", "workflow", "validation", "debug", "compact"],
|
|
380
|
+
});
|
|
381
|
+
|
|
370
382
|
// Add borders
|
|
371
383
|
this.addChild(new DynamicBorder());
|
|
372
384
|
|
|
@@ -435,6 +447,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
435
447
|
case "timestamp-format":
|
|
436
448
|
callbacks.onTimestampFormatChange(newValue as "date-time-iso" | "date-time-us");
|
|
437
449
|
break;
|
|
450
|
+
case "adaptive-mode":
|
|
451
|
+
callbacks.onAdaptiveModeChange(newValue as AdaptiveTuiMode);
|
|
452
|
+
break;
|
|
438
453
|
}
|
|
439
454
|
},
|
|
440
455
|
callbacks.onCancel,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// GSD2 TUI Tests - Runtime coverage for tool-card cleanup and success notification rendering.
|
|
1
2
|
// Runtime regression tests for the post-compaction tool-card cleanup and the
|
|
2
3
|
// green-bordered success-notification rendering. Replaces the source-grep
|
|
3
4
|
// `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875
|
|
@@ -74,7 +75,7 @@ function makeMockTUI(): MockTui {
|
|
|
74
75
|
// ─── Bug 1: tool cards stuck in "Running" after compaction ──────────────
|
|
75
76
|
|
|
76
77
|
describe("ToolExecutionComponent post-compaction cleanup", () => {
|
|
77
|
-
it("renders '
|
|
78
|
+
it("renders 'running' status while the tool call has no result", () => {
|
|
78
79
|
// Baseline: a freshly-constructed component (mid-stream) must show
|
|
79
80
|
// the running badge — this is the state we need to flip OUT of when
|
|
80
81
|
// compaction removes the result message.
|
|
@@ -88,12 +89,12 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
|
|
|
88
89
|
);
|
|
89
90
|
const rendered = c.render(60).map(stripAnsi).join("\n");
|
|
90
91
|
assert.ok(
|
|
91
|
-
rendered.includes("
|
|
92
|
-
"freshly constructed component should render '
|
|
92
|
+
rendered.includes("running"),
|
|
93
|
+
"freshly constructed component should render 'running' badge",
|
|
93
94
|
);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
it("markHistoricalNoResult flips a stuck tool card OUT of '
|
|
97
|
+
it("markHistoricalNoResult flips a stuck tool card OUT of 'running'", () => {
|
|
97
98
|
// Real bug: after session-history replay (post-compaction or session
|
|
98
99
|
// switch), tool calls without matching tool_result messages stay in
|
|
99
100
|
// isPartial = true forever. markHistoricalNoResult must produce a
|
|
@@ -111,13 +112,13 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
|
|
|
111
112
|
|
|
112
113
|
const rendered = c.render(60).map(stripAnsi).join("\n");
|
|
113
114
|
assert.ok(
|
|
114
|
-
!rendered.includes("
|
|
115
|
-
"after markHistoricalNoResult, the tool card must NOT render '
|
|
115
|
+
!rendered.includes("running"),
|
|
116
|
+
"after markHistoricalNoResult, the tool card must NOT render 'running' -- got:\n" +
|
|
116
117
|
rendered,
|
|
117
118
|
);
|
|
118
119
|
assert.ok(
|
|
119
|
-
rendered.includes("
|
|
120
|
-
"flipped card should render '
|
|
120
|
+
rendered.includes("success"),
|
|
121
|
+
"flipped card should render 'success' status (no-result success)",
|
|
121
122
|
);
|
|
122
123
|
});
|
|
123
124
|
|
|
@@ -145,7 +146,7 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
|
|
|
145
146
|
);
|
|
146
147
|
|
|
147
148
|
const before = c.render(60).map(stripAnsi).join("\n");
|
|
148
|
-
assert.ok(before.includes("
|
|
149
|
+
assert.ok(before.includes("success"), "after complete(), card shows 'success'");
|
|
149
150
|
|
|
150
151
|
c.markHistoricalNoResult(); // must early-return
|
|
151
152
|
const after = c.render(60).map(stripAnsi).join("\n");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// GSD-2 Interactive Tool Execution Rendering
|
|
1
2
|
import {
|
|
2
3
|
Box,
|
|
3
4
|
Container,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
type ImageDimensions,
|
|
7
8
|
imageFallback,
|
|
8
9
|
Spacer,
|
|
10
|
+
style,
|
|
9
11
|
Text,
|
|
10
12
|
type TUI,
|
|
11
13
|
truncateToWidth,
|
|
@@ -103,13 +105,11 @@ function renderToolFrame(
|
|
|
103
105
|
const outerWidth = Math.max(20, width);
|
|
104
106
|
const contentWidth = Math.max(1, outerWidth - 2); // "│ " + content
|
|
105
107
|
|
|
106
|
-
const borderColor = opts.tone === "error" ? "
|
|
107
|
-
const topColor =
|
|
108
|
-
const labelColor = opts.tone === "error" ? "
|
|
109
|
-
const statusColor = opts.tone === "error" ? "
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
const leftStyled = theme.fg(labelColor, theme.bold(`• ${opts.label}`));
|
|
108
|
+
const borderColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
|
|
109
|
+
const topColor = borderColor;
|
|
110
|
+
const labelColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
|
|
111
|
+
const statusColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
|
|
112
|
+
const leftStyled = theme.fg(labelColor, theme.bold(opts.label));
|
|
113
113
|
const rightStyled = theme.fg(statusColor, opts.status);
|
|
114
114
|
const gap = Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
|
|
115
115
|
const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
|
|
@@ -118,20 +118,52 @@ function renderToolFrame(
|
|
|
118
118
|
const sourceLines = trimOuterBlankLines(contentLines);
|
|
119
119
|
const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
|
|
120
120
|
const clipped = truncateToWidth(line, contentWidth, "");
|
|
121
|
-
return
|
|
121
|
+
return clipped;
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
return style()
|
|
125
|
+
.border("rule")
|
|
126
|
+
.borderColor((line) => theme.fg(line.startsWith("─") ? topColor : borderColor, line))
|
|
127
|
+
.title(headerRow + " ".repeat(headerPad))
|
|
128
|
+
.render(bodyLines, outerWidth);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function renderCollapsedToolRow(
|
|
132
|
+
label: string,
|
|
133
|
+
status: string,
|
|
134
|
+
width: number,
|
|
135
|
+
tone: Extract<ToolFrameTone, "success">,
|
|
136
|
+
): string[] {
|
|
137
|
+
const outerWidth = Math.max(20, width);
|
|
138
|
+
const contentWidth = Math.max(1, outerWidth - 2);
|
|
139
|
+
const statusColor = tone === "success" ? "toolSuccess" : "toolMuted";
|
|
140
|
+
const labelStyled = theme.fg(statusColor, label);
|
|
141
|
+
const statusStyled = theme.fg(statusColor, status);
|
|
142
|
+
const labelWidth = Math.max(1, contentWidth - visibleWidth(statusStyled) - 1);
|
|
143
|
+
const clippedLabel = truncateToWidth(labelStyled, labelWidth, "");
|
|
144
|
+
const gap = Math.max(1, contentWidth - visibleWidth(clippedLabel) - visibleWidth(statusStyled));
|
|
145
|
+
const line = `${clippedLabel}${" ".repeat(gap)}${statusStyled}`;
|
|
146
|
+
return style()
|
|
147
|
+
.border("minimal")
|
|
148
|
+
.borderColor((text) => theme.fg(statusColor, text))
|
|
149
|
+
.render([line], outerWidth);
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
const COMPACT_ARG_VALUE_LIMIT = 60;
|
|
132
153
|
const GENERIC_OUTPUT_PREVIEW_LINES = 10;
|
|
133
154
|
const GENERIC_ARGS_JSON_PREVIEW_LINES = 10;
|
|
134
155
|
|
|
156
|
+
export type ToolExecutionPhase = {
|
|
157
|
+
label: string;
|
|
158
|
+
count: number;
|
|
159
|
+
durationMs: number;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
function formatElapsed(ms: number): string {
|
|
163
|
+
if (ms < 1000) return `${ms}ms`;
|
|
164
|
+
return `${Math.max(1, Math.round(ms / 1000))}s`;
|
|
165
|
+
}
|
|
166
|
+
|
|
135
167
|
/**
|
|
136
168
|
* Format tool args for the generic-renderer fallback. Produces a one-line
|
|
137
169
|
* `k=v, k=v` summary when every value is a primitive that fits inline; falls
|
|
@@ -200,6 +232,8 @@ export class ToolExecutionComponent extends Container {
|
|
|
200
232
|
private toolDefinition?: ToolDefinition;
|
|
201
233
|
private ui: TUI;
|
|
202
234
|
private cwd: string;
|
|
235
|
+
private readonly startedAt = Date.now();
|
|
236
|
+
private endedAt: number | undefined;
|
|
203
237
|
private result?: {
|
|
204
238
|
content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;
|
|
205
239
|
isError: boolean;
|
|
@@ -434,6 +468,9 @@ export class ToolExecutionComponent extends Container {
|
|
|
434
468
|
): void {
|
|
435
469
|
this.result = result;
|
|
436
470
|
this.isPartial = isPartial;
|
|
471
|
+
if (!isPartial) {
|
|
472
|
+
this.endedAt = this.endedAt ?? Date.now();
|
|
473
|
+
}
|
|
437
474
|
if (this.normalizedToolName === "write" && !isPartial) {
|
|
438
475
|
const rawPath = str(this.args?.file_path ?? this.args?.path);
|
|
439
476
|
const fileContent = str(this.args?.content);
|
|
@@ -456,6 +493,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
456
493
|
markHistoricalNoResult(): void {
|
|
457
494
|
if (this.result) return; // real result already set, nothing to do
|
|
458
495
|
this.isPartial = false;
|
|
496
|
+
this.endedAt = this.endedAt ?? Date.now();
|
|
459
497
|
this.result = {
|
|
460
498
|
content: [],
|
|
461
499
|
isError: false,
|
|
@@ -468,6 +506,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
468
506
|
*/
|
|
469
507
|
completeWithError(message?: string): void {
|
|
470
508
|
this.isPartial = false;
|
|
509
|
+
this.endedAt = this.endedAt ?? Date.now();
|
|
471
510
|
if (this.result) {
|
|
472
511
|
let content = this.result.content;
|
|
473
512
|
if (message) {
|
|
@@ -538,14 +577,18 @@ export class ToolExecutionComponent extends Container {
|
|
|
538
577
|
}
|
|
539
578
|
const frameWidth = Math.max(20, width);
|
|
540
579
|
const contentWidth = Math.max(1, frameWidth - 4);
|
|
541
|
-
const lines = super.render(contentWidth);
|
|
542
580
|
const frameTone: ToolFrameTone =
|
|
543
581
|
this.result?.isError ? "error" : this.isPartial || !this.result ? "pending" : "success";
|
|
544
|
-
const
|
|
582
|
+
const elapsed = formatElapsed((this.endedAt ?? Date.now()) - this.startedAt);
|
|
583
|
+
const frameStatus = `${this.isPartial || !this.result ? "running" : this.result.isError ? "failed" : "success"} · ${elapsed}`;
|
|
545
584
|
const parsed = parseMcpToolName(this.toolName);
|
|
546
585
|
const frameLabel = parsed
|
|
547
|
-
?
|
|
548
|
-
:
|
|
586
|
+
? `${parsed.server}·${parsed.tool}`
|
|
587
|
+
: prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown";
|
|
588
|
+
if (this.shouldRenderCompactSuccess()) {
|
|
589
|
+
return ["", ...renderCollapsedToolRow(this.getCompactSummary(frameLabel), frameStatus, frameWidth, "success")];
|
|
590
|
+
}
|
|
591
|
+
const lines = super.render(contentWidth);
|
|
549
592
|
const framed = renderToolFrame(lines, frameWidth, {
|
|
550
593
|
label: frameLabel,
|
|
551
594
|
status: frameStatus,
|
|
@@ -554,6 +597,43 @@ export class ToolExecutionComponent extends Container {
|
|
|
554
597
|
return framed.length > 0 ? ["", ...framed] : framed;
|
|
555
598
|
}
|
|
556
599
|
|
|
600
|
+
private shouldRenderCompactSuccess(): boolean {
|
|
601
|
+
if (this.expanded || this.isPartial || !this.result || this.result.isError) return false;
|
|
602
|
+
const hasImages = this.result.content?.some((block) => block.type === "image") ?? false;
|
|
603
|
+
return !hasImages;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
getRollupPhase(): ToolExecutionPhase | null {
|
|
607
|
+
if (!this.shouldRenderCompactSuccess()) return null;
|
|
608
|
+
const label = this.getPhaseLabel();
|
|
609
|
+
const endedAt = this.endedAt ?? Date.now();
|
|
610
|
+
return {
|
|
611
|
+
label,
|
|
612
|
+
count: 1,
|
|
613
|
+
durationMs: Math.max(0, endedAt - this.startedAt),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
private getPhaseLabel(): string {
|
|
618
|
+
const name = this.normalizedToolName;
|
|
619
|
+
const displayName = prettifyToolName(this.toolName, this.toolDefinition?.label);
|
|
620
|
+
|
|
621
|
+
if (name === "bash") return "Setup / shell";
|
|
622
|
+
if (name === "read" || name === "ls" || name === "find" || name === "grep") return "Context reads";
|
|
623
|
+
if (name === "write" || name === "edit") return "File changes";
|
|
624
|
+
if (name === "web_search" || displayName === "ToolSearch") return "Discovery";
|
|
625
|
+
if (displayName === "Memory Query" || displayName === "Memory Capture" || displayName === "Gsd Graph") {
|
|
626
|
+
return "Memory lookups";
|
|
627
|
+
}
|
|
628
|
+
if (displayName === "Update Requirement" || displayName === "Save Requirement") return "Requirement writes";
|
|
629
|
+
if (displayName.startsWith("Complete ")) return "Finalization";
|
|
630
|
+
return "Other tool actions";
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private getCompactSummary(frameLabel: string): string {
|
|
634
|
+
return frameLabel;
|
|
635
|
+
}
|
|
636
|
+
|
|
557
637
|
private updateDisplay(): void {
|
|
558
638
|
// Tool body now uses transparent background; status is conveyed in the frame header.
|
|
559
639
|
const bgFn = (text: string) => text;
|
|
@@ -1201,3 +1281,24 @@ export class ToolExecutionComponent extends Container {
|
|
|
1201
1281
|
return text;
|
|
1202
1282
|
}
|
|
1203
1283
|
}
|
|
1284
|
+
|
|
1285
|
+
export class ToolPhaseSummaryComponent extends Container {
|
|
1286
|
+
constructor(private readonly phases: ToolExecutionPhase[]) {
|
|
1287
|
+
super();
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
override render(width: number): string[] {
|
|
1291
|
+
const frameWidth = Math.max(20, width);
|
|
1292
|
+
const rows = this.phases.map((phase) => {
|
|
1293
|
+
const left = `${phase.label} ${phase.count} ${phase.count === 1 ? "action" : "actions"}`;
|
|
1294
|
+
const right = `success · ${formatElapsed(phase.durationMs)}`;
|
|
1295
|
+
const contentWidth = Math.max(1, frameWidth - 2);
|
|
1296
|
+
const leftWidth = Math.max(1, contentWidth - visibleWidth(right) - 1);
|
|
1297
|
+
const leftText = truncateToWidth(left, leftWidth, "");
|
|
1298
|
+
const gap = Math.max(1, contentWidth - visibleWidth(leftText) - visibleWidth(right));
|
|
1299
|
+
return `${theme.fg("toolSuccess", leftText)}${" ".repeat(gap)}${theme.fg("toolSuccess", right)}`;
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1302
|
+
return ["", ...style().border("minimal").borderColor((text) => theme.fg("toolSuccess", text)).render(rows, frameWidth)];
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
|
|
4
|
-
import { findLatestPinnableText } from "./chat-controller.js";
|
|
4
|
+
import { findLatestPinnableText, handleAgentEvent } from "./chat-controller.js";
|
|
5
|
+
import { initTheme } from "../theme/theme.js";
|
|
5
6
|
|
|
6
7
|
test("findLatestPinnableText: empty content returns empty string", () => {
|
|
7
8
|
assert.equal(findLatestPinnableText([]), "");
|
|
@@ -69,3 +70,44 @@ test("findLatestPinnableText: thinking blocks are not pinnable", () => {
|
|
|
69
70
|
];
|
|
70
71
|
assert.equal(findLatestPinnableText(blocks), "");
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
test("handleAgentEvent: agent_start clears stale adaptive blocking error", async () => {
|
|
75
|
+
initTheme("dark", false);
|
|
76
|
+
let cleared = false;
|
|
77
|
+
let requestedRender = false;
|
|
78
|
+
const host = {
|
|
79
|
+
isInitialized: true,
|
|
80
|
+
clearBlockingError: () => {
|
|
81
|
+
cleared = true;
|
|
82
|
+
},
|
|
83
|
+
retryEscapeHandler: undefined,
|
|
84
|
+
retryLoader: undefined,
|
|
85
|
+
loadingAnimation: undefined,
|
|
86
|
+
statusContainer: {
|
|
87
|
+
clear() {},
|
|
88
|
+
addChild() {},
|
|
89
|
+
},
|
|
90
|
+
ui: {
|
|
91
|
+
requestRender() {
|
|
92
|
+
requestedRender = true;
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
defaultEditor: {},
|
|
96
|
+
footer: {
|
|
97
|
+
invalidate() {},
|
|
98
|
+
},
|
|
99
|
+
settingsManager: {
|
|
100
|
+
getTimestampFormat() {
|
|
101
|
+
return "date-time-iso";
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
defaultWorkingMessage: "Working...",
|
|
105
|
+
pendingWorkingMessage: undefined,
|
|
106
|
+
} as any;
|
|
107
|
+
|
|
108
|
+
await handleAgentEvent(host, { type: "agent_start" } as any);
|
|
109
|
+
host.loadingAnimation?.stop();
|
|
110
|
+
|
|
111
|
+
assert.equal(cleared, true);
|
|
112
|
+
assert.equal(requestedRender, true);
|
|
113
|
+
});
|