@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
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
decodeKittyPrintable,
|
|
3
|
+
Key,
|
|
3
4
|
matchesKey as piMatchesKey,
|
|
4
5
|
truncateToWidth as piTruncateToWidth,
|
|
5
6
|
visibleWidth,
|
|
6
7
|
type KeyId,
|
|
7
8
|
} from "@earendil-works/pi-tui";
|
|
8
9
|
|
|
9
|
-
export { visibleWidth };
|
|
10
|
+
export { Key, visibleWidth };
|
|
10
11
|
|
|
11
12
|
const ANSI_ESCAPE_RE = /^\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\)|_[^\x1b]*(?:\x1b\\))/;
|
|
12
13
|
const MODIFY_OTHER_KEYS_RE = /^\x1b\[27;(\d+);(\d+)~$/;
|
|
@@ -14,6 +15,19 @@ const SHIFT_MODIFIER = 1;
|
|
|
14
15
|
const LOCK_MODIFIER_MASK = 64 + 128;
|
|
15
16
|
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
16
17
|
|
|
18
|
+
export function graphemes(text: string): string[] {
|
|
19
|
+
return Array.from(segmenter.segment(text), (s) => s.segment);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface GraphemeSegment {
|
|
23
|
+
segment: string;
|
|
24
|
+
index: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function graphemeSegments(text: string): GraphemeSegment[] {
|
|
28
|
+
return Array.from(segmenter.segment(text), (s) => ({ segment: s.segment, index: s.index }));
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
function readAnsiCode(text: string, offset: number): string | null {
|
|
18
32
|
const match = ANSI_ESCAPE_RE.exec(text.slice(offset));
|
|
19
33
|
return match?.[0] ?? null;
|
|
@@ -37,9 +51,9 @@ export function truncateToWidth(
|
|
|
37
51
|
return piTruncateToWidth(text, width, suffix, false);
|
|
38
52
|
}
|
|
39
53
|
|
|
40
|
-
/** Use pi-tui's key parser/matcher
|
|
41
|
-
export function matchesKey(data: string, key:
|
|
42
|
-
return data === key || piMatchesKey(data, key
|
|
54
|
+
/** Use pi-tui's key parser/matcher with typed key identifiers. */
|
|
55
|
+
export function matchesKey(data: string, key: KeyId): boolean {
|
|
56
|
+
return data === key || piMatchesKey(data, key);
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
function decodeModifyOtherKeysPrintable(data: string): string | undefined {
|
|
@@ -67,6 +81,86 @@ export function decodePrintableKey(data: string): string | undefined {
|
|
|
67
81
|
return decodeKittyPrintable(data) ?? decodeModifyOtherKeysPrintable(data);
|
|
68
82
|
}
|
|
69
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Trim review values without flattening authored line breaks.
|
|
86
|
+
* Empty or whitespace-only values render as an explicit placeholder.
|
|
87
|
+
*/
|
|
88
|
+
export function formatReviewValue(value: string): string {
|
|
89
|
+
const trimmed = value.trim();
|
|
90
|
+
return trimmed.length === 0 ? "<empty>" : trimmed;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Wrap plain text by terminal cell width while preserving paragraph breaks.
|
|
95
|
+
* Within each paragraph, runs of whitespace collapse to a single space; this
|
|
96
|
+
* keeps labels/descriptions readable but is not intended for preformatted text.
|
|
97
|
+
*/
|
|
98
|
+
export function wrapPlainText(text: string, width: number): string[] {
|
|
99
|
+
const budget = Math.max(1, Math.floor(width));
|
|
100
|
+
const out: string[] = [];
|
|
101
|
+
for (const paragraph of text.split(/\r?\n/)) {
|
|
102
|
+
const words = paragraph.trim().split(/\s+/).filter((word) => word.length > 0);
|
|
103
|
+
if (words.length === 0) {
|
|
104
|
+
out.push("");
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
let line = "";
|
|
108
|
+
for (const word of words) {
|
|
109
|
+
if (visibleWidth(word) > budget) {
|
|
110
|
+
if (line.length > 0) {
|
|
111
|
+
out.push(line);
|
|
112
|
+
line = "";
|
|
113
|
+
}
|
|
114
|
+
let chunk = "";
|
|
115
|
+
for (const g of graphemes(word)) {
|
|
116
|
+
if (chunk.length > 0 && visibleWidth(chunk) + visibleWidth(g) > budget) {
|
|
117
|
+
out.push(chunk);
|
|
118
|
+
chunk = g;
|
|
119
|
+
} else {
|
|
120
|
+
chunk += g;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
line = chunk;
|
|
124
|
+
} else if (line.length === 0) {
|
|
125
|
+
line = word;
|
|
126
|
+
} else if (visibleWidth(line) + 1 + visibleWidth(word) <= budget) {
|
|
127
|
+
line += " " + word;
|
|
128
|
+
} else {
|
|
129
|
+
out.push(line);
|
|
130
|
+
line = word;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (line.length > 0) out.push(line);
|
|
134
|
+
}
|
|
135
|
+
return out.length > 0 ? out : [""];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface WrappedPrefixedLinesOpts {
|
|
139
|
+
text: string;
|
|
140
|
+
width: number;
|
|
141
|
+
plainPrefix: string;
|
|
142
|
+
firstPrefix: string;
|
|
143
|
+
continuationPrefix?: string;
|
|
144
|
+
suffix?: string;
|
|
145
|
+
preserveAnsi?: boolean;
|
|
146
|
+
styleLine?: (line: string, index: number) => string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Shared ask-style row wrapper for numbered choices and review value rows.
|
|
151
|
+
* Computes the wrapped text budget from the visible prefix width, then clips
|
|
152
|
+
* the composed ANSI row so narrow terminals never overflow.
|
|
153
|
+
*/
|
|
154
|
+
export function renderWrappedPrefixedLines(opts: WrappedPrefixedLinesOpts): string[] {
|
|
155
|
+
const continuationPrefix = opts.continuationPrefix ?? " ".repeat(visibleWidth(opts.plainPrefix));
|
|
156
|
+
const textBudget = Math.max(1, opts.width - visibleWidth(opts.plainPrefix));
|
|
157
|
+
return wrapPlainText(opts.text, textBudget).map((line, index) => {
|
|
158
|
+
const prefix = index === 0 ? opts.firstPrefix : continuationPrefix;
|
|
159
|
+
const styled = opts.styleLine ? opts.styleLine(line, index) : line;
|
|
160
|
+
return truncateToWidth(prefix + styled, opts.width, opts.suffix ?? "…", opts.preserveAnsi ?? true);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
70
164
|
export function sliceColumns(
|
|
71
165
|
line: string,
|
|
72
166
|
startCol: number,
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Above-editor background-workflow widget.
|
|
3
3
|
*
|
|
4
|
-
* Visual contract (DESIGN.md §5
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* line 2: `<dim mode · progress · duration>`
|
|
12
|
-
* - Blank line between entries; trailing blank trimmed.
|
|
4
|
+
* Visual contract (DESIGN.md §5):
|
|
5
|
+
* - One transparent rounded `BACKGROUND` panel with `N runs` and status
|
|
6
|
+
* badges (`✓ n ● n ○ n ✗ n`) in the title.
|
|
7
|
+
* - One compact rounded card per run:
|
|
8
|
+
* title: `<status glyph> <short id> <name>`
|
|
9
|
+
* row 1: `<dim mode · progress · duration>`
|
|
10
|
+
* - Blank line between cards; trailing blank trimmed.
|
|
13
11
|
* - Collapsed single-line form below 80 cells:
|
|
14
12
|
* `▾ N background · X ●` in dim+warning.
|
|
15
13
|
*
|
|
@@ -21,8 +19,7 @@
|
|
|
21
19
|
*
|
|
22
20
|
* cross-ref:
|
|
23
21
|
* - github.com/nicobailon/pi-subagents src/tui/render.ts buildWidgetLines
|
|
24
|
-
* - src/tui/
|
|
25
|
-
* - orchestrator-panel-ui.png
|
|
22
|
+
* - src/tui/chat-surface.ts renderRoundedBoxLines
|
|
26
23
|
*/
|
|
27
24
|
|
|
28
25
|
import type {
|
|
@@ -31,8 +28,8 @@ import type {
|
|
|
31
28
|
} from "../shared/store-types.js";
|
|
32
29
|
import { elapsedRunMs } from "../shared/timing.js";
|
|
33
30
|
import type { PiTheme } from "./store-widget-installer.js";
|
|
34
|
-
import {
|
|
35
|
-
import type {
|
|
31
|
+
import { renderRoundedBoxLines } from "./chat-surface.js";
|
|
32
|
+
import type { FlatBandBadge } from "./chat-surface.js";
|
|
36
33
|
import { deriveGraphTheme } from "./graph-theme.js";
|
|
37
34
|
import type { GraphTheme } from "./graph-theme.js";
|
|
38
35
|
import { hexToAnsi, RESET, BOLD } from "./color-utils.js";
|
|
@@ -43,7 +40,8 @@ import { hexToAnsi, RESET, BOLD } from "./color-utils.js";
|
|
|
43
40
|
|
|
44
41
|
const SHORT_ID_LEN = 6;
|
|
45
42
|
const MAX_VISIBLE_RUNS = 4;
|
|
46
|
-
const RECENT_ENDED_WINDOW_MS = 30_000;
|
|
43
|
+
export const RECENT_ENDED_WINDOW_MS = 30_000;
|
|
44
|
+
const WIDGET_CLOCK_REFRESH_MS = 1_000;
|
|
47
45
|
const COLLAPSED_BREAKPOINT_COLS = 80;
|
|
48
46
|
|
|
49
47
|
// ---------------------------------------------------------------------------
|
|
@@ -75,6 +73,7 @@ function recentlyEnded(run: RunSnapshot, now: number): boolean {
|
|
|
75
73
|
|
|
76
74
|
interface RunCounts {
|
|
77
75
|
active: number;
|
|
76
|
+
paused: number;
|
|
78
77
|
done: number;
|
|
79
78
|
failed: number;
|
|
80
79
|
/** Runs with a pending HIL prompt — surfaced as a separate badge so the
|
|
@@ -83,18 +82,43 @@ interface RunCounts {
|
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
function countRuns(runs: readonly RunSnapshot[]): RunCounts {
|
|
86
|
-
const counts: RunCounts = { active: 0, done: 0, failed: 0, awaiting: 0 };
|
|
85
|
+
const counts: RunCounts = { active: 0, paused: 0, done: 0, failed: 0, awaiting: 0 };
|
|
87
86
|
for (const r of runs) {
|
|
88
|
-
if (r.endedAt === undefined) counts.
|
|
87
|
+
if (r.endedAt === undefined && r.status === "paused") counts.paused++;
|
|
88
|
+
else if (r.endedAt === undefined) counts.active++;
|
|
89
89
|
else if (r.status === "completed") counts.done++;
|
|
90
90
|
else if (r.status === "failed" || r.status === "killed") counts.failed++;
|
|
91
|
-
if (
|
|
91
|
+
if (
|
|
92
|
+
r.endedAt === undefined &&
|
|
93
|
+
(r.pendingPrompt !== undefined || r.stages.some((s) => s.status === "awaiting_input"))
|
|
94
|
+
) {
|
|
92
95
|
counts.awaiting++;
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
return counts;
|
|
96
99
|
}
|
|
97
100
|
|
|
101
|
+
function msUntilNextClockTick(now: number): number {
|
|
102
|
+
const remainder = now % WIDGET_CLOCK_REFRESH_MS;
|
|
103
|
+
return remainder === 0 ? WIDGET_CLOCK_REFRESH_MS : WIDGET_CLOCK_REFRESH_MS - remainder;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function nextWidgetRefreshDelayMs(
|
|
107
|
+
snap: StoreSnapshot,
|
|
108
|
+
now = Date.now(),
|
|
109
|
+
): number | undefined {
|
|
110
|
+
const display = selectDisplayRuns(snap, now);
|
|
111
|
+
if (display.length === 0) return undefined;
|
|
112
|
+
|
|
113
|
+
const hasLiveClock = display.some((run) => run.endedAt === undefined && run.status !== "paused");
|
|
114
|
+
const clockDelay = hasLiveClock ? msUntilNextClockTick(now) : undefined;
|
|
115
|
+
const expiryDelays = display
|
|
116
|
+
.filter((run) => run.endedAt !== undefined)
|
|
117
|
+
.map((run) => Math.max(1, run.endedAt! + RECENT_ENDED_WINDOW_MS - now + 1));
|
|
118
|
+
const delays = [clockDelay, ...expiryDelays].filter((delay): delay is number => delay !== undefined);
|
|
119
|
+
return delays.length === 0 ? undefined : Math.min(...delays);
|
|
120
|
+
}
|
|
121
|
+
|
|
98
122
|
function selectDisplayRuns(snap: StoreSnapshot, now: number): RunSnapshot[] {
|
|
99
123
|
const all = snap.runs as readonly RunSnapshot[];
|
|
100
124
|
const active = all.filter((r) => isActive(r));
|
|
@@ -118,6 +142,8 @@ function statusGlyph(run: RunSnapshot): string {
|
|
|
118
142
|
switch (run.status) {
|
|
119
143
|
case "running":
|
|
120
144
|
return "●";
|
|
145
|
+
case "paused":
|
|
146
|
+
return "❚❚";
|
|
121
147
|
case "completed":
|
|
122
148
|
return "✓";
|
|
123
149
|
case "failed":
|
|
@@ -133,6 +159,7 @@ function statusGlyph(run: RunSnapshot): string {
|
|
|
133
159
|
function statusFg(run: RunSnapshot, theme: GraphTheme): string {
|
|
134
160
|
switch (run.status) {
|
|
135
161
|
case "running":
|
|
162
|
+
case "paused":
|
|
136
163
|
return theme.warning;
|
|
137
164
|
case "completed":
|
|
138
165
|
return theme.success;
|
|
@@ -161,11 +188,11 @@ function progressLabel(run: RunSnapshot): string | undefined {
|
|
|
161
188
|
|
|
162
189
|
function elapsedLabel(run: RunSnapshot, now: number): string {
|
|
163
190
|
if (run.endedAt !== undefined) {
|
|
164
|
-
const
|
|
165
|
-
if (run.status === "completed") return `complete · ${
|
|
166
|
-
if (run.status === "failed") return `failed · ${
|
|
167
|
-
if (run.status === "killed") return `killed · ${
|
|
168
|
-
return `${run.status} · ${
|
|
191
|
+
const elapsed = formatDuration(elapsedRunMs(run, run.endedAt));
|
|
192
|
+
if (run.status === "completed") return `complete · ${elapsed}`;
|
|
193
|
+
if (run.status === "failed") return `failed · ${elapsed}`;
|
|
194
|
+
if (run.status === "killed") return `killed · ${elapsed}`;
|
|
195
|
+
return `${run.status} · ${elapsed}`;
|
|
169
196
|
}
|
|
170
197
|
if (run.startedAt != null) return formatDuration(elapsedRunMs(run, now));
|
|
171
198
|
return "";
|
|
@@ -187,16 +214,26 @@ function metaLine(run: RunSnapshot, now: number): string {
|
|
|
187
214
|
// Count badges for the band header
|
|
188
215
|
// ---------------------------------------------------------------------------
|
|
189
216
|
|
|
190
|
-
function countBadges(counts: RunCounts, theme: GraphTheme):
|
|
191
|
-
const badges:
|
|
192
|
-
if (counts.active > 0)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
function countBadges(counts: RunCounts, theme: GraphTheme): FlatBandBadge[] {
|
|
218
|
+
const badges: FlatBandBadge[] = [];
|
|
219
|
+
if (counts.active > 0) {
|
|
220
|
+
badges.push({ text: `● ${counts.active} running`, fg: theme.warning });
|
|
221
|
+
}
|
|
222
|
+
if (counts.paused > 0) {
|
|
223
|
+
badges.push({ text: `❚❚ ${counts.paused} paused`, fg: theme.warning });
|
|
224
|
+
}
|
|
225
|
+
// Awaiting input is shown in Sky per DESIGN.md status semantics: a live
|
|
226
|
+
// human-in-the-loop request that requires attention. Spell it out in the
|
|
227
|
+
// widget title instead of relying on the ↵ glyph alone.
|
|
228
|
+
if (counts.awaiting > 0) {
|
|
229
|
+
badges.push({ text: `↵ ${counts.awaiting} needs attention (attach to workflow with \`/workflow connect\`)`, fg: theme.info });
|
|
230
|
+
}
|
|
231
|
+
if (counts.done > 0) {
|
|
232
|
+
badges.push({ text: `✓ ${counts.done} complete`, fg: theme.success });
|
|
233
|
+
}
|
|
234
|
+
if (counts.failed > 0) {
|
|
235
|
+
badges.push({ text: `✗ ${counts.failed} failed`, fg: theme.error });
|
|
236
|
+
}
|
|
200
237
|
return badges;
|
|
201
238
|
}
|
|
202
239
|
|
|
@@ -246,14 +283,16 @@ function themedCollapsed(
|
|
|
246
283
|
const dim = hexToAnsi(theme.dim);
|
|
247
284
|
const muted = hexToAnsi(theme.textMuted);
|
|
248
285
|
const warning = hexToAnsi(theme.warning);
|
|
249
|
-
const total = counts.active + counts.done + counts.failed;
|
|
286
|
+
const total = counts.active + counts.paused + counts.done + counts.failed;
|
|
250
287
|
const active = counts.active;
|
|
251
|
-
|
|
288
|
+
const paused = counts.paused > 0 ? `${dim} · ${RESET}${warning}${counts.paused} ❚❚${RESET}` : "";
|
|
289
|
+
return ` ${mauve}▾${RESET} ${muted}${total} background${RESET}${dim} · ${RESET}${warning}${active} ●${RESET}${paused}`;
|
|
252
290
|
}
|
|
253
291
|
|
|
254
292
|
function plainCollapsed(counts: RunCounts): string {
|
|
255
|
-
const total = counts.active + counts.done + counts.failed;
|
|
256
|
-
|
|
293
|
+
const total = counts.active + counts.paused + counts.done + counts.failed;
|
|
294
|
+
const paused = counts.paused > 0 ? ` · ${counts.paused} ❚❚` : "";
|
|
295
|
+
return ` ▾ ${total} background · ${counts.active} ●${paused}`;
|
|
257
296
|
}
|
|
258
297
|
|
|
259
298
|
// ---------------------------------------------------------------------------
|
|
@@ -283,7 +322,8 @@ export function buildThemedWidgetLines(
|
|
|
283
322
|
// Active + recently-ended dominate the badge counts so a finished run
|
|
284
323
|
// visually persists for a beat before dropping off.
|
|
285
324
|
const visibleCounts: RunCounts = {
|
|
286
|
-
active:
|
|
325
|
+
active: display.filter((r) => r.endedAt === undefined && r.status !== "paused").length,
|
|
326
|
+
paused: display.filter((r) => r.endedAt === undefined && r.status === "paused").length,
|
|
287
327
|
done: display.filter((r) => r.endedAt !== undefined && r.status === "completed").length,
|
|
288
328
|
failed: display.filter((r) => r.endedAt !== undefined && (r.status === "failed" || r.status === "killed")).length,
|
|
289
329
|
awaiting: counts.awaiting,
|
|
@@ -297,47 +337,29 @@ export function buildThemedWidgetLines(
|
|
|
297
337
|
return [themed ? themedCollapsed(visibleCounts, graphTheme) : plainCollapsed(visibleCounts)];
|
|
298
338
|
}
|
|
299
339
|
|
|
300
|
-
const total = counts.active + counts.done + counts.failed;
|
|
340
|
+
const total = counts.active + counts.paused + counts.done + counts.failed;
|
|
301
341
|
const subtitle = `${total} run${total === 1 ? "" : "s"}`;
|
|
302
342
|
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const badges = countBadges(visibleCounts, graphTheme);
|
|
307
|
-
// Cap the chrome width to ~min(width, 64) so a wide terminal doesn't
|
|
308
|
-
// stretch the band across the whole pane.
|
|
309
|
-
const chromeWidth = Math.min(width, 64);
|
|
310
|
-
lines.push(...renderBandHeader({
|
|
311
|
-
label: "BACKGROUND",
|
|
312
|
-
subtitle,
|
|
313
|
-
badges,
|
|
314
|
-
width: chromeWidth,
|
|
315
|
-
theme: graphTheme,
|
|
316
|
-
}));
|
|
317
|
-
} else {
|
|
318
|
-
// Plain band: 3 rows mirroring the outline-pill shape, ASCII-only.
|
|
319
|
-
const innerLen = " BACKGROUND ".length;
|
|
320
|
-
const inner = "─".repeat(innerLen);
|
|
321
|
-
const badges = countBadges(visibleCounts, graphTheme)
|
|
322
|
-
.map((b) => b.text)
|
|
323
|
-
.join(" ");
|
|
324
|
-
const subtitleSeg = ` ${subtitle}`;
|
|
325
|
-
const badgeTail = badges ? ` ${badges}` : "";
|
|
326
|
-
lines.push(` ╭${inner}╮${subtitleSeg.replace(/./g, " ")}${badgeTail.replace(/./g, " ")}`);
|
|
327
|
-
lines.push(` │ BACKGROUND │${subtitleSeg}${badgeTail}`);
|
|
328
|
-
lines.push(` ╰${inner}╯${subtitleSeg.replace(/./g, " ")}${badgeTail.replace(/./g, " ")}`);
|
|
329
|
-
}
|
|
343
|
+
const badges = countBadges(visibleCounts, graphTheme).map((b) => b.text).join(" ");
|
|
344
|
+
const title = `BACKGROUND ${subtitle}${badges ? ` ${badges}` : ""}`;
|
|
345
|
+
const body: string[] = [];
|
|
330
346
|
|
|
331
347
|
for (let i = 0; i < display.length; i++) {
|
|
332
348
|
const run = display[i]!;
|
|
333
349
|
const runLines = themed
|
|
334
350
|
? themedRunLines(run, now, graphTheme)
|
|
335
351
|
: plainRunLines(run, now);
|
|
336
|
-
|
|
337
|
-
if (i < display.length - 1)
|
|
352
|
+
body.push(...runLines);
|
|
353
|
+
if (i < display.length - 1) body.push("");
|
|
338
354
|
}
|
|
339
355
|
|
|
340
|
-
return
|
|
356
|
+
return renderRoundedBoxLines({
|
|
357
|
+
title,
|
|
358
|
+
bodyLines: body,
|
|
359
|
+
accent: themed ? graphTheme.border : undefined,
|
|
360
|
+
theme: themed ? graphTheme : undefined,
|
|
361
|
+
width,
|
|
362
|
+
});
|
|
341
363
|
}
|
|
342
364
|
|
|
343
365
|
/**
|
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
StageControlHandle,
|
|
31
31
|
StageControlRegistry,
|
|
32
32
|
} from "../runs/foreground/stage-control-registry.js";
|
|
33
|
+
import type { StageUiBroker } from "../shared/stage-ui-broker.js";
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Surface used to write Pi's footer/status tag while the attach pane is
|
|
@@ -52,6 +53,8 @@ export interface WorkflowAttachPaneOpts {
|
|
|
52
53
|
* the user attaches to a node. Defaults to the singleton registry.
|
|
53
54
|
*/
|
|
54
55
|
stageControlRegistry?: StageControlRegistry;
|
|
56
|
+
/** Broker used to route stage-local custom UI such as ask_user_question into attached chats. */
|
|
57
|
+
stageUiBroker?: StageUiBroker;
|
|
55
58
|
/**
|
|
56
59
|
* Optional UI status surface. When present, attaching/detaching
|
|
57
60
|
* updates the `pi-workflows` status tag with `<workflow>/<stage>`.
|
|
@@ -67,11 +70,12 @@ export interface WorkflowAttachPaneOpts {
|
|
|
67
70
|
onPromptResolve?: (runId: string, promptId: string, response: unknown) => void;
|
|
68
71
|
/** Live pi-tui host objects used by attached stage chat to reuse coding-agent editor UI. */
|
|
69
72
|
piTui?: TUI;
|
|
73
|
+
piTheme?: unknown;
|
|
70
74
|
piKeybindings?: unknown;
|
|
71
75
|
/** Host custom editor factory installed by extensions via ctx.ui.setEditorComponent(). */
|
|
72
76
|
piEditorFactory?: (tui: TUI, theme: EditorTheme, keybindings: unknown) => EditorComponent;
|
|
73
77
|
/** Parent chat rendering settings and extension renderers, inherited from the host UI. */
|
|
74
|
-
getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd"
|
|
78
|
+
getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd">> | undefined;
|
|
75
79
|
/** Parent footer data provider, inherited so attached chats can render the core coding-agent footer. */
|
|
76
80
|
footerData?: ReadonlyFooterDataProvider;
|
|
77
81
|
/**
|
|
@@ -113,6 +117,7 @@ export class WorkflowAttachPane implements Component {
|
|
|
113
117
|
private theme: GraphTheme;
|
|
114
118
|
private runId: string | null;
|
|
115
119
|
private registry: StageControlRegistry | undefined;
|
|
120
|
+
private stageUiBroker: StageUiBroker | undefined;
|
|
116
121
|
private uiStatus: AttachUiStatusSurface | undefined;
|
|
117
122
|
private onClose: () => void;
|
|
118
123
|
private onHide?: () => void;
|
|
@@ -122,9 +127,10 @@ export class WorkflowAttachPane implements Component {
|
|
|
122
127
|
private hostRequestRender?: () => void;
|
|
123
128
|
private setMouseScrollTracking?: (enabled: boolean) => void;
|
|
124
129
|
private piTui?: TUI;
|
|
130
|
+
private piTheme?: unknown;
|
|
125
131
|
private piKeybindings?: unknown;
|
|
126
132
|
private piEditorFactory?: (tui: TUI, theme: EditorTheme, keybindings: unknown) => EditorComponent;
|
|
127
|
-
private getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd"
|
|
133
|
+
private getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd">> | undefined;
|
|
128
134
|
private footerData?: ReadonlyFooterDataProvider;
|
|
129
135
|
|
|
130
136
|
private mode: WorkflowAttachPaneMode = "graph";
|
|
@@ -138,6 +144,7 @@ export class WorkflowAttachPane implements Component {
|
|
|
138
144
|
this.theme = opts.graphTheme;
|
|
139
145
|
this.runId = opts.runId;
|
|
140
146
|
this.registry = opts.stageControlRegistry;
|
|
147
|
+
this.stageUiBroker = opts.stageUiBroker;
|
|
141
148
|
this.uiStatus = opts.uiStatus;
|
|
142
149
|
this.onClose = opts.onClose;
|
|
143
150
|
this.onHide = opts.onHide;
|
|
@@ -147,6 +154,7 @@ export class WorkflowAttachPane implements Component {
|
|
|
147
154
|
this.hostRequestRender = opts.requestRender;
|
|
148
155
|
this.setMouseScrollTracking = opts.setMouseScrollTracking;
|
|
149
156
|
this.piTui = opts.piTui;
|
|
157
|
+
this.piTheme = opts.piTheme;
|
|
150
158
|
this.piKeybindings = opts.piKeybindings;
|
|
151
159
|
this.piEditorFactory = opts.piEditorFactory;
|
|
152
160
|
this.getChatRenderSettings = opts.getChatRenderSettings;
|
|
@@ -226,11 +234,13 @@ export class WorkflowAttachPane implements Component {
|
|
|
226
234
|
onClose: this.onClose,
|
|
227
235
|
requestRender: this.hostRequestRender,
|
|
228
236
|
piTui: this.piTui,
|
|
237
|
+
piTheme: this.piTheme,
|
|
229
238
|
piKeybindings: this.piKeybindings,
|
|
230
239
|
piEditorFactory: this.piEditorFactory,
|
|
231
240
|
getChatRenderSettings: this.getChatRenderSettings,
|
|
232
241
|
footerData: this.footerData,
|
|
233
242
|
getViewportRows: this.getViewportRows,
|
|
243
|
+
stageUiBroker: this.stageUiBroker,
|
|
234
244
|
});
|
|
235
245
|
this.store.recordStageAttached(runId, stageId, true);
|
|
236
246
|
this.mode = "stage-chat";
|
|
@@ -286,6 +296,17 @@ export class WorkflowAttachPane implements Component {
|
|
|
286
296
|
this.uiStatus?.setStatus?.(STATUS_KEY, value);
|
|
287
297
|
}
|
|
288
298
|
|
|
299
|
+
setVisible(visible: boolean): void {
|
|
300
|
+
if (this.mode === "stage-chat" && this.runId && this.lastAttachedStageId) {
|
|
301
|
+
this.store.recordStageAttached(this.runId, this.lastAttachedStageId, visible);
|
|
302
|
+
if (visible) this._setAttachedStatus(this.runId, this.lastAttachedStageId);
|
|
303
|
+
else this.uiStatus?.setStatus?.(STATUS_KEY, undefined);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (visible) this._setBaseStatus();
|
|
307
|
+
else this.uiStatus?.setStatus?.(STATUS_KEY, undefined);
|
|
308
|
+
}
|
|
309
|
+
|
|
289
310
|
private _syncMouseScrollTracking(): void {
|
|
290
311
|
this.setMouseScrollTracking?.(this.wantsMouseScrollTracking());
|
|
291
312
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `/workflow list` catalogue —
|
|
2
|
+
* `/workflow list` catalogue — rounded workflow-tool output surface.
|
|
3
3
|
*
|
|
4
4
|
* Visual contract:
|
|
5
|
-
* - One
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* row 1:
|
|
9
|
-
* row 2:
|
|
10
|
-
* row 3: ▎ stripe · dim "inputs" · signature
|
|
5
|
+
* - One rounded `WORKFLOWS` panel with the registered count in the title.
|
|
6
|
+
* - One rounded card per workflow:
|
|
7
|
+
* title: workflow name
|
|
8
|
+
* row 1: muted description
|
|
9
|
+
* row 2: dim "inputs" · signature
|
|
11
10
|
* - Hint rows pointing at `/workflow <name> …` and `/workflow inputs <name>`.
|
|
12
11
|
*
|
|
13
12
|
* Truncation policy (ui/mockups.html §4):
|
|
@@ -24,13 +23,12 @@
|
|
|
24
23
|
|
|
25
24
|
import type { GraphTheme } from "./graph-theme.js";
|
|
26
25
|
import {
|
|
27
|
-
renderFlatBand,
|
|
28
|
-
renderTaggedCard,
|
|
29
26
|
renderHintRows,
|
|
27
|
+
renderRoundedBox,
|
|
30
28
|
ELLIPSIS,
|
|
31
29
|
chatWidth,
|
|
32
30
|
} from "./chat-surface.js";
|
|
33
|
-
import { hexToAnsi, RESET } from "./color-utils.js";
|
|
31
|
+
import { hexToAnsi, RESET, BOLD } from "./color-utils.js";
|
|
34
32
|
import { visibleWidth, truncateToWidth } from "./text-helpers.js";
|
|
35
33
|
|
|
36
34
|
const INLINE_INPUT_LIMIT = 3;
|
|
@@ -58,91 +56,69 @@ export interface RenderWorkflowListOpts {
|
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
/**
|
|
61
|
-
* Render the workflow catalogue as a `
|
|
62
|
-
*
|
|
59
|
+
* Render the workflow catalogue as a rounded `WORKFLOWS` panel with
|
|
60
|
+
* structured rows for each registered workflow.
|
|
63
61
|
*/
|
|
64
62
|
export function renderWorkflowList(
|
|
65
63
|
entries: readonly WorkflowListEntry[],
|
|
66
64
|
opts: RenderWorkflowListOpts = {},
|
|
67
65
|
): string {
|
|
68
|
-
const
|
|
66
|
+
const width = effectiveWidth(opts.width);
|
|
67
|
+
const bodyWidth = Math.max(20, width - 4);
|
|
68
|
+
const body: string[] = [];
|
|
69
69
|
const subtitle = `${entries.length} registered`;
|
|
70
70
|
const accent = opts.theme?.mauve;
|
|
71
71
|
|
|
72
|
-
lines.push(renderFlatBand({
|
|
73
|
-
label: "WORKFLOWS",
|
|
74
|
-
subtitle,
|
|
75
|
-
accent,
|
|
76
|
-
theme: opts.theme,
|
|
77
|
-
width: opts.width,
|
|
78
|
-
}));
|
|
79
|
-
// Blank line after the band — mirrors the mockup's `.band { padding-bottom }`
|
|
80
|
-
// + first `.card { margin-top }` (ui/mockups.html §3). The band reads as
|
|
81
|
-
// a header, not as the first card's row 0.
|
|
82
|
-
lines.push("");
|
|
83
|
-
|
|
84
72
|
if (entries.length === 0) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Blank line between cards mirrors the mockup's `.card { margin: 0.25rem 1.1rem }`
|
|
92
|
-
// top/bottom margin — without it the three workflow rows collapse into one
|
|
93
|
-
// visual block (see ui/Screenshot 2026-05-12 "Notice how the spacing is off").
|
|
94
|
-
for (let i = 0; i < entries.length; i++) {
|
|
95
|
-
if (i > 0) lines.push("");
|
|
96
|
-
lines.push(renderWorkflowCard(entries[i]!, opts));
|
|
73
|
+
body.push(` ${emptyState(opts.theme)} `);
|
|
74
|
+
} else {
|
|
75
|
+
for (let i = 0; i < entries.length; i++) {
|
|
76
|
+
if (i > 0) body.push("");
|
|
77
|
+
body.push(...renderWorkflowEntry(entries[i]!, { ...opts, width: bodyWidth }));
|
|
78
|
+
}
|
|
97
79
|
}
|
|
98
80
|
|
|
99
81
|
if (opts.showHints !== false) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
renderHintRows(
|
|
82
|
+
body.push("");
|
|
83
|
+
body.push(
|
|
84
|
+
...renderHintRows(
|
|
103
85
|
[
|
|
104
86
|
{ command: "/workflow <name> …", hint: "run a workflow" },
|
|
105
87
|
{ command: "/workflow inputs <name>", hint: "inspect input schema" },
|
|
106
88
|
],
|
|
107
89
|
opts.theme,
|
|
108
|
-
),
|
|
90
|
+
).split("\n").map((line) => ` ${line} `),
|
|
109
91
|
);
|
|
110
92
|
}
|
|
111
93
|
|
|
112
|
-
return
|
|
94
|
+
return renderRoundedBox({
|
|
95
|
+
title: `WORKFLOWS ${subtitle}`,
|
|
96
|
+
bodyLines: body,
|
|
97
|
+
accent,
|
|
98
|
+
theme: opts.theme,
|
|
99
|
+
width,
|
|
100
|
+
});
|
|
113
101
|
}
|
|
114
102
|
|
|
115
|
-
function
|
|
103
|
+
function renderWorkflowEntry(
|
|
116
104
|
entry: WorkflowListEntry,
|
|
117
105
|
opts: RenderWorkflowListOpts,
|
|
118
|
-
): string {
|
|
106
|
+
): string[] {
|
|
119
107
|
const theme = opts.theme;
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
const tag = truncateToWidth(entry.name, tagBudget, ELLIPSIS);
|
|
130
|
-
|
|
131
|
-
// Row 2: description (muted)
|
|
132
|
-
const descBudget = Math.max(8, interior - 2);
|
|
108
|
+
const width = effectiveWidth(opts.width);
|
|
109
|
+
const interior = Math.max(8, width - 2);
|
|
110
|
+
const titleBudget = Math.max(8, Math.min(TAG_NAME_BUDGET, interior - 2));
|
|
111
|
+
const title = truncateToWidth(entry.name, titleBudget, ELLIPSIS);
|
|
112
|
+
const titleLine = theme
|
|
113
|
+
? ` ${hexToAnsi(theme.text)}${BOLD}${title}${RESET} `
|
|
114
|
+
: ` ${title} `;
|
|
115
|
+
|
|
116
|
+
const descBudget = Math.max(8, interior - 4);
|
|
133
117
|
const description = truncateToWidth(entry.description, descBudget, ELLIPSIS);
|
|
134
|
-
const
|
|
118
|
+
const row1 = ` ${paintMuted(description, theme)} `;
|
|
119
|
+
const row2 = ` ${inputsSignatureRow(entry.inputs, interior - 4, theme)} `;
|
|
135
120
|
|
|
136
|
-
|
|
137
|
-
const row3 = inputsSignatureRow(entry.inputs, interior, theme);
|
|
138
|
-
|
|
139
|
-
return renderTaggedCard({
|
|
140
|
-
tag,
|
|
141
|
-
bodyRows: [row2, row3],
|
|
142
|
-
accent,
|
|
143
|
-
width: opts.width,
|
|
144
|
-
theme,
|
|
145
|
-
});
|
|
121
|
+
return [titleLine, row1, row2];
|
|
146
122
|
}
|
|
147
123
|
|
|
148
124
|
function inputsSignatureRow(
|