gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.e146beb20
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 +48 -10
- 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/dispatcher.js +5 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- 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 +49 -12
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- 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/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
- 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 +16 -16
- 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 +16 -16
- 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/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- 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/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -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/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- 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 +67 -18
- 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/dispatcher.ts +6 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- 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 +49 -12
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- 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/prompts/plan-slice.md +1 -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/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -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/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- 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/smart-entry-complete.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +7 -0
- 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/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/unit-runtime.ts +14 -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 → y73quA-XdLo9n41nxphjW}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → y73quA-XdLo9n41nxphjW}/_ssgManifest.js +0 -0
|
@@ -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
|
+
});
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
// GSD-2 Interactive Chat Controller
|
|
1
2
|
import { Loader, Markdown, Spacer, Text } from "@gsd/pi-tui";
|
|
2
3
|
|
|
3
4
|
import type { InteractiveModeEvent, InteractiveModeStateHost } from "../interactive-mode-state.js";
|
|
4
5
|
import { theme } from "../theme/theme.js";
|
|
5
6
|
import { AssistantMessageComponent } from "../components/assistant-message.js";
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ToolExecutionComponent,
|
|
9
|
+
ToolPhaseSummaryComponent,
|
|
10
|
+
type ToolExecutionPhase,
|
|
11
|
+
} from "../components/tool-execution.js";
|
|
7
12
|
import { DynamicBorder } from "../components/dynamic-border.js";
|
|
8
13
|
import { appKey } from "../components/keybinding-hints.js";
|
|
9
14
|
|
|
@@ -100,6 +105,71 @@ let pinnedBorder: DynamicBorder | undefined;
|
|
|
100
105
|
// Reference to the pinned markdown component below the border
|
|
101
106
|
let pinnedTextComponent: Markdown | undefined;
|
|
102
107
|
|
|
108
|
+
function mergeToolPhases(phases: ToolExecutionPhase[]): ToolExecutionPhase[] {
|
|
109
|
+
const merged: ToolExecutionPhase[] = [];
|
|
110
|
+
for (const phase of phases) {
|
|
111
|
+
const previous = merged[merged.length - 1];
|
|
112
|
+
if (previous?.label === phase.label) {
|
|
113
|
+
previous.count += phase.count;
|
|
114
|
+
previous.durationMs += phase.durationMs;
|
|
115
|
+
} else {
|
|
116
|
+
merged.push({ ...phase });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return merged;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function replaceCompactToolRowsWithPhaseSummary(
|
|
123
|
+
host: InteractiveModeStateHost & { ui: { requestRender: () => void } },
|
|
124
|
+
): void {
|
|
125
|
+
let changed = false;
|
|
126
|
+
const nextRenderedSegments: RenderedSegment[] = [];
|
|
127
|
+
let rollupRun: Array<{ seg: Extract<RenderedSegment, { kind: "tool" }>; phase: ToolExecutionPhase }> = [];
|
|
128
|
+
|
|
129
|
+
const flushRollupRun = () => {
|
|
130
|
+
if (rollupRun.length < 2) {
|
|
131
|
+
nextRenderedSegments.push(...rollupRun.map((item) => item.seg));
|
|
132
|
+
rollupRun = [];
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const firstIndex = Math.max(0, host.chatContainer.children.indexOf(rollupRun[0].seg.component));
|
|
137
|
+
const summary = new ToolPhaseSummaryComponent(mergeToolPhases(rollupRun.map((item) => item.phase)));
|
|
138
|
+
|
|
139
|
+
for (const { seg } of rollupRun) {
|
|
140
|
+
host.chatContainer.removeChild(seg.component);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
host.chatContainer.addChild(summary);
|
|
144
|
+
const summaryIndex = host.chatContainer.children.indexOf(summary);
|
|
145
|
+
if (summaryIndex !== -1 && summaryIndex !== firstIndex) {
|
|
146
|
+
host.chatContainer.children.splice(summaryIndex, 1);
|
|
147
|
+
host.chatContainer.children.splice(firstIndex, 0, summary);
|
|
148
|
+
(host.chatContainer as unknown as { _prevRender: string[] | null })._prevRender = null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
changed = true;
|
|
152
|
+
rollupRun = [];
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
for (const seg of renderedSegments) {
|
|
156
|
+
const phase = seg.kind === "tool" ? seg.component.getRollupPhase() : null;
|
|
157
|
+
if (seg.kind === "tool" && phase) {
|
|
158
|
+
rollupRun.push({ seg, phase });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
flushRollupRun();
|
|
163
|
+
nextRenderedSegments.push(seg);
|
|
164
|
+
}
|
|
165
|
+
flushRollupRun();
|
|
166
|
+
|
|
167
|
+
if (changed) {
|
|
168
|
+
renderedSegments = nextRenderedSegments;
|
|
169
|
+
host.ui.requestRender();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
103
173
|
export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
104
174
|
init: () => Promise<void>;
|
|
105
175
|
getMarkdownThemeWithSettings: () => any;
|
|
@@ -177,6 +247,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
177
247
|
return;
|
|
178
248
|
}
|
|
179
249
|
case "agent_start":
|
|
250
|
+
host.clearBlockingError();
|
|
180
251
|
if (host.retryEscapeHandler) {
|
|
181
252
|
host.defaultEditor.onEscape = host.retryEscapeHandler;
|
|
182
253
|
host.retryEscapeHandler = undefined;
|
|
@@ -772,6 +843,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
772
843
|
host.streamingComponent.setShowMetadata(true);
|
|
773
844
|
host.streamingComponent.updateContent(host.streamingMessage);
|
|
774
845
|
}
|
|
846
|
+
replaceCompactToolRowsWithPhaseSummary(host);
|
|
775
847
|
|
|
776
848
|
if (host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error") {
|
|
777
849
|
if (!errorMessage) {
|
|
@@ -822,6 +894,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
822
894
|
component.setExpanded(host.toolOutputExpanded);
|
|
823
895
|
host.chatContainer.addChild(component);
|
|
824
896
|
host.pendingTools.set(event.toolCallId, component);
|
|
897
|
+
renderedSegments.push({ kind: "tool", contentIndex: Number.MAX_SAFE_INTEGER, component });
|
|
825
898
|
host.ui.requestRender();
|
|
826
899
|
}
|
|
827
900
|
break;
|
|
@@ -855,6 +928,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|
|
855
928
|
host.streamingComponent.setShowMetadata(true);
|
|
856
929
|
host.streamingComponent.updateContent(host.streamingMessage);
|
|
857
930
|
}
|
|
931
|
+
replaceCompactToolRowsWithPhaseSummary(host);
|
|
858
932
|
host.streamingComponent = undefined;
|
|
859
933
|
host.streamingMessage = undefined;
|
|
860
934
|
renderedSegments = [];
|
|
@@ -20,6 +20,7 @@ export interface InteractiveModeStateHost {
|
|
|
20
20
|
isInitialized: boolean;
|
|
21
21
|
loadingAnimation?: any;
|
|
22
22
|
pendingWorkingMessage?: string;
|
|
23
|
+
clearBlockingError(): void;
|
|
23
24
|
defaultWorkingMessage: string;
|
|
24
25
|
streamingComponent?: any;
|
|
25
26
|
streamingMessage?: any;
|
|
@@ -37,4 +38,3 @@ export interface InteractiveModeStateHost {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export type InteractiveModeEvent = AgentSessionEvent;
|
|
40
|
-
|
|
@@ -64,6 +64,7 @@ import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/cha
|
|
|
64
64
|
import { readClipboardImage } from "../../utils/clipboard-image.js";
|
|
65
65
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
66
66
|
import { AssistantMessageComponent } from "./components/assistant-message.js";
|
|
67
|
+
import { AdaptiveLayoutComponent } from "./components/adaptive-layout.js";
|
|
67
68
|
import { BashExecutionComponent } from "./components/bash-execution.js";
|
|
68
69
|
import { BorderedLoader } from "./components/bordered-loader.js";
|
|
69
70
|
import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
|
|
@@ -246,6 +247,7 @@ export class InteractiveMode {
|
|
|
246
247
|
private ui: TUI;
|
|
247
248
|
private chatContainer: Container;
|
|
248
249
|
private pendingMessagesContainer: Container;
|
|
250
|
+
private adaptiveLayout: AdaptiveLayoutComponent;
|
|
249
251
|
private statusContainer: Container;
|
|
250
252
|
private pinnedMessageContainer: Container;
|
|
251
253
|
private defaultEditor: CustomEditor;
|
|
@@ -261,6 +263,7 @@ export class InteractiveMode {
|
|
|
261
263
|
private loadingAnimation: Loader | undefined = undefined;
|
|
262
264
|
private pendingWorkingMessage: string | undefined = undefined;
|
|
263
265
|
private readonly defaultWorkingMessage = "Working...";
|
|
266
|
+
private lastBlockingError: string | undefined = undefined;
|
|
264
267
|
|
|
265
268
|
private lastSigintTime = 0;
|
|
266
269
|
private lastEscapeTime = 0;
|
|
@@ -367,6 +370,14 @@ export class InteractiveMode {
|
|
|
367
370
|
this.headerContainer = new Container();
|
|
368
371
|
this.chatContainer = new Container();
|
|
369
372
|
this.pendingMessagesContainer = new Container();
|
|
373
|
+
this.adaptiveLayout = new AdaptiveLayoutComponent(() => ({
|
|
374
|
+
override: this.settingsManager.getAdaptiveMode(),
|
|
375
|
+
activeToolCount: this.pendingTools.size,
|
|
376
|
+
gsdPhase: this.pendingWorkingMessage,
|
|
377
|
+
lastError: this.lastBlockingError,
|
|
378
|
+
sessionName: this.sessionManager.getSessionName(),
|
|
379
|
+
cwd: process.cwd(),
|
|
380
|
+
}));
|
|
370
381
|
this.statusContainer = new Container();
|
|
371
382
|
this.pinnedMessageContainer = new Container();
|
|
372
383
|
this.widgetContainerAbove = new Container();
|
|
@@ -571,6 +582,7 @@ export class InteractiveMode {
|
|
|
571
582
|
}
|
|
572
583
|
}
|
|
573
584
|
|
|
585
|
+
this.ui.addChild(this.adaptiveLayout);
|
|
574
586
|
this.ui.addChild(this.chatContainer);
|
|
575
587
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
576
588
|
this.ui.addChild(this.statusContainer);
|
|
@@ -1221,6 +1233,7 @@ export class InteractiveMode {
|
|
|
1221
1233
|
this.streamingComponent = undefined;
|
|
1222
1234
|
this.streamingMessage = undefined;
|
|
1223
1235
|
this.pendingTools.clear();
|
|
1236
|
+
this.clearBlockingError();
|
|
1224
1237
|
|
|
1225
1238
|
// Render any messages added via setup, or show empty session
|
|
1226
1239
|
this.renderInitialMessages();
|
|
@@ -2880,11 +2893,16 @@ export class InteractiveMode {
|
|
|
2880
2893
|
}
|
|
2881
2894
|
|
|
2882
2895
|
showError(errorMessage: string): void {
|
|
2896
|
+
this.lastBlockingError = errorMessage;
|
|
2883
2897
|
this.chatContainer.addChild(new Spacer(1));
|
|
2884
2898
|
this.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage}`), 1, 0));
|
|
2885
2899
|
this.ui.requestRender();
|
|
2886
2900
|
}
|
|
2887
2901
|
|
|
2902
|
+
clearBlockingError(): void {
|
|
2903
|
+
this.lastBlockingError = undefined;
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2888
2906
|
showWarning(warningMessage: string): void {
|
|
2889
2907
|
this.chatContainer.addChild(new Spacer(1));
|
|
2890
2908
|
this.chatContainer.addChild(new Text(theme.fg("warning", `Warning: ${warningMessage}`), 1, 0));
|
|
@@ -3195,6 +3213,7 @@ export class InteractiveMode {
|
|
|
3195
3213
|
quietStartup: this.settingsManager.getQuietStartup(),
|
|
3196
3214
|
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
3197
3215
|
timestampFormat: this.settingsManager.getTimestampFormat(),
|
|
3216
|
+
adaptiveMode: this.settingsManager.getAdaptiveMode(),
|
|
3198
3217
|
},
|
|
3199
3218
|
{
|
|
3200
3219
|
onAutoCompactChange: (enabled) => {
|
|
@@ -3301,6 +3320,10 @@ export class InteractiveMode {
|
|
|
3301
3320
|
onTimestampFormatChange: (format) => {
|
|
3302
3321
|
this.settingsManager.setTimestampFormat(format);
|
|
3303
3322
|
},
|
|
3323
|
+
onAdaptiveModeChange: (mode) => {
|
|
3324
|
+
this.settingsManager.setAdaptiveMode(mode);
|
|
3325
|
+
this.ui.requestRender();
|
|
3326
|
+
},
|
|
3304
3327
|
onCancel: () => {
|
|
3305
3328
|
done();
|
|
3306
3329
|
this.ui.requestRender();
|
|
@@ -3689,6 +3712,7 @@ export class InteractiveMode {
|
|
|
3689
3712
|
this.streamingComponent = undefined;
|
|
3690
3713
|
this.streamingMessage = undefined;
|
|
3691
3714
|
this.pendingTools.clear();
|
|
3715
|
+
this.clearBlockingError();
|
|
3692
3716
|
|
|
3693
3717
|
// Switch session via AgentSession (emits extension session events)
|
|
3694
3718
|
await this.session.switchSession(sessionPath);
|
|
@@ -4010,6 +4034,7 @@ export class InteractiveMode {
|
|
|
4010
4034
|
this.streamingMessage = undefined;
|
|
4011
4035
|
this.pendingTools.clear();
|
|
4012
4036
|
this.pendingImages.length = 0;
|
|
4037
|
+
this.clearBlockingError();
|
|
4013
4038
|
|
|
4014
4039
|
// Reset contextual tips for the new session
|
|
4015
4040
|
this.contextualTips.reset();
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// GSD2 - Slash command tests for interactive TUI settings commands
|
|
2
|
+
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { describe, it } from "node:test";
|
|
5
|
+
import { Container } from "@gsd/pi-tui";
|
|
6
|
+
import { SettingsManager } from "../../core/settings-manager.js";
|
|
7
|
+
import { dispatchSlashCommand, type SlashCommandContext } from "./slash-command-handlers.js";
|
|
8
|
+
|
|
9
|
+
function makeContext(settingsManager = SettingsManager.inMemory()): SlashCommandContext {
|
|
10
|
+
const statuses: string[] = [];
|
|
11
|
+
const warnings: string[] = [];
|
|
12
|
+
const renders: string[] = [];
|
|
13
|
+
return {
|
|
14
|
+
session: {} as never,
|
|
15
|
+
ui: {} as never,
|
|
16
|
+
keybindings: {} as never,
|
|
17
|
+
chatContainer: new Container(),
|
|
18
|
+
statusContainer: new Container(),
|
|
19
|
+
editorContainer: new Container(),
|
|
20
|
+
headerContainer: new Container(),
|
|
21
|
+
pendingMessagesContainer: new Container(),
|
|
22
|
+
editor: {} as never,
|
|
23
|
+
defaultEditor: {} as never,
|
|
24
|
+
sessionManager: {} as never,
|
|
25
|
+
settingsManager,
|
|
26
|
+
invalidateFooter() {},
|
|
27
|
+
showStatus(message: string) {
|
|
28
|
+
statuses.push(message);
|
|
29
|
+
},
|
|
30
|
+
showError(message: string) {
|
|
31
|
+
throw new Error(message);
|
|
32
|
+
},
|
|
33
|
+
showWarning(message: string) {
|
|
34
|
+
warnings.push(message);
|
|
35
|
+
},
|
|
36
|
+
showSelector() {},
|
|
37
|
+
updateEditorBorderColor() {},
|
|
38
|
+
getMarkdownThemeWithSettings: () => ({} as never),
|
|
39
|
+
requestRender() {
|
|
40
|
+
renders.push("render");
|
|
41
|
+
},
|
|
42
|
+
updateTerminalTitle() {},
|
|
43
|
+
showSettingsSelector() {},
|
|
44
|
+
showModelsSelector: async () => {},
|
|
45
|
+
handleModelCommand: async () => {},
|
|
46
|
+
showUserMessageSelector() {},
|
|
47
|
+
showTreeSelector() {},
|
|
48
|
+
showProviderManager() {},
|
|
49
|
+
showOAuthSelector: async () => {},
|
|
50
|
+
showSessionSelector() {},
|
|
51
|
+
handleClearCommand: async () => {},
|
|
52
|
+
handleReloadCommand: async () => {},
|
|
53
|
+
handleDebugCommand() {},
|
|
54
|
+
shutdown: async () => {},
|
|
55
|
+
executeCompaction: async () => undefined,
|
|
56
|
+
handleBashCommand: async () => {},
|
|
57
|
+
_testStatuses: statuses,
|
|
58
|
+
_testWarnings: warnings,
|
|
59
|
+
_testRenders: renders,
|
|
60
|
+
} as SlashCommandContext & {
|
|
61
|
+
_testStatuses: string[];
|
|
62
|
+
_testWarnings: string[];
|
|
63
|
+
_testRenders: string[];
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe("dispatchSlashCommand /tui", () => {
|
|
68
|
+
it("persists /tui mode validation to terminal adaptive mode", async () => {
|
|
69
|
+
const settingsManager = SettingsManager.inMemory();
|
|
70
|
+
const ctx = makeContext(settingsManager) as SlashCommandContext & {
|
|
71
|
+
_testStatuses: string[];
|
|
72
|
+
_testRenders: string[];
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const handled = await dispatchSlashCommand("/tui mode validation", ctx);
|
|
76
|
+
|
|
77
|
+
assert.equal(handled, true);
|
|
78
|
+
assert.equal(settingsManager.getAdaptiveMode(), "validation");
|
|
79
|
+
assert.deepEqual(ctx._testStatuses, ["TUI mode: validation"]);
|
|
80
|
+
assert.equal(ctx._testRenders.length, 1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("rejects unknown TUI modes without changing settings", async () => {
|
|
84
|
+
const settingsManager = SettingsManager.inMemory({ terminal: { adaptiveMode: "workflow" } });
|
|
85
|
+
const ctx = makeContext(settingsManager) as SlashCommandContext & {
|
|
86
|
+
_testWarnings: string[];
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handled = await dispatchSlashCommand("/tui mode poster", ctx);
|
|
90
|
+
|
|
91
|
+
assert.equal(handled, true);
|
|
92
|
+
assert.equal(settingsManager.getAdaptiveMode(), "workflow");
|
|
93
|
+
assert.match(ctx._testWarnings[0], /Usage: \/tui mode/);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
import type { AgentSession } from "../../core/agent-session.js";
|
|
32
32
|
import type { AppAction, KeybindingsManager } from "../../core/keybindings.js";
|
|
33
33
|
import type { SessionManager } from "../../core/session-manager.js";
|
|
34
|
-
import type { SettingsManager } from "../../core/settings-manager.js";
|
|
34
|
+
import type { AdaptiveTuiMode, SettingsManager } from "../../core/settings-manager.js";
|
|
35
35
|
import { copyToClipboard } from "../../utils/clipboard.js";
|
|
36
36
|
import { getChangelogPath, parseChangelog } from "../../utils/changelog.js";
|
|
37
37
|
import { ArminComponent } from "./components/armin.js";
|
|
@@ -235,6 +235,10 @@ export async function dispatchSlashCommand(
|
|
|
235
235
|
await ctx.handleBashCommand(command, { loginShell: true });
|
|
236
236
|
return true;
|
|
237
237
|
}
|
|
238
|
+
if (text === "/tui" || text.startsWith("/tui ")) {
|
|
239
|
+
handleTuiCommand(text, ctx);
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
238
242
|
|
|
239
243
|
return false;
|
|
240
244
|
}
|
|
@@ -665,6 +669,25 @@ function handleEditModeCommand(arg: string | undefined, ctx: SlashCommandContext
|
|
|
665
669
|
ctx.showStatus(`Edit mode: ${next}${next === "hashline" ? " (LINE#ID anchored edits)" : " (text-match edits)"}`);
|
|
666
670
|
}
|
|
667
671
|
|
|
672
|
+
function handleTuiCommand(text: string, ctx: SlashCommandContext): void {
|
|
673
|
+
const parts = text.trim().split(/\s+/);
|
|
674
|
+
const mode = parts[1] === "mode" ? parts[2] : parts[1];
|
|
675
|
+
const valid: AdaptiveTuiMode[] = ["auto", "chat", "workflow", "validation", "debug", "compact"];
|
|
676
|
+
|
|
677
|
+
if (!mode) {
|
|
678
|
+
ctx.showStatus(`TUI mode: ${ctx.settingsManager.getAdaptiveMode()}`);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
if (!valid.includes(mode as AdaptiveTuiMode)) {
|
|
682
|
+
ctx.showWarning(`Usage: /tui mode ${valid.join("|")}`);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
ctx.settingsManager.setAdaptiveMode(mode as AdaptiveTuiMode);
|
|
687
|
+
ctx.showStatus(`TUI mode: ${mode}`);
|
|
688
|
+
ctx.requestRender();
|
|
689
|
+
}
|
|
690
|
+
|
|
668
691
|
function handleArminSaysHi(ctx: SlashCommandContext): void {
|
|
669
692
|
ctx.chatContainer.addChild(new Spacer(1));
|
|
670
693
|
ctx.chatContainer.addChild(new ArminComponent(ctx.ui));
|
|
@@ -70,6 +70,19 @@ export const ThemeJsonSchema = Type.Object({
|
|
|
70
70
|
thinkingXhigh: ColorValueSchema,
|
|
71
71
|
// Bash Mode (1 color)
|
|
72
72
|
bashMode: ColorValueSchema,
|
|
73
|
+
// Adaptive TUI semantic tokens (optional; defaults are derived from core colors)
|
|
74
|
+
surfaceBorder: Type.Optional(ColorValueSchema),
|
|
75
|
+
surfaceMuted: Type.Optional(ColorValueSchema),
|
|
76
|
+
surfaceTitle: Type.Optional(ColorValueSchema),
|
|
77
|
+
surfaceAccent: Type.Optional(ColorValueSchema),
|
|
78
|
+
toolRunning: Type.Optional(ColorValueSchema),
|
|
79
|
+
toolSuccess: Type.Optional(ColorValueSchema),
|
|
80
|
+
toolError: Type.Optional(ColorValueSchema),
|
|
81
|
+
toolMuted: Type.Optional(ColorValueSchema),
|
|
82
|
+
modeWorkflow: Type.Optional(ColorValueSchema),
|
|
83
|
+
modeValidation: Type.Optional(ColorValueSchema),
|
|
84
|
+
modeDebug: Type.Optional(ColorValueSchema),
|
|
85
|
+
modeCompact: Type.Optional(ColorValueSchema),
|
|
73
86
|
}),
|
|
74
87
|
export: Type.Optional(
|
|
75
88
|
Type.Object({
|