@bastani/atomic 0.8.13 → 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 +11 -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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
|
|
3
|
+
const MAX_NESTED_ID_LENGTH = 128;
|
|
4
|
+
export const MAX_NESTED_PATH_ENTRIES = 4;
|
|
5
|
+
|
|
6
|
+
export type NestedPathEntry = { runId: string; stepIndex?: number; agent?: string };
|
|
7
|
+
|
|
8
|
+
export function isSafeNestedPathId(value: unknown): value is string {
|
|
9
|
+
return typeof value === "string"
|
|
10
|
+
&& value.length > 0
|
|
11
|
+
&& value.length <= MAX_NESTED_ID_LENGTH
|
|
12
|
+
&& !path.isAbsolute(value)
|
|
13
|
+
&& !value.includes("/")
|
|
14
|
+
&& !value.includes("\\")
|
|
15
|
+
&& !value.includes("..");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function finiteNumber(value: unknown): number | undefined {
|
|
19
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function nonEmptyString(value: unknown, max: number): string | undefined {
|
|
23
|
+
return typeof value === "string" && value.length > 0 ? value.slice(0, max) : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function sanitizeNestedPath(value: unknown): NestedPathEntry[] {
|
|
27
|
+
if (!Array.isArray(value)) return [];
|
|
28
|
+
return value.map((part) => {
|
|
29
|
+
if (!part || typeof part !== "object") return undefined;
|
|
30
|
+
const record = part as Record<string, unknown>;
|
|
31
|
+
if (!isSafeNestedPathId(record.runId)) return undefined;
|
|
32
|
+
return {
|
|
33
|
+
runId: record.runId,
|
|
34
|
+
...(finiteNumber(record.stepIndex) !== undefined ? { stepIndex: finiteNumber(record.stepIndex) } : {}),
|
|
35
|
+
...(nonEmptyString(record.agent, 128) ? { agent: nonEmptyString(record.agent, 128) } : {}),
|
|
36
|
+
};
|
|
37
|
+
}).filter((part): part is NestedPathEntry => Boolean(part)).slice(0, MAX_NESTED_PATH_ENTRIES);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function parseNestedPathEnv(value: string | undefined): NestedPathEntry[] {
|
|
41
|
+
if (!value) return [];
|
|
42
|
+
try {
|
|
43
|
+
return sanitizeNestedPath(JSON.parse(value) as unknown);
|
|
44
|
+
} catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function encodeNestedPathEnv(value: NestedPathEntry[]): string {
|
|
50
|
+
const sanitized = sanitizeNestedPath(value);
|
|
51
|
+
return sanitized.length ? JSON.stringify(sanitized) : "";
|
|
52
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { formatDuration, formatTokens, shortenPath } from "../../shared/formatters.ts";
|
|
2
|
+
import { formatActivityLabel } from "../../shared/status-format.ts";
|
|
3
|
+
import type { ActivityState, NestedRunSummary, NestedStepSummary } from "../../shared/types.ts";
|
|
4
|
+
|
|
5
|
+
export interface NestedRunCounts {
|
|
6
|
+
total: number;
|
|
7
|
+
running: number;
|
|
8
|
+
paused: number;
|
|
9
|
+
complete: number;
|
|
10
|
+
failed: number;
|
|
11
|
+
queued: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function countNestedRuns(children: NestedRunSummary[] | undefined): NestedRunCounts {
|
|
15
|
+
const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, queued: 0 };
|
|
16
|
+
for (const child of children ?? []) {
|
|
17
|
+
counts.total++;
|
|
18
|
+
counts[child.state]++;
|
|
19
|
+
const nested = countNestedRuns([...(child.children ?? []), ...(child.steps?.flatMap((step) => step.children ?? []) ?? [])]);
|
|
20
|
+
counts.total += nested.total;
|
|
21
|
+
counts.running += nested.running;
|
|
22
|
+
counts.paused += nested.paused;
|
|
23
|
+
counts.complete += nested.complete;
|
|
24
|
+
counts.failed += nested.failed;
|
|
25
|
+
counts.queued += nested.queued;
|
|
26
|
+
}
|
|
27
|
+
return counts;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function formatNestedAggregate(children: NestedRunSummary[] | undefined): string | undefined {
|
|
31
|
+
const counts = countNestedRuns(children);
|
|
32
|
+
if (counts.total === 0) return undefined;
|
|
33
|
+
const parts = [
|
|
34
|
+
counts.running > 0 ? `${counts.running} running` : "",
|
|
35
|
+
counts.paused > 0 ? `${counts.paused} paused` : "",
|
|
36
|
+
counts.failed > 0 ? `${counts.failed} failed` : "",
|
|
37
|
+
counts.complete > 0 ? `${counts.complete} complete` : "",
|
|
38
|
+
counts.queued > 0 ? `${counts.queued} queued` : "",
|
|
39
|
+
].filter(Boolean);
|
|
40
|
+
return `+${counts.total} nested run${counts.total === 1 ? "" : "s"}${parts.length ? ` (${parts.join(", ")})` : ""}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function nestedRunLabel(run: NestedRunSummary): string {
|
|
44
|
+
if (run.agent) return run.agent;
|
|
45
|
+
if (run.agents?.length) return run.agents.length === 1 ? run.agents[0]! : `${run.agents.slice(0, 2).join(", ")}${run.agents.length > 2 ? ` +${run.agents.length - 2}` : ""}`;
|
|
46
|
+
return run.id;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function formatNestedActivity(input: {
|
|
50
|
+
activityState?: ActivityState;
|
|
51
|
+
lastActivityAt?: number;
|
|
52
|
+
currentTool?: string;
|
|
53
|
+
currentToolStartedAt?: number;
|
|
54
|
+
currentPath?: string;
|
|
55
|
+
turnCount?: number;
|
|
56
|
+
toolCount?: number;
|
|
57
|
+
totalTokens?: NestedRunSummary["totalTokens"];
|
|
58
|
+
}): string | undefined {
|
|
59
|
+
const facts: string[] = [];
|
|
60
|
+
if (input.currentTool && input.currentToolStartedAt !== undefined) facts.push(`tool ${input.currentTool} ${formatDuration(Math.max(0, Date.now() - input.currentToolStartedAt))}`);
|
|
61
|
+
else if (input.currentTool) facts.push(`tool ${input.currentTool}`);
|
|
62
|
+
if (input.currentPath) facts.push(shortenPath(input.currentPath));
|
|
63
|
+
if (input.turnCount !== undefined) facts.push(`${input.turnCount} turns`);
|
|
64
|
+
if (input.toolCount !== undefined) facts.push(`${input.toolCount} tools`);
|
|
65
|
+
if (input.totalTokens) facts.push(`${formatTokens(input.totalTokens.total)} tok`);
|
|
66
|
+
const activity = formatActivityLabel(input.lastActivityAt, input.activityState as ActivityState | undefined);
|
|
67
|
+
return activity || facts.length ? [activity, ...facts].filter(Boolean).join(" | ") : undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function formatNestedRunLines(children: NestedRunSummary[] | undefined, options: { indent: string; maxDepth: number; maxLines: number; commandHints?: boolean }): string[] {
|
|
71
|
+
const lines: string[] = [];
|
|
72
|
+
const append = (items: NestedRunSummary[] | undefined, depth: number, indent: string): void => {
|
|
73
|
+
if (!items?.length || lines.length >= options.maxLines) return;
|
|
74
|
+
if (depth > options.maxDepth) {
|
|
75
|
+
const aggregate = formatNestedAggregate(items);
|
|
76
|
+
if (aggregate && lines.length < options.maxLines) lines.push(`${indent}↳ ${aggregate}`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (let index = 0; index < items.length; index++) {
|
|
80
|
+
const child = items[index]!;
|
|
81
|
+
if (lines.length >= options.maxLines) {
|
|
82
|
+
const aggregate = formatNestedAggregate(items.slice(index));
|
|
83
|
+
if (aggregate) lines[lines.length - 1] = `${indent}↳ ${aggregate}`;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const activity = child.state === "running" ? formatNestedActivity(child) : undefined;
|
|
87
|
+
const error = child.error ? ` | error: ${child.error}` : "";
|
|
88
|
+
lines.push(`${indent}↳ ${nestedRunLabel(child)} [${child.id}] ${child.state}${activity ? ` | ${activity}` : ""}${error}`);
|
|
89
|
+
if (options.commandHints && lines.length < options.maxLines) lines.push(`${indent} Status: subagent({ action: "status", id: "${child.id}" })`);
|
|
90
|
+
if (depth === options.maxDepth) {
|
|
91
|
+
const aggregate = formatNestedAggregate([...(child.steps?.flatMap((step) => step.children ?? []) ?? []), ...(child.children ?? [])]);
|
|
92
|
+
if (aggregate && lines.length < options.maxLines) lines.push(`${indent} ↳ ${aggregate}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
for (const [stepIndex, step] of (child.steps ?? []).entries()) {
|
|
96
|
+
if (lines.length >= options.maxLines) return;
|
|
97
|
+
const stepActivity = step.status === "running" ? formatNestedActivity(step) : undefined;
|
|
98
|
+
lines.push(`${indent} ${stepIndex + 1}. ${step.agent} ${step.status}${stepActivity ? ` | ${stepActivity}` : ""}${step.error ? ` | error: ${step.error}` : ""}`);
|
|
99
|
+
append(step.children, depth + 1, `${indent} `);
|
|
100
|
+
}
|
|
101
|
+
append(child.children, depth + 1, `${indent} `);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
append(children, 0, options.indent);
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function formatNestedRunStatusLines(children: NestedRunSummary[] | undefined, options: { indent?: string; maxDepth?: number; maxLines?: number; commandHints?: boolean } = {}): string[] {
|
|
109
|
+
return formatNestedRunLines(children, {
|
|
110
|
+
indent: options.indent ?? " ",
|
|
111
|
+
maxDepth: options.maxDepth ?? 2,
|
|
112
|
+
maxLines: options.maxLines ?? 40,
|
|
113
|
+
commandHints: options.commandHints ?? false,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -2,17 +2,30 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { APP_NAME } from "@bastani/atomic";
|
|
5
|
+
import { APP_NAME, getEnvValue } from "@bastani/atomic";
|
|
6
|
+
import { encodeNestedPathEnv, parseNestedPathEnv, type NestedPathEntry } from "./nested-path.ts";
|
|
7
|
+
import { resolveMcpDirectToolNames } from "./mcp-direct-tool-allowlist.ts";
|
|
6
8
|
|
|
7
9
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
8
10
|
const TASK_ARG_LIMIT = 8000;
|
|
9
|
-
const
|
|
11
|
+
export const SUBAGENT_PARENT_MAX_DEPTH = 3;
|
|
12
|
+
export const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
|
|
10
13
|
const ENV_PREFIX = APP_NAME.toUpperCase();
|
|
14
|
+
export const FANOUT_CHILD_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "extension", "fanout-child.ts");
|
|
11
15
|
export const SUBAGENT_CHILD_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD`;
|
|
12
16
|
export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = `${ENV_PREFIX}_SUBAGENT_ORCHESTRATOR_TARGET`;
|
|
13
17
|
export const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
|
|
14
18
|
export const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
|
|
15
19
|
export const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
|
|
20
|
+
export const SUBAGENT_FANOUT_CHILD_ENV = `${ENV_PREFIX}_SUBAGENT_FANOUT_CHILD`;
|
|
21
|
+
export const SUBAGENT_PARENT_EVENT_SINK_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_EVENT_SINK`;
|
|
22
|
+
export const SUBAGENT_PARENT_CONTROL_INBOX_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CONTROL_INBOX`;
|
|
23
|
+
export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_ROOT_RUN_ID`;
|
|
24
|
+
export const SUBAGENT_PARENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_RUN_ID`;
|
|
25
|
+
export const SUBAGENT_PARENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CHILD_INDEX`;
|
|
26
|
+
export const SUBAGENT_PARENT_DEPTH_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_DEPTH`;
|
|
27
|
+
export const SUBAGENT_PARENT_PATH_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_PATH`;
|
|
28
|
+
export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CAPABILITY_TOKEN`;
|
|
16
29
|
export const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_PROJECT_CONTEXT`;
|
|
17
30
|
export const SUBAGENT_INHERIT_SKILLS_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_SKILLS`;
|
|
18
31
|
export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = `${ENV_PREFIX}_SUBAGENT_INTERCOM_SESSION_NAME`;
|
|
@@ -32,12 +45,21 @@ interface BuildPiArgsInput {
|
|
|
32
45
|
extensions?: string[];
|
|
33
46
|
systemPrompt?: string | null;
|
|
34
47
|
mcpDirectTools?: string[];
|
|
48
|
+
cwd?: string;
|
|
35
49
|
promptFileStem?: string;
|
|
36
50
|
intercomSessionName?: string;
|
|
37
51
|
orchestratorIntercomTarget?: string;
|
|
38
52
|
runId?: string;
|
|
39
53
|
childAgentName?: string;
|
|
40
54
|
childIndex?: number;
|
|
55
|
+
parentEventSink?: string;
|
|
56
|
+
parentControlInbox?: string;
|
|
57
|
+
parentRootRunId?: string;
|
|
58
|
+
parentRunId?: string;
|
|
59
|
+
parentChildIndex?: number;
|
|
60
|
+
parentDepth?: number;
|
|
61
|
+
parentPath?: NestedPathEntry[];
|
|
62
|
+
parentCapabilityToken?: string;
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
interface BuildPiArgsResult {
|
|
@@ -74,22 +96,27 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
74
96
|
args.push("--model", modelArg);
|
|
75
97
|
}
|
|
76
98
|
|
|
99
|
+
const declaredBuiltinTools = input.tools?.filter((tool) => !(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) ?? [];
|
|
100
|
+
const fanoutAuthorized = declaredBuiltinTools.includes("subagent");
|
|
77
101
|
const toolExtensionPaths: string[] = [];
|
|
78
102
|
if (input.tools?.length) {
|
|
79
|
-
const builtinTools
|
|
103
|
+
const builtinTools = [...declaredBuiltinTools];
|
|
80
104
|
for (const tool of input.tools) {
|
|
81
|
-
if (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")) {
|
|
105
|
+
if (!declaredBuiltinTools.includes(tool) && (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) {
|
|
82
106
|
toolExtensionPaths.push(tool);
|
|
83
|
-
} else {
|
|
84
|
-
builtinTools.push(tool);
|
|
85
107
|
}
|
|
86
108
|
}
|
|
87
109
|
if (builtinTools.length > 0) {
|
|
110
|
+
if (input.mcpDirectTools?.length) {
|
|
111
|
+
builtinTools.push(...resolveMcpDirectToolNames(input.mcpDirectTools, input.cwd));
|
|
112
|
+
}
|
|
88
113
|
args.push("--tools", builtinTools.join(","));
|
|
89
114
|
}
|
|
90
115
|
}
|
|
91
116
|
|
|
92
|
-
const runtimeExtensions =
|
|
117
|
+
const runtimeExtensions = fanoutAuthorized
|
|
118
|
+
? [PROMPT_RUNTIME_EXTENSION_PATH, FANOUT_CHILD_EXTENSION_PATH]
|
|
119
|
+
: [PROMPT_RUNTIME_EXTENSION_PATH];
|
|
93
120
|
if (input.extensions !== undefined) {
|
|
94
121
|
args.push("--no-extensions");
|
|
95
122
|
for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...input.extensions])]) {
|
|
@@ -107,7 +134,7 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
107
134
|
|
|
108
135
|
let tempDir: string | undefined;
|
|
109
136
|
if (input.systemPrompt !== undefined && input.systemPrompt !== null) {
|
|
110
|
-
tempDir = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
137
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `${APP_NAME}-subagent-`));
|
|
111
138
|
const stem = (input.promptFileStem ?? "prompt").replace(/[^\w.-]/g, "_");
|
|
112
139
|
const promptPath = path.join(tempDir, `${stem}.md`);
|
|
113
140
|
fs.writeFileSync(promptPath, input.systemPrompt, { mode: 0o600 });
|
|
@@ -116,7 +143,7 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
116
143
|
|
|
117
144
|
if (input.task.length > TASK_ARG_LIMIT) {
|
|
118
145
|
if (!tempDir) {
|
|
119
|
-
tempDir = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
146
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `${APP_NAME}-subagent-`));
|
|
120
147
|
}
|
|
121
148
|
const taskFilePath = path.join(tempDir, "task.md");
|
|
122
149
|
fs.writeFileSync(taskFilePath, `Task: ${input.task}`, { mode: 0o600 });
|
|
@@ -127,6 +154,49 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
127
154
|
|
|
128
155
|
const env: Record<string, string | undefined> = {};
|
|
129
156
|
env[SUBAGENT_CHILD_ENV] = "1";
|
|
157
|
+
env[SUBAGENT_FANOUT_CHILD_ENV] = fanoutAuthorized ? "1" : "0";
|
|
158
|
+
const parentEventSinkEnv = getEnvValue(SUBAGENT_PARENT_EVENT_SINK_ENV);
|
|
159
|
+
const parentControlInboxEnv = getEnvValue(SUBAGENT_PARENT_CONTROL_INBOX_ENV);
|
|
160
|
+
const parentRootRunIdEnv = getEnvValue(SUBAGENT_PARENT_ROOT_RUN_ID_ENV);
|
|
161
|
+
const parentRunIdEnv = getEnvValue(SUBAGENT_PARENT_RUN_ID_ENV);
|
|
162
|
+
const parentChildIndexEnv = getEnvValue(SUBAGENT_PARENT_CHILD_INDEX_ENV);
|
|
163
|
+
const parentDepthEnv = getEnvValue(SUBAGENT_PARENT_DEPTH_ENV);
|
|
164
|
+
const parentPathEnv = getEnvValue(SUBAGENT_PARENT_PATH_ENV);
|
|
165
|
+
const parentCapabilityTokenEnv = getEnvValue(SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV);
|
|
166
|
+
const inheritedNestedRoute = Boolean(parentEventSinkEnv && parentRootRunIdEnv && parentCapabilityTokenEnv);
|
|
167
|
+
const parentRunId = input.parentRunId ?? input.runId ?? (inheritedNestedRoute ? getEnvValue(SUBAGENT_RUN_ID_ENV) : undefined) ?? parentRunIdEnv ?? "";
|
|
168
|
+
const parentChildIndex = input.parentChildIndex !== undefined
|
|
169
|
+
? String(input.parentChildIndex)
|
|
170
|
+
: input.childIndex !== undefined
|
|
171
|
+
? String(input.childIndex)
|
|
172
|
+
: parentChildIndexEnv ?? "";
|
|
173
|
+
const inheritedDepth = Number(parentDepthEnv);
|
|
174
|
+
const unclampedParentDepth = input.parentDepth ?? (inheritedNestedRoute && Number.isFinite(inheritedDepth) ? inheritedDepth + 1 : 1);
|
|
175
|
+
const parentDepth = Math.min(Math.max(1, unclampedParentDepth), SUBAGENT_PARENT_MAX_DEPTH);
|
|
176
|
+
const parentPath = input.parentPath ?? [
|
|
177
|
+
...parseNestedPathEnv(parentPathEnv),
|
|
178
|
+
...(parentRunId ? [{
|
|
179
|
+
runId: parentRunId,
|
|
180
|
+
...(parentChildIndex && /^\d+$/.test(parentChildIndex) ? { stepIndex: Number(parentChildIndex) } : {}),
|
|
181
|
+
...(input.childAgentName ? { agent: input.childAgentName } : {}),
|
|
182
|
+
}] : []),
|
|
183
|
+
];
|
|
184
|
+
env[SUBAGENT_PARENT_EVENT_SINK_ENV] = fanoutAuthorized
|
|
185
|
+
? input.parentEventSink ?? parentEventSinkEnv ?? ""
|
|
186
|
+
: "";
|
|
187
|
+
env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = fanoutAuthorized
|
|
188
|
+
? input.parentControlInbox ?? parentControlInboxEnv ?? ""
|
|
189
|
+
: "";
|
|
190
|
+
env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = fanoutAuthorized
|
|
191
|
+
? input.parentRootRunId ?? parentRootRunIdEnv ?? input.runId ?? ""
|
|
192
|
+
: "";
|
|
193
|
+
env[SUBAGENT_PARENT_RUN_ID_ENV] = fanoutAuthorized ? parentRunId : "";
|
|
194
|
+
env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = fanoutAuthorized ? parentChildIndex : "";
|
|
195
|
+
env[SUBAGENT_PARENT_DEPTH_ENV] = fanoutAuthorized ? String(parentDepth) : "";
|
|
196
|
+
env[SUBAGENT_PARENT_PATH_ENV] = fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
|
|
197
|
+
env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
|
|
198
|
+
? input.parentCapabilityToken ?? parentCapabilityTokenEnv ?? ""
|
|
199
|
+
: "";
|
|
130
200
|
env[SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV] = input.inheritProjectContext ? "1" : "0";
|
|
131
201
|
env[SUBAGENT_INHERIT_SKILLS_ENV] = input.inheritSkills ? "1" : "0";
|
|
132
202
|
if (input.intercomSessionName) {
|
|
@@ -144,6 +214,7 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
144
214
|
if (input.childIndex !== undefined) {
|
|
145
215
|
env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
|
|
146
216
|
}
|
|
217
|
+
// Bare MCP_DIRECT_TOOLS is the MCP adapter contract: unset means config defaults, __none__ forces no direct tools.
|
|
147
218
|
if (input.mcpDirectTools?.length) {
|
|
148
219
|
env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
|
|
149
220
|
} else {
|
|
@@ -153,6 +224,8 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
153
224
|
return { args, env, tempDir };
|
|
154
225
|
}
|
|
155
226
|
|
|
227
|
+
export const parseParentPathEnv = parseNestedPathEnv;
|
|
228
|
+
|
|
156
229
|
export function cleanupTempDir(tempDir: string | null | undefined): void {
|
|
157
230
|
if (!tempDir) return;
|
|
158
231
|
try {
|
|
@@ -94,7 +94,7 @@ export function resolvePiCliScript(deps: PiSpawnDeps = {}): string | undefined {
|
|
|
94
94
|
return candidate;
|
|
95
95
|
}
|
|
96
96
|
} catch {
|
|
97
|
-
// CLI
|
|
97
|
+
// Windows CLI resolution is optional; falling back to the app command lets PATH handle execution.
|
|
98
98
|
return undefined;
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -8,12 +8,22 @@ export interface SingleOutputSnapshot {
|
|
|
8
8
|
size?: number;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export function normalizeSingleOutputOverride(
|
|
12
|
+
output: string | boolean | undefined,
|
|
13
|
+
defaultOutput: string | undefined,
|
|
14
|
+
): string | false | undefined {
|
|
15
|
+
if (output === false || output === "false") return false;
|
|
16
|
+
if (output === true || output === "true") return defaultOutput;
|
|
17
|
+
if (typeof output === "string" && output.length > 0) return output;
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
export function resolveSingleOutputPath(
|
|
12
|
-
output: string |
|
|
22
|
+
output: string | boolean | undefined,
|
|
13
23
|
runtimeCwd: string,
|
|
14
24
|
requestedCwd?: string,
|
|
15
25
|
): string | undefined {
|
|
16
|
-
if (typeof output !== "string" || !output) return undefined;
|
|
26
|
+
if (typeof output !== "string" || !output || output === "false" || output === "true") return undefined;
|
|
17
27
|
if (path.isAbsolute(output)) return output;
|
|
18
28
|
const baseCwd = requestedCwd
|
|
19
29
|
? (path.isAbsolute(requestedCwd) ? requestedCwd : path.resolve(runtimeCwd, requestedCwd))
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@bastani/atomic";
|
|
2
|
-
import {
|
|
2
|
+
import { getEnvValue } from "@bastani/atomic";
|
|
3
|
+
import {
|
|
4
|
+
SUBAGENT_FANOUT_CHILD_ENV,
|
|
5
|
+
SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV,
|
|
6
|
+
SUBAGENT_INHERIT_SKILLS_ENV,
|
|
7
|
+
SUBAGENT_INTERCOM_SESSION_NAME_ENV,
|
|
8
|
+
} from "./pi-args.ts";
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_PROJECT_CONTEXT`;
|
|
6
|
-
const SUBAGENT_INHERIT_SKILLS_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_SKILLS`;
|
|
7
|
-
export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = `${ENV_PREFIX}_SUBAGENT_INTERCOM_SESSION_NAME`;
|
|
10
|
+
export { SUBAGENT_INTERCOM_SESSION_NAME_ENV } from "./pi-args.ts";
|
|
8
11
|
|
|
9
12
|
export const CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS = [
|
|
10
13
|
"You are a child subagent, not the parent orchestrator.",
|
|
@@ -14,6 +17,15 @@ export const CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS = [
|
|
|
14
17
|
"If you need to edit files, call the actual edit/write tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.",
|
|
15
18
|
].join("\n");
|
|
16
19
|
|
|
20
|
+
export const CHILD_FANOUT_BOUNDARY_INSTRUCTIONS = [
|
|
21
|
+
"You are a child subagent with explicit fanout responsibility for this assigned task.",
|
|
22
|
+
"The parent session owns final orchestration, acceptance, and follow-up implementation launches.",
|
|
23
|
+
"You may use the `subagent` tool only for the fanout work explicitly requested in this task.",
|
|
24
|
+
"Do not broaden yourself into general parent orchestration. Do not launch follow-up workers unless the task explicitly asks for that.",
|
|
25
|
+
"The maxSubagentDepth cap still applies and may block further fanout.",
|
|
26
|
+
"If you need to edit files, call the actual edit/write tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.",
|
|
27
|
+
].join("\n");
|
|
28
|
+
|
|
17
29
|
const PARENT_ONLY_CUSTOM_MESSAGE_TYPES = new Set([
|
|
18
30
|
"subagent-orchestration-instructions",
|
|
19
31
|
"subagent-slash-result",
|
|
@@ -64,9 +76,17 @@ export function stripSubagentOrchestrationSkill(prompt: string): string {
|
|
|
64
76
|
.replace(/[ \t]*<skill>\s*[\s\S]*?<\/skill>\s*/g, (block) => SUBAGENT_ORCHESTRATION_SKILL_NAME_PATTERN.test(block) ? "" : block);
|
|
65
77
|
}
|
|
66
78
|
|
|
79
|
+
function stripChildBoundaryInstructions(prompt: string): string {
|
|
80
|
+
let rewritten = prompt;
|
|
81
|
+
for (const boundary of [CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS, CHILD_FANOUT_BOUNDARY_INSTRUCTIONS]) {
|
|
82
|
+
rewritten = rewritten.split(boundary).join("");
|
|
83
|
+
}
|
|
84
|
+
return rewritten.replace(/^(?:[ \t]*\r?\n)+/, "");
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
export function rewriteSubagentPrompt(
|
|
68
88
|
prompt: string,
|
|
69
|
-
options: { inheritProjectContext: boolean; inheritSkills: boolean },
|
|
89
|
+
options: { inheritProjectContext: boolean; inheritSkills: boolean; fanoutChild?: boolean },
|
|
70
90
|
): string {
|
|
71
91
|
let rewritten = prompt;
|
|
72
92
|
if (!options.inheritProjectContext) {
|
|
@@ -76,9 +96,9 @@ export function rewriteSubagentPrompt(
|
|
|
76
96
|
rewritten = stripInheritedSkills(rewritten);
|
|
77
97
|
}
|
|
78
98
|
rewritten = stripSubagentOrchestrationSkill(rewritten);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
rewritten = stripChildBoundaryInstructions(rewritten);
|
|
100
|
+
const boundary = options.fanoutChild ? CHILD_FANOUT_BOUNDARY_INSTRUCTIONS : CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS;
|
|
101
|
+
return `${boundary}\n\n${rewritten}`;
|
|
82
102
|
}
|
|
83
103
|
|
|
84
104
|
function isParentOnlySubagentMessage(message: unknown): boolean {
|
|
@@ -141,10 +161,12 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
|
|
|
141
161
|
|
|
142
162
|
const inheritProjectContext = readBooleanEnv(SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV);
|
|
143
163
|
const inheritSkills = readBooleanEnv(SUBAGENT_INHERIT_SKILLS_ENV);
|
|
144
|
-
|
|
164
|
+
const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);
|
|
165
|
+
if (inheritProjectContext === undefined && inheritSkills === undefined && fanoutChild === undefined) return;
|
|
145
166
|
const rewritten = rewriteSubagentPrompt(event.systemPrompt, {
|
|
146
167
|
inheritProjectContext: inheritProjectContext ?? true,
|
|
147
168
|
inheritSkills: inheritSkills ?? true,
|
|
169
|
+
fanoutChild: fanoutChild === true,
|
|
148
170
|
});
|
|
149
171
|
if (rewritten === event.systemPrompt) return;
|
|
150
172
|
return { systemPrompt: rewritten };
|
|
@@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
+
import { APP_NAME } from "@bastani/atomic";
|
|
5
6
|
|
|
6
7
|
export interface WorktreeSetup {
|
|
7
8
|
cwd: string;
|
|
@@ -149,11 +150,11 @@ function safePatchAgentName(agent: string): string {
|
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
function buildWorktreeBranch(runId: string, index: number): string {
|
|
152
|
-
return
|
|
153
|
+
return `${APP_NAME}-parallel-${runId}-${index}`;
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
function buildWorktreePath(runId: string, index: number): string {
|
|
156
|
-
return path.join(os.tmpdir(),
|
|
157
|
+
return path.join(os.tmpdir(), `${APP_NAME}-worktree-${runId}-${index}`);
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
function resolveRepoCwdRelative(cwd: string): string {
|
|
@@ -88,6 +88,8 @@ export interface ControlEvent {
|
|
|
88
88
|
agent: string;
|
|
89
89
|
index?: number;
|
|
90
90
|
runId: string;
|
|
91
|
+
nestedRunId?: string;
|
|
92
|
+
nestingPath?: NestedRunAddress["path"];
|
|
91
93
|
message: string;
|
|
92
94
|
reason?: "idle" | "completion_guard" | "active_long_running" | "tool_failures" | "time_threshold" | "turn_threshold" | "token_threshold";
|
|
93
95
|
turns?: number;
|
|
@@ -103,6 +105,21 @@ export interface ControlEvent {
|
|
|
103
105
|
export type SubagentResultStatus = "completed" | "failed" | "paused" | "detached";
|
|
104
106
|
export type SubagentRunMode = "single" | "parallel" | "chain";
|
|
105
107
|
|
|
108
|
+
export type PublicNestedStepSummary = Pick<
|
|
109
|
+
NestedStepSummary,
|
|
110
|
+
"agent" | "status" | "sessionFile" | "activityState" | "lastActivityAt" | "currentTool" | "currentToolStartedAt" | "currentPath" | "turnCount" | "toolCount" | "startedAt" | "endedAt" | "error"
|
|
111
|
+
> & {
|
|
112
|
+
children?: PublicNestedRunSummary[];
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type PublicNestedRunSummary = Pick<
|
|
116
|
+
NestedRunSummary,
|
|
117
|
+
"id" | "parentRunId" | "parentStepIndex" | "parentAgent" | "depth" | "path" | "asyncDir" | "sessionId" | "sessionFile" | "intercomTarget" | "ownerIntercomTarget" | "leafIntercomTarget" | "ownerState" | "mode" | "state" | "agent" | "agents" | "currentStep" | "chainStepCount" | "parallelGroups" | "activityState" | "lastActivityAt" | "currentTool" | "currentToolStartedAt" | "currentPath" | "turnCount" | "toolCount" | "totalTokens" | "startedAt" | "endedAt" | "lastUpdate" | "error"
|
|
118
|
+
> & {
|
|
119
|
+
steps?: PublicNestedStepSummary[];
|
|
120
|
+
children?: PublicNestedRunSummary[];
|
|
121
|
+
};
|
|
122
|
+
|
|
106
123
|
export interface SubagentResultIntercomChild {
|
|
107
124
|
agent: string;
|
|
108
125
|
status: SubagentResultStatus;
|
|
@@ -111,6 +128,7 @@ export interface SubagentResultIntercomChild {
|
|
|
111
128
|
artifactPath?: string;
|
|
112
129
|
sessionPath?: string;
|
|
113
130
|
intercomTarget?: string;
|
|
131
|
+
children?: PublicNestedRunSummary[];
|
|
114
132
|
}
|
|
115
133
|
|
|
116
134
|
export interface SubagentResultIntercomPayload {
|
|
@@ -266,6 +284,76 @@ export interface AsyncParallelGroupStatus {
|
|
|
266
284
|
stepIndex: number;
|
|
267
285
|
}
|
|
268
286
|
|
|
287
|
+
export type NestedRunState = "queued" | "running" | "complete" | "failed" | "paused";
|
|
288
|
+
export type NestedOwnerState = "live" | "gone" | "unknown";
|
|
289
|
+
|
|
290
|
+
export interface NestedRunAddress {
|
|
291
|
+
id: string;
|
|
292
|
+
parentRunId: string;
|
|
293
|
+
parentStepIndex?: number;
|
|
294
|
+
parentAgent?: string;
|
|
295
|
+
depth: number;
|
|
296
|
+
path: Array<{ runId: string; stepIndex?: number; agent?: string }>;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface NestedStepSummary {
|
|
300
|
+
agent: string;
|
|
301
|
+
status: "pending" | "running" | "complete" | "completed" | "failed" | "paused";
|
|
302
|
+
sessionFile?: string;
|
|
303
|
+
activityState?: ActivityState;
|
|
304
|
+
lastActivityAt?: number;
|
|
305
|
+
currentTool?: string;
|
|
306
|
+
currentToolStartedAt?: number;
|
|
307
|
+
currentPath?: string;
|
|
308
|
+
turnCount?: number;
|
|
309
|
+
toolCount?: number;
|
|
310
|
+
startedAt?: number;
|
|
311
|
+
endedAt?: number;
|
|
312
|
+
error?: string;
|
|
313
|
+
children?: NestedRunSummary[];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export interface NestedRunSummary extends NestedRunAddress {
|
|
317
|
+
asyncDir?: string;
|
|
318
|
+
pid?: number;
|
|
319
|
+
sessionId?: string;
|
|
320
|
+
sessionFile?: string;
|
|
321
|
+
intercomTarget?: string;
|
|
322
|
+
ownerIntercomTarget?: string;
|
|
323
|
+
leafIntercomTarget?: string;
|
|
324
|
+
ownerState?: NestedOwnerState;
|
|
325
|
+
controlInbox?: string;
|
|
326
|
+
capabilityToken?: string;
|
|
327
|
+
mode?: SubagentRunMode;
|
|
328
|
+
state: NestedRunState;
|
|
329
|
+
agent?: string;
|
|
330
|
+
agents?: string[];
|
|
331
|
+
currentStep?: number;
|
|
332
|
+
chainStepCount?: number;
|
|
333
|
+
parallelGroups?: AsyncParallelGroupStatus[];
|
|
334
|
+
steps?: NestedStepSummary[];
|
|
335
|
+
children?: NestedRunSummary[];
|
|
336
|
+
activityState?: ActivityState;
|
|
337
|
+
lastActivityAt?: number;
|
|
338
|
+
currentTool?: string;
|
|
339
|
+
currentToolStartedAt?: number;
|
|
340
|
+
currentPath?: string;
|
|
341
|
+
turnCount?: number;
|
|
342
|
+
toolCount?: number;
|
|
343
|
+
totalTokens?: TokenUsage;
|
|
344
|
+
startedAt?: number;
|
|
345
|
+
endedAt?: number;
|
|
346
|
+
lastUpdate?: number;
|
|
347
|
+
error?: string;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export interface NestedRouteInfo {
|
|
351
|
+
rootRunId: string;
|
|
352
|
+
eventSink: string;
|
|
353
|
+
controlInbox: string;
|
|
354
|
+
capabilityToken: string;
|
|
355
|
+
}
|
|
356
|
+
|
|
269
357
|
export interface AsyncStartedEvent {
|
|
270
358
|
id?: string;
|
|
271
359
|
asyncDir?: string;
|
|
@@ -277,6 +365,7 @@ export interface AsyncStartedEvent {
|
|
|
277
365
|
chain?: string[];
|
|
278
366
|
chainStepCount?: number;
|
|
279
367
|
parallelGroups?: AsyncParallelGroupStatus[];
|
|
368
|
+
nestedRoute?: NestedRouteInfo;
|
|
280
369
|
}
|
|
281
370
|
|
|
282
371
|
export interface AsyncStatus {
|
|
@@ -302,6 +391,7 @@ export interface AsyncStatus {
|
|
|
302
391
|
steps?: Array<{
|
|
303
392
|
agent: string;
|
|
304
393
|
status: "pending" | "running" | "complete" | "completed" | "failed" | "paused";
|
|
394
|
+
children?: NestedRunSummary[];
|
|
305
395
|
sessionFile?: string;
|
|
306
396
|
activityState?: ActivityState;
|
|
307
397
|
lastActivityAt?: number;
|
|
@@ -366,6 +456,8 @@ export interface AsyncJobState {
|
|
|
366
456
|
totalTokens?: TokenUsage;
|
|
367
457
|
sessionFile?: string;
|
|
368
458
|
controlEventCursor?: number;
|
|
459
|
+
nestedRoute?: NestedRouteInfo;
|
|
460
|
+
nestedChildren?: NestedRunSummary[];
|
|
369
461
|
}
|
|
370
462
|
|
|
371
463
|
export interface ForegroundResumeChild {
|
|
@@ -403,6 +495,8 @@ export interface SubagentState {
|
|
|
403
495
|
turnCount?: number;
|
|
404
496
|
tokens?: number;
|
|
405
497
|
toolCount?: number;
|
|
498
|
+
nestedRoute?: NestedRouteInfo;
|
|
499
|
+
nestedChildren?: NestedRunSummary[];
|
|
406
500
|
interrupt?: () => boolean;
|
|
407
501
|
}>;
|
|
408
502
|
lastForegroundControlId: string | null;
|
|
@@ -478,6 +572,7 @@ export interface RunSyncOptions {
|
|
|
478
572
|
outputPath?: string;
|
|
479
573
|
outputMode?: OutputMode;
|
|
480
574
|
maxSubagentDepth?: number;
|
|
575
|
+
nestedRoute?: NestedRouteInfo;
|
|
481
576
|
/** Override the agent's default model (format: "provider/id" or just "id") */
|
|
482
577
|
modelOverride?: string;
|
|
483
578
|
/** Registry models available for heuristic bare-model resolution */
|
|
@@ -587,7 +682,7 @@ export function resolveTempScopeId(options?: {
|
|
|
587
682
|
|
|
588
683
|
const MAX_PARALLEL = 8;
|
|
589
684
|
export const MAX_CONCURRENCY = 4;
|
|
590
|
-
export const TEMP_ROOT_DIR = path.join(os.tmpdir(),
|
|
685
|
+
export const TEMP_ROOT_DIR = path.join(os.tmpdir(), `${APP_NAME}-subagents-${resolveTempScopeId()}`);
|
|
591
686
|
export const RESULTS_DIR = path.join(TEMP_ROOT_DIR, "async-subagent-results");
|
|
592
687
|
export const ASYNC_DIR = path.join(TEMP_ROOT_DIR, "async-subagent-runs");
|
|
593
688
|
export const CHAIN_RUNS_DIR = path.join(TEMP_ROOT_DIR, "chain-runs");
|