@bastani/atomic 0.8.13-0 → 0.8.14-0
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/CHANGELOG.md +24 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/host-html-template.ts +1 -1
- package/dist/builtin/mcp/init.ts +15 -2
- package/dist/builtin/mcp/mcp-callback-server.ts +10 -9
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/ui-session.ts +9 -6
- package/dist/builtin/subagents/CHANGELOG.md +8 -1
- package/dist/builtin/subagents/README.md +39 -32
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
- package/dist/builtin/subagents/src/agents/agent-management.ts +6 -1
- package/dist/builtin/subagents/src/agents/agent-serializer.ts +2 -0
- package/dist/builtin/subagents/src/agents/agents.ts +44 -19
- package/dist/builtin/subagents/src/extension/config.ts +16 -0
- package/dist/builtin/subagents/src/extension/fanout-child.ts +246 -0
- package/dist/builtin/subagents/src/extension/index.ts +466 -603
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +6 -4
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +109 -1
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +124 -19
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +41 -6
- package/dist/builtin/subagents/src/runs/background/async-resume.ts +28 -15
- package/dist/builtin/subagents/src/runs/background/async-status.ts +60 -30
- package/dist/builtin/subagents/src/runs/background/result-watcher.ts +111 -54
- package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +83 -0
- package/dist/builtin/subagents/src/runs/background/run-status.ts +79 -3
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +46 -1
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +66 -14
- package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +10 -3
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +14 -2
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +320 -23
- package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +23 -1
- package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +369 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events.ts +935 -0
- package/dist/builtin/subagents/src/runs/shared/nested-path.ts +52 -0
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +115 -0
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +82 -9
- package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/single-output.ts +12 -2
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +32 -10
- package/dist/builtin/subagents/src/runs/shared/worktree.ts +3 -2
- package/dist/builtin/subagents/src/shared/artifacts.ts +0 -1
- package/dist/builtin/subagents/src/shared/types.ts +96 -1
- package/dist/builtin/subagents/src/shared/utils.ts +10 -2
- package/dist/builtin/subagents/src/slash/slash-commands.ts +468 -625
- package/dist/builtin/subagents/src/tui/render.ts +1227 -2093
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +24 -0
- package/dist/builtin/workflows/README.md +28 -11
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +323 -40
- package/dist/builtin/workflows/builtin/ralph.ts +362 -176
- package/dist/builtin/workflows/package.json +2 -5
- package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
- package/dist/builtin/workflows/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/builtin/workflows/skills/skill-creator/SKILL.md +489 -0
- package/dist/builtin/workflows/skills/skill-creator/agents/analyzer.md +274 -0
- package/dist/builtin/workflows/skills/skill-creator/agents/comparator.md +202 -0
- package/dist/builtin/workflows/skills/skill-creator/agents/grader.md +223 -0
- package/dist/builtin/workflows/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/builtin/workflows/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/dist/builtin/workflows/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/dist/builtin/workflows/skills/skill-creator/references/schemas.md +430 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/__init__.py +0 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/generate_report.py +326 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/improve_description.py +247 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/package_skill.py +136 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/run_eval.py +310 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/run_loop.py +328 -0
- package/dist/builtin/workflows/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/builtin/workflows/src/extension/index.ts +869 -93
- package/dist/builtin/workflows/src/extension/render-call.ts +34 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +126 -21
- package/dist/builtin/workflows/src/extension/runtime.ts +91 -3
- package/dist/builtin/workflows/src/extension/wiring.ts +38 -12
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +62 -5
- package/dist/builtin/workflows/src/runs/background/runner.ts +3 -3
- package/dist/builtin/workflows/src/runs/background/status.ts +42 -8
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +410 -95
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +5 -2
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +8 -0
- package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +6 -4
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +3 -2
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +138 -5
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +30 -0
- package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +78 -120
- package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +193 -0
- package/dist/builtin/workflows/src/shared/store-types.ts +26 -1
- package/dist/builtin/workflows/src/shared/store.ts +145 -17
- package/dist/builtin/workflows/src/shared/timing.ts +6 -2
- package/dist/builtin/workflows/src/shared/workflow-failures.ts +375 -0
- package/dist/builtin/workflows/src/tui/chat-surface.ts +68 -17
- package/dist/builtin/workflows/src/tui/connectors.ts +2 -2
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +24 -26
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +4 -8
- package/dist/builtin/workflows/src/tui/graph-view.ts +17 -14
- package/dist/builtin/workflows/src/tui/header.ts +38 -0
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +161 -238
- package/dist/builtin/workflows/src/tui/inline-form-editor.ts +68 -73
- package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +2 -3
- package/dist/builtin/workflows/src/tui/inline-form-store.ts +2 -1
- package/dist/builtin/workflows/src/tui/inputs-overlay.ts +1 -3
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +286 -399
- package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +11 -0
- package/dist/builtin/workflows/src/tui/node-card.ts +2 -1
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -1
- package/dist/builtin/workflows/src/tui/prompt-card.ts +46 -19
- package/dist/builtin/workflows/src/tui/run-detail.ts +63 -80
- package/dist/builtin/workflows/src/tui/session-confirm.ts +9 -3
- package/dist/builtin/workflows/src/tui/session-picker.ts +19 -16
- package/dist/builtin/workflows/src/tui/stage-chat-layout.ts +88 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +368 -879
- package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +67 -75
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +50 -12
- package/dist/builtin/workflows/src/tui/submit-pane.ts +164 -0
- package/dist/builtin/workflows/src/tui/switcher.ts +27 -4
- package/dist/builtin/workflows/src/tui/text-helpers.ts +98 -4
- package/dist/builtin/workflows/src/tui/widget.ts +90 -68
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +23 -2
- package/dist/builtin/workflows/src/tui/workflow-list.ts +44 -68
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -3
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -10
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -2
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +16 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +8 -9
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +2 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +8 -6
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.js +6 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +12 -29
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +5 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts +8 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +145 -58
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +6 -20
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +38 -31
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +9 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +32 -24
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -15
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +8 -22
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +5 -4
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js +34 -11
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +1 -0
- package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/projections.js +1 -0
- package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.d.ts +1 -2
- package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.js +26 -9
- package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/state.d.ts +4 -0
- package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts +1 -0
- package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +9 -6
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +28 -7
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/props-adapter.js +4 -1
- package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +56 -53
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +3 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +8 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +3 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +44 -81
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +27 -12
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +2 -3
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +3 -3
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -5
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +2 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +11 -4
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts +2 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js +39 -21
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +9 -8
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +12 -2
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +20 -35
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts +24 -0
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -0
- package/dist/modes/interactive/chat-input-actions.js +179 -0
- package/dist/modes/interactive/chat-input-actions.js.map +1 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +14 -3
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +157 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host.js +1007 -0
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -0
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +14 -5
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +9 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +29 -4
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +18 -67
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/child-process.d.ts +1 -0
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +8 -0
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +3 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js +14 -8
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts +30 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -0
- package/dist/utils/image-resize-core.js +124 -0
- package/dist/utils/image-resize-core.js.map +1 -0
- package/dist/utils/image-resize-worker.d.ts +2 -0
- package/dist/utils/image-resize-worker.d.ts.map +1 -0
- package/dist/utils/image-resize-worker.js +31 -0
- package/dist/utils/image-resize-worker.js.map +1 -0
- package/dist/utils/image-resize.d.ts +7 -27
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +75 -115
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/paths.d.ts +16 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +49 -7
- package/dist/utils/paths.js.map +1 -1
- package/docs/changelog.mdx +29 -0
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +2 -2
- package/docs/development.md +1 -1
- package/docs/docs.json +98 -143
- package/docs/extensions.md +29 -16
- package/docs/favicon.svg +29 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/images/tree-view.png +0 -0
- package/docs/images/workflow-command.png +0 -0
- package/docs/images/workflow-graph.png +0 -0
- package/docs/images/workflow-input-picker.png +0 -0
- package/docs/images/workflow-list.png +0 -0
- package/docs/index.md +10 -1
- package/docs/logo.svg +59 -0
- package/docs/packages.md +3 -3
- package/docs/providers.md +1 -1
- package/docs/quickstart.md +98 -2
- package/docs/rpc.md +8 -8
- package/docs/sdk.md +23 -12
- package/docs/sessions.md +1 -1
- package/docs/skills.md +15 -1
- package/docs/termux.md +11 -1
- package/docs/themes.md +6 -6
- package/docs/tui.md +18 -18
- package/docs/usage.md +1 -1
- package/docs/workflows.md +172 -2
- package/examples/extensions/subagent/index.ts +2 -1
- package/package.json +6 -6
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/SKILL.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/element-attributes.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/playwright-tests.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/request-mocking.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/running-code.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/session-management.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/spec-driven-testing.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/storage-state.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/test-generation.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/tracing.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/video-recording.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/SKILL.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/deep-modules.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/interface-design.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/mocking.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/refactoring.md +0 -0
- /package/dist/builtin/{workflows → subagents}/skills/tdd/tests.md +0 -0
|
@@ -38,6 +38,17 @@ export interface KeybindingsLike {
|
|
|
38
38
|
matches(data: string, action: string): boolean;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export const TUI_ACTION = {
|
|
42
|
+
editorCursorUp: "tui.editor.cursorUp",
|
|
43
|
+
editorCursorDown: "tui.editor.cursorDown",
|
|
44
|
+
editorCursorLeft: "tui.editor.cursorLeft",
|
|
45
|
+
editorCursorRight: "tui.editor.cursorRight",
|
|
46
|
+
inputSubmit: "tui.input.submit",
|
|
47
|
+
selectUp: "tui.select.up",
|
|
48
|
+
selectDown: "tui.select.down",
|
|
49
|
+
selectConfirm: "tui.select.confirm",
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
41
52
|
/** Runtime guard for hosts that wire the keybindings manager. */
|
|
42
53
|
export function isKeybindingsLike(kb: unknown): kb is KeybindingsLike {
|
|
43
54
|
return (
|
|
@@ -71,6 +71,8 @@ function pickBorder(
|
|
|
71
71
|
return theme.error;
|
|
72
72
|
case "blocked":
|
|
73
73
|
return theme.dim;
|
|
74
|
+
case "skipped":
|
|
75
|
+
return theme.dim;
|
|
74
76
|
case "pending":
|
|
75
77
|
default:
|
|
76
78
|
// Pending has no semantic colour; the focused-tab carries the
|
|
@@ -117,7 +119,6 @@ function durationText(stage: StageSnapshot): string {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
function metaText(stage: StageSnapshot): string {
|
|
120
|
-
if (stage.model) return stage.model;
|
|
121
122
|
const deps = stage.parentIds.length;
|
|
122
123
|
if (deps === 0) return "root";
|
|
123
124
|
return deps === 1 ? "1 dep" : `${deps} deps`;
|
|
@@ -23,6 +23,7 @@ import { destroyRun } from "../runs/background/status.js";
|
|
|
23
23
|
import { cancellationRegistry } from "../runs/background/cancellation-registry.js";
|
|
24
24
|
import { stageControlRegistry as defaultStageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
25
25
|
import type { StageControlRegistry } from "../runs/foreground/stage-control-registry.js";
|
|
26
|
+
import type { StageUiBroker } from "../shared/stage-ui-broker.js";
|
|
26
27
|
import type {
|
|
27
28
|
PiCustomComponent,
|
|
28
29
|
PiCustomOverlayFactoryTui,
|
|
@@ -35,7 +36,7 @@ import type {
|
|
|
35
36
|
PiTheme,
|
|
36
37
|
} from "../extension/wiring.js";
|
|
37
38
|
|
|
38
|
-
export type OverlayChatRenderSettings = Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd"
|
|
39
|
+
export type OverlayChatRenderSettings = Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd">>;
|
|
39
40
|
|
|
40
41
|
export interface OverlayUISurface {
|
|
41
42
|
custom?: PiCustomOverlayFunction;
|
|
@@ -105,6 +106,8 @@ export interface BuildGraphOverlayAdapterOpts {
|
|
|
105
106
|
* Defaults to the singleton registry registered alongside the store.
|
|
106
107
|
*/
|
|
107
108
|
stageControlRegistry?: StageControlRegistry;
|
|
109
|
+
/** Broker used to route stage-local custom UI into attached stage chats. */
|
|
110
|
+
stageUiBroker?: StageUiBroker;
|
|
108
111
|
/**
|
|
109
112
|
* Destructive kill hook used by graph-mode `q`. The extension factory
|
|
110
113
|
* supplies this so persistence can record a terminal event before the run is
|
|
@@ -119,6 +122,7 @@ export function buildGraphOverlayAdapter(
|
|
|
119
122
|
buildOpts: BuildGraphOverlayAdapterOpts = {},
|
|
120
123
|
): GraphOverlayPort {
|
|
121
124
|
const registry = buildOpts.stageControlRegistry ?? defaultStageControlRegistry;
|
|
125
|
+
const stageUiBroker = buildOpts.stageUiBroker;
|
|
122
126
|
const killRun = buildOpts.onKillRun ?? ((id: string): void => {
|
|
123
127
|
destroyRun(id, { store, cancellation: cancellationRegistry });
|
|
124
128
|
});
|
|
@@ -161,6 +165,7 @@ export function buildGraphOverlayAdapter(
|
|
|
161
165
|
function hideMounted(): void {
|
|
162
166
|
setMouseScrollTracking(false);
|
|
163
167
|
if (currentHandle) {
|
|
168
|
+
currentView?.setVisible(false);
|
|
164
169
|
currentHandle.setHidden(true);
|
|
165
170
|
currentHandle.unfocus();
|
|
166
171
|
return;
|
|
@@ -203,6 +208,7 @@ export function buildGraphOverlayAdapter(
|
|
|
203
208
|
// Already mounted but hidden — flip visibility without remounting.
|
|
204
209
|
if (mounted && currentHandle?.isHidden()) {
|
|
205
210
|
currentView?.retarget(runId, stageId);
|
|
211
|
+
currentView?.setVisible(true);
|
|
206
212
|
setMouseScrollTracking(currentView?.wantsMouseScrollTracking() ?? true);
|
|
207
213
|
currentHandle.setHidden(false);
|
|
208
214
|
currentHandle.focus();
|
|
@@ -242,6 +248,7 @@ export function buildGraphOverlayAdapter(
|
|
|
242
248
|
graphTheme: deriveGraphThemeFromPiTheme(theme),
|
|
243
249
|
runId,
|
|
244
250
|
stageControlRegistry: registry,
|
|
251
|
+
stageUiBroker,
|
|
245
252
|
uiStatus,
|
|
246
253
|
onClose: finish,
|
|
247
254
|
onHide: hideMounted,
|
|
@@ -296,6 +303,7 @@ export function buildGraphOverlayAdapter(
|
|
|
296
303
|
// no scroll-pollution).
|
|
297
304
|
if (mounted && currentHandle) {
|
|
298
305
|
const nowHidden = !currentHandle.isHidden();
|
|
306
|
+
currentView?.setVisible(!nowHidden);
|
|
299
307
|
setMouseScrollTracking(
|
|
300
308
|
nowHidden ? false : currentView?.wantsMouseScrollTracking() ?? true,
|
|
301
309
|
);
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* │ │
|
|
13
13
|
* │ <message> │
|
|
14
14
|
* │ │
|
|
15
|
-
* │
|
|
15
|
+
* │ ╭ response ─────────────────────────────╮ │
|
|
16
16
|
* │ │ <text input / choice cycler> │ │
|
|
17
|
-
* │
|
|
17
|
+
* │ ╰───────────────────────────────────────╯ │
|
|
18
18
|
* │ │
|
|
19
19
|
* │ ↵ submit · esc skip │
|
|
20
20
|
* ╰───────────────────────────────────────────────╯
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import type { PendingPrompt } from "../shared/store-types.js";
|
|
38
38
|
import type { GraphTheme } from "./graph-theme.js";
|
|
39
39
|
import { hexToAnsi, hexBg, paint, RESET, BOLD } from "./color-utils.js";
|
|
40
|
-
import { matchesKey } from "./text-helpers.js";
|
|
40
|
+
import { Key, matchesKey } from "./text-helpers.js";
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
43
|
// State
|
|
@@ -99,7 +99,7 @@ export function handlePromptCardInput(
|
|
|
99
99
|
data: string,
|
|
100
100
|
state: PromptCardState,
|
|
101
101
|
): PromptCardAction {
|
|
102
|
-
if (matchesKey(data, "
|
|
102
|
+
if (matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.escape)) {
|
|
103
103
|
return { kind: "cancel" };
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -119,17 +119,17 @@ function handleConfirm(
|
|
|
119
119
|
data: string,
|
|
120
120
|
state: PromptCardState,
|
|
121
121
|
): PromptCardAction {
|
|
122
|
-
if (matchesKey(data,
|
|
122
|
+
if (matchesKey(data, Key.left) || matchesKey(data, Key.right) || matchesKey(data, Key.space) || matchesKey(data, Key.tab)) {
|
|
123
123
|
state.confirmValue = !state.confirmValue;
|
|
124
124
|
return { kind: "noop" };
|
|
125
125
|
}
|
|
126
|
-
if (data
|
|
126
|
+
if (matchesKey(data, "y") || matchesKey(data, Key.shift("y"))) {
|
|
127
127
|
return { kind: "submit", response: true };
|
|
128
128
|
}
|
|
129
|
-
if (data
|
|
129
|
+
if (matchesKey(data, "n") || matchesKey(data, Key.shift("n"))) {
|
|
130
130
|
return { kind: "submit", response: false };
|
|
131
131
|
}
|
|
132
|
-
if (matchesKey(data,
|
|
132
|
+
if (matchesKey(data, Key.enter)) {
|
|
133
133
|
return { kind: "submit", response: state.confirmValue };
|
|
134
134
|
}
|
|
135
135
|
return { kind: "noop" };
|
|
@@ -138,7 +138,7 @@ function handleConfirm(
|
|
|
138
138
|
function handleSelect(data: string, state: PromptCardState): PromptCardAction {
|
|
139
139
|
const choices = state.prompt.choices ?? [];
|
|
140
140
|
if (choices.length === 0) {
|
|
141
|
-
if (matchesKey(data,
|
|
141
|
+
if (matchesKey(data, Key.enter)) {
|
|
142
142
|
return { kind: "submit", response: "" };
|
|
143
143
|
}
|
|
144
144
|
return { kind: "noop" };
|
|
@@ -155,24 +155,24 @@ function handleSelect(data: string, state: PromptCardState): PromptCardAction {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
function handleInput(data: string, state: PromptCardState): PromptCardAction {
|
|
158
|
-
if (matchesKey(data,
|
|
158
|
+
if (matchesKey(data, Key.enter)) {
|
|
159
159
|
return { kind: "submit", response: state.rawText };
|
|
160
160
|
}
|
|
161
161
|
return applyTextEdit(data, state);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
function handleEditor(data: string, state: PromptCardState): PromptCardAction {
|
|
165
|
-
if (matchesKey(data,
|
|
165
|
+
if (matchesKey(data, Key.tab) || matchesKey(data, Key.shift("tab"))) {
|
|
166
166
|
state.editorSubmitFocused = !state.editorSubmitFocused;
|
|
167
167
|
return { kind: "noop" };
|
|
168
168
|
}
|
|
169
169
|
if (state.editorSubmitFocused) {
|
|
170
|
-
if (matchesKey(data,
|
|
170
|
+
if (matchesKey(data, Key.enter)) {
|
|
171
171
|
return { kind: "submit", response: state.rawText };
|
|
172
172
|
}
|
|
173
173
|
return { kind: "noop" };
|
|
174
174
|
}
|
|
175
|
-
if (matchesKey(data,
|
|
175
|
+
if (matchesKey(data, Key.enter)) {
|
|
176
176
|
state.rawText = state.rawText.slice(0, state.caret) + "\n" + state.rawText.slice(state.caret);
|
|
177
177
|
state.caret += 1;
|
|
178
178
|
return { kind: "noop" };
|
|
@@ -184,15 +184,15 @@ function applyTextEdit(
|
|
|
184
184
|
data: string,
|
|
185
185
|
state: PromptCardState,
|
|
186
186
|
): PromptCardAction {
|
|
187
|
-
if (matchesKey(data,
|
|
187
|
+
if (matchesKey(data, Key.left)) {
|
|
188
188
|
state.caret = previousGraphemeBoundary(state.rawText, state.caret);
|
|
189
189
|
return { kind: "noop" };
|
|
190
190
|
}
|
|
191
|
-
if (matchesKey(data,
|
|
191
|
+
if (matchesKey(data, Key.right)) {
|
|
192
192
|
state.caret = nextGraphemeBoundary(state.rawText, state.caret);
|
|
193
193
|
return { kind: "noop" };
|
|
194
194
|
}
|
|
195
|
-
if (matchesKey(data,
|
|
195
|
+
if (matchesKey(data, Key.backspace)) {
|
|
196
196
|
if (state.caret > 0) {
|
|
197
197
|
const prev = previousGraphemeBoundary(state.rawText, state.caret);
|
|
198
198
|
state.rawText = state.rawText.slice(0, prev) + state.rawText.slice(state.caret);
|
|
@@ -335,8 +335,8 @@ function normalizeSelectKeyData(data: string): string {
|
|
|
335
335
|
// The historical prompt card accepted left/right as select aliases; feed the
|
|
336
336
|
// corresponding vertical key into pi-tui's SelectList so it owns the actual
|
|
337
337
|
// wrap/clamp/selection update behavior.
|
|
338
|
-
if (matchesKey(data,
|
|
339
|
-
if (matchesKey(data,
|
|
338
|
+
if (matchesKey(data, Key.right)) return "\x1b[B";
|
|
339
|
+
if (matchesKey(data, Key.left)) return "\x1b[A";
|
|
340
340
|
return data;
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -372,7 +372,7 @@ export function renderPromptCard(opts: PromptCardRenderOpts): string[] {
|
|
|
372
372
|
}
|
|
373
373
|
lines.push(makePaddedRow(bg, borderColor, innerWidth, ""));
|
|
374
374
|
|
|
375
|
-
const fieldLines =
|
|
375
|
+
const fieldLines = renderResponseFieldBox(state, theme, innerWidth - 4, opts.cursorOn);
|
|
376
376
|
for (const fl of fieldLines) {
|
|
377
377
|
lines.push(makePaddedRow(bg, borderColor, innerWidth, " " + fl));
|
|
378
378
|
}
|
|
@@ -424,6 +424,33 @@ function wrapText(text: string, width: number): string[] {
|
|
|
424
424
|
return wrapTextWithAnsi(text, width);
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
+
function renderResponseFieldBox(
|
|
428
|
+
state: PromptCardState,
|
|
429
|
+
theme: GraphTheme,
|
|
430
|
+
usable: number,
|
|
431
|
+
cursorOn: boolean,
|
|
432
|
+
): string[] {
|
|
433
|
+
const boxWidth = Math.max(4, usable);
|
|
434
|
+
const contentWidth = Math.max(1, boxWidth - 2);
|
|
435
|
+
const borderColor = theme.accent;
|
|
436
|
+
const label = " response ";
|
|
437
|
+
const labelText = paint(label, theme.textMuted, { bold: true });
|
|
438
|
+
const labelW = visibleWidth(labelText);
|
|
439
|
+
const topFill = Math.max(0, boxWidth - labelW - 2);
|
|
440
|
+
const rows = renderResponseField(state, theme, contentWidth, cursorOn);
|
|
441
|
+
return [
|
|
442
|
+
paint("╭", borderColor) + labelText + paint("─".repeat(topFill) + "╮", borderColor),
|
|
443
|
+
...rows.map((row) => makeFieldRow(row, contentWidth, borderColor)),
|
|
444
|
+
paint("╰" + "─".repeat(Math.max(0, boxWidth - 2)) + "╯", borderColor),
|
|
445
|
+
];
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function makeFieldRow(content: string, width: number, borderColor: string): string {
|
|
449
|
+
const clipped = truncateToWidth(content, width, "", true);
|
|
450
|
+
const padded = clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
|
|
451
|
+
return paint("│", borderColor) + padded + paint("│", borderColor);
|
|
452
|
+
}
|
|
453
|
+
|
|
427
454
|
function renderResponseField(
|
|
428
455
|
state: PromptCardState,
|
|
429
456
|
theme: GraphTheme,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-run detail block
|
|
2
|
+
* Per-run detail block surface.
|
|
3
3
|
*
|
|
4
4
|
* Pairs with the status-list overview ({@link renderSessionList}) and the
|
|
5
|
-
* above-editor widget. Emits a
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* above-editor widget. Emits a rounded run panel, key/value run summary,
|
|
6
|
+
* rounded stage/artifact cards, all rendered against the canonical
|
|
7
|
+
* Catppuccin Mocha palette.
|
|
8
8
|
*
|
|
9
9
|
* Two output modes:
|
|
10
10
|
* - **themed** ANSI Catppuccin chrome (theme supplied)
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* cross-ref:
|
|
14
14
|
* - github.com/nicobailon/pi-subagents src/runs/background/run-status.ts
|
|
15
15
|
* inspectSubagentStatus — the source UX pattern
|
|
16
|
-
* - DESIGN.md §5 Section Labels
|
|
16
|
+
* - DESIGN.md §5 Section Labels
|
|
17
17
|
* - orchestrator-panel-ui.png — band-header chrome
|
|
18
18
|
*/
|
|
19
19
|
|
|
@@ -21,8 +21,8 @@ import type { RunDetail } from "../runs/background/status.js";
|
|
|
21
21
|
import type { StageSnapshot } from "../shared/store-types.js";
|
|
22
22
|
import { elapsedRunMs, elapsedStageMs } from "../shared/timing.js";
|
|
23
23
|
import type { GraphTheme } from "./graph-theme.js";
|
|
24
|
-
import {
|
|
25
|
-
import type {
|
|
24
|
+
import { renderRoundedBox } from "./chat-surface.js";
|
|
25
|
+
import type { FlatBandBadge } from "./chat-surface.js";
|
|
26
26
|
import { fmtDuration, statusIcon, statusColor } from "./status-helpers.js";
|
|
27
27
|
import { hexToAnsi, RESET, BOLD } from "./color-utils.js";
|
|
28
28
|
import { truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
@@ -62,58 +62,44 @@ function renderPlain(detail: RunDetail, now: number, width: number): string {
|
|
|
62
62
|
|
|
63
63
|
const sid = shortId(detail.runId);
|
|
64
64
|
const stateBadge = stateLabel(detail);
|
|
65
|
-
const innerLabel = ` RUN ${sid} `;
|
|
66
|
-
const inner = "─".repeat(innerLabel.length);
|
|
67
|
-
out.push(` ╭${inner}╮`);
|
|
68
|
-
const headerTailW = visibleWidth(` │${innerLabel}│ `) + visibleWidth(` ${stateBadge}`);
|
|
69
|
-
const headerName = truncateToWidth(detail.name, Math.max(1, width - headerTailW), "…");
|
|
70
|
-
out.push(` │${innerLabel}│ ${headerName} ${stateBadge}`);
|
|
71
|
-
out.push(` ╰${inner}╯`);
|
|
72
|
-
out.push("");
|
|
73
65
|
|
|
74
|
-
// Summary key/value lines
|
|
75
66
|
for (const [k, v] of summaryRows(detail, now)) {
|
|
76
67
|
if (v === undefined) continue;
|
|
77
|
-
const value = truncateToWidth(v, Math.max(1, width -
|
|
78
|
-
out.push(`
|
|
68
|
+
const value = truncateToWidth(v, Math.max(1, width - 4 - KEY_COL), "…");
|
|
69
|
+
out.push(` ${pad(k, KEY_COL)}${value} `);
|
|
79
70
|
}
|
|
80
71
|
out.push("");
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
out.push("▎ STAGES");
|
|
84
|
-
out.push("");
|
|
73
|
+
out.push(" STAGES ");
|
|
85
74
|
if (detail.stages.length === 0) {
|
|
86
|
-
out.push(" (no stages recorded yet)");
|
|
75
|
+
out.push(" (no stages recorded yet) ");
|
|
87
76
|
} else {
|
|
88
77
|
for (const stage of detail.stages) {
|
|
89
|
-
out.push(
|
|
90
|
-
if (stage.error) {
|
|
91
|
-
const err = truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - STAGE_NAME_COL - 11), "…");
|
|
92
|
-
out.push(` ${" ".repeat(STAGE_NAME_COL + 2)}error ${err}`);
|
|
93
|
-
}
|
|
78
|
+
out.push(...renderStageRowsPlain(stage, now, width - 4));
|
|
94
79
|
}
|
|
95
80
|
}
|
|
96
81
|
out.push("");
|
|
97
82
|
|
|
98
|
-
// Artifacts (best-effort: result + error)
|
|
99
83
|
const artifactRows = artifactRowsFor(detail);
|
|
100
84
|
if (artifactRows.length > 0) {
|
|
101
|
-
out.push("
|
|
102
|
-
out.push("");
|
|
85
|
+
out.push(" ARTIFACTS ");
|
|
103
86
|
for (const [k, v] of artifactRows) {
|
|
104
|
-
out.push(`
|
|
87
|
+
out.push(` ${pad(k, KEY_COL)}${truncateToWidth(v, Math.max(1, width - 4 - KEY_COL), "…")} `);
|
|
105
88
|
}
|
|
106
89
|
out.push("");
|
|
107
90
|
}
|
|
108
91
|
|
|
109
|
-
// Action hints
|
|
110
92
|
if (detail.endedAt === undefined) {
|
|
111
|
-
out.push(truncateToWidth(`
|
|
93
|
+
out.push(truncateToWidth(` ▸ workflow interrupt id=${sid} cancel `, width - 2, "…"));
|
|
112
94
|
} else {
|
|
113
|
-
out.push(truncateToWidth(`
|
|
95
|
+
out.push(truncateToWidth(` ▸ workflow resume id=${sid} reopen graph `, width - 2, "…"));
|
|
114
96
|
}
|
|
115
97
|
|
|
116
|
-
return
|
|
98
|
+
return renderRoundedBox({
|
|
99
|
+
title: `RUN ${sid} ${detail.name} ${stateBadge}`,
|
|
100
|
+
bodyLines: out,
|
|
101
|
+
width,
|
|
102
|
+
});
|
|
117
103
|
}
|
|
118
104
|
|
|
119
105
|
// ---------------------------------------------------------------------------
|
|
@@ -122,7 +108,6 @@ function renderPlain(detail: RunDetail, now: number, width: number): string {
|
|
|
122
108
|
|
|
123
109
|
function renderThemed(detail: RunDetail, now: number, theme: GraphTheme, width: number): string {
|
|
124
110
|
const out: string[] = [];
|
|
125
|
-
const mauve = hexToAnsi(theme.mauve);
|
|
126
111
|
const muted = hexToAnsi(theme.textMuted);
|
|
127
112
|
const dim = hexToAnsi(theme.dim);
|
|
128
113
|
const text = hexToAnsi(theme.text);
|
|
@@ -130,68 +115,51 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme, width:
|
|
|
130
115
|
|
|
131
116
|
const sid = shortId(detail.runId);
|
|
132
117
|
const badges = stateBadges(detail, theme);
|
|
133
|
-
// Band-header chrome lives within ~64 cells regardless of terminal width so
|
|
134
|
-
// it visually echoes the orchestrator overlay (which never spans the whole
|
|
135
|
-
// pane horizontally either).
|
|
136
|
-
out.push(...renderBandHeader({
|
|
137
|
-
label: `RUN ${sid}`,
|
|
138
|
-
subtitle: detail.name,
|
|
139
|
-
badges,
|
|
140
|
-
width: Math.min(64, width),
|
|
141
|
-
theme,
|
|
142
|
-
}));
|
|
143
|
-
out.push("");
|
|
144
118
|
|
|
145
|
-
// Summary key/value
|
|
146
119
|
for (const [k, v] of summaryRows(detail, now)) {
|
|
147
120
|
if (v === undefined) continue;
|
|
148
|
-
const value = truncateToWidth(v, Math.max(1, width -
|
|
149
|
-
out.push(`
|
|
121
|
+
const value = truncateToWidth(v, Math.max(1, width - 4 - KEY_COL), "…");
|
|
122
|
+
out.push(` ${muted}${pad(k, KEY_COL)}${RESET}${text}${value}${RESET} `);
|
|
150
123
|
}
|
|
151
124
|
out.push("");
|
|
152
125
|
|
|
153
|
-
|
|
154
|
-
out.push(`${mauve}▎${RESET} ${muted}${BOLD}STAGES${RESET}`);
|
|
155
|
-
out.push("");
|
|
126
|
+
out.push(` ${muted}${BOLD}STAGES${RESET} `);
|
|
156
127
|
if (detail.stages.length === 0) {
|
|
157
|
-
out.push(` ${dim}(no stages recorded yet)${RESET}`);
|
|
128
|
+
out.push(` ${dim}(no stages recorded yet)${RESET} `);
|
|
158
129
|
} else {
|
|
159
130
|
for (const stage of detail.stages) {
|
|
160
|
-
out.push(
|
|
161
|
-
if (stage.error) {
|
|
162
|
-
const errFg = hexToAnsi(theme.error);
|
|
163
|
-
const err = truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - STAGE_NAME_COL - 13), "…");
|
|
164
|
-
out.push(
|
|
165
|
-
` ${" ".repeat(STAGE_NAME_COL + 2)}${muted}error${RESET} ${errFg}${err}${RESET}`,
|
|
166
|
-
);
|
|
167
|
-
}
|
|
131
|
+
out.push(...renderStageRowsThemed(stage, now, theme, width - 4));
|
|
168
132
|
}
|
|
169
133
|
}
|
|
170
134
|
out.push("");
|
|
171
135
|
|
|
172
|
-
// Artifacts section
|
|
173
136
|
const artifactRows = artifactRowsFor(detail);
|
|
174
137
|
if (artifactRows.length > 0) {
|
|
175
|
-
out.push(
|
|
176
|
-
out.push("");
|
|
138
|
+
out.push(` ${muted}${BOLD}ARTIFACTS${RESET} `);
|
|
177
139
|
for (const [k, v] of artifactRows) {
|
|
178
|
-
out.push(`
|
|
140
|
+
out.push(` ${muted}${pad(k, KEY_COL)}${RESET}${dim}${truncateToWidth(v, Math.max(1, width - 4 - KEY_COL), "…")}${RESET} `);
|
|
179
141
|
}
|
|
180
142
|
out.push("");
|
|
181
143
|
}
|
|
182
144
|
|
|
183
|
-
// Action hints
|
|
184
145
|
if (detail.endedAt === undefined) {
|
|
185
146
|
out.push(
|
|
186
|
-
truncateToWidth(`
|
|
147
|
+
truncateToWidth(` ${dim}▸${RESET} ${accent}workflow interrupt id=${sid}${RESET}${dim} cancel${RESET} `, width - 2, "…"),
|
|
187
148
|
);
|
|
188
149
|
} else {
|
|
189
150
|
out.push(
|
|
190
|
-
truncateToWidth(`
|
|
151
|
+
truncateToWidth(` ${dim}▸${RESET} ${accent}workflow resume id=${sid}${RESET}${dim} reopen graph${RESET} `, width - 2, "…"),
|
|
191
152
|
);
|
|
192
153
|
}
|
|
193
154
|
|
|
194
|
-
|
|
155
|
+
const badgeText = badges.length > 0 ? ` ${badges.map((b) => b.text).join(" ")}` : "";
|
|
156
|
+
return renderRoundedBox({
|
|
157
|
+
title: `RUN ${sid} ${detail.name}${badgeText}`,
|
|
158
|
+
bodyLines: out,
|
|
159
|
+
accent: theme.accent,
|
|
160
|
+
theme,
|
|
161
|
+
width,
|
|
162
|
+
});
|
|
195
163
|
}
|
|
196
164
|
|
|
197
165
|
// ---------------------------------------------------------------------------
|
|
@@ -199,19 +167,16 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme, width:
|
|
|
199
167
|
// ---------------------------------------------------------------------------
|
|
200
168
|
|
|
201
169
|
function summaryRows(detail: RunDetail, now: number): Array<[string, string | undefined]> {
|
|
202
|
-
const startedAgo = formatRelative(now - detail.startedAt);
|
|
203
|
-
const updatedAt = detail.endedAt ?? detail.startedAt;
|
|
204
|
-
const updatedAgo = formatRelative(now - updatedAt);
|
|
205
170
|
const duration = elapsedRunMs(detail, now);
|
|
206
171
|
|
|
207
172
|
const rows: Array<[string, string | undefined]> = [
|
|
208
173
|
["workflow", detail.name],
|
|
209
174
|
["state", statePlain(detail)],
|
|
210
175
|
["mode", detail.mode === "chain" ? `chain · ${detail.stages.length} stages` : "single"],
|
|
211
|
-
["started",
|
|
176
|
+
["started", formatTime(detail.startedAt)],
|
|
212
177
|
];
|
|
213
178
|
if (detail.endedAt !== undefined) {
|
|
214
|
-
rows.push(["ended",
|
|
179
|
+
rows.push(["ended", formatTime(detail.endedAt)]);
|
|
215
180
|
rows.push(["duration", fmtDuration(duration)]);
|
|
216
181
|
} else {
|
|
217
182
|
rows.push(["elapsed", fmtDuration(duration)]);
|
|
@@ -276,6 +241,28 @@ function stageLineThemed(stage: StageSnapshot, now: number, theme: GraphTheme, w
|
|
|
276
241
|
);
|
|
277
242
|
}
|
|
278
243
|
|
|
244
|
+
function renderStageRowsPlain(stage: StageSnapshot, now: number, width: number): string[] {
|
|
245
|
+
const rows = [` ${stageLinePlain(stage, now, Math.max(1, width - 2))} `];
|
|
246
|
+
if (stage.error) {
|
|
247
|
+
rows.push(` error ${truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - 10), "…")} `);
|
|
248
|
+
}
|
|
249
|
+
return rows;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function renderStageRowsThemed(
|
|
253
|
+
stage: StageSnapshot,
|
|
254
|
+
now: number,
|
|
255
|
+
theme: GraphTheme,
|
|
256
|
+
width: number,
|
|
257
|
+
): string[] {
|
|
258
|
+
const rows = [` ${stageLineThemed(stage, now, theme, Math.max(1, width - 2))} `];
|
|
259
|
+
if (stage.error) {
|
|
260
|
+
const errFg = hexToAnsi(theme.error);
|
|
261
|
+
rows.push(` ${hexToAnsi(theme.textMuted)}error${RESET} ${errFg}${truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - 12), "…")}${RESET} `);
|
|
262
|
+
}
|
|
263
|
+
return rows;
|
|
264
|
+
}
|
|
265
|
+
|
|
279
266
|
function stageDurationString(stage: StageSnapshot, now: number): string | undefined {
|
|
280
267
|
const elapsed = elapsedStageMs(stage, now);
|
|
281
268
|
return elapsed === undefined ? undefined : fmtDuration(elapsed);
|
|
@@ -298,7 +285,7 @@ function stageActivityString(stage: StageSnapshot): string | undefined {
|
|
|
298
285
|
// State badges + plain-text equivalents
|
|
299
286
|
// ---------------------------------------------------------------------------
|
|
300
287
|
|
|
301
|
-
function stateBadges(detail: RunDetail, theme: GraphTheme):
|
|
288
|
+
function stateBadges(detail: RunDetail, theme: GraphTheme): FlatBandBadge[] {
|
|
302
289
|
switch (detail.status) {
|
|
303
290
|
case "running":
|
|
304
291
|
return [{ text: "● running", fg: theme.warning }];
|
|
@@ -350,7 +337,3 @@ function formatTime(ms: number): string {
|
|
|
350
337
|
const ss = String(d.getUTCSeconds()).padStart(2, "0");
|
|
351
338
|
return `${hh}:${mm}:${ss}`;
|
|
352
339
|
}
|
|
353
|
-
|
|
354
|
-
function formatRelative(ms: number): string {
|
|
355
|
-
return fmtDuration(Math.max(0, ms));
|
|
356
|
-
}
|
|
@@ -193,12 +193,18 @@ export function handleKillConfirmInput(
|
|
|
193
193
|
state: KillConfirmState,
|
|
194
194
|
): KillConfirmAction {
|
|
195
195
|
// Direct shortcuts bypass focus.
|
|
196
|
-
if (data
|
|
197
|
-
if (data
|
|
196
|
+
if (matchesKey(data, "y") || matchesKey(data, Key.shift("y"))) return { kind: "confirm" };
|
|
197
|
+
if (matchesKey(data, "n") || matchesKey(data, Key.shift("n"))) return { kind: "cancel" };
|
|
198
198
|
if (matchesKey(data, Key.escape)) return { kind: "cancel" };
|
|
199
199
|
|
|
200
200
|
// Tab / arrows toggle focus.
|
|
201
|
-
if (
|
|
201
|
+
if (
|
|
202
|
+
matchesKey(data, Key.tab) ||
|
|
203
|
+
matchesKey(data, Key.right) ||
|
|
204
|
+
matchesKey(data, Key.left) ||
|
|
205
|
+
matchesKey(data, "h") ||
|
|
206
|
+
matchesKey(data, "l")
|
|
207
|
+
) {
|
|
202
208
|
state.focusedButton = state.focusedButton === 0 ? 1 : 0;
|
|
203
209
|
return { kind: "noop" };
|
|
204
210
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Visual contract (DESIGN.md §5 Picker Rows + pi-subagents/src/tui/render-helpers.ts):
|
|
6
6
|
* - Rounded `╭─ Title ─╮` chrome in `border` colour with title in `accent`.
|
|
7
|
-
* - Section header rows use
|
|
7
|
+
* - Section header rows use a simple two-space label indent (matches GraphView).
|
|
8
8
|
* - Selected row: `picker-row-selected` token (blue bg, surface0 fg, bold).
|
|
9
9
|
* - Footer: dim hints, active key letters in `text`.
|
|
10
10
|
*
|
|
@@ -24,7 +24,10 @@ import type { GraphTheme } from "./graph-theme.js";
|
|
|
24
24
|
import { keyText } from "@bastani/atomic";
|
|
25
25
|
import { fmtDuration, statusIcon, statusColor } from "./status-helpers.js";
|
|
26
26
|
import { hexToAnsi, hexBg, RESET, BOLD } from "./color-utils.js";
|
|
27
|
-
import { matchesKey, truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
27
|
+
import { Key, matchesKey, truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
28
|
+
|
|
29
|
+
const ESCAPE_CODE = 0x1b;
|
|
30
|
+
const DOUBLE_ESCAPE_SEQUENCE = String.fromCharCode(ESCAPE_CODE, ESCAPE_CODE);
|
|
28
31
|
|
|
29
32
|
// ---------------------------------------------------------------------------
|
|
30
33
|
// State + filtering
|
|
@@ -182,7 +185,7 @@ function renderSectionRow(label: string, inner: number, theme: GraphTheme): stri
|
|
|
182
185
|
const panelBg = hexBg(theme.bg);
|
|
183
186
|
const mauve = hexToAnsi(theme.mauve);
|
|
184
187
|
const muted = hexToAnsi(theme.textMuted);
|
|
185
|
-
const content = ` ${mauve}
|
|
188
|
+
const content = ` ${mauve} ${RESET}${panelBg} ${muted}${BOLD}${label}${RESET}`;
|
|
186
189
|
return `${border}│${RESET}${panelBg}${padTo(content, inner)}${RESET}${border}│${RESET}`;
|
|
187
190
|
}
|
|
188
191
|
|
|
@@ -195,14 +198,14 @@ function renderFilterRow(inner: number, theme: GraphTheme, state: SessionPickerS
|
|
|
195
198
|
const accent = hexToAnsi(theme.accent);
|
|
196
199
|
const cursor = state.filterFocused ? `${accent}▌${RESET}${panelBg}` : "";
|
|
197
200
|
const label = state.filterFocused ? `${accent}filter` : `${muted}filter`;
|
|
198
|
-
const prefixPlain = "
|
|
201
|
+
const prefixPlain = " filter ";
|
|
199
202
|
const valueBudget = Math.max(1, inner - visibleWidth(prefixPlain) - (state.filterFocused ? 1 : 0));
|
|
200
203
|
const rawValue = state.query || "(type to filter by name or id)";
|
|
201
204
|
const shownValue = truncateToWidth(rawValue, valueBudget, "…");
|
|
202
205
|
const value = state.query
|
|
203
206
|
? `${text}${shownValue}${RESET}${panelBg}`
|
|
204
207
|
: `${muted}${shownValue}${RESET}${panelBg}`;
|
|
205
|
-
const content = ` ${mauve}
|
|
208
|
+
const content = ` ${mauve} ${RESET}${panelBg} ${label}${RESET}${panelBg} ${value}${cursor}`;
|
|
206
209
|
return `${border}│${RESET}${panelBg}${padTo(content, inner)}${RESET}${border}│${RESET}`;
|
|
207
210
|
}
|
|
208
211
|
|
|
@@ -342,15 +345,15 @@ export function handleSessionPickerInput(
|
|
|
342
345
|
): SessionPickerAction {
|
|
343
346
|
// Filter mode — typed chars feed the query, Enter/Esc exit.
|
|
344
347
|
if (state.filterFocused) {
|
|
345
|
-
if (matchesKey(data,
|
|
348
|
+
if (matchesKey(data, Key.escape) || data === DOUBLE_ESCAPE_SEQUENCE) {
|
|
346
349
|
state.filterFocused = false;
|
|
347
350
|
return { kind: "noop" };
|
|
348
351
|
}
|
|
349
|
-
if (matchesKey(data,
|
|
352
|
+
if (matchesKey(data, Key.enter)) {
|
|
350
353
|
state.filterFocused = false;
|
|
351
354
|
return { kind: "noop" };
|
|
352
355
|
}
|
|
353
|
-
if (matchesKey(data,
|
|
356
|
+
if (matchesKey(data, Key.backspace)) {
|
|
354
357
|
state.query = state.query.slice(0, -1);
|
|
355
358
|
state.selectedIndex = 0;
|
|
356
359
|
return { kind: "noop" };
|
|
@@ -364,36 +367,36 @@ export function handleSessionPickerInput(
|
|
|
364
367
|
}
|
|
365
368
|
|
|
366
369
|
// Navigation mode.
|
|
367
|
-
if (data
|
|
370
|
+
if (matchesKey(data, "/")) {
|
|
368
371
|
state.filterFocused = true;
|
|
369
372
|
return { kind: "noop" };
|
|
370
373
|
}
|
|
371
|
-
if (matchesKey(data,
|
|
372
|
-
if (data
|
|
373
|
-
if (data
|
|
374
|
+
if (matchesKey(data, Key.escape)) return { kind: "close" };
|
|
375
|
+
if (matchesKey(data, "q") || matchesKey(data, Key.shift("q"))) return { kind: "close" };
|
|
376
|
+
if (matchesKey(data, "a") || matchesKey(data, Key.shift("a"))) {
|
|
374
377
|
state.includeAll = !state.includeAll;
|
|
375
378
|
state.selectedIndex = 0;
|
|
376
379
|
return { kind: "noop" };
|
|
377
380
|
}
|
|
378
381
|
|
|
379
382
|
// Arrows + j/k.
|
|
380
|
-
if (matchesKey(data,
|
|
383
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
381
384
|
state.selectedIndex = Math.min(state.selectedIndex + 1, Math.max(0, rows.length - 1));
|
|
382
385
|
return { kind: "noop" };
|
|
383
386
|
}
|
|
384
|
-
if (matchesKey(data,
|
|
387
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
385
388
|
if (rows.length > 0 && state.selectedIndex === 0) return { kind: "noop" };
|
|
386
389
|
state.selectedIndex = Math.max(state.selectedIndex - 1, 0);
|
|
387
390
|
return { kind: "noop" };
|
|
388
391
|
}
|
|
389
392
|
|
|
390
|
-
if (matchesKey(data,
|
|
393
|
+
if (matchesKey(data, Key.enter)) {
|
|
391
394
|
const row = rows[state.selectedIndex];
|
|
392
395
|
if (!row) return { kind: "noop" };
|
|
393
396
|
return { kind: "connect", runId: row.run.id };
|
|
394
397
|
}
|
|
395
398
|
// `x` = kill. Avoids collision with vim's `k` = up.
|
|
396
|
-
if (data
|
|
399
|
+
if (matchesKey(data, "x") || matchesKey(data, Key.shift("x"))) {
|
|
397
400
|
const row = rows[state.selectedIndex];
|
|
398
401
|
if (!row) return { kind: "noop" };
|
|
399
402
|
return { kind: "kill", runId: row.run.id };
|