@ashx-j/lunr-dev 0.2.16-dev.9.1 → 0.2.21-dev.12.1
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 +67 -1
- package/README.md +7 -1
- package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -0
- package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js +44 -19
- package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +1 -2
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-computer-use.d.ts +3 -0
- package/dist/builtin-extensions/lunr-computer-use.d.ts.map +1 -0
- package/dist/builtin-extensions/lunr-computer-use.js +158 -0
- package/dist/builtin-extensions/lunr-computer-use.js.map +1 -0
- package/dist/builtin-extensions/lunr-todos.d.ts +6 -5
- package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-todos.js +9 -7
- package/dist/builtin-extensions/lunr-todos.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts +6 -4
- package/dist/builtin-extensions/pi-intercom/broker/spawn.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/broker/spawn.js +114 -61
- package/dist/builtin-extensions/pi-intercom/broker/spawn.js.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-intercom/index.js +360 -351
- package/dist/builtin-extensions/pi-intercom/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js +10 -3
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts +5 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js +26 -4
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.js +37 -27
- package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts +6 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js +33 -8
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +8 -6
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +179 -79
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +18 -8
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +44 -15
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +4 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +24 -14
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts +8 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js +247 -18
- package/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/result-intercom.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/result-intercom.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/result-intercom.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/result-intercom.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts +29 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js +179 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts +89 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js +541 -0
- package/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +11 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +38 -12
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +3 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +35 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts +7 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js +26 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/notify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js +55 -38
- package/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts +100 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +46 -31
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +3 -6
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +64 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/top-level-async.d.ts +15 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/top-level-async.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/top-level-async.js +14 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/top-level-async.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +7 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +21 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.d.ts +10 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js +38 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +0 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +74 -41
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +75 -18
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/completion-guard.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/completion-guard.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/completion-guard.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/completion-guard.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +13 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +67 -11
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +7 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js +5 -10
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/async-guidance.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/async-guidance.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/async-guidance.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/async-guidance.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +3 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +68 -11
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +12 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +21 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +21 -4
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +7 -0
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +11 -7
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +6 -0
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +46 -29
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +47 -4
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +428 -431
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/register-main.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts +2 -13
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js +5 -91
- package/dist/builtin-extensions/pi-subagents/src/watchdog/tool-actions.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +103 -102
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/computer-use/adapter.d.ts +23 -0
- package/dist/core/computer-use/adapter.d.ts.map +1 -0
- package/dist/core/computer-use/adapter.js +116 -0
- package/dist/core/computer-use/adapter.js.map +1 -0
- package/dist/core/computer-use/image.d.ts +26 -0
- package/dist/core/computer-use/image.d.ts.map +1 -0
- package/dist/core/computer-use/image.js +64 -0
- package/dist/core/computer-use/image.js.map +1 -0
- package/dist/core/computer-use/lease.d.ts +18 -0
- package/dist/core/computer-use/lease.d.ts.map +1 -0
- package/dist/core/computer-use/lease.js +129 -0
- package/dist/core/computer-use/lease.js.map +1 -0
- package/dist/core/computer-use/macos-runtime.d.ts +14 -0
- package/dist/core/computer-use/macos-runtime.d.ts.map +1 -0
- package/dist/core/computer-use/macos-runtime.js +148 -0
- package/dist/core/computer-use/macos-runtime.js.map +1 -0
- package/dist/core/computer-use/policy.d.ts +19 -0
- package/dist/core/computer-use/policy.d.ts.map +1 -0
- package/dist/core/computer-use/policy.js +62 -0
- package/dist/core/computer-use/policy.js.map +1 -0
- package/dist/core/computer-use/release.generated.d.ts +31 -0
- package/dist/core/computer-use/release.generated.d.ts.map +1 -0
- package/dist/core/computer-use/release.generated.js +36 -0
- package/dist/core/computer-use/release.generated.js.map +1 -0
- package/dist/core/computer-use/runtime.d.ts +13 -0
- package/dist/core/computer-use/runtime.d.ts.map +1 -0
- package/dist/core/computer-use/runtime.js +158 -0
- package/dist/core/computer-use/runtime.js.map +1 -0
- package/dist/core/computer-use/schemas.d.ts +91 -0
- package/dist/core/computer-use/schemas.d.ts.map +1 -0
- package/dist/core/computer-use/schemas.js +71 -0
- package/dist/core/computer-use/schemas.js.map +1 -0
- package/dist/core/computer-use/windows-desktop.d.ts +3 -0
- package/dist/core/computer-use/windows-desktop.d.ts.map +1 -0
- package/dist/core/computer-use/windows-desktop.js +48 -0
- package/dist/core/computer-use/windows-desktop.js.map +1 -0
- package/dist/core/computer-use/workflow.d.ts +32 -0
- package/dist/core/computer-use/workflow.d.ts.map +1 -0
- package/dist/core/computer-use/workflow.js +341 -0
- package/dist/core/computer-use/workflow.js.map +1 -0
- package/dist/core/customize.d.ts +2 -0
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +3 -0
- package/dist/core/customize.js.map +1 -1
- package/dist/core/keybindings.d.ts +2 -2
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +2 -2
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-runtime.d.ts +0 -3
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +1 -10
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions.d.ts +2 -1
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +31 -11
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +9 -5
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/rollback.d.ts.map +1 -1
- package/dist/core/rollback.js +13 -90
- package/dist/core/rollback.js.map +1 -1
- package/dist/core/runtime-bridges.d.ts.map +1 -1
- package/dist/core/runtime-bridges.js +0 -2
- package/dist/core/runtime-bridges.js.map +1 -1
- package/dist/core/session-manager.d.ts +0 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +21 -79
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +30 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/subagent-cancellation.d.ts +21 -0
- package/dist/core/subagent-cancellation.d.ts.map +1 -0
- package/dist/core/subagent-cancellation.js +53 -0
- package/dist/core/subagent-cancellation.js.map +1 -0
- package/dist/core/subagent-spinner-setting.d.ts +6 -0
- package/dist/core/subagent-spinner-setting.d.ts.map +1 -0
- package/dist/core/subagent-spinner-setting.js +12 -0
- package/dist/core/subagent-spinner-setting.js.map +1 -0
- package/dist/core/subagent-spinner.d.ts +4 -0
- package/dist/core/subagent-spinner.d.ts.map +1 -0
- package/dist/core/subagent-spinner.js +6 -0
- package/dist/core/subagent-spinner.js.map +1 -0
- package/dist/dev-cli.js +0 -0
- package/dist/gateway/agent-bridge.d.ts +6 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +23 -6
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/cron.d.ts +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +23 -7
- package/dist/gateway/cron.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +12 -18
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +4 -2
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +23 -32
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/processes-selector.d.ts +2 -3
- package/dist/modes/interactive/components/processes-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/processes-selector.js +5 -10
- package/dist/modes/interactive/components/processes-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +93 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +12 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/extension-widget-order.d.ts +8 -0
- package/dist/modes/interactive/extension-widget-order.d.ts.map +1 -0
- package/dist/modes/interactive/extension-widget-order.js +37 -0
- package/dist/modes/interactive/extension-widget-order.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +58 -26
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/thinking-level-slash.d.ts +4 -0
- package/dist/modes/interactive/thinking-level-slash.d.ts.map +1 -0
- package/dist/modes/interactive/thinking-level-slash.js +23 -0
- package/dist/modes/interactive/thinking-level-slash.js.map +1 -0
- package/dist/node-runtime/adapter-AZMY335J.js +279 -0
- package/dist/node-runtime/{agent-session-services-IFJMSX7Z.js → agent-session-services-QANFGM2V.js} +15 -11
- package/dist/node-runtime/{builtin-extensions-LYZ3BFWQ.js → builtin-extensions-SRCYQPZ6.js} +5 -3
- package/dist/node-runtime/chunk-2IDTZAG5.js +1415 -0
- package/dist/node-runtime/chunk-3ONQTOMR.js +68 -0
- package/dist/node-runtime/{chunk-TQNSPERU.js → chunk-5SQDLSZJ.js} +1 -1
- package/dist/node-runtime/chunk-5ZH3ZFIZ.js +308 -0
- package/dist/node-runtime/{chunk-PBC2Y6GS.js → chunk-6UB6NKA3.js} +29 -72
- package/dist/node-runtime/{chunk-A2KQXUJD.js → chunk-7AFOFSDY.js} +1 -1
- package/dist/node-runtime/chunk-A3KMVBZV.js +60 -0
- package/dist/node-runtime/{chunk-N77MY65L.js → chunk-BJ6H7DPI.js} +25 -25
- package/dist/node-runtime/{chunk-PGAJ5MO5.js → chunk-BYQ2MOFI.js} +6 -6
- package/dist/node-runtime/{chunk-QH42CDX3.js → chunk-CZUBYPFP.js} +234 -124
- package/dist/node-runtime/{chunk-LZAW4ZX3.js → chunk-D466UAID.js} +34 -13
- package/dist/node-runtime/{chunk-ZKMFUD3Q.js → chunk-GT5F3OKM.js} +3 -3
- package/dist/node-runtime/chunk-H2BI7G7T.js +73 -0
- package/dist/node-runtime/{chunk-5P7PZMRU.js → chunk-HRS4HMDX.js} +1 -1
- package/dist/node-runtime/{chunk-IPA627GP.js → chunk-HXJS2PJM.js} +4 -4
- package/dist/node-runtime/chunk-JZHEUQRL.js +180 -0
- package/dist/node-runtime/chunk-LISUTZS3.js +19 -0
- package/dist/node-runtime/chunk-LOYUC2ID.js +2185 -0
- package/dist/node-runtime/{chunk-2QKLKMKC.js → chunk-LTXUQJI4.js} +1 -1
- package/dist/node-runtime/{chunk-YF63P5ZT.js → chunk-LTYWTR3V.js} +1 -426
- package/dist/node-runtime/{chunk-MKKH27PH.js → chunk-LWJXTA6Z.js} +274 -2416
- package/dist/node-runtime/chunk-MW2XJZIK.js +108 -0
- package/dist/node-runtime/{chunk-CDFZEWPU.js → chunk-N3PNL74S.js} +537 -262
- package/dist/node-runtime/{chunk-4TLO4PO2.js → chunk-U6C7VTR5.js} +7 -1401
- package/dist/node-runtime/chunk-URD2SLIT.js +1019 -0
- package/dist/node-runtime/{chunk-HQCKFM2O.js → chunk-VGYZ3APQ.js} +3 -0
- package/dist/node-runtime/{chunk-AJX357CL.js → chunk-VQ4UBWSA.js} +30 -1013
- package/dist/node-runtime/{chunk-F4VQFJI2.js → chunk-VTGEKB7R.js} +2 -2
- package/dist/node-runtime/{chunk-AD6VXAO7.js → chunk-VTPM5V35.js} +5 -100
- package/dist/node-runtime/chunk-W3SILANP.js +24 -0
- package/dist/node-runtime/{chunk-WOVTOV5P.js → chunk-XAUQOKYK.js} +421 -63
- package/dist/node-runtime/{chunk-ECD5L7YI.js → chunk-XSRCAQK2.js} +390 -16
- package/dist/node-runtime/{chunk-PCGNAY2O.js → chunk-ZOIIMEN6.js} +54 -433
- package/dist/node-runtime/{chunk-EDBJNRSM.js → chunk-ZVSORYRM.js} +1 -1
- package/dist/node-runtime/cli-runtime.js +1 -1
- package/dist/node-runtime/{command-L3LAHDIH.js → command-ZURZJDXF.js} +1 -1
- package/dist/node-runtime/{commands-RL5YBW5I.js → commands-BZGSLIP7.js} +4 -2
- package/dist/node-runtime/{customize-XEXL2DGQ.js → customize-LF5VST47.js} +1 -1
- package/dist/node-runtime/{direct-tool-executor-JVDXTO7A.js → direct-tool-executor-BSZDHIYR.js} +7 -4
- package/dist/node-runtime/{export-html-KR26FOUZ.js → export-html-E4DT6ZJQ.js} +1 -1
- package/dist/node-runtime/{gateway-X2TI5X7F.js → gateway-FWHRIBK5.js} +24 -369
- package/dist/node-runtime/index.js +49 -42
- package/dist/node-runtime/{init-NJV2T55N.js → init-DVJUAOUO.js} +4 -2
- package/dist/node-runtime/{interactive-mode-KOM35YF2.js → interactive-mode-BBASNWHN.js} +23 -17
- package/dist/node-runtime/{interactive-view-U6OILKF3.js → interactive-view-N6F4KUIT.js} +3 -5
- package/dist/node-runtime/lunr-computer-use-TJNDAMWM.js +135 -0
- package/dist/node-runtime/{lunr-cron-YJ5UHYRD.js → lunr-cron-J64I72C6.js} +7 -1
- package/dist/node-runtime/main.js +25 -20
- package/dist/node-runtime/{mcp-auth-flow-QIXHW6QN.js → mcp-auth-flow-YL6RWPYG.js} +2 -1
- package/dist/node-runtime/{package-manager-cli-TZZHJCVI.js → package-manager-cli-VMYX4Y2S.js} +10 -7
- package/dist/node-runtime/{pi-intercom-EEMBGQID.js → pi-intercom-NV2LW6X7.js} +108 -87
- package/dist/node-runtime/{pi-mcp-adapter-QFB37AVN.js → pi-mcp-adapter-JLB5YL2F.js} +31 -25
- package/dist/node-runtime/{pi-subagents-7XJ4H53P.js → pi-subagents-WEHV3W7H.js} +1321 -631
- package/dist/node-runtime/{pi-web-access-DPGAVKOA.js → pi-web-access-FN5YC5T6.js} +67 -64
- package/dist/node-runtime/{proxy-modes-HEEFK4KC.js → proxy-modes-OR7ISBXK.js} +7 -4
- package/dist/node-runtime/rpc-entry.js +25 -20
- package/dist/node-runtime/runtime-3SB5ATHQ.js +21 -0
- package/dist/node-runtime/{runtime-bridges-PPHNBFWL.js → runtime-bridges-2VQTLPOZ.js} +3 -5
- package/dist/node-runtime/{session-manager-MQNBYACL.js → session-manager-QEMZBMTM.js} +3 -5
- package/dist/node-runtime/{session-selector-5AZLJS6U.js → session-selector-URVJLOTK.js} +2 -2
- package/dist/node-runtime/{settings-manager-5LF2VQWC.js → settings-manager-3CCU326G.js} +4 -1
- package/dist/node-runtime/{src-Y7JSCK64.js → src-BPQFJR76.js} +27 -7
- package/dist/node-runtime/{subagent-executor-5RNDEPIJ.js → subagent-executor-CXKXQDHH.js} +189 -284
- package/dist/node-runtime/{update-cli-A253SZ7P.js → update-cli-NM7B4CKL.js} +4 -1
- package/dist/node-runtime/workflow-C26QCUTW.js +468 -0
- package/dist/rpc.d.ts +3 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +18 -0
- package/dist/rpc.js.map +1 -0
- package/dist/startup/interactive-view.d.ts.map +1 -1
- package/dist/startup/interactive-view.js +1 -2
- package/dist/startup/interactive-view.js.map +1 -1
- package/docs/computer-use.md +242 -0
- package/docs/development.md +0 -32
- package/docs/features.md +24 -6
- package/docs/interactive-startup.md +10 -3
- package/docs/keybindings.md +5 -3
- package/docs/settings.md +3 -2
- package/docs/terminal-setup.md +1 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/install-lock/package-lock.json +3827 -0
- package/install-lock/package.json +18 -0
- package/native/computer-use/LICENSE.md +21 -0
- package/npm-shrinkwrap.json +3808 -0
- package/package.json +16 -10
- package/dist/builtin-extensions/lunr-settings-tools.d.ts +0 -4
- package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +0 -1
- package/dist/builtin-extensions/lunr-settings-tools.js +0 -120
- package/dist/builtin-extensions/lunr-settings-tools.js.map +0 -1
- package/dist/core/settings-tools-bridge.d.ts +0 -35
- package/dist/core/settings-tools-bridge.d.ts.map +0 -1
- package/dist/core/settings-tools-bridge.js +0 -56
- package/dist/core/settings-tools-bridge.js.map +0 -1
- package/dist/node-runtime/chunk-AHSTJBIB.js +0 -64
- package/dist/startup/interactive-shell.d.ts +0 -55
- package/dist/startup/interactive-shell.d.ts.map +0 -1
- package/dist/startup/interactive-shell.js +0 -264
- package/dist/startup/interactive-shell.js.map +0 -1
- package/dist/node-runtime/{chunk-YSKSB3BJ.js → chunk-CH6OL6P2.js} +2 -2
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
ASYNC_DIR,
|
|
7
7
|
DEFAULT_ARTIFACT_CONFIG,
|
|
8
8
|
INTERCOM_DETACH_REQUEST_EVENT,
|
|
9
|
-
MAX_WIDGET_JOBS,
|
|
10
9
|
POLL_INTERVAL_MS,
|
|
11
10
|
RESULTS_DIR,
|
|
12
11
|
SLASH_RESULT_TYPE,
|
|
@@ -17,6 +16,7 @@ import {
|
|
|
17
16
|
SLASH_SUBAGENT_UPDATE_EVENT,
|
|
18
17
|
SLASH_TEXT_RESULT_TYPE,
|
|
19
18
|
SUBAGENT_ASYNC_COMPLETE_EVENT,
|
|
19
|
+
SUBAGENT_ASYNC_GUIDANCE,
|
|
20
20
|
SUBAGENT_ASYNC_STARTED_EVENT,
|
|
21
21
|
SUBAGENT_CHILD_ENV,
|
|
22
22
|
SUBAGENT_CONTROL_EVENT,
|
|
@@ -29,10 +29,10 @@ import {
|
|
|
29
29
|
SUBAGENT_STEERING_NOTICE_EVENT,
|
|
30
30
|
TEMP_ROOT_DIR,
|
|
31
31
|
WIDGET_KEY,
|
|
32
|
-
aggregateStepStatus,
|
|
33
32
|
assertJsonSchemaObject,
|
|
34
33
|
attachNestedChildrenToResultChildren,
|
|
35
34
|
buildSubagentResultIntercomPayload,
|
|
35
|
+
childRowLabel,
|
|
36
36
|
cleanupAllArtifactDirs,
|
|
37
37
|
cleanupOldArtifacts,
|
|
38
38
|
cleanupOldChainDirs,
|
|
@@ -40,16 +40,16 @@ import {
|
|
|
40
40
|
compactNestedResultChildren,
|
|
41
41
|
deliverStopRequest,
|
|
42
42
|
deliverSubagentResultIntercomEvent,
|
|
43
|
-
flatToLogicalStepIndex,
|
|
44
43
|
formatActivityLabel,
|
|
45
44
|
formatAgentRunningLabel,
|
|
46
45
|
formatAsyncRunProgressLabel,
|
|
47
46
|
formatAsyncRunTranscript,
|
|
47
|
+
formatCompactModelBadge,
|
|
48
48
|
formatControlNoticeMessage,
|
|
49
49
|
formatDuration,
|
|
50
50
|
formatModelSelection,
|
|
51
51
|
formatNestedAggregate,
|
|
52
|
-
|
|
52
|
+
formatNestedResultLines,
|
|
53
53
|
formatTokens,
|
|
54
54
|
formatToolCall,
|
|
55
55
|
formatUsage,
|
|
@@ -60,38 +60,54 @@ import {
|
|
|
60
60
|
getSingleResultOutput,
|
|
61
61
|
handleSubagentControlNotice,
|
|
62
62
|
hasLiveNestedDescendants,
|
|
63
|
+
isAsyncSubagentExecution,
|
|
63
64
|
listAsyncRuns,
|
|
65
|
+
normalizeAsyncLaunchConfig,
|
|
64
66
|
normalizeParallelGroups,
|
|
65
67
|
projectNestedRegistryForRoot,
|
|
66
68
|
readStatus,
|
|
69
|
+
readSteerCapability,
|
|
67
70
|
reconcileAsyncRun,
|
|
68
71
|
reconcileNestedAsyncDescendants,
|
|
69
72
|
registerMainWatchdog,
|
|
73
|
+
requestAsyncSteer,
|
|
70
74
|
resolveAsyncRunLocation,
|
|
71
75
|
resolveCurrentSessionId,
|
|
76
|
+
resolveSubagentRequestParams,
|
|
72
77
|
resolveSubagentResultStatus,
|
|
78
|
+
resolveSubagentRunId,
|
|
73
79
|
resolveTurnBudgetConfig,
|
|
74
80
|
resolveWaitToolConfig,
|
|
75
81
|
resolveWatchPath,
|
|
76
82
|
sanitizeChildDescription,
|
|
77
83
|
sanitizeSummary,
|
|
78
84
|
shortenPath,
|
|
85
|
+
subagentLaunchRunsAsync,
|
|
79
86
|
summarizeAsyncStatus,
|
|
80
87
|
updateAsyncJobNestedProjection,
|
|
81
88
|
validateAcceptanceInput,
|
|
82
89
|
validateExecutionAcceptance,
|
|
83
90
|
validateToolBudgetConfig,
|
|
84
91
|
writeAtomicJson
|
|
85
|
-
} from "./chunk-
|
|
86
|
-
import
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
} from "./chunk-N3PNL74S.js";
|
|
93
|
+
import {
|
|
94
|
+
createSubagentCancellation,
|
|
95
|
+
getSubagentSpinnerDefinition,
|
|
96
|
+
registerSubagentCancellation
|
|
97
|
+
} from "./chunk-A3KMVBZV.js";
|
|
98
|
+
import "./chunk-5ZH3ZFIZ.js";
|
|
99
|
+
import "./chunk-ZVSORYRM.js";
|
|
100
|
+
import "./chunk-GT5F3OKM.js";
|
|
91
101
|
import "./chunk-53YJI7JU.js";
|
|
92
102
|
import "./chunk-GZQHMEWL.js";
|
|
93
103
|
import "./chunk-ZCHMJ34K.js";
|
|
104
|
+
import "./chunk-LISUTZS3.js";
|
|
94
105
|
import "./chunk-FVDOXRUD.js";
|
|
106
|
+
import "./chunk-MW2XJZIK.js";
|
|
107
|
+
import "./chunk-D466UAID.js";
|
|
108
|
+
import "./chunk-M3LZLQW2.js";
|
|
109
|
+
import "./chunk-VTPM5V35.js";
|
|
110
|
+
import "./chunk-3ONQTOMR.js";
|
|
95
111
|
import "./chunk-RQ2Q5IYR.js";
|
|
96
112
|
import {
|
|
97
113
|
keyText
|
|
@@ -104,10 +120,10 @@ import "./chunk-Q4Q6D4IY.js";
|
|
|
104
120
|
import "./chunk-BRJX2PRC.js";
|
|
105
121
|
|
|
106
122
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/extension/index.js
|
|
107
|
-
import { randomUUID as
|
|
108
|
-
import * as
|
|
123
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
124
|
+
import * as fs10 from "node:fs";
|
|
109
125
|
import * as os from "node:os";
|
|
110
|
-
import * as
|
|
126
|
+
import * as path12 from "node:path";
|
|
111
127
|
import { Box, Container as Container2, Spacer as Spacer2, Text as Text2, truncateToWidth as truncateToWidth2, visibleWidth as visibleWidth3, wrapTextWithAnsi as wrapTextWithAnsi2 } from "@ashx-j/lunr-tui";
|
|
112
128
|
|
|
113
129
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/tui/render.js
|
|
@@ -170,7 +186,11 @@ function wrapPlainText(text, maxWidth) {
|
|
|
170
186
|
}
|
|
171
187
|
return lines;
|
|
172
188
|
}
|
|
173
|
-
var
|
|
189
|
+
var STATIC_RUNNING_GLYPH = "\u25CF", SUBAGENT_PAINT_INTERVAL_MS = 80;
|
|
190
|
+
function selectedSubagentSpinner() {
|
|
191
|
+
let bridge = globalThis[/* @__PURE__ */ Symbol.for("@lunr/customize")];
|
|
192
|
+
return getSubagentSpinnerDefinition(bridge?.getSubagentSpinner?.() ?? "braille");
|
|
193
|
+
}
|
|
174
194
|
function runningSeed(...values) {
|
|
175
195
|
let seed;
|
|
176
196
|
for (let value of values)
|
|
@@ -178,7 +198,14 @@ function runningSeed(...values) {
|
|
|
178
198
|
return seed;
|
|
179
199
|
}
|
|
180
200
|
function runningGlyph(seed) {
|
|
181
|
-
|
|
201
|
+
if (seed === void 0)
|
|
202
|
+
return STATIC_RUNNING_GLYPH;
|
|
203
|
+
let frames = selectedSubagentSpinner().frames;
|
|
204
|
+
return frames[Math.abs(seed) % frames.length];
|
|
205
|
+
}
|
|
206
|
+
function foregroundSpinnerFrame(timerFrame) {
|
|
207
|
+
let { interval } = selectedSubagentSpinner();
|
|
208
|
+
return Math.floor(Math.max(0, timerFrame) * SUBAGENT_PAINT_INTERVAL_MS / interval);
|
|
182
209
|
}
|
|
183
210
|
function progressRunningSeed(progress) {
|
|
184
211
|
if (progress)
|
|
@@ -238,6 +265,16 @@ function statJoin(theme, parts) {
|
|
|
238
265
|
function formatTokenStat(tokens) {
|
|
239
266
|
return `${formatTokens(tokens)} token`;
|
|
240
267
|
}
|
|
268
|
+
function usageTokenTotal(usage) {
|
|
269
|
+
return usage ? (usage.input ?? 0) + (usage.output ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0) : 0;
|
|
270
|
+
}
|
|
271
|
+
function compactResultTokens(result2) {
|
|
272
|
+
let progress = result2.progress || result2.progressSummary;
|
|
273
|
+
if (progress && progress.tokens > 0)
|
|
274
|
+
return progress.tokens;
|
|
275
|
+
let fromUsage = usageTokenTotal(result2.usage);
|
|
276
|
+
return fromUsage > 0 ? fromUsage : progress?.tokens ?? 0;
|
|
277
|
+
}
|
|
241
278
|
function formatToolUseStat(count) {
|
|
242
279
|
return `${count} tool use${count === 1 ? "" : "s"}`;
|
|
243
280
|
}
|
|
@@ -248,7 +285,10 @@ function formatTotalCostStat(totalCost) {
|
|
|
248
285
|
return totalCost.inputTokens && parts.push(`in:${formatTokens(totalCost.inputTokens)}`), totalCost.outputTokens && parts.push(`out:${formatTokens(totalCost.outputTokens)}`), totalCost.costUsd && parts.push(`$${totalCost.costUsd.toFixed(4)}`), parts.join(" ");
|
|
249
286
|
}
|
|
250
287
|
function liveDurationMs(progress, running, now) {
|
|
251
|
-
|
|
288
|
+
if (!progress)
|
|
289
|
+
return 0;
|
|
290
|
+
let durationMs = progress.durationMs ?? 0;
|
|
291
|
+
return !running || progress.lastActivityAt === void 0 ? durationMs : durationMs + Math.max(0, now - progress.lastActivityAt);
|
|
252
292
|
}
|
|
253
293
|
function formatProgressStats(theme, progress, includeDuration = !0, options = {}) {
|
|
254
294
|
if (!progress)
|
|
@@ -288,13 +328,17 @@ function resultStatusLine(result2, output) {
|
|
|
288
328
|
function resultGlyph(result2, output, theme, running = result2.progress?.status === "running", seed = progressRunningSeed(result2.progress ?? result2.progressSummary), frame) {
|
|
289
329
|
return running ? frame !== void 0 ? theme.fg("accent", runningGlyph((seed ?? 0) + frame)) : theme.fg("accent", runningGlyph(seed)) : result2.detached || result2.stopped || result2.interrupted ? theme.fg("warning", "\u25A0") : result2.exitCode !== 0 ? theme.fg("error", "\u2717") : hasEmptyTextOutputWithoutOutputTarget(result2.task, output) ? theme.fg("warning", "\u2713") : theme.fg("success", "\u2713");
|
|
290
330
|
}
|
|
291
|
-
function
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
331
|
+
function formatCompactRowStats(tokens, durationMs) {
|
|
332
|
+
return `${formatTokenStat(tokens)} \xB7 ${durationMs > 0 ? formatDuration(durationMs) : "0ms"}`;
|
|
333
|
+
}
|
|
334
|
+
function formatCompactSubagentRow(theme, width, parts) {
|
|
335
|
+
let stats = formatCompactRowStats(parts.tokens, parts.durationMs), body = [
|
|
336
|
+
`${parts.prefix ?? ""}${parts.glyph} ${themeBold(theme, parts.description)}`,
|
|
337
|
+
parts.modelBadge ? theme.fg("dim", parts.modelBadge) : "",
|
|
338
|
+
theme.fg("dim", stats),
|
|
339
|
+
parts.terminalStatus ? theme.fg("dim", parts.terminalStatus) : ""
|
|
340
|
+
].filter(Boolean).join(` ${theme.fg("dim", "\xB7")} `);
|
|
341
|
+
return truncLine(body, width);
|
|
298
342
|
}
|
|
299
343
|
function widgetRenderKey(job) {
|
|
300
344
|
return JSON.stringify({
|
|
@@ -348,14 +392,12 @@ function widgetStepsRunningSeed(steps) {
|
|
|
348
392
|
function widgetJobRunningSeed(job) {
|
|
349
393
|
return runningSeed(job.currentStep, job.runningSteps, widgetStepsRunningSeed(job.steps));
|
|
350
394
|
}
|
|
351
|
-
function
|
|
352
|
-
let
|
|
353
|
-
|
|
354
|
-
seed = runningSeed(seed, widgetJobRunningSeed(job));
|
|
355
|
-
return seed;
|
|
395
|
+
function widgetAnimFrame(now = Date.now()) {
|
|
396
|
+
let definition = selectedSubagentSpinner();
|
|
397
|
+
return Math.floor(now / definition.interval) % definition.frames.length;
|
|
356
398
|
}
|
|
357
|
-
function widgetStatusGlyph(job, theme) {
|
|
358
|
-
return job.status === "running" ? theme.fg("accent", runningGlyph(widgetJobRunningSeed(job))) : job.status === "queued" ? theme.fg("muted", "\u25E6") : job.status === "complete" ? theme.fg("success", "\u2713") : job.status === "paused" || job.status === "stopped" ? theme.fg("warning", "\u25A0") : theme.fg("error", "\u2717");
|
|
399
|
+
function widgetStatusGlyph(job, theme, now = Date.now()) {
|
|
400
|
+
return job.status === "running" ? theme.fg("accent", runningGlyph((widgetJobRunningSeed(job) ?? 0) + widgetAnimFrame(now))) : job.status === "queued" ? theme.fg("muted", "\u25E6") : job.status === "complete" ? theme.fg("success", "\u2713") : job.status === "paused" || job.status === "stopped" ? theme.fg("warning", "\u25A0") : theme.fg("error", "\u2717");
|
|
359
401
|
}
|
|
360
402
|
function widgetStepGlyph(status, theme, seed) {
|
|
361
403
|
return status === "running" ? theme.fg("accent", runningGlyph(seed)) : status === "complete" || status === "completed" ? theme.fg("success", "\u2713") : status === "failed" ? theme.fg("error", "\u2717") : status === "paused" || status === "stopped" ? theme.fg("warning", "\u25A0") : theme.fg("muted", "\u25E6");
|
|
@@ -363,48 +405,6 @@ function widgetStepGlyph(status, theme, seed) {
|
|
|
363
405
|
function widgetStepStatus(status, theme) {
|
|
364
406
|
return status === "running" ? theme.fg("accent", "running") : status === "complete" || status === "completed" ? theme.fg("success", "complete") : status === "failed" ? theme.fg("error", "failed") : status === "paused" ? theme.fg("warning", "paused") : status === "stopped" ? theme.fg("warning", "stopped") : theme.fg("dim", status);
|
|
365
407
|
}
|
|
366
|
-
function widgetStepActivity(step, snapshotNow) {
|
|
367
|
-
let facts = [];
|
|
368
|
-
step.currentTool && step.currentToolStartedAt !== void 0 && snapshotNow !== void 0 ? facts.push(`${step.currentTool} ${formatDuration(Math.max(0, snapshotNow - step.currentToolStartedAt))}`) : step.currentTool && facts.push(step.currentTool), step.currentPath && facts.push(shortenPath(step.currentPath)), step.turnCount !== void 0 && facts.push(`${step.turnCount} turns`), step.toolCount !== void 0 && facts.push(`${step.toolCount} tools`), step.tokens?.total && facts.push(formatTokenStat(step.tokens.total));
|
|
369
|
-
let activity = buildLiveStatusLine(step, snapshotNow);
|
|
370
|
-
return activity && facts.length ? `${activity} \xB7 ${facts.join(" \xB7 ")}` : activity || facts.join(" \xB7 ");
|
|
371
|
-
}
|
|
372
|
-
function widgetChainDetails(job, theme, expanded = !1, width = getTermWidth()) {
|
|
373
|
-
if (!job.steps?.length)
|
|
374
|
-
return [];
|
|
375
|
-
let total = job.chainStepCount ?? job.steps.length, lines = [];
|
|
376
|
-
for (let span of buildAsyncChainStepSpans(total, job.steps.length, job.parallelGroups)) {
|
|
377
|
-
let steps = job.steps.slice(span.start, span.start + span.count);
|
|
378
|
-
if (span.isParallel) {
|
|
379
|
-
let status = aggregateStepStatus(steps);
|
|
380
|
-
lines.push(` ${widgetStepGlyph(status, theme, widgetStepsRunningSeed(steps))} Step ${span.stepIndex + 1}/${total}: ${themeBold(theme, "parallel group")} ${theme.fg("dim", "\xB7")} ${theme.fg("dim", formatParallelOutcome(steps, span.count))}`);
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
let step = steps[0];
|
|
384
|
-
if (!step) {
|
|
385
|
-
lines.push(` ${theme.fg("dim", `\u25E6 Step ${span.stepIndex + 1}/${total}: pending`)}`);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
lines.push(...foregroundStyleWidgetStepLines(job, theme, step, "Step", span.stepIndex + 1, total, expanded, width));
|
|
389
|
-
}
|
|
390
|
-
return lines;
|
|
391
|
-
}
|
|
392
|
-
function widgetParallelAgentDetails(job, theme, expanded = !1, width = getTermWidth()) {
|
|
393
|
-
if (!job.steps?.length)
|
|
394
|
-
return [];
|
|
395
|
-
if (job.mode !== "parallel" && job.mode !== "chain")
|
|
396
|
-
return [];
|
|
397
|
-
if (job.mode === "chain" && !job.activeParallelGroup && job.parallelGroups?.length)
|
|
398
|
-
return widgetChainDetails(job, theme, expanded, width);
|
|
399
|
-
let total = job.stepsTotal ?? job.steps.length, lines = [];
|
|
400
|
-
for (let [index, step] of job.steps.entries()) {
|
|
401
|
-
let marker = index === job.steps.length - 1 ? "\u2514" : "\u251C", activity = widgetStepActivity(step, job.updatedAt), itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step", modelDisplay = modelThinkingBadge(theme, step.model, step.thinking, step.modelSelection);
|
|
402
|
-
lines.push(` ${theme.fg("dim", `${marker} ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${step.agent} \xB7 ${widgetStepStatus(step.status, theme)}${modelDisplay}${activity ? ` \xB7 ${activity}` : ""}`)}`);
|
|
403
|
-
for (let nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt, expanded ? 8 : 1))
|
|
404
|
-
lines.push(` ${nestedLine}`);
|
|
405
|
-
}
|
|
406
|
-
return lines;
|
|
407
|
-
}
|
|
408
408
|
function parseParallelGroupAgentCount(label) {
|
|
409
409
|
if (!label || !label.startsWith("[") || !label.endsWith("]"))
|
|
410
410
|
return;
|
|
@@ -440,24 +440,16 @@ function buildChainStepSpans(details) {
|
|
|
440
440
|
function isChainParallelGroupActive(details) {
|
|
441
441
|
return details.mode !== "chain" || details.currentStepIndex === void 0 ? !1 : buildChainStepSpans(details).some((span) => span.stepIndex === details.currentStepIndex && span.isParallel);
|
|
442
442
|
}
|
|
443
|
-
function buildAsyncChainStepSpans(total, stepCount, parallelGroups = []) {
|
|
444
|
-
let spans = [], flatIndex = 0;
|
|
445
|
-
for (let stepIndex = 0; stepIndex < total; stepIndex++) {
|
|
446
|
-
let group = parallelGroups.find((candidate) => candidate.stepIndex === stepIndex);
|
|
447
|
-
if (group) {
|
|
448
|
-
spans.push({ stepIndex, start: group.start, count: group.count, isParallel: !0 }), flatIndex = Math.max(flatIndex, group.start + group.count);
|
|
449
|
-
continue;
|
|
450
|
-
}
|
|
451
|
-
spans.push({ stepIndex, start: flatIndex, count: flatIndex < stepCount ? 1 : 0, isParallel: !1 }), flatIndex++;
|
|
452
|
-
}
|
|
453
|
-
return spans;
|
|
454
|
-
}
|
|
455
443
|
function isDoneResult(result2) {
|
|
456
444
|
let status = result2.progress?.status;
|
|
457
445
|
return status === "completed" ? !0 : status === "running" || status === "pending" || result2.interrupted || result2.detached ? !1 : result2.exitCode === 0;
|
|
458
446
|
}
|
|
459
447
|
function workflowGraphHasStatus(details, statuses) {
|
|
460
|
-
|
|
448
|
+
let matches = (nodes) => nodes.some((node) => statuses.includes(node.status) || matches(node.children ?? []));
|
|
449
|
+
return matches(details.workflowGraph?.nodes ?? []);
|
|
450
|
+
}
|
|
451
|
+
function resultAtFlatIndex(details, flatIndex) {
|
|
452
|
+
return details.results.find((result2, arrayIndex) => (result2.progress?.index ?? result2.progressSummary?.index ?? arrayIndex) === flatIndex);
|
|
461
453
|
}
|
|
462
454
|
function buildChainRenderEntries(details, label) {
|
|
463
455
|
if (details.mode !== "chain" || !label.hasParallelInChain || label.showActiveGroupOnly)
|
|
@@ -475,13 +467,17 @@ function buildChainRenderEntries(details, label) {
|
|
|
475
467
|
});
|
|
476
468
|
continue;
|
|
477
469
|
}
|
|
478
|
-
for (let index = span.start; index < span.start + span.count; index++)
|
|
470
|
+
for (let index = span.start; index < span.start + span.count; index++) {
|
|
471
|
+
let workflowStep = details.workflowGraph?.nodes.find((node) => node.stepIndex === span.stepIndex), workflowNode = workflowStep?.children?.find((node) => node.flatIndex === index) ?? (workflowStep?.flatIndex === index ? workflowStep : void 0), result2 = resultAtFlatIndex(details, index);
|
|
479
472
|
entries.push({
|
|
480
473
|
kind: "result",
|
|
481
474
|
resultIndex: index,
|
|
482
475
|
rowNumber: index + 1,
|
|
483
|
-
agentName:
|
|
476
|
+
agentName: result2?.agent ?? workflowNode?.label ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`,
|
|
477
|
+
status: workflowNode?.status ?? span.status,
|
|
478
|
+
error: workflowNode?.error ?? span.error
|
|
484
479
|
});
|
|
480
|
+
}
|
|
485
481
|
}
|
|
486
482
|
return entries;
|
|
487
483
|
}
|
|
@@ -546,38 +542,6 @@ function resultRowLabel(details, label, resultIndex, stepNumber) {
|
|
|
546
542
|
}
|
|
547
543
|
return label.itemTitle === "Agent" ? `Agent ${label.activeParallelGroup ? Math.max(1, stepNumber - label.groupStartIndex) : stepNumber}/${label.totalCount}` : `Step ${stepNumber}`;
|
|
548
544
|
}
|
|
549
|
-
function widgetStats(job, theme, now = Date.now()) {
|
|
550
|
-
let parts = [], stepsTotal = job.stepsTotal ?? job.agents?.length ?? 1;
|
|
551
|
-
if (job.activeParallelGroup) {
|
|
552
|
-
let running = job.runningSteps ?? (job.status === "running" ? 1 : 0), done = job.completedSteps ?? (job.status === "complete" ? stepsTotal : 0);
|
|
553
|
-
if (job.mode === "parallel")
|
|
554
|
-
job.status === "running" && running > 0 && parts.push(formatAgentRunningLabel(running)), stepsTotal > 0 && parts.push(`${done}/${stepsTotal} done`);
|
|
555
|
-
else {
|
|
556
|
-
let logicalStep = (job.currentStep !== void 0 ? job.parallelGroups?.find((group) => job.currentStep >= group.start && job.currentStep < group.start + group.count) : job.parallelGroups?.find((group) => group.start === 0))?.stepIndex ?? job.currentStep ?? 0, total = job.chainStepCount ?? stepsTotal, groupParts = [`${done}/${stepsTotal} done`];
|
|
557
|
-
job.status === "running" && running > 0 && groupParts.unshift(formatAgentRunningLabel(running)), parts.push(`step ${logicalStep + 1}/${total} \xB7 parallel group: ${groupParts.join(" \xB7 ")}`);
|
|
558
|
-
}
|
|
559
|
-
} else if (job.currentStep !== void 0)
|
|
560
|
-
if (job.mode === "chain" && job.parallelGroups?.length) {
|
|
561
|
-
let total = job.chainStepCount ?? stepsTotal;
|
|
562
|
-
parts.push(`step ${flatToLogicalStepIndex(job.currentStep, total, job.parallelGroups) + 1}/${total}`);
|
|
563
|
-
} else
|
|
564
|
-
parts.push(`step ${job.currentStep + 1}/${stepsTotal}`);
|
|
565
|
-
else stepsTotal > 1 && parts.push(`steps ${stepsTotal}`);
|
|
566
|
-
if (job.toolCount !== void 0 && parts.push(formatToolUseStat(job.toolCount)), job.totalTokens?.total && parts.push(formatTokenStat(job.totalTokens.total)), job.startedAt !== void 0) {
|
|
567
|
-
let end = job.status === "running" ? now : job.updatedAt;
|
|
568
|
-
end !== void 0 && parts.push(`${job.status === "running" ? "" : "ran for "}${formatDuration(Math.max(0, end - job.startedAt))}`);
|
|
569
|
-
}
|
|
570
|
-
return statJoin(theme, parts);
|
|
571
|
-
}
|
|
572
|
-
function widgetStepStats(theme, step, now = Date.now()) {
|
|
573
|
-
let running = step.status === "running", durationMs = step.durationMs !== void 0 ? step.durationMs + (running && step.lastActivityAt !== void 0 ? Math.max(0, now - step.lastActivityAt) : 0) : step.startedAt !== void 0 ? Math.max(0, (running ? now : step.endedAt ?? step.lastActivityAt ?? now) - step.startedAt) : void 0;
|
|
574
|
-
return statJoin(theme, [
|
|
575
|
-
step.turnCount !== void 0 ? `${step.turnCount} turns` : "",
|
|
576
|
-
step.toolCount !== void 0 ? formatToolUseStat(step.toolCount) : "",
|
|
577
|
-
step.tokens?.total ? formatTokenStat(step.tokens.total) : "",
|
|
578
|
-
durationMs !== void 0 ? `${running ? "" : "ran for "}${formatDuration(durationMs)}` : ""
|
|
579
|
-
]);
|
|
580
|
-
}
|
|
581
545
|
function modelThinkingBadge(theme, model, thinking, selection) {
|
|
582
546
|
let label = formatModelSelection(selection, model, thinking);
|
|
583
547
|
return label ? theme.fg("dim", ` (${label})`) : "";
|
|
@@ -642,59 +606,45 @@ function formatNestedWidgetLines(children, theme, width, expanded, snapshotNow,
|
|
|
642
606
|
};
|
|
643
607
|
return append(children, 0, ""), lines.map((line) => truncLine(line, width));
|
|
644
608
|
}
|
|
645
|
-
function
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
if (
|
|
664
|
-
return
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
return
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
].map((line) => truncLine(line, width));
|
|
685
|
-
}
|
|
686
|
-
function compactSingleWidgetLines(job, theme, width) {
|
|
687
|
-
let fullLines = buildSingleWidgetLines(job, theme, width, !1);
|
|
688
|
-
if (fullLines.length <= 10 || !job.steps?.length || job.mode !== "parallel" && !job.activeParallelGroup)
|
|
689
|
-
return fullLines;
|
|
690
|
-
let total = job.stepsTotal ?? job.steps.length, itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step", lines = fullLines.slice(0, 2);
|
|
691
|
-
for (let [index, step] of job.steps.entries()) {
|
|
692
|
-
let status = widgetStepStatus(step.status, theme), activity = widgetStepActivityLine(step, width, !1, job.updatedAt), stepStats = widgetStepStats(theme, step), activitySuffix = activity ? ` ${theme.fg("dim", "\xB7")} ${theme.fg("dim", activity)}` : "", modelDisplay = modelThinkingBadge(theme, step.model, step.thinking, step.modelSelection);
|
|
693
|
-
lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "\xB7")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "\xB7")} ${stepStats}` : ""}`);
|
|
694
|
-
for (let nestedLine of formatNestedWidgetLines(step.children, theme, width, !1, job.updatedAt))
|
|
695
|
-
lines.push(` ${nestedLine}`);
|
|
696
|
-
}
|
|
697
|
-
return job.steps.some((step) => step.status === "running") && lines.push(theme.fg("accent", ` ${liveDetailHintText()}`)), lines.map((line) => truncLine(line, width));
|
|
609
|
+
function compactTerminalStatus(status) {
|
|
610
|
+
if (status === "failed")
|
|
611
|
+
return "failed";
|
|
612
|
+
if (status === "paused")
|
|
613
|
+
return "paused";
|
|
614
|
+
if (status === "stopped")
|
|
615
|
+
return "stopped";
|
|
616
|
+
if (status === "detached")
|
|
617
|
+
return "detached";
|
|
618
|
+
}
|
|
619
|
+
function compactJobProgress(job, step, now = Date.now()) {
|
|
620
|
+
let running = (step?.status ?? job.status) === "running", tokens = step?.tokens?.total ?? job.totalTokens?.total ?? 0;
|
|
621
|
+
if (step?.durationMs !== void 0)
|
|
622
|
+
return {
|
|
623
|
+
tokens,
|
|
624
|
+
durationMs: liveDurationMs({ durationMs: step.durationMs, lastActivityAt: step.lastActivityAt }, running, now)
|
|
625
|
+
};
|
|
626
|
+
let startedAt = step?.startedAt ?? job.startedAt;
|
|
627
|
+
if (startedAt === void 0)
|
|
628
|
+
return { tokens, durationMs: 0 };
|
|
629
|
+
let endedAt = running ? now : step?.endedAt ?? step?.lastActivityAt ?? job.updatedAt ?? now;
|
|
630
|
+
return { tokens, durationMs: Math.max(0, endedAt - startedAt) };
|
|
631
|
+
}
|
|
632
|
+
function compactJobLead(job, step) {
|
|
633
|
+
return compactRowLead({
|
|
634
|
+
description: step?.description ?? step?.agent ?? job.agents?.[0],
|
|
635
|
+
task: step?.description ?? step?.agent
|
|
636
|
+
}) || widgetJobName(job);
|
|
637
|
+
}
|
|
638
|
+
function compactJobLines(job, step, theme, width, now = Date.now()) {
|
|
639
|
+
let running = (step?.status ?? job.status) === "running", lead = compactJobLead(job, step), modelBadge = formatCompactModelBadge(step?.modelSelection, step?.model), glyph = step ? widgetStepGlyph(step.status, theme, running ? (widgetStepRunningSeed(step, step.index) ?? 0) + widgetAnimFrame(now) : widgetStepRunningSeed(step, step.index)) : widgetStatusGlyph(job, theme, now), progress = compactJobProgress(job, step, now);
|
|
640
|
+
return [formatCompactSubagentRow(theme, width, {
|
|
641
|
+
glyph,
|
|
642
|
+
description: lead,
|
|
643
|
+
modelBadge,
|
|
644
|
+
tokens: progress.tokens,
|
|
645
|
+
durationMs: progress.durationMs,
|
|
646
|
+
terminalStatus: compactTerminalStatus(step?.status ?? job.status)
|
|
647
|
+
})];
|
|
698
648
|
}
|
|
699
649
|
var RESERVED_NON_WIDGET_ROWS = 19, widgetLayoutSession;
|
|
700
650
|
function resetWidgetLayoutSession() {
|
|
@@ -713,20 +663,6 @@ function currentTerminalColumns() {
|
|
|
713
663
|
function widgetSessionMatches(expanded) {
|
|
714
664
|
return widgetLayoutSession?.expanded === expanded && widgetLayoutSession.rows === currentTerminalRows() && widgetLayoutSession.columns === currentTerminalColumns();
|
|
715
665
|
}
|
|
716
|
-
function widgetHeaderCounts(jobs) {
|
|
717
|
-
return {
|
|
718
|
-
running: jobs.filter((job) => job.status === "running"),
|
|
719
|
-
queued: jobs.filter((job) => job.status === "queued"),
|
|
720
|
-
complete: jobs.filter((job) => job.status === "complete"),
|
|
721
|
-
failed: jobs.filter((job) => job.status === "failed"),
|
|
722
|
-
paused: jobs.filter((job) => job.status === "paused"),
|
|
723
|
-
stopped: jobs.filter((job) => job.status === "stopped")
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
function buildSingleLineWidgetLines(jobs, theme, width) {
|
|
727
|
-
let counts = widgetHeaderCounts(jobs), hasActive = counts.running.length > 0 || counts.queued.length > 0, glyph = counts.running.length > 0 ? runningGlyph(widgetJobsRunningSeed(counts.running)) : hasActive ? "\u25CF" : "\u25CB", parts = [];
|
|
728
|
-
return counts.running.length > 0 && parts.push(`${counts.running.length}/${jobs.length} running`), counts.queued.length > 0 && parts.push(`${counts.queued.length} queued`), counts.failed.length > 0 && parts.push(`${counts.failed.length} failed`), counts.stopped.length > 0 && parts.push(`${counts.stopped.length} stopped`), counts.paused.length > 0 && parts.push(`${counts.paused.length} paused`), !hasActive && counts.complete.length > 0 && parts.push(`${counts.complete.length}/${jobs.length} done`), [truncLine(`${theme.fg(hasActive ? "accent" : "dim", glyph)} ${theme.fg(hasActive ? "accent" : "dim", "subagents")} (${parts.join(", ") || `${jobs.length} total`})`, width)];
|
|
729
|
-
}
|
|
730
666
|
function orderedWidgetJobs(jobs) {
|
|
731
667
|
return [
|
|
732
668
|
...jobs.filter((job) => job.status === "running"),
|
|
@@ -734,73 +670,6 @@ function orderedWidgetJobs(jobs) {
|
|
|
734
670
|
...jobs.filter((job) => job.status !== "running" && job.status !== "queued")
|
|
735
671
|
];
|
|
736
672
|
}
|
|
737
|
-
function progressiveJobKey(job) {
|
|
738
|
-
return job.asyncId;
|
|
739
|
-
}
|
|
740
|
-
function isProgressiveActiveJob(job) {
|
|
741
|
-
return job?.status === "running" || job?.status === "queued";
|
|
742
|
-
}
|
|
743
|
-
function selectProgressiveJobKeys(jobs, previousKeys, bodyRows) {
|
|
744
|
-
if (bodyRows <= 0)
|
|
745
|
-
return [];
|
|
746
|
-
let jobsByKey = new Map(jobs.map((job) => [progressiveJobKey(job), job])), selected = [], append = (key) => {
|
|
747
|
-
selected.includes(key) || !jobsByKey.has(key) || selected.push(key);
|
|
748
|
-
};
|
|
749
|
-
for (let key of previousKeys)
|
|
750
|
-
if (isProgressiveActiveJob(jobsByKey.get(key)) && (append(key), selected.length >= bodyRows))
|
|
751
|
-
return selected;
|
|
752
|
-
for (let job of orderedWidgetJobs(jobs)) {
|
|
753
|
-
if (!isProgressiveActiveJob(job))
|
|
754
|
-
continue;
|
|
755
|
-
let key = progressiveJobKey(job);
|
|
756
|
-
if (append(key), selected.length >= bodyRows)
|
|
757
|
-
break;
|
|
758
|
-
}
|
|
759
|
-
if (selected.length >= bodyRows)
|
|
760
|
-
return selected;
|
|
761
|
-
for (let key of previousKeys)
|
|
762
|
-
if (!isProgressiveActiveJob(jobsByKey.get(key)) && (append(key), selected.length >= bodyRows))
|
|
763
|
-
return selected;
|
|
764
|
-
for (let job of orderedWidgetJobs(jobs)) {
|
|
765
|
-
let key = progressiveJobKey(job);
|
|
766
|
-
if (append(key), selected.length >= bodyRows)
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
return selected;
|
|
770
|
-
}
|
|
771
|
-
function progressiveHeaderLine(jobs, theme, width) {
|
|
772
|
-
let counts = widgetHeaderCounts(jobs), hasActive = counts.running.length > 0 || counts.queued.length > 0, glyph = counts.running.length > 0 ? runningGlyph(widgetJobsRunningSeed(counts.running)) : hasActive ? "\u25CF" : "\u25CB", parts = [];
|
|
773
|
-
return counts.running.length > 0 && parts.push(formatAgentRunningLabel(counts.running.length)), counts.queued.length > 0 && parts.push(`${counts.queued.length} queued`), hasActive || (counts.failed.length > 0 && parts.push(`${counts.failed.length} failed`), counts.stopped.length > 0 && parts.push(`${counts.stopped.length} stopped`), counts.paused.length > 0 && parts.push(`${counts.paused.length} paused`), counts.complete.length > 0 && parts.push(`${counts.complete.length}/${jobs.length} done`)), truncLine(`${theme.fg(hasActive ? "accent" : "dim", glyph)} ${theme.fg(hasActive ? "accent" : "dim", "Async agents")} ${theme.fg("dim", "\xB7")} ${theme.fg("dim", parts.join(", ") || `${jobs.length} total`)}`, width);
|
|
774
|
-
}
|
|
775
|
-
function progressiveJobLine(job, theme, width) {
|
|
776
|
-
let stats = widgetStats(job, theme), activity = widgetActivity(job), status = job.status === "complete" ? "done" : job.status, parts = [
|
|
777
|
-
themeBold(theme, widgetJobName(job)),
|
|
778
|
-
theme.fg("dim", status),
|
|
779
|
-
stats,
|
|
780
|
-
activity && activity.toLowerCase() !== status ? theme.fg("dim", activity) : ""
|
|
781
|
-
].filter(Boolean);
|
|
782
|
-
return truncLine(` ${widgetStatusGlyph(job, theme)} ${parts.join(` ${theme.fg("dim", "\xB7")} `)}`, width);
|
|
783
|
-
}
|
|
784
|
-
function progressiveHiddenLine(hiddenJobs, theme, width) {
|
|
785
|
-
let counts = widgetHeaderCounts(hiddenJobs), parts = [];
|
|
786
|
-
counts.running.length > 0 && parts.push(`${counts.running.length} running`), counts.queued.length > 0 && parts.push(`${counts.queued.length} queued`);
|
|
787
|
-
let finished = counts.complete.length + counts.failed.length + counts.paused.length + counts.stopped.length;
|
|
788
|
-
return finished > 0 && parts.push(`${finished} finished`), truncLine(theme.fg("dim", ` +${hiddenJobs.length} more${parts.length ? ` (${parts.join(", ")})` : ""}`), width);
|
|
789
|
-
}
|
|
790
|
-
function buildProgressiveWidgetLines(jobs, theme, width, lockedRows, previousKeys) {
|
|
791
|
-
let rowCount = Math.max(1, lockedRows);
|
|
792
|
-
if (rowCount === 1)
|
|
793
|
-
return { lines: buildSingleLineWidgetLines(jobs, theme, width), visibleJobKeys: [] };
|
|
794
|
-
let bodyRows = rowCount - 1, visibleJobKeys = selectProgressiveJobKeys(jobs, previousKeys, bodyRows), jobsByKey = new Map(jobs.map((job) => [progressiveJobKey(job), job])), visibleJobs = visibleJobKeys.map((key) => jobsByKey.get(key)).filter((job) => !!job), hiddenJobs = jobs.filter((job) => !visibleJobKeys.includes(progressiveJobKey(job)));
|
|
795
|
-
hiddenJobs.length > 0 && visibleJobs.length >= bodyRows && bodyRows > 0 && (visibleJobs = visibleJobs.slice(0, bodyRows - 1), visibleJobKeys = visibleJobs.map(progressiveJobKey), hiddenJobs = jobs.filter((job) => !visibleJobKeys.includes(progressiveJobKey(job))));
|
|
796
|
-
let lines = [
|
|
797
|
-
progressiveHeaderLine(jobs, theme, width),
|
|
798
|
-
...visibleJobs.map((job) => progressiveJobLine(job, theme, width))
|
|
799
|
-
];
|
|
800
|
-
for (hiddenJobs.length > 0 && lines.length < rowCount && lines.push(progressiveHiddenLine(hiddenJobs, theme, width)); lines.length < rowCount; )
|
|
801
|
-
lines.push(" ");
|
|
802
|
-
return { lines: lines.slice(0, rowCount), visibleJobKeys };
|
|
803
|
-
}
|
|
804
673
|
function collapsedWidgetLineBudget(rows) {
|
|
805
674
|
return Math.max(10, Math.min(14, Math.floor(rows * 0.35)));
|
|
806
675
|
}
|
|
@@ -811,137 +680,185 @@ function fitWidgetLineBudget(lines, theme, width, expanded) {
|
|
|
811
680
|
let visibleLines = Math.max(1, budget - 1), hiddenCount = lines.length - visibleLines, hint = expanded ? `\u2026 ${hiddenCount} live-detail lines hidden` : `\u2026 ${hiddenCount} lines hidden \xB7 ${liveDetailKeyText()} expands`;
|
|
812
681
|
return [...lines.slice(0, visibleLines), truncLine(theme.fg("dim", hint), width)];
|
|
813
682
|
}
|
|
814
|
-
function fitAdaptiveWidgetLines(
|
|
683
|
+
function fitAdaptiveWidgetLines(_jobs, lines, theme, width, expanded) {
|
|
815
684
|
if (expanded)
|
|
816
685
|
return resetWidgetLayoutSession(), fitWidgetLineBudget(lines, theme, width, !0);
|
|
817
|
-
let
|
|
818
|
-
if (hasMatchingSession && widgetLayoutSession?.tier === "single-line")
|
|
819
|
-
return buildSingleLineWidgetLines(jobs, theme, width);
|
|
820
|
-
if (hasMatchingSession && widgetLayoutSession?.tier === "progressive" && widgetLayoutSession.lockedRows !== void 0) {
|
|
821
|
-
let rendered2 = buildProgressiveWidgetLines(jobs, theme, width, widgetLayoutSession.lockedRows, widgetLayoutSession.visibleJobKeys);
|
|
822
|
-
return widgetLayoutSession.visibleJobKeys = rendered2.visibleJobKeys, rendered2.lines;
|
|
823
|
-
}
|
|
686
|
+
let rows = currentTerminalRows(), columns = currentTerminalColumns(), availableRows = estimateAvailableWidgetRows();
|
|
824
687
|
if (lines.length <= availableRows)
|
|
825
|
-
return widgetLayoutSession = { expanded, rows, columns, tier: "full"
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
return (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
688
|
+
return widgetLayoutSession = { expanded, rows, columns, tier: "full" }, fitWidgetLineBudget(lines, theme, width, !1);
|
|
689
|
+
let lockedRows = widgetSessionMatches(expanded) && widgetLayoutSession?.tier === "progressive" ? widgetLayoutSession.lockedRows ?? 1 : Math.max(1, Math.min(availableRows, collapsedWidgetLineBudget(rows)));
|
|
690
|
+
if (widgetLayoutSession = { expanded, rows, columns, tier: "progressive", lockedRows }, lockedRows === 1)
|
|
691
|
+
return lines.slice(0, 1);
|
|
692
|
+
let visibleCount = Math.max(1, lockedRows - 1), visible = lines.slice(0, visibleCount), hidden = lines.length - visible.length;
|
|
693
|
+
for (hidden > 0 && visible.push(truncLine(theme.fg("dim", `+${hidden} more`), width)); visible.length < lockedRows; )
|
|
694
|
+
visible.push(" ");
|
|
695
|
+
return visible.slice(0, lockedRows);
|
|
696
|
+
}
|
|
697
|
+
function widgetExpandedDiagnostics(job, step, index, theme, width, now) {
|
|
698
|
+
let lines = [], status = step?.status ?? job.status, runLabel = step ? `${job.asyncId}:${step.index ?? index}` : job.asyncId;
|
|
699
|
+
lines.push(truncLine(theme.fg("dim", ` \u23BF run ${runLabel} \xB7 ${status}`), width));
|
|
700
|
+
let error = step?.error;
|
|
701
|
+
error && lines.push(truncLine(theme.fg("error", ` ${error}`), width));
|
|
702
|
+
let snapshotNow = status === "running" ? now : step?.endedAt ?? job.updatedAt, activity = step ? widgetStepActivityLine(step, Math.max(1, width - 4), !0, snapshotNow) : widgetActivity(job, now);
|
|
703
|
+
activity && lines.push(truncLine(theme.fg("dim", ` ${activity}`), width));
|
|
704
|
+
for (let tool of step?.recentTools?.slice(-3) ?? [])
|
|
705
|
+
lines.push(truncLine(theme.fg("dim", ` ${tool.tool}${tool.args ? `: ${tool.args}` : ""}`), width));
|
|
706
|
+
for (let output of step?.recentOutput?.slice(-5) ?? [])
|
|
707
|
+
lines.push(truncLine(theme.fg("dim", ` ${output}`), width));
|
|
708
|
+
for (let nestedLine of formatNestedWidgetLines(step?.children ?? job.nestedChildren, theme, width, !0, snapshotNow))
|
|
709
|
+
lines.push(truncLine(` ${nestedLine}`, width));
|
|
710
|
+
return lines;
|
|
838
711
|
}
|
|
839
|
-
function buildWidgetLines(jobs, theme, width = getTermWidth(), expanded = !1) {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
lines.push(truncLine(`${theme.fg(hasActive ? "accent" : "dim", headerGlyph)} ${theme.fg(hasActive ? "accent" : "dim", "Async agents")} ${theme.fg("dim", "\xB7 background")}`, width));
|
|
846
|
-
let items = [], hiddenRunning = 0, hiddenFinished = 0, queuedSummaryShown = !1, slots = MAX_WIDGET_JOBS;
|
|
847
|
-
for (let job of running) {
|
|
848
|
-
if (slots <= 0) {
|
|
849
|
-
hiddenRunning++;
|
|
850
|
-
continue;
|
|
851
|
-
}
|
|
852
|
-
let stats = widgetStats(job, theme);
|
|
853
|
-
items.push([
|
|
854
|
-
`${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "\xB7")} ${stats}` : ""}`,
|
|
855
|
-
` ${theme.fg("dim", `\u23BF ${widgetActivity(job)}`)}`,
|
|
856
|
-
...widgetParallelAgentDetails(job, theme, expanded, width)
|
|
857
|
-
]), slots--;
|
|
858
|
-
}
|
|
859
|
-
queued.length > 0 && slots > 0 && (items.push([`${theme.fg("muted", "\u25E6")} ${theme.fg("dim", `${queued.length} queued`)}`]), queuedSummaryShown = !0, slots--);
|
|
860
|
-
for (let job of finished) {
|
|
861
|
-
if (slots <= 0) {
|
|
862
|
-
hiddenFinished++;
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
let stats = widgetStats(job, theme);
|
|
866
|
-
items.push([
|
|
867
|
-
`${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "\xB7")} ${stats}` : ""}`,
|
|
868
|
-
` ${theme.fg("dim", `\u23BF ${widgetActivity(job)}`)}`,
|
|
869
|
-
...widgetParallelAgentDetails(job, theme, expanded, width)
|
|
870
|
-
]), slots--;
|
|
712
|
+
function buildWidgetLines(jobs, theme, width = getTermWidth(), expanded = !1, now = Date.now()) {
|
|
713
|
+
let lines = [];
|
|
714
|
+
for (let job of orderedWidgetJobs(jobs)) {
|
|
715
|
+
let steps = job.steps?.length ? job.steps : job.agents?.length ? job.agents.map((agent, index) => ({ agent, description: agent, status: job.status, index })) : [void 0];
|
|
716
|
+
for (let [index, step] of steps.entries())
|
|
717
|
+
lines.push(...compactJobLines(job, step, theme, width, now)), expanded && lines.push(...widgetExpandedDiagnostics(job, step, index, theme, width, now));
|
|
871
718
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
719
|
+
return lines;
|
|
720
|
+
}
|
|
721
|
+
var activeWidget, SubagentAsyncWidget = class {
|
|
722
|
+
jobs;
|
|
723
|
+
expanded;
|
|
724
|
+
theme;
|
|
725
|
+
requestRender;
|
|
726
|
+
nowFn;
|
|
727
|
+
timer;
|
|
728
|
+
disposed = !1;
|
|
729
|
+
cachedWidth;
|
|
730
|
+
cachedLines;
|
|
731
|
+
constructor(jobs, theme, options) {
|
|
732
|
+
this.jobs = jobs, this.theme = theme, this.expanded = options?.expanded ?? !1, this.requestRender = options?.requestRender, this.nowFn = options?.now ?? Date.now, this.syncTimer();
|
|
876
733
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
lines.push(truncLine(`${theme.fg("dim", branch)} ${item[0]}`, width));
|
|
880
|
-
for (let detail of item.slice(1))
|
|
881
|
-
lines.push(truncLine(`${theme.fg("dim", continuation)} ${detail}`, width));
|
|
734
|
+
setTheme(theme) {
|
|
735
|
+
this.theme = theme, this.invalidate();
|
|
882
736
|
}
|
|
883
|
-
|
|
737
|
+
setJobs(jobs) {
|
|
738
|
+
this.jobs = jobs, this.invalidate(), this.syncTimer();
|
|
739
|
+
}
|
|
740
|
+
setExpanded(expanded) {
|
|
741
|
+
this.expanded !== expanded && (this.expanded = expanded, this.invalidate());
|
|
742
|
+
}
|
|
743
|
+
setRequestRender(requestRender) {
|
|
744
|
+
this.requestRender = requestRender;
|
|
745
|
+
}
|
|
746
|
+
hasRunning() {
|
|
747
|
+
return this.jobs.some((job) => job.status === "running");
|
|
748
|
+
}
|
|
749
|
+
syncTimer() {
|
|
750
|
+
this.disposed || (this.hasRunning() ? this.startTimer() : this.stopTimer());
|
|
751
|
+
}
|
|
752
|
+
startTimer() {
|
|
753
|
+
this.timer || (this.timer = setInterval(() => {
|
|
754
|
+
this.disposed || (this.invalidate(), this.requestRender?.());
|
|
755
|
+
}, SUBAGENT_PAINT_INTERVAL_MS), this.timer.unref?.());
|
|
756
|
+
}
|
|
757
|
+
stopTimer() {
|
|
758
|
+
this.timer && (clearInterval(this.timer), this.timer = void 0);
|
|
759
|
+
}
|
|
760
|
+
invalidate() {
|
|
761
|
+
this.cachedWidth = void 0, this.cachedLines = void 0;
|
|
762
|
+
}
|
|
763
|
+
dispose() {
|
|
764
|
+
this.disposed = !0, this.stopTimer(), activeWidget === this && (activeWidget = void 0);
|
|
765
|
+
}
|
|
766
|
+
render(width) {
|
|
767
|
+
let theme = this.theme;
|
|
768
|
+
if (!theme)
|
|
769
|
+
return [];
|
|
770
|
+
if (this.cachedLines && this.cachedWidth === width && !this.hasRunning())
|
|
771
|
+
return this.cachedLines;
|
|
772
|
+
let now = this.nowFn(), innerWidth = Math.max(1, width - 2), lines = buildWidgetLines(this.jobs, theme, innerWidth, this.expanded, now), padded = fitAdaptiveWidgetLines(this.jobs, lines, theme, innerWidth, this.expanded).map((line) => {
|
|
773
|
+
let withPad = ` ${line}`, vis = visibleWidth(withPad);
|
|
774
|
+
return withPad + " ".repeat(Math.max(0, width - vis));
|
|
775
|
+
});
|
|
776
|
+
return this.cachedWidth = width, this.cachedLines = padded, padded;
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
function disposeSubagentWidget() {
|
|
780
|
+
activeWidget?.dispose(), activeWidget = void 0;
|
|
884
781
|
}
|
|
885
782
|
function renderWidget(ctx, jobs) {
|
|
886
783
|
if (jobs.length === 0) {
|
|
887
|
-
resetWidgetLayoutSession(), ctx.hasUI && ctx.ui.setWidget(WIDGET_KEY, void 0);
|
|
784
|
+
resetWidgetLayoutSession(), disposeSubagentWidget(), ctx.hasUI && ctx.ui.setWidget(WIDGET_KEY, void 0);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
if (!ctx.hasUI)
|
|
788
|
+
return;
|
|
789
|
+
let expanded = ctx.ui.getToolsExpanded?.() ?? !1, requestRender = () => ctx.ui.requestRender?.();
|
|
790
|
+
if (activeWidget) {
|
|
791
|
+
activeWidget.setJobs(jobs), activeWidget.setExpanded(expanded), activeWidget.setRequestRender(requestRender), ctx.ui.requestRender?.();
|
|
888
792
|
return;
|
|
889
793
|
}
|
|
890
|
-
|
|
794
|
+
let widget = new SubagentAsyncWidget(jobs, void 0, { expanded, requestRender });
|
|
795
|
+
activeWidget = widget, ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => (widget.setTheme(theme), widget));
|
|
796
|
+
}
|
|
797
|
+
function compactResultTerminalStatus(result2) {
|
|
798
|
+
if (result2.stopped)
|
|
799
|
+
return "stopped";
|
|
800
|
+
if (result2.detached)
|
|
801
|
+
return "detached";
|
|
802
|
+
if (result2.interrupted)
|
|
803
|
+
return "paused";
|
|
804
|
+
if (result2.exitCode !== 0)
|
|
805
|
+
return "failed";
|
|
891
806
|
}
|
|
892
807
|
function renderSingleCompact(d, r, theme, frame) {
|
|
893
|
-
let output = r.truncation?.text || getSingleResultOutput(r), progress = r.progress || r.progressSummary, isRunning = r.progress?.status === "running",
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
808
|
+
let output = r.truncation?.text || getSingleResultOutput(r), progress = r.progress || r.progressSummary, isRunning = r.progress?.status === "running", width = getTermWidth() - 4, lead = compactRowLead({ description: r.description ?? r.agent, task: r.task }), modelBadge = formatCompactModelBadge(r.modelSelection ?? progress?.modelSelection, r.model ?? progress?.model);
|
|
809
|
+
return animatedLine((animationTick, now) => formatCompactSubagentRow(theme, width, {
|
|
810
|
+
glyph: resultGlyph(r, output, theme, isRunning, void 0, foregroundSpinnerFrame(animationTick)),
|
|
811
|
+
description: lead,
|
|
812
|
+
modelBadge,
|
|
813
|
+
tokens: compactResultTokens(r),
|
|
814
|
+
durationMs: liveDurationMs(progress, isRunning, now),
|
|
815
|
+
terminalStatus: compactResultTerminalStatus(r)
|
|
816
|
+
}), frame, isRunning);
|
|
817
|
+
}
|
|
818
|
+
function progressStatusGlyph(progress, theme, frame) {
|
|
819
|
+
return !progress || progress.status === "pending" ? theme.fg("muted", "\u25E6") : progress.status === "running" ? theme.fg("accent", runningGlyph((progressRunningSeed(progress) ?? 0) + (frame ?? 0))) : progress.status === "completed" ? theme.fg("success", "\u2713") : progress.status === "failed" ? theme.fg("error", "\u2717") : theme.fg("warning", "\u25A0");
|
|
820
|
+
}
|
|
821
|
+
function flattenCompactWorkflowNodes(nodes) {
|
|
822
|
+
let rows = [];
|
|
823
|
+
for (let node of nodes)
|
|
824
|
+
node.children?.length ? rows.push(...flattenCompactWorkflowNodes(node.children)) : rows.push(node);
|
|
825
|
+
return rows;
|
|
826
|
+
}
|
|
827
|
+
function compactForegroundEntries(d) {
|
|
828
|
+
let workflowNodes = flattenCompactWorkflowNodes(d.workflowGraph?.nodes ?? []);
|
|
829
|
+
if (workflowNodes.length === 0) {
|
|
830
|
+
let progressCount2 = d.progress?.reduce((count2, entry) => Math.max(count2, entry.index + 1), 0) ?? 0, chainCount = d.mode === "chain" ? buildChainStepSpans(d).reduce((count2, span) => Math.max(count2, span.start + span.count), 0) : 0, count = Math.max(d.results.length, progressCount2, d.chainChildren?.length ?? 0, d.chainAgents?.length ?? 0, chainCount);
|
|
831
|
+
return Array.from({ length: count }, (_, flatIndex) => ({ flatIndex }));
|
|
832
|
+
}
|
|
833
|
+
let entries = workflowNodes.map((node) => ({ flatIndex: node.flatIndex, node })), seen = new Set(entries.flatMap((entry) => entry.flatIndex === void 0 ? [] : [entry.flatIndex])), progressCount = d.progress?.reduce((count, entry) => Math.max(count, entry.index + 1), 0) ?? 0, dataCount = Math.max(d.results.length, progressCount, d.chainChildren?.length ?? 0);
|
|
834
|
+
for (let flatIndex = 0; flatIndex < dataCount; flatIndex++)
|
|
835
|
+
seen.has(flatIndex) || entries.push({ flatIndex });
|
|
836
|
+
return entries;
|
|
902
837
|
}
|
|
903
838
|
function renderMultiCompact(d, theme, frame) {
|
|
904
|
-
let
|
|
905
|
-
|
|
906
|
-
let
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
});
|
|
922
|
-
for (let entry of renderEntries) {
|
|
923
|
-
if (entry.kind === "placeholder") {
|
|
924
|
-
let glyph2 = widgetStepGlyph(entry.status, theme), statusLabel = widgetStepStatus(entry.status, theme);
|
|
925
|
-
c.addChild(new Text(truncLine(` ${glyph2} ${entry.stepLabel}: ${themeBold(theme, entry.agentName)} ${theme.fg("dim", "\xB7")} ${statusLabel}`, width), 0, 0)), entry.error && c.addChild(new Text(truncLine(theme.fg("error", ` \u23BF Error: ${entry.error}`), width), 0, 0));
|
|
926
|
-
continue;
|
|
927
|
-
}
|
|
928
|
-
let i = entry.resultIndex, r = d.results[i], rowNumber = entry.rowNumber, agentName = entry.agentName;
|
|
929
|
-
if (!r) {
|
|
930
|
-
let pendingLabel2 = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`;
|
|
931
|
-
c.addChild(new Text(truncLine(theme.fg("dim", ` \u25E6 ${pendingLabel2}: ${agentName} \xB7 pending`), width), 0, 0));
|
|
932
|
-
continue;
|
|
933
|
-
}
|
|
934
|
-
let output = getSingleResultOutput(r), progressFromArray = d.progress?.find((p) => p.index === i) || d.progress?.find((p) => p.agent === r.agent && p.status === "running"), rProg = r.progress || progressFromArray || r.progressSummary, rRunning = rProg && "status" in rProg && rProg.status === "running", rPending = rProg && "status" in rProg && rProg.status === "pending", pendingLabel = rPending ? ` ${theme.fg("dim", "\xB7 pending")}` : "", lead = compactRowLead({ description: r.description ?? agentName, task: r.task }), permissionBadge = r.permissions ? theme.fg("dim", r.permissions) : "", modelBadge = formatModelSelection(r.modelSelection ?? (rProg && "modelSelection" in rProg ? rProg.modelSelection : void 0), r.model ?? (rProg && "model" in rProg ? rProg.model : void 0), r.thinking ?? (rProg && "thinking" in rProg ? rProg.thinking : void 0));
|
|
935
|
-
c.addChild(animatedLine((f, now) => {
|
|
936
|
-
let glyph2 = rPending ? theme.fg("dim", "\u25E6") : resultGlyph(r, output, theme, rRunning, progressRunningSeed(rProg), f), stepStats = formatProgressStats(theme, rProg, !0, { running: !!rRunning, terminal: !rRunning && !rPending, now });
|
|
937
|
-
return truncLine(` ${glyph2} ${themeBold(theme, lead)}${modelBadge ? ` ${theme.fg("dim", "\xB7")} ${theme.fg("dim", modelBadge)}` : ""}${permissionBadge ? ` ${theme.fg("dim", "\xB7")} ${permissionBadge}` : ""}${stepStats ? ` ${theme.fg("dim", "\xB7")} ${stepStats}` : ""}${pendingLabel}`, width);
|
|
938
|
-
}, frame, !!rRunning)), rRunning && rProg && "status" in rProg ? c.addChild(animatedLine((_f, now) => formatCompactStatsHangLine(rProg, width, (s) => theme.fg("dim", s), " \u23BF ", now, !0), frame, !0)) : !rPending && (r.exitCode !== 0 || r.interrupted || r.detached || hasEmptyTextOutputWithoutOutputTarget(r.task, output)) && c.addChild(new Text(truncLine(theme.fg(r.exitCode !== 0 ? "error" : "dim", ` \u23BF ${resultStatusLine(r, output)}`), width), 0, 0));
|
|
839
|
+
let c = new Container(), width = getTermWidth() - 4, entries = compactForegroundEntries(d);
|
|
840
|
+
for (let [rowIndex, entry] of entries.entries()) {
|
|
841
|
+
let flatIndex = entry.flatIndex, result2 = flatIndex === void 0 ? void 0 : resultAtFlatIndex(d, flatIndex), progress = result2?.progress ?? (flatIndex === void 0 ? void 0 : d.progress?.find((candidate) => candidate.index === flatIndex)) ?? result2?.progressSummary, status = progress?.status ?? entry.node?.status ?? "pending", description = compactRowLead({
|
|
842
|
+
description: result2?.description ?? progress?.description ?? entry.node?.label ?? (flatIndex === void 0 ? void 0 : d.chainChildren?.[flatIndex]?.description) ?? (flatIndex === void 0 ? void 0 : d.chainAgents?.[flatIndex]) ?? result2?.agent ?? progress?.agent,
|
|
843
|
+
task: result2?.task ?? progress?.task
|
|
844
|
+
}) || `child ${rowIndex + 1}`, running = status === "running", output = result2 ? getSingleResultOutput(result2) : "", modelBadge = formatCompactModelBadge(result2?.modelSelection ?? progress?.modelSelection, result2?.model ?? progress?.model);
|
|
845
|
+
c.addChild(animatedLine((animationTick, now) => {
|
|
846
|
+
let animationFrame = foregroundSpinnerFrame(animationTick);
|
|
847
|
+
return formatCompactSubagentRow(theme, width, {
|
|
848
|
+
glyph: result2 ? resultGlyph(result2, output, theme, running, progressRunningSeed(progress), animationFrame) : progressStatusGlyph({ ...progress, status, index: flatIndex }, theme, animationFrame),
|
|
849
|
+
description,
|
|
850
|
+
modelBadge,
|
|
851
|
+
tokens: result2 ? compactResultTokens(result2) : progress?.tokens ?? 0,
|
|
852
|
+
durationMs: liveDurationMs(progress, running, now),
|
|
853
|
+
terminalStatus: result2 ? compactResultTerminalStatus(result2) : compactTerminalStatus(status)
|
|
854
|
+
});
|
|
855
|
+
}, frame, running));
|
|
939
856
|
}
|
|
940
857
|
return c;
|
|
941
858
|
}
|
|
942
859
|
function renderSubagentResult(result2, options, theme, frame) {
|
|
943
|
-
let d = result2.details;
|
|
944
|
-
if (!d || !d.results.length) {
|
|
860
|
+
let d = result2.details, hasWorkflowRows = d?.mode !== "management" && !!(d?.workflowGraph?.nodes.length || d?.progress?.length || d?.chainChildren?.length);
|
|
861
|
+
if (!d || !d.results.length && !hasWorkflowRows) {
|
|
945
862
|
let t = result2.content[0], text = t?.type === "text" ? t.text : "(no output)", contextPrefix = d?.context === "fork" ? `${theme.fg("warning", "[fork]")} ` : "", width = getTermWidth() - 4;
|
|
946
863
|
if (!text.includes(`
|
|
947
864
|
`))
|
|
@@ -962,7 +879,7 @@ function renderSubagentResult(result2, options, theme, frame) {
|
|
|
962
879
|
return fit3(`${icon2} ${theme.fg("toolTitle", theme.bold(r.agent))}${modelDisplay}${contextBadge2}${stats ? ` | ${stats}` : ""}`);
|
|
963
880
|
}, frame, isRunning)), c2.addChild(new Spacer(1));
|
|
964
881
|
let taskMaxLen = Math.max(20, w2 - 8), taskPreview = expanded || r.task.length <= taskMaxLen ? r.task : `${r.task.slice(0, taskMaxLen)}...`;
|
|
965
|
-
if (c2.addChild(new Text(fit3(theme.fg("dim", `Task: ${taskPreview}`)), 0, 0)), c2.addChild(new Spacer(1)), isRunning && r.progress) {
|
|
882
|
+
if (c2.addChild(new Text(fit3(theme.fg("dim", `Task: ${taskPreview}`)), 0, 0)), !isRunning && compactResultTerminalStatus(r) && c2.addChild(new Text(fit3(theme.fg(r.exitCode !== 0 ? "error" : "warning", resultStatusLine(r, output))), 0, 0)), c2.addChild(new Spacer(1)), isRunning && r.progress) {
|
|
966
883
|
let progressSnapshotNow = snapshotNowForProgress(r.progress), toolLine = formatCurrentToolLine(r.progress, w2, expanded, progressSnapshotNow);
|
|
967
884
|
toolLine && c2.addChild(new Text(fit3(theme.fg("warning", `> ${toolLine}`)), 0, 0));
|
|
968
885
|
let liveStatusLine = buildLiveStatusLine(r.progress, progressSnapshotNow);
|
|
@@ -984,7 +901,7 @@ function renderSubagentResult(result2, options, theme, frame) {
|
|
|
984
901
|
}
|
|
985
902
|
if (!expanded)
|
|
986
903
|
return renderMultiCompact(d, theme, frame);
|
|
987
|
-
let hasRunning = d.progress?.some((p) => p.status === "running") || d.results.some((r) => r.progress?.status === "running") || workflowGraphHasStatus(d, ["running"]), ok = d.results.filter((r) => r.progress?.status === "completed" || r.exitCode === 0 && r.progress?.status !== "running").length, hasEmptyWithoutTarget = d.results.some((r) => r.exitCode === 0 && r.progress?.status !== "running" && hasEmptyTextOutputWithoutOutputTarget(r.task, getSingleResultOutput(r))), hasWorkflowFailure = workflowGraphHasStatus(d, ["failed"]), hasWorkflowStop = d.results.some((r) => r.stopped && r.progress?.status !== "running") || workflowGraphHasStatus(d, ["stopped"]), hasWorkflowPause = workflowGraphHasStatus(d, ["paused", "detached"]), icon = hasRunning ? theme.fg("warning", "running") : hasEmptyWithoutTarget ? theme.fg("warning", "warning") : hasWorkflowFailure ? theme.fg("error", "failed") : hasWorkflowStop ? theme.fg("warning", "stopped") : hasWorkflowPause ? theme.fg("warning", "paused") : ok === d.results.length ? theme.fg("success", "ok") : theme.fg("error", "failed"), totalSummary = d.progressSummary || d.results.reduce((acc, r) => {
|
|
904
|
+
let hasRunning = d.progress?.some((p) => p.status === "running") || d.results.some((r) => r.progress?.status === "running") || workflowGraphHasStatus(d, ["running"]), ok = d.results.filter((r) => r.progress?.status === "completed" || r.exitCode === 0 && r.progress?.status !== "running").length, hasEmptyWithoutTarget = d.results.some((r) => r.exitCode === 0 && r.progress?.status !== "running" && hasEmptyTextOutputWithoutOutputTarget(r.task, getSingleResultOutput(r))), hasWorkflowFailure = workflowGraphHasStatus(d, ["failed"]), hasWorkflowStop = d.results.some((r) => r.stopped && r.progress?.status !== "running") || workflowGraphHasStatus(d, ["stopped"]), hasWorkflowPause = workflowGraphHasStatus(d, ["paused", "detached"]), hasWorkflowPending = workflowGraphHasStatus(d, ["pending"]), icon = hasRunning ? theme.fg("warning", "running") : hasEmptyWithoutTarget ? theme.fg("warning", "warning") : hasWorkflowFailure ? theme.fg("error", "failed") : hasWorkflowStop ? theme.fg("warning", "stopped") : hasWorkflowPause ? theme.fg("warning", "paused") : hasWorkflowPending ? theme.fg("dim", "pending") : ok === d.results.length ? theme.fg("success", "ok") : theme.fg("error", "failed"), totalSummary = d.progressSummary || d.results.reduce((acc, r) => {
|
|
988
905
|
let prog = r.progress || r.progressSummary;
|
|
989
906
|
return prog && (acc.toolCount += prog.toolCount, acc.tokens += prog.tokens, acc.durationMs = d.mode === "chain" ? acc.durationMs + prog.durationMs : Math.max(acc.durationMs, prog.durationMs)), acc;
|
|
990
907
|
}, { toolCount: 0, tokens: 0, durationMs: 0 }), modeLabel = d.mode, contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "", multiLabel = buildMultiProgressLabel(d, hasRunning), itemTitle = multiLabel.itemTitle, chainVis = d.chainAgents?.length && !multiLabel.hasParallelInChain ? d.chainAgents.map((agent, i) => {
|
|
@@ -998,10 +915,26 @@ function renderSubagentResult(result2, options, theme, frame) {
|
|
|
998
915
|
].filter(Boolean), summaryStr = summaryParts.length ? ` | ${summaryParts.join(", ")}` : "";
|
|
999
916
|
return fit2(`${icon} ${theme.fg("toolTitle", theme.bold(modeLabel))}${contextBadge} \xB7 ${multiLabel.headerLabel}${summaryStr}`);
|
|
1000
917
|
}, frame, hasRunning)), chainVis && c.addChild(new Text(fit2(` ${chainVis}`), 0, 0));
|
|
1001
|
-
let
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
918
|
+
let chainEntries = buildChainRenderEntries(d, multiLabel), fallbackEntries = compactForegroundEntries(d).filter((entry) => !multiLabel.showActiveGroupOnly || entry.flatIndex === void 0 || entry.flatIndex >= multiLabel.groupStartIndex && entry.flatIndex < multiLabel.groupEndIndex).map((entry, rowIndex) => {
|
|
919
|
+
if (entry.flatIndex === void 0)
|
|
920
|
+
return {
|
|
921
|
+
kind: "placeholder",
|
|
922
|
+
rowNumber: entry.node?.stepIndex !== void 0 ? entry.node.stepIndex + 1 : rowIndex + 1,
|
|
923
|
+
stepLabel: `Step ${entry.node?.stepIndex !== void 0 ? entry.node.stepIndex + 1 : rowIndex + 1}`,
|
|
924
|
+
agentName: entry.node?.label ?? `step-${rowIndex + 1}`,
|
|
925
|
+
status: entry.node?.status ?? "pending",
|
|
926
|
+
error: entry.node?.error
|
|
927
|
+
};
|
|
928
|
+
let result3 = resultAtFlatIndex(d, entry.flatIndex), rowNumber = multiLabel.showActiveGroupOnly ? entry.flatIndex - multiLabel.groupStartIndex + 1 : entry.flatIndex + 1;
|
|
929
|
+
return {
|
|
930
|
+
kind: "result",
|
|
931
|
+
resultIndex: entry.flatIndex,
|
|
932
|
+
rowNumber,
|
|
933
|
+
agentName: result3?.agent ?? entry.node?.label ?? d.chainChildren?.[entry.flatIndex]?.description ?? d.chainAgents?.[entry.flatIndex] ?? `step-${rowNumber}`,
|
|
934
|
+
status: entry.node?.status,
|
|
935
|
+
error: entry.node?.error
|
|
936
|
+
};
|
|
937
|
+
}), renderEntries = chainEntries ?? fallbackEntries;
|
|
1005
938
|
c.addChild(new Spacer(1));
|
|
1006
939
|
for (let entry of renderEntries) {
|
|
1007
940
|
if (entry.kind === "placeholder") {
|
|
@@ -1009,10 +942,10 @@ function renderSubagentResult(result2, options, theme, frame) {
|
|
|
1009
942
|
c.addChild(new Text(fit2(` ${statusLabel} ${entry.stepLabel}: ${theme.bold(entry.agentName)}`), 0, 0)), c.addChild(new Text(theme.fg(entry.status === "failed" ? "error" : "dim", ` status: ${entry.status}`), 0, 0)), entry.error && c.addChild(new Text(theme.fg("error", ` error: ${entry.error}`), 0, 0)), c.addChild(new Spacer(1));
|
|
1010
943
|
continue;
|
|
1011
944
|
}
|
|
1012
|
-
let i = entry.resultIndex, r = d
|
|
945
|
+
let i = entry.resultIndex, r = resultAtFlatIndex(d, i), rowNumber = entry.rowNumber, agentName = entry.agentName;
|
|
1013
946
|
if (!r) {
|
|
1014
|
-
let
|
|
1015
|
-
c.addChild(new Text(fit2(theme.fg("dim", ` ${
|
|
947
|
+
let rowLabel = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`, status = entry.status ?? "pending";
|
|
948
|
+
c.addChild(new Text(fit2(theme.fg(status === "failed" ? "error" : "dim", ` ${rowLabel}: ${agentName}`)), 0, 0)), c.addChild(new Text(theme.fg(status === "failed" ? "error" : "dim", ` status: ${status}`), 0, 0)), entry.error && c.addChild(new Text(theme.fg("error", ` error: ${entry.error}`), 0, 0)), c.addChild(new Spacer(1));
|
|
1016
949
|
continue;
|
|
1017
950
|
}
|
|
1018
951
|
let progressFromArray = d.progress?.find((p) => p.index === i) || d.progress?.find((p) => p.agent === r.agent && p.status === "running"), rProg = r.progress || progressFromArray || r.progressSummary, rRunning = rProg?.status === "running", stepNumber = typeof rProg?.index == "number" ? rProg.index + 1 : i + 1, resultOutput = getSingleResultOutput(r), statusIcon = rRunning ? theme.fg("warning", "running") : r.exitCode !== 0 ? theme.fg("error", "failed") : hasEmptyTextOutputWithoutOutputTarget(r.task, resultOutput) ? theme.fg("warning", "warning") : theme.fg("success", "done"), modelDisplay = modelThinkingBadge(theme, r.model, r.thinking ?? (rProg && "thinking" in rProg ? rProg.thinking : void 0), r.modelSelection ?? (rProg && "modelSelection" in rProg ? rProg.modelSelection : void 0)), stepLabel = resultRowLabel(d, multiLabel, i, stepNumber), toolCallLines = getToolCallLines(r, expanded);
|
|
@@ -1021,7 +954,7 @@ function renderSubagentResult(result2, options, theme, frame) {
|
|
|
1021
954
|
return fit2(rRunning ? `${statusIcon} ${stepLabel}: ${theme.bold(theme.fg("warning", r.agent))}${modelDisplay}${stats ? ` | ${stats}` : ""}` : `${statusIcon} ${stepLabel}: ${theme.bold(r.agent)}${modelDisplay}${stats ? ` | ${stats}` : ""}`);
|
|
1022
955
|
}, frame, rRunning));
|
|
1023
956
|
let taskMaxLen = Math.max(20, w - 12), taskPreview = expanded || r.task.length <= taskMaxLen ? r.task : `${r.task.slice(0, taskMaxLen)}...`;
|
|
1024
|
-
if (c.addChild(new Text(fit2(theme.fg("dim", ` task: ${taskPreview}`)), 0, 0)), r.skills?.length && c.addChild(new Text(fit2(theme.fg("dim", ` skills: ${r.skills.join(", ")}`)), 0, 0)), r.skillsWarning && c.addChild(new Text(fit2(theme.fg("warning", ` Warning: ${r.skillsWarning}`)), 0, 0)), r.attemptedModels && r.attemptedModels.length > 1 && c.addChild(new Text(fit2(theme.fg("dim", ` fallbacks: ${r.attemptedModels.join(" \u2192 ")}`)), 0, 0)), rRunning && rProg) {
|
|
957
|
+
if (c.addChild(new Text(fit2(theme.fg("dim", ` task: ${taskPreview}`)), 0, 0)), !rRunning && compactResultTerminalStatus(r) && c.addChild(new Text(fit2(theme.fg(r.exitCode !== 0 ? "error" : "warning", ` ${resultStatusLine(r, resultOutput)}`)), 0, 0)), r.skills?.length && c.addChild(new Text(fit2(theme.fg("dim", ` skills: ${r.skills.join(", ")}`)), 0, 0)), r.skillsWarning && c.addChild(new Text(fit2(theme.fg("warning", ` Warning: ${r.skillsWarning}`)), 0, 0)), r.attemptedModels && r.attemptedModels.length > 1 && c.addChild(new Text(fit2(theme.fg("dim", ` fallbacks: ${r.attemptedModels.join(" \u2192 ")}`)), 0, 0)), rRunning && rProg) {
|
|
1025
958
|
rProg.skills?.length && c.addChild(new Text(fit2(theme.fg("accent", ` skills: ${rProg.skills.join(", ")}`)), 0, 0));
|
|
1026
959
|
let progressSnapshotNow = snapshotNowForProgress(rProg), toolLine = formatCurrentToolLine(rProg, w, expanded, progressSnapshotNow);
|
|
1027
960
|
toolLine && c.addChild(new Text(fit2(theme.fg("warning", ` > ${toolLine}`)), 0, 0));
|
|
@@ -1050,15 +983,15 @@ import { Type } from "typebox";
|
|
|
1050
983
|
function keepTopLevelParameterDescriptions(schema) {
|
|
1051
984
|
return pruneNestedDescriptions(schema, []);
|
|
1052
985
|
}
|
|
1053
|
-
function pruneNestedDescriptions(value,
|
|
986
|
+
function pruneNestedDescriptions(value, path13) {
|
|
1054
987
|
if (!value || typeof value != "object")
|
|
1055
988
|
return value;
|
|
1056
989
|
let result2 = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
|
|
1057
990
|
for (let key of Reflect.ownKeys(value)) {
|
|
1058
991
|
let descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1059
|
-
if (descriptor && !(key === "description" && !
|
|
992
|
+
if (descriptor && !(key === "description" && !isPropertiesMap(path13) && !isTopLevelParameterHelpText(path13))) {
|
|
1060
993
|
if ("value" in descriptor) {
|
|
1061
|
-
let nextPath = typeof key == "string" ? [...
|
|
994
|
+
let nextPath = typeof key == "string" ? [...path13, key] : path13;
|
|
1062
995
|
descriptor.value = pruneNestedDescriptions(descriptor.value, nextPath);
|
|
1063
996
|
}
|
|
1064
997
|
Object.defineProperty(result2, key, descriptor);
|
|
@@ -1066,8 +999,11 @@ function pruneNestedDescriptions(value, path12) {
|
|
|
1066
999
|
}
|
|
1067
1000
|
return result2;
|
|
1068
1001
|
}
|
|
1069
|
-
function
|
|
1070
|
-
return
|
|
1002
|
+
function isPropertiesMap(path13) {
|
|
1003
|
+
return path13[path13.length - 1] === "properties";
|
|
1004
|
+
}
|
|
1005
|
+
function isTopLevelParameterHelpText(path13) {
|
|
1006
|
+
return path13.length === 2 && path13[0] === "properties";
|
|
1071
1007
|
}
|
|
1072
1008
|
var SkillOverride = Type.Unsafe({
|
|
1073
1009
|
anyOf: [
|
|
@@ -1085,10 +1021,16 @@ var SkillOverride = Type.Unsafe({
|
|
|
1085
1021
|
}), OutputModeOverride = Type.String({
|
|
1086
1022
|
enum: ["inline", "file-only"],
|
|
1087
1023
|
description: "Return saved output inline (default) or only a concise file reference. file-only requires output to be a path."
|
|
1088
|
-
}), TierOverride = Type.String({
|
|
1024
|
+
}), TIER_SELECTION_DESCRIPTION = "Choose the lowest model tier that can reliably complete the task: 'light' for quick checks, fact gathering, and small code inspections; 'standard' for everyday coding, clearly described bugs, and focused reviews; 'heavy' for complex implementation, difficult debugging, architectural decisions, and large or high-risk reviews.", TierOverride = Type.Optional(Type.String({
|
|
1089
1025
|
enum: ["light", "standard", "heavy"],
|
|
1090
|
-
description:
|
|
1091
|
-
}),
|
|
1026
|
+
description: `Required by default. ${TIER_SELECTION_DESCRIPTION} Do not combine with model. The configured tier model must be available and authenticated.`
|
|
1027
|
+
})), ModelOverride = Type.Optional(Type.String({
|
|
1028
|
+
minLength: 1,
|
|
1029
|
+
description: "Explicit provider/model id only when the user names a model. Do not combine with tier. Optional thinking belongs in the thinking field or as a known :level suffix."
|
|
1030
|
+
})), ThinkingOverride = Type.Optional(Type.String({
|
|
1031
|
+
enum: ["off", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
1032
|
+
description: "Thinking level for an explicit model launch. Omit for tier launches (they use configured tier thinking)."
|
|
1033
|
+
})), ReadsOverride = Type.Unsafe({
|
|
1092
1034
|
anyOf: [
|
|
1093
1035
|
{ type: "array", items: { type: "string" } },
|
|
1094
1036
|
{ type: "boolean", enum: [!1] }
|
|
@@ -1135,6 +1077,8 @@ var SkillOverride = Type.Unsafe({
|
|
|
1135
1077
|
reads: Type.Optional(ReadsOverride),
|
|
1136
1078
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking for this task" })),
|
|
1137
1079
|
tier: TierOverride,
|
|
1080
|
+
model: ModelOverride,
|
|
1081
|
+
thinking: ThinkingOverride,
|
|
1138
1082
|
skill: Type.Optional(SkillOverride),
|
|
1139
1083
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
1140
1084
|
acceptance: Type.Optional(AcceptanceOverride)
|
|
@@ -1154,6 +1098,8 @@ var SkillOverride = Type.Unsafe({
|
|
|
1154
1098
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
1155
1099
|
skill: Type.Optional(SkillOverride),
|
|
1156
1100
|
tier: TierOverride,
|
|
1101
|
+
model: ModelOverride,
|
|
1102
|
+
thinking: ThinkingOverride,
|
|
1157
1103
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
1158
1104
|
acceptance: Type.Optional(AcceptanceOverride)
|
|
1159
1105
|
}), DynamicExpandSchema = Type.Object({
|
|
@@ -1183,6 +1129,8 @@ var SkillOverride = Type.Unsafe({
|
|
|
1183
1129
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
1184
1130
|
skill: Type.Optional(SkillOverride),
|
|
1185
1131
|
tier: TierOverride,
|
|
1132
|
+
model: ModelOverride,
|
|
1133
|
+
thinking: ThinkingOverride,
|
|
1186
1134
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
1187
1135
|
acceptance: Type.Optional(AcceptanceOverride)
|
|
1188
1136
|
}, { additionalProperties: !1 }), DynamicCollectSchema = Type.Object({
|
|
@@ -1205,6 +1153,8 @@ var SkillOverride = Type.Unsafe({
|
|
|
1205
1153
|
progress: Type.Optional(Type.Boolean({ description: "Enable progress.md tracking in {chain_dir}" })),
|
|
1206
1154
|
skill: Type.Optional(SkillOverride),
|
|
1207
1155
|
tier: TierOverride,
|
|
1156
|
+
model: ModelOverride,
|
|
1157
|
+
thinking: ThinkingOverride,
|
|
1208
1158
|
toolBudget: Type.Optional(ToolBudgetOverride),
|
|
1209
1159
|
acceptance: Type.Optional(AcceptanceOverride),
|
|
1210
1160
|
parallel: Type.Optional(Type.Unsafe({
|
|
@@ -1222,7 +1172,7 @@ var SkillOverride = Type.Unsafe({
|
|
|
1222
1172
|
description: "Create isolated git worktrees for each parallel task."
|
|
1223
1173
|
}))
|
|
1224
1174
|
}, {
|
|
1225
|
-
description: "Chain step: use {task, description, tier, permissions?} for sequential, {parallel: [...]} for static concurrent execution, or {expand, parallel: {...}, collect} for dynamic fanout. Every executable child
|
|
1175
|
+
description: "Chain step: use {task, description, tier|model, permissions?} for sequential, {parallel: [...]} for static concurrent execution, or {expand, parallel: {...}, collect} for dynamic fanout. Every executable child needs exactly one of tier or model.",
|
|
1226
1176
|
additionalProperties: !1
|
|
1227
1177
|
}), ControlOverrides = Type.Object({
|
|
1228
1178
|
enabled: Type.Optional(Type.Boolean({ description: "Enable/disable subagent control attention tracking for this run" })),
|
|
@@ -1261,12 +1211,9 @@ var SkillOverride = Type.Unsafe({
|
|
|
1261
1211
|
})),
|
|
1262
1212
|
lines: Type.Optional(Type.Integer({ minimum: 1, maximum: 500, description: "Maximum transcript lines for action='status', view='transcript'. Defaults to 80." })),
|
|
1263
1213
|
message: Type.Optional(Type.String({ description: "Follow-up message for action='resume' or non-terminal guidance for action='steer'. Use index to choose a child from multi-child runs." })),
|
|
1264
|
-
scope: Type.Optional(Type.String({ enum: ["session", "user", "project"], description: "Scope for action='watchdog.configure'. Defaults to session to avoid persistent settings writes unless user/project is explicit." })),
|
|
1265
|
-
target: Type.Optional(Type.String({ enum: ["main", "children"], description: "Target for action='watchdog.configure'. Defaults to main." })),
|
|
1266
|
-
thinking: Type.Optional(Type.Unsafe({ anyOf: [{ type: "string" }, { type: "boolean", enum: [!1] }], description: "Thinking level for action='watchdog.configure' (off/minimal/low/medium/high/xhigh/max, inherit, or false for off)." })),
|
|
1267
1214
|
schedule: Type.Optional(Type.String({ description: "Explicit one-shot schedule for action='schedule'. Only honored when scheduledRuns.enabled is true. Use '+10m' or a future ISO timestamp with timezone; scheduled runs always launch async with fresh context." })),
|
|
1268
1215
|
scheduleName: Type.Optional(Type.String({ description: "Optional display name for action='schedule'." })),
|
|
1269
|
-
tasks: Type.Optional(Type.Array(TaskItem, { description: "PARALLEL mode: [{task, description, tier, permissions?, count?, output?, outputMode?, reads?, progress?}, ...]" })),
|
|
1216
|
+
tasks: Type.Optional(Type.Array(TaskItem, { description: "PARALLEL mode: [{task, description, tier|model, thinking?, permissions?, count?, output?, outputMode?, reads?, progress?}, ...]" })),
|
|
1270
1217
|
concurrency: Type.Optional(Type.Integer({ minimum: 1, description: "Top-level PARALLEL mode only: max concurrent tasks. Defaults to config.parallel.concurrency or unlimited." })),
|
|
1271
1218
|
worktree: Type.Optional(Type.Boolean({
|
|
1272
1219
|
description: "Create isolated git worktrees for parallel tasks; requires clean git state."
|
|
@@ -1277,7 +1224,7 @@ var SkillOverride = Type.Unsafe({
|
|
|
1277
1224
|
description: "Children always start with a fresh session. Fork context is not available."
|
|
1278
1225
|
})),
|
|
1279
1226
|
chainDir: Type.Optional(Type.String({ description: "Persistent chain artifact directory; defaults to user-scoped temp storage." })),
|
|
1280
|
-
async: Type.Optional(Type.Boolean({ description: "Run in background
|
|
1227
|
+
async: Type.Optional(Type.Boolean({ description: "Run async in the background. Defaults to true when omitted; set false for immediate foreground results." })),
|
|
1281
1228
|
timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Optional run-level timeout in ms for foreground and async/background runs. Alias of maxRuntimeMs." })),
|
|
1282
1229
|
maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias of timeoutMs for optional run-level timeout in foreground and async/background runs." })),
|
|
1283
1230
|
turnBudget: Type.Optional(TurnBudgetOverride),
|
|
@@ -1288,7 +1235,7 @@ var SkillOverride = Type.Unsafe({
|
|
|
1288
1235
|
share: Type.Optional(Type.Boolean({ description: "Upload session to GitHub Gist for sharing (default: false)" })),
|
|
1289
1236
|
sessionDir: Type.Optional(Type.String({ description: "Directory to store session logs (default: temp; enables sessions even if share=false)" })),
|
|
1290
1237
|
// Clarification TUI
|
|
1291
|
-
clarify: Type.Optional(Type.Boolean({ description: "Show TUI
|
|
1238
|
+
clarify: Type.Optional(Type.Boolean({ description: "Show the interactive TUI preview/editor before execution. clarify:true keeps the run foreground even when async is omitted or true." })),
|
|
1292
1239
|
control: Type.Optional(ControlOverrides),
|
|
1293
1240
|
output: Type.Optional(Type.Unsafe({
|
|
1294
1241
|
anyOf: [
|
|
@@ -1301,15 +1248,26 @@ var SkillOverride = Type.Unsafe({
|
|
|
1301
1248
|
skill: Type.Optional(SkillOverride),
|
|
1302
1249
|
tier: Type.Optional(Type.String({
|
|
1303
1250
|
enum: ["light", "standard", "heavy"],
|
|
1304
|
-
description:
|
|
1251
|
+
description: `Preferred for SINGLE execution. Required by default. Omit for control actions. Do not combine with model; PARALLEL and CHAIN children carry their own tier or model. ${TIER_SELECTION_DESCRIPTION}`
|
|
1252
|
+
})),
|
|
1253
|
+
model: Type.Optional(Type.String({
|
|
1254
|
+
minLength: 1,
|
|
1255
|
+
description: "Explicit provider/model for SINGLE execution only when the user names a model. Do not combine with tier."
|
|
1256
|
+
})),
|
|
1257
|
+
thinking: Type.Optional(Type.String({
|
|
1258
|
+
enum: ["off", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
1259
|
+
description: "Thinking level for an explicit model launch. Tier launches use configured tier thinking instead."
|
|
1305
1260
|
})),
|
|
1306
1261
|
acceptance: Type.Optional(AcceptanceOverride)
|
|
1307
1262
|
}), SubagentParams = keepTopLevelParameterDescriptions(SubagentParamsSchema), SubagentWaitParamsSchema = Type.Object({
|
|
1308
1263
|
id: Type.Optional(Type.String({
|
|
1309
1264
|
description: "Async run or remembered detached foreground run id/prefix to wait for one specific run. Omit to wait across every active async run started in this session."
|
|
1310
1265
|
})),
|
|
1266
|
+
questionId: Type.Optional(Type.String({
|
|
1267
|
+
description: "Wait for one supervisor question id from subagent_supervisor action='ask'. Returns when that question is answered, expired, or cancelled. Separate from final async run results."
|
|
1268
|
+
})),
|
|
1311
1269
|
all: Type.Optional(Type.Boolean({
|
|
1312
|
-
description: "Wait for ALL active runs to finish. Default false: return as soon as the first run finishes, so a fleet manager can spawn a replacement and wait again. Ignored when id targets
|
|
1270
|
+
description: "Wait for ALL active runs to finish. Default false: return as soon as the first run finishes, so a fleet manager can spawn a replacement and wait again. Ignored when id or questionId targets one item."
|
|
1313
1271
|
})),
|
|
1314
1272
|
timeoutMs: Type.Optional(Type.Integer({
|
|
1315
1273
|
minimum: 1,
|
|
@@ -1334,28 +1292,28 @@ function typeName(value) {
|
|
|
1334
1292
|
function quoteList(keys) {
|
|
1335
1293
|
return keys.map((key) => `"${key}"`).join(", ");
|
|
1336
1294
|
}
|
|
1337
|
-
function disallowedMessage(
|
|
1295
|
+
function disallowedMessage(path13, keys, allowed, example) {
|
|
1338
1296
|
let subject = keys.length === 1 ? `property "${keys[0]}" is not allowed` : `properties ${quoteList(keys)} are not allowed`, examplePart = example ? `
|
|
1339
1297
|
|
|
1340
1298
|
Example: ${example}` : "";
|
|
1341
|
-
return `subagent ${
|
|
1299
|
+
return `subagent ${path13}: ${subject}.
|
|
1342
1300
|
Allowed properties: ${allowed.join(", ")}.${examplePart}`;
|
|
1343
1301
|
}
|
|
1344
|
-
function expectObject(value,
|
|
1302
|
+
function expectObject(value, path13, allowed, example) {
|
|
1345
1303
|
if (!isPlainObject(value)) {
|
|
1346
1304
|
let examplePart = example ? `
|
|
1347
1305
|
|
|
1348
1306
|
Example: ${example}` : "";
|
|
1349
|
-
throw new Error(`subagent ${
|
|
1307
|
+
throw new Error(`subagent ${path13}: expected an object, received ${typeName(value)}.
|
|
1350
1308
|
Allowed properties: ${allowed.join(", ")}.${examplePart}`);
|
|
1351
1309
|
}
|
|
1352
1310
|
}
|
|
1353
|
-
function checkNoExtraKeys(value,
|
|
1311
|
+
function checkNoExtraKeys(value, path13, schema, allowed, example) {
|
|
1354
1312
|
if (schema.additionalProperties !== !1)
|
|
1355
1313
|
return;
|
|
1356
1314
|
let extra = disallowedKeys(value, allowed);
|
|
1357
1315
|
if (extra.length > 0)
|
|
1358
|
-
throw new Error(disallowedMessage(
|
|
1316
|
+
throw new Error(disallowedMessage(path13, extra, allowed, example));
|
|
1359
1317
|
}
|
|
1360
1318
|
function validateChainInput(args) {
|
|
1361
1319
|
if (!isPlainObject(args))
|
|
@@ -1513,7 +1471,7 @@ function createAsyncJobTracker(pi, state, asyncDirRoot, options = {}) {
|
|
|
1513
1471
|
if (parsed.type !== "subagent.control")
|
|
1514
1472
|
return;
|
|
1515
1473
|
let record = parsed;
|
|
1516
|
-
if (!record.event || !Array.isArray(record.channels))
|
|
1474
|
+
if (!record.event || !Array.isArray(record.channels) || record.event.reason === "completion_guard")
|
|
1517
1475
|
return;
|
|
1518
1476
|
let payload = {
|
|
1519
1477
|
event: record.event,
|
|
@@ -1608,8 +1566,7 @@ function createAsyncJobTracker(pi, state, asyncDirRoot, options = {}) {
|
|
|
1608
1566
|
}
|
|
1609
1567
|
widgetRenderKey(job) !== widgetStateBefore && (widgetChanged = !0);
|
|
1610
1568
|
}
|
|
1611
|
-
|
|
1612
|
-
(widgetChanged || timerNeedsPaint) && state.lastUiContext?.hasUI && rerenderWidget(state.lastUiContext);
|
|
1569
|
+
widgetChanged && state.lastUiContext?.hasUI && rerenderWidget(state.lastUiContext);
|
|
1613
1570
|
}, pollIntervalMs), state.poller.unref?.());
|
|
1614
1571
|
};
|
|
1615
1572
|
return { ensurePoller, refreshWidget, handleStarted: (data) => {
|
|
@@ -1749,15 +1706,15 @@ function createFileCoalescer(handler, defaultDelayMs, timerApi = defaultTimerApi
|
|
|
1749
1706
|
|
|
1750
1707
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/runs/background/result-watcher.js
|
|
1751
1708
|
var WATCHER_RESTART_DELAY_MS = 3e3, POLL_INTERVAL_MS2 = 3e3;
|
|
1752
|
-
function sanitizeNestedResultChildren(value, resultPath, label) {
|
|
1709
|
+
function sanitizeNestedResultChildren(value, resultPath, label, report) {
|
|
1753
1710
|
if (value === void 0)
|
|
1754
1711
|
return;
|
|
1755
1712
|
if (!Array.isArray(value)) {
|
|
1756
|
-
|
|
1713
|
+
report(`Ignoring invalid nested children in subagent result file '${resultPath}' at ${label}: expected an array.`);
|
|
1757
1714
|
return;
|
|
1758
1715
|
}
|
|
1759
1716
|
let children = value.map((child) => sanitizeSummary(child)).filter((child) => !!child);
|
|
1760
|
-
return children.length !== value.length &&
|
|
1717
|
+
return children.length !== value.length && report(`Ignoring ${value.length - children.length} invalid nested child record(s) in subagent result file '${resultPath}' at ${label}.`), children.length ? children : void 0;
|
|
1761
1718
|
}
|
|
1762
1719
|
function getErrorCode(error) {
|
|
1763
1720
|
return typeof error == "object" && error !== null && "code" in error ? error.code : void 0;
|
|
@@ -1770,27 +1727,27 @@ function shouldFallBackToPolling(error) {
|
|
|
1770
1727
|
return code === "EMFILE" || code === "ENOSPC";
|
|
1771
1728
|
}
|
|
1772
1729
|
function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {}) {
|
|
1773
|
-
let fsApi = deps.fs ?? fs2, timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval },
|
|
1774
|
-
|
|
1775
|
-
|
|
1730
|
+
let fsApi = deps.fs ?? fs2, timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval }, generation = 0, inFlight = /* @__PURE__ */ new Set(), attempts = /* @__PURE__ */ new Map(), report = (message, error) => {
|
|
1731
|
+
pi.appendEntry?.("subagent_result_delivery", { message, error: error instanceof Error ? error.message : error });
|
|
1732
|
+
}, handleResult = async (file) => {
|
|
1733
|
+
if (inFlight.has(file) || (attempts.get(file) ?? 0) >= 3)
|
|
1734
|
+
return;
|
|
1735
|
+
let currentGeneration = generation, sessionId = state.currentSessionId, isCurrent = () => generation === currentGeneration && state.currentSessionId === sessionId, resultPath = path2.join(resultsDir, file);
|
|
1736
|
+
if (fsApi.existsSync(resultPath)) {
|
|
1737
|
+
inFlight.add(file);
|
|
1776
1738
|
try {
|
|
1777
1739
|
let data = JSON.parse(fsApi.readFileSync(resultPath, "utf-8"));
|
|
1778
1740
|
if (typeof data.sessionId != "string" || data.sessionId !== state.currentSessionId)
|
|
1779
1741
|
return;
|
|
1780
|
-
let runId = data.runId ?? data.id ?? file.replace(/\.json$/i, ""), hasExplicitNestedChildren = data.nestedChildren !== void 0, nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
|
|
1742
|
+
let runId = data.runId ?? data.id ?? file.replace(/\.json$/i, ""), hasExplicitNestedChildren = data.nestedChildren !== void 0, nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren", report));
|
|
1781
1743
|
if (!nestedChildren?.length && !hasExplicitNestedChildren)
|
|
1782
1744
|
try {
|
|
1783
1745
|
nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
|
|
1784
1746
|
} catch (error) {
|
|
1785
|
-
|
|
1747
|
+
report(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
|
|
1786
1748
|
return;
|
|
1787
1749
|
}
|
|
1788
|
-
let now = Date.now(), completionKey = buildCompletionKey(data, `result:${file}`)
|
|
1789
|
-
if (markSeenWithTtl(state.completionSeen, completionKey, now, completionTtlMs)) {
|
|
1790
|
-
fsApi.unlinkSync(resultPath);
|
|
1791
|
-
return;
|
|
1792
|
-
}
|
|
1793
|
-
let hasResultChildren = Array.isArray(data.results) && data.results.length > 0, resultChildren = hasResultChildren ? data.results : [{
|
|
1750
|
+
let now = Date.now(), completionKey = buildCompletionKey(data, `result:${file}`), hasResultChildren = Array.isArray(data.results) && data.results.length > 0, resultChildren = hasResultChildren ? data.results : [{
|
|
1794
1751
|
agent: data.agent,
|
|
1795
1752
|
output: data.summary,
|
|
1796
1753
|
success: data.success
|
|
@@ -1798,7 +1755,7 @@ function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps = {})
|
|
|
1798
1755
|
let baseOutput = result2.output ?? data.summary, hasRealOutput = typeof baseOutput == "string" && baseOutput.trim().length > 0, output = hasRealOutput ? baseOutput : "(no output)", summary = result2.success === !1 && result2.error ? `${result2.error}${hasRealOutput ? `
|
|
1799
1756
|
|
|
1800
1757
|
Output:
|
|
1801
|
-
${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : void 0), childNestedChildren = sanitizeNestedResultChildren(result2.children, resultPath, `results[${index}].children
|
|
1758
|
+
${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : void 0), childNestedChildren = sanitizeNestedResultChildren(result2.children, resultPath, `results[${index}].children`, report), childState = result2.state === "paused" || result2.state === "stopped" ? result2.state : result2.stopped === !0 ? "stopped" : data.state === "paused" || !hasResultChildren && (data.state === "stopped" || typeof result2.success != "boolean") ? data.state : void 0;
|
|
1802
1759
|
return {
|
|
1803
1760
|
agent: result2.agent ?? data.agent ?? `step-${index + 1}`,
|
|
1804
1761
|
status: resolveSubagentResultStatus({
|
|
@@ -1812,7 +1769,24 @@ ${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChil
|
|
|
1812
1769
|
...result2.intercomTarget ? { intercomTarget: result2.intercomTarget } : {},
|
|
1813
1770
|
...childNestedChildren ? { children: childNestedChildren } : {}
|
|
1814
1771
|
};
|
|
1815
|
-
}), nestedChildren)
|
|
1772
|
+
}), nestedChildren);
|
|
1773
|
+
if (markSeenWithTtl(state.completionSeen, completionKey, now, completionTtlMs) || pi.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
|
|
1774
|
+
...data,
|
|
1775
|
+
runId,
|
|
1776
|
+
...nestedChildren?.length ? { nestedChildren } : {},
|
|
1777
|
+
...Array.isArray(data.results) ? { results: hasResultChildren ? normalizedChildren.map((child, index) => ({
|
|
1778
|
+
...data.results[index],
|
|
1779
|
+
agent: child.agent,
|
|
1780
|
+
status: child.status,
|
|
1781
|
+
summary: child.summary,
|
|
1782
|
+
index: child.index,
|
|
1783
|
+
artifactPath: child.artifactPath,
|
|
1784
|
+
sessionPath: child.sessionPath,
|
|
1785
|
+
children: child.children
|
|
1786
|
+
})) : [] } : {}
|
|
1787
|
+
}), !isCurrent())
|
|
1788
|
+
return;
|
|
1789
|
+
let intercomTarget = data.state === "stopped" ? void 0 : data.intercomTarget?.trim();
|
|
1816
1790
|
if (intercomTarget) {
|
|
1817
1791
|
let mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain" ? data.mode : resultChildren.length > 1 ? "chain" : "single", payload = buildSubagentResultIntercomPayload({
|
|
1818
1792
|
to: intercomTarget,
|
|
@@ -1823,30 +1797,24 @@ ${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChil
|
|
|
1823
1797
|
asyncId: data.id,
|
|
1824
1798
|
asyncDir: data.asyncDir
|
|
1825
1799
|
});
|
|
1826
|
-
|
|
1800
|
+
payload.requestId = `async-result:${sessionId}:${completionKey}`, payload.ownerNotificationSessionId = sessionId, attempts.set(file, (attempts.get(file) ?? 0) + 1);
|
|
1801
|
+
let delivered = await deliverSubagentResultIntercomEvent(pi.events, payload);
|
|
1802
|
+
if (!isCurrent())
|
|
1803
|
+
return;
|
|
1804
|
+
if (!delivered) {
|
|
1805
|
+
report(`Async result delivery pending for '${runId}'; output retained.`, resultPath), attempts.get(file) < 3 && state.resultFileCoalescer.schedule(file, 1e3);
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1827
1808
|
}
|
|
1828
|
-
|
|
1829
|
-
...data,
|
|
1830
|
-
runId,
|
|
1831
|
-
...nestedChildren?.length ? { nestedChildren } : {},
|
|
1832
|
-
...Array.isArray(data.results) ? {
|
|
1833
|
-
results: hasResultChildren ? normalizedChildren.map((child, index) => ({
|
|
1834
|
-
...data.results[index],
|
|
1835
|
-
agent: child.agent,
|
|
1836
|
-
status: child.status,
|
|
1837
|
-
summary: child.summary,
|
|
1838
|
-
index: child.index,
|
|
1839
|
-
artifactPath: child.artifactPath,
|
|
1840
|
-
sessionPath: child.sessionPath,
|
|
1841
|
-
children: child.children
|
|
1842
|
-
})) : []
|
|
1843
|
-
} : {}
|
|
1844
|
-
}), fsApi.unlinkSync(resultPath);
|
|
1809
|
+
isCurrent() && fsApi.unlinkSync(resultPath);
|
|
1845
1810
|
} catch (error) {
|
|
1846
1811
|
if (isNotFoundError(error))
|
|
1847
1812
|
return;
|
|
1848
|
-
|
|
1813
|
+
report(`Failed to process subagent result file '${resultPath}'.`, error);
|
|
1814
|
+
} finally {
|
|
1815
|
+
inFlight.delete(file);
|
|
1849
1816
|
}
|
|
1817
|
+
}
|
|
1850
1818
|
};
|
|
1851
1819
|
state.resultFileCoalescer = createFileCoalescer((file) => {
|
|
1852
1820
|
handleResult(file);
|
|
@@ -1857,10 +1825,10 @@ ${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChil
|
|
|
1857
1825
|
} catch (error) {
|
|
1858
1826
|
if (isNotFoundError(error))
|
|
1859
1827
|
return;
|
|
1860
|
-
|
|
1828
|
+
report(`Failed to scan subagent result directory '${resultsDir}':`, error);
|
|
1861
1829
|
}
|
|
1862
1830
|
}, startPollingFallback = (reason) => {
|
|
1863
|
-
state.watcher?.close(), state.watcher = null, !state.watcherRestartTimer && (
|
|
1831
|
+
state.watcher?.close(), state.watcher = null, !state.watcherRestartTimer && (report(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${getErrorCode(reason) ?? "unknown error"}).`), primeExistingResults(), state.watcherRestartTimer = timers.setInterval(primeExistingResults, POLL_INTERVAL_MS2), state.watcherRestartTimer.unref?.());
|
|
1864
1832
|
}, scheduleRestart = () => {
|
|
1865
1833
|
state.watcherRestartTimer || (state.watcherRestartTimer = timers.setTimeout(() => {
|
|
1866
1834
|
state.watcherRestartTimer = null;
|
|
@@ -1871,7 +1839,7 @@ ${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChil
|
|
|
1871
1839
|
startPollingFallback(error);
|
|
1872
1840
|
return;
|
|
1873
1841
|
}
|
|
1874
|
-
|
|
1842
|
+
report(`Failed to restart subagent result watcher for '${resultsDir}':`, error), scheduleRestart();
|
|
1875
1843
|
}
|
|
1876
1844
|
}, WATCHER_RESTART_DELAY_MS), state.watcherRestartTimer.unref?.());
|
|
1877
1845
|
}, startResultWatcher = () => {
|
|
@@ -1889,19 +1857,19 @@ ${baseOutput}` : ""}` : output, sessionPath = result2.sessionFile ?? (resultChil
|
|
|
1889
1857
|
startPollingFallback(error);
|
|
1890
1858
|
return;
|
|
1891
1859
|
}
|
|
1892
|
-
|
|
1860
|
+
report(`Subagent result watcher failed for '${resultsDir}':`, error), state.watcher?.close(), state.watcher = null, scheduleRestart();
|
|
1893
1861
|
}), state.watcher.unref?.();
|
|
1894
1862
|
} catch (error) {
|
|
1895
1863
|
if (shouldFallBackToPolling(error)) {
|
|
1896
1864
|
startPollingFallback(error);
|
|
1897
1865
|
return;
|
|
1898
1866
|
}
|
|
1899
|
-
|
|
1867
|
+
report(`Failed to start subagent result watcher for '${resultsDir}':`, error), state.watcher = null, scheduleRestart();
|
|
1900
1868
|
}
|
|
1901
1869
|
}
|
|
1902
1870
|
};
|
|
1903
1871
|
return { startResultWatcher, primeExistingResults, stopResultWatcher: () => {
|
|
1904
|
-
state.watcher?.close(), state.watcher = null, state.watcherRestartTimer && (timers.clearTimeout(state.watcherRestartTimer), timers.clearInterval(state.watcherRestartTimer)), state.watcherRestartTimer = null, state.resultFileCoalescer.clear();
|
|
1872
|
+
generation++, attempts.clear(), state.watcher?.close(), state.watcher = null, state.watcherRestartTimer && (timers.clearTimeout(state.watcherRestartTimer), timers.clearInterval(state.watcherRestartTimer)), state.watcherRestartTimer = null, state.resultFileCoalescer.clear();
|
|
1905
1873
|
} };
|
|
1906
1874
|
}
|
|
1907
1875
|
|
|
@@ -2434,7 +2402,7 @@ function substituteArgs(template, args) {
|
|
|
2434
2402
|
return template.replace(/\$ARGUMENTS/g, all).replace(/\$@/g, all).replace(/\$\{(\d+):-([^}]*)\}/g, (_match, index, fallback) => args[Number(index) - 1] || fallback).replace(/\$(\d+)/g, (_match, index) => args[Number(index) - 1] ?? "");
|
|
2435
2403
|
}
|
|
2436
2404
|
function parseRuntimeOptions(words) {
|
|
2437
|
-
let args = [], descriptionOverride, permissions, worktree = !1,
|
|
2405
|
+
let args = [], descriptionOverride, permissions, worktree = !1, async;
|
|
2438
2406
|
for (let i = 0; i < words.length; i++) {
|
|
2439
2407
|
let word = words[i];
|
|
2440
2408
|
if (word === "--read-only") {
|
|
@@ -2450,7 +2418,11 @@ function parseRuntimeOptions(words) {
|
|
|
2450
2418
|
continue;
|
|
2451
2419
|
}
|
|
2452
2420
|
if (word === "--bg" || word === "--async") {
|
|
2453
|
-
|
|
2421
|
+
async = !0;
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
if (word === "--fg" || word === "--foreground") {
|
|
2425
|
+
async = !1;
|
|
2454
2426
|
continue;
|
|
2455
2427
|
}
|
|
2456
2428
|
if (word === "--description") {
|
|
@@ -2464,7 +2436,7 @@ function parseRuntimeOptions(words) {
|
|
|
2464
2436
|
}
|
|
2465
2437
|
args.push(word);
|
|
2466
2438
|
}
|
|
2467
|
-
return { args, descriptionOverride, permissions, worktree,
|
|
2439
|
+
return { args, descriptionOverride, permissions, worktree, async };
|
|
2468
2440
|
}
|
|
2469
2441
|
function splitChainDeclaration(input) {
|
|
2470
2442
|
let delimiter = input.indexOf(" -- ");
|
|
@@ -2483,7 +2455,7 @@ function workflowParams(workflow, args, runtime) {
|
|
|
2483
2455
|
...workflow.skill !== void 0 ? { skill: workflow.skill } : {},
|
|
2484
2456
|
...workflow.cwd ? { cwd: workflow.cwd } : {},
|
|
2485
2457
|
...runtime.worktree || workflow.worktree ? { worktree: !0 } : {},
|
|
2486
|
-
...runtime.
|
|
2458
|
+
...runtime.async !== void 0 ? { async: runtime.async } : {}
|
|
2487
2459
|
};
|
|
2488
2460
|
}
|
|
2489
2461
|
function workflowChainStep(workflow, args, runtime) {
|
|
@@ -2531,7 +2503,7 @@ function registerPromptWorkflowCommands(input) {
|
|
|
2531
2503
|
throw new Error(`Unknown prompt workflow in chain '${workflow.name}': ${stepName}`);
|
|
2532
2504
|
return workflowChainStep(step, runtime.args, runtime);
|
|
2533
2505
|
});
|
|
2534
|
-
await run({ chain, task: runtime.args.join(" "), clarify: !1, ...runtime.
|
|
2506
|
+
await run({ chain, task: runtime.args.join(" "), clarify: !1, ...runtime.async !== void 0 ? { async: runtime.async } : {} }, ctx);
|
|
2535
2507
|
return;
|
|
2536
2508
|
}
|
|
2537
2509
|
await run(workflowParams(workflow, runtime.args, runtime), ctx);
|
|
@@ -2559,7 +2531,7 @@ function registerPromptWorkflowCommands(input) {
|
|
|
2559
2531
|
throw new Error(`Unknown prompt workflow: ${name}`);
|
|
2560
2532
|
return workflowChainStep(workflow, runtime.args, runtime);
|
|
2561
2533
|
});
|
|
2562
|
-
await run({ chain, task: runtime.args.join(" "), clarify: !1, ...runtime.
|
|
2534
|
+
await run({ chain, task: runtime.args.join(" "), clarify: !1, ...runtime.async !== void 0 ? { async: runtime.async } : {} }, ctx);
|
|
2563
2535
|
} catch (error) {
|
|
2564
2536
|
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
2565
2537
|
}
|
|
@@ -3090,6 +3062,12 @@ var parseInlineConfig = (raw) => {
|
|
|
3090
3062
|
case "tier":
|
|
3091
3063
|
(val === "light" || val === "standard" || val === "heavy") && (config.tier = val);
|
|
3092
3064
|
break;
|
|
3065
|
+
case "model":
|
|
3066
|
+
val && (config.model = val);
|
|
3067
|
+
break;
|
|
3068
|
+
case "thinking":
|
|
3069
|
+
["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(val) && (config.thinking = val);
|
|
3070
|
+
break;
|
|
3093
3071
|
case "permissions":
|
|
3094
3072
|
(val === "full" || val === "read-only") && (config.permissions = val);
|
|
3095
3073
|
break;
|
|
@@ -3133,15 +3111,14 @@ var parseInlineConfig = (raw) => {
|
|
|
3133
3111
|
let end = token.lastIndexOf("]");
|
|
3134
3112
|
return { name: token.slice(0, bracket), config: parseInlineConfig(token.slice(bracket + 1, end !== -1 ? end : void 0)) };
|
|
3135
3113
|
}, extractExecutionFlags = (rawArgs) => {
|
|
3136
|
-
let args = rawArgs.trim(),
|
|
3114
|
+
let args = rawArgs.trim(), async;
|
|
3137
3115
|
for (; ; ) {
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
break;
|
|
3116
|
+
let match = args.match(/(?:^|\s)(--bg|--async|--fg|--foreground)$/);
|
|
3117
|
+
if (!match)
|
|
3118
|
+
break;
|
|
3119
|
+
async ??= match[1] === "--bg" || match[1] === "--async", args = args.slice(0, match.index).trim();
|
|
3143
3120
|
}
|
|
3144
|
-
return { args,
|
|
3121
|
+
return { args, async };
|
|
3145
3122
|
};
|
|
3146
3123
|
function sendSlashText(pi, text) {
|
|
3147
3124
|
pi.sendMessage({ customType: SLASH_TEXT_RESULT_TYPE, content: text, display: !0 });
|
|
@@ -3639,12 +3616,16 @@ function loadInlineOutputSchema(baseCwd, agent, value) {
|
|
|
3639
3616
|
}
|
|
3640
3617
|
var mapParsedTaskToStepObject = (step, fallbackTask, isFirst, opts) => {
|
|
3641
3618
|
let { name, config, task: stepTask } = step;
|
|
3642
|
-
if (!config.tier)
|
|
3643
|
-
throw new SlashParseError(`Step '${name}' requires tier=light
|
|
3619
|
+
if (!config.tier && !config.model)
|
|
3620
|
+
throw new SlashParseError(`Step '${name}' requires tier=light|standard|heavy or model=provider/id.`);
|
|
3621
|
+
if (config.tier && config.model)
|
|
3622
|
+
throw new SlashParseError(`Step '${name}' must choose exactly one of tier or model.`);
|
|
3644
3623
|
return config.acceptance !== void 0 && validateInlineAcceptanceInput(config.acceptance, name), {
|
|
3645
3624
|
description: name,
|
|
3646
3625
|
permissions: config.permissions ?? "full",
|
|
3647
|
-
tier: config.tier,
|
|
3626
|
+
...config.tier ? { tier: config.tier } : {},
|
|
3627
|
+
...config.model ? { model: config.model } : {},
|
|
3628
|
+
...config.thinking ? { thinking: config.thinking } : {},
|
|
3648
3629
|
...stepTask ? { task: stepTask } : isFirst && fallbackTask ? { task: fallbackTask } : {},
|
|
3649
3630
|
...config.output !== void 0 ? { output: config.output } : {},
|
|
3650
3631
|
...config.outputMode !== void 0 ? { outputMode: config.outputMode } : {},
|
|
@@ -3718,16 +3699,16 @@ function registerSlashCommands(pi, state) {
|
|
|
3718
3699
|
}
|
|
3719
3700
|
};
|
|
3720
3701
|
pi.registerCommand("run", {
|
|
3721
|
-
description: "Run
|
|
3702
|
+
description: "Run an async prompt-defined child; add --foreground to wait inline",
|
|
3722
3703
|
handler: async (args, ctx) => {
|
|
3723
|
-
let { args: cleanedArgs,
|
|
3704
|
+
let { args: cleanedArgs, async } = extractExecutionFlags(args), input = cleanedArgs.trim(), firstSpace = input.indexOf(" ");
|
|
3724
3705
|
if (!input) {
|
|
3725
|
-
ctx.ui.notify("Usage: /run <description> <task> [--
|
|
3706
|
+
ctx.ui.notify("Usage: /run <description> <task> [--foreground]", "error");
|
|
3726
3707
|
return;
|
|
3727
3708
|
}
|
|
3728
3709
|
let { name: description, config: inline } = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace)), task = firstSpace === -1 ? "" : input.slice(firstSpace + 1).trim();
|
|
3729
3710
|
if (!description || !task || !inline.tier) {
|
|
3730
|
-
ctx.ui.notify("Usage: /run <description>[tier=light|standard|heavy] <task> [--
|
|
3711
|
+
ctx.ui.notify("Usage: /run <description>[tier=light|standard|heavy] <task> [--foreground]", "error");
|
|
3731
3712
|
return;
|
|
3732
3713
|
}
|
|
3733
3714
|
let finalTask = task;
|
|
@@ -3735,27 +3716,29 @@ function registerSlashCommands(pi, state) {
|
|
|
3735
3716
|
|
|
3736
3717
|
${finalTask}`);
|
|
3737
3718
|
let params = { description, permissions: inline.permissions ?? "full", tier: inline.tier, task: finalTask, clarify: !1 };
|
|
3738
|
-
inline.output !== void 0 && (params.output = inline.output), inline.outputMode !== void 0 && (params.outputMode = inline.outputMode), inline.skill !== void 0 && (params.skill = inline.skill),
|
|
3719
|
+
inline.output !== void 0 && (params.output = inline.output), inline.outputMode !== void 0 && (params.outputMode = inline.outputMode), inline.skill !== void 0 && (params.skill = inline.skill), async !== void 0 && (params.async = async), await runSlashSubagent(pi, ctx, params);
|
|
3739
3720
|
}
|
|
3740
3721
|
}), pi.registerCommand("chain", {
|
|
3741
|
-
description:
|
|
3722
|
+
description: "Run prompt-defined children as an async sequence; add --foreground to wait inline",
|
|
3742
3723
|
handler: async (args, ctx) => {
|
|
3743
|
-
let { args: cleanedArgs,
|
|
3724
|
+
let { args: cleanedArgs, async } = extractExecutionFlags(args), built = buildChainExpressionSteps(state, cleanedArgs, ctx);
|
|
3744
3725
|
if (!built)
|
|
3745
3726
|
return;
|
|
3746
3727
|
let params = { chain: built.chain, task: built.task, clarify: !1 };
|
|
3747
|
-
|
|
3728
|
+
async !== void 0 && (params.async = async), await runSlashSubagent(pi, ctx, params);
|
|
3748
3729
|
}
|
|
3749
3730
|
}), pi.registerCommand("parallel", {
|
|
3750
|
-
description:
|
|
3731
|
+
description: "Run prompt-defined children async in parallel; add --foreground to wait inline",
|
|
3751
3732
|
handler: async (args, ctx) => {
|
|
3752
|
-
let { args: cleanedArgs,
|
|
3733
|
+
let { args: cleanedArgs, async } = extractExecutionFlags(args), parsed = parseAgentArgs(state, cleanedArgs, "parallel", ctx);
|
|
3753
3734
|
if (!parsed)
|
|
3754
3735
|
return;
|
|
3755
3736
|
let tasks = parsed.steps.map(({ name, config, task: stepTask }) => ({
|
|
3756
3737
|
description: name,
|
|
3757
3738
|
permissions: config.permissions ?? "full",
|
|
3758
|
-
tier: config.tier,
|
|
3739
|
+
...config.tier ? { tier: config.tier } : {},
|
|
3740
|
+
...config.model ? { model: config.model } : {},
|
|
3741
|
+
...config.thinking ? { thinking: config.thinking } : {},
|
|
3759
3742
|
task: stepTask ?? parsed.task,
|
|
3760
3743
|
...config.output !== void 0 ? { output: config.output } : {},
|
|
3761
3744
|
...config.outputMode !== void 0 ? { outputMode: config.outputMode } : {},
|
|
@@ -3763,12 +3746,16 @@ ${finalTask}`);
|
|
|
3763
3746
|
...config.skill !== void 0 ? { skill: config.skill } : {},
|
|
3764
3747
|
...config.progress !== void 0 ? { progress: config.progress } : {}
|
|
3765
3748
|
}));
|
|
3766
|
-
if (tasks.some((task) => !task.tier)) {
|
|
3767
|
-
ctx.ui.notify("Every parallel child requires [tier=light|standard|heavy].", "error");
|
|
3749
|
+
if (tasks.some((task) => !task.tier && !task.model)) {
|
|
3750
|
+
ctx.ui.notify("Every parallel child requires [tier=light|standard|heavy] or [model=provider/id].", "error");
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
if (tasks.some((task) => task.tier && task.model)) {
|
|
3754
|
+
ctx.ui.notify("Each parallel child must choose exactly one of tier or model.", "error");
|
|
3768
3755
|
return;
|
|
3769
3756
|
}
|
|
3770
3757
|
let params = { tasks, clarify: !1 };
|
|
3771
|
-
|
|
3758
|
+
async !== void 0 && (params.async = async), await runSlashSubagent(pi, ctx, params);
|
|
3772
3759
|
}
|
|
3773
3760
|
}), pi.registerCommand("subagent-cost", {
|
|
3774
3761
|
description: "Show parent and subagent child usage cost for this session",
|
|
@@ -4392,28 +4379,506 @@ function registerSlashSubagentBridge(options) {
|
|
|
4392
4379
|
}
|
|
4393
4380
|
|
|
4394
4381
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js
|
|
4382
|
+
import * as fs7 from "node:fs";
|
|
4383
|
+
import * as path8 from "node:path";
|
|
4384
|
+
import { Type as Type2 } from "typebox";
|
|
4385
|
+
|
|
4386
|
+
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-questions.js
|
|
4387
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
4395
4388
|
import * as fs6 from "node:fs";
|
|
4396
4389
|
import * as path7 from "node:path";
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4390
|
+
var QUESTIONS_DIR = "questions", SUPERVISOR_CHANNEL_ROOT = path7.join(TEMP_ROOT_DIR, "supervisor-channels"), SUBAGENT_SUPERVISOR_ANSWER_TYPE = "subagent_supervisor_answer", SUBAGENT_QUESTION_EVENT = "subagent:supervisor-question", MAX_MESSAGE_BYTES = 64 * 1024, DEFAULT_ASK_TIMEOUT_MS = 600 * 1e3, activeQuestionWaits = /* @__PURE__ */ new Set();
|
|
4391
|
+
function askTimeoutMs() {
|
|
4392
|
+
let parsed = Number(process.env.PI_INTERCOM_ASK_TIMEOUT_MS);
|
|
4393
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_ASK_TIMEOUT_MS;
|
|
4394
|
+
}
|
|
4395
|
+
function safeSegment(value) {
|
|
4396
|
+
return value.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
|
|
4397
|
+
}
|
|
4398
|
+
function resolveSupervisorChannelDir(runId, agent, childIndex) {
|
|
4399
|
+
return path7.join(SUPERVISOR_CHANNEL_ROOT, `${safeSegment(runId)}-${safeSegment(agent)}-${childIndex}`);
|
|
4400
|
+
}
|
|
4401
|
+
function questionsDir(channelDir) {
|
|
4402
|
+
return path7.join(channelDir, QUESTIONS_DIR);
|
|
4403
|
+
}
|
|
4404
|
+
function questionFile(channelDir, questionId) {
|
|
4405
|
+
return path7.join(questionsDir(channelDir), `${safeSegment(questionId)}.json`);
|
|
4406
|
+
}
|
|
4407
|
+
function deliveredFile(channelDir, questionId) {
|
|
4408
|
+
return path7.join(questionsDir(channelDir), `${safeSegment(questionId)}.delivered.json`);
|
|
4409
|
+
}
|
|
4410
|
+
function terminalFile(channelDir, questionId) {
|
|
4411
|
+
return path7.join(questionsDir(channelDir), `${safeSegment(questionId)}.terminal.json`);
|
|
4412
|
+
}
|
|
4413
|
+
function notifiedFile(channelDir, questionId) {
|
|
4414
|
+
return path7.join(questionsDir(channelDir), `${safeSegment(questionId)}.notified.json`);
|
|
4415
|
+
}
|
|
4416
|
+
function lateFile(channelDir, questionId) {
|
|
4417
|
+
return path7.join(questionsDir(channelDir), `${safeSegment(questionId)}.late.json`);
|
|
4418
|
+
}
|
|
4419
|
+
function writeExclusiveJson(filePath, payload) {
|
|
4420
|
+
fs6.mkdirSync(path7.dirname(filePath), { recursive: !0, mode: 448 });
|
|
4421
|
+
let temporary = `${filePath}.${randomUUID3()}.tmp`;
|
|
4422
|
+
try {
|
|
4423
|
+
return fs6.writeFileSync(temporary, JSON.stringify(payload), { encoding: "utf-8", flag: "wx", mode: 384 }), fs6.linkSync(temporary, filePath), !0;
|
|
4424
|
+
} catch (error) {
|
|
4425
|
+
if (error.code === "EEXIST")
|
|
4426
|
+
return !1;
|
|
4427
|
+
throw error;
|
|
4428
|
+
} finally {
|
|
4429
|
+
fs6.rmSync(temporary, { force: !0 });
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
function readJsonFile(filePath) {
|
|
4433
|
+
return JSON.parse(fs6.readFileSync(filePath, "utf-8"));
|
|
4434
|
+
}
|
|
4435
|
+
function tryReadJson(filePath) {
|
|
4436
|
+
try {
|
|
4437
|
+
return readJsonFile(filePath);
|
|
4438
|
+
} catch (error) {
|
|
4439
|
+
return error.code === "ENOENT", void 0;
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
function parseIncarnation(raw) {
|
|
4443
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4444
|
+
return;
|
|
4445
|
+
let input = raw, pid = input.pid, readyAt = input.readyAt;
|
|
4446
|
+
if (!(!Number.isInteger(pid) || pid === void 0 || pid <= 0) && !(typeof readyAt != "number" || !Number.isFinite(readyAt) || readyAt <= 0))
|
|
4447
|
+
return { pid, readyAt };
|
|
4448
|
+
}
|
|
4449
|
+
function parseQuestionRecord(raw) {
|
|
4450
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4451
|
+
return;
|
|
4452
|
+
let input = raw;
|
|
4453
|
+
if (input.type !== "subagent.supervisor.question" || typeof input.id != "string" || !input.id.trim() || typeof input.createdAt != "number" || !Number.isFinite(input.createdAt) || typeof input.expiresAt != "number" || !Number.isFinite(input.expiresAt) || typeof input.reason != "string" || !input.reason.trim() || typeof input.message != "string" || !input.message.trim() || typeof input.runId != "string" || !input.runId.trim())
|
|
4454
|
+
return;
|
|
4455
|
+
let childIndex = input.childIndex;
|
|
4456
|
+
if (!Number.isInteger(childIndex) || childIndex === void 0 || childIndex < 0 || typeof input.childId != "string" || !input.childId.trim() || typeof input.parentSessionId != "string" || !input.parentSessionId.trim())
|
|
4457
|
+
return;
|
|
4458
|
+
let parentGeneration = input.parentGeneration;
|
|
4459
|
+
if (!Number.isInteger(parentGeneration) || parentGeneration === void 0 || parentGeneration < 0)
|
|
4460
|
+
return;
|
|
4461
|
+
let incarnation = parseIncarnation(input.childIncarnation);
|
|
4462
|
+
return {
|
|
4463
|
+
type: "subagent.supervisor.question",
|
|
4464
|
+
id: input.id.trim(),
|
|
4465
|
+
createdAt: input.createdAt,
|
|
4466
|
+
expiresAt: input.expiresAt,
|
|
4467
|
+
reason: input.reason.trim(),
|
|
4468
|
+
message: input.message.trim(),
|
|
4469
|
+
runId: input.runId.trim(),
|
|
4470
|
+
childIndex,
|
|
4471
|
+
childId: input.childId.trim(),
|
|
4472
|
+
parentSessionId: input.parentSessionId.trim(),
|
|
4473
|
+
parentGeneration,
|
|
4474
|
+
...incarnation ? { childIncarnation: incarnation } : {}
|
|
4475
|
+
};
|
|
4476
|
+
}
|
|
4477
|
+
function parseDeliveredRecord(raw) {
|
|
4478
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4479
|
+
return;
|
|
4480
|
+
let input = raw;
|
|
4481
|
+
if (input.type !== "subagent.supervisor.delivered" || typeof input.id != "string" || !input.id.trim() || typeof input.at != "number" || !Number.isFinite(input.at))
|
|
4482
|
+
return;
|
|
4483
|
+
let incarnation = parseIncarnation(input);
|
|
4484
|
+
if (incarnation)
|
|
4485
|
+
return { type: "subagent.supervisor.delivered", id: input.id.trim(), at: input.at, pid: incarnation.pid, readyAt: incarnation.readyAt };
|
|
4486
|
+
}
|
|
4487
|
+
function parseTerminalRecord(raw) {
|
|
4488
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4489
|
+
return;
|
|
4490
|
+
let input = raw;
|
|
4491
|
+
if (!(input.type !== "subagent.supervisor.terminal" || typeof input.id != "string" || !input.id.trim()) && !(typeof input.at != "number" || !Number.isFinite(input.at))) {
|
|
4492
|
+
if (input.state === "answered")
|
|
4493
|
+
return typeof input.message != "string" || !input.message.trim() ? void 0 : { type: "subagent.supervisor.terminal", id: input.id.trim(), state: "answered", at: input.at, message: input.message };
|
|
4494
|
+
if (input.state === "expired")
|
|
4495
|
+
return { type: "subagent.supervisor.terminal", id: input.id.trim(), state: "expired", at: input.at };
|
|
4496
|
+
if (input.state === "cancelled")
|
|
4497
|
+
return typeof input.reason != "string" || !input.reason.trim() ? void 0 : { type: "subagent.supervisor.terminal", id: input.id.trim(), state: "cancelled", at: input.at, reason: input.reason.trim() };
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4500
|
+
function parseNotifiedRecord(raw) {
|
|
4501
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4502
|
+
return;
|
|
4503
|
+
let input = raw;
|
|
4504
|
+
if (!(input.type !== "subagent.supervisor.notified" || typeof input.id != "string" || !input.id.trim()) && !(typeof input.at != "number" || !Number.isFinite(input.at)))
|
|
4505
|
+
return { type: "subagent.supervisor.notified", id: input.id.trim(), at: input.at };
|
|
4506
|
+
}
|
|
4507
|
+
function parseLateRecord(raw) {
|
|
4508
|
+
if (!raw || typeof raw != "object" || Array.isArray(raw))
|
|
4509
|
+
return;
|
|
4510
|
+
let input = raw;
|
|
4511
|
+
if (!(input.type !== "subagent.supervisor.late-answer" || typeof input.id != "string" || !input.id.trim()) && !(typeof input.at != "number" || !Number.isFinite(input.at) || typeof input.message != "string"))
|
|
4512
|
+
return { type: "subagent.supervisor.late-answer", id: input.id.trim(), at: input.at, message: input.message };
|
|
4513
|
+
}
|
|
4514
|
+
function composeQuestion(record, channelDir) {
|
|
4515
|
+
let delivered = parseDeliveredRecord(tryReadJson(deliveredFile(channelDir, record.id))), terminal = parseTerminalRecord(tryReadJson(terminalFile(channelDir, record.id))), notified = parseNotifiedRecord(tryReadJson(notifiedFile(channelDir, record.id))), late = parseLateRecord(tryReadJson(lateFile(channelDir, record.id)));
|
|
4516
|
+
return {
|
|
4517
|
+
...record,
|
|
4518
|
+
...delivered ? { deliveredAt: delivered.at, childIncarnation: record.childIncarnation ?? { pid: delivered.pid, readyAt: delivered.readyAt } } : {},
|
|
4519
|
+
...terminal?.state === "answered" ? { answeredAt: terminal.at, answer: terminal.message } : {},
|
|
4520
|
+
...terminal?.state === "expired" ? { expiredAt: terminal.at } : {},
|
|
4521
|
+
...terminal?.state === "cancelled" ? { cancelledAt: terminal.at, cancelReason: terminal.reason } : {},
|
|
4522
|
+
...notified ? { notifiedAt: notified.at } : {},
|
|
4523
|
+
...late ? { lateAnswerAt: late.at, ...terminal?.state === "answered" ? {} : { answer: late.message } } : {}
|
|
4524
|
+
};
|
|
4525
|
+
}
|
|
4526
|
+
function assertMessageSize(value, label) {
|
|
4527
|
+
if (Buffer.byteLength(value, "utf-8") > MAX_MESSAGE_BYTES)
|
|
4528
|
+
throw new Error(`${label} is too large.`);
|
|
4529
|
+
}
|
|
4530
|
+
function ensureQuestionsDir(channelDir) {
|
|
4531
|
+
fs6.mkdirSync(questionsDir(channelDir), { recursive: !0, mode: 448 });
|
|
4532
|
+
}
|
|
4533
|
+
function supervisorQuestionPublicState(question) {
|
|
4534
|
+
return question.answeredAt ? "answered" : question.expiredAt ? "expired" : question.cancelledAt ? "cancelled" : "pending";
|
|
4535
|
+
}
|
|
4536
|
+
function supervisorQuestionIsTerminal(question) {
|
|
4537
|
+
return supervisorQuestionPublicState(question) !== "pending";
|
|
4538
|
+
}
|
|
4539
|
+
function readSupervisorQuestion(channelDir, questionId) {
|
|
4540
|
+
let record = parseQuestionRecord(tryReadJson(questionFile(channelDir, questionId)));
|
|
4541
|
+
if (!(!record || record.id !== questionId))
|
|
4542
|
+
return composeQuestion(record, channelDir);
|
|
4543
|
+
}
|
|
4544
|
+
function listSupervisorQuestions(channelDir) {
|
|
4545
|
+
let dir = questionsDir(channelDir), entries;
|
|
4546
|
+
try {
|
|
4547
|
+
entries = fs6.readdirSync(dir).filter((name) => name.endsWith(".json") && !name.endsWith(".delivered.json") && !name.endsWith(".terminal.json") && !name.endsWith(".notified.json") && !name.endsWith(".late.json"));
|
|
4548
|
+
} catch (error) {
|
|
4549
|
+
if (error.code === "ENOENT")
|
|
4550
|
+
return [];
|
|
4551
|
+
throw error;
|
|
4552
|
+
}
|
|
4553
|
+
let questions = [];
|
|
4554
|
+
for (let entry of entries.sort()) {
|
|
4555
|
+
let record = parseQuestionRecord(tryReadJson(path7.join(dir, entry)));
|
|
4556
|
+
record && questions.push(composeQuestion(record, channelDir));
|
|
4557
|
+
}
|
|
4558
|
+
return questions;
|
|
4559
|
+
}
|
|
4560
|
+
function writeTerminal(channelDir, record) {
|
|
4561
|
+
return writeExclusiveJson(terminalFile(channelDir, record.id), record);
|
|
4562
|
+
}
|
|
4563
|
+
function createSupervisorQuestion(input) {
|
|
4564
|
+
let reason = input.reason.trim(), message = input.message.trim();
|
|
4565
|
+
if (!reason)
|
|
4566
|
+
throw new Error("reason is required and must name the concrete decision the child's answer will change.");
|
|
4567
|
+
if (!message)
|
|
4568
|
+
throw new Error("message is required for supervisor questions.");
|
|
4569
|
+
assertMessageSize(reason, "reason"), assertMessageSize(message, "message");
|
|
4570
|
+
let createdAt = input.now ?? Date.now(), timeoutMs = input.timeoutMs && input.timeoutMs > 0 ? input.timeoutMs : askTimeoutMs(), record = {
|
|
4571
|
+
type: "subagent.supervisor.question",
|
|
4572
|
+
id: input.id ?? randomUUID3(),
|
|
4573
|
+
createdAt,
|
|
4574
|
+
expiresAt: createdAt + timeoutMs,
|
|
4575
|
+
reason,
|
|
4576
|
+
message,
|
|
4577
|
+
runId: input.runId,
|
|
4578
|
+
childIndex: input.childIndex,
|
|
4579
|
+
childId: input.childId,
|
|
4580
|
+
parentSessionId: input.parentSessionId,
|
|
4581
|
+
parentGeneration: input.parentGeneration,
|
|
4582
|
+
...input.childIncarnation ? { childIncarnation: input.childIncarnation } : {}
|
|
4583
|
+
};
|
|
4584
|
+
if (assertMessageSize(JSON.stringify(record), "Supervisor question"), ensureQuestionsDir(input.channelDir), !writeExclusiveJson(questionFile(input.channelDir, record.id), record))
|
|
4585
|
+
throw new Error(`Supervisor question '${record.id}' already exists.`);
|
|
4586
|
+
return composeQuestion(record, input.channelDir);
|
|
4587
|
+
}
|
|
4588
|
+
function outstandingQuestionsForChild(channelDir, childIndex, childId) {
|
|
4589
|
+
return refreshSupervisorQuestionLifecycle(channelDir), listSupervisorQuestions(channelDir).filter((question) => !(supervisorQuestionIsTerminal(question) || question.childIndex !== childIndex || childId && question.childId !== childId));
|
|
4590
|
+
}
|
|
4591
|
+
function hasBlockingSupervisorRequest(channelDir, runId, childIndex) {
|
|
4592
|
+
let directory = path7.join(channelDir, "requests");
|
|
4593
|
+
if (!fs6.existsSync(directory))
|
|
4594
|
+
return !1;
|
|
4595
|
+
for (let name of fs6.readdirSync(directory)) {
|
|
4596
|
+
if (!name.endsWith(".json"))
|
|
4597
|
+
continue;
|
|
4598
|
+
let raw = tryReadJson(path7.join(directory, name));
|
|
4599
|
+
if (!raw || typeof raw != "object")
|
|
4600
|
+
continue;
|
|
4601
|
+
let request = raw;
|
|
4602
|
+
if (!(request.type !== "subagent.supervisor.request" || request.expectsReply !== !0) && !(request.runId !== runId || request.childIndex !== childIndex || typeof request.id != "string") && !(typeof request.expiresAt == "number" && request.expiresAt <= Date.now()) && !fs6.existsSync(path7.join(channelDir, "replies", `${safeSegment(request.id)}.json`)))
|
|
4603
|
+
return !0;
|
|
4604
|
+
}
|
|
4605
|
+
return !1;
|
|
4606
|
+
}
|
|
4607
|
+
function hasOutstandingQuestionForChild(channelDir, childIndex, childId) {
|
|
4608
|
+
return outstandingQuestionsForChild(channelDir, childIndex, childId).length > 0;
|
|
4609
|
+
}
|
|
4610
|
+
function incarnationMatches(expected, actual) {
|
|
4611
|
+
return expected ? expected.pid === actual.pid && expected.readyAt === actual.readyAt : !0;
|
|
4612
|
+
}
|
|
4613
|
+
function expireSupervisorQuestion(channelDir, questionId, now = Date.now()) {
|
|
4614
|
+
let current = readSupervisorQuestion(channelDir, questionId);
|
|
4615
|
+
return !current || supervisorQuestionIsTerminal(current) || now <= current.expiresAt ? current && supervisorQuestionIsTerminal(current) ? current : void 0 : (writeTerminal(channelDir, { type: "subagent.supervisor.terminal", id: questionId, state: "expired", at: now }), readSupervisorQuestion(channelDir, questionId));
|
|
4616
|
+
}
|
|
4617
|
+
function cancelSupervisorQuestion(channelDir, questionId, reason, now = Date.now()) {
|
|
4618
|
+
let current = readSupervisorQuestion(channelDir, questionId);
|
|
4619
|
+
return !current || supervisorQuestionIsTerminal(current) ? current : (writeTerminal(channelDir, { type: "subagent.supervisor.terminal", id: questionId, state: "cancelled", at: now, reason: reason.trim() || "cancelled" }), readSupervisorQuestion(channelDir, questionId));
|
|
4620
|
+
}
|
|
4621
|
+
function refreshSupervisorQuestionLifecycle(channelDir, now = Date.now()) {
|
|
4622
|
+
let changed = [];
|
|
4623
|
+
for (let question of listSupervisorQuestions(channelDir))
|
|
4624
|
+
if (!supervisorQuestionIsTerminal(question) && now > question.expiresAt) {
|
|
4625
|
+
let expired = expireSupervisorQuestion(channelDir, question.id, now);
|
|
4626
|
+
expired && expired.expiredAt && changed.push(expired);
|
|
4627
|
+
}
|
|
4628
|
+
return changed;
|
|
4629
|
+
}
|
|
4630
|
+
function formatParentQuestionForChild(question) {
|
|
4631
|
+
return [
|
|
4632
|
+
`Parent question (${question.id})`,
|
|
4633
|
+
`Decision needed: ${question.reason}`,
|
|
4634
|
+
"",
|
|
4635
|
+
question.message,
|
|
4636
|
+
"",
|
|
4637
|
+
`Reply with: contact_supervisor({ action: "reply", replyTo: "${question.id}", message: "..." })`,
|
|
4638
|
+
"Answer from current findings and uncertainty. Do not silently start extra investigation. Continue the assigned task after replying."
|
|
4639
|
+
].join(`
|
|
4640
|
+
`);
|
|
4641
|
+
}
|
|
4642
|
+
function formatSupervisorQuestionAnswer(question) {
|
|
4643
|
+
let state = supervisorQuestionPublicState(question), lines = [
|
|
4644
|
+
state === "answered" ? `Subagent answer (${question.id})` : `Subagent question ${state} (${question.id})`,
|
|
4645
|
+
`Run: ${question.runId}`,
|
|
4646
|
+
`Child: ${question.childId} [#${question.childIndex}]`,
|
|
4647
|
+
`Decision: ${question.reason}`
|
|
4648
|
+
];
|
|
4649
|
+
return state === "answered" && question.answer?.trim() ? lines.push("", question.answer.trim()) : question.cancelReason && lines.push("", question.cancelReason), lines.join(`
|
|
4650
|
+
`);
|
|
4651
|
+
}
|
|
4652
|
+
function registerQuestionWait(questionIds) {
|
|
4653
|
+
let ids = [...questionIds];
|
|
4654
|
+
for (let id of ids)
|
|
4655
|
+
activeQuestionWaits.add(id);
|
|
4656
|
+
return () => {
|
|
4657
|
+
for (let id of ids)
|
|
4658
|
+
activeQuestionWaits.delete(id);
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
function isQuestionWaitActive(questionId) {
|
|
4662
|
+
return activeQuestionWaits.has(questionId);
|
|
4663
|
+
}
|
|
4664
|
+
function claimQuestionNotification(channelDir, questionId, now = Date.now()) {
|
|
4665
|
+
return writeExclusiveJson(notifiedFile(channelDir, questionId), {
|
|
4666
|
+
type: "subagent.supervisor.notified",
|
|
4667
|
+
id: questionId,
|
|
4668
|
+
at: now
|
|
4669
|
+
});
|
|
4670
|
+
}
|
|
4671
|
+
function listSupervisorChannelDirs() {
|
|
4672
|
+
let entries;
|
|
4673
|
+
try {
|
|
4674
|
+
entries = fs6.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: !0 });
|
|
4675
|
+
} catch (error) {
|
|
4676
|
+
if (error.code === "ENOENT")
|
|
4677
|
+
return [];
|
|
4678
|
+
throw error;
|
|
4679
|
+
}
|
|
4680
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => path7.join(SUPERVISOR_CHANNEL_ROOT, entry.name));
|
|
4681
|
+
}
|
|
4682
|
+
function findSupervisorQuestion(questionId) {
|
|
4683
|
+
let id = questionId.trim();
|
|
4684
|
+
if (id)
|
|
4685
|
+
for (let channelDir of listSupervisorChannelDirs()) {
|
|
4686
|
+
let question = readSupervisorQuestion(channelDir, id);
|
|
4687
|
+
if (question)
|
|
4688
|
+
return { channelDir, question };
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
function cancelPendingSupervisorQuestionsForOwner(input) {
|
|
4692
|
+
if (!input.parentSessionId?.trim())
|
|
4693
|
+
return [];
|
|
4694
|
+
let now = input.now ?? Date.now(), cancelled = [];
|
|
4695
|
+
for (let channelDir of listSupervisorChannelDirs())
|
|
4696
|
+
for (let question of listSupervisorQuestions(channelDir)) {
|
|
4697
|
+
if (supervisorQuestionIsTerminal(question) || question.parentSessionId !== input.parentSessionId || input.parentGeneration !== void 0 && question.parentGeneration !== input.parentGeneration || input.runId && question.runId !== input.runId)
|
|
4698
|
+
continue;
|
|
4699
|
+
let next = cancelSupervisorQuestion(channelDir, question.id, input.reason, now);
|
|
4700
|
+
next?.cancelledAt && cancelled.push(next);
|
|
4701
|
+
}
|
|
4702
|
+
return cancelled;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/intercom/supervisor-ask.js
|
|
4706
|
+
function runningSteps(status) {
|
|
4707
|
+
return (status.steps ?? []).map((step, index) => ({
|
|
4708
|
+
index,
|
|
4709
|
+
childId: step.childId ?? step.agent,
|
|
4710
|
+
agent: step.agent,
|
|
4711
|
+
status: step.status
|
|
4712
|
+
})).filter((step) => step.status === "running").map((step) => ({ index: step.index, childId: step.childId, agent: step.agent }));
|
|
4713
|
+
}
|
|
4714
|
+
function resolveAskChild(status, params) {
|
|
4715
|
+
if (params.index !== void 0 && (!Number.isInteger(params.index) || params.index < 0))
|
|
4716
|
+
throw new Error("index must be a non-negative integer.");
|
|
4717
|
+
let running = runningSteps(status);
|
|
4718
|
+
if (params.childId?.trim()) {
|
|
4719
|
+
let childId = params.childId.trim(), matches = (status.steps ?? []).map((step, index) => ({ index, childId: step.childId ?? step.agent, agent: step.agent, status: step.status })).filter((step) => step.childId === childId);
|
|
4720
|
+
if (matches.length === 0)
|
|
4721
|
+
throw new Error(`Async run '${status.runId}' has no child '${childId}'.`);
|
|
4722
|
+
if (matches.length > 1)
|
|
4723
|
+
throw new Error(`Async run '${status.runId}' has multiple children named '${childId}'. Pass index.`);
|
|
4724
|
+
let match = matches[0];
|
|
4725
|
+
if (params.index !== void 0 && params.index !== match.index)
|
|
4726
|
+
throw new Error(`Child '${childId}' is index ${match.index}, not ${params.index}.`);
|
|
4727
|
+
if (match.status !== "running")
|
|
4728
|
+
throw new Error(`Async run '${status.runId}' child ${match.index} is ${match.status} and cannot be asked.`);
|
|
4729
|
+
return { index: match.index, childId: match.childId, agent: match.agent };
|
|
4730
|
+
}
|
|
4731
|
+
if (params.index !== void 0) {
|
|
4732
|
+
let steps = status.steps ?? [];
|
|
4733
|
+
if (params.index >= steps.length)
|
|
4734
|
+
throw new Error(`Async run '${status.runId}' has ${steps.length} children. Index ${params.index} is out of range.`);
|
|
4735
|
+
let step = steps[params.index];
|
|
4736
|
+
if (step.status !== "running")
|
|
4737
|
+
throw new Error(`Async run '${status.runId}' child ${params.index} is ${step.status} and cannot be asked.`);
|
|
4738
|
+
return { index: params.index, childId: step.childId ?? step.agent, agent: step.agent };
|
|
4739
|
+
}
|
|
4740
|
+
if (running.length === 1)
|
|
4741
|
+
return running[0];
|
|
4742
|
+
throw running.length === 0 ? new Error(`Async run '${status.runId}' has no running child to ask.`) : new Error(`Async run '${status.runId}' has ${running.length} running children. Pass index or childId; broadcast asks are not supported.`);
|
|
4743
|
+
}
|
|
4744
|
+
function requestMatchesChild(request, runId, child) {
|
|
4745
|
+
if (!request.expectsReply || typeof request.runId != "string" || request.runId !== runId)
|
|
4746
|
+
return !1;
|
|
4747
|
+
let indexMatches = Number.isInteger(request.childIndex) && request.childIndex === child.index, idMatches = request.agent === child.childId || request.agent === child.agent || request.childTarget === child.childId;
|
|
4748
|
+
return indexMatches && idMatches;
|
|
4749
|
+
}
|
|
4750
|
+
function reconcileAsyncQuestion(channelDir, question, state) {
|
|
4751
|
+
expireSupervisorQuestion(channelDir, question.id);
|
|
4752
|
+
let current = readSupervisorQuestion(channelDir, question.id) ?? question;
|
|
4753
|
+
if (supervisorQuestionIsTerminal(current))
|
|
4754
|
+
return current;
|
|
4755
|
+
let resolved = resolveSubagentRunId(current.runId, { state });
|
|
4756
|
+
if (resolved?.kind !== "async" || !resolved.location.asyncDir)
|
|
4757
|
+
return current;
|
|
4758
|
+
let status = readStatus(resolved.location.asyncDir);
|
|
4759
|
+
if (!status)
|
|
4760
|
+
return current;
|
|
4761
|
+
let step = status.steps?.[current.childIndex], capability = readSteerCapability(resolved.location.asyncDir, current.childIndex), reason;
|
|
4762
|
+
status.sessionId !== current.parentSessionId ? reason = "async run ownership changed" : status.state !== "running" || !step || step.status !== "running" ? reason = "target child is no longer running" : (step.childId ?? step.agent) !== current.childId ? reason = "target child identity changed" : capability && !incarnationMatches(current.childIncarnation, capability) ? reason = "target child process changed" : capability && !capability.supported && (reason = "target child no longer accepts questions");
|
|
4763
|
+
let delivery = status.steering?.recent.find((request) => request.id === current.id)?.targets.find((target) => target.index === current.childIndex);
|
|
4764
|
+
return (delivery?.state === "failed" || delivery?.state === "late") && (reason = delivery.reason ?? "question delivery failed"), reason ? cancelSupervisorQuestion(channelDir, current.id, reason) ?? current : current;
|
|
4765
|
+
}
|
|
4766
|
+
function askRunningAsyncChild(input) {
|
|
4767
|
+
let runId = input.params.id?.trim();
|
|
4768
|
+
if (!runId)
|
|
4769
|
+
throw new Error("action='ask' requires id for the async run.");
|
|
4770
|
+
let reason = input.params.reason?.trim(), message = input.params.message?.trim();
|
|
4771
|
+
if (!reason)
|
|
4772
|
+
throw new Error("action='ask' requires reason naming the concrete decision the child's answer will change.");
|
|
4773
|
+
if (!message)
|
|
4774
|
+
throw new Error("action='ask' requires message.");
|
|
4775
|
+
let sessionId = input.state.currentSessionId;
|
|
4776
|
+
if (!sessionId)
|
|
4777
|
+
throw new Error("action='ask' requires an active session identity.");
|
|
4778
|
+
let resolved = resolveSubagentRunId(runId, { state: input.state });
|
|
4779
|
+
if (!resolved)
|
|
4780
|
+
throw new Error(`No async run matched '${runId}'.`);
|
|
4781
|
+
if (resolved.kind !== "async")
|
|
4782
|
+
throw new Error("action='ask' targets a running async child only. It does not revive, reassign, or broadcast.");
|
|
4783
|
+
if (!resolved.location.asyncDir)
|
|
4784
|
+
throw new Error(`Async run '${resolved.id}' has no live run directory.`);
|
|
4785
|
+
let status = readStatus(resolved.location.asyncDir);
|
|
4786
|
+
if (!status)
|
|
4787
|
+
throw new Error(`Async run '${resolved.id}' has no status.`);
|
|
4788
|
+
if (!status.sessionId || status.sessionId !== sessionId)
|
|
4789
|
+
throw new Error(`Async run '${resolved.id}' was not found in the active session.`);
|
|
4790
|
+
if (status.state !== "running")
|
|
4791
|
+
throw new Error(`Async run '${resolved.id}' is ${status.state} and cannot be asked.`);
|
|
4792
|
+
let child = resolveAskChild(status, input.params), channelDir = resolveSupervisorChannelDir(status.runId, child.childId, child.index);
|
|
4793
|
+
if (hasOutstandingQuestionForChild(channelDir, child.index, child.childId))
|
|
4794
|
+
throw new Error(`A question is already outstanding for async run '${status.runId}' child ${child.index}. Wait for that answer or expiry before asking again.`);
|
|
4795
|
+
for (let request of input.childRequests ?? [])
|
|
4796
|
+
if (requestMatchesChild(request, status.runId, child))
|
|
4797
|
+
throw new Error(`Child ${child.index} is waiting for a supervisor reply. Asking now would deadlock. Reply to the child request first.`);
|
|
4798
|
+
if (hasBlockingSupervisorRequest(channelDir, status.runId, child.index))
|
|
4799
|
+
throw new Error("Child is waiting for a supervisor reply. Reply to its request before asking a question.");
|
|
4800
|
+
let capability = readSteerCapability(resolved.location.asyncDir, child.index);
|
|
4801
|
+
if (!capability?.supported)
|
|
4802
|
+
throw new Error("This child is not ready to receive questions. Continue other work until it is ready; no question was queued.");
|
|
4803
|
+
let incarnation = { pid: capability.pid, readyAt: capability.readyAt }, question = createSupervisorQuestion({
|
|
4804
|
+
channelDir,
|
|
4805
|
+
reason,
|
|
4806
|
+
message,
|
|
4807
|
+
runId: status.runId,
|
|
4808
|
+
childIndex: child.index,
|
|
4809
|
+
childId: child.childId,
|
|
4810
|
+
parentSessionId: sessionId,
|
|
4811
|
+
parentGeneration: input.state.sessionGeneration ?? 0,
|
|
4812
|
+
childIncarnation: incarnation
|
|
4813
|
+
});
|
|
4814
|
+
try {
|
|
4815
|
+
if (hasBlockingSupervisorRequest(channelDir, status.runId, child.index))
|
|
4816
|
+
throw new Error("Child is waiting for a supervisor reply. Reply to its request before asking a question.");
|
|
4817
|
+
requestAsyncSteer(resolved.location.asyncDir, {
|
|
4818
|
+
message: formatParentQuestionForChild(question),
|
|
4819
|
+
targetIndex: child.index,
|
|
4820
|
+
source: "supervisor-question",
|
|
4821
|
+
id: question.id
|
|
4822
|
+
});
|
|
4823
|
+
} catch (error) {
|
|
4824
|
+
throw cancelSupervisorQuestion(channelDir, question.id, "failed to queue delivery to child"), error instanceof Error ? error : new Error(String(error));
|
|
4825
|
+
}
|
|
4826
|
+
return {
|
|
4827
|
+
content: [{ type: "text", text: `Question ${question.id} queued for async run ${status.runId} child ${child.index}. The child's answer is delivered separately from the run result.` }],
|
|
4828
|
+
details: {
|
|
4829
|
+
questionId: question.id,
|
|
4830
|
+
state: "pending",
|
|
4831
|
+
runId: status.runId,
|
|
4832
|
+
childIndex: child.index,
|
|
4833
|
+
childId: child.childId,
|
|
4834
|
+
delivered: !1,
|
|
4835
|
+
answered: !1
|
|
4836
|
+
}
|
|
4837
|
+
};
|
|
4838
|
+
}
|
|
4839
|
+
|
|
4840
|
+
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/intercom/native-supervisor-channel.js
|
|
4841
|
+
var REQUESTS_DIR = "requests", REPLIES_DIR = "replies", NATIVE_SUPERVISOR_TOOL_NAME = "subagent_supervisor";
|
|
4842
|
+
var MAX_MESSAGE_BYTES2 = 64 * 1024, DEFAULT_ASK_TIMEOUT_MS2 = 600 * 1e3, CHANNEL_POLL_MS = Math.min(POLL_INTERVAL_MS, 500), STALE_EMPTY_CHANNEL_AGE_MS = 60 * 1e3, STALE_EMPTY_CHANNEL_CLEANUP_INTERVAL_MS = 60 * 1e3, PARENT_ASK_DESCRIPTION = [
|
|
4843
|
+
"Ask a specific running async child, or reply to a child supervisor request.",
|
|
4844
|
+
"Ask only when the child owns missing context, the answer changes a concrete next decision, and waiting risks a block or rework.",
|
|
4845
|
+
"Use available results first, batch related questions, and keep working while awaiting the answer. Do not use ask for status checks, polling, duplicate queries, or step-by-step supervision. Follow up only when the answer leaves the original decision unresolved.",
|
|
4846
|
+
"Returns a question id immediately. The child's explicit answer is delivered separately from the final run result.",
|
|
4847
|
+
'Ask: { action: "ask", id: "<runId>", index?: 0, childId?: "...", reason: "<concrete decision>", message: "..." }',
|
|
4848
|
+
"Use pending or list to find child requests awaiting your reply; status reports channel availability. Free-form send is unsupported. Asking never revives a child or changes its assignment.",
|
|
4849
|
+
'Reply: { action: "reply", replyTo: "<requestId>", message: "..." }'
|
|
4850
|
+
].join(" "), CHILD_CONTACT_DESCRIPTION = [
|
|
4851
|
+
"Contact the parent/supervisor session for a blocking decision, structured interview, progress update, or reply to a parent question.",
|
|
4852
|
+
"For parent questions use action='reply' with replyTo set to the question id. Answer from current findings and uncertainty; do not start extra investigation just to reply. Continue the assigned task after replying.",
|
|
4853
|
+
"Do not open a blocking need_decision while a parent question is already outstanding for this child."
|
|
4854
|
+
].join(" "), ContactSupervisorParamsSchema = Type2.Object({
|
|
4855
|
+
reason: Type2.Optional(Type2.String({ enum: ["need_decision", "interview_request", "progress_update"] })),
|
|
4400
4856
|
message: Type2.Optional(Type2.String()),
|
|
4401
|
-
interview: Type2.Optional(Type2.Unsafe({ type: "object", additionalProperties: !0 }))
|
|
4857
|
+
interview: Type2.Optional(Type2.Unsafe({ type: "object", additionalProperties: !0 })),
|
|
4858
|
+
action: Type2.Optional(Type2.String({ enum: ["reply"] })),
|
|
4859
|
+
replyTo: Type2.Optional(Type2.String())
|
|
4402
4860
|
}, { additionalProperties: !1 }), IntercomParamsSchema = Type2.Object({
|
|
4403
4861
|
action: Type2.String({ enum: ["list", "send", "ask", "reply", "pending", "status"] }),
|
|
4404
4862
|
to: Type2.Optional(Type2.String()),
|
|
4405
4863
|
message: Type2.Optional(Type2.String()),
|
|
4406
|
-
replyTo: Type2.Optional(Type2.String())
|
|
4864
|
+
replyTo: Type2.Optional(Type2.String()),
|
|
4865
|
+
id: Type2.Optional(Type2.String({ description: "Async run id for action='ask'." })),
|
|
4866
|
+
index: Type2.Optional(Type2.Integer({ minimum: 0, description: "Zero-based child index for action='ask'. Select index or childId when more than one child is running." })),
|
|
4867
|
+
childId: Type2.Optional(Type2.String({ description: "Private child identity for action='ask'." })),
|
|
4868
|
+
reason: Type2.Optional(Type2.String({ description: "Concrete decision the child's answer will change. Required for action='ask'." }))
|
|
4869
|
+
}, { additionalProperties: !1 }), ParentSupervisorParamsSchema = Type2.Object({
|
|
4870
|
+
...IntercomParamsSchema.properties,
|
|
4871
|
+
action: Type2.String({ enum: ["list", "ask", "reply", "pending", "status"] })
|
|
4407
4872
|
}, { additionalProperties: !1 });
|
|
4408
|
-
function
|
|
4873
|
+
function safeSegment2(value) {
|
|
4409
4874
|
return value.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
|
|
4410
4875
|
}
|
|
4411
4876
|
function replyPath(channelDir, requestId) {
|
|
4412
|
-
return
|
|
4877
|
+
return path8.join(channelDir, REPLIES_DIR, `${safeSegment2(requestId)}.json`);
|
|
4413
4878
|
}
|
|
4414
|
-
function
|
|
4879
|
+
function askTimeoutMs2() {
|
|
4415
4880
|
let parsed = Number(process.env.PI_INTERCOM_ASK_TIMEOUT_MS);
|
|
4416
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed :
|
|
4881
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_ASK_TIMEOUT_MS2;
|
|
4417
4882
|
}
|
|
4418
4883
|
function hasTool(pi, name) {
|
|
4419
4884
|
try {
|
|
@@ -4424,16 +4889,26 @@ function hasTool(pi, name) {
|
|
|
4424
4889
|
}
|
|
4425
4890
|
function parseRequestFile(file, channelDir) {
|
|
4426
4891
|
try {
|
|
4427
|
-
let parsed = JSON.parse(
|
|
4428
|
-
return parsed.type !== "subagent.supervisor.request" || typeof parsed.id != "string" || !parsed.id || parsed.reason !== "need_decision" && parsed.reason !== "interview_request" && parsed.reason !== "progress_update" || typeof parsed.message != "string" || !parsed.message || typeof parsed.runId != "string" || typeof parsed.agent != "string" || typeof parsed.childIndex != "number" ? void 0 : { ...parsed, channelDir, requestFile: file };
|
|
4892
|
+
let parsed = JSON.parse(fs7.readFileSync(file, "utf-8"));
|
|
4893
|
+
return parsed.type !== "subagent.supervisor.request" || parsed.supervisorSessionId !== void 0 && (typeof parsed.supervisorSessionId != "string" || !parsed.supervisorSessionId.trim()) || typeof parsed.id != "string" || !parsed.id || parsed.reason !== "need_decision" && parsed.reason !== "interview_request" && parsed.reason !== "progress_update" || typeof parsed.message != "string" || !parsed.message || typeof parsed.runId != "string" || typeof parsed.agent != "string" || typeof parsed.childIndex != "number" ? void 0 : { ...parsed, channelDir, requestFile: file };
|
|
4429
4894
|
} catch {
|
|
4430
4895
|
return;
|
|
4431
4896
|
}
|
|
4432
4897
|
}
|
|
4898
|
+
function hasPendingBlockingSupervisorRequest(runId, sessionId, now = Date.now()) {
|
|
4899
|
+
if (!runId)
|
|
4900
|
+
return !1;
|
|
4901
|
+
for (let { channelDir, file } of listRequestFiles()) {
|
|
4902
|
+
let request = parseRequestFile(file, channelDir);
|
|
4903
|
+
if (request?.expectsReply && request.runId === runId && !(sessionId && (request.supervisorSessionId ?? request.orchestratorSessionId) !== sessionId) && !fs7.existsSync(replyPath(request.channelDir, request.id)) && !(now > requestExpiresAt(request, now)))
|
|
4904
|
+
return !0;
|
|
4905
|
+
}
|
|
4906
|
+
return !1;
|
|
4907
|
+
}
|
|
4433
4908
|
function listRequestFiles() {
|
|
4434
4909
|
let channelEntries;
|
|
4435
4910
|
try {
|
|
4436
|
-
channelEntries =
|
|
4911
|
+
channelEntries = fs7.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: !0 });
|
|
4437
4912
|
} catch (error) {
|
|
4438
4913
|
if (error.code === "ENOENT")
|
|
4439
4914
|
return [];
|
|
@@ -4443,34 +4918,34 @@ function listRequestFiles() {
|
|
|
4443
4918
|
for (let entry of channelEntries) {
|
|
4444
4919
|
if (!entry.isDirectory())
|
|
4445
4920
|
continue;
|
|
4446
|
-
let channelDir =
|
|
4921
|
+
let channelDir = path8.join(SUPERVISOR_CHANNEL_ROOT, entry.name), requestsDir = path8.join(channelDir, REQUESTS_DIR), requestEntries;
|
|
4447
4922
|
try {
|
|
4448
|
-
requestEntries =
|
|
4923
|
+
requestEntries = fs7.readdirSync(requestsDir, { withFileTypes: !0 });
|
|
4449
4924
|
} catch {
|
|
4450
4925
|
continue;
|
|
4451
4926
|
}
|
|
4452
4927
|
for (let requestEntry of requestEntries)
|
|
4453
|
-
requestEntry.isFile() && requestEntry.name.endsWith(".json") && files.push({ channelDir, file:
|
|
4928
|
+
requestEntry.isFile() && requestEntry.name.endsWith(".json") && files.push({ channelDir, file: path8.join(requestsDir, requestEntry.name) });
|
|
4454
4929
|
}
|
|
4455
4930
|
return files;
|
|
4456
4931
|
}
|
|
4457
4932
|
function readDirectoryEntries(dir) {
|
|
4458
4933
|
try {
|
|
4459
|
-
return
|
|
4934
|
+
return fs7.readdirSync(dir, { withFileTypes: !0 });
|
|
4460
4935
|
} catch (error) {
|
|
4461
4936
|
return error.code === "ENOENT" ? [] : void 0;
|
|
4462
4937
|
}
|
|
4463
4938
|
}
|
|
4464
4939
|
function directoryMtimeMs(dir) {
|
|
4465
4940
|
try {
|
|
4466
|
-
return
|
|
4941
|
+
return fs7.statSync(dir).mtimeMs;
|
|
4467
4942
|
} catch {
|
|
4468
4943
|
return 0;
|
|
4469
4944
|
}
|
|
4470
4945
|
}
|
|
4471
4946
|
function removeEmptyDirectory(dir) {
|
|
4472
4947
|
try {
|
|
4473
|
-
return
|
|
4948
|
+
return fs7.rmdirSync(dir), !0;
|
|
4474
4949
|
} catch (error) {
|
|
4475
4950
|
let code = error.code;
|
|
4476
4951
|
if (code === "ENOENT")
|
|
@@ -4481,19 +4956,22 @@ function removeEmptyDirectory(dir) {
|
|
|
4481
4956
|
}
|
|
4482
4957
|
}
|
|
4483
4958
|
function removeStaleEmptySupervisorChannel(channelDir, nowMs) {
|
|
4484
|
-
let requestsDir =
|
|
4959
|
+
let requestsDir = path8.join(channelDir, REQUESTS_DIR), repliesDir = path8.join(channelDir, REPLIES_DIR), questionsPath = path8.join(channelDir, QUESTIONS_DIR), newestKnownMtimeMs = Math.max(directoryMtimeMs(channelDir), directoryMtimeMs(requestsDir), directoryMtimeMs(repliesDir), directoryMtimeMs(questionsPath));
|
|
4485
4960
|
if (nowMs - newestKnownMtimeMs < STALE_EMPTY_CHANNEL_AGE_MS)
|
|
4486
4961
|
return !1;
|
|
4487
4962
|
let requestEntries = readDirectoryEntries(requestsDir);
|
|
4488
4963
|
if (!requestEntries || requestEntries.length > 0)
|
|
4489
4964
|
return !1;
|
|
4490
4965
|
let replyEntries = readDirectoryEntries(repliesDir);
|
|
4491
|
-
|
|
4966
|
+
if (!replyEntries || replyEntries.length > 0)
|
|
4967
|
+
return !1;
|
|
4968
|
+
let questionEntries = readDirectoryEntries(questionsPath);
|
|
4969
|
+
return !(!questionEntries || questionEntries.length > 0 || !removeEmptyDirectory(requestsDir) || !removeEmptyDirectory(repliesDir) || !removeEmptyDirectory(questionsPath) || !removeEmptyDirectory(channelDir));
|
|
4492
4970
|
}
|
|
4493
4971
|
function cleanupStaleEmptySupervisorChannels(nowMs = Date.now()) {
|
|
4494
4972
|
let channelEntries;
|
|
4495
4973
|
try {
|
|
4496
|
-
channelEntries =
|
|
4974
|
+
channelEntries = fs7.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: !0 });
|
|
4497
4975
|
} catch (error) {
|
|
4498
4976
|
if (error.code === "ENOENT")
|
|
4499
4977
|
return 0;
|
|
@@ -4503,7 +4981,7 @@ function cleanupStaleEmptySupervisorChannels(nowMs = Date.now()) {
|
|
|
4503
4981
|
for (let entry of channelEntries)
|
|
4504
4982
|
if (entry.isDirectory())
|
|
4505
4983
|
try {
|
|
4506
|
-
removeStaleEmptySupervisorChannel(
|
|
4984
|
+
removeStaleEmptySupervisorChannel(path8.join(SUPERVISOR_CHANNEL_ROOT, entry.name), nowMs) && removed++;
|
|
4507
4985
|
} catch {
|
|
4508
4986
|
}
|
|
4509
4987
|
return removed;
|
|
@@ -4517,19 +4995,26 @@ function currentContextSessionId(state, ctx) {
|
|
|
4517
4995
|
}
|
|
4518
4996
|
return state.currentSessionId ?? void 0;
|
|
4519
4997
|
}
|
|
4998
|
+
function currentSupervisorSessionId(state, ctx) {
|
|
4999
|
+
try {
|
|
5000
|
+
return ctx.sessionManager.getSessionFile?.() ?? currentContextSessionId(state, ctx);
|
|
5001
|
+
} catch {
|
|
5002
|
+
return state.currentSessionId ?? void 0;
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
4520
5005
|
function requestMatchesContext(request, state, ctx) {
|
|
4521
|
-
let currentSessionId = currentContextSessionId(state, ctx);
|
|
4522
|
-
return !!(currentSessionId && request.orchestratorSessionId === currentSessionId);
|
|
5006
|
+
let currentSessionId = request.supervisorSessionId !== void 0 ? currentSupervisorSessionId(state, ctx) : currentContextSessionId(state, ctx);
|
|
5007
|
+
return !!(currentSessionId && (request.supervisorSessionId ?? request.orchestratorSessionId) === currentSessionId);
|
|
4523
5008
|
}
|
|
4524
5009
|
function removeRequestFile(file) {
|
|
4525
5010
|
try {
|
|
4526
|
-
|
|
5011
|
+
fs7.rmSync(file, { force: !0 });
|
|
4527
5012
|
} catch {
|
|
4528
5013
|
}
|
|
4529
5014
|
}
|
|
4530
5015
|
function requestExpiresAt(request, now) {
|
|
4531
5016
|
let expiresAt = request.expiresAt;
|
|
4532
|
-
return typeof expiresAt == "number" && Number.isFinite(expiresAt) ? expiresAt : Number.isFinite(request.createdAt) ? request.createdAt +
|
|
5017
|
+
return typeof expiresAt == "number" && Number.isFinite(expiresAt) ? expiresAt : Number.isFinite(request.createdAt) ? request.createdAt + askTimeoutMs2() : now;
|
|
4533
5018
|
}
|
|
4534
5019
|
function requestRunInactive(request, state) {
|
|
4535
5020
|
if (state.foregroundControls.has(request.runId))
|
|
@@ -4546,7 +5031,7 @@ function requestRunInactive(request, state) {
|
|
|
4546
5031
|
return stepStatus === "complete" || stepStatus === "completed" || stepStatus === "failed" || stepStatus === "paused";
|
|
4547
5032
|
}
|
|
4548
5033
|
function requestLifecycle(request, state, ctx, now) {
|
|
4549
|
-
return ctx && !requestMatchesContext(request, state, ctx) ? "wrong-session" :
|
|
5034
|
+
return ctx && !requestMatchesContext(request, state, ctx) ? "wrong-session" : fs7.existsSync(request.requestFile) ? request.expectsReply && fs7.existsSync(replyPath(request.channelDir, request.id)) ? "resolved" : request.expectsReply && now > requestExpiresAt(request, now) ? "expired" : request.expectsReply && requestRunInactive(request, state) ? "inactive" : "pending" : "missing";
|
|
4550
5035
|
}
|
|
4551
5036
|
function cleanupRequestLifecycle(request, lifecycle) {
|
|
4552
5037
|
(lifecycle === "resolved" || lifecycle === "expired" || lifecycle === "inactive") && removeRequestFile(request.requestFile);
|
|
@@ -4611,8 +5096,8 @@ function buildParentIntercomTool(pending, state, name = "intercom") {
|
|
|
4611
5096
|
return {
|
|
4612
5097
|
name,
|
|
4613
5098
|
label: name === "intercom" ? "Intercom" : "Subagent Supervisor",
|
|
4614
|
-
description:
|
|
4615
|
-
parameters:
|
|
5099
|
+
description: PARENT_ASK_DESCRIPTION,
|
|
5100
|
+
parameters: ParentSupervisorParamsSchema,
|
|
4616
5101
|
async execute(_id, params) {
|
|
4617
5102
|
refreshPendingRequests(pending, state, state.lastUiContext ?? void 0);
|
|
4618
5103
|
let input = params;
|
|
@@ -4627,10 +5112,59 @@ function buildParentIntercomTool(pending, state, name = "intercom") {
|
|
|
4627
5112
|
let request = resolvePendingRequest(pending, input);
|
|
4628
5113
|
return writeReply(request, input.message ?? ""), pending.delete(request.id), { content: [{ type: "text", text: `Replied to supervisor request ${request.id}.` }], details: { replyTo: request.id, runId: request.runId, agent: request.agent } };
|
|
4629
5114
|
}
|
|
4630
|
-
|
|
5115
|
+
if (input.action === "ask")
|
|
5116
|
+
return askRunningAsyncChild({
|
|
5117
|
+
params: {
|
|
5118
|
+
id: input.id,
|
|
5119
|
+
index: input.index,
|
|
5120
|
+
childId: input.childId,
|
|
5121
|
+
reason: input.reason,
|
|
5122
|
+
message: input.message
|
|
5123
|
+
},
|
|
5124
|
+
state,
|
|
5125
|
+
childRequests: pending.values()
|
|
5126
|
+
});
|
|
5127
|
+
throw input.action === "send" ? new Error("Native pi-subagents intercom does not support free-form send. Use action='ask' for a running async child or action='reply' for a pending child request.") : new Error(`Unsupported intercom action: ${input.action}`);
|
|
4631
5128
|
}
|
|
4632
5129
|
};
|
|
4633
5130
|
}
|
|
5131
|
+
function questionMatchesParentContext(question, state, ctx) {
|
|
5132
|
+
let sessionId = currentSupervisorSessionId(state, ctx);
|
|
5133
|
+
return !(!sessionId || question.parentSessionId !== sessionId || (state.sessionGeneration ?? 0) !== question.parentGeneration);
|
|
5134
|
+
}
|
|
5135
|
+
function notifyQuestionTerminal(pi, question, channelDir) {
|
|
5136
|
+
if (!supervisorQuestionIsTerminal(question) || question.notifiedAt || (pi.events?.emit(SUBAGENT_QUESTION_EVENT, {
|
|
5137
|
+
questionId: question.id,
|
|
5138
|
+
state: supervisorQuestionPublicState(question),
|
|
5139
|
+
runId: question.runId
|
|
5140
|
+
}), isQuestionWaitActive(question.id)) || !claimQuestionNotification(channelDir, question.id))
|
|
5141
|
+
return;
|
|
5142
|
+
let state = supervisorQuestionPublicState(question);
|
|
5143
|
+
pi.sendMessage({
|
|
5144
|
+
customType: SUBAGENT_SUPERVISOR_ANSWER_TYPE,
|
|
5145
|
+
content: formatSupervisorQuestionAnswer(question),
|
|
5146
|
+
display: state === "answered",
|
|
5147
|
+
details: {
|
|
5148
|
+
questionId: question.id,
|
|
5149
|
+
state,
|
|
5150
|
+
runId: question.runId,
|
|
5151
|
+
childIndex: question.childIndex,
|
|
5152
|
+
childId: question.childId,
|
|
5153
|
+
reason: question.reason,
|
|
5154
|
+
answered: state === "answered",
|
|
5155
|
+
delivered: !!question.deliveredAt
|
|
5156
|
+
}
|
|
5157
|
+
}, { triggerTurn: state === "answered" });
|
|
5158
|
+
}
|
|
5159
|
+
function pollSupervisorQuestions(pi, state, ctx) {
|
|
5160
|
+
for (let channelDir of listSupervisorChannelDirs())
|
|
5161
|
+
for (let question of listSupervisorQuestions(channelDir)) {
|
|
5162
|
+
if (!questionMatchesParentContext(question, state, ctx))
|
|
5163
|
+
continue;
|
|
5164
|
+
let current = reconcileAsyncQuestion(channelDir, question, state);
|
|
5165
|
+
notifyQuestionTerminal(pi, current, channelDir);
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
4634
5168
|
function createNativeSupervisorChannel(pi, state) {
|
|
4635
5169
|
let pending = /* @__PURE__ */ new Map(), seenFiles = /* @__PURE__ */ new Set(), poller, lastStaleCleanupAt = 0, registerParentTools = () => {
|
|
4636
5170
|
hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME) || pi.registerTool(buildParentIntercomTool(pending, state, NATIVE_SUPERVISOR_TOOL_NAME)), hasTool(pi, "intercom") || pi.registerTool(buildParentIntercomTool(pending, state));
|
|
@@ -4643,12 +5177,24 @@ function createNativeSupervisorChannel(pi, state) {
|
|
|
4643
5177
|
} catch {
|
|
4644
5178
|
}
|
|
4645
5179
|
}
|
|
5180
|
+
}, cancelOwnedQuestions = (reason) => {
|
|
5181
|
+
state.currentSessionId && cancelPendingSupervisorQuestionsForOwner({
|
|
5182
|
+
parentSessionId: state.currentSessionId,
|
|
5183
|
+
parentGeneration: state.sessionGeneration ?? 0,
|
|
5184
|
+
reason
|
|
5185
|
+
});
|
|
5186
|
+
}, settleRunQuestions = (runId, reason) => {
|
|
5187
|
+
state.currentSessionId && cancelPendingSupervisorQuestionsForOwner({
|
|
5188
|
+
parentSessionId: state.currentSessionId,
|
|
5189
|
+
runId,
|
|
5190
|
+
reason
|
|
5191
|
+
});
|
|
4646
5192
|
}, poll = () => {
|
|
4647
5193
|
cleanupStaleChannelsIfDue();
|
|
4648
5194
|
let ctx = state.lastUiContext;
|
|
4649
5195
|
if (!ctx)
|
|
4650
5196
|
return;
|
|
4651
|
-
refreshPendingRequests(pending, state, ctx);
|
|
5197
|
+
refreshPendingRequests(pending, state, ctx), pollSupervisorQuestions(pi, state, ctx);
|
|
4652
5198
|
let now = Date.now();
|
|
4653
5199
|
for (let { channelDir, file } of listRequestFiles()) {
|
|
4654
5200
|
if (seenFiles.has(file))
|
|
@@ -4661,7 +5207,7 @@ function createNativeSupervisorChannel(pi, state) {
|
|
|
4661
5207
|
seenFiles.add(file), cleanupRequestLifecycle(request, lifecycle);
|
|
4662
5208
|
continue;
|
|
4663
5209
|
}
|
|
4664
|
-
seenFiles.add(file), request.expectsReply ? pending.set(request.id, request) : removeRequestFile(request.requestFile), pi.sendMessage({
|
|
5210
|
+
if (seenFiles.add(file), request.expectsReply ? pending.set(request.id, request) : removeRequestFile(request.requestFile), pi.sendMessage({
|
|
4665
5211
|
customType: "subagent_supervisor_request",
|
|
4666
5212
|
content: requestVisibleText(request),
|
|
4667
5213
|
display: !0,
|
|
@@ -4673,12 +5219,23 @@ function createNativeSupervisorChannel(pi, state) {
|
|
|
4673
5219
|
agent: request.agent,
|
|
4674
5220
|
childIndex: request.childIndex
|
|
4675
5221
|
}
|
|
4676
|
-
}), request.expectsReply
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
5222
|
+
}), request.expectsReply) {
|
|
5223
|
+
let job = state.asyncJobs.get(request.runId);
|
|
5224
|
+
job && (job.activityState = "needs_attention");
|
|
5225
|
+
let events = pi.events;
|
|
5226
|
+
events?.emit(INTERCOM_DETACH_REQUEST_EVENT, {
|
|
5227
|
+
requestId: request.id,
|
|
5228
|
+
runId: request.runId,
|
|
5229
|
+
agent: request.agent,
|
|
5230
|
+
childIndex: request.childIndex
|
|
5231
|
+
}), events?.emit(SUBAGENT_CONTROL_EVENT, {
|
|
5232
|
+
type: "needs_attention",
|
|
5233
|
+
to: "needs_attention",
|
|
5234
|
+
runId: request.runId,
|
|
5235
|
+
agent: request.agent,
|
|
5236
|
+
index: request.childIndex
|
|
5237
|
+
});
|
|
5238
|
+
}
|
|
4682
5239
|
}
|
|
4683
5240
|
};
|
|
4684
5241
|
return {
|
|
@@ -4686,14 +5243,16 @@ function createNativeSupervisorChannel(pi, state) {
|
|
|
4686
5243
|
poller || (registerParentTools(), poll(), poller = setInterval(poll, CHANNEL_POLL_MS), poller.unref?.());
|
|
4687
5244
|
},
|
|
4688
5245
|
dispose: () => {
|
|
4689
|
-
poller && clearInterval(poller), poller = void 0, pending.clear(), seenFiles.clear();
|
|
5246
|
+
cancelOwnedQuestions("parent supervisor channel disposed"), poller && clearInterval(poller), poller = void 0, pending.clear(), seenFiles.clear();
|
|
4690
5247
|
},
|
|
4691
|
-
pending
|
|
5248
|
+
pending,
|
|
5249
|
+
cancelOwnedQuestions,
|
|
5250
|
+
settleRunQuestions
|
|
4692
5251
|
};
|
|
4693
5252
|
}
|
|
4694
5253
|
|
|
4695
5254
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/extension/rpc.js
|
|
4696
|
-
import * as
|
|
5255
|
+
import * as path9 from "node:path";
|
|
4697
5256
|
import { Compile } from "typebox/compile";
|
|
4698
5257
|
var SUBAGENT_RPC_PROTOCOL_VERSION = 1, SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request", SUBAGENT_RPC_READY_EVENT = "subagents:rpc:v1:ready", SUBAGENT_RPC_REPLY_EVENT_PREFIX = "subagents:rpc:v1:reply:", SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "interrupt", "stop"], SubagentRpcError = class extends Error {
|
|
4699
5258
|
code;
|
|
@@ -4800,7 +5359,7 @@ function stopAsyncRun(params, options, ctx) {
|
|
|
4800
5359
|
}
|
|
4801
5360
|
if (!location.asyncDir)
|
|
4802
5361
|
throw new SubagentRpcError("not_found", "Async run not found or already completed; stop requires a live async run directory.");
|
|
4803
|
-
let currentSessionId = ctx.sessionManager.getSessionId(), initialStatus = readStatus(location.asyncDir), initialRunId = initialStatus?.runId ?? location.resolvedId ??
|
|
5362
|
+
let currentSessionId = ctx.sessionManager.getSessionId(), initialStatus = readStatus(location.asyncDir), initialRunId = initialStatus?.runId ?? location.resolvedId ?? path9.basename(location.asyncDir);
|
|
4804
5363
|
if (!initialStatus)
|
|
4805
5364
|
throw new SubagentRpcError("not_found", `Status file not found for async run '${initialRunId}'.`);
|
|
4806
5365
|
if (!currentSessionId || initialStatus.sessionId !== currentSessionId)
|
|
@@ -5032,7 +5591,9 @@ var ACTIVE_STATES = ["queued", "running"], DEFAULT_TIMEOUT_MS = 1800 * 1e3, MIN_
|
|
|
5032
5591
|
SUBAGENT_FOREGROUND_COMPLETE_EVENT,
|
|
5033
5592
|
SUBAGENT_CONTROL_EVENT,
|
|
5034
5593
|
SUBAGENT_CONTROL_INTERCOM_EVENT,
|
|
5035
|
-
SUBAGENT_RESULT_INTERCOM_EVENT
|
|
5594
|
+
SUBAGENT_RESULT_INTERCOM_EVENT,
|
|
5595
|
+
INTERCOM_DETACH_REQUEST_EVENT,
|
|
5596
|
+
SUBAGENT_QUESTION_EVENT
|
|
5036
5597
|
];
|
|
5037
5598
|
function defaultSleep(ms, signal) {
|
|
5038
5599
|
return new Promise((resolve3) => {
|
|
@@ -5101,8 +5662,8 @@ function summarizeForegroundChildren(run, indices) {
|
|
|
5101
5662
|
!indices.has(child.index) || child.status === "detached" || counts.set(child.status, (counts.get(child.status) ?? 0) + 1);
|
|
5102
5663
|
return [...counts.entries()].map(([status, count]) => `${count} ${status}`).join(", ");
|
|
5103
5664
|
}
|
|
5104
|
-
function needsAttention(run) {
|
|
5105
|
-
return run.activityState === "needs_attention";
|
|
5665
|
+
function needsAttention(run, sessionId) {
|
|
5666
|
+
return run.activityState === "needs_attention" || hasPendingBlockingSupervisorRequest(run.id, sessionId);
|
|
5106
5667
|
}
|
|
5107
5668
|
function backgroundWorkIdentity(item) {
|
|
5108
5669
|
return `${item.provider}\0${item.sessionId}\0${item.id}`;
|
|
@@ -5124,7 +5685,7 @@ function activeRunsForSession(params, deps) {
|
|
|
5124
5685
|
return params.id ? runs.filter((run) => matchesId(run, params.id)) : runs;
|
|
5125
5686
|
}
|
|
5126
5687
|
function attentionRunsForSession(params, deps, initialIds) {
|
|
5127
|
-
return activeRunsForSession(params, deps).filter((run) => needsAttention(run) && initialIds.has(run.id));
|
|
5688
|
+
return activeRunsForSession(params, deps).filter((run) => needsAttention(run, deps.state.currentSessionId) && initialIds.has(run.id));
|
|
5128
5689
|
}
|
|
5129
5690
|
function allRunsForSession(params, deps) {
|
|
5130
5691
|
let asyncDirRoot = deps.asyncDirRoot ?? ASYNC_DIR, resultsDir = deps.resultsDir ?? RESULTS_DIR, runs = listAsyncRuns(asyncDirRoot, {
|
|
@@ -5170,12 +5731,57 @@ async function waitForDetachedForegroundRun(run, signal, deps, startedAt, now, p
|
|
|
5170
5731
|
await waitForWake(pollIntervalMs, signal, deps);
|
|
5171
5732
|
}
|
|
5172
5733
|
}
|
|
5734
|
+
async function waitForSupervisorQuestion(questionId, signal, deps, startedAt, now, pollIntervalMs, timeoutMs) {
|
|
5735
|
+
let sessionId = deps.state.currentSessionId;
|
|
5736
|
+
if (!sessionId)
|
|
5737
|
+
return result("subagent_wait requires an active session identity to scope background work safely.", !0);
|
|
5738
|
+
let releaseWait = registerQuestionWait([questionId]);
|
|
5739
|
+
try {
|
|
5740
|
+
for (; ; ) {
|
|
5741
|
+
let found = findSupervisorQuestion(questionId);
|
|
5742
|
+
if (!found)
|
|
5743
|
+
return result(`No supervisor question matched "${questionId}".`, !0);
|
|
5744
|
+
let { channelDir } = found, { question } = found;
|
|
5745
|
+
if (question.parentSessionId !== sessionId || deps.state.currentSessionId !== sessionId)
|
|
5746
|
+
return result(`Supervisor question "${questionId}" belongs to another session.`, !0);
|
|
5747
|
+
if ((deps.state.sessionGeneration ?? 0) !== question.parentGeneration)
|
|
5748
|
+
return result(`Supervisor question "${questionId}" was cancelled by a session replacement.`, !0);
|
|
5749
|
+
if (question = reconcileAsyncQuestion(channelDir, question, deps.state), supervisorQuestionIsTerminal(question)) {
|
|
5750
|
+
claimQuestionNotification(channelDir, question.id);
|
|
5751
|
+
let state = supervisorQuestionPublicState(question);
|
|
5752
|
+
return {
|
|
5753
|
+
content: [{ type: "text", text: formatSupervisorQuestionAnswer(question) }],
|
|
5754
|
+
...state === "answered" ? {} : { isError: !0 },
|
|
5755
|
+
details: {
|
|
5756
|
+
mode: "management",
|
|
5757
|
+
results: [],
|
|
5758
|
+
questionId: question.id,
|
|
5759
|
+
state,
|
|
5760
|
+
runId: question.runId,
|
|
5761
|
+
answered: state === "answered",
|
|
5762
|
+
delivered: !!question.deliveredAt
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
}
|
|
5766
|
+
if (signal?.aborted)
|
|
5767
|
+
return result(`Wait aborted after ${formatDuration(now() - startedAt)} for supervisor question "${questionId}".`, !0);
|
|
5768
|
+
if (now() - startedAt >= timeoutMs)
|
|
5769
|
+
return result(`Wait timed out after ${formatDuration(timeoutMs)} for supervisor question "${questionId}". The question remains pending until answered, expired, or cancelled.`, !0);
|
|
5770
|
+
await waitForWake(pollIntervalMs, signal, deps);
|
|
5771
|
+
}
|
|
5772
|
+
} finally {
|
|
5773
|
+
releaseWait();
|
|
5774
|
+
}
|
|
5775
|
+
}
|
|
5173
5776
|
async function waitForSubagents(params, signal, deps) {
|
|
5174
5777
|
if (deps.enabled === !1)
|
|
5175
5778
|
return result('subagent_wait is disabled by config.waitTool or PI_SUBAGENT_WAIT_TOOL_ENABLED; returning immediately without blocking background work. Active work keeps going, and you can inspect subagents with subagent({ action: "status" }) or rely on completion notifications.');
|
|
5176
5779
|
if (!deps.state.currentSessionId)
|
|
5177
5780
|
return result("subagent_wait requires an active session identity to scope background work safely.", !0);
|
|
5178
|
-
let now = deps.now ?? Date.now, pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS), timeoutMs = params.timeoutMs !== void 0 && params.timeoutMs > 0 ? params.timeoutMs : DEFAULT_TIMEOUT_MS, startedAt = now()
|
|
5781
|
+
let now = deps.now ?? Date.now, pollIntervalMs = Math.max(MIN_POLL_INTERVAL_MS, deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS), timeoutMs = params.timeoutMs !== void 0 && params.timeoutMs > 0 ? params.timeoutMs : DEFAULT_TIMEOUT_MS, startedAt = now();
|
|
5782
|
+
if (params.questionId?.trim())
|
|
5783
|
+
return waitForSupervisorQuestion(params.questionId.trim(), signal, deps, startedAt, now, pollIntervalMs, timeoutMs);
|
|
5784
|
+
let waitForAll = params.id ? !0 : params.all === !0, active, foreground, providerSnapshot;
|
|
5179
5785
|
try {
|
|
5180
5786
|
active = activeRunsForSession(params, deps), foreground = activeDetachedForegroundRuns(params, deps), providerSnapshot = params.id ? { providers: [], items: [] } : backgroundWorkForSession(deps, startedAt);
|
|
5181
5787
|
} catch (error) {
|
|
@@ -5196,7 +5802,7 @@ async function waitForSubagents(params, signal, deps) {
|
|
|
5196
5802
|
let providerActive = providerSnapshot.items;
|
|
5197
5803
|
if (active.length === 0 && providerActive.length === 0)
|
|
5198
5804
|
return result(params.id ? `No active run matched "${params.id}". Nothing to wait for.` : "No active async runs or registered provider work in this session. Nothing to wait for.");
|
|
5199
|
-
let waitParams = params.id ? { ...params, id: active[0].id } : params, initialAsyncIds = new Set(active.map((run) => run.id)), initialProviderIds = new Set(providerActive.map(backgroundWorkIdentity)), initialProviderNames = new Set(providerActive.map((item) => item.provider)), initialCount = initialAsyncIds.size + initialProviderIds.size, stopOnAttention = deps.stopOnAttention !== !1, attention = active.filter((run) => needsAttention(run)), isDone = () => {
|
|
5805
|
+
let waitParams = params.id ? { ...params, id: active[0].id } : params, initialAsyncIds = new Set(active.map((run) => run.id)), initialProviderIds = new Set(providerActive.map(backgroundWorkIdentity)), initialProviderNames = new Set(providerActive.map((item) => item.provider)), initialCount = initialAsyncIds.size + initialProviderIds.size, stopOnAttention = deps.stopOnAttention !== !1, attention = active.filter((run) => needsAttention(run, deps.state.currentSessionId)), isDone = () => {
|
|
5200
5806
|
if (stopOnAttention && attention.some((run) => initialAsyncIds.has(run.id)))
|
|
5201
5807
|
return !0;
|
|
5202
5808
|
let activeAsyncIds = new Set(active.map((run) => run.id)), activeProviderIds2 = new Set(providerActive.map(backgroundWorkIdentity));
|
|
@@ -5238,25 +5844,26 @@ async function waitForSubagents(params, signal, deps) {
|
|
|
5238
5844
|
}
|
|
5239
5845
|
|
|
5240
5846
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js
|
|
5241
|
-
function registerWaitTool(pi, state, enabled = resolveWaitToolConfig().enabled) {
|
|
5847
|
+
function registerWaitTool(pi, state, enabled = resolveWaitToolConfig().enabled, waitForPendingLaunches) {
|
|
5242
5848
|
let tool = {
|
|
5243
5849
|
name: "subagent_wait",
|
|
5244
5850
|
label: "Subagent Wait",
|
|
5245
5851
|
description: `Block until background work owned by this session changes, then return.
|
|
5246
5852
|
|
|
5247
|
-
|
|
5853
|
+
Call this when the current turn or skill must finish after its children. For normal interactive completion, yield and let lunR wake the session. Headless sessions auto-drain current-session work after the agent turn.
|
|
5248
5854
|
|
|
5249
5855
|
\u2022 { } \u2014 return when the first initially active async run or registered provider item finishes, or when a subagent needs attention.
|
|
5250
5856
|
\u2022 { all: true } \u2014 wait for every async run and provider item that was active when the call began.
|
|
5251
5857
|
\u2022 { id: "..." } \u2014 wait for one async or remembered detached foreground subagent run (id or prefix).
|
|
5858
|
+
\u2022 { questionId: "..." } \u2014 wait for one supervisor question from subagent_supervisor action='ask' (answered/expired/cancelled). Separate from final run results.
|
|
5252
5859
|
\u2022 { timeoutMs: 600000 } \u2014 stop waiting after N ms; active work keeps running.
|
|
5253
5860
|
|
|
5254
5861
|
Provider jobs are session-scoped and identified exactly, so replacing one job with another cannot hide a completion. Provider extensions must be explicitly loaded in this process. In a child agent, keep \`subagent_wait\` in the child tool allowlist and load each provider through the agent's extensions or subagentOnlyExtensions; this tool never loads providers or grants tools itself.${enabled ? "" : `
|
|
5255
5862
|
|
|
5256
5863
|
Configured behavior: subagent_wait is disabled by config.waitTool or PI_SUBAGENT_WAIT_TOOL_ENABLED and returns immediately without blocking.`}`,
|
|
5257
5864
|
parameters: SubagentWaitParams,
|
|
5258
|
-
execute(_id, params, signal) {
|
|
5259
|
-
return waitForSubagents(params, signal, { state, events: pi.events, enabled });
|
|
5865
|
+
async execute(_id, params, signal) {
|
|
5866
|
+
return await Promise.resolve(), await waitForPendingLaunches?.(signal), signal?.throwIfAborted(), waitForSubagents(params, signal, { state, events: pi.events, enabled });
|
|
5260
5867
|
}
|
|
5261
5868
|
};
|
|
5262
5869
|
pi.registerTool(tool);
|
|
@@ -5383,7 +5990,7 @@ function formatSingleCompletion(details) {
|
|
|
5383
5990
|
}
|
|
5384
5991
|
function parseSubagentNotifyContent(content) {
|
|
5385
5992
|
let lines = content.split(`
|
|
5386
|
-
`), match = (lines[0] ?? "").match(/^(Background task|Detached foreground task) (completed|failed|paused): \*\*(.+?)\*\*(?:\s+(\([^)]*\)))?$/);
|
|
5993
|
+
`), match = (lines[0] ?? "").match(/^(Background task|Detached foreground task) (completed|failed|paused|stopped): \*\*(.+?)\*\*(?:\s+(\([^)]*\)))?$/);
|
|
5387
5994
|
if (!match)
|
|
5388
5995
|
return;
|
|
5389
5996
|
let body = lines.slice(2), sessionIndex = -1;
|
|
@@ -5427,7 +6034,7 @@ function sendCompletion(pi, details) {
|
|
|
5427
6034
|
customType: "subagent-notify",
|
|
5428
6035
|
content,
|
|
5429
6036
|
display: !0
|
|
5430
|
-
}, { triggerTurn:
|
|
6037
|
+
}, { triggerTurn: details.some((detail) => detail.status !== "stopped") });
|
|
5431
6038
|
}
|
|
5432
6039
|
function completionBatchKey(result2) {
|
|
5433
6040
|
let sessionId = typeof result2.sessionId == "string" ? result2.sessionId.trim() : "";
|
|
@@ -5437,13 +6044,38 @@ function completionBatchKey(result2) {
|
|
|
5437
6044
|
return cwd ? `cwd:${cwd}` : "unknown";
|
|
5438
6045
|
}
|
|
5439
6046
|
function buildCompletionDetails(result2) {
|
|
5440
|
-
let agent = result2.agent ?? "unknown", summary = typeof result2.summary == "string" ? result2.summary : "",
|
|
6047
|
+
let agent = result2.agent ?? "unknown", summary = typeof result2.summary == "string" ? result2.summary : "", paused = !result2.success && (result2.exitCode === 0 || result2.state === "paused" || summary.startsWith("Paused after interrupt.")), status = result2.state === "stopped" ? "stopped" : paused ? "paused" : result2.success ? "completed" : "failed", taskInfo = result2.taskIndex !== void 0 && result2.totalTasks !== void 0 ? ` (${result2.taskIndex + 1}/${result2.totalTasks})` : void 0, session = result2.shareUrl ? { label: "Session", value: result2.shareUrl } : result2.shareError ? { label: "Session share error", value: result2.shareError } : result2.sessionFile ? { label: "Session file", value: result2.sessionFile } : void 0;
|
|
5441
6048
|
return {
|
|
5442
6049
|
agent,
|
|
5443
6050
|
status,
|
|
5444
6051
|
...result2.source ? { source: result2.source } : {},
|
|
5445
6052
|
...taskInfo ? { taskInfo } : {},
|
|
5446
|
-
resultPreview:
|
|
6053
|
+
resultPreview: [
|
|
6054
|
+
result2.id ? `Run: ${result2.id}` : void 0,
|
|
6055
|
+
result2.asyncDir ? `Async dir: ${result2.asyncDir}` : void 0,
|
|
6056
|
+
result2.results?.length ? result2.results.map((child, index) => {
|
|
6057
|
+
let output = child.summary ?? (child.error ? `${child.error}
|
|
6058
|
+
|
|
6059
|
+
Output:
|
|
6060
|
+
${child.output}` : child.output), report = child.acceptance?.childReport, childIndex = child.index ?? index;
|
|
6061
|
+
return [
|
|
6062
|
+
`${childIndex + 1}. ${child.agent} [${child.status ?? resolveSubagentResultStatus({ success: child.success, state: result2.state })}]`,
|
|
6063
|
+
child.artifactPath ? `Output artifact: ${child.artifactPath}` : void 0,
|
|
6064
|
+
child.sessionPath ? `Session: ${child.sessionPath}` : void 0,
|
|
6065
|
+
child.sessionPath && result2.id && result2.source !== "foreground" ? `Revive: subagent({ action: "resume", id: ${JSON.stringify(result2.id)}, index: ${childIndex}, message: "..." })` : void 0,
|
|
6066
|
+
...formatNestedResultLines(child.children),
|
|
6067
|
+
output,
|
|
6068
|
+
report ? `\`\`\`acceptance-report
|
|
6069
|
+
${JSON.stringify(report, null, 2)}
|
|
6070
|
+
\`\`\`` : void 0
|
|
6071
|
+
].filter((line) => line !== void 0).join(`
|
|
6072
|
+
`);
|
|
6073
|
+
}).join(`
|
|
6074
|
+
|
|
6075
|
+
`) : summary
|
|
6076
|
+
].filter((line) => line !== void 0).join(`
|
|
6077
|
+
|
|
6078
|
+
`),
|
|
5447
6079
|
...typeof result2.durationMs == "number" ? { durationMs: result2.durationMs } : {},
|
|
5448
6080
|
...session ? { sessionLabel: session.label, sessionValue: session.value } : {}
|
|
5449
6081
|
};
|
|
@@ -5526,15 +6158,15 @@ function handleSubagentSteeringNotice(input) {
|
|
|
5526
6158
|
}
|
|
5527
6159
|
|
|
5528
6160
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/extension/config.js
|
|
5529
|
-
import * as
|
|
5530
|
-
import * as
|
|
6161
|
+
import * as fs8 from "node:fs";
|
|
6162
|
+
import * as path10 from "node:path";
|
|
5531
6163
|
function getConfigPath() {
|
|
5532
|
-
return
|
|
6164
|
+
return path10.join(getAgentDir(), "extensions", "subagent", "config.json");
|
|
5533
6165
|
}
|
|
5534
6166
|
function readConfigForUpdate(configPath = getConfigPath()) {
|
|
5535
|
-
if (!
|
|
6167
|
+
if (!fs8.existsSync(configPath))
|
|
5536
6168
|
return {};
|
|
5537
|
-
let parsed = JSON.parse(
|
|
6169
|
+
let parsed = JSON.parse(fs8.readFileSync(configPath, "utf-8"));
|
|
5538
6170
|
if (!parsed || typeof parsed != "object" || Array.isArray(parsed))
|
|
5539
6171
|
throw new Error(`Subagent config at '${configPath}' must be a JSON object`);
|
|
5540
6172
|
return parsed;
|
|
@@ -5550,25 +6182,31 @@ function loadConfig() {
|
|
|
5550
6182
|
}
|
|
5551
6183
|
|
|
5552
6184
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js
|
|
5553
|
-
import * as
|
|
5554
|
-
import * as
|
|
5555
|
-
var CUSTOM_TOOL_DESCRIPTION_FILE = "subagent-tool-description.md", CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024,
|
|
6185
|
+
import * as fs9 from "node:fs";
|
|
6186
|
+
import * as path11 from "node:path";
|
|
6187
|
+
var CUSTOM_TOOL_DESCRIPTION_FILE = "subagent-tool-description.md", CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024, SUBAGENT_TIER_GUIDANCE = `TIER SELECTION:
|
|
6188
|
+
\u2022 Choose the lowest tier that can reliably complete the task.
|
|
6189
|
+
\u2022 light: Use for simple, straightforward tasks that require little reasoning. Good for quick checks, finding information, collecting facts for research, inspecting a small amount of code, or verifying a specific fact.
|
|
6190
|
+
\u2022 standard: Use for moderately difficult work and everyday coding tasks. Good for writing simple code, fixing a clearly described bug, reviewing a focused change, or completing work with clear requirements. Use heavy when the task requires deep architectural understanding or complex reasoning.
|
|
6191
|
+
\u2022 heavy: Use for complex or ambiguous tasks that require deep reasoning and strong code understanding. Good for implementing complex plans, debugging difficult or poorly understood problems, reviewing large or high-risk changes, and making architectural decisions.`, SUBAGENT_SAFETY_GUIDANCE = `SAFETY-CRITICAL SUBAGENT GUIDANCE:
|
|
5556
6192
|
\u2022 Prompt children directly. There is no agent roster. Every execution task needs task (the full child prompt) and description (a concise UI label).
|
|
5557
|
-
\u2022 Every executable child
|
|
6193
|
+
\u2022 Every executable child chooses exactly one of tier: "light"|"standard"|"heavy" (default) or model: "provider/id" when the user names a model. Do not pass both, and do not use inherit. Missing, disabled, unconfigured, unavailable, or unauthenticated selections fail before launch.
|
|
6194
|
+
\u2022 Optional thinking (off/minimal/low/medium/high/xhigh/max) is only valid with an explicit model. Tier launches use the configured tier thinking level.
|
|
6195
|
+
${SUBAGENT_TIER_GUIDANCE}
|
|
5558
6196
|
\u2022 permissions is "full" or "read-only". Omitted permissions means full. Plan-mode parents must pass permissions: "read-only"; full or omitted launches are rejected.
|
|
5559
|
-
\u2022 Keep execution and control separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for status/interrupt/stop/resume/steer/append-step/doctor/watchdog
|
|
5560
|
-
\u2022
|
|
6197
|
+
\u2022 Keep execution and control separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for status/interrupt/stop/resume/steer/append-step/doctor/watchdog.status|check|recommend-model/schedule*.
|
|
6198
|
+
\u2022 ${SUBAGENT_ASYNC_GUIDANCE}
|
|
5561
6199
|
\u2022 Child-safety boundary: ordinary children are not orchestrators and must not run subagents. Only explicitly configured fanout children may use the child-safe subagent tool, still bounded by depth/session limits.
|
|
5562
6200
|
\u2022 Writing/review safety: keep one full-access writer for the same cwd/worktree. Use fresh-context permissions: "read-only" children for independent review, then have the parent synthesize and apply fixes as the sole writer unless an isolated worktree was intentionally requested.
|
|
5563
6201
|
\u2022 Artifacts/status essentials: chain outputs live under {chain_dir}; async runs expose asyncId/asyncDir with status.json, events.jsonl, output logs, and status via { action: "status", id }. Include output paths and residual risks when reporting results.`, FULL_SUBAGENT_TOOL_DESCRIPTION = `Delegate work to generic children by prompting them directly. There are no named agent types.
|
|
5564
6202
|
|
|
5565
6203
|
EXECUTION (use exactly ONE mode):
|
|
5566
|
-
\u2022 SINGLE: { task, description, tier, permissions? } \u2014 one child. Multiple SINGLE calls in the same turn run concurrently; explicit concurrency/run limits still apply.
|
|
5567
|
-
\u2022 PARALLEL: { tasks: [{task, description, tier, permissions?, count?, output?, reads?, progress?}, ...], concurrency?: number, worktree?: true } \u2014 one-call concurrent execution (default: all tasks at once; worktree: isolate each task in a git worktree)
|
|
5568
|
-
\u2022 CHAIN: { chain: [{task, description, tier, permissions?}, {parallel:[{task, description, tier, permissions?, count:3}]}] } \u2014 sequential pipeline with optional parallel fan-out. Use chain when a later child needs an earlier result.
|
|
6204
|
+
\u2022 SINGLE: { task, description, tier|model, thinking?, permissions? } \u2014 one child. Multiple SINGLE calls in the same turn run concurrently; explicit concurrency/run limits still apply.
|
|
6205
|
+
\u2022 PARALLEL: { tasks: [{task, description, tier|model, thinking?, permissions?, count?, output?, reads?, progress?}, ...], concurrency?: number, worktree?: true } \u2014 one-call concurrent execution (default: all tasks at once; worktree: isolate each task in a git worktree)
|
|
6206
|
+
\u2022 CHAIN: { chain: [{task, description, tier|model, thinking?, permissions?}, {parallel:[{task, description, tier|model, thinking?, permissions?, count:3}]}] } \u2014 sequential pipeline with optional parallel fan-out. Use chain when a later child needs an earlier result.
|
|
5569
6207
|
\u2022 description is required, single-line, max 80 characters. It is UI metadata only. task is the complete child prompt.
|
|
5570
6208
|
\u2022 permissions: "full" (default) or "read-only". Full includes coding tools (read, search, shell, edit, write, web, LSP, MCP) and excludes parent-owned tools (cron, memory, behavior, goals, nested subagents). Plan-mode parents may launch only permissions: "read-only".
|
|
5571
|
-
\u2022
|
|
6209
|
+
\u2022 Model selection: pass tier by default ("light"|"standard"|"heavy"). Pass model: "provider/id" only when the user specifies a model. Exactly one of tier or model. Optional thinking only with model; tier uses configured thinking. Direct model launches do not require tier mode to be enabled. No inherit and no silent fallback for an explicit model.
|
|
5572
6210
|
\u2022 Children always start with a fresh session (no inherited parent transcript).
|
|
5573
6211
|
\u2022 Optional timeout: { timeoutMs } or { maxRuntimeMs } sets a run-level max runtime for foreground and async/background runs
|
|
5574
6212
|
|
|
@@ -5583,8 +6221,7 @@ CHAIN EXAMPLES:
|
|
|
5583
6221
|
\u2022 Mixed: { chain: [{task:"Research {task}", description:"Research request", tier:"standard", permissions:"read-only"}, {parallel: [{task:"Review {previous}", description:"Review findings", tier:"light", permissions:"read-only", count: 2}]}, {task:"Summarize {previous}", description:"Summarize reviews", tier:"standard"}] }
|
|
5584
6222
|
|
|
5585
6223
|
CONTROL (use action field, omit task/chain/tasks):
|
|
5586
|
-
\u2022 { action: "watchdog.status" | "watchdog.check" | "watchdog.recommend-model" } - inspect the opt-in subagent watchdog and its strong complementary model recommendation
|
|
5587
|
-
\u2022 { action: "watchdog.configure", model: "recommended" | "inherit" | "provider/model[:thinking]", scope?: "session" | "user" | "project", target?: "main" | "children", thinking?: "inherit" | "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" } - configure watchdog model selection; default scope is session, use persistent scopes only when the user asks
|
|
6224
|
+
\u2022 { action: "watchdog.status" | "watchdog.check" | "watchdog.recommend-model" } - inspect the opt-in subagent watchdog and its strong complementary model recommendation (read-only; there is no configure action)
|
|
5588
6225
|
\u2022 { action: "status", id: "..." } - inspect an async/background run by id or prefix
|
|
5589
6226
|
\u2022 { action: "status", view: "fleet" } - read-only active foreground/async fleet view with transcript commands
|
|
5590
6227
|
\u2022 { action: "status", id: "...", view: "transcript", index?: 0, lines?: 80 } - tail a run or child output/session transcript
|
|
@@ -5592,10 +6229,12 @@ CONTROL (use action field, omit task/chain/tasks):
|
|
|
5592
6229
|
\u2022 { action: "stop", id: "..." } - stop a current-session top-level async run; stopped runs finish with state "stopped"
|
|
5593
6230
|
\u2022 { action: "resume", id: "...", message: "...", index?: 0 } - interrupt then follow up with a live async child, or revive a completed async/foreground child from its session
|
|
5594
6231
|
\u2022 { action: "steer", id: "...", message: "...", index?: 0 } - await correlated child input acceptance for up to 3 seconds; returns delivered, scheduled, pending, partial, recovered, or failed with a request id. Only top-level single runs may recover after a further 15-second pause/revival bound; chain, parallel, and nested runs never auto-interrupt.
|
|
6232
|
+
\u2022 subagent_supervisor({ action: "ask", id, reason, message, index?, childId? }) - ask one running async child; returns question id immediately. Ask only when the child owns missing context, the answer changes a concrete next decision, and waiting risks block/rework. No broadcast, revive, task replacement, status polling, or micromanagement.
|
|
6233
|
+
\u2022 subagent_wait({ questionId }) - wait for that supervisor question answer/expiry/cancel. Answers stay separate from final run results.
|
|
5595
6234
|
\u2022 { action: "append-step", id: "...", chain: [{task:"Use {previous}", description:"Follow-up step", tier:"standard"}] } - append one step to the tail of a running async chain
|
|
5596
6235
|
|
|
5597
6236
|
SCHEDULE (opt-in; requires { "scheduledRuns": { "enabled": true } } in config.json):
|
|
5598
|
-
\u2022 { action: "schedule", task, description, tier, permissions?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? } - defer a child launch until a future time. Also accepts tasks[] or chain[]. Scheduled runs always launch async with fresh context; they become normal tracked async runs once they fire. Only schedule explicit delayed runs the user asked for.
|
|
6237
|
+
\u2022 { action: "schedule", task, description, tier|model, thinking?, permissions?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? } - defer a child launch until a future time. Also accepts tasks[] or chain[]. Scheduled runs always launch async with fresh context; they become normal tracked async runs once they fire. Only schedule explicit delayed runs the user asked for.
|
|
5599
6238
|
\u2022 { action: "schedule-list" } - list scheduled runs for this session
|
|
5600
6239
|
\u2022 { action: "schedule-status", id: "..." } - inspect one scheduled run
|
|
5601
6240
|
\u2022 { action: "schedule-cancel", id: "..." } - cancel a scheduled run before it fires
|
|
@@ -5606,19 +6245,20 @@ DIAGNOSTICS:
|
|
|
5606
6245
|
${SUBAGENT_SAFETY_GUIDANCE}`, COMPACT_SUBAGENT_TOOL_DESCRIPTION = `Delegate to generic children by prompting them. Use exactly one mode per call.
|
|
5607
6246
|
|
|
5608
6247
|
EXECUTE:
|
|
5609
|
-
\u2022 SINGLE {task, description, tier, permissions?} (same-turn singles overlap); PARALLEL {tasks:[{task,description,tier,permissions?,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{task,description,tier,permissions?},{parallel:[...]}]} for sequential work.
|
|
6248
|
+
\u2022 SINGLE {task, description, tier|model, thinking?, permissions?} (same-turn singles overlap); PARALLEL {tasks:[{task,description,tier|model,thinking?,permissions?,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{task,description,tier|model,thinking?,permissions?},{parallel:[...]}]} for sequential work.
|
|
5610
6249
|
\u2022 description is required (single-line, max 80 chars, UI only). task is the full child prompt. permissions omitted = full. Plan-mode parents must pass permissions:"read-only".
|
|
5611
|
-
\u2022
|
|
6250
|
+
\u2022 Exactly one of tier:"light"|"standard"|"heavy" (default) or model:"provider/id" when the user names a model. thinking only with model. No inherit; fail closed on unavailable selections. Children always start fresh. timeoutMs/maxRuntimeMs apply to foreground and async/background runs.
|
|
6251
|
+
${SUBAGENT_TIER_GUIDANCE}
|
|
5612
6252
|
\u2022 Chain templates may use {task}, {previous}, {chain_dir}, and named outputs. Parallel worktree isolation requires a clean git repo.
|
|
5613
6253
|
\u2022 Chain example: { chain: [{task:"Analyze {task}", description:"Analyze request", tier:"standard"}, {parallel: [{task:"Check {previous}", description:"Check prior result", tier:"light", permissions:"read-only", count: 3}]}] }
|
|
5614
6254
|
|
|
5615
6255
|
CONTROL:
|
|
5616
|
-
\u2022 Use action without execution fields: doctor, watchdog.status, watchdog.check, watchdog.recommend-model,
|
|
6256
|
+
\u2022 Use action without execution fields: doctor, watchdog.status, watchdog.check, watchdog.recommend-model, status, interrupt, stop, resume, steer, append-step.
|
|
5617
6257
|
\u2022 Async control actions: status, interrupt, stop, resume, steer, append-step. Use stop with an id for current-session top-level async runs. Use status view:"fleet" for active-run overview, view:"transcript" to tail child output, and steer for acknowledged live guidance. Steering delivery means lunR accepted the correlated user input, not model compliance; use index for a specific child.
|
|
5618
6258
|
\u2022 Opt-in schedule actions: schedule, schedule-list, schedule-status, schedule-cancel. Schedule only explicit delayed runs the user asked for.
|
|
5619
6259
|
|
|
5620
6260
|
ASYNC / WAIT:
|
|
5621
|
-
\u2022
|
|
6261
|
+
\u2022 ${SUBAGENT_ASYNC_GUIDANCE}
|
|
5622
6262
|
\u2022 Status and artifacts live under asyncId/asyncDir with status.json, events.jsonl, output logs, session files, and { action:"status", id:"..." }.
|
|
5623
6263
|
|
|
5624
6264
|
SAFETY:
|
|
@@ -5637,8 +6277,8 @@ function resolveToolDescriptionMode(config, options) {
|
|
|
5637
6277
|
function customDescriptionPaths(options) {
|
|
5638
6278
|
let cwd = options?.cwd ?? process.cwd(), agentDir = options?.agentDir ?? getAgentDir();
|
|
5639
6279
|
return [
|
|
5640
|
-
|
|
5641
|
-
|
|
6280
|
+
path11.join(getProjectConfigDir(cwd), CUSTOM_TOOL_DESCRIPTION_FILE),
|
|
6281
|
+
path11.join(agentDir, CUSTOM_TOOL_DESCRIPTION_FILE)
|
|
5642
6282
|
];
|
|
5643
6283
|
}
|
|
5644
6284
|
function renderCustomTemplate(template, options) {
|
|
@@ -5661,7 +6301,7 @@ function loadCustomToolDescription(options) {
|
|
|
5661
6301
|
for (let filePath of customDescriptionPaths(options)) {
|
|
5662
6302
|
let stat;
|
|
5663
6303
|
try {
|
|
5664
|
-
stat =
|
|
6304
|
+
stat = fs9.statSync(filePath);
|
|
5665
6305
|
} catch (error) {
|
|
5666
6306
|
if (typeof error == "object" && error !== null && "code" in error && error.code === "ENOENT")
|
|
5667
6307
|
continue;
|
|
@@ -5677,7 +6317,7 @@ function loadCustomToolDescription(options) {
|
|
|
5677
6317
|
continue;
|
|
5678
6318
|
}
|
|
5679
6319
|
try {
|
|
5680
|
-
let template =
|
|
6320
|
+
let template = fs9.readFileSync(filePath, "utf-8").trim();
|
|
5681
6321
|
if (!template) {
|
|
5682
6322
|
warn(options, `Ignoring empty custom tool description '${filePath}'.`);
|
|
5683
6323
|
continue;
|
|
@@ -5716,24 +6356,24 @@ function buildSubagentToolDescription(config = {}, options) {
|
|
|
5716
6356
|
// packages/coding-agent/dist/builtin-extensions/pi-subagents/src/extension/index.js
|
|
5717
6357
|
function getSubagentSessionRoot(parentSessionFile) {
|
|
5718
6358
|
if (parentSessionFile) {
|
|
5719
|
-
let baseName =
|
|
5720
|
-
return
|
|
6359
|
+
let baseName = path12.basename(parentSessionFile, ".jsonl"), sessionsDir = path12.dirname(parentSessionFile);
|
|
6360
|
+
return path12.join(sessionsDir, baseName);
|
|
5721
6361
|
}
|
|
5722
|
-
return
|
|
6362
|
+
return fs10.mkdtempSync(path12.join(os.tmpdir(), "pi-subagent-session-"));
|
|
5723
6363
|
}
|
|
5724
6364
|
function expandTilde(p) {
|
|
5725
|
-
return p.startsWith("~/") ?
|
|
6365
|
+
return p.startsWith("~/") ? path12.join(os.homedir(), p.slice(2)) : p;
|
|
5726
6366
|
}
|
|
5727
6367
|
function ensureAccessibleDir(dirPath) {
|
|
5728
|
-
|
|
6368
|
+
fs10.mkdirSync(dirPath, { recursive: !0 });
|
|
5729
6369
|
try {
|
|
5730
|
-
|
|
6370
|
+
fs10.accessSync(dirPath, fs10.constants.R_OK | fs10.constants.W_OK);
|
|
5731
6371
|
} catch {
|
|
5732
6372
|
try {
|
|
5733
|
-
|
|
6373
|
+
fs10.rmSync(dirPath, { recursive: !0, force: !0 });
|
|
5734
6374
|
} catch {
|
|
5735
6375
|
}
|
|
5736
|
-
|
|
6376
|
+
fs10.mkdirSync(dirPath, { recursive: !0 }), fs10.accessSync(dirPath, fs10.constants.R_OK | fs10.constants.W_OK);
|
|
5737
6377
|
}
|
|
5738
6378
|
}
|
|
5739
6379
|
function isSlashResultRunning(result2) {
|
|
@@ -5748,23 +6388,58 @@ function effectiveParallelTaskCount(tasks) {
|
|
|
5748
6388
|
return total + count;
|
|
5749
6389
|
}, 0);
|
|
5750
6390
|
}
|
|
5751
|
-
function
|
|
6391
|
+
function matchingActionJobs(state, requestedId) {
|
|
6392
|
+
let jobs = /* @__PURE__ */ new Map();
|
|
6393
|
+
for (let job of state.asyncJobs.values())
|
|
6394
|
+
jobs.set(job.asyncId, job);
|
|
6395
|
+
for (let job of state.fleetJobs?.values() ?? [])
|
|
6396
|
+
jobs.set(job.asyncId, job);
|
|
6397
|
+
let exact = jobs.get(requestedId);
|
|
6398
|
+
return exact ? [exact] : [...jobs.values()].filter((job) => job.asyncId.startsWith(requestedId));
|
|
6399
|
+
}
|
|
6400
|
+
function resolveSubagentActionDisplayTitle(args, state) {
|
|
6401
|
+
let requestedId = (args.id || args.runId || "").trim();
|
|
6402
|
+
if (!requestedId)
|
|
6403
|
+
return;
|
|
6404
|
+
let matches = matchingActionJobs(state, requestedId);
|
|
6405
|
+
if (matches.length !== 1)
|
|
6406
|
+
return;
|
|
6407
|
+
let job = matches[0], steps = job.steps ?? [];
|
|
6408
|
+
if (Number.isInteger(args.index)) {
|
|
6409
|
+
let step = steps.find((candidate) => candidate.index === args.index) ?? steps[args.index];
|
|
6410
|
+
return step ? childRowLabel(step) : void 0;
|
|
6411
|
+
}
|
|
6412
|
+
if (steps.length === 1)
|
|
6413
|
+
return childRowLabel(steps[0]);
|
|
6414
|
+
if (steps.length > 1)
|
|
6415
|
+
return `${job.mode ?? "subagent"} run`;
|
|
6416
|
+
if (job.agents?.length === 1)
|
|
6417
|
+
return job.agents[0];
|
|
6418
|
+
if (job.agents?.length)
|
|
6419
|
+
return `${job.mode ?? "subagent"} run`;
|
|
6420
|
+
}
|
|
6421
|
+
function renderSubagentCall(rawArgs, theme, context, options) {
|
|
6422
|
+
let args = resolveSubagentRequestParams(rawArgs);
|
|
5752
6423
|
if (args.action) {
|
|
5753
|
-
let target = args.id || args.runId || "";
|
|
6424
|
+
let target = context?.result?.details?.displayTitle || options?.resolveActionTitle?.(args) || args.id || args.runId || "";
|
|
5754
6425
|
return new Text2(`${theme.fg("toolTitle", theme.bold("subagent "))}${args.action}${target ? ` ${theme.fg("accent", target)}` : ""}`, 0, 0);
|
|
5755
6426
|
}
|
|
5756
|
-
let isParallel = (args.tasks?.length ?? 0) > 0, parallelCount = effectiveParallelTaskCount(args.tasks),
|
|
6427
|
+
let isParallel = (args.tasks?.length ?? 0) > 0, parallelCount = effectiveParallelTaskCount(args.tasks), asyncMark = subagentLaunchRunsAsync(args) ? `${theme.fg("warning", "async")} ` : "";
|
|
5757
6428
|
if (args.chain?.length)
|
|
5758
|
-
return new Text2(`${theme.fg("toolTitle", theme.bold("subagent "))}chain (${args.chain.length})
|
|
6429
|
+
return new Text2(`${theme.fg("toolTitle", theme.bold("subagent "))}${asyncMark}chain (${args.chain.length})`, 0, 0);
|
|
5759
6430
|
if (isParallel)
|
|
5760
|
-
return new Text2(`${theme.fg("toolTitle", theme.bold("subagent "))}parallel (${parallelCount})
|
|
5761
|
-
let description = !context?.isPartial && !context?.expanded && !context?.isError ? theme.fg("accent", args.description || args.task || "?") : "";
|
|
5762
|
-
return new Text2(
|
|
6431
|
+
return new Text2(`${theme.fg("toolTitle", theme.bold("subagent "))}${asyncMark}parallel (${parallelCount})`, 0, 0);
|
|
6432
|
+
let description = !context?.result && !context?.isPartial && !context?.expanded && !context?.isError ? theme.fg("accent", args.description || args.task || "?") : "", title = theme.fg("toolTitle", theme.bold("subagent")), rest = [asyncMark.trim() ? theme.fg("warning", "async") : "", description].filter(Boolean).join(" ");
|
|
6433
|
+
return new Text2(rest ? `${title} ${rest}` : title, 0, 0);
|
|
6434
|
+
}
|
|
6435
|
+
function renderSubagentNotify(details, theme) {
|
|
6436
|
+
let status = typeof details?.status == "string" ? details.status : "", icon = status === "completed" ? theme.fg("success", "\u2713") : status === "failed" ? theme.fg("error", "\u2717") : theme.fg("warning", "\u25A0"), title = details?.agent || "child";
|
|
6437
|
+
return new Text2(`${icon} ${theme.bold(title)} ${theme.fg("dim", status)}`, 0, 0);
|
|
5763
6438
|
}
|
|
5764
6439
|
function ensureSubagentResultAnimation(context) {
|
|
5765
6440
|
let state = context.state;
|
|
5766
6441
|
state.subagentResultAnimationTimer || typeof context.invalidate == "function" && (state.frame === void 0 && (state.frame = 0), state.subagentResultAnimationTimer = setInterval(() => {
|
|
5767
|
-
state.frame = (
|
|
6442
|
+
state.frame = (state.frame ?? 0) + 1;
|
|
5768
6443
|
try {
|
|
5769
6444
|
let entries = state.animEntries;
|
|
5770
6445
|
if (entries?.length && typeof context.requestRender == "function") {
|
|
@@ -5776,7 +6451,7 @@ function ensureSubagentResultAnimation(context) {
|
|
|
5776
6451
|
context.invalidate();
|
|
5777
6452
|
} catch {
|
|
5778
6453
|
}
|
|
5779
|
-
},
|
|
6454
|
+
}, SUBAGENT_PAINT_INTERVAL_MS));
|
|
5780
6455
|
}
|
|
5781
6456
|
function isSlashResultError(result2) {
|
|
5782
6457
|
return result2.details?.results.some((entry) => entry.exitCode !== 0 && entry.progress?.status !== "running") || !1;
|
|
@@ -5806,11 +6481,12 @@ function registerSubagentExtension(pi) {
|
|
|
5806
6481
|
} catch {
|
|
5807
6482
|
}
|
|
5808
6483
|
ensureAccessibleDir(RESULTS_DIR), ensureAccessibleDir(ASYNC_DIR), cleanupOldChainDirs();
|
|
5809
|
-
let config = loadConfig(), waitToolConfig = resolveWaitToolConfig(config.waitTool),
|
|
6484
|
+
let config = normalizeAsyncLaunchConfig(loadConfig()), waitToolConfig = resolveWaitToolConfig(config.waitTool), tempArtifactsDir = getArtifactsDir(null);
|
|
5810
6485
|
cleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);
|
|
5811
6486
|
let state = {
|
|
5812
6487
|
baseCwd: "",
|
|
5813
6488
|
currentSessionId: null,
|
|
6489
|
+
sessionGeneration: 0,
|
|
5814
6490
|
foregroundSubagentInFlight: 0,
|
|
5815
6491
|
subagentSpawns: { sessionId: null, count: 0 },
|
|
5816
6492
|
asyncJobs: /* @__PURE__ */ new Map(),
|
|
@@ -5832,47 +6508,61 @@ function registerSubagentExtension(pi) {
|
|
|
5832
6508
|
}
|
|
5833
6509
|
}, supervisorChannel = createNativeSupervisorChannel(pi, state), mainWatchdog = registerMainWatchdog(pi), { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(pi, state, RESULTS_DIR, 600 * 1e3);
|
|
5834
6510
|
startResultWatcher(), primeExistingResults();
|
|
5835
|
-
let generation = 0, executorPromise, runtimeCleanup = () => {
|
|
5836
|
-
generation++, executorPromise = void 0, mainWatchdog.dispose(), stopResultWatcher(), scheduledRunManager.stop(), supervisorChannel.dispose(), clearPendingForegroundControlNotices(state), state.poller && (clearInterval(state.poller), state.poller = null);
|
|
6511
|
+
let generation = 0, executorPromise, pendingLaunches = /* @__PURE__ */ new Set(), pendingAsyncLaunches = /* @__PURE__ */ new Set(), unregisterCancellation, runtimeCleanup = () => {
|
|
6512
|
+
generation++, supervisorChannel.cancelOwnedQuestions("parent runtime replaced"), state.sessionGeneration = (state.sessionGeneration ?? 0) + 1, executorPromise = void 0, pendingLaunches.clear(), pendingAsyncLaunches.clear(), unregisterCancellation?.(), mainWatchdog.dispose(), stopResultWatcher(), scheduledRunManager.stop(), supervisorChannel.dispose(), clearPendingForegroundControlNotices(state), disposeSubagentWidget(), state.poller && (clearInterval(state.poller), state.poller = null);
|
|
5837
6513
|
};
|
|
5838
6514
|
globalStore[runtimeCleanupStoreKey] = runtimeCleanup;
|
|
5839
|
-
let { ensurePoller, refreshWidget, handleStarted, handleComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR, {
|
|
6515
|
+
let { ensurePoller, refreshWidget, handleStarted, handleComplete: trackComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR, {
|
|
5840
6516
|
widgetEnabled: config.asyncWidget !== !1
|
|
5841
|
-
}),
|
|
6517
|
+
}), handleComplete = (data) => {
|
|
6518
|
+
trackComplete(data);
|
|
6519
|
+
let result2 = data;
|
|
6520
|
+
typeof state.currentSessionId == "string" && result2.sessionId !== state.currentSessionId || typeof result2.id == "string" && result2.id.trim() && supervisorChannel.settleRunQuestions(result2.id, "async run settled");
|
|
6521
|
+
}, executorExecute, scheduledRunManager = createScheduledRunManager({
|
|
5842
6522
|
config,
|
|
5843
|
-
launch: (params, ctx, signal) => executorExecute ? executorExecute(
|
|
6523
|
+
launch: (params, ctx, signal) => executorExecute ? executorExecute(randomUUID4(), params, signal, void 0, ctx) : Promise.resolve({
|
|
5844
6524
|
content: [{ type: "text", text: "Scheduled subagent launch is unavailable (executor not ready)." }],
|
|
5845
6525
|
isError: !0,
|
|
5846
6526
|
details: { mode: "management", results: [] }
|
|
5847
6527
|
})
|
|
5848
6528
|
}), executor = {
|
|
5849
6529
|
async execute(id, params, signal, onUpdate, ctx) {
|
|
5850
|
-
let
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
6530
|
+
let resolveLaunchReady, launchReady = !1, launchReadyPromise = new Promise((resolve3) => {
|
|
6531
|
+
resolveLaunchReady = resolve3;
|
|
6532
|
+
}), markLaunchReady = () => {
|
|
6533
|
+
launchReady || (launchReady = !0, pendingLaunches.delete(launchReadyPromise), pendingAsyncLaunches.delete(launchReadyPromise), resolveLaunchReady());
|
|
6534
|
+
};
|
|
6535
|
+
pendingLaunches.add(launchReadyPromise), isAsyncSubagentExecution(resolveSubagentRequestParams(params)) && pendingAsyncLaunches.add(launchReadyPromise);
|
|
6536
|
+
try {
|
|
6537
|
+
let currentGeneration = generation;
|
|
6538
|
+
if (signal?.throwIfAborted(), !executorPromise) {
|
|
6539
|
+
let pending = import("./subagent-executor-CXKXQDHH.js").then(({ createSubagentExecutor }) => {
|
|
6540
|
+
if (generation !== currentGeneration)
|
|
6541
|
+
throw new Error("Subagent session changed before initialization");
|
|
6542
|
+
return createSubagentExecutor({
|
|
6543
|
+
pi,
|
|
6544
|
+
state,
|
|
6545
|
+
config,
|
|
6546
|
+
waitToolEnabled: waitToolConfig.enabled,
|
|
6547
|
+
handleScheduledRunAction: (params2, ctx2) => scheduledRunManager.handleToolCall(params2, ctx2),
|
|
6548
|
+
watchdog: mainWatchdog,
|
|
6549
|
+
tempArtifactsDir,
|
|
6550
|
+
getSubagentSessionRoot,
|
|
6551
|
+
expandTilde
|
|
6552
|
+
});
|
|
5866
6553
|
});
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
}
|
|
6554
|
+
executorPromise = pending, pending.catch(() => {
|
|
6555
|
+
executorPromise === pending && (executorPromise = void 0);
|
|
6556
|
+
});
|
|
6557
|
+
}
|
|
6558
|
+
let ready = await awaitWithAbort(executorPromise, signal);
|
|
6559
|
+
if (signal?.throwIfAborted(), generation !== currentGeneration)
|
|
6560
|
+
throw new Error("Subagent session changed before execution");
|
|
6561
|
+
let execution = ready.execute(id, params, signal, onUpdate, ctx);
|
|
6562
|
+
return markLaunchReady(), await execution;
|
|
6563
|
+
} finally {
|
|
6564
|
+
markLaunchReady();
|
|
5871
6565
|
}
|
|
5872
|
-
let ready = await awaitWithAbort(executorPromise, signal);
|
|
5873
|
-
if (signal?.throwIfAborted(), generation !== currentGeneration)
|
|
5874
|
-
throw new Error("Subagent session changed before execution");
|
|
5875
|
-
return ready.execute(id, params, signal, onUpdate, ctx);
|
|
5876
6566
|
}
|
|
5877
6567
|
};
|
|
5878
6568
|
executorExecute = executor.execute, pi.registerMessageRenderer(SLASH_RESULT_TYPE, (message, options, theme) => {
|
|
@@ -5883,35 +6573,20 @@ function registerSubagentExtension(pi) {
|
|
|
5883
6573
|
let content = typeof message.content == "string" ? message.content : message.content.filter((entry) => entry.type === "text").map((entry) => entry.text).join(`
|
|
5884
6574
|
`);
|
|
5885
6575
|
return new Text2(content, 0, 0);
|
|
5886
|
-
}), pi.registerMessageRenderer("subagent-notify", (message,
|
|
6576
|
+
}), pi.registerMessageRenderer("subagent-notify", (message, _options, theme) => {
|
|
5887
6577
|
let content = typeof message.content == "string" ? message.content : "", details = message.details ?? parseSubagentNotifyContent(content);
|
|
5888
|
-
|
|
5889
|
-
return new Text2(content, 0, 0);
|
|
5890
|
-
let icon = details.status === "completed" ? theme.fg("success", "\u2713") : details.status === "paused" ? theme.fg("warning", "\u25A0") : theme.fg("error", "\u2717"), parts = [];
|
|
5891
|
-
details.taskInfo && parts.push(details.taskInfo), details.durationMs !== void 0 && parts.push(formatDuration(details.durationMs));
|
|
5892
|
-
let notifyLabel = details.taskInfo || details.agent || "child", text = `${icon} ${theme.bold(notifyLabel)} ${theme.fg("dim", details.status)}`;
|
|
5893
|
-
parts.length > 0 && (text += ` ${theme.fg("dim", "\xB7")} ${parts.map((part) => theme.fg("dim", part)).join(` ${theme.fg("dim", "\xB7")} `)}`);
|
|
5894
|
-
let trimmedPreview = details.resultPreview.trim(), previewLines = options.expanded ? trimmedPreview.split(`
|
|
5895
|
-
`).filter((line) => line.trim()) : [trimmedPreview.split(`
|
|
5896
|
-
`, 1)[0] ?? ""].filter((line) => line.trim());
|
|
5897
|
-
for (let line of previewLines.length > 0 ? previewLines : ["(no output)"])
|
|
5898
|
-
text += `
|
|
5899
|
-
${theme.fg("dim", `\u23BF ${line}`)}`;
|
|
5900
|
-
if (!options.expanded && trimmedPreview.includes(`
|
|
5901
|
-
`)) {
|
|
5902
|
-
let expandKey = keyText("app.tools.expand");
|
|
5903
|
-
text += `
|
|
5904
|
-
${theme.fg("dim", `${expandKey} full notification`)}`;
|
|
5905
|
-
}
|
|
5906
|
-
return details.sessionLabel && details.sessionValue && (text += `
|
|
5907
|
-
${theme.fg("muted", `${details.sessionLabel}: ${shortenPath(details.sessionValue)}`)}`), new Text2(text, 0, 0);
|
|
6578
|
+
return details ? renderSubagentNotify(details, theme) : new Text2(content, 0, 0);
|
|
5908
6579
|
}), pi.registerMessageRenderer(SUBAGENT_STEERING_MESSAGE_TYPE, (message, _options, theme) => {
|
|
5909
6580
|
let details = message.details;
|
|
5910
6581
|
if (details)
|
|
5911
6582
|
return new Text2(theme.fg(details.state === "recovered" ? "warning" : "error", formatSteeringNotice(details)), 0, 0);
|
|
5912
6583
|
}), pi.registerMessageRenderer(SUBAGENT_CONTROL_MESSAGE_TYPE, () => {
|
|
5913
6584
|
});
|
|
5914
|
-
let executeSubagentCollapsed = (id, params, signal, onUpdate, ctx) =>
|
|
6585
|
+
let executeSubagentCollapsed = async (id, params, signal, onUpdate, ctx) => {
|
|
6586
|
+
ctx.hasUI && ctx.ui.setToolsExpanded(!1);
|
|
6587
|
+
let displayTitle = params.action === "steer" ? resolveSubagentActionDisplayTitle(params, state) : void 0, result2 = await executor.execute(id, params, signal, onUpdate, ctx);
|
|
6588
|
+
return displayTitle && result2.details && (result2.details.displayTitle = displayTitle), result2;
|
|
6589
|
+
}, slashBridge = registerSlashSubagentBridge({
|
|
5915
6590
|
events: pi.events,
|
|
5916
6591
|
getContext: () => state.lastUiContext,
|
|
5917
6592
|
execute: (id, params, signal, onUpdate, ctx) => executeSubagentCollapsed(id, params, signal, onUpdate, ctx)
|
|
@@ -5936,7 +6611,9 @@ function registerSubagentExtension(pi) {
|
|
|
5936
6611
|
execute(id, params, signal, onUpdate, ctx) {
|
|
5937
6612
|
return executeSubagentCollapsed(id, params, signal, onUpdate, ctx);
|
|
5938
6613
|
},
|
|
5939
|
-
renderCall: renderSubagentCall,
|
|
6614
|
+
renderCall: (args, theme, context) => renderSubagentCall(args, theme, context, {
|
|
6615
|
+
resolveActionTitle: (params) => resolveSubagentActionDisplayTitle(params, state)
|
|
6616
|
+
}),
|
|
5940
6617
|
renderResult(result2, options, theme, context) {
|
|
5941
6618
|
subagentResultIsRunning(result2) ? ensureSubagentResultAnimation(context) : clearLegacyResultAnimationTimer(context);
|
|
5942
6619
|
let state2 = context.state, entries = [];
|
|
@@ -5950,7 +6627,11 @@ function registerSubagentExtension(pi) {
|
|
|
5950
6627
|
};
|
|
5951
6628
|
pi.registerTool(tool), globalThis[/* @__PURE__ */ Symbol.for("@lunr/model-tiers")]?.registerToolDescriptionRefresher?.(() => {
|
|
5952
6629
|
tool.description = buildSubagentToolDescription(config), pi.registerTool(tool);
|
|
5953
|
-
}), registerWaitTool(pi, state, waitToolConfig.enabled
|
|
6630
|
+
}), registerWaitTool(pi, state, waitToolConfig.enabled, async (signal) => {
|
|
6631
|
+
let launches = [...pendingLaunches];
|
|
6632
|
+
launches.length !== 0 && await awaitWithAbort(Promise.all(launches).then(() => {
|
|
6633
|
+
}), signal);
|
|
6634
|
+
}), pi.on("agent_end", async (_event, ctx) => {
|
|
5954
6635
|
ctx.hasUI || await drainOutstandingWork({ state, events: pi.events });
|
|
5955
6636
|
}), registerSlashCommands(pi, state);
|
|
5956
6637
|
let eventUnsubscribeStoreKey = "__piSubagentEventUnsubscribes", controlNoticeSeenStoreKey = "__piSubagentVisibleControlNotices", previousEventUnsubscribes = globalStore[eventUnsubscribeStoreKey];
|
|
@@ -5991,16 +6672,25 @@ function registerSubagentExtension(pi) {
|
|
|
5991
6672
|
} catch {
|
|
5992
6673
|
}
|
|
5993
6674
|
}, resetSessionState = (ctx) => {
|
|
5994
|
-
if (generation++, executorPromise = void 0, state.baseCwd = ctx.cwd, state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager), state.subagentSpawns = { sessionId: state.currentSessionId, count: 0 }, !process.env[SUBAGENT_CHILD_ENV]) {
|
|
5995
|
-
let
|
|
5996
|
-
|
|
5997
|
-
}
|
|
5998
|
-
state.lastUiContext = ctx, cleanupSessionArtifacts(ctx), clearPendingForegroundControlNotices(state), resetJobs(ctx), restoreActiveJobs(ctx)
|
|
6675
|
+
if (generation++, supervisorChannel.cancelOwnedQuestions("parent session replaced"), state.sessionGeneration = (state.sessionGeneration ?? 0) + 1, executorPromise = void 0, pendingLaunches.clear(), pendingAsyncLaunches.clear(), unregisterCancellation?.(), state.baseCwd = ctx.cwd, state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager), state.subagentSpawns = { sessionId: state.currentSessionId, count: 0 }, !process.env[SUBAGENT_CHILD_ENV]) {
|
|
6676
|
+
let sessionId2 = ctx.sessionManager.getSessionId();
|
|
6677
|
+
sessionId2 && (process.env[SUBAGENT_PARENT_SESSION_ENV] = sessionId2);
|
|
6678
|
+
}
|
|
6679
|
+
state.lastUiContext = ctx, cleanupSessionArtifacts(ctx), clearPendingForegroundControlNotices(state), resetJobs(ctx), restoreActiveJobs(ctx);
|
|
6680
|
+
let sessionId = state.currentSessionId, sessionGeneration = generation;
|
|
6681
|
+
sessionId && (unregisterCancellation = registerSubagentCancellation(sessionId, createSubagentCancellation({
|
|
6682
|
+
pendingLaunches: pendingAsyncLaunches,
|
|
6683
|
+
isCurrent: () => generation === sessionGeneration && state.currentSessionId === sessionId,
|
|
6684
|
+
getActiveRunIds: () => [...state.asyncJobs.values()].filter((job) => job.sessionId === sessionId && (job.status === "queued" || job.status === "running")).map((job) => job.asyncId),
|
|
6685
|
+
async stopRun(id) {
|
|
6686
|
+
return !(await executor.execute(randomUUID4(), { action: "stop", id }, new AbortController().signal, void 0, ctx)).isError;
|
|
6687
|
+
}
|
|
6688
|
+
}))), scheduledRunManager.bindSession(ctx), restoreSlashFinalSnapshots(ctx.sessionManager.getEntries()), primeExistingResults();
|
|
5999
6689
|
};
|
|
6000
6690
|
pi.on("session_start", (_event, ctx) => {
|
|
6001
6691
|
resetSessionState(ctx), rpcBridge.emitReady(ctx), supervisorChannel.start();
|
|
6002
6692
|
}), pi.on("session_shutdown", () => {
|
|
6003
|
-
generation++, executorPromise = void 0, delete process.env[SUBAGENT_PARENT_SESSION_ENV];
|
|
6693
|
+
generation++, supervisorChannel.cancelOwnedQuestions("parent session shutdown"), state.sessionGeneration = (state.sessionGeneration ?? 0) + 1, executorPromise = void 0, pendingLaunches.clear(), pendingAsyncLaunches.clear(), unregisterCancellation?.(), delete process.env[SUBAGENT_PARENT_SESSION_ENV];
|
|
6004
6694
|
for (let unsubscribe of eventUnsubscribes)
|
|
6005
6695
|
try {
|
|
6006
6696
|
unsubscribe();
|
|
@@ -6009,7 +6699,7 @@ function registerSubagentExtension(pi) {
|
|
|
6009
6699
|
globalStore[eventUnsubscribeStoreKey] === eventUnsubscribes && delete globalStore[eventUnsubscribeStoreKey], stopResultWatcher(), scheduledRunManager.stop(), state.poller && clearInterval(state.poller), state.poller = null, clearPendingForegroundControlNotices(state);
|
|
6010
6700
|
for (let timer of state.cleanupTimers.values())
|
|
6011
6701
|
clearTimeout(timer);
|
|
6012
|
-
state.cleanupTimers.clear(), state.asyncJobs.clear(), clearSlashSnapshots(), slashBridge.cancelAll(), slashBridge.dispose(), promptTemplateBridge.cancelAll(), promptTemplateBridge.dispose(), supervisorChannel.dispose(), globalStore[runtimeCleanupStoreKey] === runtimeCleanup && delete globalStore[runtimeCleanupStoreKey];
|
|
6702
|
+
state.cleanupTimers.clear(), state.asyncJobs.clear(), clearSlashSnapshots(), slashBridge.cancelAll(), slashBridge.dispose(), promptTemplateBridge.cancelAll(), promptTemplateBridge.dispose(), supervisorChannel.dispose(), globalStore[runtimeCleanupStoreKey] === runtimeCleanup && delete globalStore[runtimeCleanupStoreKey], disposeSubagentWidget();
|
|
6013
6703
|
try {
|
|
6014
6704
|
state.lastUiContext?.hasUI && state.lastUiContext.ui.setWidget(WIDGET_KEY, void 0);
|
|
6015
6705
|
} catch (error) {
|