@bastani/atomic 0.8.28-alpha.1 → 0.8.28-alpha.3
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 +60 -0
- package/README.md +120 -118
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +26 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/builtin/open-claude-design.ts +150 -13
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +5 -2
- package/dist/builtin/workflows/src/extension/dispatcher.ts +2 -0
- package/dist/builtin/workflows/src/extension/index.ts +8 -0
- package/dist/builtin/workflows/src/extension/render-result.ts +5 -2
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +18 -0
- package/dist/builtin/workflows/src/runs/background/status.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +1251 -110
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +34 -10
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +10 -2
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +28 -9
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +9 -3
- package/dist/builtin/workflows/src/shared/store-types.ts +10 -3
- package/dist/builtin/workflows/src/shared/store.ts +29 -7
- package/dist/builtin/workflows/src/shared/types.ts +12 -10
- package/dist/builtin/workflows/src/tui/chat-surface.ts +32 -33
- package/dist/builtin/workflows/src/tui/run-detail.ts +23 -4
- package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +47 -3
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +1 -1
- package/dist/builtin/workflows/src/tui/widget.ts +12 -3
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +3 -3
- package/dist/cli/args.d.ts +4 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +35 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/project-trust.d.ts +10 -0
- package/dist/cli/project-trust.d.ts.map +1 -0
- package/dist/cli/project-trust.js +36 -0
- package/dist/cli/project-trust.js.map +1 -0
- package/dist/cli/startup-ui.d.ts +7 -0
- package/dist/cli/startup-ui.d.ts.map +1 -0
- package/dist/cli/startup-ui.js +57 -0
- package/dist/cli/startup-ui.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +3 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +1 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +3 -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 +9 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +70 -21
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -3
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +3 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +9 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +18 -24
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/experimental.d.ts +2 -0
- package/dist/core/experimental.d.ts.map +1 -0
- package/dist/core/experimental.js +5 -0
- package/dist/core/experimental.js.map +1 -0
- package/dist/core/export-html/template.js +19 -6
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +6 -4
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +11 -4
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +53 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +34 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +27 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +64 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts +1 -0
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js +52 -22
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +20 -8
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/project-trust.d.ts +15 -0
- package/dist/core/project-trust.d.ts.map +1 -0
- package/dist/core/project-trust.js +58 -0
- package/dist/core/project-trust.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +5 -4
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +30 -29
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +73 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +3 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +9 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +134 -11
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +12 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +108 -18
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +4 -2
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +13 -42
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -7
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +99 -35
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +15 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +69 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +0 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/inline-input.d.ts +28 -0
- package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -0
- package/dist/core/tools/ask-user-question/state/inline-input.js +56 -0
- package/dist/core/tools/ask-user-question/state/inline-input.js.map +1 -0
- package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/key-router.js +30 -4
- package/dist/core/tools/ask-user-question/state/key-router.js.map +1 -1
- 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 +9 -8
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/row-intent.d.ts +3 -2
- package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/row-intent.js +1 -1
- package/dist/core/tools/ask-user-question/state/row-intent.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +2 -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 +2 -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.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.js +36 -24
- 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 +8 -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/tool/format-answer.d.ts +6 -0
- package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/format-answer.js +19 -1
- package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
- package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +3 -2
- package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/response-envelope.js +15 -3
- package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
- package/dist/core/tools/ask-user-question/tool/types.d.ts +2 -1
- package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/types.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts +5 -2
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +2 -0
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +1 -0
- 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 +2 -1
- 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 +3 -3
- 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 +11 -4
- package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
- package/dist/core/tools/bash-policy.d.ts +62 -0
- package/dist/core/tools/bash-policy.d.ts.map +1 -0
- package/dist/core/tools/bash-policy.js +1069 -0
- package/dist/core/tools/bash-policy.js.map +1 -0
- package/dist/core/tools/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +9 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- 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 +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/oversized-tool-result.d.ts +53 -0
- package/dist/core/tools/oversized-tool-result.d.ts.map +1 -0
- package/dist/core/tools/oversized-tool-result.js +206 -0
- package/dist/core/tools/oversized-tool-result.js.map +1 -0
- package/dist/core/tools/read.d.ts +12 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +99 -34
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +6 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +17 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +6 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +2 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-limits.d.ts +25 -0
- package/dist/core/tools/tool-limits.d.ts.map +1 -0
- package/dist/core/tools/tool-limits.js +25 -0
- package/dist/core/tools/tool-limits.js.map +1 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts +31 -0
- package/dist/core/trust-manager.d.ts.map +1 -0
- package/dist/core/trust-manager.js +196 -0
- package/dist/core/trust-manager.js.map +1 -0
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +142 -30
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +3 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +325 -7
- package/dist/migrations.js.map +1 -1
- package/dist/modes/index.d.ts +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +2 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +6 -0
- 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 +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +9 -16
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +20 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +22 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/trust-selector.js +85 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +130 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +10 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +1 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +50 -6
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -4
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +6 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +104 -10
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/changelog.d.ts +1 -0
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +72 -0
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/deprecation.d.ts +4 -0
- package/dist/utils/deprecation.d.ts.map +1 -0
- package/dist/utils/deprecation.js +13 -0
- package/dist/utils/deprecation.js.map +1 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/json.d.ts +3 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +7 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/docs/containerization.md +111 -0
- package/docs/custom-provider.md +9 -9
- package/docs/development.md +1 -1
- package/docs/docs.json +2 -0
- package/docs/extensions.md +40 -4
- package/docs/index.md +2 -0
- package/docs/models.md +10 -10
- package/docs/packages.md +1 -1
- package/docs/prompt-templates.md +9 -2
- package/docs/providers.md +18 -5
- package/docs/quickstart.md +1 -0
- package/docs/rpc.md +3 -2
- package/docs/sdk.md +47 -0
- package/docs/security.md +58 -0
- package/docs/session-format.md +2 -2
- package/docs/sessions.md +8 -0
- package/docs/settings.md +21 -4
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +44 -2
- package/docs/themes.md +1 -1
- package/docs/tmux.md +4 -2
- package/docs/tui.md +14 -5
- package/docs/usage.md +17 -3
- package/docs/workflows.md +127 -15
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +8 -5
- package/examples/extensions/bash-spawn-hook.ts +1 -1
- package/examples/extensions/built-in-tool-renderer.ts +1 -1
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/custom-header.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
- package/examples/extensions/custom-provider-anthropic/package.json +6 -6
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +55 -4
- package/examples/extensions/custom-provider-gitlab-duo/package.json +3 -3
- package/examples/extensions/doom-overlay/README.md +1 -1
- package/examples/extensions/doom-overlay/index.ts +2 -2
- package/examples/extensions/git-merge-and-resolve.ts +115 -0
- package/examples/extensions/gondolin/index.ts +523 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +2 -2
- package/examples/extensions/input-transform-streaming.ts +39 -0
- package/examples/extensions/input-transform.ts +3 -3
- package/examples/extensions/interactive-shell.ts +2 -2
- package/examples/extensions/mac-system-theme.ts +2 -2
- package/examples/extensions/minimal-mode.ts +1 -1
- package/examples/extensions/modal-editor.ts +1 -1
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +198 -179
- package/examples/extensions/overlay-test.ts +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/preset.ts +14 -12
- package/examples/extensions/project-trust.ts +64 -0
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/sandbox/index.ts +16 -14
- package/examples/extensions/sandbox/package-lock.json +90 -90
- package/examples/extensions/sandbox/package.json +17 -17
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/subagent/README.md +13 -13
- package/examples/extensions/subagent/agents.ts +4 -2
- package/examples/extensions/subagent/index.ts +6 -6
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +6 -1
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +7 -7
- package/examples/extensions/working-indicator.ts +4 -4
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/06-extensions.ts +2 -2
- package/examples/sdk/08-prompt-templates.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/examples/sdk/README.md +2 -2
- package/package.json +4 -4
package/docs/settings.md
CHANGED
|
@@ -7,7 +7,19 @@ Atomic uses JSON settings files with project settings overriding global settings
|
|
|
7
7
|
| `~/.atomic/agent/settings.json` | Global (all projects) |
|
|
8
8
|
| `.atomic/settings.json` | Project (current directory) |
|
|
9
9
|
|
|
10
|
-
Edit directly or use `/settings` for common options. Atomic reads legacy `~/.pi/agent/settings.json` and `.pi/settings.json` as compatibility fallbacks, with `.atomic` paths taking precedence.
|
|
10
|
+
Edit directly or use `/settings` for common options. Atomic also reads legacy `~/.pi/agent/settings.json` and `.pi/settings.json` as compatibility fallbacks, with `.atomic` paths taking precedence.
|
|
11
|
+
|
|
12
|
+
## Project Trust
|
|
13
|
+
|
|
14
|
+
On interactive startup, Atomic asks before trusting a project folder that contains trust-gated project inputs and has no saved decision for the folder or a parent folder in `~/.atomic/agent/trust.json`. Trusting a project allows Atomic to load project-local `.atomic/settings.json` and `.atomic` resources, legacy `.pi/settings.json` and `.pi` resources, project-local context files, install missing project packages, and execute project extensions.
|
|
15
|
+
|
|
16
|
+
Non-interactive modes (`-p`, `--mode json`, and `--mode rpc`) do not show a trust prompt. Without an applicable saved trust decision, they use `defaultProjectTrust` from global settings: `ask` (default) and `never` ignore trust-gated project inputs, while `always` trusts them. Pass `--approve`/`-a` or `--no-approve`/`-na` to override project trust for one run.
|
|
17
|
+
|
|
18
|
+
If no extension or saved decision applies, `defaultProjectTrust` controls the fallback behavior. Set it to `"ask"`, `"always"`, or `"never"` in `~/.atomic/agent/settings.json`, or change it with `/settings`.
|
|
19
|
+
|
|
20
|
+
`atomic config` and package commands use the same project trust flow. Pass `--approve` to trust project-local settings for one command or `--no-approve` to ignore them.
|
|
21
|
+
|
|
22
|
+
Use `/trust` in interactive mode to save a project trust decision for future sessions, including trust for the immediate parent folder. It writes `~/.atomic/agent/trust.json` only; the current session is not reloaded, so restart Atomic for changes to take effect.
|
|
11
23
|
|
|
12
24
|
## All Settings
|
|
13
25
|
|
|
@@ -58,13 +70,14 @@ Use `/fast` in interactive mode to edit these settings. Atomic applies fast mode
|
|
|
58
70
|
|---------|------|---------|-------------|
|
|
59
71
|
| `theme` | string | `"dark"` | Theme name (`"dark"`, `"light"`, a Catppuccin built-in, or custom) |
|
|
60
72
|
| `quietStartup` | boolean | `false` | Hide startup header |
|
|
73
|
+
| `defaultProjectTrust` | string | `"ask"` | Fallback project trust behavior: `"ask"`, `"always"`, or `"never"`. Global setting only |
|
|
61
74
|
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
|
62
75
|
| `enableInstallTelemetry` | boolean | `true` | Send an anonymous install/update version ping after first install or changelog-detected updates. This does not control update checks |
|
|
63
76
|
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
|
|
64
77
|
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
|
|
65
78
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
|
66
79
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
|
67
|
-
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
|
80
|
+
| `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
|
|
68
81
|
|
|
69
82
|
### Telemetry and update checks
|
|
70
83
|
|
|
@@ -117,11 +130,13 @@ Set `ATOMIC_SKIP_VERSION_CHECK=1` to disable the Atomic version update check. Us
|
|
|
117
130
|
| `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts |
|
|
118
131
|
| `retry.baseDelayMs` | number | `2000` | Base delay for agent-level exponential backoff (2s, 4s, 8s) |
|
|
119
132
|
| `retry.provider.timeoutMs` | number | SDK default | Provider/SDK request timeout in milliseconds |
|
|
120
|
-
| `retry.provider.maxRetries` | number |
|
|
133
|
+
| `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
|
|
121
134
|
| `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |
|
|
122
135
|
|
|
123
136
|
When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs` (e.g., Google's "quota will reset after 5h"), the request fails immediately with an informative error instead of waiting silently. Set to `0` to disable the cap.
|
|
124
137
|
|
|
138
|
+
Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explicitly needed. Setting it above `0` can make SDK/provider retries handle out-of-usage-limit errors before Atomic sees them, which may block the agent until the provider quota resets in some circumstances.
|
|
139
|
+
|
|
125
140
|
```json
|
|
126
141
|
{
|
|
127
142
|
"retry": {
|
|
@@ -168,7 +183,9 @@ The `/settings` picker offers these presets:
|
|
|
168
183
|
|---------|------|---------|-------------|
|
|
169
184
|
| `steeringMode` | string | `"one-at-a-time"` | How steering messages are sent: `"all"` or `"one-at-a-time"` |
|
|
170
185
|
| `followUpMode` | string | `"one-at-a-time"` | How follow-up messages are sent: `"all"` or `"one-at-a-time"` |
|
|
171
|
-
| `transport` | string | `"
|
|
186
|
+
| `transport` | string | `"auto"` | Preferred transport for providers that support multiple transports: `"sse"`, `"websocket"`, `"websocket-cached"`, or `"auto"` |
|
|
187
|
+
| `httpIdleTimeoutMs` | number | `300000` | HTTP header/body idle timeout in milliseconds, also used by providers with explicit stream idle timeouts. Set to `0` to disable. |
|
|
188
|
+
| `websocketConnectTimeoutMs` | number | `15000` | WebSocket connect/open handshake timeout in milliseconds for providers that support WebSocket transports. Set to `0` to disable. |
|
|
172
189
|
|
|
173
190
|
### Terminal & Images
|
|
174
191
|
|
package/docs/skills.md
CHANGED
|
@@ -26,7 +26,7 @@ Atomic loads skills from:
|
|
|
26
26
|
- Global:
|
|
27
27
|
- `~/.atomic/agent/skills/` (legacy `~/.pi/agent/skills/`)
|
|
28
28
|
- `~/.agents/skills/`
|
|
29
|
-
- Project:
|
|
29
|
+
- Project (only after the project is trusted):
|
|
30
30
|
- `.atomic/skills/` (legacy `.pi/skills/`)
|
|
31
31
|
- `.agents/skills/` in `cwd` and ancestor directories (up to git repo root, or filesystem root when not in a repo)
|
|
32
32
|
- Packages: `skills/` directories, `atomic.skills`, or legacy `pi.skills` entries in `package.json`
|
package/docs/terminal-setup.md
CHANGED
|
@@ -6,6 +6,12 @@ Atomic uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboa
|
|
|
6
6
|
|
|
7
7
|
Work out of the box.
|
|
8
8
|
|
|
9
|
+
## Apple Terminal
|
|
10
|
+
|
|
11
|
+
Atomic enables enhanced key reporting when available. If Terminal.app still sends plain Return for `SHIFT+Enter`, Atomic uses a local macOS modifier fallback to treat that Return as `SHIFT+Enter`.
|
|
12
|
+
|
|
13
|
+
This fallback only works when Atomic runs on the same Mac as Terminal.app. It cannot detect the local keyboard over remote SSH.
|
|
14
|
+
|
|
9
15
|
## Ghostty
|
|
10
16
|
|
|
11
17
|
Add to your Ghostty config (`~/Library/Application Support/com.mitchellh.ghostty/config` on macOS, `~/.config/ghostty/config` on Linux):
|
|
@@ -34,7 +40,7 @@ If you want `SHIFT+Enter` to keep working in tmux via that remap, add `ctrl+j` t
|
|
|
34
40
|
|
|
35
41
|
## WezTerm
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
WezTerm usually works out of the box for `SHIFT+Enter` via xterm modifyOtherKeys. To use the Kitty keyboard protocol explicitly, create `~/.wezterm.lua`:
|
|
38
44
|
|
|
39
45
|
```lua
|
|
40
46
|
local wezterm = require 'wezterm'
|
|
@@ -43,14 +49,50 @@ config.enable_kitty_keyboard = true
|
|
|
43
49
|
return config
|
|
44
50
|
```
|
|
45
51
|
|
|
52
|
+
On macOS, WezTerm binds `Option+Enter` to fullscreen by default. To use `Option+Enter` for Atomic follow-up queueing, add this key override:
|
|
53
|
+
|
|
54
|
+
```lua
|
|
55
|
+
local wezterm = require 'wezterm'
|
|
56
|
+
local config = wezterm.config_builder()
|
|
57
|
+
config.keys = {
|
|
58
|
+
{
|
|
59
|
+
key = 'Enter',
|
|
60
|
+
mods = 'ALT',
|
|
61
|
+
action = wezterm.action.SendString('\x1b[13;3u'),
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
return config
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If you already have a `config.keys` table, add the entry to it.
|
|
68
|
+
|
|
69
|
+
On WSL, WezTerm may require a visible hardware cursor for IME candidate window positioning. If CJK IME candidates do not follow the text cursor, set `ATOMIC_HARDWARE_CURSOR=1` before running Atomic or set `showHardwareCursor` to `true` in settings. The legacy `PI_HARDWARE_CURSOR=1` alias also works.
|
|
70
|
+
|
|
71
|
+
## Alacritty
|
|
72
|
+
|
|
73
|
+
Alacritty usually works out of the box for `SHIFT+Enter`. On macOS, `Option+Enter` may arrive as plain `Enter`. To use `Option+Enter` for Atomic follow-up queueing, add to `~/.config/alacritty/alacritty.toml`:
|
|
74
|
+
|
|
75
|
+
```toml
|
|
76
|
+
[[keyboard.bindings]]
|
|
77
|
+
key = "Enter"
|
|
78
|
+
mods = "Alt"
|
|
79
|
+
chars = "\u001b[13;3u"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Restart Alacritty after changing the config.
|
|
83
|
+
|
|
46
84
|
## VS Code (Integrated Terminal)
|
|
47
85
|
|
|
86
|
+
VS Code 1.109.5 and newer enable Kitty keyboard protocol in the integrated terminal by default, so `SHIFT+Enter` should work out of the box.
|
|
87
|
+
|
|
88
|
+
VS Code versions older than 1.109.5 need an explicit terminal keybinding for `SHIFT+Enter`.
|
|
89
|
+
|
|
48
90
|
`keybindings.json` locations:
|
|
49
91
|
- macOS: `~/Library/Application Support/Code/User/keybindings.json`
|
|
50
92
|
- Linux: `~/.config/Code/User/keybindings.json`
|
|
51
93
|
- Windows: `%APPDATA%\\Code\\User\\keybindings.json`
|
|
52
94
|
|
|
53
|
-
Add to `keybindings.json
|
|
95
|
+
Add to `keybindings.json`:
|
|
54
96
|
|
|
55
97
|
```json
|
|
56
98
|
{
|
package/docs/themes.md
CHANGED
|
@@ -20,7 +20,7 @@ Atomic loads themes from:
|
|
|
20
20
|
|
|
21
21
|
- Built-in: `dark`, `light`, `catppuccin-frappe`, `catppuccin-latte`, `catppuccin-macchiato`, `catppuccin-mocha`
|
|
22
22
|
- Global: `~/.atomic/agent/themes/*.json` (legacy `~/.pi/agent/themes/*.json`)
|
|
23
|
-
- Project: `.atomic/themes/*.json` (legacy `.pi/themes/*.json
|
|
23
|
+
- Project: `.atomic/themes/*.json` (legacy `.pi/themes/*.json`, only after the project is trusted)
|
|
24
24
|
- Packages: `themes/` directories, `atomic.themes`, or legacy `pi.themes` entries in `package.json`
|
|
25
25
|
- Settings: `themes` array with files or directories
|
|
26
26
|
- CLI: `--theme <path>` (repeatable)
|
package/docs/tmux.md
CHANGED
|
@@ -18,7 +18,7 @@ tmux kill-server
|
|
|
18
18
|
tmux
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Atomic requests extended key reporting automatically when Kitty keyboard protocol is not available. With `extended-keys-format csi-u`, tmux forwards modified keys in CSI-u format, which is the most reliable configuration.
|
|
21
|
+
Atomic requests extended key reporting automatically when Kitty keyboard protocol is not available. With `extended-keys-format csi-u`, tmux forwards modified keys in CSI-u format, which is the most reliable configuration. The `extended-keys-format` option requires tmux 3.5 or later.
|
|
22
22
|
|
|
23
23
|
## Why `csi-u` Is Recommended
|
|
24
24
|
|
|
@@ -57,5 +57,7 @@ This affects the default keybindings (`Enter` to submit, `SHIFT+Enter` for newli
|
|
|
57
57
|
|
|
58
58
|
## Requirements
|
|
59
59
|
|
|
60
|
-
- tmux 3.
|
|
60
|
+
- tmux 3.5 or later for `extended-keys-format csi-u` (run `tmux -V` to check)
|
|
61
61
|
- A terminal emulator that supports extended keys (Ghostty, Kitty, iTerm2, WezTerm, Windows Terminal)
|
|
62
|
+
|
|
63
|
+
With tmux 3.2 through 3.4, omit `extended-keys-format csi-u`; Atomic still supports tmux's default xterm `modifyOtherKeys` format.
|
package/docs/tui.md
CHANGED
|
@@ -50,9 +50,9 @@ When a `Focusable` component has focus, TUI:
|
|
|
50
50
|
1. Sets `focused = true` on the component
|
|
51
51
|
2. Scans rendered output for `CURSOR_MARKER` (a zero-width APC escape sequence)
|
|
52
52
|
3. Positions the hardware terminal cursor at that location
|
|
53
|
-
4. Shows the hardware cursor
|
|
53
|
+
4. Shows the hardware cursor only when `showHardwareCursor` is enabled
|
|
54
54
|
|
|
55
|
-
This
|
|
55
|
+
The cursor remains hidden by default. This keeps the fake cursor rendering, while still positioning the hardware cursor for terminals that track IME candidate windows with hidden cursors. Some terminals require a visible hardware cursor for IME positioning; enable it with `showHardwareCursor`, `setShowHardwareCursor(true)`, or `ATOMIC_HARDWARE_CURSOR=1`. The `Editor` and `Input` built-in components already implement this interface.
|
|
56
56
|
|
|
57
57
|
### Container Components with Embedded Inputs
|
|
58
58
|
|
|
@@ -138,8 +138,11 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
138
138
|
// Responsive: hide on narrow terminals
|
|
139
139
|
visible: (termWidth, termHeight) => termWidth >= 80,
|
|
140
140
|
},
|
|
141
|
-
// Get handle for programmatic visibility control
|
|
141
|
+
// Get handle for programmatic focus and visibility control
|
|
142
142
|
onHandle: (handle) => {
|
|
143
|
+
// handle.focus() - focus this overlay and bring it to the visual front
|
|
144
|
+
// handle.unfocus() - release input to normal fallback
|
|
145
|
+
// handle.unfocus({ target }) - release input to a specific component or null
|
|
143
146
|
// handle.setHidden(true/false) - toggle visibility
|
|
144
147
|
// handle.hide() - permanently remove
|
|
145
148
|
},
|
|
@@ -147,6 +150,12 @@ const result = await ctx.ui.custom<string | null>(
|
|
|
147
150
|
);
|
|
148
151
|
```
|
|
149
152
|
|
|
153
|
+
### Overlay Focus
|
|
154
|
+
|
|
155
|
+
A focused visible overlay keeps input ownership across temporary non-overlay UI. If an overlay opens another `ctx.ui.custom()` component without `{ overlay: true }`, that replacement UI receives input while it is active; when it closes, the focused overlay can reclaim input.
|
|
156
|
+
|
|
157
|
+
Use `handle.unfocus()` when a visible overlay should stop owning input and let TUI fall back to another visible capturing overlay or the previous focus target. Use `handle.unfocus({ target })` when a specific component should receive input while the overlay stays visible. Passing `{ target: null }` intentionally leaves no focused component until focus is set again.
|
|
158
|
+
|
|
150
159
|
### Overlay Lifecycle
|
|
151
160
|
|
|
152
161
|
Overlay components are disposed when closed. Don't reuse references - create fresh instances:
|
|
@@ -433,10 +442,10 @@ interface MyTheme {
|
|
|
433
442
|
|
|
434
443
|
## Debug logging
|
|
435
444
|
|
|
436
|
-
Set `
|
|
445
|
+
Set `ATOMIC_TUI_WRITE_LOG` to capture the raw ANSI stream written to stdout.
|
|
437
446
|
|
|
438
447
|
```bash
|
|
439
|
-
|
|
448
|
+
ATOMIC_TUI_WRITE_LOG=/tmp/tui-ansi.log atomic
|
|
440
449
|
```
|
|
441
450
|
|
|
442
451
|
Atomic vendors TUI components through the installed `@earendil-works/pi-tui` dependency; this monorepo does not include the upstream TUI test source tree.
|
package/docs/usage.md
CHANGED
|
@@ -79,7 +79,9 @@ Sessions are saved automatically to `~/.atomic/agent/sessions/`, organized by wo
|
|
|
79
79
|
atomic -c # Continue most recent session
|
|
80
80
|
atomic -r # Browse and select a session
|
|
81
81
|
atomic --no-session # Ephemeral mode; do not save
|
|
82
|
-
atomic --session <path|id> # Use a specific session file or session ID
|
|
82
|
+
atomic --session <path|id> # Use a specific session file or partial session ID
|
|
83
|
+
atomic --session-id <id> # Use/create an exact project-local session ID
|
|
84
|
+
atomic --name "Refactor" # Set the session display name
|
|
83
85
|
atomic --fork <path|id> # Fork a session into a new session file
|
|
84
86
|
```
|
|
85
87
|
|
|
@@ -118,7 +120,7 @@ Use `/export [file]` to write a session to HTML.
|
|
|
118
120
|
|
|
119
121
|
Use `/share` to upload a private GitHub gist with a shareable HTML link.
|
|
120
122
|
|
|
121
|
-
If you use Atomic for open source work and want to publish sessions for model, prompt, tool, and evaluation research,
|
|
123
|
+
If you use Atomic for open source work and want to publish sessions for model, prompt, tool, and evaluation research, use an Atomic-owned workflow or your team's dataset process. Upstream Pi session-sharing utilities may still be useful for historical context, but they are not the primary Atomic publication path.
|
|
122
124
|
|
|
123
125
|
## CLI Reference
|
|
124
126
|
|
|
@@ -176,8 +178,10 @@ cat README.md | atomic -p "Summarize this text"
|
|
|
176
178
|
| `-c`, `--continue` | Continue the most recent session |
|
|
177
179
|
| `-r`, `--resume` | Browse and select a session |
|
|
178
180
|
| `--session <path\|id>` | Use a specific session file or partial UUID |
|
|
181
|
+
| `--session-id <id>` | Use an exact project session ID, creating it if missing |
|
|
179
182
|
| `--fork <path\|id>` | Fork a session file or partial UUID into a new session |
|
|
180
183
|
| `--session-dir <dir>` | Custom session storage directory |
|
|
184
|
+
| `--name <name>`, `-n <name>` | Set the session display name |
|
|
181
185
|
| `--no-session` | Ephemeral mode; do not save |
|
|
182
186
|
|
|
183
187
|
### Tool Options
|
|
@@ -185,10 +189,20 @@ cat README.md | atomic -p "Summarize this text"
|
|
|
185
189
|
| Option | Description |
|
|
186
190
|
|--------|-------------|
|
|
187
191
|
| `--tools <list>`, `-t <list>` | Allowlist specific built-in, extension, and custom tools |
|
|
192
|
+
| `--exclude-tools <list>`, `-xt <list>` | Denylist specific built-in, extension, and custom tools |
|
|
188
193
|
| `--no-builtin-tools`, `-nbt` | Disable built-in tools but keep extension/custom tools enabled |
|
|
189
194
|
| `--no-tools`, `-nt` | Disable all tools |
|
|
190
195
|
|
|
191
|
-
Default built-in tools: `read`, `bash`, `edit`, `write`, `ask_user_question`, `todo`. Additional built-in read-only tools are available through tool options: `grep`, `find`, `ls`.
|
|
196
|
+
Default built-in tools: `read`, `bash`, `edit`, `write`, `ask_user_question`, `todo`. Additional built-in read-only tools are available through tool options: `grep`, `find`, `ls`. Use `--exclude-tools` to disable one or more tools while leaving the rest available, for example `atomic --exclude-tools ask_user_question`.
|
|
197
|
+
|
|
198
|
+
### Project Trust Options
|
|
199
|
+
|
|
200
|
+
| Option | Description |
|
|
201
|
+
|--------|-------------|
|
|
202
|
+
| `--approve`, `-a` | Trust project-local files/resources for this run |
|
|
203
|
+
| `--no-approve`, `-na` | Ignore project-local files/resources for this run |
|
|
204
|
+
|
|
205
|
+
Project trust gates `.atomic`/legacy `.pi` project resources, project package settings, project-local context files, and `.agents/skills` discovered from the project tree. Saved trust decisions can be managed with `/trust`; see [Security](/security).
|
|
192
206
|
|
|
193
207
|
### Resource Options
|
|
194
208
|
|
package/docs/workflows.md
CHANGED
|
@@ -588,6 +588,41 @@ Atomic discovers workflow definitions in this order:
|
|
|
588
588
|
|
|
589
589
|
A workflow module may export one default workflow definition and/or named workflow definitions. Discovery checks the default export first, then named exports.
|
|
590
590
|
|
|
591
|
+
Every runtime export of a discovered workflow file is validated as a workflow definition. A named export that is not a compiled definition — a widget factory, shared constant, or utility function — is rejected with an `INVALID_DEFINITION` discovery diagnostic (`export is not an object`), even when the module also has a valid default export (the valid workflow still loads; the diagnostic flags the extra export as skipped). Type-only exports (`export type` / `export interface`) are erased at runtime and never flagged.
|
|
592
|
+
|
|
593
|
+
To co-locate reusable helpers with your workflows — for example a `ctx.ui.custom<T>` widget factory you want to import in tests without running the workflow — put them in a subdirectory and import them from the workflow file. Discovery scans only the top level of each workflow directory, so subdirectories such as `.atomic/workflows/lib/` are never treated as workflow modules:
|
|
594
|
+
|
|
595
|
+
```text
|
|
596
|
+
.atomic/workflows/
|
|
597
|
+
release-picker.ts # only runtime export: defineWorkflow(...).compile()
|
|
598
|
+
lib/
|
|
599
|
+
table-selector.ts # widget factory + helpers; not scanned by discovery
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
```ts
|
|
603
|
+
// .atomic/workflows/release-picker.ts
|
|
604
|
+
import { defineWorkflow, Type } from "@bastani/workflows";
|
|
605
|
+
import { tableSelectorFactory } from "./lib/table-selector.js";
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
```ts
|
|
609
|
+
// .atomic/workflows/lib/table-selector.ts
|
|
610
|
+
import type { WorkflowCustomUiFactory } from "@bastani/workflows";
|
|
611
|
+
|
|
612
|
+
export const tableSelectorFactory: WorkflowCustomUiFactory<{ id: string; name: string }> = (
|
|
613
|
+
tui,
|
|
614
|
+
theme,
|
|
615
|
+
_keybindings,
|
|
616
|
+
done,
|
|
617
|
+
) => ({
|
|
618
|
+
render: (width) => ["..."],
|
|
619
|
+
invalidate: () => {},
|
|
620
|
+
handleInput: (data) => {
|
|
621
|
+
/* ... done({ id, name }) on Enter ... */
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
```
|
|
625
|
+
|
|
591
626
|
Workflow files are loaded via [jiti](https://github.com/unjs/jiti), so TypeScript works without compilation.
|
|
592
627
|
|
|
593
628
|
## Workflow Configuration
|
|
@@ -765,7 +800,7 @@ Input overrides are bare `key=value` tokens. Values are JSON-parsed when possibl
|
|
|
765
800
|
|
|
766
801
|
In the TUI, `/workflow <name>` opens an input picker when the workflow declares inputs and either no arguments were supplied or required inputs are missing. Supplied values seed the picker. Pass `--no-picker` to skip that interactive flow.
|
|
767
802
|
|
|
768
|
-
In non-interactive (`-p`, `--print`, or `--mode json`) sessions, named workflow dispatch waits for the terminal run snapshot and skips pickers. Because human input is runtime-only and workflows no longer carry a declaration-time HIL marker, headless dispatch does not reject a workflow just because its source contains `ctx.ui.*`. If you copy a HIL workflow example into a headless session, it can pass dispatch and then fail when execution reaches the prompt with an error such as `atomic-workflows:
|
|
803
|
+
In non-interactive (`-p`, `--print`, or `--mode json`) sessions, named workflow dispatch waits for the terminal run snapshot and skips pickers. Because human input is runtime-only and workflows no longer carry a declaration-time HIL marker, headless dispatch does not reject a workflow just because its source contains `ctx.ui.*`. If you copy a HIL workflow example into a headless session, it can pass dispatch and then fail when execution reaches the prompt with an error such as `atomic-workflows: interactive ctx.ui.confirm is unavailable in headless (non-interactive) mode; run the workflow in interactive mode or remove the interactive prompt from this stage` (the primitive name varies, including `ctx.ui.custom`). Run those workflows interactively, or guard/remove runtime `ctx.ui.*` calls before using headless mode.
|
|
769
804
|
|
|
770
805
|
<p align="center"><img src="images/workflow-input-picker.png" alt="Workflow Input Picker" width="600" /></p>
|
|
771
806
|
|
|
@@ -831,6 +866,7 @@ workflow({ action: "reload", reason: "added team workflow" })
|
|
|
831
866
|
Control behavior:
|
|
832
867
|
|
|
833
868
|
- `runId` accepts full run ids or unique prefixes for lifecycle and inspection actions. Status lists and run pickers show top-level user-launched workflows; nested child runs are implementation details of the expanded parent graph.
|
|
869
|
+
- `status` / `status <runId>` show terminal `ctx.exit(...)` statuses (`completed`, `skipped`, `cancelled`, or `blocked`) and the optional exit reason when one was supplied.
|
|
834
870
|
- `stages` lists stage summaries, including flattened stages from nested `ctx.workflow(...)` imports and `sessionFile`/`transcriptPath` when a stage has a persisted session. Use `statusFilter: "all"` to include completed, failed, skipped, and pending stages.
|
|
835
871
|
- `stage` returns details for one stage by stage id, unique prefix, or stage name, including nested child stages shown in the expanded graph and the persisted `sessionFile` when available.
|
|
836
872
|
- `transcript` is reference-first with a small preview by default: it returns metadata, transcript paths, and up to 5 recent entries. For targeted lookup, quote the exact `sessionFile`/`transcriptPath` value without changing platform separators (preserve Windows backslashes), search it with `rg` or `grep`, then read only small surrounding ranges. Text results include JSON-escaped `sessionFileJson`/`transcriptPathJson` lines for copy-safe path literals. Pass explicit `tail` or `limit` to override the 5-entry preview; `tail` overrides `limit`; `includeToolOutput` includes captured snapshot tool output in snapshot transcript results.
|
|
@@ -929,7 +965,7 @@ workflow({
|
|
|
929
965
|
})
|
|
930
966
|
```
|
|
931
967
|
|
|
932
|
-
Direct mode supports top-level/default options and per-task options such as `context`, `forkFromSessionFile`, `model`, `fallbackModels`, `thinkingLevel`, `tools`, `noTools`, `customTools`, `mcp`, `output`, `outputMode`, `reads`, `worktree`, `gitWorktreeDir`, `baseBranch`, `maxOutput`, `artifacts`, `sessionDir`, `cwd`, and `agentDir`. Direct chains also support `chainName`, `chainDir`, and `failFast`.
|
|
968
|
+
Direct mode supports top-level/default options and per-task options such as `context`, `forkFromSessionFile`, `model`, `fallbackModels`, `thinkingLevel`, `tools`, `noTools`, `customTools`, `bashPolicy`, `mcp`, `output`, `outputMode`, `reads`, `worktree`, `gitWorktreeDir`, `baseBranch`, `maxOutput`, `artifacts`, `sessionDir`, `cwd`, and `agentDir`. Direct chains also support `chainName`, `chainDir`, and `failFast`.
|
|
933
969
|
|
|
934
970
|
For large fan-outs, prefer `outputMode: "file-only"` so the parent result contains compact file references instead of full output. Treat intercom payloads from async direct runs as user-visible workflow output.
|
|
935
971
|
|
|
@@ -1020,7 +1056,42 @@ Builder basics:
|
|
|
1020
1056
|
|
|
1021
1057
|
`prompt` and `task` are aliases for task text. Prefer `prompt` inside authored workflow files because it mirrors lower-level `stage.prompt(...)`; `task` remains useful in direct tool calls and chain examples.
|
|
1022
1058
|
|
|
1023
|
-
Author workflows to create at least one tracked stage by calling `ctx.task()`, `ctx.chain()`, `ctx.parallel()`, `ctx.stage()`, or `ctx.workflow()` in the run body so each run has graph nodes to inspect, attach to, interrupt, resume, and render.
|
|
1059
|
+
Author workflows to create at least one tracked stage by calling `ctx.task()`, `ctx.chain()`, `ctx.parallel()`, `ctx.stage()`, or `ctx.workflow()` in the run body so each normal run has graph nodes to inspect, attach to, interrupt, resume, and render. Guard-only workflows may call `ctx.exit(...)` before creating a stage when they intentionally stop early.
|
|
1060
|
+
|
|
1061
|
+
### Early exit with `ctx.exit()`
|
|
1062
|
+
|
|
1063
|
+
Use `ctx.exit(options?)` when workflow code intentionally stops the current run from a helper, branch, loop, or precondition guard without classifying the run as failed. `ctx.exit()` throws an executor-owned control signal and is typed as `never`, so code after it is unreachable. In async `.run()` bodies, prefer `return ctx.exit(...)` when the exit is the only path so TypeScript can see the non-returning branch.
|
|
1064
|
+
|
|
1065
|
+
```ts
|
|
1066
|
+
export default defineWorkflow("guarded-import")
|
|
1067
|
+
.output("scanned", Type.Number())
|
|
1068
|
+
.run(async (ctx) => {
|
|
1069
|
+
const files = await findCandidateFiles(ctx.cwd);
|
|
1070
|
+
if (files.length === 0) {
|
|
1071
|
+
return ctx.exit({
|
|
1072
|
+
status: "skipped",
|
|
1073
|
+
reason: "No matching files",
|
|
1074
|
+
outputs: { scanned: 0 },
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const review = await ctx.task("review", { prompt: `Review ${files.join(", ")}` });
|
|
1079
|
+
return { scanned: files.length };
|
|
1080
|
+
})
|
|
1081
|
+
.compile();
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
`ctx.exit()` accepts `status: "completed" | "skipped" | "cancelled" | "blocked"`; it never accepts `"failed"` or `"killed"` because thrown errors and external run-control keep those meanings. `status` defaults to `"completed"`. `reason` is persisted and shown in status surfaces, including the default `/workflow status` list and `/workflow status <runId>` detail, so do not put secrets in it. `outputs` may contain a partial subset of declared outputs; provided keys still must be declared with `.output(...)`, match their TypeBox schema, and be JSON-serializable. Missing required outputs are allowed only on the `ctx.exit(...)` path. Exited runs are terminal and not resumable; external `kill`, `pause`, and `interrupt` keep their existing behavior.
|
|
1085
|
+
|
|
1086
|
+
The first selected `ctx.exit({ outputs })` snapshots its output payload synchronously by value before JavaScript `finally` blocks or cleanup callbacks can mutate the caller-owned object. The snapshot preserves undeclared keys and invalid values until post-cleanup validation, so deleting an undeclared key or changing an invalid value after `ctx.exit(...)` does not change the terminal validation result. If reading `status`, `reason`, or `outputs` options, or enumerating/copying the output snapshot itself, throws, Atomic still selects the exit signal, runs workflow-exit cleanup when feasible, and then records a terminal non-resumable authoring failure (`resumable: false`) if no external terminal control won first.
|
|
1087
|
+
|
|
1088
|
+
After the first `ctx.exit(...)` wins, the executor treats that exit as a level-triggered gate. Later delayed calls to `ctx.stage`, `ctx.task`, `ctx.chain`, `ctx.parallel`, `ctx.workflow`, or graph-backed `ctx.ui.*` prompts rethrow the selected exit signal before creating stages, prompt nodes, child runs, or control handles. Retained `StageContext` handles from before the exit also become inert: `prompt`, `complete`, steering/follow-up, model/thinking controls, tree navigation, compaction, abort, and attached-pane session-realization paths refuse to touch or create an `AgentSession` after the exit is selected. `ctx.parallel` stops dequeuing queued work after exit even with `failFast: false` and limited concurrency; already-started stages and prompt nodes are finalized as `skipped` with a `workflow-exit` reason that prompt-node abort handling preserves instead of overwriting with a generic run-aborted reason.
|
|
1089
|
+
|
|
1090
|
+
Continuation replay also observes the exit gate. Replayed `ctx.stage(...).prompt(...)`, replayed `complete(...)`, graph-backed prompt-node replay, and completed child-boundary replay re-check for a selected exit after their replay microtask and before writing a current-run completed stage end. If `ctx.exit(...)` wins that gap, the pending replay finalizer is skipped/suppressed with the workflow-exit reason instead of creating a misleading completed stage in the resumed run.
|
|
1091
|
+
|
|
1092
|
+
The store is the terminal authority for all run-end races. `ctx.exit(...)` starts cleanup before validating exit outputs, and an external `/workflow kill` can still win the terminal `recordRunEnd` write while that cleanup is pending. When that happens, the SDK `RunResult`, `onRunEnd` callback, live store, and persisted `workflow.run.end` entries all report the canonical `killed` state; the losing `ctx.exit` status or validation failure is not returned and does not append a second run-end entry.
|
|
1093
|
+
|
|
1094
|
+
Control-signal probing is fail-closed. When the executor inspects an arbitrary thrown value or abort reason for internal workflow-exit markers, parent-exit markers, aggregate `errors`, `cause`, `reason`, or `scope`, throwing or inaccessible accessors are treated as “no signal for that branch.” The run then continues through ordinary failure finalization, or the ordinary killed path for external abort reasons, instead of letting author-defined getters escape the executor catch path or be misclassified as `ctx.exit(...)`.
|
|
1024
1095
|
|
|
1025
1096
|
### Guiding Principles
|
|
1026
1097
|
|
|
@@ -1061,7 +1132,7 @@ In TypeScript workflow files, `.input(...)` also narrows `ctx.inputs` for better
|
|
|
1061
1132
|
|
|
1062
1133
|
### Outputs
|
|
1063
1134
|
|
|
1064
|
-
Workflow outputs are runtime contracts for completed workflow runs and for parent workflows that call a child with `ctx.workflow(childWorkflow, ...)`. A workflow returns a JSON-serializable object from `.run()`, and `.output(key, schema)` documents, validates, and exposes keys from that returned object. Primitives, arrays, `null`, functions, symbols, `undefined` properties, `NaN`, and infinite numbers fail validation.
|
|
1135
|
+
Workflow outputs are runtime contracts for completed workflow runs and for parent workflows that call a child with `ctx.workflow(childWorkflow, ...)`. A workflow normally returns a JSON-serializable object from `.run()`, and `.output(key, schema)` documents, validates, and exposes keys from that returned object. `ctx.exit({ outputs })` can expose a partial subset of the same declared output contract when the run intentionally stops early. Primitives, arrays, `null`, functions, symbols, `undefined` properties, `NaN`, and infinite numbers fail validation.
|
|
1065
1136
|
|
|
1066
1137
|
**Return convention:** outputs are return-object keys. Atomic never infers child workflow outputs from stage names, stage order, or the final assistant message. If a parent should read `child.outputs.foo`, the child workflow's `.run()` must both declare `.output("foo", schema)` and return `{ foo: value }`. `result` is not special and is never added for you: to expose `result`, declare `.output("result", schema)` and return `{ result }` exactly like any other output. Returning a key that is not declared with `.output(...)` fails the run with `atomic-workflows: workflow "<name>" returned undeclared output "<key>"; declare it with .output("<key>", Type....) or remove it from the .run() return`.
|
|
1067
1138
|
|
|
@@ -1167,7 +1238,7 @@ Tradeoff: `Type.Unsafe<T>()` does not deeply validate at runtime — it trusts t
|
|
|
1167
1238
|
|
|
1168
1239
|
- `ctx.inputs.x` is `Static<inputSchema>` for the input you declared with `.input("x", schema)` — required and defaulted schemas are always present, and `Type.Optional(...)` adds `| undefined`.
|
|
1169
1240
|
- The `.run()` return is checked against your declared outputs at **compile time** (a missing required output or a wrong value type is a TypeScript error) and at **runtime** via TypeBox `Value` (undeclared keys are rejected and the declared shape is enforced recursively).
|
|
1170
|
-
- `ctx.workflow(child).outputs` is
|
|
1241
|
+
- `ctx.workflow(child)` returns a discriminated child result. When `child.exited === false`, `child.outputs` is the child's full declared `.output(...)` contract; when `child.exited === true`, `child.outputs` is `Partial<TOutputs>` because child `ctx.exit({ outputs })` may intentionally provide only a subset.
|
|
1171
1242
|
|
|
1172
1243
|
Use `Static<typeof schema>` (both `Static` and `TSchema` are re-exported from `@bastani/workflows`) when you need the inferred TypeScript type of a schema directly — for example to type a helper that builds an output value.
|
|
1173
1244
|
|
|
@@ -1209,6 +1280,9 @@ export default defineWorkflow("research-and-synthesize")
|
|
|
1209
1280
|
inputs: { topic: ctx.inputs.topic },
|
|
1210
1281
|
stageName: "run shared research",
|
|
1211
1282
|
});
|
|
1283
|
+
if (child.exited === true) {
|
|
1284
|
+
return ctx.exit({ status: child.status, reason: child.exitReason ?? "shared research stopped early" });
|
|
1285
|
+
}
|
|
1212
1286
|
|
|
1213
1287
|
const final = await ctx.task("synthesize", {
|
|
1214
1288
|
prompt: `Synthesize:\n\n${String(child.outputs.summary)}`,
|
|
@@ -1271,6 +1345,9 @@ export default defineWorkflow("research-then-implement")
|
|
|
1271
1345
|
inputs: { prompt: topic, max_concurrency: 4 },
|
|
1272
1346
|
stageName: "deep research",
|
|
1273
1347
|
});
|
|
1348
|
+
if (research.exited === true) {
|
|
1349
|
+
return ctx.exit({ status: research.status, reason: research.exitReason ?? "deep research stopped early" });
|
|
1350
|
+
}
|
|
1274
1351
|
|
|
1275
1352
|
if (String(ctx.inputs.runner) === "ralph") {
|
|
1276
1353
|
const implementation = await ctx.workflow(ralph, {
|
|
@@ -1280,6 +1357,9 @@ export default defineWorkflow("research-then-implement")
|
|
|
1280
1357
|
},
|
|
1281
1358
|
stageName: "ralph implementation",
|
|
1282
1359
|
});
|
|
1360
|
+
if (implementation.exited === true) {
|
|
1361
|
+
return ctx.exit({ status: implementation.status, reason: implementation.exitReason ?? "ralph stopped early" });
|
|
1362
|
+
}
|
|
1283
1363
|
|
|
1284
1364
|
return {
|
|
1285
1365
|
research_doc_path: research.outputs.research_doc_path,
|
|
@@ -1295,6 +1375,9 @@ export default defineWorkflow("research-then-implement")
|
|
|
1295
1375
|
},
|
|
1296
1376
|
stageName: "goal implementation",
|
|
1297
1377
|
});
|
|
1378
|
+
if (implementation.exited === true) {
|
|
1379
|
+
return ctx.exit({ status: implementation.status, reason: implementation.exitReason ?? "goal stopped early" });
|
|
1380
|
+
}
|
|
1298
1381
|
|
|
1299
1382
|
return {
|
|
1300
1383
|
research_doc_path: research.outputs.research_doc_path,
|
|
@@ -1313,8 +1396,10 @@ Passing a compiled definition directly to `ctx.workflow(...)` uses the child wor
|
|
|
1313
1396
|
|---|---|
|
|
1314
1397
|
| `workflow` | Normalized child workflow name. |
|
|
1315
1398
|
| `runId` | Nested child run id. |
|
|
1316
|
-
| `status` | `completed` when the child
|
|
1317
|
-
| `
|
|
1399
|
+
| `status` | `completed`, or `skipped` / `cancelled` / `blocked` when the child intentionally ended with `ctx.exit(...)`. Failed or externally killed children make the parent child call fail. |
|
|
1400
|
+
| `exited` | `false` for normal child completion; `true` when the child used `ctx.exit(...)` (including `ctx.exit({ status: "completed" })`). |
|
|
1401
|
+
| `outputs` | Full declared child outputs when `exited === false`; partial declared child outputs when `exited === true`. |
|
|
1402
|
+
| `exitReason` | Optional child `ctx.exit({ reason })` text, present only on the `exited === true` branch. |
|
|
1318
1403
|
|
|
1319
1404
|
`ctx.workflow()` options:
|
|
1320
1405
|
|
|
@@ -1327,17 +1412,23 @@ Output exposure rules:
|
|
|
1327
1412
|
|
|
1328
1413
|
```ts
|
|
1329
1414
|
const child = await ctx.workflow(sharedResearch);
|
|
1330
|
-
child.
|
|
1331
|
-
child.outputs.
|
|
1415
|
+
if (child.exited === true) {
|
|
1416
|
+
child.outputs.summary; // string | undefined: ctx.exit({ outputs }) may be partial
|
|
1417
|
+
} else {
|
|
1418
|
+
child.outputs.summary; // string: normal completion returned the full declared contract
|
|
1419
|
+
child.outputs.sources; // string[] | undefined: optional output declared by sharedResearch
|
|
1420
|
+
}
|
|
1332
1421
|
```
|
|
1333
1422
|
|
|
1334
|
-
A child exposes exactly its declared outputs — the keys it declared with `.output(...)` and returned from `.run()`. There are no implicit outputs and no raw return-object passthrough. If `.run()` returns a key that was not declared with `.output(...)`, the child run fails with `atomic-workflows: workflow "<childName>" returned undeclared output "<key>"; declare it with .output("<key>", Type....) or remove it from the .run() return`, and the parent surfaces that failure through the wrapper `atomic-workflows: child workflow "<childName>" (<displayName>) failed with status failed: ...`. A child with no declared outputs therefore exposes no outputs. Missing required outputs, schema type mismatches, and non-JSON-serializable returned values fail
|
|
1423
|
+
A child exposes exactly its declared outputs — the keys it declared with `.output(...)` and returned from `.run()` or supplied to `ctx.exit({ outputs })`. There are no implicit outputs and no raw return-object passthrough. If `.run()` returns a key that was not declared with `.output(...)`, the child run fails with `atomic-workflows: workflow "<childName>" returned undeclared output "<key>"; declare it with .output("<key>", Type....) or remove it from the .run() return`, and the parent surfaces that failure through the wrapper `atomic-workflows: child workflow "<childName>" (<displayName>) failed with status failed: ...`. A child with no declared outputs therefore exposes no outputs. Missing required outputs, schema type mismatches, and non-JSON-serializable returned values fail normal child completion before the parent continues; child `ctx.exit({ outputs })` allows missing required outputs but still validates every provided key and sets `child.exited === true` so parent code must handle the partial shape.
|
|
1335
1424
|
|
|
1336
1425
|
Only compiled workflow definitions can be passed to `ctx.workflow(...)`. Import reusable workflows with TypeScript `import` statements first; use `/workflow` names such as `goal` only for launching named runs, not as `ctx.workflow(...)` arguments. If a module is missing or does not export a compiled workflow definition, workflow discovery fails when loading that module. Nested child workflows count against `maxDepth` (default `4` total workflow levels).
|
|
1337
1426
|
|
|
1338
|
-
The graph includes both the parent boundary node and the imported child workflow's own stages while the child is loading/running, so the user can observe progress and interrupt sub-workflows before they complete. Completed boundaries still retain the child workflow name, child run id prefix, and exposed output count for replay/debugging. Use `stageName` when the parent needs a more specific label, but keep it concise so the child summary remains readable in the graph.
|
|
1427
|
+
The graph includes both the parent boundary node and the imported child workflow's own stages while the child is loading/running, so the user can observe progress and interrupt sub-workflows before they complete. Completed boundaries still retain the child workflow name, child run id prefix, and exposed output count for replay/debugging. Skipped or failed boundaries do not retain child-edge metadata (`workflowChild` / `workflowChildRun`), and graph expansion ignores any stale non-completed boundary metadata from older persisted sessions instead of flattening an unrelated child run. Use `stageName` when the parent needs a more specific label, but keep it concise so the child summary remains readable in the graph.
|
|
1428
|
+
|
|
1429
|
+
If a parent workflow exits through `ctx.exit(...)` while a child workflow is in flight, the parent executor only skips the parent boundary and sends the child a typed parent-exit abort reason. The hidden child executor owns child cleanup: active child stages and prompt nodes are skipped for `workflow-exit`, live child stage handles/sessions are disposed, and the child run is finalized as terminal `cancelled` (not `killed`) and non-resumable. The child executor writes each skipped child `workflow.stage.end` exactly once before its child `workflow.run.end`, and parent exit finalization waits for that child cleanup before writing the parent `workflow.run.end`, so restored sessions do not reconstruct the child as interrupted or failed. The skipped parent boundary clears any live child-run edge before store or persistence updates, so status/graph views do not display stale child stages from a boundary that did not complete. A delayed parent branch that calls `ctx.workflow(...)` after the exit gate is selected does not create a boundary or child run.
|
|
1339
1430
|
|
|
1340
|
-
Continuation replay treats the parent child-workflow boundary as the durable checkpoint: a previously completed child boundary replays with the original exposed outputs and without re-running the child, while a child that failed or was interrupted before completion starts again from the beginning on continuation.
|
|
1431
|
+
Continuation replay treats the parent child-workflow boundary as the durable checkpoint: a previously completed child boundary replays with the original exposed outputs and without re-running the child, while a child that failed or was interrupted before completion starts again from the beginning on continuation. If `ctx.exit(...)` wins while a completed boundary is being replayed but before replay finalization, the boundary is finalized as skipped and its preloaded child metadata is omitted from store, persistence, restore, and expanded graph views.
|
|
1341
1432
|
|
|
1342
1433
|
## Workflow Primitives
|
|
1343
1434
|
|
|
@@ -1381,10 +1472,31 @@ Common task/stage options include:
|
|
|
1381
1472
|
- `previous` for small handoff context; use artifact paths plus `reads` for large outputs, logs, research bundles, or reviewer payloads
|
|
1382
1473
|
- `context: "fresh" | "fork"`, `forkFromSessionFile`
|
|
1383
1474
|
- `model`, `fallbackModels`, `thinkingLevel`, `scopedModels`, `modelRegistry` — `model` and each `fallbackModels` entry accept a `model_name:thinking_effort` reasoning suffix; the standalone `thinkingLevel` is deprecated (see [Reasoning levels](#reasoning-levels))
|
|
1384
|
-
- `tools`, `noTools`, `customTools`, `mcp: { allow?: string[], deny?: string[] }`
|
|
1475
|
+
- `tools`, `noTools`, `customTools`, `mcp: { allow?: string[], deny?: string[] }`, `bashPolicy`
|
|
1385
1476
|
- `output`, `outputMode`, `reads`, `worktree`, `gitWorktreeDir`, `baseBranch`, `maxOutput`, `artifacts`, `sessionDir`, `cwd`, `agentDir`
|
|
1386
1477
|
- advanced host-supplied SDK seams: `authStorage`, `resourceLoader`, `sessionManager`, `settingsManager`, `sessionStartEvent`
|
|
1387
1478
|
|
|
1479
|
+
`bashPolicy` scopes the built-in `bash` tool for one stage or task. `tools` must still include `"bash"` (or leave it available by default); the policy only narrows command text after the shell tool is exposed. It supports exact strings, `{ prefix }`, command-string `{ glob }`, and `{ regex, flags? }` rules, `default: "allow" | "deny"` (default `"allow"`), `deny` precedence, and `match: "segments" | "whole"` (default `"segments"`). Omitting `bashPolicy`, passing `{}`, or passing a default-allow policy with no `allow`/`deny` rules (including empty arrays or match-only default-allow policies) preserves legacy behavior and does not parse commands; malformed policy shapes such as unknown top-level keys (`denny`, `extra`), non-array `allow`/`deny`, invalid rule objects, invalid regexes, invalid glob bracket ranges, or stateful `g`/`y` regex flags fail closed as `invalid-policy`. Segment mode checks each command in pipelines/chains/substitutions before execution, treats unquoted LF, CRLF, and bare CR as command separators, keeps non-leading Bash `>|` noclobber redirections inside the current command segment, and rejects reserved/compound shell heads, leading redirections, attached command-head redirections, and command heads that are not literal words.
|
|
1480
|
+
|
|
1481
|
+
```ts
|
|
1482
|
+
await ctx.task("browser-preview", {
|
|
1483
|
+
tools: ["bash"],
|
|
1484
|
+
bashPolicy: {
|
|
1485
|
+
default: "deny",
|
|
1486
|
+
allow: [
|
|
1487
|
+
"which browse",
|
|
1488
|
+
{ prefix: "browse open " },
|
|
1489
|
+
{ prefix: "browse snapshot" },
|
|
1490
|
+
{ prefix: "grep " },
|
|
1491
|
+
],
|
|
1492
|
+
deny: [{ regex: "\\brm\\b" }],
|
|
1493
|
+
},
|
|
1494
|
+
prompt: "Open the preview with browse, then summarize the visible state.",
|
|
1495
|
+
});
|
|
1496
|
+
```
|
|
1497
|
+
|
|
1498
|
+
A command such as `browse snapshot | grep title` passes only when both segments are allowed, and `browse snapshot\nrm -rf /tmp/proof` cannot be hidden behind a `{ prefix: "browse " }` rule because the newline starts a new segment. Glob rules match command strings rather than filesystem path segments: `*` and `?` may span `/`, so `{ glob: "browse *" }` matches URLs and slash-bearing paths such as `browse http://localhost:3000`, `browse docs/index.html`, and `browse ./preview/output.html` while still matching the whole target rather than `echo browse ...`; escaped bracket-class metacharacters such as `\-`, `\^`, `\]`, `\[`, and `\\` stay literal, while malformed glob ranges such as `{ glob: "echo [z-a]" }` become `invalid-policy` denials. Segment mode accepts literal heads such as `grep`, `./script`, `/usr/bin/env`, `bun`, and `browse`, and treats non-leading `>|` as redirection syntax so `echo ok >|/tmp/out` stays one segment, but conservatively rejects reserved or compound heads (`coproc`, `if`, `for`, `while`, `case`, `{`, `}`, `!`), leading redirections (`>file cmd`, `2>file cmd`, `<file cmd`, `&>file cmd`, `&>>file cmd`, `>|file cmd`, `<&0 cmd`, `>&2 cmd`), redirections attached to the command-head word (`cmd>file`, `cmd>>file`, `cmd>|file`, `cmd2>file`, `cmd>&2`, `cmd</tmp/in`), leading environment assignments (`PATH=/tmp:$PATH browse snapshot`, `LD_PRELOAD=/tmp/x browse snapshot`, `FOO=bar`), dynamic heads such as `$cmd`, `${cmd}`, `r''m`, `r\m`, `~/bin/rm`, `r*m`, `{rm,echo}`, `r$(printf m)`, or backtick-built command names. A single denied, redirection-prefixed, attached-redirection, assignment-prefixed, dynamic, or unrecognized segment blocks the whole command with a model-readable tool error and no UI prompt, so the behavior works in headless workflow runs. Use `match: "whole"` only when raw-command matching is intentional.
|
|
1499
|
+
|
|
1388
1500
|
`gitWorktreeDir` selects a reusable Git worktree root for `ctx.stage`, `ctx.task`, `ctx.chain`, and `ctx.parallel`. If the path is missing, Atomic creates it with `git worktree add --detach <path> <baseBranch>`; if it exists, it must be a same-repository worktree root. The default stage cwd becomes the matching cwd inside the worktree and preserves the invoking repo-relative subdirectory. Explicit `cwd` still wins; relative `cwd` values resolve from the worktree cwd, while absolute `cwd` values are used as provided. `gitWorktreeDir` is mutually exclusive with `worktree: true`: use `gitWorktreeDir` for named/reusable worktrees and `worktree: true` for temporary direct-mode worktrees that are cleaned up after the run.
|
|
1389
1501
|
|
|
1390
1502
|
To bind user inputs to a workflow-wide worktree default, use the builder method:
|
|
@@ -1438,7 +1550,7 @@ This applies everywhere a stage accepts a model: direct `ctx.task`/`ctx.chain`/`
|
|
|
1438
1550
|
- `/workflow <name> key=value ...` for interactive named runs
|
|
1439
1551
|
- `/workflow connect|attach|pause|interrupt|resume|status|inputs|reload` for live control, inspection, and rediscovery
|
|
1440
1552
|
- the `workflow` tool for agent-initiated orchestration and direct one-off runs
|
|
1441
|
-
Workflow definition files must export definitions produced by `defineWorkflow(...).compile()`. The former imperative object-form runner is not part of the public SDK, and authored workflow files cannot import `runWorkflow` from `@bastani/workflows`.
|
|
1553
|
+
Workflow definition files must export definitions produced by `defineWorkflow(...).compile()`. Keep non-workflow runtime helpers (widget factories, shared utilities) in a subdirectory the discovery scan ignores, such as `.atomic/workflows/lib/` — see [Workflow Locations](#workflow-locations). The former imperative object-form runner is not part of the public SDK, and authored workflow files cannot import `runWorkflow` from `@bastani/workflows`.
|
|
1442
1554
|
|
|
1443
1555
|
Standalone TypeScript workflow packages type-check the SDK import with no hand-authored `.d.ts`, no `declare module` shim, and no `tsconfig` `paths` alias. The SDK types ship with `@bastani/atomic`, so a workflow package depends only on `@bastani/atomic` (plus a `typebox` peer):
|
|
1444
1556
|
|
|
@@ -1677,7 +1789,7 @@ Good workflows are information-flow systems, not just prompt sequences. Keep sta
|
|
|
1677
1789
|
- Do not use legacy workflow tool fields like `agent`, `stage`, or run-control `name`.
|
|
1678
1790
|
- Do not pass strings such as `"goal"` or path objects to `ctx.workflow(...)`; import the compiled workflow definition from `@bastani/workflows/builtin` or another TypeScript module first.
|
|
1679
1791
|
- Do not rely on undeclared child outputs; returning a key that is not declared with `.output(...)` fails the run. Declare `.output(...)` for every child-workflow field you expose — including `result` — and return values matching those schemas from `.run()`.
|
|
1680
|
-
- Do not expect to select or rename child outputs at the call site; parent workflows receive the child's declared output contract as `child.outputs`.
|
|
1792
|
+
- Do not expect to select or rename child outputs at the call site; parent workflows receive the child's declared output contract as `child.outputs` after checking `child.exited === false`, and a partial declared-output map when `child.exited === true`.
|
|
1681
1793
|
- Do not expect named workflow runs to block the chat turn; they are background tasks.
|
|
1682
1794
|
- Do not call `kill` when the user asks to interrupt or pause resumably.
|
|
1683
1795
|
- Keep stage names readable because they appear in workflow status and UI.
|
package/examples/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Extension Examples
|
|
2
2
|
|
|
3
|
-
Example extensions for
|
|
3
|
+
Example extensions for Atomic.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Load an extension with --extension flag
|
|
9
|
-
|
|
9
|
+
atomic --extension examples/extensions/permission-gate.ts
|
|
10
10
|
|
|
11
11
|
# Or copy to extensions directory for auto-discovery
|
|
12
|
-
cp permission-gate.ts ~/.
|
|
12
|
+
cp permission-gate.ts ~/.atomic/agent/extensions/
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Examples
|
|
@@ -23,6 +23,8 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|
|
23
23
|
| `confirm-destructive.ts` | Confirms before destructive session actions (clear, switch, fork) |
|
|
24
24
|
| `dirty-repo-guard.ts` | Prevents session changes with uncommitted git changes |
|
|
25
25
|
| `sandbox/` | OS-level sandboxing using `@anthropic-ai/sandbox-runtime` with per-project config |
|
|
26
|
+
| `project-trust.ts` | Demonstrates the `project_trust` event for user/global and CLI extensions |
|
|
27
|
+
| `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM |
|
|
26
28
|
|
|
27
29
|
### Custom Tools
|
|
28
30
|
|
|
@@ -75,6 +77,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|
|
75
77
|
| `reload-runtime.ts` | Adds `/reload-runtime` and `reload_runtime` tool showing safe reload flow |
|
|
76
78
|
| `interactive-shell.ts` | Run interactive commands (vim, htop) with full terminal via `user_bash` hook |
|
|
77
79
|
| `inline-bash.ts` | Expands `!{command}` patterns in prompts via `input` event transformation |
|
|
80
|
+
| `input-transform-streaming.ts` | Skips expensive input preprocessing for mid-stream steering via `streamingBehavior` |
|
|
78
81
|
|
|
79
82
|
### Git Integration
|
|
80
83
|
|
|
@@ -96,7 +99,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|
|
96
99
|
|
|
97
100
|
| Extension | Description |
|
|
98
101
|
|-----------|-------------|
|
|
99
|
-
| `mac-system-theme.ts` | Syncs
|
|
102
|
+
| `mac-system-theme.ts` | Syncs Atomic theme with macOS dark/light mode |
|
|
100
103
|
|
|
101
104
|
### Resources
|
|
102
105
|
|
|
@@ -123,7 +126,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/
|
|
|
123
126
|
| Extension | Description |
|
|
124
127
|
|-----------|-------------|
|
|
125
128
|
| `custom-provider-anthropic/` | Custom Anthropic provider with OAuth support and custom streaming implementation |
|
|
126
|
-
| `custom-provider-gitlab-duo/` | GitLab Duo provider using pi-ai's built-in Anthropic/OpenAI streaming via proxy |
|
|
129
|
+
| `custom-provider-gitlab-duo/` | GitLab Duo provider using `@earendil-works/pi-ai`'s built-in Anthropic/OpenAI streaming via proxy |
|
|
127
130
|
|
|
128
131
|
### External Dependencies
|
|
129
132
|
|