@bastani/atomic 0.8.31-alpha.5 → 0.9.0-alpha.2
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 +28 -1
- package/dist/builtin/cursor/CHANGELOG.md +10 -1
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/cursor/src/proto/protobuf-codec-json.ts +44 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec-request.ts +271 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec-wire.ts +231 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec.ts +5 -523
- package/dist/builtin/cursor/src/stream.ts +6 -70
- package/dist/builtin/cursor/src/transport-errors.ts +74 -0
- package/dist/builtin/cursor/src/transport-frame.ts +56 -0
- package/dist/builtin/cursor/src/transport-http2.ts +122 -0
- package/dist/builtin/cursor/src/transport-native-client.ts +161 -0
- package/dist/builtin/cursor/src/transport-run-stream.ts +188 -0
- package/dist/builtin/cursor/src/transport-timeouts.ts +87 -0
- package/dist/builtin/cursor/src/transport-types.ts +140 -0
- package/dist/builtin/cursor/src/transport.ts +24 -790
- package/dist/builtin/intercom/CHANGELOG.md +9 -0
- package/dist/builtin/intercom/broker/client.ts +0 -35
- package/dist/builtin/intercom/contact-supervisor-tool.ts +289 -0
- package/dist/builtin/intercom/index-heavy.ts +77 -1336
- package/dist/builtin/intercom/intercom-tool.ts +409 -0
- package/dist/builtin/intercom/intercom-utils.ts +401 -0
- package/dist/builtin/intercom/lifecycle.ts +133 -0
- package/dist/builtin/intercom/overlay.ts +96 -0
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/intercom/subagent-relay.ts +137 -0
- package/dist/builtin/mcp/CHANGELOG.md +9 -0
- package/dist/builtin/mcp/config-write-utils.ts +104 -0
- package/dist/builtin/mcp/config.ts +4 -180
- package/dist/builtin/mcp/mcp-panel-renderer.ts +243 -0
- package/dist/builtin/mcp/mcp-panel-state.ts +227 -0
- package/dist/builtin/mcp/mcp-panel-types.ts +86 -0
- package/dist/builtin/mcp/mcp-panel.ts +145 -579
- package/dist/builtin/mcp/mcp-setup-panel.ts +4 -81
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/mcp/proxy-auth.ts +61 -0
- package/dist/builtin/mcp/proxy-call.ts +373 -0
- package/dist/builtin/mcp/proxy-connect.ts +58 -0
- package/dist/builtin/mcp/proxy-info-modes.ts +326 -0
- package/dist/builtin/mcp/proxy-modes.ts +3 -805
- package/dist/builtin/mcp/proxy-types.ts +3 -0
- package/dist/builtin/mcp/ui-server-http.ts +81 -0
- package/dist/builtin/mcp/ui-server.ts +2 -127
- package/dist/builtin/subagents/CHANGELOG.md +9 -0
- package/dist/builtin/subagents/package.json +4 -4
- package/dist/builtin/subagents/src/agents/agent-discovery.ts +127 -0
- package/dist/builtin/subagents/src/agents/agent-loaders.ts +175 -0
- package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +310 -0
- package/dist/builtin/subagents/src/agents/agent-management.ts +3 -309
- package/dist/builtin/subagents/src/agents/agent-overrides.ts +397 -0
- package/dist/builtin/subagents/src/agents/agent-paths.ts +88 -0
- package/dist/builtin/subagents/src/agents/agent-types.ts +136 -0
- package/dist/builtin/subagents/src/agents/agents.ts +22 -895
- package/dist/builtin/subagents/src/agents/skills-paths.ts +333 -0
- package/dist/builtin/subagents/src/agents/skills.ts +3 -326
- package/dist/builtin/subagents/src/extension/index.ts +4 -118
- package/dist/builtin/subagents/src/extension/prompt-guidance.ts +13 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +401 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +131 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +213 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +84 -0
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +13 -795
- package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +215 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +136 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +105 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +112 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +159 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +127 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +427 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +273 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +269 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +196 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +70 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +44 -2233
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +75 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +202 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +97 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +160 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +72 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +161 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +203 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +234 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +103 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +29 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +4 -1328
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +117 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-details.ts +35 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +194 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +183 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +185 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +229 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +194 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +94 -1043
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +135 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +107 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +17 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +454 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +219 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +77 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-updates.ts +34 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-utils.ts +56 -0
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +6 -1082
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +207 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +140 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +266 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +270 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +157 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +375 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +463 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +17 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +320 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +207 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +121 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-worktree.ts +113 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +150 -2522
- package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +0 -16
- package/dist/builtin/subagents/src/runs/shared/nested-events-control.ts +167 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events-core.ts +219 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events-projection.ts +121 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events-registry.ts +289 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events-sanitize.ts +201 -0
- package/dist/builtin/subagents/src/runs/shared/nested-events.ts +50 -935
- package/dist/builtin/subagents/src/runs/shared/worktree.ts +0 -78
- package/dist/builtin/subagents/src/shared/types-async.ts +265 -0
- package/dist/builtin/subagents/src/shared/types-config.ts +125 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +121 -0
- package/dist/builtin/subagents/src/shared/types-output.ts +63 -0
- package/dist/builtin/subagents/src/shared/types-results.ts +318 -0
- package/dist/builtin/subagents/src/shared/types-runtime.ts +136 -0
- package/dist/builtin/subagents/src/shared/types.ts +10 -975
- package/dist/builtin/subagents/src/slash/slash-commands.ts +0 -12
- package/dist/builtin/subagents/src/tui/render-chain-graph.ts +247 -0
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +259 -0
- package/dist/builtin/subagents/src/tui/render-layout.ts +120 -0
- package/dist/builtin/subagents/src/tui/render-result-animation.ts +56 -0
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +154 -0
- package/dist/builtin/subagents/src/tui/render-result.ts +390 -0
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +83 -0
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +133 -0
- package/dist/builtin/subagents/src/tui/render-widget-graph.ts +166 -0
- package/dist/builtin/subagents/src/tui/render-widget.ts +273 -0
- package/dist/builtin/subagents/src/tui/render.ts +14 -1801
- package/dist/builtin/web-access/CHANGELOG.md +9 -0
- package/dist/builtin/web-access/content-tools.ts +348 -0
- package/dist/builtin/web-access/curator-page-assets/script-1.ts +400 -0
- package/dist/builtin/web-access/curator-page-assets/script-2.ts +400 -0
- package/dist/builtin/web-access/curator-page-assets/script-3.ts +400 -0
- package/dist/builtin/web-access/curator-page-assets/script-4.ts +400 -0
- package/dist/builtin/web-access/curator-page-assets/script-5.ts +398 -0
- package/dist/builtin/web-access/curator-page-assets/styles-1.ts +394 -0
- package/dist/builtin/web-access/curator-page-assets/styles-2.ts +394 -0
- package/dist/builtin/web-access/curator-page-assets/styles-3.ts +393 -0
- package/dist/builtin/web-access/curator-page.ts +17 -3180
- package/dist/builtin/web-access/curator-server-helpers.ts +115 -0
- package/dist/builtin/web-access/curator-server.ts +2 -113
- package/dist/builtin/web-access/exa-mcp.ts +218 -0
- package/dist/builtin/web-access/exa.ts +2 -207
- package/dist/builtin/web-access/extract-frames.ts +228 -0
- package/dist/builtin/web-access/extract.ts +13 -214
- package/dist/builtin/web-access/github-config.ts +156 -0
- package/dist/builtin/web-access/github-extract.ts +3 -154
- package/dist/builtin/web-access/index-heavy.ts +8 -1904
- package/dist/builtin/web-access/package.json +3 -2
- package/dist/builtin/web-access/web-search-activity.ts +102 -0
- package/dist/builtin/web-access/web-search-browser.ts +116 -0
- package/dist/builtin/web-access/web-search-command.ts +242 -0
- package/dist/builtin/web-access/web-search-config.ts +163 -0
- package/dist/builtin/web-access/web-search-curator.ts +214 -0
- package/dist/builtin/web-access/web-search-features.ts +165 -0
- package/dist/builtin/web-access/web-search-formatting.ts +117 -0
- package/dist/builtin/web-access/web-search-return.ts +136 -0
- package/dist/builtin/web-access/web-search-summary.ts +170 -0
- package/dist/builtin/web-access/web-search-tool.ts +290 -0
- package/dist/builtin/web-access/web-search-types.ts +50 -0
- package/dist/builtin/workflows/CHANGELOG.md +16 -1
- package/dist/builtin/workflows/README.md +189 -122
- package/dist/builtin/workflows/builtin/deep-research-codebase-runner.ts +492 -0
- package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +346 -0
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +36 -849
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +43 -0
- package/dist/builtin/workflows/builtin/goal-ledger.ts +54 -0
- package/dist/builtin/workflows/builtin/goal-prompts.ts +360 -0
- package/dist/builtin/workflows/builtin/goal-reducer.ts +141 -0
- package/dist/builtin/workflows/builtin/goal-reports.ts +56 -0
- package/dist/builtin/workflows/builtin/goal-review.ts +84 -0
- package/dist/builtin/workflows/builtin/goal-runner.ts +336 -0
- package/dist/builtin/workflows/builtin/goal-schemas.ts +60 -0
- package/dist/builtin/workflows/builtin/goal-types.ts +132 -0
- package/dist/builtin/workflows/builtin/goal.ts +40 -1201
- package/dist/builtin/workflows/builtin/index.d.ts +1 -0
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +432 -0
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +476 -0
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +312 -0
- package/dist/builtin/workflows/builtin/open-claude-design.d.ts +1 -0
- package/dist/builtin/workflows/builtin/open-claude-design.ts +47 -1131
- package/dist/builtin/workflows/builtin/ralph-core.ts +408 -0
- package/dist/builtin/workflows/builtin/ralph-models.ts +123 -0
- package/dist/builtin/workflows/builtin/ralph-runner.ts +499 -0
- package/dist/builtin/workflows/builtin/ralph.ts +50 -1019
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +8 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +13 -15
- package/dist/builtin/workflows/skills/impeccable/scripts/live-manual-edit-evidence.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-server.mjs +9 -0
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/authoring/typebox-defaults.ts +217 -0
- package/dist/builtin/workflows/src/authoring/workflow.ts +184 -0
- package/dist/builtin/workflows/src/authoring.d.ts +14 -66
- package/dist/builtin/workflows/src/engine/graph-inference.ts +100 -0
- package/dist/builtin/workflows/src/engine/options.ts +40 -0
- package/dist/builtin/workflows/src/engine/primitives/chain.ts +29 -0
- package/dist/builtin/workflows/src/engine/primitives/exit.ts +2 -0
- package/dist/builtin/workflows/src/engine/primitives/parallel.ts +47 -0
- package/dist/builtin/workflows/src/engine/primitives/task.ts +108 -0
- package/dist/builtin/workflows/src/engine/primitives/ui.ts +41 -0
- package/dist/builtin/workflows/src/engine/primitives/workflow.ts +159 -0
- package/dist/builtin/workflows/src/engine/replay.ts +8 -0
- package/dist/builtin/workflows/src/engine/run.ts +356 -0
- package/dist/builtin/workflows/src/engine/runtime.ts +160 -0
- package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +186 -0
- package/dist/builtin/workflows/src/extension/config-file-loader.ts +152 -0
- package/dist/builtin/workflows/src/extension/config-loader.ts +2 -167
- package/dist/builtin/workflows/src/extension/discovery-loaders.ts +115 -0
- package/dist/builtin/workflows/src/extension/discovery.ts +3 -117
- package/dist/builtin/workflows/src/extension/extension-factory.ts +120 -0
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +109 -0
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +270 -0
- package/dist/builtin/workflows/src/extension/index.ts +42 -4166
- package/dist/builtin/workflows/src/extension/public-types.ts +295 -0
- package/dist/builtin/workflows/src/extension/render-component.ts +14 -0
- package/dist/builtin/workflows/src/extension/runtime-direct.ts +96 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +1 -92
- package/dist/builtin/workflows/src/extension/ui-surface.ts +286 -0
- package/dist/builtin/workflows/src/extension/wiring.ts +6 -475
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +111 -0
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +213 -0
- package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +81 -0
- package/dist/builtin/workflows/src/extension/workflow-command-utils.ts +181 -0
- package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +9 -3
- package/dist/builtin/workflows/src/extension/workflow-policy.ts +15 -0
- package/dist/builtin/workflows/src/extension/workflow-ports.ts +41 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +23 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +286 -0
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +1 -19
- package/dist/builtin/workflows/src/extension/workflow-stage-results.ts +264 -0
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +181 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +175 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +205 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-helpers.ts +66 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +164 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-registration.ts +54 -0
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +164 -0
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +102 -0
- package/dist/builtin/workflows/src/index.ts +0 -2
- package/dist/builtin/workflows/src/runs/background/runner.ts +6 -3
- package/dist/builtin/workflows/src/runs/foreground/executor-abort.ts +431 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-child-boundary.ts +232 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-child-helpers.ts +74 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-child-workflow.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +167 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +450 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +233 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-exit-manager.ts +195 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +368 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-inputs.ts +83 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +441 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-outputs.ts +160 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +274 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-run-finalizers.ts +122 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-run.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +204 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +194 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +120 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +126 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +359 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +135 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +61 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-task-context.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +293 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +109 -0
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +19 -5354
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +219 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +500 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-messages.ts +129 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +53 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +146 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-session.ts +55 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-structured-output.ts +82 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +141 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +13 -1355
- package/dist/builtin/workflows/src/runs/shared/graph-inference.ts +2 -100
- package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +453 -0
- package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +442 -0
- package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +2 -836
- package/dist/builtin/workflows/src/runs/shared/worktree-diff.ts +165 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +220 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-setup.ts +335 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +92 -0
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +18 -791
- package/dist/builtin/workflows/src/sdk-surface.ts +6 -9
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +371 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +439 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +206 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +282 -0
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +5 -598
- package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +428 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +9 -431
- package/dist/builtin/workflows/src/shared/store-factory.ts +16 -0
- package/dist/builtin/workflows/src/shared/store-internal.ts +219 -0
- package/dist/builtin/workflows/src/shared/store-prompt-methods.ts +219 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +215 -0
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +223 -0
- package/dist/builtin/workflows/src/shared/store-stage-methods.ts +305 -0
- package/dist/builtin/workflows/src/shared/store.ts +11 -1138
- package/dist/builtin/workflows/src/shared/types.ts +25 -8
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +49 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.ts +84 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-classifier.ts +266 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-contract.ts +75 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +477 -0
- package/dist/builtin/workflows/src/shared/workflow-failures-signals.ts +248 -0
- package/dist/builtin/workflows/src/shared/workflow-failures.ts +13 -1001
- package/dist/builtin/workflows/src/tui/chat-surface.ts +0 -66
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +45 -0
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +161 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +333 -0
- package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +336 -0
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +194 -0
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +306 -0
- package/dist/builtin/workflows/src/tui/graph-view-types.ts +70 -0
- package/dist/builtin/workflows/src/tui/graph-view.ts +4 -1386
- package/dist/builtin/workflows/src/tui/inline-form-editor-text.ts +121 -0
- package/dist/builtin/workflows/src/tui/inline-form-editor.ts +11 -223
- package/dist/builtin/workflows/src/tui/inputs-picker-editing.ts +151 -0
- package/dist/builtin/workflows/src/tui/inputs-picker-input.ts +305 -0
- package/dist/builtin/workflows/src/tui/inputs-picker-render.ts +300 -0
- package/dist/builtin/workflows/src/tui/inputs-picker-types.ts +190 -0
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +19 -997
- package/dist/builtin/workflows/src/tui/prompt-card-input.ts +226 -0
- package/dist/builtin/workflows/src/tui/prompt-card-render.ts +373 -0
- package/dist/builtin/workflows/src/tui/prompt-card-select.ts +116 -0
- package/dist/builtin/workflows/src/tui/prompt-card-state.ts +61 -0
- package/dist/builtin/workflows/src/tui/prompt-card-text.ts +129 -0
- package/dist/builtin/workflows/src/tui/prompt-card.ts +8 -910
- package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +315 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-custom-ui.ts +127 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +187 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +222 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-render-helpers.ts +152 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +464 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-transcript.ts +242 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +151 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +141 -1777
- package/dist/builtin/workflows/src/tui/workflow-attach-pane-types.ts +85 -0
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +1 -129
- package/dist/builtin/workflows/src/workflows/registry.ts +7 -3
- package/dist/config-self-update.d.ts +21 -0
- package/dist/config-self-update.d.ts.map +1 -0
- package/dist/config-self-update.js +265 -0
- package/dist/config-self-update.js.map +1 -0
- package/dist/config.d.ts +3 -12
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +15 -252
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-accessors.d.ts +3 -0
- package/dist/core/agent-session-accessors.d.ts.map +1 -0
- package/dist/core/agent-session-accessors.js +36 -0
- package/dist/core/agent-session-accessors.js.map +1 -0
- package/dist/core/agent-session-auto-compaction.d.ts +32 -0
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -0
- package/dist/core/agent-session-auto-compaction.js +219 -0
- package/dist/core/agent-session-auto-compaction.js.map +1 -0
- package/dist/core/agent-session-bash.d.ts +30 -0
- package/dist/core/agent-session-bash.d.ts.map +1 -0
- package/dist/core/agent-session-bash.js +79 -0
- package/dist/core/agent-session-bash.js.map +1 -0
- package/dist/core/agent-session-compaction.d.ts +44 -0
- package/dist/core/agent-session-compaction.d.ts.map +1 -0
- package/dist/core/agent-session-compaction.js +282 -0
- package/dist/core/agent-session-compaction.js.map +1 -0
- package/dist/core/agent-session-events.d.ts +65 -0
- package/dist/core/agent-session-events.d.ts.map +1 -0
- package/dist/core/agent-session-events.js +373 -0
- package/dist/core/agent-session-events.js.map +1 -0
- package/dist/core/agent-session-export.d.ts +42 -0
- package/dist/core/agent-session-export.d.ts.map +1 -0
- package/dist/core/agent-session-export.js +199 -0
- package/dist/core/agent-session-export.js.map +1 -0
- package/dist/core/agent-session-extension-bindings.d.ts +37 -0
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -0
- package/dist/core/agent-session-extension-bindings.js +231 -0
- package/dist/core/agent-session-extension-bindings.js.map +1 -0
- package/dist/core/agent-session-message-queue.d.ts +85 -0
- package/dist/core/agent-session-message-queue.d.ts.map +1 -0
- package/dist/core/agent-session-message-queue.js +264 -0
- package/dist/core/agent-session-message-queue.js.map +1 -0
- package/dist/core/agent-session-methods.d.ts +300 -0
- package/dist/core/agent-session-methods.d.ts.map +1 -0
- package/dist/core/agent-session-methods.js +2 -0
- package/dist/core/agent-session-methods.js.map +1 -0
- package/dist/core/agent-session-models.d.ts +111 -0
- package/dist/core/agent-session-models.d.ts.map +1 -0
- package/dist/core/agent-session-models.js +368 -0
- package/dist/core/agent-session-models.js.map +1 -0
- package/dist/core/agent-session-prompt.d.ts +61 -0
- package/dist/core/agent-session-prompt.d.ts.map +1 -0
- package/dist/core/agent-session-prompt.js +330 -0
- package/dist/core/agent-session-prompt.js.map +1 -0
- package/dist/core/agent-session-retry.d.ts +62 -0
- package/dist/core/agent-session-retry.d.ts.map +1 -0
- package/dist/core/agent-session-retry.js +202 -0
- package/dist/core/agent-session-retry.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +0 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-skill-block.d.ts +13 -0
- package/dist/core/agent-session-skill-block.d.ts.map +1 -0
- package/dist/core/agent-session-skill-block.js +37 -0
- package/dist/core/agent-session-skill-block.js.map +1 -0
- package/dist/core/agent-session-state.d.ts +48 -0
- package/dist/core/agent-session-state.d.ts.map +1 -0
- package/dist/core/agent-session-state.js +129 -0
- package/dist/core/agent-session-state.js.map +1 -0
- package/dist/core/agent-session-tool-hooks.d.ts +7 -0
- package/dist/core/agent-session-tool-hooks.d.ts.map +1 -0
- package/dist/core/agent-session-tool-hooks.js +72 -0
- package/dist/core/agent-session-tool-hooks.js.map +1 -0
- package/dist/core/agent-session-tool-registry.d.ts +15 -0
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -0
- package/dist/core/agent-session-tool-registry.js +149 -0
- package/dist/core/agent-session-tool-registry.js.map +1 -0
- package/dist/core/agent-session-tree.d.ts +46 -0
- package/dist/core/agent-session-tree.d.ts.map +1 -0
- package/dist/core/agent-session-tree.js +217 -0
- package/dist/core/agent-session-tree.js.map +1 -0
- package/dist/core/agent-session-types.d.ts +157 -0
- package/dist/core/agent-session-types.d.ts.map +1 -0
- package/dist/core/agent-session-types.js +41 -0
- package/dist/core/agent-session-types.js.map +1 -0
- package/dist/core/agent-session.d.ts +66 -688
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +26 -3153
- 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 +1 -1
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/auth-storage-backends.d.ts +49 -0
- package/dist/core/auth-storage-backends.d.ts.map +1 -0
- package/dist/core/auth-storage-backends.js +185 -0
- package/dist/core/auth-storage-backends.js.map +1 -0
- package/dist/core/auth-storage.d.ts +2 -49
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -183
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +16 -0
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-metrics.js +58 -0
- package/dist/core/compaction/context-compaction-metrics.js.map +1 -0
- package/dist/core/compaction/context-compaction-prompt.d.ts +9 -0
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-prompt.js +161 -0
- package/dist/core/compaction/context-compaction-prompt.js.map +1 -0
- package/dist/core/compaction/context-compaction-runner.d.ts +5 -0
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-runner.js +181 -0
- package/dist/core/compaction/context-compaction-runner.js.map +1 -0
- package/dist/core/compaction/context-compaction-strategy.d.ts +5 -0
- package/dist/core/compaction/context-compaction-strategy.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-strategy.js +27 -0
- package/dist/core/compaction/context-compaction-strategy.js.map +1 -0
- package/dist/core/compaction/context-compaction-types.d.ts +73 -0
- package/dist/core/compaction/context-compaction-types.d.ts.map +1 -0
- package/dist/core/compaction/context-compaction-types.js +6 -0
- package/dist/core/compaction/context-compaction-types.js.map +1 -0
- package/dist/core/compaction/context-compaction.d.ts +9 -200
- package/dist/core/compaction/context-compaction.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction.js +7 -1943
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/compaction/context-deletion-application.d.ts +13 -0
- package/dist/core/compaction/context-deletion-application.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-application.js +259 -0
- package/dist/core/compaction/context-deletion-application.js.map +1 -0
- package/dist/core/compaction/context-deletion-store.d.ts +78 -0
- package/dist/core/compaction/context-deletion-store.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-store.js +162 -0
- package/dist/core/compaction/context-deletion-store.js.map +1 -0
- package/dist/core/compaction/context-deletion-targets.d.ts +40 -0
- package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-targets.js +267 -0
- package/dist/core/compaction/context-deletion-targets.js.map +1 -0
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +187 -0
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-tool-definitions.js +98 -0
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +1 -0
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts +19 -0
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-tool-helpers.js +137 -0
- package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -0
- package/dist/core/compaction/context-deletion-tools.d.ts +4 -0
- package/dist/core/compaction/context-deletion-tools.d.ts.map +1 -0
- package/dist/core/compaction/context-deletion-tools.js +395 -0
- package/dist/core/compaction/context-deletion-tools.js.map +1 -0
- package/dist/core/compaction/context-transcript-analysis.d.ts +9 -0
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -0
- package/dist/core/compaction/context-transcript-analysis.js +234 -0
- package/dist/core/compaction/context-transcript-analysis.js.map +1 -0
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +2 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template-js/data-tree.js +287 -0
- package/dist/core/export-html/template-js/entries-navigation.js +424 -0
- package/dist/core/export-html/template-js/initialization.js +312 -0
- package/dist/core/export-html/template-js/message-tools.js +415 -0
- package/dist/core/export-html/template-js/tree-filter-render.js +421 -0
- package/dist/core/export-html/template-script.d.ts +3 -0
- package/dist/core/export-html/template-script.d.ts.map +1 -0
- package/dist/core/export-html/template-script.js +13 -0
- package/dist/core/export-html/template-script.js.map +1 -0
- package/dist/core/export-html/template.js +3 -1
- package/dist/core/extensions/agent-events.d.ts +159 -0
- package/dist/core/extensions/agent-events.d.ts.map +1 -0
- package/dist/core/extensions/agent-events.js +2 -0
- package/dist/core/extensions/agent-events.js.map +1 -0
- package/dist/core/extensions/api-types.d.ts +189 -0
- package/dist/core/extensions/api-types.d.ts.map +1 -0
- package/dist/core/extensions/api-types.js +2 -0
- package/dist/core/extensions/api-types.js.map +1 -0
- package/dist/core/extensions/command-types.d.ts +14 -0
- package/dist/core/extensions/command-types.d.ts.map +1 -0
- package/dist/core/extensions/command-types.js +2 -0
- package/dist/core/extensions/command-types.js.map +1 -0
- package/dist/core/extensions/context-types.d.ts +130 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -0
- package/dist/core/extensions/context-types.js +2 -0
- package/dist/core/extensions/context-types.js.map +1 -0
- package/dist/core/extensions/event-results.d.ts +61 -0
- package/dist/core/extensions/event-results.d.ts.map +1 -0
- package/dist/core/extensions/event-results.js +2 -0
- package/dist/core/extensions/event-results.js.map +1 -0
- package/dist/core/extensions/event-types.d.ts +6 -0
- package/dist/core/extensions/event-types.d.ts.map +1 -0
- package/dist/core/extensions/event-types.js +2 -0
- package/dist/core/extensions/event-types.js.map +1 -0
- package/dist/core/extensions/loader-api.d.ts +10 -0
- package/dist/core/extensions/loader-api.d.ts.map +1 -0
- package/dist/core/extensions/loader-api.js +143 -0
- package/dist/core/extensions/loader-api.js.map +1 -0
- package/dist/core/extensions/loader-core.d.ts +10 -0
- package/dist/core/extensions/loader-core.d.ts.map +1 -0
- package/dist/core/extensions/loader-core.js +98 -0
- package/dist/core/extensions/loader-core.js.map +1 -0
- package/dist/core/extensions/loader-discovery.d.ts +7 -0
- package/dist/core/extensions/loader-discovery.d.ts.map +1 -0
- package/dist/core/extensions/loader-discovery.js +139 -0
- package/dist/core/extensions/loader-discovery.js.map +1 -0
- package/dist/core/extensions/loader-resources.d.ts +11 -0
- package/dist/core/extensions/loader-resources.d.ts.map +1 -0
- package/dist/core/extensions/loader-resources.js +10 -0
- package/dist/core/extensions/loader-resources.js.map +1 -0
- package/dist/core/extensions/loader-runtime.d.ts +7 -0
- package/dist/core/extensions/loader-runtime.d.ts.map +1 -0
- package/dist/core/extensions/loader-runtime.js +51 -0
- package/dist/core/extensions/loader-runtime.js.map +1 -0
- package/dist/core/extensions/loader-virtual-modules.d.ts +9 -0
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/loader-virtual-modules.js +124 -0
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +5 -28
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +4 -542
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/message-types.d.ts +34 -0
- package/dist/core/extensions/message-types.d.ts.map +1 -0
- package/dist/core/extensions/message-types.js +2 -0
- package/dist/core/extensions/message-types.js.map +1 -0
- package/dist/core/extensions/provider-types.d.ts +71 -0
- package/dist/core/extensions/provider-types.d.ts.map +1 -0
- package/dist/core/extensions/provider-types.js +2 -0
- package/dist/core/extensions/provider-types.js.map +1 -0
- package/dist/core/extensions/runner-context.d.ts +42 -0
- package/dist/core/extensions/runner-context.d.ts.map +1 -0
- package/dist/core/extensions/runner-context.js +112 -0
- package/dist/core/extensions/runner-context.js.map +1 -0
- package/dist/core/extensions/runner-events.d.ts +47 -0
- package/dist/core/extensions/runner-events.d.ts.map +1 -0
- package/dist/core/extensions/runner-events.js +280 -0
- package/dist/core/extensions/runner-events.js.map +1 -0
- package/dist/core/extensions/runner-handlers.d.ts +32 -0
- package/dist/core/extensions/runner-handlers.d.ts.map +1 -0
- package/dist/core/extensions/runner-handlers.js +2 -0
- package/dist/core/extensions/runner-handlers.js.map +1 -0
- package/dist/core/extensions/runner-project-trust.d.ts +6 -0
- package/dist/core/extensions/runner-project-trust.d.ts.map +1 -0
- package/dist/core/extensions/runner-project-trust.js +27 -0
- package/dist/core/extensions/runner-project-trust.js.map +1 -0
- package/dist/core/extensions/runner-registries.d.ts +8 -0
- package/dist/core/extensions/runner-registries.d.ts.map +1 -0
- package/dist/core/extensions/runner-registries.js +76 -0
- package/dist/core/extensions/runner-registries.js.map +1 -0
- package/dist/core/extensions/runner-shortcuts.d.ts +10 -0
- package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -0
- package/dist/core/extensions/runner-shortcuts.js +71 -0
- package/dist/core/extensions/runner-shortcuts.js.map +1 -0
- package/dist/core/extensions/runner-ui.d.ts +3 -0
- package/dist/core/extensions/runner-ui.d.ts.map +1 -0
- package/dist/core/extensions/runner-ui.js +50 -0
- package/dist/core/extensions/runner-ui.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +7 -74
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +67 -673
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +179 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -0
- package/dist/core/extensions/runtime-types.js +2 -0
- package/dist/core/extensions/runtime-types.js.map +1 -0
- package/dist/core/extensions/session-events.d.ts +89 -0
- package/dist/core/extensions/session-events.d.ts.map +1 -0
- package/dist/core/extensions/session-events.js +2 -0
- package/dist/core/extensions/session-events.js.map +1 -0
- package/dist/core/extensions/tool-events.d.ts +127 -0
- package/dist/core/extensions/tool-events.d.ts.map +1 -0
- package/dist/core/extensions/tool-events.js +26 -0
- package/dist/core/extensions/tool-events.js.map +1 -0
- package/dist/core/extensions/tool-types.d.ts +100 -0
- package/dist/core/extensions/tool-types.d.ts.map +1 -0
- package/dist/core/extensions/tool-types.js +11 -0
- package/dist/core/extensions/tool-types.js.map +1 -0
- package/dist/core/extensions/types.d.ts +20 -1288
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +4 -34
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/ui-types.d.ts +200 -0
- package/dist/core/extensions/ui-types.d.ts.map +1 -0
- package/dist/core/extensions/ui-types.js +2 -0
- package/dist/core/extensions/ui-types.js.map +1 -0
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +0 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-registry-auth.d.ts +7 -0
- package/dist/core/model-registry-auth.d.ts.map +1 -0
- package/dist/core/model-registry-auth.js +64 -0
- package/dist/core/model-registry-auth.js.map +1 -0
- package/dist/core/model-registry-builtins.d.ts +9 -0
- package/dist/core/model-registry-builtins.d.ts.map +1 -0
- package/dist/core/model-registry-builtins.js +126 -0
- package/dist/core/model-registry-builtins.js.map +1 -0
- package/dist/core/model-registry-custom-loader.d.ts +3 -0
- package/dist/core/model-registry-custom-loader.d.ts.map +1 -0
- package/dist/core/model-registry-custom-loader.js +213 -0
- package/dist/core/model-registry-custom-loader.js.map +1 -0
- package/dist/core/model-registry-dynamic.d.ts +6 -0
- package/dist/core/model-registry-dynamic.d.ts.map +1 -0
- package/dist/core/model-registry-dynamic.js +155 -0
- package/dist/core/model-registry-dynamic.js.map +1 -0
- package/dist/core/model-registry-loader.d.ts +4 -0
- package/dist/core/model-registry-loader.d.ts.map +1 -0
- package/dist/core/model-registry-loader.js +20 -0
- package/dist/core/model-registry-loader.js.map +1 -0
- package/dist/core/model-registry-schemas.d.ts +1136 -0
- package/dist/core/model-registry-schemas.d.ts.map +1 -0
- package/dist/core/model-registry-schemas.js +171 -0
- package/dist/core/model-registry-schemas.js.map +1 -0
- package/dist/core/model-registry-types.d.ts +74 -0
- package/dist/core/model-registry-types.d.ts.map +1 -0
- package/dist/core/model-registry-types.js +2 -0
- package/dist/core/model-registry-types.js.map +1 -0
- package/dist/core/model-registry.d.ts +3 -76
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +24 -733
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver-cli.d.ts +19 -0
- package/dist/core/model-resolver-cli.d.ts.map +1 -0
- package/dist/core/model-resolver-cli.js +118 -0
- package/dist/core/model-resolver-cli.js.map +1 -0
- package/dist/core/model-resolver-defaults.d.ts +5 -0
- package/dist/core/model-resolver-defaults.d.ts.map +1 -0
- package/dist/core/model-resolver-defaults.js +47 -0
- package/dist/core/model-resolver-defaults.js.map +1 -0
- package/dist/core/model-resolver-initial.d.ts +31 -0
- package/dist/core/model-resolver-initial.d.ts.map +1 -0
- package/dist/core/model-resolver-initial.js +116 -0
- package/dist/core/model-resolver-initial.js.map +1 -0
- package/dist/core/model-resolver-patterns.d.ts +26 -0
- package/dist/core/model-resolver-patterns.d.ts.map +1 -0
- package/dist/core/model-resolver-patterns.js +139 -0
- package/dist/core/model-resolver-patterns.js.map +1 -0
- package/dist/core/model-resolver-scope.d.ts +15 -0
- package/dist/core/model-resolver-scope.d.ts.map +1 -0
- package/dist/core/model-resolver-scope.js +66 -0
- package/dist/core/model-resolver-scope.js.map +1 -0
- package/dist/core/model-resolver-types.d.ts +29 -0
- package/dist/core/model-resolver-types.d.ts.map +1 -0
- package/dist/core/model-resolver-types.js +2 -0
- package/dist/core/model-resolver-types.js.map +1 -0
- package/dist/core/model-resolver.d.ts +6 -107
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +5 -549
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager-auto-resources.d.ts +5 -0
- package/dist/core/package-manager-auto-resources.d.ts.map +1 -0
- package/dist/core/package-manager-auto-resources.js +109 -0
- package/dist/core/package-manager-auto-resources.js.map +1 -0
- package/dist/core/package-manager-command.d.ts +11 -0
- package/dist/core/package-manager-command.d.ts.map +1 -0
- package/dist/core/package-manager-command.js +102 -0
- package/dist/core/package-manager-command.js.map +1 -0
- package/dist/core/package-manager-constants.d.ts +4 -0
- package/dist/core/package-manager-constants.d.ts.map +1 -0
- package/dist/core/package-manager-constants.js +4 -0
- package/dist/core/package-manager-constants.js.map +1 -0
- package/dist/core/package-manager-env.d.ts +4 -0
- package/dist/core/package-manager-env.d.ts.map +1 -0
- package/dist/core/package-manager-env.js +40 -0
- package/dist/core/package-manager-env.js.map +1 -0
- package/dist/core/package-manager-git.d.ts +10 -0
- package/dist/core/package-manager-git.d.ts.map +1 -0
- package/dist/core/package-manager-git.js +271 -0
- package/dist/core/package-manager-git.js.map +1 -0
- package/dist/core/package-manager-manifest.d.ts +7 -0
- package/dist/core/package-manager-manifest.d.ts.map +1 -0
- package/dist/core/package-manager-manifest.js +45 -0
- package/dist/core/package-manager-manifest.js.map +1 -0
- package/dist/core/package-manager-npm.d.ts +25 -0
- package/dist/core/package-manager-npm.d.ts.map +1 -0
- package/dist/core/package-manager-npm.js +252 -0
- package/dist/core/package-manager-npm.js.map +1 -0
- package/dist/core/package-manager-operations.d.ts +11 -0
- package/dist/core/package-manager-operations.d.ts.map +1 -0
- package/dist/core/package-manager-operations.js +196 -0
- package/dist/core/package-manager-operations.js.map +1 -0
- package/dist/core/package-manager-paths.d.ts +14 -0
- package/dist/core/package-manager-paths.d.ts.map +1 -0
- package/dist/core/package-manager-paths.js +61 -0
- package/dist/core/package-manager-paths.js.map +1 -0
- package/dist/core/package-manager-progress.d.ts +4 -0
- package/dist/core/package-manager-progress.d.ts.map +1 -0
- package/dist/core/package-manager-progress.js +16 -0
- package/dist/core/package-manager-progress.js.map +1 -0
- package/dist/core/package-manager-resolver.d.ts +5 -0
- package/dist/core/package-manager-resolver.d.ts.map +1 -0
- package/dist/core/package-manager-resolver.js +149 -0
- package/dist/core/package-manager-resolver.js.map +1 -0
- package/dist/core/package-manager-resource-accumulator.d.ts +6 -0
- package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -0
- package/dist/core/package-manager-resource-accumulator.js +67 -0
- package/dist/core/package-manager-resource-accumulator.js.map +1 -0
- package/dist/core/package-manager-resource-collector.d.ts +5 -0
- package/dist/core/package-manager-resource-collector.d.ts.map +1 -0
- package/dist/core/package-manager-resource-collector.js +148 -0
- package/dist/core/package-manager-resource-collector.js.map +1 -0
- package/dist/core/package-manager-resource-files.d.ts +14 -0
- package/dist/core/package-manager-resource-files.d.ts.map +1 -0
- package/dist/core/package-manager-resource-files.js +265 -0
- package/dist/core/package-manager-resource-files.js.map +1 -0
- package/dist/core/package-manager-resource-patterns.d.ts +12 -0
- package/dist/core/package-manager-resource-patterns.d.ts.map +1 -0
- package/dist/core/package-manager-resource-patterns.js +136 -0
- package/dist/core/package-manager-resource-patterns.js.map +1 -0
- package/dist/core/package-manager-settings.d.ts +10 -0
- package/dist/core/package-manager-settings.d.ts.map +1 -0
- package/dist/core/package-manager-settings.js +91 -0
- package/dist/core/package-manager-settings.js.map +1 -0
- package/dist/core/package-manager-source.d.ts +21 -0
- package/dist/core/package-manager-source.d.ts.map +1 -0
- package/dist/core/package-manager-source.js +146 -0
- package/dist/core/package-manager-source.js.map +1 -0
- package/dist/core/package-manager-types.d.ts +169 -0
- package/dist/core/package-manager-types.d.ts.map +1 -0
- package/dist/core/package-manager-types.js +9 -0
- package/dist/core/package-manager-types.js.map +1 -0
- package/dist/core/package-manager.d.ts +9 -174
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +56 -2100
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader-assets.d.ts +6 -0
- package/dist/core/resource-loader-assets.d.ts.map +1 -0
- package/dist/core/resource-loader-assets.js +209 -0
- package/dist/core/resource-loader-assets.js.map +1 -0
- package/dist/core/resource-loader-context-files.d.ts +10 -0
- package/dist/core/resource-loader-context-files.d.ts.map +1 -0
- package/dist/core/resource-loader-context-files.js +74 -0
- package/dist/core/resource-loader-context-files.js.map +1 -0
- package/dist/core/resource-loader-core.d.ts +83 -0
- package/dist/core/resource-loader-core.d.ts.map +1 -0
- package/dist/core/resource-loader-core.js +170 -0
- package/dist/core/resource-loader-core.js.map +1 -0
- package/dist/core/resource-loader-discovery.d.ts +4 -0
- package/dist/core/resource-loader-discovery.d.ts.map +1 -0
- package/dist/core/resource-loader-discovery.js +28 -0
- package/dist/core/resource-loader-discovery.js.map +1 -0
- package/dist/core/resource-loader-extensions.d.ts +13 -0
- package/dist/core/resource-loader-extensions.d.ts.map +1 -0
- package/dist/core/resource-loader-extensions.js +110 -0
- package/dist/core/resource-loader-extensions.js.map +1 -0
- package/dist/core/resource-loader-helpers.d.ts +4 -0
- package/dist/core/resource-loader-helpers.d.ts.map +1 -0
- package/dist/core/resource-loader-helpers.js +23 -0
- package/dist/core/resource-loader-helpers.js.map +1 -0
- package/dist/core/resource-loader-internals.d.ts +97 -0
- package/dist/core/resource-loader-internals.d.ts.map +1 -0
- package/dist/core/resource-loader-internals.js +4 -0
- package/dist/core/resource-loader-internals.js.map +1 -0
- package/dist/core/resource-loader-package-resources.d.ts +31 -0
- package/dist/core/resource-loader-package-resources.d.ts.map +1 -0
- package/dist/core/resource-loader-package-resources.js +112 -0
- package/dist/core/resource-loader-package-resources.js.map +1 -0
- package/dist/core/resource-loader-paths.d.ts +4 -0
- package/dist/core/resource-loader-paths.d.ts.map +1 -0
- package/dist/core/resource-loader-paths.js +22 -0
- package/dist/core/resource-loader-paths.js.map +1 -0
- package/dist/core/resource-loader-reload.d.ts +6 -0
- package/dist/core/resource-loader-reload.d.ts.map +1 -0
- package/dist/core/resource-loader-reload.js +230 -0
- package/dist/core/resource-loader-reload.js.map +1 -0
- package/dist/core/resource-loader-source-info.d.ts +9 -0
- package/dist/core/resource-loader-source-info.d.ts.map +1 -0
- package/dist/core/resource-loader-source-info.js +101 -0
- package/dist/core/resource-loader-source-info.js.map +1 -0
- package/dist/core/resource-loader-types.d.ts +130 -0
- package/dist/core/resource-loader-types.d.ts.map +1 -0
- package/dist/core/resource-loader-types.js +2 -0
- package/dist/core/resource-loader-types.js.map +1 -0
- package/dist/core/resource-loader.d.ts +3 -242
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -976
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +7 -0
- package/dist/core/sdk-exports.d.ts.map +1 -0
- package/dist/core/sdk-exports.js +5 -0
- package/dist/core/sdk-exports.js.map +1 -0
- package/dist/core/sdk-types.d.ts +83 -0
- package/dist/core/sdk-types.d.ts.map +1 -0
- package/dist/core/sdk-types.js +2 -0
- package/dist/core/sdk-types.js.map +1 -0
- package/dist/core/sdk.d.ts +3 -91
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -7
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-archive.d.ts +27 -0
- package/dist/core/session-manager-archive.d.ts.map +1 -0
- package/dist/core/session-manager-archive.js +114 -0
- package/dist/core/session-manager-archive.js.map +1 -0
- package/dist/core/session-manager-core.d.ts +104 -0
- package/dist/core/session-manager-core.d.ts.map +1 -0
- package/dist/core/session-manager-core.js +346 -0
- package/dist/core/session-manager-core.js.map +1 -0
- package/dist/core/session-manager-entries.d.ts +38 -0
- package/dist/core/session-manager-entries.d.ts.map +1 -0
- package/dist/core/session-manager-entries.js +124 -0
- package/dist/core/session-manager-entries.js.map +1 -0
- package/dist/core/session-manager-history.d.ts +38 -0
- package/dist/core/session-manager-history.d.ts.map +1 -0
- package/dist/core/session-manager-history.js +379 -0
- package/dist/core/session-manager-history.js.map +1 -0
- package/dist/core/session-manager-list.d.ts +5 -0
- package/dist/core/session-manager-list.d.ts.map +1 -0
- package/dist/core/session-manager-list.js +196 -0
- package/dist/core/session-manager-list.js.map +1 -0
- package/dist/core/session-manager-migrations.d.ts +11 -0
- package/dist/core/session-manager-migrations.d.ts.map +1 -0
- package/dist/core/session-manager-migrations.js +80 -0
- package/dist/core/session-manager-migrations.js.map +1 -0
- package/dist/core/session-manager-paths.d.ts +7 -0
- package/dist/core/session-manager-paths.d.ts.map +1 -0
- package/dist/core/session-manager-paths.js +22 -0
- package/dist/core/session-manager-paths.js.map +1 -0
- package/dist/core/session-manager-storage.d.ts +15 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -0
- package/dist/core/session-manager-storage.js +127 -0
- package/dist/core/session-manager-storage.js.map +1 -0
- package/dist/core/session-manager-types.d.ts +172 -0
- package/dist/core/session-manager-types.d.ts.map +1 -0
- package/dist/core/session-manager-types.js +2 -0
- package/dist/core/session-manager-types.js.map +1 -0
- package/dist/core/session-manager-validation.d.ts +7 -0
- package/dist/core/session-manager-validation.d.ts.map +1 -0
- package/dist/core/session-manager-validation.js +34 -0
- package/dist/core/session-manager-validation.js.map +1 -0
- package/dist/core/session-manager.d.ts +8 -390
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +7 -1418
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +65 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -0
- package/dist/core/settings-manager-basic-accessors.js +253 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -0
- package/dist/core/settings-manager-core.d.ts +57 -0
- package/dist/core/settings-manager-core.d.ts.map +1 -0
- package/dist/core/settings-manager-core.js +387 -0
- package/dist/core/settings-manager-core.js.map +1 -0
- package/dist/core/settings-manager-internals.d.ts +13 -0
- package/dist/core/settings-manager-internals.d.ts.map +1 -0
- package/dist/core/settings-manager-internals.js +4 -0
- package/dist/core/settings-manager-internals.js.map +1 -0
- package/dist/core/settings-manager-resource-accessors.d.ts +43 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -0
- package/dist/core/settings-manager-resource-accessors.js +172 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -0
- package/dist/core/settings-manager-ui-accessors.d.ts +44 -0
- package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -0
- package/dist/core/settings-manager-ui-accessors.js +208 -0
- package/dist/core/settings-manager-ui-accessors.js.map +1 -0
- package/dist/core/settings-manager.d.ts +6 -321
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +5 -1060
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-merge.d.ts +4 -0
- package/dist/core/settings-merge.d.ts.map +1 -0
- package/dist/core/settings-merge.js +26 -0
- package/dist/core/settings-merge.js.map +1 -0
- package/dist/core/settings-storage.d.ts +20 -0
- package/dist/core/settings-storage.d.ts.map +1 -0
- package/dist/core/settings-storage.js +100 -0
- package/dist/core/settings-storage.js.map +1 -0
- package/dist/core/settings-types.d.ts +123 -0
- package/dist/core/settings-types.d.ts.map +1 -0
- package/dist/core/settings-types.js +2 -0
- package/dist/core/settings-types.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +0 -5
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +10 -11
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff-preserve.d.ts +18 -0
- package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -0
- package/dist/core/tools/edit-diff-preserve.js +85 -0
- package/dist/core/tools/edit-diff-preserve.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +3 -2
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +15 -18
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +0 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/todos-execute.d.ts +5 -0
- package/dist/core/tools/todos-execute.d.ts.map +1 -0
- package/dist/core/tools/todos-execute.js +200 -0
- package/dist/core/tools/todos-execute.js.map +1 -0
- package/dist/core/tools/todos-locks.d.ts +4 -0
- package/dist/core/tools/todos-locks.d.ts.map +1 -0
- package/dist/core/tools/todos-locks.js +80 -0
- package/dist/core/tools/todos-locks.js.map +1 -0
- package/dist/core/tools/todos-model.d.ts +21 -0
- package/dist/core/tools/todos-model.d.ts.map +1 -0
- package/dist/core/tools/todos-model.js +71 -0
- package/dist/core/tools/todos-model.js.map +1 -0
- package/dist/core/tools/todos-mutations.d.ts +6 -0
- package/dist/core/tools/todos-mutations.d.ts.map +1 -0
- package/dist/core/tools/todos-mutations.js +85 -0
- package/dist/core/tools/todos-mutations.js.map +1 -0
- package/dist/core/tools/todos-paths.d.ts +5 -0
- package/dist/core/tools/todos-paths.d.ts.map +1 -0
- package/dist/core/tools/todos-paths.js +25 -0
- package/dist/core/tools/todos-paths.js.map +1 -0
- package/dist/core/tools/todos-render.d.ts +10 -0
- package/dist/core/tools/todos-render.d.ts.map +1 -0
- package/dist/core/tools/todos-render.js +159 -0
- package/dist/core/tools/todos-render.js.map +1 -0
- package/dist/core/tools/todos-storage.d.ts +9 -0
- package/dist/core/tools/todos-storage.d.ts.map +1 -0
- package/dist/core/tools/todos-storage.js +183 -0
- package/dist/core/tools/todos-storage.js.map +1 -0
- package/dist/core/tools/todos-types.d.ts +46 -0
- package/dist/core/tools/todos-types.d.ts.map +1 -0
- package/dist/core/tools/todos-types.js +27 -0
- package/dist/core/tools/todos-types.js.map +1 -0
- package/dist/core/tools/todos.d.ts +12 -32
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +7 -893
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/index-extensions.d.ts +3 -0
- package/dist/index-extensions.d.ts.map +1 -0
- package/dist/index-extensions.js +2 -0
- package/dist/index-extensions.js.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main-app-mode.d.ts +15 -0
- package/dist/main-app-mode.d.ts.map +1 -0
- package/dist/main-app-mode.js +51 -0
- package/dist/main-app-mode.js.map +1 -0
- package/dist/main-session-options.d.ts +12 -0
- package/dist/main-session-options.d.ts.map +1 -0
- package/dist/main-session-options.js +87 -0
- package/dist/main-session-options.js.map +1 -0
- package/dist/main-session.d.ts +9 -0
- package/dist/main-session.d.ts.map +1 -0
- package/dist/main-session.js +188 -0
- package/dist/main-session.js.map +1 -0
- package/dist/main-stdio.d.ts +12 -0
- package/dist/main-stdio.d.ts.map +1 -0
- package/dist/main-stdio.js +68 -0
- package/dist/main-stdio.js.map +1 -0
- package/dist/main.d.ts +2 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +11 -388
- package/dist/main.js.map +1 -1
- package/dist/migrations-config-values.d.ts +9 -0
- package/dist/migrations-config-values.d.ts.map +1 -0
- package/dist/migrations-config-values.js +298 -0
- package/dist/migrations-config-values.js.map +1 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +2 -296
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +0 -7
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts +9 -0
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-actions.js +244 -0
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +18 -0
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-editor.js +165 -0
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-events.d.ts +5 -0
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-events.js +200 -0
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts +13 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.js +185 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +13 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.js +101 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +53 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.js +42 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-types.d.ts +63 -0
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-types.js +2 -0
- package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts +28 -0
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-utils.js +103 -0
- package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts +6 -129
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +50 -1022
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/config-selector-list.d.ts +65 -0
- package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -0
- package/dist/modes/interactive/components/config-selector-list.js +458 -0
- package/dist/modes/interactive/components/config-selector-list.js.map +1 -0
- package/dist/modes/interactive/components/config-selector.d.ts +3 -58
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +2 -457
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-delete.d.ts +10 -0
- package/dist/modes/interactive/components/session-selector-delete.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-delete.js +40 -0
- package/dist/modes/interactive/components/session-selector-delete.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-header.d.ts +33 -0
- package/dist/modes/interactive/components/session-selector-header.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-header.js +117 -0
- package/dist/modes/interactive/components/session-selector-header.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-list.d.ts +49 -0
- package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-list.js +307 -0
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-tree.d.ts +25 -0
- package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-tree.js +53 -0
- package/dist/modes/interactive/components/session-selector-tree.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-types.d.ts +4 -0
- package/dist/modes/interactive/components/session-selector-types.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-types.js +2 -0
- package/dist/modes/interactive/components/session-selector-types.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-utils.d.ts +4 -0
- package/dist/modes/interactive/components/session-selector-utils.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-utils.js +37 -0
- package/dist/modes/interactive/components/session-selector-utils.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +3 -49
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +5 -542
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts +3 -0
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js +84 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector-items.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector-items.js +211 -0
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector-options.d.ts +6 -0
- package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector-options.js +14 -0
- package/dist/modes/interactive/components/settings-selector-options.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector-submenus.d.ts +44 -0
- package/dist/modes/interactive/components/settings-selector-submenus.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector-submenus.js +228 -0
- package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector-types.d.ts +67 -0
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector-types.js +2 -0
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -63
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -538
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-component.d.ts +21 -0
- package/dist/modes/interactive/components/tree-selector-component.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-component.js +80 -0
- package/dist/modes/interactive/components/tree-selector-component.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-content.d.ts +8 -0
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-content.js +263 -0
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-help.d.ts +16 -0
- package/dist/modes/interactive/components/tree-selector-help.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-help.js +103 -0
- package/dist/modes/interactive/components/tree-selector-help.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-label-input.d.ts +16 -0
- package/dist/modes/interactive/components/tree-selector-label-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-label-input.js +46 -0
- package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-list.d.ts +33 -0
- package/dist/modes/interactive/components/tree-selector-list.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-list.js +336 -0
- package/dist/modes/interactive/components/tree-selector-list.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-model.d.ts +7 -0
- package/dist/modes/interactive/components/tree-selector-model.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-model.js +358 -0
- package/dist/modes/interactive/components/tree-selector-model.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-types.d.ts +57 -0
- package/dist/modes/interactive/components/tree-selector-types.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-types.js +6 -0
- package/dist/modes/interactive/components/tree-selector-types.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector-viewport.d.ts +10 -0
- package/dist/modes/interactive/components/tree-selector-viewport.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector-viewport.js +32 -0
- package/dist/modes/interactive/components/tree-selector-viewport.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector.d.ts +2 -88
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +1 -1200
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts +2 -0
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-agent-events.js +370 -0
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -0
- package/dist/modes/interactive/interactive-auth-login.d.ts +2 -0
- package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-auth-login.js +214 -0
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -0
- package/dist/modes/interactive/interactive-auth-routing.d.ts +2 -0
- package/dist/modes/interactive/interactive-auth-routing.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-auth-routing.js +128 -0
- package/dist/modes/interactive/interactive-auth-routing.js.map +1 -0
- package/dist/modes/interactive/interactive-autocomplete.d.ts +2 -0
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-autocomplete.js +140 -0
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -0
- package/dist/modes/interactive/interactive-bash-compact.d.ts +2 -0
- package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-bash-compact.js +112 -0
- package/dist/modes/interactive/interactive-bash-compact.js.map +1 -0
- package/dist/modes/interactive/interactive-editor-actions.d.ts +2 -0
- package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-editor-actions.js +131 -0
- package/dist/modes/interactive/interactive-editor-actions.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-context.d.ts +2 -0
- package/dist/modes/interactive/interactive-extension-context.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-extension-context.js +159 -0
- package/dist/modes/interactive/interactive-extension-context.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-custom-ui.d.ts +2 -0
- package/dist/modes/interactive/interactive-extension-custom-ui.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-extension-custom-ui.js +208 -0
- package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-dialogs.d.ts +2 -0
- package/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-extension-dialogs.js +162 -0
- package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-runtime.d.ts +2 -0
- package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-extension-runtime.js +179 -0
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -0
- package/dist/modes/interactive/interactive-extension-widgets.d.ts +2 -0
- package/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-extension-widgets.js +113 -0
- package/dist/modes/interactive/interactive-extension-widgets.js.map +1 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts +2 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js +186 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -0
- package/dist/modes/interactive/interactive-input-handling.d.ts +2 -0
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-input-handling.js +275 -0
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts +103 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode-base.js +130 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -0
- package/dist/modes/interactive/interactive-mode-deps.d.ts +81 -0
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode-deps.js +74 -0
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -0
- package/dist/modes/interactive/interactive-mode-helpers.d.ts +21 -0
- package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode-helpers.js +77 -0
- package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts +313 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode-surface.js +2 -0
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts +29 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode-types.js +2 -0
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +30 -404
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +29 -5260
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts +2 -0
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-model-routing.js +269 -0
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -0
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts +2 -0
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-process-lifecycle.js +189 -0
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -0
- package/dist/modes/interactive/interactive-queueing.d.ts +2 -0
- package/dist/modes/interactive/interactive-queueing.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-queueing.js +163 -0
- package/dist/modes/interactive/interactive-queueing.js.map +1 -0
- package/dist/modes/interactive/interactive-render-chat.d.ts +2 -0
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-render-chat.js +170 -0
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -0
- package/dist/modes/interactive/interactive-resource-disclosure.d.ts +2 -0
- package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-resource-disclosure.js +101 -0
- package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -0
- package/dist/modes/interactive/interactive-resource-paths.d.ts +2 -0
- package/dist/modes/interactive/interactive-resource-paths.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-resource-paths.js +228 -0
- package/dist/modes/interactive/interactive-resource-paths.js.map +1 -0
- package/dist/modes/interactive/interactive-resource-rendering.d.ts +2 -0
- package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-resource-rendering.js +181 -0
- package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts +2 -0
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-selectors.js +198 -0
- package/dist/modes/interactive/interactive-selectors.js.map +1 -0
- package/dist/modes/interactive/interactive-session-routing.d.ts +2 -0
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-session-routing.js +232 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -0
- package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -0
- package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-session-runtime.js +131 -0
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -0
- package/dist/modes/interactive/interactive-slash-commands.d.ts +2 -0
- package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-slash-commands.js +338 -0
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -0
- package/dist/modes/interactive/interactive-startup.d.ts +2 -0
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-startup.js +348 -0
- package/dist/modes/interactive/interactive-startup.js.map +1 -0
- package/dist/modes/interactive/model-search.d.ts +5 -0
- package/dist/modes/interactive/model-search.d.ts.map +1 -1
- package/dist/modes/interactive/model-search.js +9 -0
- package/dist/modes/interactive/model-search.js.map +1 -1
- package/dist/modes/interactive/theme/color-utils.d.ts +20 -0
- package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -0
- package/dist/modes/interactive/theme/color-utils.js +204 -0
- package/dist/modes/interactive/theme/color-utils.js.map +1 -0
- package/dist/modes/interactive/theme/export-colors.d.ts +19 -0
- package/dist/modes/interactive/theme/export-colors.d.ts.map +1 -0
- package/dist/modes/interactive/theme/export-colors.js +69 -0
- package/dist/modes/interactive/theme/export-colors.js.map +1 -0
- package/dist/modes/interactive/theme/global-theme.d.ts +12 -0
- package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/global-theme.js +150 -0
- package/dist/modes/interactive/theme/global-theme.js.map +1 -0
- package/dist/modes/interactive/theme/terminal-detection.d.ts +30 -0
- package/dist/modes/interactive/theme/terminal-detection.d.ts.map +1 -0
- package/dist/modes/interactive/theme/terminal-detection.js +89 -0
- package/dist/modes/interactive/theme/terminal-detection.js.map +1 -0
- package/dist/modes/interactive/theme/theme-class.d.ts +30 -0
- package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-class.js +83 -0
- package/dist/modes/interactive/theme/theme-class.js.map +1 -0
- package/dist/modes/interactive/theme/theme-loading.d.ts +17 -0
- package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-loading.js +155 -0
- package/dist/modes/interactive/theme/theme-loading.js.map +1 -0
- package/dist/modes/interactive/theme/theme-parse.d.ts +5 -0
- package/dist/modes/interactive/theme/theme-parse.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-parse.js +52 -0
- package/dist/modes/interactive/theme/theme-parse.js.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts +255 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.js +78 -0
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts +6 -108
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +6 -1065
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/interactive/theme/tui-theme.d.ts +15 -0
- package/dist/modes/interactive/theme/tui-theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/tui-theme.js +199 -0
- package/dist/modes/interactive/theme/tui-theme.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -61
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -72
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts +14 -0
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-command-handler.js +226 -0
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -0
- package/dist/modes/rpc/rpc-extension-ui.d.ts +15 -0
- package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-extension-ui.js +196 -0
- package/dist/modes/rpc/rpc-extension-ui.js.map +1 -0
- package/dist/modes/rpc/rpc-input.d.ts +12 -0
- package/dist/modes/rpc/rpc-input.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-input.js +54 -0
- package/dist/modes/rpc/rpc-input.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +43 -607
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-responses.d.ts +8 -0
- package/dist/modes/rpc/rpc-responses.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-responses.js +27 -0
- package/dist/modes/rpc/rpc-responses.js.map +1 -0
- package/dist/modes/rpc/rpc-session-binding.d.ts +25 -0
- package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-session-binding.js +70 -0
- package/dist/modes/rpc/rpc-session-binding.js.map +1 -0
- package/dist/package-manager-cli-parser.d.ts +28 -0
- package/dist/package-manager-cli-parser.d.ts.map +1 -0
- package/dist/package-manager-cli-parser.js +269 -0
- package/dist/package-manager-cli-parser.js.map +1 -0
- package/dist/package-manager-cli.d.ts +0 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +2 -267
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +10 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/shell.d.ts +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +12 -5
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/version-check.d.ts +1 -0
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +17 -0
- package/dist/utils/version-check.js.map +1 -1
- package/docs/custom-provider.md +4 -3
- package/docs/development.md +4 -0
- package/docs/models.md +3 -2
- package/docs/packages.md +2 -2
- package/docs/quickstart.md +1 -1
- package/docs/sdk.md +2 -40
- package/docs/security.md +1 -1
- package/docs/workflows.md +246 -179
- package/examples/extensions/custom-provider-anthropic/index.ts +1 -106
- package/examples/extensions/gondolin/index.ts +0 -23
- package/examples/extensions/overlay-qa-animation-components.ts +255 -0
- package/examples/extensions/overlay-qa-focus-components.ts +222 -0
- package/examples/extensions/overlay-qa-position-components.ts +433 -0
- package/examples/extensions/overlay-qa-shared.ts +37 -0
- package/examples/extensions/overlay-qa-streaming-input-components.ts +205 -0
- package/examples/extensions/overlay-qa-tests.ts +17 -1156
- package/examples/extensions/overlay-qa-toggle-passive-components.ts +169 -0
- package/examples/extensions/space-invaders.ts +0 -60
- package/examples/extensions/subagent/display.ts +148 -0
- package/examples/extensions/subagent/index.ts +11 -858
- package/examples/extensions/subagent/render.ts +383 -0
- package/examples/extensions/subagent/runner.ts +252 -0
- package/examples/extensions/subagent/schemas.ts +59 -0
- package/examples/extensions/subagent/types.ts +36 -0
- package/examples/extensions/tic-tac-toe-instructions.ts +65 -0
- package/examples/extensions/tic-tac-toe-rendering.ts +414 -0
- package/examples/extensions/tic-tac-toe-state.ts +158 -0
- package/examples/extensions/tic-tac-toe.ts +92 -754
- package/examples/rpc-extension-ui-components.ts +189 -0
- package/examples/rpc-extension-ui.ts +2 -179
- package/package.json +7 -7
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +0 -277
- package/dist/core/tools/bash-policy.d.ts +0 -62
- package/dist/core/tools/bash-policy.d.ts.map +0 -1
- package/dist/core/tools/bash-policy.js +0 -1069
- package/dist/core/tools/bash-policy.js.map +0 -1
|
@@ -1,4166 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
} from "../tui/store-widget-installer.js";
|
|
44
|
-
import type { WidgetFactory } from "../tui/store-widget-installer.js";
|
|
45
|
-
import { buildGraphOverlayAdapter } from "../tui/overlay-adapter.js";
|
|
46
|
-
import type { OverlayPiSurface } from "../tui/overlay-adapter.js";
|
|
47
|
-
import type { GraphOverlayPort } from "../tui/overlay-adapter.js";
|
|
48
|
-
import { renderSessionList } from "../tui/session-list.js";
|
|
49
|
-
import { selectRunsForPicker } from "../tui/session-picker.js";
|
|
50
|
-
import { renderRunDetail } from "../tui/run-detail.js";
|
|
51
|
-
|
|
52
|
-
import { openSessionPicker, openKillConfirm } from "../tui/session-overlays.js";
|
|
53
|
-
import {
|
|
54
|
-
openInlineInputsForm,
|
|
55
|
-
registerInlineFormRenderer,
|
|
56
|
-
} from "../tui/inline-form-overlay.js";
|
|
57
|
-
import { clearForms } from "../tui/inline-form-store.js";
|
|
58
|
-
import {
|
|
59
|
-
registerChatSurfaceRenderer,
|
|
60
|
-
emitChatSurface,
|
|
61
|
-
} from "../tui/chat-surface-message.js";
|
|
62
|
-
import { openInputsPicker } from "../tui/inputs-overlay.js";
|
|
63
|
-
import { deriveGraphTheme } from "../tui/graph-theme.js";
|
|
64
|
-
import { createExtensionRuntime } from "./runtime.js";
|
|
65
|
-
import type { ExtensionRuntime } from "./runtime.js";
|
|
66
|
-
import {
|
|
67
|
-
discoverWorkflows,
|
|
68
|
-
discoverStartupWorkflowsSync,
|
|
69
|
-
} from "./discovery.js";
|
|
70
|
-
import type { DiscoveryResult } from "./discovery.js";
|
|
71
|
-
import {
|
|
72
|
-
loadWorkflowConfig,
|
|
73
|
-
toScopedDiscoveryConfig,
|
|
74
|
-
WORKFLOW_CONFIG_DEFAULTS,
|
|
75
|
-
withWorkflowDefaults,
|
|
76
|
-
} from "./config-loader.js";
|
|
77
|
-
import {
|
|
78
|
-
createWorkflowLifecycleNotificationState,
|
|
79
|
-
installWorkflowLifecycleNotifications,
|
|
80
|
-
registerLifecycleNoticeRenderer,
|
|
81
|
-
resetWorkflowLifecycleNotificationState,
|
|
82
|
-
seedWorkflowLifecycleNotificationState,
|
|
83
|
-
withWorkflowLifecycleNotificationsSuppressed,
|
|
84
|
-
withWorkflowLifecycleNotificationsSuppressedAsync,
|
|
85
|
-
} from "./lifecycle-notifications.js";
|
|
86
|
-
import type { WorkflowLifecycleNotificationConfig } from "./lifecycle-notifications.js";
|
|
87
|
-
import {
|
|
88
|
-
createWorkflowHilAnswerNotificationState,
|
|
89
|
-
installWorkflowHilAnswerNotifications,
|
|
90
|
-
registerHilAnswerNoticeRenderer,
|
|
91
|
-
resetWorkflowHilAnswerNotificationState,
|
|
92
|
-
} from "./hil-answer-notifications.js";
|
|
93
|
-
import type { ConfigLoadResult } from "./config-loader.js";
|
|
94
|
-
import type {
|
|
95
|
-
WorkflowPersistencePort,
|
|
96
|
-
WorkflowMcpPort,
|
|
97
|
-
WorkflowRuntimeConfig,
|
|
98
|
-
WorkflowChainStep,
|
|
99
|
-
WorkflowDirectTaskItem,
|
|
100
|
-
WorkflowDetails,
|
|
101
|
-
WorkflowMaxOutput,
|
|
102
|
-
WorkflowModelCatalogPort,
|
|
103
|
-
WorkflowModelInfo,
|
|
104
|
-
StageOptions,
|
|
105
|
-
WorkflowExecutionPolicy,
|
|
106
|
-
WorkflowInputValues,
|
|
107
|
-
WorkflowSerializableValue,
|
|
108
|
-
} from "../shared/types.js";
|
|
109
|
-
import { INTERACTIVE_WORKFLOW_POLICY, NON_INTERACTIVE_WORKFLOW_POLICY } from "../shared/types.js";
|
|
110
|
-
import { buildRuntimeAdapters } from "./wiring.js";
|
|
111
|
-
import type { PiUISurface } from "./wiring.js";
|
|
112
|
-
import { createStatusWriter } from "./status-writer.js";
|
|
113
|
-
import type { StatusWriter } from "./status-writer.js";
|
|
114
|
-
import { setMcpScope, clearMcpScope } from "./mcp.js";
|
|
115
|
-
import type { PiMcpExtensionAPI, PiEventBus } from "./mcp.js";
|
|
116
|
-
import type { StageSessionRuntime } from "../runs/foreground/stage-runner.js";
|
|
117
|
-
import {
|
|
118
|
-
expandWorkflowGraph,
|
|
119
|
-
expandedStageLabel,
|
|
120
|
-
stageMatchesExpandedIdentifier,
|
|
121
|
-
} from "../shared/expanded-workflow-graph.js";
|
|
122
|
-
import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
|
|
123
|
-
import {
|
|
124
|
-
WORKFLOW_STAGE_SUBAGENT_GUARD_ENV,
|
|
125
|
-
getEnvValue,
|
|
126
|
-
type CreateAgentSessionOptions,
|
|
127
|
-
type DefaultResourceLoaderInheritanceSnapshot,
|
|
128
|
-
} from "@bastani/atomic";
|
|
129
|
-
|
|
130
|
-
export const WORKFLOW_TOOL_DESCRIPTION =
|
|
131
|
-
"Run named workflows or direct one-off task/tasks/chain workflows; " +
|
|
132
|
-
"discover with list/get/inputs, inspect status/stages/stage details, " +
|
|
133
|
-
"send prompt answers or steering, pause/resume/interrupt/kill runs, and reload workflow resources. " +
|
|
134
|
-
"For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. " +
|
|
135
|
-
"For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, " +
|
|
136
|
-
"quote the exact path without rewriting separators (Windows backslashes are valid), " +
|
|
137
|
-
"then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.";
|
|
138
|
-
|
|
139
|
-
export const DEFAULT_PROMPT_GUIDANCE: string[] = [
|
|
140
|
-
`**Workflows**: Use the \`workflow\` tool for existing named workflows and for repeatable, inspectable, resumable, or multi-stage processes; use direct \`task\`, \`tasks\`, or \`chain\` workflow calls for one-off tracked work when that is useful.
|
|
141
|
-
- For unfamiliar named workflows, discover with \`action: "list"\`, inspect with \`action: "get"\` or \`action: "inputs"\`, and run with \`action: "run"\`, \`workflow\`, and validated \`inputs\`; do not invent workflow names or input keys.
|
|
142
|
-
- When designing or editing workflows, read docs/workflows.md and reference its Workflow Starter Patterns: Classify-and-act, Fan-out-and-synthesize, Adversarial verification, Generate-and-filter, Tournament, and Loop until done. Choose or combine these patterns before inventing a custom stage graph, and reflect the selected pattern in the spec and Mermaid diagram when using the create-spec skill.
|
|
143
|
-
- Once you run a workflow with the workflow tool, end your current turn and wait for the next user input or lifecycle notice.
|
|
144
|
-
- You will automatically be alerted of key lifecycle events like start, finish, failure; do not micro-manage the run with sleep/status polling loops or read its logs/stages unless the user asks you to or you need information for the next step.
|
|
145
|
-
- If the user needs information from the workflow run, use targeted \`status\`/\`stages\`/\`stage\` checks instead of trying to read everything.
|
|
146
|
-
- Offer to help the user on another task instead of anxiously polling or help the user run another workflow if they need.
|
|
147
|
-
- Use run-control and messaging actions (\`send\`, \`pause\`, \`resume\`, \`interrupt\`, \`kill\`) only when needed to answer prompts, steer a stage, resume or interrupt paused work, or respond to user requests/control signals.
|
|
148
|
-
- For transcripts, avoid reading whole session transcripts at once. Use \`stages\` or \`stage\` to get \`sessionFile\`/\`transcriptPath\`, quote the exact path without rewriting separators (preserve Windows backslashes), search it with \`rg\`/\`grep\`, and read small relevant ranges; use \`transcript\` with explicit \`tail\` or \`limit\` only for quick recent-context checks.
|
|
149
|
-
- If a user asks to create or edit a workflow, use the create-spec skill when available and ask detailed clarifying questions until you understand its purpose, inputs, stages, handoffs, validation, success criteria, and selected starter pattern. Then read the workflow docs/examples and implement the workflow from the created spec directly as a TypeScript definition. After you implement the workflow, reload it to access it and run it with test inputs to validate it works as intended before presenting it to the user.
|
|
150
|
-
- Tip: when designing workflows, implement it in a way that you pass information from stage to stage by writing it to a file or artifact (either deterministic or model-driven), pass the path with \`reads\`, and explicitly prompt the downstream agent with wording like \`Read the file at <path>...\`; do not inject large \`previous\` payloads or session history into the next prompt unless explicitly requested to.
|
|
151
|
-
- If you run \`ralph\` or \`goal\` workflow, define an objective that includes tight scope, concrete and verifiable done criteria, and validation steps; then monitor progress as above instead of doing parallel implementation yourself.`,
|
|
152
|
-
];
|
|
153
|
-
|
|
154
|
-
// ---------------------------------------------------------------------------
|
|
155
|
-
// Minimal ExtensionAPI structural types
|
|
156
|
-
// No `any`; all optional fields use explicit union with undefined.
|
|
157
|
-
// cross-ref: pi docs/skills/authoring-extensions.md (ExtensionAPI shape)
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
|
|
160
|
-
/** Theme object passed to renderCall/renderResult slots (opaque — not consumed in stubs). */
|
|
161
|
-
export type PiTheme = Record<string, string>;
|
|
162
|
-
|
|
163
|
-
/** Context object passed to renderCall/renderResult slots. */
|
|
164
|
-
export interface PiRenderContext {
|
|
165
|
-
state?: {
|
|
166
|
-
runId?: string;
|
|
167
|
-
stages?: unknown[];
|
|
168
|
-
};
|
|
169
|
-
invalidate?: () => void;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Options bag passed to renderResult. */
|
|
173
|
-
export interface PiRenderResultOpts extends RenderResultOpts {}
|
|
174
|
-
|
|
175
|
-
export interface PiRenderComponent {
|
|
176
|
-
render(width: number): string[];
|
|
177
|
-
invalidate?: () => void;
|
|
178
|
-
includes(searchString: string): boolean;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export interface PiMessageRenderComponent {
|
|
182
|
-
render(width: number): string[];
|
|
183
|
-
invalidate?: () => void;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export interface PiMessageRenderOptions {
|
|
187
|
-
expanded: boolean;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export type PiMessageRendererResult = string | PiMessageRenderComponent | null | undefined;
|
|
191
|
-
export type PiMessageRenderer = (
|
|
192
|
-
payload: unknown,
|
|
193
|
-
options?: PiMessageRenderOptions,
|
|
194
|
-
theme?: unknown,
|
|
195
|
-
) => PiMessageRendererResult;
|
|
196
|
-
|
|
197
|
-
function dynamicTextRenderComponent(renderText: (width: number) => string): PiRenderComponent {
|
|
198
|
-
return {
|
|
199
|
-
render(width: number): string[] {
|
|
200
|
-
return renderText(width).split("\n");
|
|
201
|
-
},
|
|
202
|
-
includes(searchString: string): boolean {
|
|
203
|
-
return renderText(120).includes(searchString);
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Completion for a slash-command argument. Matches pi-tui's `AutocompleteItem`.
|
|
210
|
-
* `value` is the text inserted on selection; `label` is the menu display; the
|
|
211
|
-
* optional `description` is the secondary line. Without `value`, pi-tui crashes
|
|
212
|
-
* in `getBestAutocompleteMatchIndex` (`value.startsWith(prefix)`).
|
|
213
|
-
* cross-ref: @earendil-works/pi-tui autocomplete AutocompleteItem
|
|
214
|
-
*/
|
|
215
|
-
export interface PiArgumentCompletion {
|
|
216
|
-
value: string;
|
|
217
|
-
label: string;
|
|
218
|
-
description?: string;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Canonical slash command options for pi.registerCommand(name, options).
|
|
223
|
-
* Mirrors `RegisteredCommand` from pi's `extensibility/extensions/types.ts`
|
|
224
|
-
* minus the `name` field (which is the first arg to registerCommand).
|
|
225
|
-
* cross-ref: research/docs/2026-05-11-pi-coding-agent-reference.md §4.2
|
|
226
|
-
*/
|
|
227
|
-
export type PiArgumentCompletionResult = PiArgumentCompletion[] | null;
|
|
228
|
-
|
|
229
|
-
export interface PiCommandOptions {
|
|
230
|
-
description: string;
|
|
231
|
-
handler: (args: string, ctx: PiCommandContext) => Promise<void> | void;
|
|
232
|
-
getArgumentCompletions?: (partial: string) => PiArgumentCompletionResult;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Context provided to slash command handlers. Aligns with pi's
|
|
237
|
-
* `ExtensionCommandContext` (subset of what we actually consume): the
|
|
238
|
-
* host always supplies `ui` and `ui.notify`, so callers print via
|
|
239
|
-
* `ctx.ui.notify("…", "info")` directly — no wrapper indirection.
|
|
240
|
-
*/
|
|
241
|
-
interface PiRuntimeModel {
|
|
242
|
-
readonly provider: string;
|
|
243
|
-
readonly id: string;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
interface PiRuntimeModelRegistry {
|
|
247
|
-
getAvailable(): PiRuntimeModel[];
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
interface PiModelContext {
|
|
251
|
-
readonly model?: PiRuntimeModel;
|
|
252
|
-
readonly modelRegistry?: PiRuntimeModelRegistry;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export interface PiCommandContext extends PiModelContext {
|
|
256
|
-
ui: {
|
|
257
|
-
notify: (message: string, type?: "info" | "warning" | "error") => void;
|
|
258
|
-
} & PiUISurface;
|
|
259
|
-
/**
|
|
260
|
-
* False when the host bound a no-op UI surface (print/JSON `-p` modes).
|
|
261
|
-
* Absent on older hosts and unit-test stubs; treat absence as interactive.
|
|
262
|
-
*/
|
|
263
|
-
hasUI?: boolean;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** CLI flag registration options. Mirrors the inline options on `ExtensionAPI.registerFlag`. */
|
|
267
|
-
export interface PiFlagNamedOpts {
|
|
268
|
-
description: string;
|
|
269
|
-
type?: "string" | "boolean";
|
|
270
|
-
default?: unknown;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Pi's AgentToolResult shape — returned by `execute` and consumed by
|
|
275
|
-
* `renderResult`. `details` carries the original workflow result for the
|
|
276
|
-
* renderer; `content` is what the model sees on tool completion.
|
|
277
|
-
*/
|
|
278
|
-
export interface PiAgentToolResult<TDetails> {
|
|
279
|
-
content: Array<
|
|
280
|
-
{ type: "text"; text: string } | { type: "image"; [key: string]: unknown }
|
|
281
|
-
>;
|
|
282
|
-
details: TDetails;
|
|
283
|
-
terminate?: boolean;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/** Tool registration options aligned with pi's `ToolDefinition`. */
|
|
287
|
-
export interface PiToolOpts<TArgs, TDetails> {
|
|
288
|
-
name: string;
|
|
289
|
-
label: string;
|
|
290
|
-
description: string;
|
|
291
|
-
parameters: unknown; // TypeBox TSchema — pi consumes it opaquely
|
|
292
|
-
promptGuidelines?: string[];
|
|
293
|
-
renderShell?: "default" | "self";
|
|
294
|
-
/**
|
|
295
|
-
* Pi calls execute positionally: `(toolCallId, params, signal, onUpdate, ctx)`.
|
|
296
|
-
* cross-ref: pi-coding-agent dist/core/extensions/types.d.ts ToolDefinition.execute
|
|
297
|
-
*/
|
|
298
|
-
execute: (
|
|
299
|
-
toolCallId: string,
|
|
300
|
-
params: TArgs,
|
|
301
|
-
signal: AbortSignal | undefined,
|
|
302
|
-
onUpdate: ((partial: PiAgentToolResult<TDetails>) => void) | undefined,
|
|
303
|
-
ctx: PiExecuteContext,
|
|
304
|
-
) => Promise<PiAgentToolResult<TDetails>>;
|
|
305
|
-
/** Pi passes args directly as the first positional arg (not wrapped). */
|
|
306
|
-
renderCall?: (
|
|
307
|
-
args: TArgs,
|
|
308
|
-
theme: PiTheme,
|
|
309
|
-
context: PiRenderContext,
|
|
310
|
-
) => PiRenderComponent | string;
|
|
311
|
-
/** Pi passes the full AgentToolResult as the first positional arg. */
|
|
312
|
-
renderResult?: (
|
|
313
|
-
result: PiAgentToolResult<TDetails>,
|
|
314
|
-
opts: PiRenderResultOpts,
|
|
315
|
-
theme: PiTheme,
|
|
316
|
-
context: PiRenderContext,
|
|
317
|
-
) => PiRenderComponent | string;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/** Execution context provided to tool execute handlers. */
|
|
321
|
-
export interface PiExecuteContext extends PiModelContext {
|
|
322
|
-
sessionId?: string;
|
|
323
|
-
ui?: PiUISurface;
|
|
324
|
-
hasUI?: boolean;
|
|
325
|
-
orchestrationContext?: CreateAgentSessionOptions["orchestrationContext"];
|
|
326
|
-
sessionManager?: SessionManager & {
|
|
327
|
-
getSessionFile?: () => string | undefined;
|
|
328
|
-
};
|
|
329
|
-
[key: string]: unknown;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Structural subset of pi's `ExtensionAPI` (see
|
|
334
|
-
* `packages/coding-agent/src/extensibility/extensions/types.ts`) covering
|
|
335
|
-
* the methods this extension consumes. Fields are optional so test
|
|
336
|
-
* mocks can stub a minimal surface; production runtime supplies all of
|
|
337
|
-
* them.
|
|
338
|
-
*/
|
|
339
|
-
export interface WorkflowResourceInfo {
|
|
340
|
-
readonly path: string;
|
|
341
|
-
readonly enabled: boolean;
|
|
342
|
-
readonly metadata?: {
|
|
343
|
-
readonly source?: string;
|
|
344
|
-
readonly scope?: string;
|
|
345
|
-
readonly origin?: string;
|
|
346
|
-
readonly baseDir?: string;
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
export interface ExtensionAPI {
|
|
351
|
-
registerTool?: <TArgs, TResult>(opts: PiToolOpts<TArgs, TResult>) => void;
|
|
352
|
-
/**
|
|
353
|
-
* `pi.registerCommand(name, options)` — sole slash-command registration
|
|
354
|
-
* surface. Mirrors pi's `ExtensionAPI.registerCommand`.
|
|
355
|
-
*/
|
|
356
|
-
registerCommand?: (name: string, options: PiCommandOptions) => void;
|
|
357
|
-
registerMessageRenderer?: (
|
|
358
|
-
event: string,
|
|
359
|
-
renderer: PiMessageRenderer,
|
|
360
|
-
) => void;
|
|
361
|
-
/**
|
|
362
|
-
* Inject a custom message into chat history. Used by inline workflow surfaces
|
|
363
|
-
* such as `workflows:input-form`; cards stay in scrollback and are
|
|
364
|
-
* re-rendered by the registered renderer on every `tui.requestRender()`.
|
|
365
|
-
*/
|
|
366
|
-
sendMessage?: <T = unknown>(
|
|
367
|
-
message: {
|
|
368
|
-
customType: string;
|
|
369
|
-
content?: string;
|
|
370
|
-
display?: boolean;
|
|
371
|
-
details?: T;
|
|
372
|
-
},
|
|
373
|
-
options?: {
|
|
374
|
-
triggerTurn?: boolean;
|
|
375
|
-
deliverAs?: "steer" | "followUp" | "nextTurn" | "interrupt";
|
|
376
|
-
excludeFromContext?: boolean;
|
|
377
|
-
interruptAbortMessage?: string;
|
|
378
|
-
},
|
|
379
|
-
) => void | Promise<void>;
|
|
380
|
-
registerFlag?: (name: string, opts: PiFlagNamedOpts) => void;
|
|
381
|
-
/** Return package-provided workflow files discovered by Atomic's package loader. */
|
|
382
|
-
getWorkflowResources?: () => readonly WorkflowResourceInfo[];
|
|
383
|
-
/** Refresh package-provided workflow files before rediscovery, when supported by host. */
|
|
384
|
-
refreshWorkflowResources?: () => Promise<readonly WorkflowResourceInfo[]>;
|
|
385
|
-
/** Return resource-loader options child Atomic workflow stages should inherit. */
|
|
386
|
-
getResourceLoaderInheritanceSnapshot?: () => DefaultResourceLoaderInheritanceSnapshot | undefined;
|
|
387
|
-
/**
|
|
388
|
-
* Register a keyboard shortcut.
|
|
389
|
-
* Present on pi >= 1.x; absent on older runtimes.
|
|
390
|
-
*/
|
|
391
|
-
registerShortcut?: (
|
|
392
|
-
key: string,
|
|
393
|
-
opts: {
|
|
394
|
-
description: string;
|
|
395
|
-
handler: (ctx?: PiCommandContext) => void | Promise<void>;
|
|
396
|
-
},
|
|
397
|
-
) => void;
|
|
398
|
-
/**
|
|
399
|
-
* Read the model's currently-active tool names. Present on pi's ExtensionAPI;
|
|
400
|
-
* absent on older runtimes.
|
|
401
|
-
*/
|
|
402
|
-
getActiveTools?: () => string[];
|
|
403
|
-
/**
|
|
404
|
-
* Replace the model's active tool set by name. Present on pi's ExtensionAPI;
|
|
405
|
-
* absent on older runtimes.
|
|
406
|
-
*/
|
|
407
|
-
setActiveTools?: (toolNames: string[]) => void;
|
|
408
|
-
/**
|
|
409
|
-
* Sets the current session name. Present on pi's ExtensionAPI.
|
|
410
|
-
*/
|
|
411
|
-
setSessionName?: (name: string) => void | Promise<void>;
|
|
412
|
-
/**
|
|
413
|
-
* pi events bus — used for workflow-scoped MCP events and subagent
|
|
414
|
-
* lifecycle/result routing.
|
|
415
|
-
*/
|
|
416
|
-
events?: {
|
|
417
|
-
emit?: (event: string, payload: Record<string, unknown>) => void;
|
|
418
|
-
on?: (event: string, handler: (payload: unknown) => void) => void;
|
|
419
|
-
};
|
|
420
|
-
/**
|
|
421
|
-
* Execute a shell command and return stdout/stderr/exit code.
|
|
422
|
-
* Present on the pi ExtensionAPI.
|
|
423
|
-
*/
|
|
424
|
-
exec?: (
|
|
425
|
-
command: string,
|
|
426
|
-
args: string[],
|
|
427
|
-
opts?: { signal?: AbortSignal; timeout?: number },
|
|
428
|
-
) => Promise<{
|
|
429
|
-
stdout: string;
|
|
430
|
-
stderr: string;
|
|
431
|
-
code: number;
|
|
432
|
-
killed: boolean;
|
|
433
|
-
}>;
|
|
434
|
-
/** Test seam: inject a stub session factory instead of importing the pi SDK at runtime. */
|
|
435
|
-
createAgentSession?: (
|
|
436
|
-
options?: CreateAgentSessionOptions,
|
|
437
|
-
) => Promise<{ session: StageSessionRuntime }>;
|
|
438
|
-
/** Test/degraded-runtime seam: skip project/global discovery work at startup. */
|
|
439
|
-
disableAsyncDiscovery?: boolean;
|
|
440
|
-
// -------------------------------------------------------------------------
|
|
441
|
-
// Persistence API (§5.6)
|
|
442
|
-
// -------------------------------------------------------------------------
|
|
443
|
-
/** Appends a typed entry to the session transcript. Returns the entry ID. */
|
|
444
|
-
appendEntry?: (
|
|
445
|
-
type: string,
|
|
446
|
-
payload: Record<string, unknown>,
|
|
447
|
-
) => string | undefined;
|
|
448
|
-
/** Labels an entry for /tree bookmark filtering. */
|
|
449
|
-
setLabel?: (entryId: string, label: string) => void;
|
|
450
|
-
/** Appends a synthetic system/assistant message entry. */
|
|
451
|
-
appendCustomMessageEntry?: (
|
|
452
|
-
content: string,
|
|
453
|
-
meta?: Record<string, unknown>,
|
|
454
|
-
) => string | undefined;
|
|
455
|
-
// -------------------------------------------------------------------------
|
|
456
|
-
// Lifecycle events (§5.6, §8.1 Phase D)
|
|
457
|
-
// -------------------------------------------------------------------------
|
|
458
|
-
/** Register a listener for a pi lifecycle event (e.g. session_start, session_before_compact). */
|
|
459
|
-
on?: (
|
|
460
|
-
event: string,
|
|
461
|
-
handler: (
|
|
462
|
-
event?: unknown,
|
|
463
|
-
ctx?: PiCommandContext & {
|
|
464
|
-
sessionManager?: SessionManager;
|
|
465
|
-
hasUI?: boolean;
|
|
466
|
-
},
|
|
467
|
-
) => void | object | Promise<void | object>,
|
|
468
|
-
) => void;
|
|
469
|
-
// -------------------------------------------------------------------------
|
|
470
|
-
// Session manager (§5.6 restore)
|
|
471
|
-
// -------------------------------------------------------------------------
|
|
472
|
-
sessionManager?: SessionManager;
|
|
473
|
-
ui?: {
|
|
474
|
-
setWidget?: (
|
|
475
|
-
key: string,
|
|
476
|
-
factory: WidgetFactory | undefined,
|
|
477
|
-
opts?: { placement?: string },
|
|
478
|
-
) => void;
|
|
479
|
-
/**
|
|
480
|
-
* Spawn a custom TUI component (overlay or inline).
|
|
481
|
-
* When overlay: true, the panel floats over existing content.
|
|
482
|
-
* Returns a handle with close() to dismiss, or undefined when unsupported.
|
|
483
|
-
*/
|
|
484
|
-
custom?: PiUISurface["custom"];
|
|
485
|
-
} & PiUISurface;
|
|
486
|
-
[key: string]: unknown;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// ---------------------------------------------------------------------------
|
|
490
|
-
// Workflow tool argument shape
|
|
491
|
-
// ---------------------------------------------------------------------------
|
|
492
|
-
|
|
493
|
-
export interface WorkflowToolArgs extends StageOptions {
|
|
494
|
-
/** Canonical named workflow identifier. */
|
|
495
|
-
workflow?: string;
|
|
496
|
-
inputs?: WorkflowInputValues;
|
|
497
|
-
action?:
|
|
498
|
-
| "run"
|
|
499
|
-
| "list"
|
|
500
|
-
| "get"
|
|
501
|
-
| "status"
|
|
502
|
-
| "stages"
|
|
503
|
-
| "stage"
|
|
504
|
-
| "transcript"
|
|
505
|
-
| "send"
|
|
506
|
-
| "pause"
|
|
507
|
-
| "interrupt"
|
|
508
|
-
| "kill"
|
|
509
|
-
| "resume"
|
|
510
|
-
| "reload"
|
|
511
|
-
| "inputs";
|
|
512
|
-
/** Canonical run identifier or unique prefix for status/interrupt/kill/resume. */
|
|
513
|
-
runId?: string;
|
|
514
|
-
/** Apply supported run-control actions to all in-flight runs. */
|
|
515
|
-
all?: boolean;
|
|
516
|
-
/** Stage id, unique prefix, or name for stage-scoped resume. */
|
|
517
|
-
stageId?: string;
|
|
518
|
-
/** Optional message forwarded when resuming paused work. */
|
|
519
|
-
message?: string;
|
|
520
|
-
statusFilter?: StageStatus | "all";
|
|
521
|
-
format?: "text" | "json";
|
|
522
|
-
limit?: number;
|
|
523
|
-
tail?: number;
|
|
524
|
-
includeToolOutput?: boolean;
|
|
525
|
-
text?: string;
|
|
526
|
-
response?: unknown;
|
|
527
|
-
delivery?: "auto" | "answer" | "prompt" | "steer" | "followUp" | "resume";
|
|
528
|
-
promptId?: string;
|
|
529
|
-
reason?: string;
|
|
530
|
-
/** Direct single-task mode, or root task string when chain is present. */
|
|
531
|
-
task?: WorkflowDirectTaskItem | string;
|
|
532
|
-
/** Direct top-level parallel mode. */
|
|
533
|
-
tasks?: WorkflowDirectTaskItem[];
|
|
534
|
-
/** Direct sequential/parallel chain mode. */
|
|
535
|
-
chain?: WorkflowChainStep[];
|
|
536
|
-
chainName?: string;
|
|
537
|
-
context?: "fresh" | "fork";
|
|
538
|
-
/** Internal host-derived parent session file for context:"fork". */
|
|
539
|
-
forkFromSessionFile?: string;
|
|
540
|
-
concurrency?: number;
|
|
541
|
-
failFast?: boolean;
|
|
542
|
-
async?: boolean;
|
|
543
|
-
intercom?: {
|
|
544
|
-
enabled?: boolean;
|
|
545
|
-
delivery?: "off" | "notify" | "result" | "control-and-result";
|
|
546
|
-
parentSession?: string;
|
|
547
|
-
notifyOn?: Array<
|
|
548
|
-
"active_long_running" | "needs_attention" | "completed" | "failed"
|
|
549
|
-
>;
|
|
550
|
-
};
|
|
551
|
-
output?: string | false;
|
|
552
|
-
outputMode?: "inline" | "file-only";
|
|
553
|
-
reads?: readonly string[] | false;
|
|
554
|
-
chainDir?: string;
|
|
555
|
-
maxOutput?: WorkflowMaxOutput;
|
|
556
|
-
artifacts?: boolean;
|
|
557
|
-
worktree?: boolean;
|
|
558
|
-
gitWorktreeDir?: string;
|
|
559
|
-
baseBranch?: string;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// ---------------------------------------------------------------------------
|
|
563
|
-
// Tool parameter schema
|
|
564
|
-
// ---------------------------------------------------------------------------
|
|
565
|
-
|
|
566
|
-
const workflowParameters = WorkflowParametersSchema;
|
|
567
|
-
|
|
568
|
-
function hasDirectExecutionMode(args: WorkflowToolArgs): boolean {
|
|
569
|
-
return (
|
|
570
|
-
(args.task !== undefined && typeof args.task === "object") ||
|
|
571
|
-
Array.isArray(args.tasks) ||
|
|
572
|
-
Array.isArray(args.chain)
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
function directModeCount(args: WorkflowToolArgs): number {
|
|
577
|
-
return [
|
|
578
|
-
args.task !== undefined && typeof args.task === "object",
|
|
579
|
-
Array.isArray(args.tasks),
|
|
580
|
-
Array.isArray(args.chain),
|
|
581
|
-
].filter(Boolean).length;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
function hasNamedExecutionMode(args: WorkflowToolArgs): boolean {
|
|
585
|
-
return typeof args.workflow === "string" && args.workflow.trim().length > 0;
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
function directRequestsFork(args: WorkflowToolArgs): boolean {
|
|
589
|
-
if (args.context === "fork") return true;
|
|
590
|
-
if (
|
|
591
|
-
args.task !== undefined &&
|
|
592
|
-
typeof args.task === "object" &&
|
|
593
|
-
args.task.context === "fork"
|
|
594
|
-
)
|
|
595
|
-
return true;
|
|
596
|
-
if (args.tasks?.some((task) => task.context === "fork")) return true;
|
|
597
|
-
return (
|
|
598
|
-
args.chain?.some((step) =>
|
|
599
|
-
"parallel" in step
|
|
600
|
-
? step.parallel.some((task) => task.context === "fork")
|
|
601
|
-
: step.context === "fork",
|
|
602
|
-
) ?? false
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
function withForkParentSession(
|
|
607
|
-
args: WorkflowToolArgs,
|
|
608
|
-
ctx: PiExecuteContext,
|
|
609
|
-
): WorkflowToolArgs {
|
|
610
|
-
if (!directRequestsFork(args) || args.forkFromSessionFile !== undefined)
|
|
611
|
-
return args;
|
|
612
|
-
const sessionFile = ctx.sessionManager?.getSessionFile?.();
|
|
613
|
-
return typeof sessionFile === "string" && sessionFile.length > 0
|
|
614
|
-
? { ...args, forkFromSessionFile: sessionFile }
|
|
615
|
-
: args;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
function workflowRunResultFromDetails(
|
|
619
|
-
details: WorkflowDetails,
|
|
620
|
-
): WorkflowToolResult {
|
|
621
|
-
return {
|
|
622
|
-
action: "run",
|
|
623
|
-
name: `direct-${details.mode}`,
|
|
624
|
-
runId: details.runId ?? "",
|
|
625
|
-
status: details.status,
|
|
626
|
-
result: details.output,
|
|
627
|
-
details,
|
|
628
|
-
error: details.error,
|
|
629
|
-
stages: [],
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
function stringifyWorkflowToolResult(result: WorkflowToolResult): string {
|
|
634
|
-
return JSON.stringify(result, null, 2);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
function compactWorkflowToolMessage(
|
|
638
|
-
result: Extract<WorkflowToolResult, {
|
|
639
|
-
action: "send" | "pause" | "reload" | "interrupt" | "kill" | "resume";
|
|
640
|
-
}>,
|
|
641
|
-
): string {
|
|
642
|
-
if (result.action === "reload") {
|
|
643
|
-
return `${result.action}: ${result.status} — ${result.message}`;
|
|
644
|
-
}
|
|
645
|
-
const target = [
|
|
646
|
-
result.runId,
|
|
647
|
-
result.action === "send" ? result.stageId : undefined,
|
|
648
|
-
].filter((part): part is string => part !== undefined && part.length > 0)
|
|
649
|
-
.join("/");
|
|
650
|
-
return `${result.action}:${target ? ` ${target}` : ""} ${result.status} — ${result.message}`;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
function renderTranscriptToolContent(
|
|
654
|
-
result: Extract<WorkflowToolResult, { action: "transcript" }>,
|
|
655
|
-
): string {
|
|
656
|
-
const lines = [
|
|
657
|
-
`action: transcript`,
|
|
658
|
-
`runId: ${result.runId}`,
|
|
659
|
-
`stageId: ${result.stageId}`,
|
|
660
|
-
`source: ${result.source}`,
|
|
661
|
-
`truncated: ${result.truncated}`,
|
|
662
|
-
];
|
|
663
|
-
if (result.sessionId) lines.push(`sessionId: ${result.sessionId}`);
|
|
664
|
-
if (result.sessionFile) lines.push(`sessionFile: ${result.sessionFile}`);
|
|
665
|
-
if (result.sessionFile) lines.push(`sessionFileJson: ${JSON.stringify(result.sessionFile)}`);
|
|
666
|
-
if (result.transcriptPath) lines.push(`transcriptPath: ${result.transcriptPath}`);
|
|
667
|
-
if (result.transcriptPath) lines.push(`transcriptPathJson: ${JSON.stringify(result.transcriptPath)}`);
|
|
668
|
-
if (result.entryCount !== undefined) lines.push(`availableEntries: ${result.entryCount}`);
|
|
669
|
-
if (result.entryLimit !== undefined) lines.push(`entryLimit: ${result.entryLimit}`);
|
|
670
|
-
if (result.lazyReadPrompt) lines.push(`lazyReadPrompt: ${result.lazyReadPrompt}`);
|
|
671
|
-
if (result.fallbackNote) lines.push(`fallbackNote: ${result.fallbackNote}`);
|
|
672
|
-
if (result.entries.length === 0) {
|
|
673
|
-
lines.push(result.inlineMode === "path_only" || result.lazyReadPrompt ? "entries: not inlined" : "entries: none");
|
|
674
|
-
return lines.join("\n");
|
|
675
|
-
}
|
|
676
|
-
lines.push("entries:");
|
|
677
|
-
result.entries.forEach((entry, index) => {
|
|
678
|
-
const metadata = [
|
|
679
|
-
`[${index + 1}]`,
|
|
680
|
-
`role=${entry.role}`,
|
|
681
|
-
entry.toolName ? `tool=${entry.toolName}` : undefined,
|
|
682
|
-
entry.timestamp !== undefined ? `timestamp=${entry.timestamp}` : undefined,
|
|
683
|
-
].filter((part): part is string => part !== undefined);
|
|
684
|
-
lines.push(metadata.join(" "));
|
|
685
|
-
if (entry.text !== undefined) lines.push(entry.text);
|
|
686
|
-
if (entry.output !== undefined) {
|
|
687
|
-
lines.push("tool output:");
|
|
688
|
-
lines.push(entry.output);
|
|
689
|
-
}
|
|
690
|
-
if (entry.text === undefined && entry.output === undefined) {
|
|
691
|
-
lines.push("(no body)");
|
|
692
|
-
}
|
|
693
|
-
});
|
|
694
|
-
return lines.join("\n");
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function renderStagesToolContent(
|
|
698
|
-
result: Extract<WorkflowToolResult, { action: "stages" }>,
|
|
699
|
-
): string {
|
|
700
|
-
const lines = [
|
|
701
|
-
"action: stages",
|
|
702
|
-
`runId: ${result.runId}`,
|
|
703
|
-
`filter: ${result.filter}`,
|
|
704
|
-
];
|
|
705
|
-
if (result.error) lines.push(`error: ${result.error}`);
|
|
706
|
-
if (result.stages.length === 0) {
|
|
707
|
-
lines.push("stages: none");
|
|
708
|
-
return lines.join("\n");
|
|
709
|
-
}
|
|
710
|
-
lines.push("stages:");
|
|
711
|
-
result.stages.forEach((stage, index) => {
|
|
712
|
-
lines.push(`[${index + 1}] ${stage.name} (${stage.id}) ${stage.status}`);
|
|
713
|
-
if (stage.sessionId) lines.push(`sessionId: ${stage.sessionId}`);
|
|
714
|
-
if (stage.sessionFile) lines.push(`sessionFile: ${stage.sessionFile}`);
|
|
715
|
-
if (stage.sessionFile) lines.push(`sessionFileJson: ${JSON.stringify(stage.sessionFile)}`);
|
|
716
|
-
if (stage.transcriptPath) lines.push(`transcriptPath: ${stage.transcriptPath}`);
|
|
717
|
-
if (stage.transcriptPath) lines.push(`transcriptPathJson: ${JSON.stringify(stage.transcriptPath)}`);
|
|
718
|
-
if (stage.error) lines.push(`error: ${stage.error}`);
|
|
719
|
-
if (stage.skippedReason) lines.push(`skippedReason: ${stage.skippedReason}`);
|
|
720
|
-
if (stage.awaitingInputSince !== undefined) {
|
|
721
|
-
lines.push(`awaitingInputSince: ${stage.awaitingInputSince}`);
|
|
722
|
-
}
|
|
723
|
-
if (stage.pendingPrompt !== undefined) {
|
|
724
|
-
lines.push("pendingPrompt:");
|
|
725
|
-
lines.push(JSON.stringify(stage.pendingPrompt, null, 2));
|
|
726
|
-
}
|
|
727
|
-
if (stage.inputRequest !== undefined) {
|
|
728
|
-
lines.push("inputRequest:");
|
|
729
|
-
lines.push(JSON.stringify(stage.inputRequest, null, 2));
|
|
730
|
-
}
|
|
731
|
-
if (stage.promptFootprint !== undefined) {
|
|
732
|
-
lines.push("promptFootprint:");
|
|
733
|
-
lines.push(JSON.stringify(stage.promptFootprint, null, 2));
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
return lines.join("\n");
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
function renderStageToolContent(
|
|
740
|
-
result: Extract<WorkflowToolResult, { action: "stage" }>,
|
|
741
|
-
): string {
|
|
742
|
-
const lines = ["action: stage", `runId: ${result.runId}`];
|
|
743
|
-
if (result.error || result.stage === undefined) {
|
|
744
|
-
lines.push(`error: ${result.error ?? "stage not found"}`);
|
|
745
|
-
return lines.join("\n");
|
|
746
|
-
}
|
|
747
|
-
lines.push("stage:");
|
|
748
|
-
lines.push(JSON.stringify(result.stage, null, 2));
|
|
749
|
-
if (result.stage.sessionFile) {
|
|
750
|
-
lines.push(`transcriptPath: ${result.stage.sessionFile}`);
|
|
751
|
-
lines.push(`transcriptPathJson: ${JSON.stringify(result.stage.sessionFile)}`);
|
|
752
|
-
}
|
|
753
|
-
return lines.join("\n");
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
function renderWorkflowToolContent(
|
|
757
|
-
result: WorkflowToolResult,
|
|
758
|
-
args: WorkflowToolArgs,
|
|
759
|
-
): string {
|
|
760
|
-
if (args.format === "json") return stringifyWorkflowToolResult(result);
|
|
761
|
-
|
|
762
|
-
switch (result.action) {
|
|
763
|
-
case "transcript":
|
|
764
|
-
return renderTranscriptToolContent(result);
|
|
765
|
-
case "stages":
|
|
766
|
-
return renderStagesToolContent(result);
|
|
767
|
-
case "stage":
|
|
768
|
-
return renderStageToolContent(result);
|
|
769
|
-
case "send":
|
|
770
|
-
case "pause":
|
|
771
|
-
case "reload":
|
|
772
|
-
case "interrupt":
|
|
773
|
-
case "kill":
|
|
774
|
-
case "resume":
|
|
775
|
-
return compactWorkflowToolMessage(result);
|
|
776
|
-
case "list":
|
|
777
|
-
case "status":
|
|
778
|
-
case "statusDetail":
|
|
779
|
-
case "inputs":
|
|
780
|
-
case "get":
|
|
781
|
-
case "run":
|
|
782
|
-
return stringifyWorkflowToolResult(result);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function workflowGetResult(
|
|
787
|
-
runtime: ExtensionRuntime,
|
|
788
|
-
args: WorkflowToolArgs,
|
|
789
|
-
): WorkflowToolResult {
|
|
790
|
-
const workflow = args.workflow ?? "";
|
|
791
|
-
const def = runtime.registry.get(workflow);
|
|
792
|
-
if (!def) {
|
|
793
|
-
return {
|
|
794
|
-
action: "get",
|
|
795
|
-
workflow,
|
|
796
|
-
error: `Workflow not found: "${workflow}"`,
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
const inputs = deriveInputFields(def.inputs);
|
|
800
|
-
return {
|
|
801
|
-
action: "get",
|
|
802
|
-
workflow: def.normalizedName,
|
|
803
|
-
details: {
|
|
804
|
-
mode: "inspection",
|
|
805
|
-
action: "get",
|
|
806
|
-
status: "completed",
|
|
807
|
-
output: {
|
|
808
|
-
workflow: def.normalizedName,
|
|
809
|
-
name: def.name,
|
|
810
|
-
description: def.description,
|
|
811
|
-
inputs: inputs as unknown as WorkflowSerializableValue[],
|
|
812
|
-
},
|
|
813
|
-
progress: { completed: 0, total: 0 },
|
|
814
|
-
},
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
// ---------------------------------------------------------------------------
|
|
819
|
-
// Stage tool helpers
|
|
820
|
-
// ---------------------------------------------------------------------------
|
|
821
|
-
|
|
822
|
-
type WorkflowStageSummary = {
|
|
823
|
-
id: string;
|
|
824
|
-
name: string;
|
|
825
|
-
status: StageStatus;
|
|
826
|
-
sessionId?: string;
|
|
827
|
-
sessionFile?: string;
|
|
828
|
-
transcriptPath?: string;
|
|
829
|
-
error?: string;
|
|
830
|
-
skippedReason?: string;
|
|
831
|
-
awaitingInputSince?: number;
|
|
832
|
-
pendingPrompt?: StageSnapshot["pendingPrompt"];
|
|
833
|
-
inputRequest?: StageSnapshot["inputRequest"];
|
|
834
|
-
promptFootprint?: StageSnapshot["promptFootprint"];
|
|
835
|
-
};
|
|
836
|
-
|
|
837
|
-
type WorkflowTranscriptEntry = {
|
|
838
|
-
role: string;
|
|
839
|
-
text?: string;
|
|
840
|
-
toolName?: string;
|
|
841
|
-
output?: string;
|
|
842
|
-
timestamp?: number;
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
type MessageContentBlock = { readonly type?: string; readonly text?: string };
|
|
846
|
-
type MessageLike = {
|
|
847
|
-
readonly role?: string;
|
|
848
|
-
readonly content?: string | readonly MessageContentBlock[];
|
|
849
|
-
readonly name?: string;
|
|
850
|
-
readonly toolName?: string;
|
|
851
|
-
readonly timestamp?: number;
|
|
852
|
-
readonly createdAt?: number;
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
function cloneStage(stage: StageSnapshot): StageSnapshot & { transcriptPath?: string } {
|
|
856
|
-
const cloned = structuredClone(stage) as StageSnapshot & { transcriptPath?: string };
|
|
857
|
-
if (cloned.sessionFile !== undefined) cloned.transcriptPath = cloned.sessionFile;
|
|
858
|
-
return cloned;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
function summarizeStage(stage: StageSnapshot): WorkflowStageSummary {
|
|
862
|
-
return {
|
|
863
|
-
id: stage.id,
|
|
864
|
-
name: stage.name,
|
|
865
|
-
status: stage.status,
|
|
866
|
-
sessionId: stage.sessionId,
|
|
867
|
-
sessionFile: stage.sessionFile,
|
|
868
|
-
transcriptPath: stage.sessionFile,
|
|
869
|
-
error: stage.error,
|
|
870
|
-
skippedReason: stage.skippedReason,
|
|
871
|
-
awaitingInputSince: stage.awaitingInputSince,
|
|
872
|
-
pendingPrompt: stage.pendingPrompt === undefined
|
|
873
|
-
? undefined
|
|
874
|
-
: structuredClone(stage.pendingPrompt),
|
|
875
|
-
inputRequest: stage.inputRequest === undefined
|
|
876
|
-
? undefined
|
|
877
|
-
: structuredClone(stage.inputRequest),
|
|
878
|
-
promptFootprint: stage.promptFootprint === undefined
|
|
879
|
-
? undefined
|
|
880
|
-
: structuredClone(stage.promptFootprint),
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
const DEFAULT_TRANSCRIPT_LIMIT = 5;
|
|
885
|
-
|
|
886
|
-
type TranscriptEntrySelection = {
|
|
887
|
-
entries: WorkflowTranscriptEntry[];
|
|
888
|
-
truncated: boolean;
|
|
889
|
-
entryCount: number;
|
|
890
|
-
entryLimit?: number;
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
type WorkflowTranscriptResult = Extract<WorkflowToolResult, { action: "transcript" }>;
|
|
894
|
-
|
|
895
|
-
function isTranscriptPreviewExplicit(args: WorkflowToolArgs): boolean {
|
|
896
|
-
return args.tail !== undefined || args.limit !== undefined;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
function requestedTranscriptEntryLimit(args: WorkflowToolArgs): number {
|
|
900
|
-
const raw = args.tail ?? args.limit;
|
|
901
|
-
if (raw === undefined) return DEFAULT_TRANSCRIPT_LIMIT;
|
|
902
|
-
if (!Number.isFinite(raw) || raw <= 0) return 0;
|
|
903
|
-
return Math.floor(raw);
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
function selectTranscriptEntries(
|
|
907
|
-
entries: readonly WorkflowTranscriptEntry[],
|
|
908
|
-
args: WorkflowToolArgs,
|
|
909
|
-
): TranscriptEntrySelection {
|
|
910
|
-
const count = requestedTranscriptEntryLimit(args);
|
|
911
|
-
const entryCount = entries.length;
|
|
912
|
-
if (count === 0) {
|
|
913
|
-
return {
|
|
914
|
-
entries: [],
|
|
915
|
-
truncated: false,
|
|
916
|
-
entryCount,
|
|
917
|
-
entryLimit: count,
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
if (entries.length <= count) {
|
|
921
|
-
return {
|
|
922
|
-
entries: [...entries],
|
|
923
|
-
truncated: false,
|
|
924
|
-
entryCount,
|
|
925
|
-
entryLimit: count,
|
|
926
|
-
};
|
|
927
|
-
}
|
|
928
|
-
return {
|
|
929
|
-
entries: entries.slice(entries.length - count),
|
|
930
|
-
truncated: true,
|
|
931
|
-
entryCount,
|
|
932
|
-
entryLimit: count,
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
function transcriptLazyReadPrompt(path: string): string {
|
|
937
|
-
return `Transcript not inlined to protect context. Read it lazily from ${path} with your file read tools (read small ranges; rg/grep for targeted lookups).`;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
function transcriptFallbackNote(limit: number): string {
|
|
941
|
-
return `No transcript file path is available for this stage; falling back to a bounded inline preview of up to ${limit} recent ${limit === 1 ? "entry" : "entries"}.`;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
/**
|
|
945
|
-
* Shape a transcript tool result, keeping the context-safe path-only default
|
|
946
|
-
* the cheap hot path for the large runs #1314 protects against.
|
|
947
|
-
*
|
|
948
|
-
* `buildEntries` is a thunk so the default case (a transcript file path exists
|
|
949
|
-
* and no explicit `tail`/`limit` was requested) never materializes entry bodies
|
|
950
|
-
* just to discard them. Only the caller-provided `entryCount` is needed for the
|
|
951
|
-
* advisory count, which matches what `buildEntries()` would yield. The thunk is
|
|
952
|
-
* invoked solely for the explicit-preview and no-path fallback branches.
|
|
953
|
-
*/
|
|
954
|
-
function shapeTranscriptResult(input: {
|
|
955
|
-
runId: string;
|
|
956
|
-
stageId: string;
|
|
957
|
-
source: "live" | "snapshot";
|
|
958
|
-
entryCount: number;
|
|
959
|
-
buildEntries: () => readonly WorkflowTranscriptEntry[];
|
|
960
|
-
args: WorkflowToolArgs;
|
|
961
|
-
sessionId?: string | undefined;
|
|
962
|
-
sessionFile?: string | undefined;
|
|
963
|
-
transcriptPath?: string | undefined;
|
|
964
|
-
}): WorkflowTranscriptResult {
|
|
965
|
-
// `transcriptPath` already falls back to `sessionFile`, so it is the single
|
|
966
|
-
// resolved path the agent should lazily read.
|
|
967
|
-
const transcriptPath = input.transcriptPath ?? input.sessionFile;
|
|
968
|
-
if (transcriptPath !== undefined && !isTranscriptPreviewExplicit(input.args)) {
|
|
969
|
-
const result: WorkflowTranscriptResult = {
|
|
970
|
-
action: "transcript",
|
|
971
|
-
runId: input.runId,
|
|
972
|
-
stageId: input.stageId,
|
|
973
|
-
source: input.source,
|
|
974
|
-
entries: [],
|
|
975
|
-
// `truncated` here means "more transcript exists on disk than was inlined"
|
|
976
|
-
// (everything, since the default inlines nothing), not "an explicit limit
|
|
977
|
-
// clipped results". It only drives the cosmetic "(truncated)" notice
|
|
978
|
-
// suffix; no consumer re-fetches on it.
|
|
979
|
-
truncated: input.entryCount > 0,
|
|
980
|
-
entryCount: input.entryCount,
|
|
981
|
-
entryLimit: 0,
|
|
982
|
-
lazyReadPrompt: transcriptLazyReadPrompt(transcriptPath),
|
|
983
|
-
inlineMode: "path_only",
|
|
984
|
-
};
|
|
985
|
-
if (input.sessionId !== undefined) result.sessionId = input.sessionId;
|
|
986
|
-
if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
|
|
987
|
-
result.transcriptPath = transcriptPath;
|
|
988
|
-
return result;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
const limited = selectTranscriptEntries(input.buildEntries(), input.args);
|
|
992
|
-
const result: WorkflowTranscriptResult = {
|
|
993
|
-
action: "transcript",
|
|
994
|
-
runId: input.runId,
|
|
995
|
-
stageId: input.stageId,
|
|
996
|
-
source: input.source,
|
|
997
|
-
entries: limited.entries,
|
|
998
|
-
truncated: limited.truncated,
|
|
999
|
-
entryCount: limited.entryCount,
|
|
1000
|
-
entryLimit: limited.entryLimit,
|
|
1001
|
-
inlineMode: transcriptPath === undefined ? "fallback_preview" : "preview",
|
|
1002
|
-
};
|
|
1003
|
-
if (input.sessionId !== undefined) result.sessionId = input.sessionId;
|
|
1004
|
-
if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
|
|
1005
|
-
if (transcriptPath !== undefined) result.transcriptPath = transcriptPath;
|
|
1006
|
-
if (transcriptPath === undefined) result.fallbackNote = transcriptFallbackNote(limited.entryLimit ?? DEFAULT_TRANSCRIPT_LIMIT);
|
|
1007
|
-
return result;
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
function messageText(content: MessageLike["content"]): string | undefined {
|
|
1011
|
-
if (typeof content === "string") return content;
|
|
1012
|
-
if (!Array.isArray(content)) return undefined;
|
|
1013
|
-
let sawTextBlock = false;
|
|
1014
|
-
const text = content
|
|
1015
|
-
.map((block) => {
|
|
1016
|
-
if (block.type === "text" && typeof block.text === "string") {
|
|
1017
|
-
sawTextBlock = true;
|
|
1018
|
-
return block.text;
|
|
1019
|
-
}
|
|
1020
|
-
return "";
|
|
1021
|
-
})
|
|
1022
|
-
.join("");
|
|
1023
|
-
return sawTextBlock ? text : undefined;
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
function transcriptEntryFromMessage(message: MessageLike): WorkflowTranscriptEntry {
|
|
1027
|
-
const entry: WorkflowTranscriptEntry = { role: message.role ?? "unknown" };
|
|
1028
|
-
const text = messageText(message.content);
|
|
1029
|
-
if (text !== undefined) entry.text = text;
|
|
1030
|
-
const toolName = message.toolName ?? message.name;
|
|
1031
|
-
if (toolName !== undefined) entry.toolName = toolName;
|
|
1032
|
-
const timestamp = message.timestamp ?? message.createdAt;
|
|
1033
|
-
if (timestamp !== undefined) entry.timestamp = timestamp;
|
|
1034
|
-
return entry;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
function transcriptEntriesFromToolEvents(
|
|
1038
|
-
events: readonly ToolEvent[],
|
|
1039
|
-
includeOutput: boolean,
|
|
1040
|
-
): WorkflowTranscriptEntry[] {
|
|
1041
|
-
return events.map((event) => ({
|
|
1042
|
-
role: "tool",
|
|
1043
|
-
toolName: event.name,
|
|
1044
|
-
output: includeOutput ? event.output : undefined,
|
|
1045
|
-
timestamp: event.endedAt ?? event.startedAt,
|
|
1046
|
-
}));
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
function hasPayloadProperty(args: WorkflowToolArgs): boolean {
|
|
1050
|
-
return (
|
|
1051
|
-
args.text !== undefined ||
|
|
1052
|
-
args.response !== undefined ||
|
|
1053
|
-
args.message !== undefined
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
function promptPayloadFromArgs(args: WorkflowToolArgs): unknown {
|
|
1058
|
-
if (args.response !== undefined) return args.response;
|
|
1059
|
-
if (args.text !== undefined) return args.text;
|
|
1060
|
-
return args.message;
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
/**
|
|
1064
|
-
* Shape a `send` payload into a headless answer for a brokered stage prompt
|
|
1065
|
-
* (ask_user_question / readiness gate). A structured `response` (object or
|
|
1066
|
-
* JSON string) is normalized so it matches the question's options instead of
|
|
1067
|
-
* being forwarded verbatim as a result that violates the QuestionnaireResult
|
|
1068
|
-
* contract; otherwise the plain text / message payload is matched against
|
|
1069
|
-
* option labels / indices by the stage prompt adapter.
|
|
1070
|
-
*/
|
|
1071
|
-
function brokerAnswerFromArgs(args: WorkflowToolArgs): StageInputAnswer {
|
|
1072
|
-
if (args.response !== undefined) {
|
|
1073
|
-
const coerced = coerceStageInputAnswer(args.response);
|
|
1074
|
-
if (hasStageInputAnswerContent(coerced)) return coerced;
|
|
1075
|
-
}
|
|
1076
|
-
const text = textPayloadFromArgs(args);
|
|
1077
|
-
return text !== undefined ? { text } : {};
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
function textPayloadFromArgs(args: WorkflowToolArgs): string | undefined {
|
|
1081
|
-
if (args.text !== undefined) return args.text;
|
|
1082
|
-
if (typeof args.response === "string") {
|
|
1083
|
-
return args.response;
|
|
1084
|
-
}
|
|
1085
|
-
if (args.message !== undefined) return args.message;
|
|
1086
|
-
return undefined;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
type WorkflowSendToolResult = Extract<WorkflowToolResult, { action: "send" }>;
|
|
1090
|
-
|
|
1091
|
-
function workflowSendResult(
|
|
1092
|
-
runId: string,
|
|
1093
|
-
stageId: string,
|
|
1094
|
-
delivery: WorkflowSendToolResult["delivery"],
|
|
1095
|
-
status: WorkflowSendToolResult["status"],
|
|
1096
|
-
message: string,
|
|
1097
|
-
): WorkflowSendToolResult {
|
|
1098
|
-
return { action: "send", runId, stageId, delivery, status, message };
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
function sortTranscriptEntriesChronologically(
|
|
1102
|
-
entries: readonly WorkflowTranscriptEntry[],
|
|
1103
|
-
): WorkflowTranscriptEntry[] {
|
|
1104
|
-
return entries
|
|
1105
|
-
.map((entry, index) => ({ entry, index }))
|
|
1106
|
-
.sort((a, b) => {
|
|
1107
|
-
const aTimestamp = a.entry.timestamp;
|
|
1108
|
-
const bTimestamp = b.entry.timestamp;
|
|
1109
|
-
if (
|
|
1110
|
-
typeof aTimestamp === "number" &&
|
|
1111
|
-
typeof bTimestamp === "number" &&
|
|
1112
|
-
aTimestamp !== bTimestamp
|
|
1113
|
-
) {
|
|
1114
|
-
return aTimestamp - bTimestamp;
|
|
1115
|
-
}
|
|
1116
|
-
return a.index - b.index;
|
|
1117
|
-
})
|
|
1118
|
-
.map(({ entry }) => entry);
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
function terminalTranscriptEntry(
|
|
1122
|
-
role: "assistant" | "notice",
|
|
1123
|
-
text: string,
|
|
1124
|
-
endedAt: number | undefined,
|
|
1125
|
-
): WorkflowTranscriptEntry {
|
|
1126
|
-
const entry: WorkflowTranscriptEntry = { role, text };
|
|
1127
|
-
if (endedAt !== undefined) entry.timestamp = endedAt;
|
|
1128
|
-
return entry;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
function snapshotTranscriptEntries(
|
|
1132
|
-
snapshot: StageSnapshot | undefined,
|
|
1133
|
-
includeOutput: boolean,
|
|
1134
|
-
): WorkflowTranscriptEntry[] {
|
|
1135
|
-
if (snapshot === undefined) return [];
|
|
1136
|
-
const entries: WorkflowTranscriptEntry[] = [
|
|
1137
|
-
...transcriptEntriesFromToolEvents(snapshot.toolEvents ?? [], includeOutput),
|
|
1138
|
-
];
|
|
1139
|
-
if (snapshot.result !== undefined) {
|
|
1140
|
-
entries.push(terminalTranscriptEntry("assistant", snapshot.result, snapshot.endedAt));
|
|
1141
|
-
}
|
|
1142
|
-
if (snapshot.error !== undefined) {
|
|
1143
|
-
entries.push(terminalTranscriptEntry("notice", snapshot.error, snapshot.endedAt));
|
|
1144
|
-
}
|
|
1145
|
-
return sortTranscriptEntriesChronologically(entries);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
function formatAlreadyEndedRetainedMessage(runId: string): string {
|
|
1149
|
-
return `Run ${runId.slice(0, 8)} already ended; retained for inspection.`;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
function stageFailureMessage(
|
|
1153
|
-
runId: string,
|
|
1154
|
-
resultReason: string,
|
|
1155
|
-
action: "pause" | "interrupt",
|
|
1156
|
-
): string {
|
|
1157
|
-
switch (resultReason) {
|
|
1158
|
-
case "not_found":
|
|
1159
|
-
return `Run not found: ${runId}`;
|
|
1160
|
-
case "already_ended":
|
|
1161
|
-
return `Run already ended: ${runId}`;
|
|
1162
|
-
case "stage_not_found":
|
|
1163
|
-
return `Stage not found for run: ${runId}`;
|
|
1164
|
-
default:
|
|
1165
|
-
return `No active stages to ${action} for run: ${runId}`;
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
function inFlightRunCount(): number {
|
|
1170
|
-
return topLevelWorkflowRuns(store.runs()).filter((run) => run.endedAt === undefined).length;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
function topLevelExpandedSnapshots() {
|
|
1174
|
-
const snapshot = store.snapshot();
|
|
1175
|
-
return topLevelWorkflowRuns(snapshot.runs).map((run) => ({
|
|
1176
|
-
...structuredClone(run),
|
|
1177
|
-
stages: expandWorkflowGraph(snapshot, run.id).stages.map((stage) => structuredClone(stage)),
|
|
1178
|
-
}));
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
function reloadBlockedMessage(count = inFlightRunCount()): string {
|
|
1182
|
-
return `Reload skipped: ${count} workflow run(s) still in flight. Wait for them to finish, or pause/kill them before reloading workflow resources.`;
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
function allStageConflictMessage(action: "pause" | "interrupt" | "kill"): string {
|
|
1186
|
-
return `Cannot ${action} --all with a stageId; omit stageId or target a single run.`;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
class WorkflowReloadBlockedError extends Error {
|
|
1190
|
-
constructor(message: string) {
|
|
1191
|
-
super(message);
|
|
1192
|
-
this.name = "WorkflowReloadBlockedError";
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
function reloadFailureMessage(error: unknown): string {
|
|
1197
|
-
if (error instanceof WorkflowReloadBlockedError) return error.message;
|
|
1198
|
-
return `Reload failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
function hasWorkflowStageSubagentGuardEnv(): boolean {
|
|
1202
|
-
return getEnvValue(WORKFLOW_STAGE_SUBAGENT_GUARD_ENV) === "1";
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
function isWorkflowStageToolContext(ctx: PiExecuteContext): boolean {
|
|
1206
|
-
return hasWorkflowStageSubagentGuardEnv() || ctx.orchestrationContext?.kind === "workflow-stage";
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
/**
|
|
1210
|
-
* Legacy message retained for consumers that imported the old refusal string.
|
|
1211
|
-
* Non-interactive sessions now keep the workflow tool and `/workflow` command
|
|
1212
|
-
* available; policy gates interactive pickers and runtime human-input APIs.
|
|
1213
|
-
*/
|
|
1214
|
-
export const WORKFLOW_NON_INTERACTIVE_MESSAGE =
|
|
1215
|
-
"Workflows are policy-gated in non-interactive (-p) mode; deterministic workflows can run headlessly while runtime human input remains unavailable.";
|
|
1216
|
-
|
|
1217
|
-
export function workflowPolicyFromContext(ctx?: { readonly hasUI?: boolean }): WorkflowExecutionPolicy {
|
|
1218
|
-
if (ctx?.hasUI === false) {
|
|
1219
|
-
return NON_INTERACTIVE_WORKFLOW_POLICY;
|
|
1220
|
-
}
|
|
1221
|
-
return INTERACTIVE_WORKFLOW_POLICY;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
function isRunStatus(value: string): value is RunStatus {
|
|
1225
|
-
switch (value) {
|
|
1226
|
-
case "pending":
|
|
1227
|
-
case "running":
|
|
1228
|
-
case "paused":
|
|
1229
|
-
case "completed":
|
|
1230
|
-
case "skipped":
|
|
1231
|
-
case "cancelled":
|
|
1232
|
-
case "blocked":
|
|
1233
|
-
case "failed":
|
|
1234
|
-
case "killed":
|
|
1235
|
-
return true;
|
|
1236
|
-
default:
|
|
1237
|
-
return false;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
function fallbackRunDetailFromResult(
|
|
1242
|
-
workflowName: string,
|
|
1243
|
-
inputs: Readonly<WorkflowInputValues>,
|
|
1244
|
-
result: Extract<WorkflowToolResult, { action: "run"; runId: string }>,
|
|
1245
|
-
): RunDetail {
|
|
1246
|
-
const now = Date.now();
|
|
1247
|
-
const stages = result.stages?.map((stage) => structuredClone(stage)) ?? [];
|
|
1248
|
-
// This path is a degraded last-resort view used only when the retained run
|
|
1249
|
-
// snapshot has disappeared before output rendering. Timestamps are synthetic,
|
|
1250
|
-
// so prefer a conservative failed status over fabricating success if the tool
|
|
1251
|
-
// result status is not one of the known run states.
|
|
1252
|
-
return {
|
|
1253
|
-
runId: result.runId,
|
|
1254
|
-
name: result.name ?? workflowName,
|
|
1255
|
-
status: isRunStatus(result.status) ? result.status : "failed",
|
|
1256
|
-
mode: stages.length > 1 ? "chain" : "single",
|
|
1257
|
-
startedAt: now,
|
|
1258
|
-
endedAt: now,
|
|
1259
|
-
durationMs: 0,
|
|
1260
|
-
inputs,
|
|
1261
|
-
stages,
|
|
1262
|
-
result: result.result,
|
|
1263
|
-
error: result.error,
|
|
1264
|
-
exited: result.exited,
|
|
1265
|
-
exitReason: result.exitReason,
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
function emitTerminalRunDetailSurface(
|
|
1270
|
-
pi: ExtensionAPI,
|
|
1271
|
-
workflowName: string,
|
|
1272
|
-
inputs: Readonly<WorkflowInputValues>,
|
|
1273
|
-
result: Extract<WorkflowToolResult, { action: "run"; runId: string }>,
|
|
1274
|
-
): void {
|
|
1275
|
-
const inspected = inspectRun(result.runId);
|
|
1276
|
-
const detail = inspected.ok
|
|
1277
|
-
? inspected.detail
|
|
1278
|
-
: fallbackRunDetailFromResult(workflowName, inputs, result);
|
|
1279
|
-
emitChatSurface(
|
|
1280
|
-
pi,
|
|
1281
|
-
{ kind: "detail", detail },
|
|
1282
|
-
{ content: renderRunDetail(detail, { width: 100 }) },
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
export const WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE = "workflows:command-output";
|
|
1287
|
-
|
|
1288
|
-
interface WorkflowCommandOutputDetails {
|
|
1289
|
-
readonly command: string;
|
|
1290
|
-
readonly workflowName?: string;
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
function emitWorkflowCommandOutput(
|
|
1294
|
-
pi: ExtensionAPI,
|
|
1295
|
-
content: string,
|
|
1296
|
-
details: WorkflowCommandOutputDetails,
|
|
1297
|
-
): void {
|
|
1298
|
-
if (typeof pi.sendMessage !== "function") return;
|
|
1299
|
-
void pi.sendMessage<WorkflowCommandOutputDetails>({
|
|
1300
|
-
customType: WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE,
|
|
1301
|
-
content,
|
|
1302
|
-
display: true,
|
|
1303
|
-
details,
|
|
1304
|
-
});
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
interface WorkflowCommandReporter {
|
|
1308
|
-
info(message: string): void;
|
|
1309
|
-
error(message: string): void;
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
function formatAvailableWorkflowNames(names: readonly string[]): string {
|
|
1313
|
-
return names.length > 0 ? names.join(", ") : "(none)";
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
|
|
1317
|
-
|
|
1318
|
-
function deAdvertiseAskUserQuestionWhenHeadless(
|
|
1319
|
-
pi: ExtensionAPI,
|
|
1320
|
-
hasUI: boolean | undefined,
|
|
1321
|
-
): void {
|
|
1322
|
-
if (hasUI !== false) return;
|
|
1323
|
-
if (typeof pi.getActiveTools !== "function" || typeof pi.setActiveTools !== "function") return;
|
|
1324
|
-
|
|
1325
|
-
const activeTools = pi.getActiveTools();
|
|
1326
|
-
if (!activeTools.includes(ASK_USER_QUESTION_TOOL_NAME)) return;
|
|
1327
|
-
|
|
1328
|
-
pi.setActiveTools(activeTools.filter((toolName) => toolName !== ASK_USER_QUESTION_TOOL_NAME));
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
class WorkflowHeadlessCommandError extends Error {
|
|
1332
|
-
constructor(message: string) {
|
|
1333
|
-
super(message);
|
|
1334
|
-
this.name = "WorkflowHeadlessCommandError";
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
function createWorkflowCommandReporter(
|
|
1339
|
-
ctx: PiCommandContext,
|
|
1340
|
-
policy: WorkflowExecutionPolicy = workflowPolicyFromContext(ctx),
|
|
1341
|
-
pi?: ExtensionAPI,
|
|
1342
|
-
): WorkflowCommandReporter {
|
|
1343
|
-
return {
|
|
1344
|
-
info(message: string): void {
|
|
1345
|
-
if (policy.mode === "non_interactive") {
|
|
1346
|
-
if (pi) {
|
|
1347
|
-
emitWorkflowCommandOutput(pi, message, { command: "message" });
|
|
1348
|
-
}
|
|
1349
|
-
return;
|
|
1350
|
-
}
|
|
1351
|
-
ctx.ui.notify(message, "info");
|
|
1352
|
-
},
|
|
1353
|
-
error(message: string): void {
|
|
1354
|
-
if (policy.mode === "non_interactive") {
|
|
1355
|
-
throw new WorkflowHeadlessCommandError(message);
|
|
1356
|
-
}
|
|
1357
|
-
ctx.ui.notify(message, "error");
|
|
1358
|
-
},
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// ---------------------------------------------------------------------------
|
|
1363
|
-
// Tool execute — dispatch with real registry for list/inputs/run (Phase E)
|
|
1364
|
-
// + real status/interrupt/resume (Phase D)
|
|
1365
|
-
// ---------------------------------------------------------------------------
|
|
1366
|
-
|
|
1367
|
-
export function makeExecuteWorkflowTool(
|
|
1368
|
-
runtime: ExtensionRuntime | ((ctx: PiExecuteContext) => ExtensionRuntime),
|
|
1369
|
-
getPersistence: () => WorkflowPersistencePort | undefined,
|
|
1370
|
-
reloadWorkflowResources: () => Promise<void> | void,
|
|
1371
|
-
) {
|
|
1372
|
-
return async function executeWorkflowTool(
|
|
1373
|
-
args: WorkflowToolArgs,
|
|
1374
|
-
ctx: PiExecuteContext,
|
|
1375
|
-
): Promise<WorkflowToolResult> {
|
|
1376
|
-
const action = args.action ?? "run";
|
|
1377
|
-
const runId = args.runId ?? "";
|
|
1378
|
-
if (isWorkflowStageToolContext(ctx)) {
|
|
1379
|
-
// Workflow stages must not invoke the workflow tool at all, including
|
|
1380
|
-
// read-only inspection actions. The tool is normally excluded from stage
|
|
1381
|
-
// sessions; this guard is a defense-in-depth fallback for stale or
|
|
1382
|
-
// hand-crafted registrations.
|
|
1383
|
-
return {
|
|
1384
|
-
action: "run",
|
|
1385
|
-
runId,
|
|
1386
|
-
status: "failed",
|
|
1387
|
-
error: "workflows cannot invoke workflows from workflow stages",
|
|
1388
|
-
stages: [],
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
const activeRuntime =
|
|
1392
|
-
typeof runtime === "function" ? runtime(ctx) : runtime;
|
|
1393
|
-
const policy = workflowPolicyFromContext(ctx);
|
|
1394
|
-
|
|
1395
|
-
switch (action) {
|
|
1396
|
-
case "get":
|
|
1397
|
-
return workflowGetResult(activeRuntime, args);
|
|
1398
|
-
|
|
1399
|
-
case "list":
|
|
1400
|
-
case "inputs":
|
|
1401
|
-
case "run":
|
|
1402
|
-
if (action === "run" && hasDirectExecutionMode(args)) {
|
|
1403
|
-
const normalModeCount =
|
|
1404
|
-
directModeCount(args) + (hasNamedExecutionMode(args) ? 1 : 0);
|
|
1405
|
-
if (normalModeCount !== 1) {
|
|
1406
|
-
throw new Error(
|
|
1407
|
-
"Workflow extension: specify exactly one normal execution mode: workflow, task, tasks, or chain",
|
|
1408
|
-
);
|
|
1409
|
-
}
|
|
1410
|
-
const details = await activeRuntime.runDirect(
|
|
1411
|
-
withForkParentSession(args, ctx),
|
|
1412
|
-
{ policy },
|
|
1413
|
-
);
|
|
1414
|
-
return workflowRunResultFromDetails(details);
|
|
1415
|
-
}
|
|
1416
|
-
// Delegate to registry-backed dispatcher.
|
|
1417
|
-
// Real errors propagate — no broad catch.
|
|
1418
|
-
return activeRuntime.dispatch(args, { policy });
|
|
1419
|
-
|
|
1420
|
-
case "status": {
|
|
1421
|
-
// Detail mode — single-run lookup via id.
|
|
1422
|
-
const target = args.runId;
|
|
1423
|
-
if (target !== undefined) {
|
|
1424
|
-
const result = inspectRun(target);
|
|
1425
|
-
if (result.ok) {
|
|
1426
|
-
return {
|
|
1427
|
-
action: "statusDetail",
|
|
1428
|
-
runId: result.runId,
|
|
1429
|
-
detail: result.detail,
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
return {
|
|
1433
|
-
action: "statusDetail",
|
|
1434
|
-
runId: target,
|
|
1435
|
-
error: `run not found: ${target}`,
|
|
1436
|
-
};
|
|
1437
|
-
}
|
|
1438
|
-
// List mode — emit all retained snapshots; the renderer produces the
|
|
1439
|
-
// canonical band + card surface.
|
|
1440
|
-
return {
|
|
1441
|
-
action: "status",
|
|
1442
|
-
snapshots: topLevelExpandedSnapshots(),
|
|
1443
|
-
};
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
case "stages": {
|
|
1447
|
-
const target = resolveToolRunTarget(args, "No active run to inspect.");
|
|
1448
|
-
const filter = args.statusFilter ?? "all";
|
|
1449
|
-
if (target.kind === "all") {
|
|
1450
|
-
return {
|
|
1451
|
-
action: "stages",
|
|
1452
|
-
runId: "--all",
|
|
1453
|
-
filter,
|
|
1454
|
-
stages: [],
|
|
1455
|
-
error: "Stage listing requires a single run.",
|
|
1456
|
-
};
|
|
1457
|
-
}
|
|
1458
|
-
if (target.kind === "ambiguous") {
|
|
1459
|
-
return {
|
|
1460
|
-
action: "stages",
|
|
1461
|
-
runId: target.target,
|
|
1462
|
-
filter,
|
|
1463
|
-
stages: [],
|
|
1464
|
-
error: ambiguousRunMessage(target.target, target.matches),
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
if (target.kind === "not_found") {
|
|
1468
|
-
return {
|
|
1469
|
-
action: "stages",
|
|
1470
|
-
runId: target.target,
|
|
1471
|
-
filter,
|
|
1472
|
-
stages: [],
|
|
1473
|
-
error: target.message,
|
|
1474
|
-
};
|
|
1475
|
-
}
|
|
1476
|
-
const run = store.runs().find((r) => r.id === target.runId);
|
|
1477
|
-
const stages = (run?.stages ?? [])
|
|
1478
|
-
.filter((stage) => filter === "all" || stage.status === filter)
|
|
1479
|
-
.map(summarizeStage);
|
|
1480
|
-
return { action: "stages", runId: target.runId, filter, stages };
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
case "stage": {
|
|
1484
|
-
const target = resolveToolRunTarget(args, "No active run to inspect.");
|
|
1485
|
-
if (target.kind === "all") {
|
|
1486
|
-
return {
|
|
1487
|
-
action: "stage",
|
|
1488
|
-
runId: "--all",
|
|
1489
|
-
error: "Stage inspection requires a single run.",
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
if (target.kind === "ambiguous") {
|
|
1493
|
-
return {
|
|
1494
|
-
action: "stage",
|
|
1495
|
-
runId: target.target,
|
|
1496
|
-
error: ambiguousRunMessage(target.target, target.matches),
|
|
1497
|
-
};
|
|
1498
|
-
}
|
|
1499
|
-
if (target.kind === "not_found") {
|
|
1500
|
-
return {
|
|
1501
|
-
action: "stage",
|
|
1502
|
-
runId: target.target,
|
|
1503
|
-
error: target.message,
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1507
|
-
if (!stage.ok || stage.stageId === undefined) {
|
|
1508
|
-
return {
|
|
1509
|
-
action: "stage",
|
|
1510
|
-
runId: target.runId,
|
|
1511
|
-
error: stage.ok
|
|
1512
|
-
? "Stage id, prefix, or name is required."
|
|
1513
|
-
: stage.message,
|
|
1514
|
-
};
|
|
1515
|
-
}
|
|
1516
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1517
|
-
const run = store.runs().find((r) => r.id === stageRunId);
|
|
1518
|
-
const snapshot = run?.stages.find((s) => s.id === stage.stageId);
|
|
1519
|
-
return snapshot
|
|
1520
|
-
? { action: "stage", runId: stageRunId, stage: cloneStage(snapshot) }
|
|
1521
|
-
: {
|
|
1522
|
-
action: "stage",
|
|
1523
|
-
runId: stageRunId,
|
|
1524
|
-
error: `Stage not found in run ${stageRunId.slice(0, 8)}: ${stage.stageId}`,
|
|
1525
|
-
};
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
case "transcript": {
|
|
1529
|
-
const target = resolveToolRunTarget(args, "No active run to inspect.");
|
|
1530
|
-
if (target.kind === "all") {
|
|
1531
|
-
return {
|
|
1532
|
-
action: "transcript",
|
|
1533
|
-
runId: "--all",
|
|
1534
|
-
stageId: "",
|
|
1535
|
-
source: "error",
|
|
1536
|
-
entries: [],
|
|
1537
|
-
truncated: false,
|
|
1538
|
-
};
|
|
1539
|
-
}
|
|
1540
|
-
if (target.kind === "ambiguous") {
|
|
1541
|
-
return {
|
|
1542
|
-
action: "transcript",
|
|
1543
|
-
runId: target.target,
|
|
1544
|
-
stageId: "",
|
|
1545
|
-
source: "error",
|
|
1546
|
-
entries: [
|
|
1547
|
-
{ role: "notice", text: ambiguousRunMessage(target.target, target.matches) },
|
|
1548
|
-
],
|
|
1549
|
-
truncated: false,
|
|
1550
|
-
};
|
|
1551
|
-
}
|
|
1552
|
-
if (target.kind === "not_found") {
|
|
1553
|
-
return {
|
|
1554
|
-
action: "transcript",
|
|
1555
|
-
runId: target.target,
|
|
1556
|
-
stageId: "",
|
|
1557
|
-
source: "error",
|
|
1558
|
-
entries: [{ role: "notice", text: target.message }],
|
|
1559
|
-
truncated: false,
|
|
1560
|
-
};
|
|
1561
|
-
}
|
|
1562
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1563
|
-
if (!stage.ok || stage.stageId === undefined) {
|
|
1564
|
-
return {
|
|
1565
|
-
action: "transcript",
|
|
1566
|
-
runId: target.runId,
|
|
1567
|
-
stageId: "",
|
|
1568
|
-
source: "error",
|
|
1569
|
-
entries: [
|
|
1570
|
-
{
|
|
1571
|
-
role: "notice",
|
|
1572
|
-
text: stage.ok
|
|
1573
|
-
? "Stage id, prefix, or name is required."
|
|
1574
|
-
: stage.message,
|
|
1575
|
-
},
|
|
1576
|
-
],
|
|
1577
|
-
truncated: false,
|
|
1578
|
-
};
|
|
1579
|
-
}
|
|
1580
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1581
|
-
const run = store.runs().find((r) => r.id === stageRunId);
|
|
1582
|
-
const snapshot = run?.stages.find((s) => s.id === stage.stageId);
|
|
1583
|
-
const liveHandle = stageControlRegistry.get(stageRunId, stage.stageId);
|
|
1584
|
-
if (liveHandle !== undefined) {
|
|
1585
|
-
const sessionFile = liveHandle.sessionFile ?? snapshot?.sessionFile;
|
|
1586
|
-
const sessionId = liveHandle.sessionId ?? snapshot?.sessionId;
|
|
1587
|
-
return shapeTranscriptResult({
|
|
1588
|
-
runId: stageRunId,
|
|
1589
|
-
stageId: stage.stageId,
|
|
1590
|
-
source: "live",
|
|
1591
|
-
entryCount: liveHandle.messages.length,
|
|
1592
|
-
buildEntries: () =>
|
|
1593
|
-
liveHandle.messages.map((m) => transcriptEntryFromMessage(m as MessageLike)),
|
|
1594
|
-
args,
|
|
1595
|
-
sessionId,
|
|
1596
|
-
sessionFile,
|
|
1597
|
-
transcriptPath: sessionFile,
|
|
1598
|
-
});
|
|
1599
|
-
}
|
|
1600
|
-
const snapshotSessionFile = snapshot?.sessionFile;
|
|
1601
|
-
const includeSnapshotOutput = args.includeToolOutput === true && (
|
|
1602
|
-
isTranscriptPreviewExplicit(args) || snapshotSessionFile === undefined
|
|
1603
|
-
);
|
|
1604
|
-
// Cheap count matches `snapshotTranscriptEntries(...).length` (one entry
|
|
1605
|
-
// per tool event plus the optional terminal result/error entries)
|
|
1606
|
-
// without building bodies for the path-only default.
|
|
1607
|
-
const snapshotEntryCount = (snapshot?.toolEvents?.length ?? 0)
|
|
1608
|
-
+ (snapshot?.result !== undefined ? 1 : 0)
|
|
1609
|
-
+ (snapshot?.error !== undefined ? 1 : 0);
|
|
1610
|
-
return shapeTranscriptResult({
|
|
1611
|
-
runId: stageRunId,
|
|
1612
|
-
stageId: stage.stageId,
|
|
1613
|
-
source: "snapshot",
|
|
1614
|
-
entryCount: snapshotEntryCount,
|
|
1615
|
-
buildEntries: () => snapshotTranscriptEntries(snapshot, includeSnapshotOutput),
|
|
1616
|
-
args,
|
|
1617
|
-
sessionId: snapshot?.sessionId,
|
|
1618
|
-
sessionFile: snapshotSessionFile,
|
|
1619
|
-
transcriptPath: snapshotSessionFile,
|
|
1620
|
-
});
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
case "send": {
|
|
1624
|
-
const target = resolveToolRunTarget(args, "No active run to message.");
|
|
1625
|
-
const requestedDelivery = args.delivery ?? "auto";
|
|
1626
|
-
if (target.kind === "all") {
|
|
1627
|
-
return workflowSendResult("--all", "", requestedDelivery, "noop", "Send requires a single run.");
|
|
1628
|
-
}
|
|
1629
|
-
if (target.kind === "ambiguous") {
|
|
1630
|
-
return workflowSendResult(target.target, "", requestedDelivery, "noop", ambiguousRunMessage(target.target, target.matches));
|
|
1631
|
-
}
|
|
1632
|
-
if (target.kind === "not_found") {
|
|
1633
|
-
return workflowSendResult(target.target, "", requestedDelivery, "noop", target.message);
|
|
1634
|
-
}
|
|
1635
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1636
|
-
if (!stage.ok || stage.stageId === undefined) {
|
|
1637
|
-
return workflowSendResult(
|
|
1638
|
-
target.runId,
|
|
1639
|
-
"",
|
|
1640
|
-
requestedDelivery,
|
|
1641
|
-
"noop",
|
|
1642
|
-
stage.ok ? "Stage id, prefix, or name is required." : stage.message,
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1646
|
-
const run = store.runs().find((r) => r.id === stageRunId);
|
|
1647
|
-
const snapshot = run?.stages.find((s) => s.id === stage.stageId);
|
|
1648
|
-
// Brokered structured prompts (in-stage ask_user_question / readiness
|
|
1649
|
-
// gate) resolve through StageUiBroker rather than store.pendingPrompt.
|
|
1650
|
-
// Answer those first when one is pending and the promptId (if any) lines
|
|
1651
|
-
// up — otherwise fall through to the store-prompt / live-handle paths.
|
|
1652
|
-
const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
|
|
1653
|
-
const targetsBrokerPrompt =
|
|
1654
|
-
brokerPrompt !== undefined &&
|
|
1655
|
-
(args.promptId === undefined || args.promptId === brokerPrompt.id) &&
|
|
1656
|
-
(requestedDelivery === "answer" ||
|
|
1657
|
-
args.promptId !== undefined ||
|
|
1658
|
-
requestedDelivery === "auto");
|
|
1659
|
-
if (targetsBrokerPrompt && brokerPrompt !== undefined) {
|
|
1660
|
-
if (!hasPayloadProperty(args)) {
|
|
1661
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
1662
|
-
}
|
|
1663
|
-
const ok = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
|
|
1664
|
-
answerSource: "workflow_tool",
|
|
1665
|
-
});
|
|
1666
|
-
return workflowSendResult(
|
|
1667
|
-
stageRunId,
|
|
1668
|
-
stage.stageId,
|
|
1669
|
-
"answer",
|
|
1670
|
-
ok ? "ok" : "noop",
|
|
1671
|
-
ok ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`,
|
|
1672
|
-
);
|
|
1673
|
-
}
|
|
1674
|
-
const customPrompt = snapshot?.status === "awaiting_input" && snapshot.promptFootprint?.kind === "custom"
|
|
1675
|
-
? snapshot.promptFootprint
|
|
1676
|
-
: undefined;
|
|
1677
|
-
const targetsCustomPrompt =
|
|
1678
|
-
customPrompt !== undefined &&
|
|
1679
|
-
(args.promptId === undefined || args.promptId === customPrompt.id) &&
|
|
1680
|
-
(requestedDelivery === "answer" ||
|
|
1681
|
-
args.promptId !== undefined ||
|
|
1682
|
-
requestedDelivery === "auto");
|
|
1683
|
-
if (targetsCustomPrompt && customPrompt !== undefined) {
|
|
1684
|
-
return workflowSendResult(
|
|
1685
|
-
stageRunId,
|
|
1686
|
-
stage.stageId,
|
|
1687
|
-
"answer",
|
|
1688
|
-
"noop",
|
|
1689
|
-
`Custom UI prompt ${customPrompt.id} requires the interactive workflow graph; arbitrary ctx.ui.custom<T> results cannot be answered through workflow send.`,
|
|
1690
|
-
);
|
|
1691
|
-
}
|
|
1692
|
-
const targetsPrompt =
|
|
1693
|
-
requestedDelivery === "answer" ||
|
|
1694
|
-
args.promptId !== undefined ||
|
|
1695
|
-
(requestedDelivery === "auto" && snapshot?.pendingPrompt !== undefined);
|
|
1696
|
-
if (targetsPrompt) {
|
|
1697
|
-
const promptId = args.promptId ?? snapshot?.pendingPrompt?.id;
|
|
1698
|
-
if (promptId === undefined) {
|
|
1699
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "No pending prompt to answer.");
|
|
1700
|
-
}
|
|
1701
|
-
if (!hasPayloadProperty(args)) {
|
|
1702
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
1703
|
-
}
|
|
1704
|
-
if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
|
|
1705
|
-
return workflowSendResult(
|
|
1706
|
-
stageRunId,
|
|
1707
|
-
stage.stageId,
|
|
1708
|
-
"answer",
|
|
1709
|
-
"ok",
|
|
1710
|
-
`Input request ${promptId} was already answered.`,
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, promptPayloadFromArgs(args), {
|
|
1714
|
-
answerSource: "workflow_tool",
|
|
1715
|
-
});
|
|
1716
|
-
return workflowSendResult(
|
|
1717
|
-
stageRunId,
|
|
1718
|
-
stage.stageId,
|
|
1719
|
-
"answer",
|
|
1720
|
-
ok ? "ok" : "noop",
|
|
1721
|
-
ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`,
|
|
1722
|
-
);
|
|
1723
|
-
}
|
|
1724
|
-
const text = textPayloadFromArgs(args);
|
|
1725
|
-
if (text === undefined) {
|
|
1726
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Send requires text, response, or message.");
|
|
1727
|
-
}
|
|
1728
|
-
const handle = stageControlRegistry.get(stageRunId, stage.stageId);
|
|
1729
|
-
if (handle === undefined) {
|
|
1730
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "No live handle for stage.");
|
|
1731
|
-
}
|
|
1732
|
-
if (requestedDelivery === "resume" || (requestedDelivery === "auto" && handle.status === "paused")) {
|
|
1733
|
-
await handle.resume(text);
|
|
1734
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "ok", "Resumed stage with message.");
|
|
1735
|
-
}
|
|
1736
|
-
if (requestedDelivery === "steer" || (requestedDelivery === "auto" && handle.isStreaming)) {
|
|
1737
|
-
await handle.steer(text);
|
|
1738
|
-
return workflowSendResult(stageRunId, stage.stageId, "steer", "ok", "Steered live stage.");
|
|
1739
|
-
}
|
|
1740
|
-
if (requestedDelivery === "prompt") {
|
|
1741
|
-
await handle.prompt(text);
|
|
1742
|
-
return workflowSendResult(stageRunId, stage.stageId, "prompt", "ok", "Prompt sent to stage.");
|
|
1743
|
-
}
|
|
1744
|
-
await handle.followUp(text);
|
|
1745
|
-
return workflowSendResult(stageRunId, stage.stageId, "followUp", "ok", "Follow-up queued for stage.");
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
case "pause": {
|
|
1749
|
-
const target = resolveToolRunTarget(args, "No in-flight runs to pause.");
|
|
1750
|
-
if (target.kind === "all") {
|
|
1751
|
-
if (args.stageId !== undefined && args.stageId.length > 0) {
|
|
1752
|
-
return {
|
|
1753
|
-
action,
|
|
1754
|
-
runId: "--all",
|
|
1755
|
-
status: "noop",
|
|
1756
|
-
message: allStageConflictMessage("pause"),
|
|
1757
|
-
};
|
|
1758
|
-
}
|
|
1759
|
-
const results = pauseAllRuns();
|
|
1760
|
-
const paused = results.filter((r) => r.ok).length;
|
|
1761
|
-
return {
|
|
1762
|
-
action,
|
|
1763
|
-
runId: "--all",
|
|
1764
|
-
status: paused > 0 ? "paused" : "noop",
|
|
1765
|
-
message: paused > 0
|
|
1766
|
-
? `Paused ${paused} run(s).`
|
|
1767
|
-
: "No in-flight runs to pause.",
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
if (target.kind === "ambiguous") return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
|
|
1771
|
-
if (target.kind === "not_found") return { action, runId: target.target, status: "noop", message: target.message };
|
|
1772
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1773
|
-
if (!stage.ok) return { action, runId: target.runId, status: "noop", message: stage.message };
|
|
1774
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1775
|
-
const result = pauseRun(stageRunId, { stageId: stage.stageId });
|
|
1776
|
-
return result.ok
|
|
1777
|
-
? { action, runId: result.runId, status: "paused", message: `Paused ${result.paused.length} stage(s) on run ${result.runId.slice(0, 8)}.` }
|
|
1778
|
-
: {
|
|
1779
|
-
action,
|
|
1780
|
-
runId: stageRunId,
|
|
1781
|
-
status: "noop",
|
|
1782
|
-
message: stageFailureMessage(stageRunId, result.reason, "pause"),
|
|
1783
|
-
};
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
case "reload": {
|
|
1787
|
-
// Fast UX check; reloadWorkflowResourcesNow re-checks inside the
|
|
1788
|
-
// serialized reload queue and remains the authoritative TOCTOU guard.
|
|
1789
|
-
const activeRuns = inFlightRunCount();
|
|
1790
|
-
if (activeRuns > 0) {
|
|
1791
|
-
return {
|
|
1792
|
-
action: "reload",
|
|
1793
|
-
status: "noop",
|
|
1794
|
-
message: reloadBlockedMessage(activeRuns),
|
|
1795
|
-
};
|
|
1796
|
-
}
|
|
1797
|
-
try {
|
|
1798
|
-
await reloadWorkflowResources();
|
|
1799
|
-
} catch (error) {
|
|
1800
|
-
return {
|
|
1801
|
-
action: "reload",
|
|
1802
|
-
status: "noop",
|
|
1803
|
-
message: reloadFailureMessage(error),
|
|
1804
|
-
};
|
|
1805
|
-
}
|
|
1806
|
-
return {
|
|
1807
|
-
action: "reload",
|
|
1808
|
-
status: "ok",
|
|
1809
|
-
message: args.reason?.trim()
|
|
1810
|
-
? `Reloaded workflow resources (${args.reason.trim()}).`
|
|
1811
|
-
: "Reloaded workflow resources.",
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
case "kill": {
|
|
1816
|
-
const target = resolveToolRunTarget(args, "No in-flight runs to kill.");
|
|
1817
|
-
if (target.kind === "all") {
|
|
1818
|
-
if (args.stageId !== undefined && args.stageId.length > 0) {
|
|
1819
|
-
return {
|
|
1820
|
-
action,
|
|
1821
|
-
runId: "--all",
|
|
1822
|
-
status: "noop",
|
|
1823
|
-
message: allStageConflictMessage("kill"),
|
|
1824
|
-
};
|
|
1825
|
-
}
|
|
1826
|
-
const results = killAllRuns({
|
|
1827
|
-
cancellation: cancellationRegistry,
|
|
1828
|
-
persistence: getPersistence(),
|
|
1829
|
-
});
|
|
1830
|
-
const killed = results.filter((r) => r.ok).length;
|
|
1831
|
-
return {
|
|
1832
|
-
action,
|
|
1833
|
-
runId: "--all",
|
|
1834
|
-
status: killed > 0 ? "killed" : "noop",
|
|
1835
|
-
message:
|
|
1836
|
-
killed > 0
|
|
1837
|
-
? `Killed and retained ${killed} run(s) for inspection.`
|
|
1838
|
-
: "No in-flight runs to kill.",
|
|
1839
|
-
};
|
|
1840
|
-
}
|
|
1841
|
-
if (target.kind === "ambiguous") {
|
|
1842
|
-
return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
|
|
1843
|
-
}
|
|
1844
|
-
if (target.kind === "not_found") {
|
|
1845
|
-
return { action, runId: target.target, status: "noop", message: target.message };
|
|
1846
|
-
}
|
|
1847
|
-
const result = killRun(target.runId, {
|
|
1848
|
-
cancellation: cancellationRegistry,
|
|
1849
|
-
persistence: getPersistence(),
|
|
1850
|
-
});
|
|
1851
|
-
if (result.ok) {
|
|
1852
|
-
return {
|
|
1853
|
-
action,
|
|
1854
|
-
runId: result.runId,
|
|
1855
|
-
status: "killed",
|
|
1856
|
-
message: `Run ${result.runId} killed and retained for inspection (was ${result.previousStatus}).`,
|
|
1857
|
-
};
|
|
1858
|
-
}
|
|
1859
|
-
return {
|
|
1860
|
-
action,
|
|
1861
|
-
runId: target.runId,
|
|
1862
|
-
status: "noop",
|
|
1863
|
-
message: result.reason === "already_ended"
|
|
1864
|
-
? formatAlreadyEndedRetainedMessage(target.runId)
|
|
1865
|
-
// Defensive fallback: resolveRunTarget already found this run, and killRun no longer removes runs.
|
|
1866
|
-
: `Run not found: ${target.runId}`,
|
|
1867
|
-
};
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
case "interrupt": {
|
|
1871
|
-
// Interrupt is resumable: it pauses live work and keeps runs in history/status.
|
|
1872
|
-
const target = resolveToolRunTarget(args, "No in-flight runs to interrupt.");
|
|
1873
|
-
if (target.kind === "all") {
|
|
1874
|
-
if (args.stageId !== undefined && args.stageId.length > 0) {
|
|
1875
|
-
return {
|
|
1876
|
-
action,
|
|
1877
|
-
runId: "--all",
|
|
1878
|
-
status: "noop",
|
|
1879
|
-
message: allStageConflictMessage("interrupt"),
|
|
1880
|
-
};
|
|
1881
|
-
}
|
|
1882
|
-
const results = interruptAllRuns();
|
|
1883
|
-
const interrupted = results.filter((r) => r.ok).length;
|
|
1884
|
-
return {
|
|
1885
|
-
action,
|
|
1886
|
-
runId: "--all",
|
|
1887
|
-
status: interrupted > 0 ? "paused" : "noop",
|
|
1888
|
-
message:
|
|
1889
|
-
interrupted > 0
|
|
1890
|
-
? `Interrupted ${interrupted} run(s).`
|
|
1891
|
-
: "No in-flight runs to interrupt.",
|
|
1892
|
-
};
|
|
1893
|
-
}
|
|
1894
|
-
if (target.kind === "ambiguous") {
|
|
1895
|
-
return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
|
|
1896
|
-
}
|
|
1897
|
-
if (target.kind === "not_found") {
|
|
1898
|
-
return { action, runId: target.target, status: "noop", message: target.message };
|
|
1899
|
-
}
|
|
1900
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1901
|
-
if (!stage.ok) {
|
|
1902
|
-
return { action, runId: target.runId, status: "noop", message: stage.message };
|
|
1903
|
-
}
|
|
1904
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1905
|
-
const result = interruptRun(stageRunId, { stageId: stage.stageId });
|
|
1906
|
-
if (result.ok) {
|
|
1907
|
-
return {
|
|
1908
|
-
action,
|
|
1909
|
-
runId: result.runId,
|
|
1910
|
-
status: "paused",
|
|
1911
|
-
message: stage.stageId
|
|
1912
|
-
? `Stage ${stage.stageId} interrupted on run ${result.runId} and can be resumed.`
|
|
1913
|
-
: `Run ${result.runId} interrupted and can be resumed.`,
|
|
1914
|
-
};
|
|
1915
|
-
}
|
|
1916
|
-
return {
|
|
1917
|
-
action,
|
|
1918
|
-
runId: stageRunId,
|
|
1919
|
-
status: "noop",
|
|
1920
|
-
message: stageFailureMessage(stageRunId, result.reason, "interrupt"),
|
|
1921
|
-
};
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
case "resume": {
|
|
1925
|
-
const target = resolveToolRunTarget(args, "No active run to resume.");
|
|
1926
|
-
if (target.kind === "all") {
|
|
1927
|
-
return { action: "resume", runId: "--all", status: "noop", message: "Resume does not support --all." };
|
|
1928
|
-
}
|
|
1929
|
-
if (target.kind === "ambiguous") {
|
|
1930
|
-
return { action: "resume", runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
|
|
1931
|
-
}
|
|
1932
|
-
if (target.kind === "not_found") {
|
|
1933
|
-
return { action: "resume", runId: target.target, status: "noop", message: target.message };
|
|
1934
|
-
}
|
|
1935
|
-
const stage = resolveToolStageTarget(target.runId, args.stageId);
|
|
1936
|
-
if (!stage.ok) {
|
|
1937
|
-
return { action: "resume", runId: target.runId, status: "noop", message: stage.message };
|
|
1938
|
-
}
|
|
1939
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
1940
|
-
const run = store.runs().find((r) => r.id === stageRunId);
|
|
1941
|
-
const isPaused =
|
|
1942
|
-
run?.status === "paused" ||
|
|
1943
|
-
(run?.stages.some((s) => s.status === "paused") ?? false);
|
|
1944
|
-
const isResumableContinuation = run !== undefined && !isPaused && (
|
|
1945
|
-
(run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
|
|
1946
|
-
(run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable")
|
|
1947
|
-
);
|
|
1948
|
-
if (isResumableContinuation) {
|
|
1949
|
-
const continuation = activeRuntime.resumeFailedRun(stageRunId, stage.stageId, { policy });
|
|
1950
|
-
return {
|
|
1951
|
-
action: "resume",
|
|
1952
|
-
runId: continuation.ok ? continuation.runId : stageRunId,
|
|
1953
|
-
status: continuation.ok ? "running" : "noop",
|
|
1954
|
-
message: continuation.message,
|
|
1955
|
-
};
|
|
1956
|
-
}
|
|
1957
|
-
const result = resumeRun(stageRunId, { stageId: stage.stageId, message: args.message });
|
|
1958
|
-
if (result.ok) {
|
|
1959
|
-
const message = result.message ?? (isPaused
|
|
1960
|
-
? result.resumed.length === 0
|
|
1961
|
-
? `No paused stages on run ${result.runId.slice(0, 8)}.`
|
|
1962
|
-
: `Resumed ${result.resumed.length} stage(s) on run ${result.runId.slice(0, 8)}${args.message ? ` with message: "${args.message}"` : ""}.`
|
|
1963
|
-
: `Snapshot available: run ${result.runId} (${result.snapshot.name}) — status: ${result.snapshot.status}, stages: ${result.snapshot.stages.length}`);
|
|
1964
|
-
return {
|
|
1965
|
-
action: "resume",
|
|
1966
|
-
runId: result.runId,
|
|
1967
|
-
status: "ok",
|
|
1968
|
-
message,
|
|
1969
|
-
};
|
|
1970
|
-
}
|
|
1971
|
-
return {
|
|
1972
|
-
action: "resume",
|
|
1973
|
-
runId: stageRunId,
|
|
1974
|
-
status: "noop",
|
|
1975
|
-
message: `Run not found: ${stageRunId}`,
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
default: {
|
|
1980
|
-
// Exhaustive — all action variants handled above.
|
|
1981
|
-
const _exhaustive: never = action;
|
|
1982
|
-
throw new Error(`Workflow extension: unknown action "${_exhaustive}"`);
|
|
1983
|
-
}
|
|
1984
|
-
}
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
// ---------------------------------------------------------------------------
|
|
1989
|
-
// Slash command helpers
|
|
1990
|
-
// ---------------------------------------------------------------------------
|
|
1991
|
-
|
|
1992
|
-
/**
|
|
1993
|
-
* Local registry of workflow command (name → handler). Populated by
|
|
1994
|
-
* `registerWorkflowCommand` alongside the host registration so the
|
|
1995
|
-
* `on("input", …)` interceptor below can dispatch our commands directly
|
|
1996
|
-
* — bypassing pi's optimistic `startPendingSubmission` flow which
|
|
1997
|
-
* fires the `Working… (esc to interrupt)` loader before the host knows
|
|
1998
|
-
* the input is a synchronous picker/connect UI, not a streaming turn.
|
|
1999
|
-
*
|
|
2000
|
-
* See `installInputInterceptor()` for the dispatch path and rationale.
|
|
2001
|
-
*/
|
|
2002
|
-
type WorkflowCommandHandler = PiCommandOptions["handler"];
|
|
2003
|
-
|
|
2004
|
-
interface ParsedWorkflowSlashCommand {
|
|
2005
|
-
name: string;
|
|
2006
|
-
args: string;
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
function parseWorkflowSlashCommand(text: string): ParsedWorkflowSlashCommand | undefined {
|
|
2010
|
-
const trimmed = text.trim();
|
|
2011
|
-
if (!trimmed.startsWith("/")) return undefined;
|
|
2012
|
-
|
|
2013
|
-
// First token (after `/`) is the command name. Whitespace splits
|
|
2014
|
-
// command from args; quote handling lives inside the command
|
|
2015
|
-
// handler itself (`tokenizeWorkflowArgs`).
|
|
2016
|
-
const firstSpace = trimmed.indexOf(" ");
|
|
2017
|
-
const name =
|
|
2018
|
-
firstSpace === -1 ? trimmed.slice(1) : trimmed.slice(1, firstSpace);
|
|
2019
|
-
const args = firstSpace === -1 ? "" : trimmed.slice(firstSpace + 1);
|
|
2020
|
-
|
|
2021
|
-
return { name, args };
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
/**
|
|
2025
|
-
* Register a slash command with the host AND remember the handler so
|
|
2026
|
-
* the input interceptor can dispatch directly.
|
|
2027
|
-
*
|
|
2028
|
-
* `pi.registerCommand` is the sole supported registration surface
|
|
2029
|
-
* (mirrors pi's `ExtensionAPI.registerCommand`). When the host
|
|
2030
|
-
* lacks `registerCommand` (degraded runtime — RPC mode, headless, or a
|
|
2031
|
-
* mock that didn't stub it) we still populate the registry so the
|
|
2032
|
-
* input interceptor can intercept the command text the user typed.
|
|
2033
|
-
*
|
|
2034
|
-
* We forward to `pi.registerCommand` first so any host-side wrapping
|
|
2035
|
-
* (telemetry, logging, sandboxing) of `options.handler` lands in the
|
|
2036
|
-
* registry; the input interceptor then dispatches the same callable
|
|
2037
|
-
* the host would dispatch from `session.prompt`.
|
|
2038
|
-
*/
|
|
2039
|
-
function registerWorkflowCommand(
|
|
2040
|
-
pi: ExtensionAPI,
|
|
2041
|
-
name: string,
|
|
2042
|
-
options: PiCommandOptions,
|
|
2043
|
-
registry: Map<string, WorkflowCommandHandler>,
|
|
2044
|
-
): void {
|
|
2045
|
-
pi.registerCommand?.(name, options);
|
|
2046
|
-
registry.set(name, options.handler);
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
|
-
/**
|
|
2050
|
-
* Install an `on("input", …)` interceptor that short-circuits the host
|
|
2051
|
-
* submission pipeline for our registered workflow commands.
|
|
2052
|
-
*
|
|
2053
|
-
* Why this exists
|
|
2054
|
-
* ---------------
|
|
2055
|
-
* pi's editor `onSubmit` handler unconditionally calls
|
|
2056
|
-
* `startPendingSubmission` for any text that isn't a built-in slash /
|
|
2057
|
-
* skill / bash / python command — this echoes the message into chat
|
|
2058
|
-
* scrollback AND starts the `Working… (esc to interrupt)` loader in
|
|
2059
|
-
* `statusContainer` before `session.prompt` even runs. The loader is
|
|
2060
|
-
* an optimistic affordance for the agent-streaming case; for our
|
|
2061
|
-
* synchronous picker/connect UIs (`/workflow connect`, `/workflow run`,
|
|
2062
|
-
* `/workflow pause`, …) it's noise — the
|
|
2063
|
-
* spinner sits above the picker until the handler returns.
|
|
2064
|
-
*
|
|
2065
|
-
* `runner.emitInput` runs BEFORE `startPendingSubmission` (see
|
|
2066
|
-
* `packages/coding-agent/src/modes/controllers/input-controller.ts`
|
|
2067
|
-
* `setupEditorSubmitHandler`). Returning `{ action: "handled" }` from an
|
|
2068
|
-
* `on("input", …)` handler short-circuits the function: the host
|
|
2069
|
-
* clears the editor and returns without echoing or starting the
|
|
2070
|
-
* loader. We dispatch the command handler ourselves with the same
|
|
2071
|
-
* context the host would have passed.
|
|
2072
|
-
*
|
|
2073
|
-
* Shape note: pi's `InputEventResult` is `{ action: "continue" } |
|
|
2074
|
-
* { action: "transform"; text; images? } | { action: "handled" }`. The
|
|
2075
|
-
* older `{ handled: true }` shape is silently ignored by the runner
|
|
2076
|
-
* (`result?.action === "handled"` check), which lets the loader fire.
|
|
2077
|
-
*
|
|
2078
|
-
* cross-ref:
|
|
2079
|
-
* - pi docs/extensions.md (input event)
|
|
2080
|
-
* - pi docs/slash-command-internals.md (#tryExecuteExtensionCommand)
|
|
2081
|
-
* - pi packages/coding-agent/src/modes/interactive-mode.ts
|
|
2082
|
-
* `startPendingSubmission` / `ensureLoadingAnimation`
|
|
2083
|
-
*/
|
|
2084
|
-
function installInputInterceptor(
|
|
2085
|
-
pi: ExtensionAPI,
|
|
2086
|
-
commands: Map<string, WorkflowCommandHandler>,
|
|
2087
|
-
): void {
|
|
2088
|
-
if (typeof pi.on !== "function") return;
|
|
2089
|
-
|
|
2090
|
-
pi.on("input", async (event, ctx) => {
|
|
2091
|
-
const text = (event as { text?: unknown } | undefined)?.text;
|
|
2092
|
-
if (typeof text !== "string") return undefined;
|
|
2093
|
-
const parsedCommand = parseWorkflowSlashCommand(text);
|
|
2094
|
-
if (!parsedCommand) return undefined;
|
|
2095
|
-
|
|
2096
|
-
const { name, args } = parsedCommand;
|
|
2097
|
-
const handler = commands.get(name);
|
|
2098
|
-
if (!handler) return undefined; // not ours — let host run its normal flow.
|
|
2099
|
-
const commandCtx = ctx as PiCommandContext;
|
|
2100
|
-
try {
|
|
2101
|
-
await handler(args, commandCtx);
|
|
2102
|
-
} catch (err) {
|
|
2103
|
-
if (commandCtx.hasUI === false) {
|
|
2104
|
-
throw err;
|
|
2105
|
-
}
|
|
2106
|
-
// Match the host command runner for interactive contexts: swallow
|
|
2107
|
-
// handler exceptions so a throw never bubbles out and crashes the
|
|
2108
|
-
// editor submit pipeline. Surface the failure via `ctx.ui.notify` so
|
|
2109
|
-
// the user sees it. Headless contexts rethrow above because notify is
|
|
2110
|
-
// a no-op in print mode and would otherwise hide command failures.
|
|
2111
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2112
|
-
commandCtx.ui.notify(`/${name} failed: ${message}`, "error");
|
|
2113
|
-
}
|
|
2114
|
-
return { action: "handled" };
|
|
2115
|
-
});
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
function formatStartupDiagnostics(
|
|
2119
|
-
configResult: ConfigLoadResult | null,
|
|
2120
|
-
discoveryResult: DiscoveryResult | null,
|
|
2121
|
-
): string | null {
|
|
2122
|
-
const lines: string[] = [];
|
|
2123
|
-
for (const diagnostic of configResult?.diagnostics ?? []) {
|
|
2124
|
-
lines.push(`- [${diagnostic.level} ${diagnostic.code}] ${diagnostic.source ?? "workflow config"}: ${diagnostic.message}`);
|
|
2125
|
-
}
|
|
2126
|
-
for (const diagnostic of discoveryResult?.errors ?? []) {
|
|
2127
|
-
lines.push(`- [${diagnostic.level} ${diagnostic.code}] ${diagnostic.source ?? "workflow discovery"}: ${diagnostic.message}`);
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
if (lines.length === 0) return null;
|
|
2131
|
-
|
|
2132
|
-
const maxVisible = 8;
|
|
2133
|
-
const visible = lines.slice(0, maxVisible);
|
|
2134
|
-
const remaining = lines.length - visible.length;
|
|
2135
|
-
return [
|
|
2136
|
-
`Workflow discovery diagnostics (${lines.length}): some workflow resources were skipped or need attention.`,
|
|
2137
|
-
...visible,
|
|
2138
|
-
...(remaining > 0 ? [`- … ${remaining} more`] : []),
|
|
2139
|
-
].join("\n");
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
/**
|
|
2143
|
-
* Resolve a user-supplied run identifier (full UUID or unique prefix) to
|
|
2144
|
-
* a concrete runId. The widget surfaces an 8-char prefix to keep the
|
|
2145
|
-
* status line scannable; users copy that prefix straight into the interrupt
|
|
2146
|
-
* slash command, so prefix matching is the expected affordance.
|
|
2147
|
-
*/
|
|
2148
|
-
type RunIdResolution =
|
|
2149
|
-
| { kind: "exact"; runId: string }
|
|
2150
|
-
| { kind: "ambiguous"; matches: string[] }
|
|
2151
|
-
| { kind: "not_found" };
|
|
2152
|
-
|
|
2153
|
-
function resolveRunIdPrefix(target: string): RunIdResolution {
|
|
2154
|
-
const runs = store.runs();
|
|
2155
|
-
const exact = runs.find((r) => r.id === target);
|
|
2156
|
-
if (exact) return { kind: "exact", runId: exact.id };
|
|
2157
|
-
|
|
2158
|
-
const prefixed = runs.filter((r) => r.id.startsWith(target));
|
|
2159
|
-
if (prefixed.length === 0) return { kind: "not_found" };
|
|
2160
|
-
if (prefixed.length === 1) return { kind: "exact", runId: prefixed[0]!.id };
|
|
2161
|
-
return { kind: "ambiguous", matches: prefixed.map((r) => r.id) };
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
|
-
type ToolRunTarget =
|
|
2165
|
-
| { kind: "all" }
|
|
2166
|
-
| { kind: "run"; runId: string }
|
|
2167
|
-
| { kind: "ambiguous"; target: string; matches: string[] }
|
|
2168
|
-
| { kind: "not_found"; target: string; message: string };
|
|
2169
|
-
|
|
2170
|
-
function resolveToolRunTarget(
|
|
2171
|
-
args: WorkflowToolArgs,
|
|
2172
|
-
emptyMessage: string,
|
|
2173
|
-
): ToolRunTarget {
|
|
2174
|
-
const rawTarget = args.runId?.trim() ?? "";
|
|
2175
|
-
if (args.all === true || rawTarget === "--all") return { kind: "all" };
|
|
2176
|
-
|
|
2177
|
-
const target = rawTarget || store.activeRunId() || "";
|
|
2178
|
-
if (!target) return { kind: "not_found", target: rawTarget, message: emptyMessage };
|
|
2179
|
-
|
|
2180
|
-
const resolved = resolveRunIdPrefix(target);
|
|
2181
|
-
if (resolved.kind === "exact") return { kind: "run", runId: resolved.runId };
|
|
2182
|
-
if (resolved.kind === "ambiguous") {
|
|
2183
|
-
return { kind: "ambiguous", target, matches: resolved.matches };
|
|
2184
|
-
}
|
|
2185
|
-
return { kind: "not_found", target, message: `Run not found: ${target}` };
|
|
2186
|
-
}
|
|
2187
|
-
|
|
2188
|
-
type ToolStageTarget =
|
|
2189
|
-
| { ok: true; runId?: string; stageId?: string }
|
|
2190
|
-
| { ok: false; message: string };
|
|
2191
|
-
|
|
2192
|
-
function resolveStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
|
|
2193
|
-
const target = stageTarget?.trim();
|
|
2194
|
-
if (!target) return { ok: true, runId };
|
|
2195
|
-
|
|
2196
|
-
const graph = expandWorkflowGraph(store.snapshot(), runId);
|
|
2197
|
-
const exactId = graph.stages.find(
|
|
2198
|
-
(stage) => stage.id === target || stage.workflowGraphTarget.stageId === target,
|
|
2199
|
-
);
|
|
2200
|
-
if (exactId !== undefined) {
|
|
2201
|
-
return {
|
|
2202
|
-
ok: true,
|
|
2203
|
-
runId: exactId.workflowGraphTarget.runId,
|
|
2204
|
-
stageId: exactId.workflowGraphTarget.stageId,
|
|
2205
|
-
};
|
|
2206
|
-
}
|
|
2207
|
-
|
|
2208
|
-
const exactNames = graph.stages.filter((stage) => stage.name === target);
|
|
2209
|
-
if (exactNames.length === 1) {
|
|
2210
|
-
const stage = exactNames[0]!;
|
|
2211
|
-
return {
|
|
2212
|
-
ok: true,
|
|
2213
|
-
runId: stage.workflowGraphTarget.runId,
|
|
2214
|
-
stageId: stage.workflowGraphTarget.stageId,
|
|
2215
|
-
};
|
|
2216
|
-
}
|
|
2217
|
-
if (exactNames.length > 1) return { ok: false, message: `Ambiguous stage identifier "${target}" matches: ${exactNames.map(expandedStageLabel).join(", ")}` };
|
|
2218
|
-
|
|
2219
|
-
const matches = graph.stages.filter((stage) => stageMatchesExpandedIdentifier(stage, target));
|
|
2220
|
-
if (matches.length === 0) return { ok: false, message: `Stage not found in run ${runId.slice(0, 8)}: ${target}` };
|
|
2221
|
-
if (matches.length > 1) return { ok: false, message: `Ambiguous stage identifier "${target}" matches: ${matches.map(expandedStageLabel).join(", ")}` };
|
|
2222
|
-
const stage = matches[0]!;
|
|
2223
|
-
return {
|
|
2224
|
-
ok: true,
|
|
2225
|
-
runId: stage.workflowGraphTarget.runId,
|
|
2226
|
-
stageId: stage.workflowGraphTarget.stageId,
|
|
2227
|
-
};
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
function resolveToolStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
|
|
2231
|
-
return resolveStageTarget(runId, stageTarget);
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
function ambiguousRunMessage(target: string, matches: readonly string[]): string {
|
|
2235
|
-
return `Ambiguous run prefix "${target}" matches: ${matches
|
|
2236
|
-
.map((id) => id.slice(0, 12))
|
|
2237
|
-
.join(", ")}`;
|
|
2238
|
-
}
|
|
2239
|
-
|
|
2240
|
-
function overlaySurfaceFromContext(ctx?: {
|
|
2241
|
-
ui?: PiUISurface;
|
|
2242
|
-
}): OverlayPiSurface | undefined {
|
|
2243
|
-
// Only forward `ctx.ui` to the overlay adapter when it actually
|
|
2244
|
-
// carries the `custom` mount surface. Inline pickers (replace-editor)
|
|
2245
|
-
// hand us a print-only `ui.notify` which would otherwise shadow
|
|
2246
|
-
// `pi.ui` inside the adapter and short-circuit the open.
|
|
2247
|
-
return typeof ctx?.ui?.custom === "function" ? { ui: ctx.ui } : undefined;
|
|
2248
|
-
}
|
|
2249
|
-
|
|
2250
|
-
/**
|
|
2251
|
-
* Strip the clack-style `--yes` / `-y` confirmation skip flag from a token
|
|
2252
|
-
* list. Used by `/workflow interrupt` and `/workflow kill` to skip the confirmation overlay.
|
|
2253
|
-
*/
|
|
2254
|
-
export function stripYesFlag(tokens: string[]): {
|
|
2255
|
-
tokens: string[];
|
|
2256
|
-
yes: boolean;
|
|
2257
|
-
} {
|
|
2258
|
-
const yes = tokens.some((t) => t === "--yes" || t === "-y");
|
|
2259
|
-
return { tokens: tokens.filter((t) => t !== "--yes" && t !== "-y"), yes };
|
|
2260
|
-
}
|
|
2261
|
-
|
|
2262
|
-
/**
|
|
2263
|
-
* Shell-aware split for `/workflow <name> [args…]` chat tokens.
|
|
2264
|
-
*
|
|
2265
|
-
* `prompt="map the codebase"` is one token, not three. Both single and
|
|
2266
|
-
* double quotes are honoured; the quote characters themselves are kept
|
|
2267
|
-
* inside the token so {@link parseWorkflowArgs} can `JSON.parse` the
|
|
2268
|
-
* value and the wrapping quotes coerce it back to a plain string.
|
|
2269
|
-
* Backslash-escaping is **not** supported — workflow inputs are short,
|
|
2270
|
-
* the picker overlay is always available as a fallback for anything
|
|
2271
|
-
* exotic, and the simpler grammar matches what users type in shells.
|
|
2272
|
-
*
|
|
2273
|
-
* An unterminated quote is treated as if a closing quote sat at EOL —
|
|
2274
|
-
* we never throw on user input mid-stream; the parser downstream sees
|
|
2275
|
-
* a partial JSON literal and falls back to keeping it as a string.
|
|
2276
|
-
*/
|
|
2277
|
-
export function tokenizeWorkflowArgs(args: string): string[] {
|
|
2278
|
-
const tokens: string[] = [];
|
|
2279
|
-
let buf = "";
|
|
2280
|
-
let quote: '"' | "'" | undefined;
|
|
2281
|
-
let hasBuf = false;
|
|
2282
|
-
for (let i = 0; i < args.length; i++) {
|
|
2283
|
-
const ch = args[i]!;
|
|
2284
|
-
if (quote !== undefined) {
|
|
2285
|
-
buf += ch;
|
|
2286
|
-
if (ch === quote) quote = undefined;
|
|
2287
|
-
continue;
|
|
2288
|
-
}
|
|
2289
|
-
if (ch === '"' || ch === "'") {
|
|
2290
|
-
buf += ch;
|
|
2291
|
-
hasBuf = true;
|
|
2292
|
-
quote = ch;
|
|
2293
|
-
continue;
|
|
2294
|
-
}
|
|
2295
|
-
if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r") {
|
|
2296
|
-
if (hasBuf) {
|
|
2297
|
-
tokens.push(buf);
|
|
2298
|
-
buf = "";
|
|
2299
|
-
hasBuf = false;
|
|
2300
|
-
}
|
|
2301
|
-
continue;
|
|
2302
|
-
}
|
|
2303
|
-
buf += ch;
|
|
2304
|
-
hasBuf = true;
|
|
2305
|
-
}
|
|
2306
|
-
if (hasBuf) tokens.push(buf);
|
|
2307
|
-
return tokens;
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
/**
|
|
2311
|
-
* Parse remaining args tokens as key=value pairs.
|
|
2312
|
-
* Tokens matching `key=value` are split on the first `=`.
|
|
2313
|
-
* Tokens that are standalone valid JSON objects/arrays are merged in.
|
|
2314
|
-
* All other tokens are ignored (non-kv positional args not supported).
|
|
2315
|
-
*/
|
|
2316
|
-
export function parseWorkflowArgs(tokens: string[]): WorkflowInputValues {
|
|
2317
|
-
const result: Record<string, WorkflowSerializableValue> = {};
|
|
2318
|
-
for (const token of tokens) {
|
|
2319
|
-
// Try JSON object/array merge
|
|
2320
|
-
if (
|
|
2321
|
-
(token.startsWith("{") && token.endsWith("}")) ||
|
|
2322
|
-
(token.startsWith("[") && token.endsWith("]"))
|
|
2323
|
-
) {
|
|
2324
|
-
try {
|
|
2325
|
-
const parsed = JSON.parse(token) as unknown;
|
|
2326
|
-
if (
|
|
2327
|
-
parsed !== null &&
|
|
2328
|
-
typeof parsed === "object" &&
|
|
2329
|
-
!Array.isArray(parsed)
|
|
2330
|
-
) {
|
|
2331
|
-
Object.assign(result, parsed as WorkflowInputValues);
|
|
2332
|
-
}
|
|
2333
|
-
continue;
|
|
2334
|
-
} catch {
|
|
2335
|
-
// not valid JSON — fall through to kv parse
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
// key=value
|
|
2339
|
-
const eqIdx = token.indexOf("=");
|
|
2340
|
-
if (eqIdx > 0) {
|
|
2341
|
-
const key = token.slice(0, eqIdx);
|
|
2342
|
-
const raw = token.slice(eqIdx + 1);
|
|
2343
|
-
// Try to parse value as JSON for typed values (numbers, booleans, objects)
|
|
2344
|
-
let value: WorkflowSerializableValue = raw;
|
|
2345
|
-
try {
|
|
2346
|
-
value = JSON.parse(raw) as WorkflowSerializableValue;
|
|
2347
|
-
} catch {
|
|
2348
|
-
// keep as string
|
|
2349
|
-
}
|
|
2350
|
-
result[key] = value;
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
return result;
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
// ---------------------------------------------------------------------------
|
|
2357
|
-
// Persistence port builder
|
|
2358
|
-
// ---------------------------------------------------------------------------
|
|
2359
|
-
|
|
2360
|
-
/**
|
|
2361
|
-
* Build a WorkflowPersistencePort from the pi ExtensionAPI when persistence
|
|
2362
|
-
* is enabled. Returns undefined when:
|
|
2363
|
-
* - persistRuns is false, OR
|
|
2364
|
-
* - pi.appendEntry is absent (older pi runtime without persistence API).
|
|
2365
|
-
*/
|
|
2366
|
-
export function makePersistencePort(
|
|
2367
|
-
pi: ExtensionAPI,
|
|
2368
|
-
persistRuns: boolean,
|
|
2369
|
-
): WorkflowPersistencePort | undefined {
|
|
2370
|
-
if (!persistRuns) return undefined;
|
|
2371
|
-
if (typeof pi.appendEntry !== "function") return undefined;
|
|
2372
|
-
|
|
2373
|
-
const port: WorkflowPersistencePort = {
|
|
2374
|
-
appendEntry: (type, payload) => pi.appendEntry!(type, payload),
|
|
2375
|
-
};
|
|
2376
|
-
if (typeof pi.setLabel === "function") {
|
|
2377
|
-
port.setLabel = (entryId, label) => pi.setLabel!(entryId, label);
|
|
2378
|
-
}
|
|
2379
|
-
if (typeof pi.appendCustomMessageEntry === "function") {
|
|
2380
|
-
port.appendCustomMessageEntry = (content, meta) =>
|
|
2381
|
-
pi.appendCustomMessageEntry!(content, meta);
|
|
2382
|
-
}
|
|
2383
|
-
return port;
|
|
2384
|
-
}
|
|
2385
|
-
|
|
2386
|
-
// ---------------------------------------------------------------------------
|
|
2387
|
-
// MCP port builder
|
|
2388
|
-
// ---------------------------------------------------------------------------
|
|
2389
|
-
|
|
2390
|
-
/**
|
|
2391
|
-
* Build a WorkflowMcpPort from the pi ExtensionAPI when MCP scope gating is
|
|
2392
|
-
* supported. Returns undefined when pi.events?.emit is absent (adapter not
|
|
2393
|
-
* installed or older runtime without events bus) — scoping becomes a no-op.
|
|
2394
|
-
*/
|
|
2395
|
-
export function makeMcpPort(pi: ExtensionAPI): WorkflowMcpPort | undefined {
|
|
2396
|
-
if (typeof pi.events?.emit !== "function") return undefined;
|
|
2397
|
-
|
|
2398
|
-
// Adapt ExtensionAPI to the minimal PiMcpExtensionAPI shape expected by
|
|
2399
|
-
// setMcpScope / clearMcpScope. We only forward events.emit (confirmed above).
|
|
2400
|
-
const piForMcp: PiMcpExtensionAPI = {
|
|
2401
|
-
events: { emit: pi.events.emit as PiEventBus["emit"] },
|
|
2402
|
-
};
|
|
2403
|
-
|
|
2404
|
-
return {
|
|
2405
|
-
setScope(stageId: string, allow: string[] | null, deny: string[] | null) {
|
|
2406
|
-
setMcpScope(piForMcp, {
|
|
2407
|
-
stageId,
|
|
2408
|
-
allow: allow ?? undefined,
|
|
2409
|
-
deny: deny ?? undefined,
|
|
2410
|
-
});
|
|
2411
|
-
},
|
|
2412
|
-
clearScope(stageId: string) {
|
|
2413
|
-
clearMcpScope(piForMcp, stageId);
|
|
2414
|
-
},
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// ---------------------------------------------------------------------------
|
|
2419
|
-
// Factory — the default export consumed by the pi runtime
|
|
2420
|
-
// ---------------------------------------------------------------------------
|
|
2421
|
-
|
|
2422
|
-
function factory(pi: ExtensionAPI): void {
|
|
2423
|
-
// -------------------------------------------------------------------------
|
|
2424
|
-
// 0. Build StageAdapters from pi runtime surfaces. Stage prompting uses
|
|
2425
|
-
// pi's in-process SDK `createAgentSession()` surface; HIL prompts
|
|
2426
|
-
// flow through the store-backed background adapter built inside
|
|
2427
|
-
// `runDetached()` — they never touch pi.ui.
|
|
2428
|
-
// -------------------------------------------------------------------------
|
|
2429
|
-
const adapters = buildRuntimeAdapters(pi);
|
|
2430
|
-
|
|
2431
|
-
// Local registry of workflow command (name → handler). Populated by
|
|
2432
|
-
// `registerWorkflowCommand` calls below and consumed by the
|
|
2433
|
-
// `pi.on("input", …)` interceptor at the end of the factory — see
|
|
2434
|
-
// `installInputInterceptor` for the rationale.
|
|
2435
|
-
const workflowCommands = new Map<string, WorkflowCommandHandler>();
|
|
2436
|
-
|
|
2437
|
-
// -------------------------------------------------------------------------
|
|
2438
|
-
// 1. Create ExtensionRuntime — mutable ref seeded from startup discovery,
|
|
2439
|
-
// upgraded to unified async discovery once discoverWorkflows() resolves.
|
|
2440
|
-
//
|
|
2441
|
-
// runtimeProxy delegates all calls to runtimeRef.current so every
|
|
2442
|
-
// registration closure automatically uses the most-current registry without
|
|
2443
|
-
// needing to be re-registered.
|
|
2444
|
-
// -------------------------------------------------------------------------
|
|
2445
|
-
const persistenceRef: { current: WorkflowPersistencePort | undefined } = {
|
|
2446
|
-
current: makePersistencePort(pi, WORKFLOW_CONFIG_DEFAULTS.persistRuns),
|
|
2447
|
-
};
|
|
2448
|
-
|
|
2449
|
-
// Build graph overlay adapter — wraps GraphView + pi.ui.custom.
|
|
2450
|
-
// noopOverlay returned when pi.ui?.custom is absent (degraded runtime).
|
|
2451
|
-
const overlay: GraphOverlayPort = buildGraphOverlayAdapter(pi, store, {
|
|
2452
|
-
onKillRun: (runId) => {
|
|
2453
|
-
const run = store.runs().find((r) => r.id === runId);
|
|
2454
|
-
const result = killRun(runId, {
|
|
2455
|
-
cancellation: cancellationRegistry,
|
|
2456
|
-
persistence: persistenceRef.current,
|
|
2457
|
-
});
|
|
2458
|
-
if (run && result.ok) {
|
|
2459
|
-
emitChatSurface(pi, {
|
|
2460
|
-
kind: "killed",
|
|
2461
|
-
run,
|
|
2462
|
-
previousStatus: result.previousStatus,
|
|
2463
|
-
});
|
|
2464
|
-
}
|
|
2465
|
-
},
|
|
2466
|
-
});
|
|
2467
|
-
|
|
2468
|
-
const mcpPort: WorkflowMcpPort | undefined = makeMcpPort(pi);
|
|
2469
|
-
|
|
2470
|
-
/**
|
|
2471
|
-
* Mutable ref for the resolved runtime config.
|
|
2472
|
-
* Seeded with WORKFLOW_CONFIG_DEFAULTS at startup; replaced after async config load.
|
|
2473
|
-
* Injected into every createExtensionRuntime() call so the dispatcher, executor,
|
|
2474
|
-
* and detached runner all receive the same resolved tunables.
|
|
2475
|
-
*/
|
|
2476
|
-
const runtimeConfigRef: { current: WorkflowRuntimeConfig } = {
|
|
2477
|
-
current: {
|
|
2478
|
-
maxDepth: WORKFLOW_CONFIG_DEFAULTS.maxDepth,
|
|
2479
|
-
defaultConcurrency: WORKFLOW_CONFIG_DEFAULTS.defaultConcurrency,
|
|
2480
|
-
persistRuns: WORKFLOW_CONFIG_DEFAULTS.persistRuns,
|
|
2481
|
-
statusFile: WORKFLOW_CONFIG_DEFAULTS.statusFile,
|
|
2482
|
-
resumeInFlight: WORKFLOW_CONFIG_DEFAULTS.resumeInFlight,
|
|
2483
|
-
},
|
|
2484
|
-
};
|
|
2485
|
-
|
|
2486
|
-
/**
|
|
2487
|
-
* Mutable ref for the status writer instance.
|
|
2488
|
-
* Replaced (old unsubscribed) each time runtimeConfigRef is updated after
|
|
2489
|
-
* async config resolution. Starts as a no-op (statusFile defaults to false).
|
|
2490
|
-
*/
|
|
2491
|
-
let statusWriterRef: StatusWriter = createStatusWriter(
|
|
2492
|
-
store,
|
|
2493
|
-
runtimeConfigRef.current,
|
|
2494
|
-
);
|
|
2495
|
-
let lifecycleNotificationsUnsubscribe: (() => void) | null = null;
|
|
2496
|
-
let lifecycleNotificationsActive = false;
|
|
2497
|
-
let hilAnswerNotificationsUnsubscribe: (() => void) | null = null;
|
|
2498
|
-
let hilAnswerNotificationsActive = false;
|
|
2499
|
-
const lifecycleNotificationState = createWorkflowLifecycleNotificationState();
|
|
2500
|
-
const hilAnswerNotificationState = createWorkflowHilAnswerNotificationState();
|
|
2501
|
-
const lifecycleNotificationConfigRef: { current: WorkflowLifecycleNotificationConfig } = {
|
|
2502
|
-
current: WORKFLOW_CONFIG_DEFAULTS.workflowNotifications,
|
|
2503
|
-
};
|
|
2504
|
-
const registerMessageRenderer: ExtensionAPI["registerMessageRenderer"] | undefined =
|
|
2505
|
-
typeof pi.registerMessageRenderer === "function"
|
|
2506
|
-
? (event, renderer) => pi.registerMessageRenderer!(event, renderer)
|
|
2507
|
-
: undefined;
|
|
2508
|
-
registerLifecycleNoticeRenderer({
|
|
2509
|
-
rendererHost: pi,
|
|
2510
|
-
registerMessageRenderer,
|
|
2511
|
-
});
|
|
2512
|
-
registerHilAnswerNoticeRenderer({
|
|
2513
|
-
rendererHost: pi,
|
|
2514
|
-
registerMessageRenderer,
|
|
2515
|
-
});
|
|
2516
|
-
const sendWorkflowNotificationMessage: ExtensionAPI["sendMessage"] | undefined =
|
|
2517
|
-
typeof pi.sendMessage === "function"
|
|
2518
|
-
? (message, options) => pi.sendMessage!(message, options)
|
|
2519
|
-
: undefined;
|
|
2520
|
-
const reinstallLifecycleNotifications = (): void => {
|
|
2521
|
-
lifecycleNotificationsUnsubscribe?.();
|
|
2522
|
-
lifecycleNotificationsUnsubscribe = null;
|
|
2523
|
-
if (!lifecycleNotificationsActive) return;
|
|
2524
|
-
lifecycleNotificationsUnsubscribe = installWorkflowLifecycleNotifications({
|
|
2525
|
-
store,
|
|
2526
|
-
config: lifecycleNotificationConfigRef.current,
|
|
2527
|
-
state: lifecycleNotificationState,
|
|
2528
|
-
seedExisting: true,
|
|
2529
|
-
sendMessage: sendWorkflowNotificationMessage,
|
|
2530
|
-
});
|
|
2531
|
-
};
|
|
2532
|
-
const reinstallHilAnswerNotifications = (): void => {
|
|
2533
|
-
hilAnswerNotificationsUnsubscribe?.();
|
|
2534
|
-
hilAnswerNotificationsUnsubscribe = null;
|
|
2535
|
-
if (!hilAnswerNotificationsActive) return;
|
|
2536
|
-
hilAnswerNotificationsUnsubscribe = installWorkflowHilAnswerNotifications({
|
|
2537
|
-
store,
|
|
2538
|
-
stageUiBroker,
|
|
2539
|
-
state: hilAnswerNotificationState,
|
|
2540
|
-
sendMessage: sendWorkflowNotificationMessage,
|
|
2541
|
-
});
|
|
2542
|
-
};
|
|
2543
|
-
|
|
2544
|
-
async function runWithLifecycleSuppressedForPolicy<T>(
|
|
2545
|
-
policy: WorkflowExecutionPolicy,
|
|
2546
|
-
fn: () => Promise<T>,
|
|
2547
|
-
): Promise<T> {
|
|
2548
|
-
if (policy.mode !== "non_interactive" || policy.awaitTerminalRun !== true) {
|
|
2549
|
-
return fn();
|
|
2550
|
-
}
|
|
2551
|
-
return withWorkflowLifecycleNotificationsSuppressedAsync(
|
|
2552
|
-
lifecycleNotificationState,
|
|
2553
|
-
fn,
|
|
2554
|
-
);
|
|
2555
|
-
}
|
|
2556
|
-
let intercomParentSession: string | null = null;
|
|
2557
|
-
const intercomPort = {
|
|
2558
|
-
emit:
|
|
2559
|
-
typeof pi.events?.emit === "function"
|
|
2560
|
-
? (event: string, payload: Record<string, unknown>) =>
|
|
2561
|
-
pi.events!.emit!(event, payload)
|
|
2562
|
-
: undefined,
|
|
2563
|
-
parentSession: () => intercomParentSession ?? undefined,
|
|
2564
|
-
};
|
|
2565
|
-
const hostStageSessionDir: { current: string | undefined } = { current: undefined };
|
|
2566
|
-
const resolveDefaultStageSessionDir = (): string | undefined => hostStageSessionDir.current;
|
|
2567
|
-
const updateHostStageSessionDir = (sessionManager: SessionManager | undefined): void => {
|
|
2568
|
-
try {
|
|
2569
|
-
hostStageSessionDir.current = sessionManager?.usesDefaultSessionDir?.() === false
|
|
2570
|
-
? sessionManager.getSessionDir?.()
|
|
2571
|
-
: undefined;
|
|
2572
|
-
} catch {
|
|
2573
|
-
hostStageSessionDir.current = undefined;
|
|
2574
|
-
}
|
|
2575
|
-
};
|
|
2576
|
-
|
|
2577
|
-
const startupDiscovery = discoverStartupWorkflowsSync();
|
|
2578
|
-
const runtimeRef: { current: ExtensionRuntime } = {
|
|
2579
|
-
current: createExtensionRuntime({
|
|
2580
|
-
registry: startupDiscovery.registry,
|
|
2581
|
-
cwd: process.cwd(),
|
|
2582
|
-
adapters,
|
|
2583
|
-
cancellation: cancellationRegistry,
|
|
2584
|
-
persistence: persistenceRef.current,
|
|
2585
|
-
mcp: mcpPort,
|
|
2586
|
-
intercom: intercomPort,
|
|
2587
|
-
config: runtimeConfigRef.current,
|
|
2588
|
-
resolveDefaultStageSessionDir,
|
|
2589
|
-
}),
|
|
2590
|
-
};
|
|
2591
|
-
const discoveryRef: { current: DiscoveryResult | null } = { current: null };
|
|
2592
|
-
const configLoadRef: { current: ConfigLoadResult | null } = { current: null };
|
|
2593
|
-
|
|
2594
|
-
/** Stable proxy — all registrations close over this; delegates to runtimeRef.current. */
|
|
2595
|
-
const runtimeProxy: ExtensionRuntime = {
|
|
2596
|
-
get registry() {
|
|
2597
|
-
return runtimeRef.current.registry;
|
|
2598
|
-
},
|
|
2599
|
-
dispatch(args, options) {
|
|
2600
|
-
return runtimeRef.current.dispatch(args, options);
|
|
2601
|
-
},
|
|
2602
|
-
runDirect(args, options) {
|
|
2603
|
-
return runtimeRef.current.runDirect(args, options);
|
|
2604
|
-
},
|
|
2605
|
-
resumeFailedRun(sourceRunId, stageId, options) {
|
|
2606
|
-
return runtimeRef.current.resumeFailedRun(sourceRunId, stageId, options);
|
|
2607
|
-
},
|
|
2608
|
-
};
|
|
2609
|
-
|
|
2610
|
-
function modelFullId(model: PiRuntimeModel): string {
|
|
2611
|
-
return `${String(model.provider)}/${model.id}`;
|
|
2612
|
-
}
|
|
2613
|
-
|
|
2614
|
-
function workflowModelCatalogFromContext(
|
|
2615
|
-
ctx?: PiModelContext,
|
|
2616
|
-
): WorkflowModelCatalogPort | undefined {
|
|
2617
|
-
if (ctx?.modelRegistry === undefined && ctx?.model === undefined)
|
|
2618
|
-
return undefined;
|
|
2619
|
-
return {
|
|
2620
|
-
listModels: async (): Promise<readonly WorkflowModelInfo[]> => {
|
|
2621
|
-
const available =
|
|
2622
|
-
ctx.modelRegistry?.getAvailable() ??
|
|
2623
|
-
(ctx.model === undefined ? [] : [ctx.model]);
|
|
2624
|
-
return available.map((model) => ({
|
|
2625
|
-
provider: String(model.provider),
|
|
2626
|
-
id: model.id,
|
|
2627
|
-
fullId: modelFullId(model),
|
|
2628
|
-
model: model as NonNullable<CreateAgentSessionOptions["model"]>,
|
|
2629
|
-
}));
|
|
2630
|
-
},
|
|
2631
|
-
...(ctx.model !== undefined
|
|
2632
|
-
? {
|
|
2633
|
-
currentModel: ctx.model as NonNullable<
|
|
2634
|
-
CreateAgentSessionOptions["model"]
|
|
2635
|
-
>,
|
|
2636
|
-
preferredProvider: String(ctx.model.provider),
|
|
2637
|
-
}
|
|
2638
|
-
: {}),
|
|
2639
|
-
};
|
|
2640
|
-
}
|
|
2641
|
-
|
|
2642
|
-
function runtimeWithModels(
|
|
2643
|
-
models: WorkflowModelCatalogPort | undefined,
|
|
2644
|
-
): ExtensionRuntime {
|
|
2645
|
-
if (models === undefined) return runtimeProxy;
|
|
2646
|
-
return createExtensionRuntime({
|
|
2647
|
-
registry: runtimeRef.current.registry,
|
|
2648
|
-
cwd: process.cwd(),
|
|
2649
|
-
adapters,
|
|
2650
|
-
cancellation: cancellationRegistry,
|
|
2651
|
-
persistence: persistenceRef.current,
|
|
2652
|
-
mcp: mcpPort,
|
|
2653
|
-
intercom: intercomPort,
|
|
2654
|
-
config: runtimeConfigRef.current,
|
|
2655
|
-
models,
|
|
2656
|
-
resolveDefaultStageSessionDir,
|
|
2657
|
-
});
|
|
2658
|
-
}
|
|
2659
|
-
|
|
2660
|
-
// The runtime normally does not depend on per-command UI, but model fallback
|
|
2661
|
-
// resolution uses the live command/tool context when pi exposes modelRegistry.
|
|
2662
|
-
function runtimeForContext(
|
|
2663
|
-
ctx?: { ui?: PiUISurface } & PiModelContext,
|
|
2664
|
-
): ExtensionRuntime {
|
|
2665
|
-
return runtimeWithModels(workflowModelCatalogFromContext(ctx));
|
|
2666
|
-
}
|
|
2667
|
-
|
|
2668
|
-
let intercomControlUnsubscribe: (() => void) | null = null;
|
|
2669
|
-
let workflowReloadQueue: Promise<void> = Promise.resolve();
|
|
2670
|
-
|
|
2671
|
-
async function reloadWorkflowResources(options?: { allowInFlight?: boolean }): Promise<void> {
|
|
2672
|
-
const reload = workflowReloadQueue.then(() => reloadWorkflowResourcesNow(options));
|
|
2673
|
-
workflowReloadQueue = reload.catch(() => {});
|
|
2674
|
-
await reload;
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2677
|
-
async function loadPackageWorkflowPaths(): Promise<string[]> {
|
|
2678
|
-
const packageResources =
|
|
2679
|
-
(await pi.refreshWorkflowResources?.()) ??
|
|
2680
|
-
pi.getWorkflowResources?.() ??
|
|
2681
|
-
[];
|
|
2682
|
-
return packageResources
|
|
2683
|
-
.filter((resource) => resource.enabled !== false)
|
|
2684
|
-
.map((resource) => resource.path);
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
|
-
async function reloadWorkflowResourcesNow(options?: { allowInFlight?: boolean }): Promise<void> {
|
|
2688
|
-
const activeRuns = inFlightRunCount();
|
|
2689
|
-
if (options?.allowInFlight !== true) {
|
|
2690
|
-
if (activeRuns > 0) {
|
|
2691
|
-
throw new WorkflowReloadBlockedError(reloadBlockedMessage(activeRuns));
|
|
2692
|
-
}
|
|
2693
|
-
} else if (activeRuns > 0 && process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
|
|
2694
|
-
console.warn(
|
|
2695
|
-
`Workflow reload bypassed in-flight guard with ${activeRuns} active run(s).`,
|
|
2696
|
-
);
|
|
2697
|
-
}
|
|
2698
|
-
|
|
2699
|
-
const configResult = await loadWorkflowConfig();
|
|
2700
|
-
configLoadRef.current = configResult;
|
|
2701
|
-
|
|
2702
|
-
// Build scope-aware DiscoveryConfig: global entries → globalWorkflows (resolved
|
|
2703
|
-
// under <homeDir>/.atomic/agent), project entries → projectWorkflows (resolved under
|
|
2704
|
-
// projectRoot). Project keys override global keys. Paths pre-resolved to absolute.
|
|
2705
|
-
const { homedir } = await import("node:os");
|
|
2706
|
-
const hasGlobal = configResult.globalConfig != null;
|
|
2707
|
-
const hasProject = configResult.projectConfig != null;
|
|
2708
|
-
const discoveryConfig =
|
|
2709
|
-
hasGlobal || hasProject
|
|
2710
|
-
? toScopedDiscoveryConfig(
|
|
2711
|
-
configResult.globalConfig ?? null,
|
|
2712
|
-
configResult.projectConfig ?? null,
|
|
2713
|
-
{ projectRoot: process.cwd(), homeDir: homedir() },
|
|
2714
|
-
)
|
|
2715
|
-
: undefined;
|
|
2716
|
-
|
|
2717
|
-
const packageWorkflowPaths = await loadPackageWorkflowPaths();
|
|
2718
|
-
const result = await discoverWorkflows({ config: discoveryConfig, packageWorkflowPaths });
|
|
2719
|
-
discoveryRef.current = result;
|
|
2720
|
-
|
|
2721
|
-
// Resolve effective config (fills in all defaults) and build WorkflowRuntimeConfig.
|
|
2722
|
-
const effectiveConfig = withWorkflowDefaults(configResult.config ?? {});
|
|
2723
|
-
runtimeConfigRef.current = {
|
|
2724
|
-
maxDepth: effectiveConfig.maxDepth,
|
|
2725
|
-
defaultConcurrency: effectiveConfig.defaultConcurrency,
|
|
2726
|
-
persistRuns: effectiveConfig.persistRuns,
|
|
2727
|
-
statusFile: effectiveConfig.statusFile,
|
|
2728
|
-
resumeInFlight: effectiveConfig.resumeInFlight,
|
|
2729
|
-
};
|
|
2730
|
-
lifecycleNotificationConfigRef.current = effectiveConfig.workflowNotifications;
|
|
2731
|
-
reinstallLifecycleNotifications();
|
|
2732
|
-
|
|
2733
|
-
// Replace status writer with one that reflects the resolved config.
|
|
2734
|
-
// Unsubscribe the prior (no-op) writer before creating the new one.
|
|
2735
|
-
statusWriterRef.unsubscribe();
|
|
2736
|
-
statusWriterRef = createStatusWriter(store, runtimeConfigRef.current);
|
|
2737
|
-
|
|
2738
|
-
persistenceRef.current = makePersistencePort(
|
|
2739
|
-
pi,
|
|
2740
|
-
effectiveConfig.persistRuns,
|
|
2741
|
-
);
|
|
2742
|
-
runtimeRef.current = createExtensionRuntime({
|
|
2743
|
-
registry: result.registry,
|
|
2744
|
-
cwd: process.cwd(),
|
|
2745
|
-
adapters,
|
|
2746
|
-
cancellation: cancellationRegistry,
|
|
2747
|
-
persistence: persistenceRef.current,
|
|
2748
|
-
mcp: mcpPort,
|
|
2749
|
-
intercom: intercomPort,
|
|
2750
|
-
config: runtimeConfigRef.current,
|
|
2751
|
-
resolveDefaultStageSessionDir,
|
|
2752
|
-
});
|
|
2753
|
-
}
|
|
2754
|
-
|
|
2755
|
-
const executeWorkflowTool = makeExecuteWorkflowTool(
|
|
2756
|
-
(ctx) => runtimeForContext(ctx),
|
|
2757
|
-
() => persistenceRef.current,
|
|
2758
|
-
reloadWorkflowResources,
|
|
2759
|
-
);
|
|
2760
|
-
let storeWidgetUnsubscribe: (() => void) | null = null;
|
|
2761
|
-
|
|
2762
|
-
// Start unified async discovery immediately.
|
|
2763
|
-
// On resolve: swap runtime ref so /workflow completions and dispatch see
|
|
2764
|
-
// project-local, user-global, and settings-provided workflows.
|
|
2765
|
-
// Load startup config before discovery so workflow paths and tunables are applied.
|
|
2766
|
-
const discoveryPromise = pi.disableAsyncDiscovery
|
|
2767
|
-
? Promise.resolve()
|
|
2768
|
-
: reloadWorkflowResources({ allowInFlight: true });
|
|
2769
|
-
|
|
2770
|
-
// -------------------------------------------------------------------------
|
|
2771
|
-
// 1. Register the `workflow` tool
|
|
2772
|
-
// Pi's ToolDefinition.execute is positional: (toolCallId, params, signal,
|
|
2773
|
-
// onUpdate, ctx) → Promise<AgentToolResult<TDetails>>. The internal
|
|
2774
|
-
// `executeWorkflowTool` keeps its (args, ctx) shape for test ergonomics;
|
|
2775
|
-
// we adapt here at the registration boundary only.
|
|
2776
|
-
// cross-ref: pi-coding-agent dist/core/extensions/types.d.ts ToolDefinition
|
|
2777
|
-
// -------------------------------------------------------------------------
|
|
2778
|
-
if (typeof pi.registerTool === "function") {
|
|
2779
|
-
pi.registerTool<WorkflowToolArgs, WorkflowToolResult>({
|
|
2780
|
-
name: "workflow",
|
|
2781
|
-
label: "workflow",
|
|
2782
|
-
description: WORKFLOW_TOOL_DESCRIPTION,
|
|
2783
|
-
parameters: workflowParameters,
|
|
2784
|
-
promptGuidelines: DEFAULT_PROMPT_GUIDANCE,
|
|
2785
|
-
renderShell: "self",
|
|
2786
|
-
execute: async (_toolCallId, params, _signal, _onUpdate, ctx) => {
|
|
2787
|
-
// Overlay is opt-in via F2 / ctrl+h; do not auto-open from a
|
|
2788
|
-
// tool-call dispatch path. Awaited non-interactive runs suppress
|
|
2789
|
-
// lifecycle steer notices until the terminal tool result is ready.
|
|
2790
|
-
const policy = workflowPolicyFromContext(ctx);
|
|
2791
|
-
const details = (params.action ?? "run") === "run"
|
|
2792
|
-
? await runWithLifecycleSuppressedForPolicy(policy, () =>
|
|
2793
|
-
executeWorkflowTool(params, ctx),
|
|
2794
|
-
)
|
|
2795
|
-
: await executeWorkflowTool(params, ctx);
|
|
2796
|
-
return {
|
|
2797
|
-
content: [{ type: "text", text: renderWorkflowToolContent(details, params) }],
|
|
2798
|
-
details,
|
|
2799
|
-
};
|
|
2800
|
-
},
|
|
2801
|
-
renderCall: (args, _theme, _context) =>
|
|
2802
|
-
dynamicTextRenderComponent((width) => renderCall(args, { width })),
|
|
2803
|
-
renderResult: (result, opts, _theme, context) => {
|
|
2804
|
-
// Capture wall-clock ONCE per chat entry. The lambda below is
|
|
2805
|
-
// invoked on every TUI re-render; without a captured `now`, every
|
|
2806
|
-
// tick would recompute elapsed/running durations and trigger
|
|
2807
|
-
// pi-tui's full-redraw path for any entry above the viewport —
|
|
2808
|
-
// visible as whole-screen flicker on terminals without
|
|
2809
|
-
// synchronized output support (e.g. mosh).
|
|
2810
|
-
const capturedNow = Date.now();
|
|
2811
|
-
return dynamicTextRenderComponent((width) =>
|
|
2812
|
-
renderResult(result.details, {
|
|
2813
|
-
...opts,
|
|
2814
|
-
width,
|
|
2815
|
-
now: capturedNow,
|
|
2816
|
-
runInputs: (context as { args?: WorkflowToolArgs }).args?.inputs,
|
|
2817
|
-
}),
|
|
2818
|
-
);
|
|
2819
|
-
},
|
|
2820
|
-
});
|
|
2821
|
-
}
|
|
2822
|
-
|
|
2823
|
-
// -------------------------------------------------------------------------
|
|
2824
|
-
// 2. Register /workflow slash command
|
|
2825
|
-
// -------------------------------------------------------------------------
|
|
2826
|
-
/**
|
|
2827
|
-
* Shared top-level run-control handler.
|
|
2828
|
-
*
|
|
2829
|
-
* connect [runId|prefix] no arg → picker overlay; arg → attach to graph
|
|
2830
|
-
* attach [runId|prefix [stageId]] open the in-place attach pane on a stage
|
|
2831
|
-
* interrupt [runId|prefix|--all] [-y] confirmation overlay unless -y
|
|
2832
|
-
* kill [runId|prefix|--all] [-y] kill and retain for inspection
|
|
2833
|
-
* pause [runId|prefix [stageId]] pause a run or specific stage
|
|
2834
|
-
* resume [runId|prefix [stageId] …] resume paused work or reopen snapshot
|
|
2835
|
-
*/
|
|
2836
|
-
async function handleRunControlCommand(
|
|
2837
|
-
action: "connect" | "interrupt" | "kill" | "attach" | "pause" | "resume",
|
|
2838
|
-
rest: string[],
|
|
2839
|
-
ctx: PiCommandContext,
|
|
2840
|
-
reporter: WorkflowCommandReporter = createWorkflowCommandReporter(ctx),
|
|
2841
|
-
): Promise<boolean> {
|
|
2842
|
-
const policy = workflowPolicyFromContext(ctx);
|
|
2843
|
-
const print = (msg: string): void => reporter.info(msg);
|
|
2844
|
-
const fail = (msg: string): void => reporter.error(msg);
|
|
2845
|
-
const canOpenPicker = (ui: PiCommandContext["ui"] | undefined): boolean =>
|
|
2846
|
-
policy.allowInputPicker && typeof ui?.custom === "function";
|
|
2847
|
-
const confirmationPrompt = policy.allowHumanInput && typeof ctx.ui?.confirm === "function"
|
|
2848
|
-
? ctx.ui.confirm.bind(ctx.ui)
|
|
2849
|
-
: undefined;
|
|
2850
|
-
const theme = deriveGraphTheme({});
|
|
2851
|
-
const failHeadlessAttachCommand = (
|
|
2852
|
-
targetAction: "connect" | "attach",
|
|
2853
|
-
runId: string,
|
|
2854
|
-
stageId?: string,
|
|
2855
|
-
): boolean => {
|
|
2856
|
-
if (policy.allowInputPicker) return false;
|
|
2857
|
-
const displayTarget = stageId
|
|
2858
|
-
? `${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}`
|
|
2859
|
-
: runId.slice(0, 8);
|
|
2860
|
-
fail(
|
|
2861
|
-
`/workflow ${targetAction} requires an interactive UI surface and cannot attach in non-interactive mode. ` +
|
|
2862
|
-
`Target: ${displayTarget}. Use /workflow status ${runId.slice(0, 8)} or the workflow tool's status/stages/transcript actions for non-interactive inspection.`,
|
|
2863
|
-
);
|
|
2864
|
-
return true;
|
|
2865
|
-
};
|
|
2866
|
-
|
|
2867
|
-
if (action === "connect") {
|
|
2868
|
-
const target = rest.find((t) => !t.startsWith("--"));
|
|
2869
|
-
if (!target) {
|
|
2870
|
-
// Picker mode — mount the overlay and route the resolved action.
|
|
2871
|
-
const ui = ctx.ui;
|
|
2872
|
-
if (!canOpenPicker(ui)) {
|
|
2873
|
-
fail(
|
|
2874
|
-
`${renderSessionList(store.runs(), { theme, includeAll: true })}\n\nPicker requires an interactive UI surface. Pass a runId: /workflow connect <id>`,
|
|
2875
|
-
);
|
|
2876
|
-
return true;
|
|
2877
|
-
}
|
|
2878
|
-
const result = await openSessionPicker(ui, store, theme, "connect");
|
|
2879
|
-
if (result.kind === "close") return true;
|
|
2880
|
-
if (result.kind === "connect") {
|
|
2881
|
-
overlay.open(result.runId, overlaySurfaceFromContext(ctx));
|
|
2882
|
-
return true;
|
|
2883
|
-
}
|
|
2884
|
-
if (result.kind === "kill") {
|
|
2885
|
-
const run = store.runs().find((r) => r.id === result.runId);
|
|
2886
|
-
if (!run) {
|
|
2887
|
-
fail(`Run not found: ${result.runId}`);
|
|
2888
|
-
return true;
|
|
2889
|
-
}
|
|
2890
|
-
if (run.endedAt !== undefined) {
|
|
2891
|
-
print(formatAlreadyEndedRetainedMessage(result.runId));
|
|
2892
|
-
return true;
|
|
2893
|
-
}
|
|
2894
|
-
const confirmed = await openKillConfirm(ui, run, theme);
|
|
2895
|
-
if (!confirmed) {
|
|
2896
|
-
print(
|
|
2897
|
-
`Cancelled. Run ${result.runId.slice(0, 8)} is still active.`,
|
|
2898
|
-
);
|
|
2899
|
-
return true;
|
|
2900
|
-
}
|
|
2901
|
-
const killed = killRun(result.runId, {
|
|
2902
|
-
cancellation: cancellationRegistry,
|
|
2903
|
-
persistence: persistenceRef.current,
|
|
2904
|
-
});
|
|
2905
|
-
if (killed.ok) {
|
|
2906
|
-
emitChatSurface(pi, {
|
|
2907
|
-
kind: "killed",
|
|
2908
|
-
run,
|
|
2909
|
-
previousStatus: killed.previousStatus,
|
|
2910
|
-
});
|
|
2911
|
-
print(`Run ${killed.runId.slice(0, 8)} killed and retained for inspection.`);
|
|
2912
|
-
} else if (killed.reason === "already_ended") {
|
|
2913
|
-
print(formatAlreadyEndedRetainedMessage(killed.runId));
|
|
2914
|
-
} else {
|
|
2915
|
-
fail(`Run not found: ${result.runId.slice(0, 8)}.`);
|
|
2916
|
-
}
|
|
2917
|
-
return true;
|
|
2918
|
-
}
|
|
2919
|
-
return true;
|
|
2920
|
-
}
|
|
2921
|
-
const resolved = resolveRunIdPrefix(target);
|
|
2922
|
-
if (resolved.kind === "not_found") {
|
|
2923
|
-
fail(
|
|
2924
|
-
`Run not found: ${target}\n\n${renderSessionList(store.runs(), { theme, includeAll: true })}`,
|
|
2925
|
-
);
|
|
2926
|
-
return true;
|
|
2927
|
-
}
|
|
2928
|
-
if (resolved.kind === "ambiguous") {
|
|
2929
|
-
fail(
|
|
2930
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches
|
|
2931
|
-
.map((id) => id.slice(0, 12))
|
|
2932
|
-
.join(", ")}`,
|
|
2933
|
-
);
|
|
2934
|
-
return true;
|
|
2935
|
-
}
|
|
2936
|
-
if (failHeadlessAttachCommand("connect", resolved.runId)) {
|
|
2937
|
-
return true;
|
|
2938
|
-
}
|
|
2939
|
-
if (policy.allowInputPicker) {
|
|
2940
|
-
overlay.open(resolved.runId, overlaySurfaceFromContext(ctx));
|
|
2941
|
-
}
|
|
2942
|
-
print(
|
|
2943
|
-
`Attached to ${resolved.runId.slice(0, 8)}. h/ctrl+d hide · q kill · esc close.`,
|
|
2944
|
-
);
|
|
2945
|
-
return true;
|
|
2946
|
-
}
|
|
2947
|
-
|
|
2948
|
-
if (action === "interrupt") {
|
|
2949
|
-
const { tokens: interruptArgs, yes } = stripYesFlag(rest);
|
|
2950
|
-
let target = interruptArgs.find((t) => !t.startsWith("--"));
|
|
2951
|
-
const wantsAll = interruptArgs.includes("--all");
|
|
2952
|
-
if (!target && !wantsAll) {
|
|
2953
|
-
target = store.activeRunId() ?? undefined;
|
|
2954
|
-
if (!target) {
|
|
2955
|
-
fail("No in-flight runs to interrupt.");
|
|
2956
|
-
return true;
|
|
2957
|
-
}
|
|
2958
|
-
}
|
|
2959
|
-
if (wantsAll) {
|
|
2960
|
-
const inFlight = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
|
|
2961
|
-
if (inFlight.length === 0) {
|
|
2962
|
-
fail("No in-flight runs to interrupt.");
|
|
2963
|
-
return true;
|
|
2964
|
-
}
|
|
2965
|
-
if (!yes && confirmationPrompt) {
|
|
2966
|
-
const ok = await confirmationPrompt(
|
|
2967
|
-
`Interrupt all ${inFlight.length} in-flight workflow runs?`,
|
|
2968
|
-
`Pauses: ${inFlight.map((r) => `${r.name} (${r.id.slice(0, 8)})`).join(", ")}`,
|
|
2969
|
-
);
|
|
2970
|
-
if (!ok) {
|
|
2971
|
-
print("Cancelled.");
|
|
2972
|
-
return true;
|
|
2973
|
-
}
|
|
2974
|
-
}
|
|
2975
|
-
const results = interruptAllRuns();
|
|
2976
|
-
const interrupted = results.filter((r) => r.ok).length;
|
|
2977
|
-
if (interrupted > 0) {
|
|
2978
|
-
print(`Interrupted ${interrupted} run(s).`);
|
|
2979
|
-
} else {
|
|
2980
|
-
fail("No in-flight runs to interrupt.");
|
|
2981
|
-
}
|
|
2982
|
-
return true;
|
|
2983
|
-
}
|
|
2984
|
-
const resolved = resolveRunIdPrefix(target!);
|
|
2985
|
-
if (resolved.kind === "not_found") {
|
|
2986
|
-
fail(`Run not found: ${target}`);
|
|
2987
|
-
return true;
|
|
2988
|
-
}
|
|
2989
|
-
if (resolved.kind === "ambiguous") {
|
|
2990
|
-
fail(
|
|
2991
|
-
`Ambiguous run prefix "${target}" matches multiple runs: ${resolved.matches
|
|
2992
|
-
.map((id) => id.slice(0, 12))
|
|
2993
|
-
.join(", ")}`,
|
|
2994
|
-
);
|
|
2995
|
-
return true;
|
|
2996
|
-
}
|
|
2997
|
-
const run = store.runs().find((r) => r.id === resolved.runId);
|
|
2998
|
-
if (!yes && run && run.endedAt === undefined && confirmationPrompt) {
|
|
2999
|
-
const confirmed = await confirmationPrompt(
|
|
3000
|
-
`Interrupt workflow run ${run.name} (${run.id.slice(0, 8)})?`,
|
|
3001
|
-
"Pauses live work so it can be resumed later.",
|
|
3002
|
-
);
|
|
3003
|
-
if (!confirmed) {
|
|
3004
|
-
print(
|
|
3005
|
-
`Cancelled. Run ${resolved.runId.slice(0, 8)} is still active.`,
|
|
3006
|
-
);
|
|
3007
|
-
return true;
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
const result = interruptRun(resolved.runId);
|
|
3011
|
-
if (result.ok) {
|
|
3012
|
-
print(
|
|
3013
|
-
`Run ${result.runId.slice(0, 8)} interrupted and can be resumed.`,
|
|
3014
|
-
);
|
|
3015
|
-
} else {
|
|
3016
|
-
fail(
|
|
3017
|
-
result.reason === "not_found"
|
|
3018
|
-
? `Run not found: ${target}`
|
|
3019
|
-
: result.reason === "already_ended"
|
|
3020
|
-
? `Run already ended: ${target}`
|
|
3021
|
-
: result.reason === "stage_not_found"
|
|
3022
|
-
? `Stage not found for run ${resolved.runId.slice(0, 8)}.`
|
|
3023
|
-
: `No active stages to interrupt on run ${resolved.runId.slice(0, 8)}.`,
|
|
3024
|
-
);
|
|
3025
|
-
}
|
|
3026
|
-
return true;
|
|
3027
|
-
}
|
|
3028
|
-
|
|
3029
|
-
if (action === "kill") {
|
|
3030
|
-
const { tokens: killArgs, yes } = stripYesFlag(rest);
|
|
3031
|
-
let target = killArgs.find((t) => !t.startsWith("--"));
|
|
3032
|
-
const wantsAll = killArgs.includes("--all");
|
|
3033
|
-
if (!target && !wantsAll) {
|
|
3034
|
-
target = store.activeRunId() ?? undefined;
|
|
3035
|
-
if (!target) {
|
|
3036
|
-
fail("No in-flight runs to kill.");
|
|
3037
|
-
return true;
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
if (wantsAll) {
|
|
3041
|
-
const inFlight = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
|
|
3042
|
-
if (inFlight.length === 0) {
|
|
3043
|
-
fail("No in-flight runs to kill.");
|
|
3044
|
-
return true;
|
|
3045
|
-
}
|
|
3046
|
-
if (!yes && confirmationPrompt) {
|
|
3047
|
-
const ok = await confirmationPrompt(
|
|
3048
|
-
`Kill ${inFlight.length} in-flight workflow runs? Killed runs are retained for inspection.`,
|
|
3049
|
-
`Aborts: ${inFlight.map((r) => `${r.name} (${r.id.slice(0, 8)})`).join(", ")}`,
|
|
3050
|
-
);
|
|
3051
|
-
if (!ok) {
|
|
3052
|
-
print("Cancelled.");
|
|
3053
|
-
return true;
|
|
3054
|
-
}
|
|
3055
|
-
}
|
|
3056
|
-
const results = killAllRuns({
|
|
3057
|
-
cancellation: cancellationRegistry,
|
|
3058
|
-
persistence: persistenceRef.current,
|
|
3059
|
-
});
|
|
3060
|
-
const killed = results.filter((r) => r.ok).length;
|
|
3061
|
-
if (killed > 0) {
|
|
3062
|
-
print(`Killed and retained ${killed} run(s) for inspection.`);
|
|
3063
|
-
} else {
|
|
3064
|
-
fail("No in-flight runs to kill.");
|
|
3065
|
-
}
|
|
3066
|
-
return true;
|
|
3067
|
-
}
|
|
3068
|
-
const resolved = resolveRunIdPrefix(target!);
|
|
3069
|
-
if (resolved.kind === "not_found") {
|
|
3070
|
-
fail(`Run not found: ${target}`);
|
|
3071
|
-
return true;
|
|
3072
|
-
}
|
|
3073
|
-
if (resolved.kind === "ambiguous") {
|
|
3074
|
-
fail(
|
|
3075
|
-
`Ambiguous run prefix "${target}" matches multiple runs: ${resolved.matches
|
|
3076
|
-
.map((id) => id.slice(0, 12))
|
|
3077
|
-
.join(", ")}`,
|
|
3078
|
-
);
|
|
3079
|
-
return true;
|
|
3080
|
-
}
|
|
3081
|
-
const run = store.runs().find((r) => r.id === resolved.runId);
|
|
3082
|
-
if (run?.endedAt !== undefined) {
|
|
3083
|
-
print(formatAlreadyEndedRetainedMessage(resolved.runId));
|
|
3084
|
-
return true;
|
|
3085
|
-
}
|
|
3086
|
-
if (!yes && run && confirmationPrompt) {
|
|
3087
|
-
const confirmed = await openKillConfirm(ctx.ui, run, theme);
|
|
3088
|
-
if (!confirmed) {
|
|
3089
|
-
print(
|
|
3090
|
-
`Cancelled. Run ${resolved.runId.slice(0, 8)} is still in history/status.`,
|
|
3091
|
-
);
|
|
3092
|
-
return true;
|
|
3093
|
-
}
|
|
3094
|
-
}
|
|
3095
|
-
const result = killRun(resolved.runId, {
|
|
3096
|
-
cancellation: cancellationRegistry,
|
|
3097
|
-
persistence: persistenceRef.current,
|
|
3098
|
-
});
|
|
3099
|
-
if (result.ok) {
|
|
3100
|
-
if (run) {
|
|
3101
|
-
emitChatSurface(pi, {
|
|
3102
|
-
kind: "killed",
|
|
3103
|
-
run,
|
|
3104
|
-
previousStatus: result.previousStatus,
|
|
3105
|
-
});
|
|
3106
|
-
}
|
|
3107
|
-
print(
|
|
3108
|
-
`Run ${result.runId.slice(0, 8)} killed and retained for inspection (was ${result.previousStatus}).`,
|
|
3109
|
-
);
|
|
3110
|
-
} else if (result.reason === "already_ended") {
|
|
3111
|
-
print(formatAlreadyEndedRetainedMessage(result.runId));
|
|
3112
|
-
} else {
|
|
3113
|
-
fail(`Run not found: ${target}`);
|
|
3114
|
-
}
|
|
3115
|
-
return true;
|
|
3116
|
-
}
|
|
3117
|
-
|
|
3118
|
-
if (action === "attach") {
|
|
3119
|
-
const target = rest[0];
|
|
3120
|
-
const stageTarget = rest[1];
|
|
3121
|
-
let runId: string;
|
|
3122
|
-
if (!target) {
|
|
3123
|
-
const ui = ctx.ui;
|
|
3124
|
-
if (!canOpenPicker(ui)) {
|
|
3125
|
-
fail(
|
|
3126
|
-
`${renderSessionList(store.runs(), { theme, includeAll: true })}\n\nPicker requires an interactive UI surface. Pass a runId: /workflow attach <id> [stageId]`,
|
|
3127
|
-
);
|
|
3128
|
-
return true;
|
|
3129
|
-
}
|
|
3130
|
-
const picked = await openSessionPicker(ui, store, theme, "connect");
|
|
3131
|
-
if (picked.kind === "close") return true;
|
|
3132
|
-
if (picked.kind !== "connect") {
|
|
3133
|
-
// The picker may have surfaced interrupt from the `x` shortcut.
|
|
3134
|
-
// Forward through the existing interrupt flow for clarity.
|
|
3135
|
-
if (picked.kind === "kill") {
|
|
3136
|
-
return handleRunControlCommand(
|
|
3137
|
-
"kill",
|
|
3138
|
-
[picked.runId, "-y"],
|
|
3139
|
-
ctx,
|
|
3140
|
-
reporter,
|
|
3141
|
-
);
|
|
3142
|
-
}
|
|
3143
|
-
return true;
|
|
3144
|
-
}
|
|
3145
|
-
runId = picked.runId;
|
|
3146
|
-
} else {
|
|
3147
|
-
const resolved = resolveRunIdPrefix(target);
|
|
3148
|
-
if (resolved.kind === "not_found") {
|
|
3149
|
-
fail(`Run not found: ${target}`);
|
|
3150
|
-
return true;
|
|
3151
|
-
}
|
|
3152
|
-
if (resolved.kind === "ambiguous") {
|
|
3153
|
-
fail(
|
|
3154
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
|
|
3155
|
-
);
|
|
3156
|
-
return true;
|
|
3157
|
-
}
|
|
3158
|
-
runId = resolved.runId;
|
|
3159
|
-
}
|
|
3160
|
-
const run = store.runs().find((r) => r.id === runId);
|
|
3161
|
-
let stageId: string | undefined;
|
|
3162
|
-
if (stageTarget && run) {
|
|
3163
|
-
const exact = run.stages.find((s) => s.id === stageTarget);
|
|
3164
|
-
const prefix =
|
|
3165
|
-
exact ?? run.stages.find((s) => s.id.startsWith(stageTarget));
|
|
3166
|
-
const byName = prefix ?? run.stages.find((s) => s.name === stageTarget);
|
|
3167
|
-
if (!byName) {
|
|
3168
|
-
fail(`Stage not found in run ${runId.slice(0, 8)}: ${stageTarget}`);
|
|
3169
|
-
return true;
|
|
3170
|
-
}
|
|
3171
|
-
stageId = byName.id;
|
|
3172
|
-
}
|
|
3173
|
-
if (failHeadlessAttachCommand("attach", runId, stageId)) {
|
|
3174
|
-
return true;
|
|
3175
|
-
}
|
|
3176
|
-
if (policy.allowInputPicker) {
|
|
3177
|
-
overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
|
|
3178
|
-
}
|
|
3179
|
-
print(
|
|
3180
|
-
stageId
|
|
3181
|
-
? `Attached to ${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}. ctrl+d return to graph · esc close.`
|
|
3182
|
-
: `Attached to ${runId.slice(0, 8)}. ↵ chat · ctrl+d detach.`,
|
|
3183
|
-
);
|
|
3184
|
-
return true;
|
|
3185
|
-
}
|
|
3186
|
-
|
|
3187
|
-
if (action === "pause") {
|
|
3188
|
-
const target = rest[0];
|
|
3189
|
-
const stageTarget = rest[1];
|
|
3190
|
-
let runId: string;
|
|
3191
|
-
if (!target) {
|
|
3192
|
-
const ui = ctx.ui;
|
|
3193
|
-
if (!canOpenPicker(ui)) {
|
|
3194
|
-
const active = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
|
|
3195
|
-
if (active.length === 0) {
|
|
3196
|
-
fail("No active runs to pause.");
|
|
3197
|
-
return true;
|
|
3198
|
-
}
|
|
3199
|
-
fail(
|
|
3200
|
-
`Picker requires an interactive UI surface. Active runs:\n${active.map((r) => ` ${r.id.slice(0, 8)} ${r.name}`).join("\n")}\n\nUsage: /workflow pause <runId> [stageId]`,
|
|
3201
|
-
);
|
|
3202
|
-
return true;
|
|
3203
|
-
}
|
|
3204
|
-
const picked = await openSessionPicker(ui, store, theme, "pause");
|
|
3205
|
-
if (picked.kind !== "pause") return true;
|
|
3206
|
-
runId = picked.runId;
|
|
3207
|
-
} else {
|
|
3208
|
-
const resolved = resolveRunIdPrefix(target);
|
|
3209
|
-
if (resolved.kind === "not_found") {
|
|
3210
|
-
fail(`Run not found: ${target}`);
|
|
3211
|
-
return true;
|
|
3212
|
-
}
|
|
3213
|
-
if (resolved.kind === "ambiguous") {
|
|
3214
|
-
fail(
|
|
3215
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
|
|
3216
|
-
);
|
|
3217
|
-
return true;
|
|
3218
|
-
}
|
|
3219
|
-
runId = resolved.runId;
|
|
3220
|
-
}
|
|
3221
|
-
let stageId: string | undefined;
|
|
3222
|
-
let stageRunId = runId;
|
|
3223
|
-
if (stageTarget) {
|
|
3224
|
-
const resolvedStage = resolveStageTarget(runId, stageTarget);
|
|
3225
|
-
if (!resolvedStage.ok) {
|
|
3226
|
-
fail(resolvedStage.message);
|
|
3227
|
-
return true;
|
|
3228
|
-
}
|
|
3229
|
-
stageId = resolvedStage.stageId;
|
|
3230
|
-
stageRunId = resolvedStage.runId ?? runId;
|
|
3231
|
-
}
|
|
3232
|
-
const result = pauseRun(stageRunId, { stageId });
|
|
3233
|
-
if (!result.ok) {
|
|
3234
|
-
const why =
|
|
3235
|
-
result.reason === "not_found"
|
|
3236
|
-
? `Run not found: ${stageRunId.slice(0, 8)}`
|
|
3237
|
-
: result.reason === "already_ended"
|
|
3238
|
-
? `Run ${stageRunId.slice(0, 8)} already ended.`
|
|
3239
|
-
: result.reason === "no_active_stages"
|
|
3240
|
-
? `No pausable stages on run ${stageRunId.slice(0, 8)}.`
|
|
3241
|
-
: `Stage not found: ${stageTarget ?? "(unknown)"}`;
|
|
3242
|
-
fail(why);
|
|
3243
|
-
return true;
|
|
3244
|
-
}
|
|
3245
|
-
// Open the orchestrator overlay (graph for run-level pause, stage
|
|
3246
|
-
// chat when a stage was named). This mirrors connect/attach/resume:
|
|
3247
|
-
// the full-screen overlay hides Pi's "Working… (esc to interrupt)"
|
|
3248
|
-
// spinner, which otherwise stays visible because the host session
|
|
3249
|
-
// is still streaming whatever was happening before the pause hit.
|
|
3250
|
-
if (policy.allowInputPicker) {
|
|
3251
|
-
overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
|
|
3252
|
-
}
|
|
3253
|
-
print(
|
|
3254
|
-
result.paused.length === 0
|
|
3255
|
-
? `No stages were paused on run ${stageRunId.slice(0, 8)}.`
|
|
3256
|
-
: `Paused ${result.paused.length} stage(s) on run ${stageRunId.slice(0, 8)}: ${result.paused.map((s) => s.name).join(", ")}`,
|
|
3257
|
-
);
|
|
3258
|
-
return true;
|
|
3259
|
-
}
|
|
3260
|
-
|
|
3261
|
-
if (action === "resume") {
|
|
3262
|
-
const target = rest[0];
|
|
3263
|
-
const stageTarget = rest[1];
|
|
3264
|
-
const message = rest.slice(2).join(" ").trim() || undefined;
|
|
3265
|
-
let runId: string;
|
|
3266
|
-
if (!target) {
|
|
3267
|
-
const ui = ctx.ui;
|
|
3268
|
-
if (!canOpenPicker(ui)) {
|
|
3269
|
-
fail(`Usage: /workflow resume <runId> [stageId] [message…]`);
|
|
3270
|
-
return true;
|
|
3271
|
-
}
|
|
3272
|
-
const picked = await openSessionPicker(ui, store, theme, "resume");
|
|
3273
|
-
if (picked.kind !== "resume") return true;
|
|
3274
|
-
runId = picked.runId;
|
|
3275
|
-
} else {
|
|
3276
|
-
const resolved = resolveRunIdPrefix(target);
|
|
3277
|
-
if (resolved.kind === "not_found") {
|
|
3278
|
-
fail(`Run not found: ${target}`);
|
|
3279
|
-
return true;
|
|
3280
|
-
}
|
|
3281
|
-
if (resolved.kind === "ambiguous") {
|
|
3282
|
-
fail(
|
|
3283
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
|
|
3284
|
-
);
|
|
3285
|
-
return true;
|
|
3286
|
-
}
|
|
3287
|
-
runId = resolved.runId;
|
|
3288
|
-
}
|
|
3289
|
-
let stageId: string | undefined;
|
|
3290
|
-
const resolvedStage = resolveStageTarget(runId, stageTarget);
|
|
3291
|
-
if (!resolvedStage.ok) {
|
|
3292
|
-
fail(resolvedStage.message);
|
|
3293
|
-
return true;
|
|
3294
|
-
}
|
|
3295
|
-
stageId = resolvedStage.stageId;
|
|
3296
|
-
const stageRunId = resolvedStage.runId ?? runId;
|
|
3297
|
-
const run = store.runs().find((r) => r.id === stageRunId);
|
|
3298
|
-
const isPaused =
|
|
3299
|
-
run?.status === "paused" ||
|
|
3300
|
-
(run?.stages.some((s) => s.status === "paused") ?? false);
|
|
3301
|
-
const isResumableContinuation = run !== undefined && !isPaused && (
|
|
3302
|
-
(run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
|
|
3303
|
-
(run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable")
|
|
3304
|
-
);
|
|
3305
|
-
if (isResumableContinuation) {
|
|
3306
|
-
const continuation = runtimeForContext(ctx).resumeFailedRun(stageRunId, stageId, { policy });
|
|
3307
|
-
if (continuation.ok) {
|
|
3308
|
-
print(continuation.message);
|
|
3309
|
-
} else {
|
|
3310
|
-
fail(continuation.message);
|
|
3311
|
-
}
|
|
3312
|
-
return true;
|
|
3313
|
-
}
|
|
3314
|
-
const result = resumeRun(stageRunId, { stageId, message });
|
|
3315
|
-
if (!result.ok) {
|
|
3316
|
-
fail(`Run not found: ${stageRunId.slice(0, 8)}`);
|
|
3317
|
-
return true;
|
|
3318
|
-
}
|
|
3319
|
-
if (!isPaused) {
|
|
3320
|
-
// Non-paused fallback: reopen the orchestrator overlay as before when interactive.
|
|
3321
|
-
if (policy.allowInputPicker) {
|
|
3322
|
-
overlay.open(result.runId, overlaySurfaceFromContext(ctx));
|
|
3323
|
-
}
|
|
3324
|
-
print(
|
|
3325
|
-
result.message ?? `Snapshot available: run ${result.runId} (${result.snapshot.name}) \u2014 status: ${result.snapshot.status}, stages: ${result.snapshot.stages.length}`,
|
|
3326
|
-
);
|
|
3327
|
-
return true;
|
|
3328
|
-
}
|
|
3329
|
-
// Paused live resume: when no message was provided and the picker
|
|
3330
|
-
// is available, open the attached chat so the user can talk to
|
|
3331
|
-
// the freshly-resumed stage.
|
|
3332
|
-
if (!message && stageId && policy.allowInputPicker) {
|
|
3333
|
-
overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
|
|
3334
|
-
}
|
|
3335
|
-
if (result.resumed.length === 0) {
|
|
3336
|
-
fail(`No paused stages on run ${stageRunId.slice(0, 8)}.`);
|
|
3337
|
-
} else {
|
|
3338
|
-
print(`Resumed ${result.resumed.length} stage(s) on run ${stageRunId.slice(0, 8)}${message ? ` with message: "${message}"` : ""}.`);
|
|
3339
|
-
}
|
|
3340
|
-
return true;
|
|
3341
|
-
}
|
|
3342
|
-
|
|
3343
|
-
return false;
|
|
3344
|
-
}
|
|
3345
|
-
|
|
3346
|
-
registerWorkflowCommand(
|
|
3347
|
-
pi,
|
|
3348
|
-
"workflow",
|
|
3349
|
-
{
|
|
3350
|
-
description:
|
|
3351
|
-
"Run or inspect Atomic workflows. Usage: /workflow <name> [key=value…] | /workflow [list|status|connect|attach|interrupt|kill|pause|resume|inputs|reload] [args]",
|
|
3352
|
-
handler: async (args: string, ctx: PiCommandContext) => {
|
|
3353
|
-
const policy = workflowPolicyFromContext(ctx);
|
|
3354
|
-
const reporter = createWorkflowCommandReporter(ctx, policy, pi);
|
|
3355
|
-
const print = (msg: string): void => reporter.info(msg);
|
|
3356
|
-
const fail = (msg: string): void => reporter.error(msg);
|
|
3357
|
-
const withImplicitYesFlag = (tokens: string[]): string[] =>
|
|
3358
|
-
tokens.some((t) => t === "--yes" || t === "-y") ? tokens : [...tokens, "-y"];
|
|
3359
|
-
const showWorkflowInputs = async (
|
|
3360
|
-
workflowName: string,
|
|
3361
|
-
command: WorkflowCommandOutputDetails["command"] = "inputs",
|
|
3362
|
-
): Promise<void> => {
|
|
3363
|
-
const result = await runtimeForContext(ctx).dispatch({
|
|
3364
|
-
workflow: workflowName,
|
|
3365
|
-
inputs: {},
|
|
3366
|
-
action: "inputs",
|
|
3367
|
-
}, { policy });
|
|
3368
|
-
if (result.action === "inputs" && "inputs" in result) {
|
|
3369
|
-
const r = result as Extract<
|
|
3370
|
-
WorkflowToolResult,
|
|
3371
|
-
{ action: "inputs" }
|
|
3372
|
-
>;
|
|
3373
|
-
if (r.error) {
|
|
3374
|
-
const available = runtimeProxy.registry.names();
|
|
3375
|
-
fail(
|
|
3376
|
-
`${r.error}\nAvailable: ${formatAvailableWorkflowNames(available)}`,
|
|
3377
|
-
);
|
|
3378
|
-
} else {
|
|
3379
|
-
const schemaText = renderInputsSchema(workflowName, r.inputs, {
|
|
3380
|
-
theme: deriveGraphTheme({}),
|
|
3381
|
-
});
|
|
3382
|
-
if (policy.mode === "non_interactive") {
|
|
3383
|
-
emitWorkflowCommandOutput(pi, schemaText, {
|
|
3384
|
-
command,
|
|
3385
|
-
workflowName,
|
|
3386
|
-
});
|
|
3387
|
-
} else {
|
|
3388
|
-
print(schemaText);
|
|
3389
|
-
}
|
|
3390
|
-
}
|
|
3391
|
-
}
|
|
3392
|
-
};
|
|
3393
|
-
// Quote-aware split so `prompt="map the codebase"` stays a single
|
|
3394
|
-
// token. Plain `.split(/\s+/)` would mangle quoted multi-word values
|
|
3395
|
-
// into `prompt="map`, `the`, `codebase"` — the dispatch confirm then
|
|
3396
|
-
// renders `prompt=""map"` (see ui/qa-current-render-2.png).
|
|
3397
|
-
const parts = tokenizeWorkflowArgs(args);
|
|
3398
|
-
const subcommand = parts[0] ?? "";
|
|
3399
|
-
|
|
3400
|
-
// -----------------------------------------------------------------------
|
|
3401
|
-
// connect — open the orchestrator pane (picker if no id).
|
|
3402
|
-
// attach — open the in-place attach pane on a stage (or pick run).
|
|
3403
|
-
// pause — pause a run or specific stage.
|
|
3404
|
-
// -----------------------------------------------------------------------
|
|
3405
|
-
if (subcommand === "connect") {
|
|
3406
|
-
await handleRunControlCommand("connect", parts.slice(1), ctx, reporter);
|
|
3407
|
-
return;
|
|
3408
|
-
}
|
|
3409
|
-
if (subcommand === "attach") {
|
|
3410
|
-
await handleRunControlCommand("attach", parts.slice(1), ctx, reporter);
|
|
3411
|
-
return;
|
|
3412
|
-
}
|
|
3413
|
-
if (subcommand === "pause") {
|
|
3414
|
-
await handleRunControlCommand("pause", parts.slice(1), ctx, reporter);
|
|
3415
|
-
return;
|
|
3416
|
-
}
|
|
3417
|
-
|
|
3418
|
-
// -----------------------------------------------------------------------
|
|
3419
|
-
// list (default when no subcommand) — render the workflow catalogue
|
|
3420
|
-
// via the same renderer used by the LLM tool path.
|
|
3421
|
-
// -----------------------------------------------------------------------
|
|
3422
|
-
if (!subcommand || subcommand === "list") {
|
|
3423
|
-
const items = runtimeProxy.registry.all().map((def) => ({
|
|
3424
|
-
name: def.normalizedName,
|
|
3425
|
-
description: def.description,
|
|
3426
|
-
inputs: Object.entries(def.inputs).map(([iname, schema]) => ({
|
|
3427
|
-
name: iname,
|
|
3428
|
-
required: schemaIsRequired(schema),
|
|
3429
|
-
})),
|
|
3430
|
-
}));
|
|
3431
|
-
emitChatSurface(pi, { kind: "list", entries: items });
|
|
3432
|
-
return;
|
|
3433
|
-
}
|
|
3434
|
-
|
|
3435
|
-
// -----------------------------------------------------------------------
|
|
3436
|
-
// status — band-header rich list, or per-run detail when an id is
|
|
3437
|
-
// supplied. `/workflow status` lists all retained snapshots; `/workflow
|
|
3438
|
-
// status <id>` drills into a single run via the inspectRun detail block.
|
|
3439
|
-
// -----------------------------------------------------------------------
|
|
3440
|
-
if (subcommand === "status") {
|
|
3441
|
-
const target = parts[1];
|
|
3442
|
-
if (target && !target.startsWith("--")) {
|
|
3443
|
-
const resolved = resolveRunIdPrefix(target);
|
|
3444
|
-
if (resolved.kind === "not_found") {
|
|
3445
|
-
fail(`Run not found: ${target}`);
|
|
3446
|
-
return;
|
|
3447
|
-
}
|
|
3448
|
-
if (resolved.kind === "ambiguous") {
|
|
3449
|
-
fail(
|
|
3450
|
-
`Ambiguous run prefix "${target}" matches: ${resolved.matches
|
|
3451
|
-
.map((id) => id.slice(0, 12))
|
|
3452
|
-
.join(", ")}`,
|
|
3453
|
-
);
|
|
3454
|
-
return;
|
|
3455
|
-
}
|
|
3456
|
-
const inspected = inspectRun(resolved.runId);
|
|
3457
|
-
if (!inspected.ok) {
|
|
3458
|
-
fail(`Run not found: ${target}`);
|
|
3459
|
-
return;
|
|
3460
|
-
}
|
|
3461
|
-
emitChatSurface(pi, { kind: "detail", detail: inspected.detail });
|
|
3462
|
-
return;
|
|
3463
|
-
}
|
|
3464
|
-
// Status lists all retained snapshots by default; --all remains
|
|
3465
|
-
// accepted as a compatibility no-op.
|
|
3466
|
-
const rows = selectRunsForPicker(
|
|
3467
|
-
store.runs(),
|
|
3468
|
-
"",
|
|
3469
|
-
true,
|
|
3470
|
-
Date.now(),
|
|
3471
|
-
);
|
|
3472
|
-
emitChatSurface(pi, { kind: "status", runs: rows.map((r) => r.run) });
|
|
3473
|
-
return;
|
|
3474
|
-
}
|
|
3475
|
-
|
|
3476
|
-
// -----------------------------------------------------------------------
|
|
3477
|
-
// reload — refresh workflow resources in-process when no workflows are
|
|
3478
|
-
// currently running. Reload swaps runtime/persistence wiring, so doing it
|
|
3479
|
-
// mid-flight would split active runs across old and new resources.
|
|
3480
|
-
// -----------------------------------------------------------------------
|
|
3481
|
-
if (subcommand === "reload") {
|
|
3482
|
-
const activeRuns = inFlightRunCount();
|
|
3483
|
-
if (activeRuns > 0) {
|
|
3484
|
-
fail(reloadBlockedMessage(activeRuns));
|
|
3485
|
-
return;
|
|
3486
|
-
}
|
|
3487
|
-
try {
|
|
3488
|
-
await reloadWorkflowResources();
|
|
3489
|
-
print("Reloaded workflow resources.");
|
|
3490
|
-
} catch (error) {
|
|
3491
|
-
fail(reloadFailureMessage(error));
|
|
3492
|
-
}
|
|
3493
|
-
return;
|
|
3494
|
-
}
|
|
3495
|
-
|
|
3496
|
-
// -----------------------------------------------------------------------
|
|
3497
|
-
// interrupt — top-level chat fast path (no confirmation overlay).
|
|
3498
|
-
// -----------------------------------------------------------------------
|
|
3499
|
-
if (subcommand === "interrupt") {
|
|
3500
|
-
// The top-level chat command is the fast interrupt path surfaced by the
|
|
3501
|
-
// widget hint (`/workflow interrupt <id>`). The user's explicit slash
|
|
3502
|
-
// command should pause immediately, even when a confirm surface is
|
|
3503
|
-
// unavailable or would steal focus from the running workflow.
|
|
3504
|
-
const interruptArgs = parts.slice(1);
|
|
3505
|
-
await handleRunControlCommand(
|
|
3506
|
-
"interrupt",
|
|
3507
|
-
withImplicitYesFlag(interruptArgs),
|
|
3508
|
-
ctx,
|
|
3509
|
-
reporter,
|
|
3510
|
-
);
|
|
3511
|
-
return;
|
|
3512
|
-
}
|
|
3513
|
-
|
|
3514
|
-
// -----------------------------------------------------------------------
|
|
3515
|
-
// kill — abort in-flight work, mark killed, and retain for inspection.
|
|
3516
|
-
// -----------------------------------------------------------------------
|
|
3517
|
-
if (subcommand === "kill") {
|
|
3518
|
-
const killArgs = parts.slice(1);
|
|
3519
|
-
await handleRunControlCommand(
|
|
3520
|
-
"kill",
|
|
3521
|
-
withImplicitYesFlag(killArgs),
|
|
3522
|
-
ctx,
|
|
3523
|
-
reporter,
|
|
3524
|
-
);
|
|
3525
|
-
return;
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3528
|
-
// -----------------------------------------------------------------------
|
|
3529
|
-
// resume — non-paused runs reopen the orchestrator pane (legacy
|
|
3530
|
-
// behaviour); paused runs resume live work through the registry.
|
|
3531
|
-
// -----------------------------------------------------------------------
|
|
3532
|
-
if (subcommand === "resume") {
|
|
3533
|
-
await handleRunControlCommand("resume", parts.slice(1), ctx, reporter);
|
|
3534
|
-
return;
|
|
3535
|
-
}
|
|
3536
|
-
|
|
3537
|
-
// -----------------------------------------------------------------------
|
|
3538
|
-
// inputs — pretty-printed via theme; falls back to plain in non-TTY tests.
|
|
3539
|
-
// -----------------------------------------------------------------------
|
|
3540
|
-
if (subcommand === "inputs") {
|
|
3541
|
-
const workflowName = parts[1] ?? "";
|
|
3542
|
-
if (!workflowName) {
|
|
3543
|
-
fail("Usage: /workflow inputs <name>");
|
|
3544
|
-
return;
|
|
3545
|
-
}
|
|
3546
|
-
await showWorkflowInputs(workflowName);
|
|
3547
|
-
return;
|
|
3548
|
-
}
|
|
3549
|
-
|
|
3550
|
-
// -----------------------------------------------------------------------
|
|
3551
|
-
// Workflow name dispatch — workflows always run as background tasks.
|
|
3552
|
-
// The chat editor remains usable; HIL prompts surface through the graph
|
|
3553
|
-
// viewer overlay (F2 / `/workflow connect`).
|
|
3554
|
-
// -----------------------------------------------------------------------
|
|
3555
|
-
const workflowName = subcommand;
|
|
3556
|
-
const inputTokens = parts.slice(1);
|
|
3557
|
-
|
|
3558
|
-
if (inputTokens.includes("--help")) {
|
|
3559
|
-
await showWorkflowInputs(workflowName, "help");
|
|
3560
|
-
return;
|
|
3561
|
-
}
|
|
3562
|
-
|
|
3563
|
-
const inputs = parseWorkflowArgs(inputTokens);
|
|
3564
|
-
// -----------------------------------------------------------------------
|
|
3565
|
-
// Interactive argument picker.
|
|
3566
|
-
//
|
|
3567
|
-
// Triggers when:
|
|
3568
|
-
// - the workflow has at least one declared input (zero-input
|
|
3569
|
-
// workflows go straight to dispatch — there's nothing to ask),
|
|
3570
|
-
// - the user did not pass `--no-picker`,
|
|
3571
|
-
// - an interactive TUI surface is available,
|
|
3572
|
-
// - AND either no key=value was supplied or one of the required
|
|
3573
|
-
// inputs is still missing after parsing.
|
|
3574
|
-
//
|
|
3575
|
-
// The picker is seeded with whatever the user *did* type, so a
|
|
3576
|
-
// partial invocation like `/workflow gen-spec research_doc=notes.md`
|
|
3577
|
-
// pre-fills that field and focuses the next unfilled required one.
|
|
3578
|
-
// -----------------------------------------------------------------------
|
|
3579
|
-
const wantsPickerSkip = inputTokens.includes("--no-picker");
|
|
3580
|
-
let mergedInputs = inputs;
|
|
3581
|
-
// Track whether the inputs picker actually showed a UI to the user.
|
|
3582
|
-
// We use this below to mount the orchestrator overlay on dispatch
|
|
3583
|
-
// success — same UX as `/workflow connect|attach|pause|resume`,
|
|
3584
|
-
// which all cover Pi's `⠴ Working… (esc to interrupt)` spinner
|
|
3585
|
-
// with the full-screen overlay instead of leaving it visible in
|
|
3586
|
-
// the chat while the workflow runs in the background.
|
|
3587
|
-
let pickerWasShown = false;
|
|
3588
|
-
// Prefer the sticky inline form when the host can install a custom
|
|
3589
|
-
// editor. If the host rejects that editor contract at runtime, fall
|
|
3590
|
-
// back to the supported overlay picker rather than surfacing the host
|
|
3591
|
-
// exception as a workflow command error.
|
|
3592
|
-
const canOpenPicker =
|
|
3593
|
-
policy.allowInputPicker &&
|
|
3594
|
-
!wantsPickerSkip &&
|
|
3595
|
-
(typeof ctx.ui?.setEditorComponent === "function" ||
|
|
3596
|
-
typeof ctx.ui?.custom === "function");
|
|
3597
|
-
if (canOpenPicker) {
|
|
3598
|
-
const schemaResult = await runtimeForContext(ctx).dispatch({
|
|
3599
|
-
workflow: workflowName,
|
|
3600
|
-
inputs: {},
|
|
3601
|
-
action: "inputs",
|
|
3602
|
-
}, { policy });
|
|
3603
|
-
const schema =
|
|
3604
|
-
schemaResult.action === "inputs" && "inputs" in schemaResult
|
|
3605
|
-
? (schemaResult as Extract<
|
|
3606
|
-
WorkflowToolResult,
|
|
3607
|
-
{ action: "inputs" }
|
|
3608
|
-
>)
|
|
3609
|
-
: undefined;
|
|
3610
|
-
const fields = schema?.inputs ?? [];
|
|
3611
|
-
const hasFields = fields.length > 0;
|
|
3612
|
-
const missingRequired = fields.some(
|
|
3613
|
-
(f: WorkflowInputEntry) =>
|
|
3614
|
-
f.required === true &&
|
|
3615
|
-
(inputs[f.name] === undefined ||
|
|
3616
|
-
(typeof inputs[f.name] === "string" &&
|
|
3617
|
-
(inputs[f.name] as string).trim() === "")),
|
|
3618
|
-
);
|
|
3619
|
-
const noTokensAtAll = inputTokens.length === 0;
|
|
3620
|
-
if (hasFields && (noTokensAtAll || missingRequired)) {
|
|
3621
|
-
pickerWasShown = true;
|
|
3622
|
-
const pickerTheme = deriveGraphTheme({});
|
|
3623
|
-
let pickerResult =
|
|
3624
|
-
typeof ctx.ui?.setEditorComponent === "function"
|
|
3625
|
-
? await openInlineInputsForm(pi, ctx, {
|
|
3626
|
-
workflowName,
|
|
3627
|
-
fields,
|
|
3628
|
-
prefilled: inputs,
|
|
3629
|
-
theme: pickerTheme,
|
|
3630
|
-
})
|
|
3631
|
-
: { kind: "unsupported" as const };
|
|
3632
|
-
if (
|
|
3633
|
-
pickerResult.kind === "unsupported" &&
|
|
3634
|
-
typeof ctx.ui?.custom === "function"
|
|
3635
|
-
) {
|
|
3636
|
-
pickerResult = await openInputsPicker(ctx.ui, {
|
|
3637
|
-
workflowName,
|
|
3638
|
-
fields,
|
|
3639
|
-
prefilled: inputs,
|
|
3640
|
-
theme: pickerTheme,
|
|
3641
|
-
});
|
|
3642
|
-
}
|
|
3643
|
-
if (pickerResult.kind === "cancel") {
|
|
3644
|
-
return;
|
|
3645
|
-
}
|
|
3646
|
-
if (pickerResult.kind === "run") {
|
|
3647
|
-
mergedInputs = pickerResult.values;
|
|
3648
|
-
}
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
|
|
3652
|
-
const result = await runWithLifecycleSuppressedForPolicy(policy, () =>
|
|
3653
|
-
runtimeForContext(ctx).dispatch({
|
|
3654
|
-
workflow: workflowName,
|
|
3655
|
-
inputs: mergedInputs,
|
|
3656
|
-
action: "run",
|
|
3657
|
-
}, { policy }),
|
|
3658
|
-
);
|
|
3659
|
-
if (result.action === "run" && "runId" in result) {
|
|
3660
|
-
const r = result as Extract<
|
|
3661
|
-
WorkflowToolResult,
|
|
3662
|
-
{ action: "run"; runId: string }
|
|
3663
|
-
>;
|
|
3664
|
-
if (r.status === "failed" && r.runId === "") {
|
|
3665
|
-
if (r.error?.toLowerCase().includes("not found")) {
|
|
3666
|
-
const available = runtimeProxy.registry.names();
|
|
3667
|
-
fail(
|
|
3668
|
-
`Workflow not found: ${workflowName}\nAvailable: ${formatAvailableWorkflowNames(available)}`,
|
|
3669
|
-
);
|
|
3670
|
-
} else {
|
|
3671
|
-
fail(
|
|
3672
|
-
`Workflow "${workflowName}" failed: ${r.error ?? "unknown error"}`,
|
|
3673
|
-
);
|
|
3674
|
-
}
|
|
3675
|
-
} else if (r.status === "failed") {
|
|
3676
|
-
fail(
|
|
3677
|
-
`Workflow "${workflowName}" failed: ${r.error ?? "unknown error"}`,
|
|
3678
|
-
);
|
|
3679
|
-
} else {
|
|
3680
|
-
if (policy.mode === "non_interactive") {
|
|
3681
|
-
emitTerminalRunDetailSurface(pi, workflowName, mergedInputs, r);
|
|
3682
|
-
return;
|
|
3683
|
-
}
|
|
3684
|
-
// Always-background — the run is alive, the chat is free.
|
|
3685
|
-
// Route via emitChatSurface so the band+card chrome receives the
|
|
3686
|
-
// real chat content width via pi-tui's Component contract
|
|
3687
|
-
// (registered renderer returns `{ render(width): string[] }`),
|
|
3688
|
-
// not a `process.stdout.columns - 2` heuristic.
|
|
3689
|
-
emitChatSurface(pi, {
|
|
3690
|
-
kind: "dispatch",
|
|
3691
|
-
workflowName,
|
|
3692
|
-
runId: r.runId,
|
|
3693
|
-
inputs: mergedInputs,
|
|
3694
|
-
});
|
|
3695
|
-
// When the user reached this path via the inputs picker (i.e.
|
|
3696
|
-
// they didn't pre-supply all required args), open the
|
|
3697
|
-
// orchestrator overlay. The full-screen overlay covers the
|
|
3698
|
-
// chat statusContainer so Pi's working spinner is not left
|
|
3699
|
-
// visible behind the dispatch card. Direct invocations with
|
|
3700
|
-
// complete args remain opt-in via F2 / `/workflow connect`.
|
|
3701
|
-
if (pickerWasShown && typeof ctx.ui?.custom === "function") {
|
|
3702
|
-
overlay.open(r.runId, overlaySurfaceFromContext(ctx));
|
|
3703
|
-
}
|
|
3704
|
-
}
|
|
3705
|
-
}
|
|
3706
|
-
return;
|
|
3707
|
-
},
|
|
3708
|
-
getArgumentCompletions: (partial: string): PiArgumentCompletionResult => {
|
|
3709
|
-
const completeToken = (
|
|
3710
|
-
argumentText: string,
|
|
3711
|
-
candidates: PiArgumentCompletion[],
|
|
3712
|
-
): PiArgumentCompletionResult => {
|
|
3713
|
-
const tokenStart = /\s$/.test(argumentText)
|
|
3714
|
-
? argumentText.length
|
|
3715
|
-
: Math.max(
|
|
3716
|
-
argumentText.lastIndexOf(" "),
|
|
3717
|
-
argumentText.lastIndexOf("\t"),
|
|
3718
|
-
) + 1;
|
|
3719
|
-
const head = argumentText.slice(0, tokenStart);
|
|
3720
|
-
const token = argumentText.slice(tokenStart);
|
|
3721
|
-
const filtered = candidates
|
|
3722
|
-
.filter((candidate) => candidate.value.startsWith(token))
|
|
3723
|
-
.map((candidate) => ({
|
|
3724
|
-
...candidate,
|
|
3725
|
-
value: `${head}${candidate.value}`,
|
|
3726
|
-
}));
|
|
3727
|
-
return filtered.length > 0 ? filtered : null;
|
|
3728
|
-
};
|
|
3729
|
-
|
|
3730
|
-
const workflowNameItems = (): PiArgumentCompletion[] =>
|
|
3731
|
-
runtimeProxy.registry.names().map((name) => ({
|
|
3732
|
-
value: `${name} `,
|
|
3733
|
-
label: name,
|
|
3734
|
-
description: `Run workflow: ${name}`,
|
|
3735
|
-
}));
|
|
3736
|
-
|
|
3737
|
-
const runIdItems = (): PiArgumentCompletion[] =>
|
|
3738
|
-
topLevelWorkflowRuns(store.runs()).map((run) => ({
|
|
3739
|
-
value: `${run.id} `,
|
|
3740
|
-
label: run.id.slice(0, 8),
|
|
3741
|
-
description: `${run.name} — ${run.status}`,
|
|
3742
|
-
}));
|
|
3743
|
-
|
|
3744
|
-
const adminCompletions: PiArgumentCompletion[] = [
|
|
3745
|
-
{
|
|
3746
|
-
value: "connect ",
|
|
3747
|
-
label: "connect",
|
|
3748
|
-
description: "Attach to a run (picker if no id)",
|
|
3749
|
-
},
|
|
3750
|
-
{
|
|
3751
|
-
value: "attach ",
|
|
3752
|
-
label: "attach",
|
|
3753
|
-
description: "Open the in-place attach pane on a node",
|
|
3754
|
-
},
|
|
3755
|
-
{
|
|
3756
|
-
value: "list ",
|
|
3757
|
-
label: "list",
|
|
3758
|
-
description: "List registered workflows",
|
|
3759
|
-
},
|
|
3760
|
-
{
|
|
3761
|
-
value: "status ",
|
|
3762
|
-
label: "status",
|
|
3763
|
-
description: "List current-session active and retained terminal runs",
|
|
3764
|
-
},
|
|
3765
|
-
{
|
|
3766
|
-
value: "interrupt ",
|
|
3767
|
-
label: "interrupt",
|
|
3768
|
-
description: "Interrupt a run",
|
|
3769
|
-
},
|
|
3770
|
-
{
|
|
3771
|
-
value: "kill ",
|
|
3772
|
-
label: "kill",
|
|
3773
|
-
description: "Kill and retain a run for inspection",
|
|
3774
|
-
},
|
|
3775
|
-
{
|
|
3776
|
-
value: "pause ",
|
|
3777
|
-
label: "pause",
|
|
3778
|
-
description: "Pause a run or stage",
|
|
3779
|
-
},
|
|
3780
|
-
{
|
|
3781
|
-
value: "resume ",
|
|
3782
|
-
label: "resume",
|
|
3783
|
-
description: "Re-open overlay for a run",
|
|
3784
|
-
},
|
|
3785
|
-
{
|
|
3786
|
-
value: "inputs ",
|
|
3787
|
-
label: "inputs",
|
|
3788
|
-
description: "Show a workflow's input schema",
|
|
3789
|
-
},
|
|
3790
|
-
{
|
|
3791
|
-
value: "reload ",
|
|
3792
|
-
label: "reload",
|
|
3793
|
-
description: "Reload workflow resources",
|
|
3794
|
-
},
|
|
3795
|
-
];
|
|
3796
|
-
|
|
3797
|
-
const parts = partial.trim().split(/\s+/).filter(Boolean);
|
|
3798
|
-
const subcommand = parts[0] ?? "";
|
|
3799
|
-
if (!partial.includes(" ")) {
|
|
3800
|
-
return completeToken(partial, [
|
|
3801
|
-
...adminCompletions,
|
|
3802
|
-
...workflowNameItems(),
|
|
3803
|
-
]);
|
|
3804
|
-
}
|
|
3805
|
-
|
|
3806
|
-
if (subcommand === "inputs") {
|
|
3807
|
-
return completeToken(partial, workflowNameItems());
|
|
3808
|
-
}
|
|
3809
|
-
|
|
3810
|
-
if (subcommand === "status") {
|
|
3811
|
-
return completeToken(partial, runIdItems());
|
|
3812
|
-
}
|
|
3813
|
-
|
|
3814
|
-
if (subcommand === "connect") {
|
|
3815
|
-
return completeToken(partial, runIdItems());
|
|
3816
|
-
}
|
|
3817
|
-
|
|
3818
|
-
if (subcommand === "resume") {
|
|
3819
|
-
return completeToken(partial, runIdItems());
|
|
3820
|
-
}
|
|
3821
|
-
|
|
3822
|
-
if (subcommand === "attach" || subcommand === "pause") {
|
|
3823
|
-
return completeToken(partial, runIdItems());
|
|
3824
|
-
}
|
|
3825
|
-
|
|
3826
|
-
if (subcommand === "interrupt" || subcommand === "kill") {
|
|
3827
|
-
const verb = subcommand === "kill" ? "Kill and retain" : "Interrupt";
|
|
3828
|
-
return completeToken(partial, [
|
|
3829
|
-
{
|
|
3830
|
-
value: "--all ",
|
|
3831
|
-
label: "--all",
|
|
3832
|
-
description: `${verb} all in-flight runs`,
|
|
3833
|
-
},
|
|
3834
|
-
{
|
|
3835
|
-
value: "--yes ",
|
|
3836
|
-
label: "--yes",
|
|
3837
|
-
description: "Skip confirmation",
|
|
3838
|
-
},
|
|
3839
|
-
{ value: "-y ", label: "-y", description: "Skip confirmation" },
|
|
3840
|
-
...runIdItems(),
|
|
3841
|
-
]);
|
|
3842
|
-
}
|
|
3843
|
-
|
|
3844
|
-
// `partial` ends with whitespace and no subcommand was typed yet
|
|
3845
|
-
// (e.g. `/workflow `). pi's autocomplete is asking what to suggest
|
|
3846
|
-
// after the trailing space; offer the same admin + workflow-name
|
|
3847
|
-
// menu as the no-space branch above. Skipping this guard would call
|
|
3848
|
-
// `registry.get("")`, which throws TypeError from normalizeWorkflowName.
|
|
3849
|
-
if (!subcommand) {
|
|
3850
|
-
return completeToken(partial, [
|
|
3851
|
-
...adminCompletions,
|
|
3852
|
-
...workflowNameItems(),
|
|
3853
|
-
]);
|
|
3854
|
-
}
|
|
3855
|
-
|
|
3856
|
-
const workflow = runtimeProxy.registry.get(subcommand);
|
|
3857
|
-
if (!workflow) return null;
|
|
3858
|
-
|
|
3859
|
-
const tokenStart = /\s$/.test(partial)
|
|
3860
|
-
? partial.length
|
|
3861
|
-
: Math.max(partial.lastIndexOf(" "), partial.lastIndexOf("\t")) + 1;
|
|
3862
|
-
const token = partial.slice(tokenStart);
|
|
3863
|
-
const equalsIndex = token.indexOf("=");
|
|
3864
|
-
if (equalsIndex > 0) {
|
|
3865
|
-
const inputName = token.slice(0, equalsIndex);
|
|
3866
|
-
const schema = workflow.inputs[inputName];
|
|
3867
|
-
const schemaChoiceValues = schema === undefined ? undefined : schemaChoices(schema);
|
|
3868
|
-
const schemaKind = schema === undefined ? undefined : schemaFieldKind(schema);
|
|
3869
|
-
if (schemaChoiceValues !== undefined) {
|
|
3870
|
-
return completeToken(
|
|
3871
|
-
partial,
|
|
3872
|
-
schemaChoiceValues.map((choice) => ({
|
|
3873
|
-
value: `${inputName}=${choice} `,
|
|
3874
|
-
label: choice,
|
|
3875
|
-
description: inputName,
|
|
3876
|
-
})),
|
|
3877
|
-
);
|
|
3878
|
-
}
|
|
3879
|
-
if (schemaKind === "boolean") {
|
|
3880
|
-
return completeToken(partial, [
|
|
3881
|
-
{
|
|
3882
|
-
value: `${inputName}=true `,
|
|
3883
|
-
label: "true",
|
|
3884
|
-
description: inputName,
|
|
3885
|
-
},
|
|
3886
|
-
{
|
|
3887
|
-
value: `${inputName}=false `,
|
|
3888
|
-
label: "false",
|
|
3889
|
-
description: inputName,
|
|
3890
|
-
},
|
|
3891
|
-
]);
|
|
3892
|
-
}
|
|
3893
|
-
return null;
|
|
3894
|
-
}
|
|
3895
|
-
|
|
3896
|
-
const inputCompletions: PiArgumentCompletion[] = Object.entries(
|
|
3897
|
-
workflow.inputs,
|
|
3898
|
-
).map(([name, schema]) => ({
|
|
3899
|
-
value: `${name}=`,
|
|
3900
|
-
label: name,
|
|
3901
|
-
description: schemaDescription(schema),
|
|
3902
|
-
}));
|
|
3903
|
-
return completeToken(partial, [
|
|
3904
|
-
{
|
|
3905
|
-
value: "--no-picker ",
|
|
3906
|
-
label: "--no-picker",
|
|
3907
|
-
description: "Skip interactive input picker",
|
|
3908
|
-
},
|
|
3909
|
-
{
|
|
3910
|
-
value: "--help ",
|
|
3911
|
-
label: "--help",
|
|
3912
|
-
description: "Show this workflow's input schema",
|
|
3913
|
-
},
|
|
3914
|
-
...inputCompletions,
|
|
3915
|
-
]);
|
|
3916
|
-
},
|
|
3917
|
-
},
|
|
3918
|
-
workflowCommands,
|
|
3919
|
-
);
|
|
3920
|
-
|
|
3921
|
-
// -------------------------------------------------------------------------
|
|
3922
|
-
// 3. Register message renderers for lifecycle events (§5.6)
|
|
3923
|
-
// -------------------------------------------------------------------------
|
|
3924
|
-
// Chat-scroll renderers are deliberately limited to run-level events
|
|
3925
|
-
// (start + end). Per-stage chatter is owned by the orchestrator pane —
|
|
3926
|
-
// duplicating it into chat scroll just creates visual noise and pushes
|
|
3927
|
-
// older chat content out of view every time a stage transitions.
|
|
3928
|
-
if (typeof pi.registerMessageRenderer === "function") {
|
|
3929
|
-
// Wrap the string-producing banners in a render component: the host adds a
|
|
3930
|
-
// renderer's result directly as a TUI child, so a bare string would crash
|
|
3931
|
-
// `Container.render()` with "child.render is not a function".
|
|
3932
|
-
pi.registerMessageRenderer("workflow.run.start", (payload) =>
|
|
3933
|
-
dynamicTextRenderComponent(() => renderRunBanner(payload as RunStartPayload)),
|
|
3934
|
-
);
|
|
3935
|
-
pi.registerMessageRenderer("workflow.run.end", (payload) =>
|
|
3936
|
-
dynamicTextRenderComponent(() => renderRunSummary(payload as RunEndPayload)),
|
|
3937
|
-
);
|
|
3938
|
-
// Inline workflow-input form (Option C in the design conversation):
|
|
3939
|
-
// a sticky chat-history card driven by a custom EditorComponent. The
|
|
3940
|
-
// renderer reads form state from the module-level store keyed by
|
|
3941
|
-
// `details.formId`. Registered once; openInlineInputsForm() emits the
|
|
3942
|
-
// card via pi.sendMessage on each invocation.
|
|
3943
|
-
registerInlineFormRenderer(pi, deriveGraphTheme({}));
|
|
3944
|
-
|
|
3945
|
-
// Chat-scroll surfaces for /workflow run|list|status|status <id>. Bypasses
|
|
3946
|
-
// the default `notify`/`Text(paddingX=1)` path so band+card chrome
|
|
3947
|
-
// receives the *real* chat content width instead of a `cols - 2` heuristic.
|
|
3948
|
-
// See src/tui/chat-surface-message.ts for the contract.
|
|
3949
|
-
registerChatSurfaceRenderer(pi, deriveGraphTheme({}));
|
|
3950
|
-
}
|
|
3951
|
-
|
|
3952
|
-
// -------------------------------------------------------------------------
|
|
3953
|
-
// 4. Persistence: session_start restore + session_before_compact hook (§5.6, Phase D)
|
|
3954
|
-
// -------------------------------------------------------------------------
|
|
3955
|
-
if (typeof pi.on === "function") {
|
|
3956
|
-
pi.on("session_before_switch", async (event, ctx) => {
|
|
3957
|
-
const reason = typeof event === "object" && event !== null && "reason" in event
|
|
3958
|
-
? (event as { readonly reason?: string }).reason
|
|
3959
|
-
: undefined;
|
|
3960
|
-
if (reason !== "new" && reason !== "resume") return undefined;
|
|
3961
|
-
|
|
3962
|
-
// "In-flight" intentionally includes paused runs: session_start kills any run
|
|
3963
|
-
// without endedAt, so warn for the same set that would be stopped by the switch.
|
|
3964
|
-
const inFlightWorkflowCount = inFlightRunCount();
|
|
3965
|
-
if (inFlightWorkflowCount === 0) return undefined;
|
|
3966
|
-
|
|
3967
|
-
const confirmSessionSwitch = ctx?.ui?.confirm;
|
|
3968
|
-
// Headless/non-interactive callers intentionally fail open so automation cannot wedge.
|
|
3969
|
-
if (typeof confirmSessionSwitch !== "function") return undefined;
|
|
3970
|
-
|
|
3971
|
-
const workflowNoun = inFlightWorkflowCount === 1 ? "workflow" : "workflows";
|
|
3972
|
-
const actionLabel = reason === "new" ? "Start a new session" : "Resume another session";
|
|
3973
|
-
const messageLabel = reason === "new" ? "Starting a new session" : "Resuming another session";
|
|
3974
|
-
const promptTitle = `${actionLabel} and stop ${inFlightWorkflowCount} in-flight ${workflowNoun}?`;
|
|
3975
|
-
const promptMessage =
|
|
3976
|
-
`${messageLabel} will stop/kill ${inFlightWorkflowCount} in-flight ${workflowNoun} and clear workflow history tied to the current session.`;
|
|
3977
|
-
let shouldSwitchSession: boolean | undefined;
|
|
3978
|
-
try {
|
|
3979
|
-
shouldSwitchSession = await confirmSessionSwitch(promptTitle, promptMessage);
|
|
3980
|
-
} catch {
|
|
3981
|
-
// Keep headless/failed UI behavior fail-open so session automation cannot wedge.
|
|
3982
|
-
return undefined;
|
|
3983
|
-
}
|
|
3984
|
-
if (shouldSwitchSession) return undefined;
|
|
3985
|
-
|
|
3986
|
-
const cancelledLabel = reason === "new" ? "New session" : "Resume";
|
|
3987
|
-
ctx?.ui?.notify?.(`${cancelledLabel} cancelled; in-flight workflows were left unchanged.`, "info");
|
|
3988
|
-
return { cancel: true };
|
|
3989
|
-
});
|
|
3990
|
-
|
|
3991
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
3992
|
-
// Non-interactive (`-p` / `--mode json`) sessions keep the workflow tool
|
|
3993
|
-
// available for deterministic automation. Policy gates disable pickers
|
|
3994
|
-
// and make runtime human-input APIs unavailable.
|
|
3995
|
-
// Defense-in-depth for older/nonstandard hosts: remove only the
|
|
3996
|
-
// unavailable human-input tool from the active tool set.
|
|
3997
|
-
deAdvertiseAskUserQuestionWhenHeadless(pi, ctx?.hasUI);
|
|
3998
|
-
|
|
3999
|
-
// Workflow lifecycle is scoped to the originating chat session.
|
|
4000
|
-
// A new session inherits a clean store; any leftover live runs from a
|
|
4001
|
-
// previous session in the same pi process are killed (subprocess
|
|
4002
|
-
// aborted), then all stale snapshots are cleared. `restoreOnSessionStart`
|
|
4003
|
-
// below loads *this* session's persisted runs from disk.
|
|
4004
|
-
killAllRuns({
|
|
4005
|
-
store,
|
|
4006
|
-
cancellation: cancellationRegistry,
|
|
4007
|
-
persistence: persistenceRef.current,
|
|
4008
|
-
});
|
|
4009
|
-
store.clear();
|
|
4010
|
-
// Drop any inline input-form state from a previous session in this pi
|
|
4011
|
-
// process. A resumed/replaced session must not render a stale live form,
|
|
4012
|
-
// and rehydrated `workflows:input-form` cards then resolve to no backing
|
|
4013
|
-
// state so their renderer suppresses output (input widget hidden after
|
|
4014
|
-
// /resume).
|
|
4015
|
-
clearForms();
|
|
4016
|
-
resetWorkflowLifecycleNotificationState(lifecycleNotificationState);
|
|
4017
|
-
resetWorkflowHilAnswerNotificationState(hilAnswerNotificationState);
|
|
4018
|
-
stageControlRegistry.clear();
|
|
4019
|
-
|
|
4020
|
-
// pi-intercom session naming lives here so we don't trip the
|
|
4021
|
-
// loader's "Action methods cannot be called during extension
|
|
4022
|
-
// loading" guard.
|
|
4023
|
-
intercomParentSession = registerIntercomParentSession(pi);
|
|
4024
|
-
|
|
4025
|
-
// Ensure config+discovery are ready before restoring in-flight runs —
|
|
4026
|
-
// tunables must be resolved first.
|
|
4027
|
-
await discoveryPromise;
|
|
4028
|
-
lifecycleNotificationsActive = true;
|
|
4029
|
-
hilAnswerNotificationsActive = true;
|
|
4030
|
-
reinstallLifecycleNotifications();
|
|
4031
|
-
reinstallHilAnswerNotifications();
|
|
4032
|
-
if (ctx?.ui) {
|
|
4033
|
-
const diagnostics = formatStartupDiagnostics(configLoadRef.current, discoveryRef.current);
|
|
4034
|
-
if (diagnostics !== null) {
|
|
4035
|
-
ctx.ui.notify?.(diagnostics, "warning");
|
|
4036
|
-
}
|
|
4037
|
-
storeWidgetUnsubscribe?.();
|
|
4038
|
-
storeWidgetUnsubscribe = installStoreWidget({ ui: ctx.ui }, store);
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
|
-
const sessionManager = ctx?.sessionManager ?? pi.sessionManager;
|
|
4042
|
-
updateHostStageSessionDir(sessionManager);
|
|
4043
|
-
if (sessionManager) {
|
|
4044
|
-
const cfg = configLoadRef.current?.config;
|
|
4045
|
-
withWorkflowLifecycleNotificationsSuppressed(
|
|
4046
|
-
lifecycleNotificationState,
|
|
4047
|
-
() => {
|
|
4048
|
-
restoreOnSessionStart(
|
|
4049
|
-
sessionManager,
|
|
4050
|
-
{
|
|
4051
|
-
resumeInFlight: cfg?.resumeInFlight ?? "ask",
|
|
4052
|
-
persistRuns: cfg?.persistRuns ?? true,
|
|
4053
|
-
},
|
|
4054
|
-
store,
|
|
4055
|
-
);
|
|
4056
|
-
// The suppressed subscriber observes restore replay and marks matching
|
|
4057
|
-
// notices delivered. Seed explicitly as a defensive backstop for
|
|
4058
|
-
// runtimes without a lifecycle-notification subscriber installed.
|
|
4059
|
-
seedWorkflowLifecycleNotificationState(
|
|
4060
|
-
lifecycleNotificationState,
|
|
4061
|
-
store.snapshot(),
|
|
4062
|
-
);
|
|
4063
|
-
},
|
|
4064
|
-
);
|
|
4065
|
-
}
|
|
4066
|
-
});
|
|
4067
|
-
|
|
4068
|
-
installCompactionHook(pi, store);
|
|
4069
|
-
pi.on("session_shutdown", (event) => {
|
|
4070
|
-
// Only application exit owns workflow teardown. Session replacement
|
|
4071
|
-
// paths (reload/new/resume/fork) are handled by session_start restore
|
|
4072
|
-
// logic so they do not masquerade as app-exit kills.
|
|
4073
|
-
const reason = typeof event === "object" && event !== null && "reason" in event
|
|
4074
|
-
? (event as { readonly reason?: string }).reason
|
|
4075
|
-
: undefined;
|
|
4076
|
-
intercomControlUnsubscribe?.();
|
|
4077
|
-
intercomControlUnsubscribe = null;
|
|
4078
|
-
if (reason === "quit") {
|
|
4079
|
-
killAllRuns({
|
|
4080
|
-
store,
|
|
4081
|
-
cancellation: cancellationRegistry,
|
|
4082
|
-
persistence: persistenceRef.current,
|
|
4083
|
-
});
|
|
4084
|
-
stageControlRegistry.clear();
|
|
4085
|
-
}
|
|
4086
|
-
storeWidgetUnsubscribe?.();
|
|
4087
|
-
storeWidgetUnsubscribe = null;
|
|
4088
|
-
lifecycleNotificationsActive = false;
|
|
4089
|
-
hilAnswerNotificationsActive = false;
|
|
4090
|
-
lifecycleNotificationsUnsubscribe?.();
|
|
4091
|
-
lifecycleNotificationsUnsubscribe = null;
|
|
4092
|
-
hilAnswerNotificationsUnsubscribe?.();
|
|
4093
|
-
hilAnswerNotificationsUnsubscribe = null;
|
|
4094
|
-
});
|
|
4095
|
-
}
|
|
4096
|
-
|
|
4097
|
-
storeWidgetUnsubscribe = installStoreWidget(pi, store);
|
|
4098
|
-
installToolExecutionHooks(pi, store);
|
|
4099
|
-
|
|
4100
|
-
// -------------------------------------------------------------------------
|
|
4101
|
-
// 5. Register F2 keyboard shortcut — open graph overlay for active run.
|
|
4102
|
-
// Falls back to noop when pi.registerShortcut is absent (degraded runtime).
|
|
4103
|
-
// Existing API shape: (key, { description, handler }).
|
|
4104
|
-
//
|
|
4105
|
-
// Note: the historical `ctrl+h` toggle was removed when workflow runs
|
|
4106
|
-
// became background-by-default — a global toggle is no longer the
|
|
4107
|
-
// primary way to manage visibility. Inside the pane, press `h` to
|
|
4108
|
-
// hide (calls setHidden(true) on the overlay handle); re-open via
|
|
4109
|
-
// `F2` or `/workflow connect <id>`.
|
|
4110
|
-
// -------------------------------------------------------------------------
|
|
4111
|
-
if (typeof pi.registerShortcut === "function") {
|
|
4112
|
-
// Prefer the in-flight run; if nothing's active, fall back to the
|
|
4113
|
-
// most recently observed run so users can still review what just
|
|
4114
|
-
// finished without typing `/workflow resume <id>`.
|
|
4115
|
-
const openPane = (ctx?: PiCommandContext): void => {
|
|
4116
|
-
const activeRunId = store.activeRunId();
|
|
4117
|
-
const fallback = activeRunId ?? store.runs().at(-1)?.id ?? null;
|
|
4118
|
-
overlay.open(fallback, overlaySurfaceFromContext(ctx));
|
|
4119
|
-
};
|
|
4120
|
-
|
|
4121
|
-
pi.registerShortcut("F2", {
|
|
4122
|
-
description: "Open workflow orchestrator pane",
|
|
4123
|
-
handler: openPane,
|
|
4124
|
-
});
|
|
4125
|
-
}
|
|
4126
|
-
|
|
4127
|
-
// -------------------------------------------------------------------------
|
|
4128
|
-
// 6. Register sibling integrations (Phase G — §5.8, §5.9, §5.10)
|
|
4129
|
-
// All registration calls are guarded; no throw when sibling is absent.
|
|
4130
|
-
// Note: registerIntercomParentSession (pi-intercom session naming) calls
|
|
4131
|
-
// pi.setSessionName which is an action method — see session_start handler
|
|
4132
|
-
// above for that registration.
|
|
4133
|
-
// -------------------------------------------------------------------------
|
|
4134
|
-
|
|
4135
|
-
// pi-intercom: route subagent:control-intercom events to overlay/store callbacks.
|
|
4136
|
-
// buildIntercomCallbacks wires store.recordNotice, pi.ui.confirm (when present),
|
|
4137
|
-
// and pi.events.emit (when present) so escalations are never silently dropped.
|
|
4138
|
-
intercomControlUnsubscribe = subscribeIntercomControl(
|
|
4139
|
-
pi,
|
|
4140
|
-
buildIntercomCallbacks({
|
|
4141
|
-
store,
|
|
4142
|
-
emit:
|
|
4143
|
-
typeof pi.events?.emit === "function"
|
|
4144
|
-
? (event, payload) => pi.events!.emit!(event, payload)
|
|
4145
|
-
: undefined,
|
|
4146
|
-
confirm:
|
|
4147
|
-
typeof pi.ui?.confirm === "function"
|
|
4148
|
-
? (title, message) => pi.ui!.confirm!(title, message)
|
|
4149
|
-
: undefined,
|
|
4150
|
-
}),
|
|
4151
|
-
);
|
|
4152
|
-
|
|
4153
|
-
// -------------------------------------------------------------------------
|
|
4154
|
-
// 7. Suppress pi's optimistic "Working… (esc to interrupt)" loader
|
|
4155
|
-
// for our slash commands. Workflow commands are synchronous picker /
|
|
4156
|
-
// connect / inspect UIs, not streaming turns — the loader is noise
|
|
4157
|
-
// that pads chrome above the picker. The `on("input")` hook fires
|
|
4158
|
-
// BEFORE `startPendingSubmission`, so returning `{ action: "handled" }`
|
|
4159
|
-
// short-circuits the host before the loader starts. We dispatch the
|
|
4160
|
-
// registered handler ourselves. See `installInputInterceptor` for
|
|
4161
|
-
// the full rationale and host pipeline reference.
|
|
4162
|
-
// -------------------------------------------------------------------------
|
|
4163
|
-
installInputInterceptor(pi, workflowCommands);
|
|
4164
|
-
}
|
|
4165
|
-
|
|
4166
|
-
export default factory;
|
|
1
|
+
export { default } from "./extension-factory.js";
|
|
2
|
+
export {
|
|
3
|
+
DEFAULT_PROMPT_GUIDANCE,
|
|
4
|
+
WORKFLOW_TOOL_DESCRIPTION,
|
|
5
|
+
} from "./workflow-prompts.js";
|
|
6
|
+
export {
|
|
7
|
+
WORKFLOW_NON_INTERACTIVE_MESSAGE,
|
|
8
|
+
workflowPolicyFromContext,
|
|
9
|
+
} from "./workflow-policy.js";
|
|
10
|
+
export { makeExecuteWorkflowTool } from "./workflow-tool.js";
|
|
11
|
+
export {
|
|
12
|
+
WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE,
|
|
13
|
+
parseWorkflowArgs,
|
|
14
|
+
stripYesFlag,
|
|
15
|
+
tokenizeWorkflowArgs,
|
|
16
|
+
} from "./workflow-command-utils.js";
|
|
17
|
+
export { makeMcpPort, makePersistencePort } from "./workflow-ports.js";
|
|
18
|
+
export type {
|
|
19
|
+
ExtensionAPI,
|
|
20
|
+
PiAgentToolResult,
|
|
21
|
+
PiArgumentCompletion,
|
|
22
|
+
PiArgumentCompletionResult,
|
|
23
|
+
PiCommandContext,
|
|
24
|
+
PiCommandOptions,
|
|
25
|
+
PiExecuteContext,
|
|
26
|
+
PiFlagNamedOpts,
|
|
27
|
+
PiMessageRenderComponent,
|
|
28
|
+
PiMessageRenderOptions,
|
|
29
|
+
PiMessageRenderer,
|
|
30
|
+
PiMessageRendererResult,
|
|
31
|
+
PiModelContext,
|
|
32
|
+
PiRenderComponent,
|
|
33
|
+
PiRenderContext,
|
|
34
|
+
PiRenderResultOpts,
|
|
35
|
+
PiRuntimeModel,
|
|
36
|
+
PiRuntimeModelRegistry,
|
|
37
|
+
PiTheme,
|
|
38
|
+
PiToolOpts,
|
|
39
|
+
WorkflowExecuteToolResult,
|
|
40
|
+
WorkflowResourceInfo,
|
|
41
|
+
WorkflowToolArgs,
|
|
42
|
+
} from "./public-types.js";
|