open-multi-agent-kit 0.98.5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +4 -3
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +1 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bundled-coding-agent.d.ts +10 -0
- package/dist/bun/register-bundled-coding-agent.d.ts.map +1 -0
- package/dist/bun/register-bundled-coding-agent.js +12 -0
- package/dist/bun/register-bundled-coding-agent.js.map +1 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +2 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/neo-cli.d.ts +9 -0
- package/dist/commands/neo-cli.d.ts.map +1 -0
- package/dist/commands/neo-cli.js +61 -0
- package/dist/commands/neo-cli.js.map +1 -0
- package/dist/commands/verified-run-cli.d.ts.map +1 -1
- package/dist/commands/verified-run-cli.js +2 -2
- package/dist/commands/verified-run-cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +29 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +126 -32
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bundled-skills.d.ts +4 -0
- package/dist/core/bundled-skills.d.ts.map +1 -0
- package/dist/core/bundled-skills.js +32 -0
- package/dist/core/bundled-skills.js.map +1 -0
- package/dist/core/cli-diagnostics.d.ts +6 -0
- package/dist/core/cli-diagnostics.d.ts.map +1 -0
- package/dist/core/cli-diagnostics.js +20 -0
- package/dist/core/cli-diagnostics.js.map +1 -0
- package/dist/core/context-budget-headroom.d.ts +12 -0
- package/dist/core/context-budget-headroom.d.ts.map +1 -1
- package/dist/core/context-budget-headroom.js +35 -0
- package/dist/core/context-budget-headroom.js.map +1 -1
- package/dist/core/context-budget-v2-input-validation.d.ts +4 -0
- package/dist/core/context-budget-v2-input-validation.d.ts.map +1 -0
- package/dist/core/context-budget-v2-input-validation.js +79 -0
- package/dist/core/context-budget-v2-input-validation.js.map +1 -0
- package/dist/core/context-budget-v2-observability.d.ts +15 -0
- package/dist/core/context-budget-v2-observability.d.ts.map +1 -0
- package/dist/core/context-budget-v2-observability.js +35 -0
- package/dist/core/context-budget-v2-observability.js.map +1 -0
- package/dist/core/context-budget-v2-planned-items.d.ts +5 -0
- package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -0
- package/dist/core/context-budget-v2-planned-items.js +40 -0
- package/dist/core/context-budget-v2-planned-items.js.map +1 -0
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +57 -38
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +19 -3
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +35 -57
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-tiers.d.ts.map +1 -1
- package/dist/core/context-budget-v2-tiers.js +9 -42
- package/dist/core/context-budget-v2-tiers.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +8 -1
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/devin-harness-dispatch.d.ts +12 -0
- package/dist/core/devin-harness-dispatch.d.ts.map +1 -0
- package/dist/core/devin-harness-dispatch.js +12 -0
- package/dist/core/devin-harness-dispatch.js.map +1 -0
- package/dist/core/devin-harness.d.ts +53 -0
- package/dist/core/devin-harness.d.ts.map +1 -0
- package/dist/core/devin-harness.js +112 -0
- package/dist/core/devin-harness.js.map +1 -0
- package/dist/core/domain-dispatch.d.ts +4 -1
- package/dist/core/domain-dispatch.d.ts.map +1 -1
- package/dist/core/domain-dispatch.js +5 -0
- package/dist/core/domain-dispatch.js.map +1 -1
- package/dist/core/domain-loadouts-provider-harness.d.ts +12 -0
- package/dist/core/domain-loadouts-provider-harness.d.ts.map +1 -0
- package/dist/core/domain-loadouts-provider-harness.js +122 -0
- package/dist/core/domain-loadouts-provider-harness.js.map +1 -0
- package/dist/core/domain-loadouts.d.ts +2 -33
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +3 -56
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/domain-profile.d.ts +40 -0
- package/dist/core/domain-profile.d.ts.map +1 -0
- package/dist/core/domain-profile.js +7 -0
- package/dist/core/domain-profile.js.map +1 -0
- package/dist/core/extensions/bundled-virtual-modules.d.ts +15 -0
- package/dist/core/extensions/bundled-virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/bundled-virtual-modules.js +63 -0
- package/dist/core/extensions/bundled-virtual-modules.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -42
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/grok-harness-dispatch.d.ts +6 -20
- package/dist/core/grok-harness-dispatch.d.ts.map +1 -1
- package/dist/core/grok-harness-dispatch.js +6 -55
- package/dist/core/grok-harness-dispatch.js.map +1 -1
- package/dist/core/grok-harness.d.ts +7 -9
- package/dist/core/grok-harness.d.ts.map +1 -1
- package/dist/core/grok-harness.js +9 -23
- package/dist/core/grok-harness.js.map +1 -1
- package/dist/core/harness-skills.d.ts +20 -0
- package/dist/core/harness-skills.d.ts.map +1 -0
- package/dist/core/harness-skills.js +36 -0
- package/dist/core/harness-skills.js.map +1 -0
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/loadout-runtime-state.d.ts +25 -0
- package/dist/core/loadout-runtime-state.d.ts.map +1 -0
- package/dist/core/loadout-runtime-state.js +39 -0
- package/dist/core/loadout-runtime-state.js.map +1 -0
- package/dist/core/loadout-runtime.d.ts +4 -20
- package/dist/core/loadout-runtime.d.ts.map +1 -1
- package/dist/core/loadout-runtime.js +6 -13
- package/dist/core/loadout-runtime.js.map +1 -1
- package/dist/core/mcp/client.d.ts +27 -6
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +80 -20
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/manager.d.ts +10 -1
- package/dist/core/mcp/manager.d.ts.map +1 -1
- package/dist/core/mcp/manager.js +68 -9
- package/dist/core/mcp/manager.js.map +1 -1
- package/dist/core/mcp/protocol.d.ts +9 -3
- package/dist/core/mcp/protocol.d.ts.map +1 -1
- package/dist/core/mcp/protocol.js +61 -15
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/stdio-transport.d.ts +12 -1
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -1
- package/dist/core/mcp/stdio-transport.js +30 -2
- package/dist/core/mcp/stdio-transport.js.map +1 -1
- package/dist/core/mcp-descriptor-injection.d.ts +26 -0
- package/dist/core/mcp-descriptor-injection.d.ts.map +1 -0
- package/dist/core/mcp-descriptor-injection.js +25 -0
- package/dist/core/mcp-descriptor-injection.js.map +1 -0
- package/dist/core/mcp-public-presets.d.ts +1 -3
- package/dist/core/mcp-public-presets.d.ts.map +1 -1
- package/dist/core/mcp-public-presets.js +3 -15
- package/dist/core/mcp-public-presets.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +24 -3
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -41
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -49
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/neo/catalog.d.ts +20 -0
- package/dist/core/neo/catalog.d.ts.map +1 -0
- package/dist/core/neo/catalog.js +50 -0
- package/dist/core/neo/catalog.js.map +1 -0
- package/dist/core/neo/setup.d.ts +3 -0
- package/dist/core/neo/setup.d.ts.map +1 -0
- package/dist/core/neo/setup.js +47 -0
- package/dist/core/neo/setup.js.map +1 -0
- package/dist/core/provider-default-models.d.ts +43 -0
- package/dist/core/provider-default-models.d.ts.map +1 -0
- package/dist/core/provider-default-models.js +51 -0
- package/dist/core/provider-default-models.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +2 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/provider-error-classification.d.ts +57 -0
- package/dist/core/provider-error-classification.d.ts.map +1 -0
- package/dist/core/provider-error-classification.js +103 -0
- package/dist/core/provider-error-classification.js.map +1 -0
- package/dist/core/provider-harness-dispatch.d.ts +63 -0
- package/dist/core/provider-harness-dispatch.d.ts.map +1 -0
- package/dist/core/provider-harness-dispatch.js +60 -0
- package/dist/core/provider-harness-dispatch.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +10 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +36 -3
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-usage-commandcode.d.ts +9 -0
- package/dist/core/provider-usage-commandcode.d.ts.map +1 -0
- package/dist/core/provider-usage-commandcode.js +198 -0
- package/dist/core/provider-usage-commandcode.js.map +1 -0
- package/dist/core/provider-usage-devin.d.ts +18 -0
- package/dist/core/provider-usage-devin.d.ts.map +1 -0
- package/dist/core/provider-usage-devin.js +71 -0
- package/dist/core/provider-usage-devin.js.map +1 -0
- package/dist/core/provider-usage-text.d.ts +5 -0
- package/dist/core/provider-usage-text.d.ts.map +1 -0
- package/dist/core/provider-usage-text.js +15 -0
- package/dist/core/provider-usage-text.js.map +1 -0
- package/dist/core/provider-usage-types.d.ts +2 -1
- package/dist/core/provider-usage-types.d.ts.map +1 -1
- package/dist/core/provider-usage-types.js.map +1 -1
- package/dist/core/provider-usage.d.ts +1 -2
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +18 -7
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/resource-admission.d.ts +36 -0
- package/dist/core/resource-admission.d.ts.map +1 -1
- package/dist/core/resource-admission.js +59 -0
- package/dist/core/resource-admission.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/run-execution-api.d.ts +1 -1
- package/dist/core/run-execution-api.d.ts.map +1 -1
- package/dist/core/run-execution-api.js.map +1 -1
- package/dist/core/run-usage-ledger.d.ts +47 -0
- package/dist/core/run-usage-ledger.d.ts.map +1 -0
- package/dist/core/run-usage-ledger.js +162 -0
- package/dist/core/run-usage-ledger.js.map +1 -0
- package/dist/core/run-usage-operation.d.ts +8 -0
- package/dist/core/run-usage-operation.d.ts.map +1 -0
- package/dist/core/run-usage-operation.js +12 -0
- package/dist/core/run-usage-operation.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +20 -16
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-failure-cause.d.ts.map +1 -1
- package/dist/core/session-failure-cause.js +14 -5
- package/dist/core/session-failure-cause.js.map +1 -1
- package/dist/core/session-prompt-lifecycle.d.ts +6 -0
- package/dist/core/session-prompt-lifecycle.d.ts.map +1 -1
- package/dist/core/session-prompt-lifecycle.js +47 -2
- package/dist/core/session-prompt-lifecycle.js.map +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +4 -2
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/subagent-lane-authority.d.ts +28 -0
- package/dist/core/subagent-lane-authority.d.ts.map +1 -0
- package/dist/core/subagent-lane-authority.js +119 -0
- package/dist/core/subagent-lane-authority.js.map +1 -0
- package/dist/core/subagent-lane-contract.d.ts +114 -0
- package/dist/core/subagent-lane-contract.d.ts.map +1 -0
- package/dist/core/subagent-lane-contract.js +18 -0
- package/dist/core/subagent-lane-contract.js.map +1 -0
- package/dist/core/subagent-lane-launcher.d.ts +3 -6
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
- package/dist/core/subagent-lane-launcher.js +53 -12
- package/dist/core/subagent-lane-launcher.js.map +1 -1
- package/dist/core/subagent-orchestration.d.ts +4 -17
- package/dist/core/subagent-orchestration.d.ts.map +1 -1
- package/dist/core/subagent-orchestration.js.map +1 -1
- package/dist/core/verified-run/broker.d.ts.map +1 -1
- package/dist/core/verified-run/broker.js +4 -1
- package/dist/core/verified-run/broker.js.map +1 -1
- package/dist/core/verified-run/dag-phase.d.ts +1 -1
- package/dist/core/verified-run/dag-phase.d.ts.map +1 -1
- package/dist/core/verified-run/dag-phase.js +46 -8
- package/dist/core/verified-run/dag-phase.js.map +1 -1
- package/dist/core/verified-run/dag-projection.d.ts.map +1 -1
- package/dist/core/verified-run/dag-projection.js +25 -12
- package/dist/core/verified-run/dag-projection.js.map +1 -1
- package/dist/core/verified-run/dag-types.d.ts +11 -0
- package/dist/core/verified-run/dag-types.d.ts.map +1 -1
- package/dist/core/verified-run/dag-types.js.map +1 -1
- package/dist/core/verified-run/event-parser.d.ts.map +1 -1
- package/dist/core/verified-run/event-parser.js +1 -0
- package/dist/core/verified-run/event-parser.js.map +1 -1
- package/dist/core/verified-run/owned-execution.d.ts +1 -0
- package/dist/core/verified-run/owned-execution.d.ts.map +1 -1
- package/dist/core/verified-run/owned-execution.js +7 -1
- package/dist/core/verified-run/owned-execution.js.map +1 -1
- package/dist/core/verified-run/process-projection.d.ts +13 -0
- package/dist/core/verified-run/process-projection.d.ts.map +1 -0
- package/dist/core/verified-run/process-projection.js +82 -0
- package/dist/core/verified-run/process-projection.js.map +1 -0
- package/dist/core/verified-run/projection.d.ts.map +1 -1
- package/dist/core/verified-run/projection.js +11 -55
- package/dist/core/verified-run/projection.js.map +1 -1
- package/dist/core/verified-run/run-types.d.ts +1 -0
- package/dist/core/verified-run/run-types.d.ts.map +1 -1
- package/dist/core/verified-run/run-types.js.map +1 -1
- package/dist/core/verified-run/task-execution.d.ts +9 -0
- package/dist/core/verified-run/task-execution.d.ts.map +1 -0
- package/dist/core/verified-run/task-execution.js +29 -0
- package/dist/core/verified-run/task-execution.js.map +1 -0
- package/dist/core/verified-run/writer-projection.d.ts.map +1 -1
- package/dist/core/verified-run/writer-projection.js +6 -5
- package/dist/core/verified-run/writer-projection.js.map +1 -1
- package/dist/core/workload-permit-pool.d.ts +1 -1
- package/dist/core/workload-permit-pool.d.ts.map +1 -1
- package/dist/core/workload-permit-pool.js +3 -0
- package/dist/core/workload-permit-pool.js.map +1 -1
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts +34 -0
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts.map +1 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js +70 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +11 -18
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-agent.d.ts +24 -0
- package/dist/modes/acp/acp-agent.d.ts.map +1 -0
- package/dist/modes/acp/acp-agent.js +133 -0
- package/dist/modes/acp/acp-agent.js.map +1 -0
- package/dist/modes/acp/acp-mode.d.ts +4 -0
- package/dist/modes/acp/acp-mode.d.ts.map +1 -0
- package/dist/modes/acp/acp-mode.js +34 -0
- package/dist/modes/acp/acp-mode.js.map +1 -0
- package/dist/modes/acp/acp-session.d.ts +4 -0
- package/dist/modes/acp/acp-session.d.ts.map +1 -0
- package/dist/modes/acp/acp-session.js +76 -0
- package/dist/modes/acp/acp-session.js.map +1 -0
- package/dist/modes/acp/acp-transport.d.ts +5 -0
- package/dist/modes/acp/acp-transport.d.ts.map +1 -0
- package/dist/modes/acp/acp-transport.js +90 -0
- package/dist/modes/acp/acp-transport.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +3 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/resource-description.d.ts +3 -0
- package/dist/modes/interactive/resource-description.d.ts.map +1 -0
- package/dist/modes/interactive/resource-description.js +15 -0
- package/dist/modes/interactive/resource-description.js.map +1 -0
- package/docs/audit-revalidation-2026-09-17.md +77 -0
- package/docs/devin-harness.md +150 -0
- package/docs/docs.json +4 -0
- package/docs/ecraf-normalization.md +83 -0
- package/docs/environment-variables.md +2 -1
- package/docs/index.md +1 -0
- package/docs/loadout-domains/README.md +2 -1
- package/docs/loadout-domains/devin-harness.md +72 -0
- package/docs/metrics.md +57 -16
- package/docs/model-catalog-refresh.md +51 -1
- package/docs/models.md +1 -1
- package/docs/neo.md +134 -0
- package/docs/providers.md +143 -1
- package/docs/release-audit-0.98.5.md +17 -0
- package/docs/release-audit-0.99.0.md +68 -0
- package/docs/run-protocol.md +4 -3
- package/docs/run-usage-ledger.md +56 -0
- package/docs/runtime-algorithms.md +48 -1
- package/docs/sdk.md +9 -5
- package/docs/settings.md +1 -1
- package/docs/skills.md +1 -1
- package/docs/startup-resource-labels-testing.md +47 -0
- package/docs/tb21-audit.md +18 -4
- package/docs/usage.md +7 -1
- package/docs/verified-run-remaining-design.md +881 -0
- package/docs/verified-run-testing.md +91 -0
- package/docs/verified-run.md +30 -9
- 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/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/adaptive-agent-runtime.ts +14 -1
- package/examples/extensions/subagent/graph-result.ts +48 -0
- package/examples/extensions/subagent/index.ts +246 -111
- package/examples/extensions/subagent/managed-process-tree.ts +42 -0
- package/examples/extensions/subagent/managed-process.test.ts +24 -0
- package/examples/extensions/subagent/managed-process.ts +93 -112
- package/examples/extensions/subagent/subagent-runtime-types.ts +17 -1
- package/examples/extensions/subagent/subagent-stream.ts +161 -0
- package/examples/extensions/terminal-browser/README.md +54 -0
- package/examples/extensions/terminal-browser/bridge-protocol.ts +29 -0
- package/examples/extensions/terminal-browser/bridge.ts +219 -0
- package/examples/extensions/terminal-browser/browser-surface.ts +288 -0
- package/examples/extensions/terminal-browser/index.ts +215 -0
- package/examples/extensions/terminal-browser/placeholders.ts +49 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +8 -7
- package/resources/neo/skills/omk-browser/SKILL.md +32 -0
- package/resources/neo/skills/omk-code-review/SKILL.md +24 -0
- package/resources/neo/skills/omk-computeruse/SKILL.md +34 -0
- package/resources/neo/skills/omk-mcp-setup/SKILL.md +48 -0
- package/resources/neo/skills/omk-research/SKILL.md +24 -0
- package/resources/neo/skills/omk-site/SKILL.md +28 -0
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* Uses JSON mode to capture structured output from subagents.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
16
17
|
import * as fs from "node:fs";
|
|
17
18
|
import * as os from "node:os";
|
|
18
19
|
import * as path from "node:path";
|
|
@@ -42,8 +43,10 @@ import {
|
|
|
42
43
|
resolveSubagentExecutionPolicy,
|
|
43
44
|
} from "./deadline-budget.ts";
|
|
44
45
|
import { DeadlineProfileStore } from "./deadline-profile-store.ts";
|
|
46
|
+
import { blockedResult, dependencyDigests, failedResult as isFailedResult, laneResult } from "./graph-result.ts";
|
|
45
47
|
import { runManagedProcess } from "./managed-process.ts";
|
|
46
48
|
import { emptyUsage, type SingleResult, type SubagentAttemptResult } from "./subagent-runtime-types.ts";
|
|
49
|
+
import { createSubagentStream } from "./subagent-stream.ts";
|
|
47
50
|
import {
|
|
48
51
|
type GraphTask,
|
|
49
52
|
GraphValidationError,
|
|
@@ -233,10 +236,6 @@ function getFinalOutput(messages: Message[]): string {
|
|
|
233
236
|
return "";
|
|
234
237
|
}
|
|
235
238
|
|
|
236
|
-
function isFailedResult(result: SingleResult): boolean {
|
|
237
|
-
return result.exitCode !== 0 || result.stopReason === "error" || result.stopReason === "aborted";
|
|
238
|
-
}
|
|
239
|
-
|
|
240
239
|
function getResultOutput(result: SingleResult): string {
|
|
241
240
|
const partialOutput = result.output || getFinalOutput(result.messages);
|
|
242
241
|
if (isFailedResult(result)) {
|
|
@@ -385,6 +384,7 @@ async function runSingleAgentAttempt(
|
|
|
385
384
|
let tmpPromptPath: string | null = null;
|
|
386
385
|
|
|
387
386
|
const currentResult: SingleResult = {
|
|
387
|
+
attemptId: randomUUID(),
|
|
388
388
|
agent: agentName,
|
|
389
389
|
agentSource: agent.source,
|
|
390
390
|
task: logicalTask,
|
|
@@ -419,38 +419,7 @@ async function runSingleAgentAttempt(
|
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
args.push(`Task: ${task}`);
|
|
422
|
-
|
|
423
|
-
const processLine = (line: string) => {
|
|
424
|
-
const event = parseSubagentEvent(line);
|
|
425
|
-
if (event === undefined) return;
|
|
426
|
-
if (event.type === "message_end" && event.message !== undefined) {
|
|
427
|
-
const msg = event.message;
|
|
428
|
-
currentResult.messages.push(msg);
|
|
429
|
-
if (msg.role === "assistant") {
|
|
430
|
-
currentResult.usage.turns += 1;
|
|
431
|
-
const usage = msg.usage;
|
|
432
|
-
if (usage) {
|
|
433
|
-
currentResult.usage.input += usage.input || 0;
|
|
434
|
-
currentResult.usage.output += usage.output || 0;
|
|
435
|
-
currentResult.usage.cacheRead += usage.cacheRead || 0;
|
|
436
|
-
currentResult.usage.cacheWrite += usage.cacheWrite || 0;
|
|
437
|
-
currentResult.usage.cost += usage.cost?.total || 0;
|
|
438
|
-
currentResult.usage.contextTokens = Math.max(
|
|
439
|
-
currentResult.usage.contextTokens,
|
|
440
|
-
usage.totalTokens || 0,
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
if (!currentResult.model && msg.model) currentResult.model = msg.model;
|
|
444
|
-
if (msg.stopReason) currentResult.stopReason = msg.stopReason;
|
|
445
|
-
if (msg.errorMessage) currentResult.errorMessage = msg.errorMessage;
|
|
446
|
-
}
|
|
447
|
-
emitUpdate();
|
|
448
|
-
}
|
|
449
|
-
if (event.type === "tool_result_end" && event.message !== undefined) {
|
|
450
|
-
currentResult.messages.push(event.message);
|
|
451
|
-
emitUpdate();
|
|
452
|
-
}
|
|
453
|
-
};
|
|
422
|
+
const stream = createSubagentStream(currentResult, emitUpdate);
|
|
454
423
|
const invocation = getOmkInvocation(args);
|
|
455
424
|
const processResult = await runManagedProcess({
|
|
456
425
|
command: invocation.command,
|
|
@@ -458,17 +427,11 @@ async function runSingleAgentAttempt(
|
|
|
458
427
|
cwd: cwd ?? defaultCwd,
|
|
459
428
|
cutoffMs,
|
|
460
429
|
signal,
|
|
461
|
-
onStdout:
|
|
462
|
-
|
|
463
|
-
const lines = buffer.split("\n");
|
|
464
|
-
buffer = lines.pop() || "";
|
|
465
|
-
for (const line of lines) processLine(line);
|
|
466
|
-
},
|
|
467
|
-
onStderr: (chunk) => {
|
|
468
|
-
currentResult.stderr += chunk;
|
|
469
|
-
},
|
|
430
|
+
onStdout: stream.stdout,
|
|
431
|
+
onStderr: stream.stderr,
|
|
470
432
|
});
|
|
471
|
-
|
|
433
|
+
currentResult.process = processResult;
|
|
434
|
+
const streamFailure = stream.finish(processResult.reason === "completed" && processResult.exitCode === 0);
|
|
472
435
|
currentResult.exitCode = processResult.exitCode;
|
|
473
436
|
currentResult.output = getFinalOutput(currentResult.messages);
|
|
474
437
|
if (processResult.reason === "cutoff") {
|
|
@@ -484,6 +447,17 @@ async function runSingleAgentAttempt(
|
|
|
484
447
|
currentResult.stopReason = "error";
|
|
485
448
|
currentResult.errorMessage = processResult.errorMessage ?? "Unable to spawn subagent";
|
|
486
449
|
}
|
|
450
|
+
if (processResult.reason === "signal" || processResult.reason === "callback-error" || streamFailure) {
|
|
451
|
+
currentResult.exitCode ||= 1;
|
|
452
|
+
currentResult.stopReason = "error";
|
|
453
|
+
currentResult.errorMessage =
|
|
454
|
+
streamFailure ?? processResult.errorMessage ?? `Subagent terminated by ${processResult.signal}`;
|
|
455
|
+
}
|
|
456
|
+
if (!processResult.terminationObserved) {
|
|
457
|
+
currentResult.exitCode ||= 1;
|
|
458
|
+
currentResult.stopReason = "unsettled";
|
|
459
|
+
currentResult.errorMessage = `${currentResult.errorMessage ?? "Subagent termination unconfirmed"} (unsettled)`;
|
|
460
|
+
}
|
|
487
461
|
return { result: currentResult, process: processResult };
|
|
488
462
|
} finally {
|
|
489
463
|
if (tmpPromptPath)
|
|
@@ -501,30 +475,6 @@ async function runSingleAgentAttempt(
|
|
|
501
475
|
}
|
|
502
476
|
}
|
|
503
477
|
|
|
504
|
-
interface SubagentJsonEvent {
|
|
505
|
-
readonly type: string;
|
|
506
|
-
readonly message?: Message;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
function parseSubagentEvent(line: string): SubagentJsonEvent | undefined {
|
|
510
|
-
if (line.trim() === "") return undefined;
|
|
511
|
-
let value: unknown;
|
|
512
|
-
try {
|
|
513
|
-
value = JSON.parse(line);
|
|
514
|
-
} catch {
|
|
515
|
-
return undefined;
|
|
516
|
-
}
|
|
517
|
-
if (!isRecord(value) || typeof value.type !== "string") return undefined;
|
|
518
|
-
const message = value.message;
|
|
519
|
-
if (message === undefined) return { type: value.type };
|
|
520
|
-
if (!isRecord(message) || typeof message.role !== "string" || !Array.isArray(message.content)) return undefined;
|
|
521
|
-
return { type: value.type, message: message as unknown as Message };
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
525
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
478
|
async function runSingleAgent(
|
|
529
479
|
defaultCwd: string,
|
|
530
480
|
agents: AgentConfig[],
|
|
@@ -602,6 +552,11 @@ const TaskItem = Type.Object({
|
|
|
602
552
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
603
553
|
task: Type.String({ description: "Task to delegate to the agent" }),
|
|
604
554
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
555
|
+
writeScope: Type.Optional(
|
|
556
|
+
Type.Array(Type.String(), {
|
|
557
|
+
description: "Owned write paths for ownership-safe parallel scheduling (spec 020).",
|
|
558
|
+
}),
|
|
559
|
+
),
|
|
605
560
|
});
|
|
606
561
|
|
|
607
562
|
const ChainItem = Type.Object({
|
|
@@ -616,6 +571,11 @@ const GraphItem = Type.Object({
|
|
|
616
571
|
task: Type.String({ description: "Task; use {dependencies} to inject declared dependency outputs" }),
|
|
617
572
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
618
573
|
dependsOn: Type.Optional(Type.Array(Type.String(), { description: "Task node ids that must complete first" })),
|
|
574
|
+
writeScope: Type.Optional(
|
|
575
|
+
Type.Array(Type.String(), {
|
|
576
|
+
description: "Owned write paths for ownership-safe parallel scheduling (spec 020).",
|
|
577
|
+
}),
|
|
578
|
+
),
|
|
619
579
|
});
|
|
620
580
|
|
|
621
581
|
const AgentScopeSchema = StringEnum(["user", "project", "both"] as const, {
|
|
@@ -830,15 +790,46 @@ export default function (omk: ExtensionAPI) {
|
|
|
830
790
|
|
|
831
791
|
const results: SingleResult[] = [];
|
|
832
792
|
const outputs = new Map<string, string>();
|
|
793
|
+
const resultById = new Map<string, SingleResult>();
|
|
833
794
|
const completedNodeIds: string[] = [];
|
|
834
795
|
graphDetails = { waves: plan.waves, completedNodeIds };
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
796
|
+
|
|
797
|
+
// Spec 020 Req1 — when the session binds a lane authority, the DAG
|
|
798
|
+
// routes through buildSubagentOrchestrationPlan → launchSubagentLanes.
|
|
799
|
+
// Batches run sequentially, so renderDependencyContext sees completed
|
|
800
|
+
// dependency outputs at launch time.
|
|
801
|
+
const laneAuthority = ctx.getSubagentLaneAuthority?.();
|
|
802
|
+
if (laneAuthority) {
|
|
803
|
+
const nodeById = new Map(plan.tasks);
|
|
804
|
+
const lanes = params.graph.map((node) => ({
|
|
805
|
+
id: node.id,
|
|
806
|
+
role: "executor" as const,
|
|
807
|
+
task: node.task,
|
|
808
|
+
agentName: node.agent,
|
|
809
|
+
dependsOn: node.dependsOn ?? [],
|
|
810
|
+
...(node.writeScope ? { writeScope: node.writeScope } : {}),
|
|
811
|
+
}));
|
|
812
|
+
const dispatch = await laneAuthority.dispatchLanes({
|
|
813
|
+
lanes,
|
|
814
|
+
spawnPlan: {
|
|
815
|
+
whyParallel: `${params.graph.length} DAG tasks in graph mode`,
|
|
816
|
+
whyNotLocal: "isolated subagent context per node",
|
|
817
|
+
independence: "explicit dependsOn DAG",
|
|
818
|
+
expectedReceiptShape: "per-node SingleResult map",
|
|
819
|
+
maxInlineTokens: 8192,
|
|
820
|
+
},
|
|
821
|
+
configuredMaxParallelLanes: executionPolicy.unbounded ? undefined : executionPolicy.concurrency,
|
|
822
|
+
heavyLaneIds: laneAuthority.getCurrentResourceAdmission()
|
|
823
|
+
? new Set(lanes.map((lane) => lane.id))
|
|
824
|
+
: undefined,
|
|
825
|
+
signal,
|
|
826
|
+
launchLane: async ({ laneId, signal: laneSignal }) => {
|
|
827
|
+
const task = nodeById.get(laneId);
|
|
828
|
+
if (!task) return { status: "failed" as const };
|
|
829
|
+
if ((task.dependsOn ?? []).some((id) => !outputs.has(id))) {
|
|
830
|
+
resultById.set(laneId, blockedResult(task));
|
|
831
|
+
return { status: "failed" as const };
|
|
832
|
+
}
|
|
842
833
|
const result = await runSingleAgent(
|
|
843
834
|
ctx.cwd,
|
|
844
835
|
agents,
|
|
@@ -846,52 +837,104 @@ export default function (omk: ExtensionAPI) {
|
|
|
846
837
|
renderDependencyContext(task, outputs),
|
|
847
838
|
task.cwd,
|
|
848
839
|
undefined,
|
|
849
|
-
|
|
840
|
+
laneSignal,
|
|
850
841
|
undefined,
|
|
851
842
|
makeDetails("graph"),
|
|
852
843
|
executionPolicy.unbounded,
|
|
853
844
|
executionBudget,
|
|
854
845
|
profileStore,
|
|
855
|
-
|
|
846
|
+
0,
|
|
856
847
|
);
|
|
857
|
-
|
|
848
|
+
result.nodeId = laneId;
|
|
849
|
+
result.dependencyDigests = dependencyDigests(task, outputs);
|
|
850
|
+
resultById.set(laneId, result);
|
|
851
|
+
if (!isFailedResult(result)) {
|
|
852
|
+
outputs.set(laneId, getResultOutput(result));
|
|
853
|
+
completedNodeIds.push(laneId);
|
|
854
|
+
}
|
|
855
|
+
return laneResult(result);
|
|
858
856
|
},
|
|
859
|
-
);
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
if (!
|
|
863
|
-
|
|
864
|
-
|
|
857
|
+
});
|
|
858
|
+
const outcomes = new Map(dispatch.outcomes.map((outcome) => [outcome.laneId, outcome]));
|
|
859
|
+
for (const [id, task] of plan.tasks) {
|
|
860
|
+
if (!resultById.has(id)) {
|
|
861
|
+
const outcome = outcomes.get(id);
|
|
862
|
+
resultById.set(
|
|
863
|
+
id,
|
|
864
|
+
blockedResult(
|
|
865
|
+
task,
|
|
866
|
+
dispatch.blockers.join("; ") ||
|
|
867
|
+
outcome?.diagnostic ||
|
|
868
|
+
outcome?.status ||
|
|
869
|
+
"blocked-dependency",
|
|
870
|
+
),
|
|
871
|
+
);
|
|
865
872
|
}
|
|
866
873
|
}
|
|
867
874
|
graphDetails = { waves: plan.waves, completedNodeIds: [...completedNodeIds] };
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
875
|
+
} else {
|
|
876
|
+
for (const [waveIndex, wave] of plan.waves.entries()) {
|
|
877
|
+
const waveResults = await mapWithConcurrencyLimit<string, { id: string; result: SingleResult }>(
|
|
878
|
+
[...wave],
|
|
879
|
+
executionPolicy.concurrency,
|
|
880
|
+
async (id) => {
|
|
881
|
+
const task = plan.tasks.get(id);
|
|
882
|
+
if (!task) throw new GraphValidationError(`node '${id}' disappeared after validation`);
|
|
883
|
+
if ((task.dependsOn ?? []).some((dependency) => !outputs.has(dependency)))
|
|
884
|
+
return { id, result: blockedResult(task) };
|
|
885
|
+
const result = await runSingleAgent(
|
|
886
|
+
ctx.cwd,
|
|
887
|
+
agents,
|
|
888
|
+
task.agent,
|
|
889
|
+
renderDependencyContext(task, outputs),
|
|
890
|
+
task.cwd,
|
|
891
|
+
undefined,
|
|
892
|
+
signal,
|
|
893
|
+
undefined,
|
|
894
|
+
makeDetails("graph"),
|
|
895
|
+
executionPolicy.unbounded,
|
|
896
|
+
executionBudget,
|
|
897
|
+
profileStore,
|
|
898
|
+
plan.waves.length - waveIndex,
|
|
899
|
+
);
|
|
900
|
+
return { id, result };
|
|
901
|
+
},
|
|
902
|
+
);
|
|
903
|
+
for (const { id, result } of waveResults) {
|
|
904
|
+
result.nodeId = id;
|
|
905
|
+
const task = plan.tasks.get(id);
|
|
906
|
+
if (task) result.dependencyDigests = dependencyDigests(task, outputs);
|
|
907
|
+
resultById.set(id, result);
|
|
908
|
+
if (!isFailedResult(result)) {
|
|
909
|
+
outputs.set(id, getResultOutput(result));
|
|
910
|
+
completedNodeIds.push(id);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
graphDetails = { waves: plan.waves, completedNodeIds: [...completedNodeIds] };
|
|
914
|
+
const failed = waveResults.filter(({ result }) => isFailedResult(result));
|
|
915
|
+
if (failed.length > 0) break;
|
|
881
916
|
}
|
|
882
917
|
}
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
918
|
+
for (const [id, task] of plan.tasks) results.push(resultById.get(id) ?? blockedResult(task));
|
|
919
|
+
graphDetails = {
|
|
920
|
+
waves: plan.waves,
|
|
921
|
+
completedNodeIds: results
|
|
922
|
+
.filter((result) => !isFailedResult(result))
|
|
923
|
+
.flatMap((result) => (result.nodeId ? [result.nodeId] : [])),
|
|
924
|
+
};
|
|
925
|
+
const summaries = results.map((result) => {
|
|
926
|
+
const status = isFailedResult(result) ? (result.stopReason ?? "failed") : "completed";
|
|
927
|
+
return `### [${result.nodeId}] ${status}\n\n${truncateParallelOutput(getResultOutput(result))}`;
|
|
886
928
|
});
|
|
887
929
|
return {
|
|
888
930
|
content: [
|
|
889
931
|
{
|
|
890
932
|
type: "text",
|
|
891
|
-
text: `Graph: ${
|
|
933
|
+
text: `Graph: ${graphDetails.completedNodeIds.length}/${params.graph.length} completed in ${plan.waves.length} waves\n\n${summaries.join("\n\n---\n\n")}`,
|
|
892
934
|
},
|
|
893
935
|
],
|
|
894
936
|
details: makeDetails("graph")(results),
|
|
937
|
+
isError: results.some(isFailedResult),
|
|
895
938
|
};
|
|
896
939
|
}
|
|
897
940
|
|
|
@@ -936,10 +979,101 @@ export default function (omk: ExtensionAPI) {
|
|
|
936
979
|
}
|
|
937
980
|
};
|
|
938
981
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
982
|
+
// Spec 020 Req1 — when the session binds a lane authority, parallel
|
|
983
|
+
// tasks route through buildSubagentOrchestrationPlan →
|
|
984
|
+
// launchSubagentLanes (parent admission + shared pool + settlement).
|
|
985
|
+
// Without one (bare/test contexts) keep the local concurrency path.
|
|
986
|
+
const laneAuthority = ctx.getSubagentLaneAuthority?.();
|
|
987
|
+
let results: SingleResult[];
|
|
988
|
+
if (laneAuthority) {
|
|
989
|
+
const laneIndexById = new Map<string, number>();
|
|
990
|
+
const lanes = params.tasks.map((t, index) => {
|
|
991
|
+
const id = `task-${index}`;
|
|
992
|
+
laneIndexById.set(id, index);
|
|
993
|
+
return {
|
|
994
|
+
id,
|
|
995
|
+
role: "executor" as const,
|
|
996
|
+
task: t.task,
|
|
997
|
+
agentName: t.agent,
|
|
998
|
+
...(t.writeScope ? { writeScope: t.writeScope } : {}),
|
|
999
|
+
};
|
|
1000
|
+
});
|
|
1001
|
+
const dispatch = await laneAuthority.dispatchLanes({
|
|
1002
|
+
lanes,
|
|
1003
|
+
spawnPlan: {
|
|
1004
|
+
whyParallel: `${params.tasks.length} independent agent tasks requested in parallel mode`,
|
|
1005
|
+
whyNotLocal: "isolated subagent context per task",
|
|
1006
|
+
independence: "tasks declare no dependencies",
|
|
1007
|
+
expectedReceiptShape: "per-task SingleResult array",
|
|
1008
|
+
maxInlineTokens: 8192,
|
|
1009
|
+
},
|
|
1010
|
+
configuredMaxParallelLanes: executionPolicy.unbounded ? undefined : executionPolicy.concurrency,
|
|
1011
|
+
// Child omk processes are heavy — they draw the shared permit
|
|
1012
|
+
// only under a governed admission decision; observe/off keeps
|
|
1013
|
+
// the legacy breadth (spec Req1.3 vs. observe-mode semantics).
|
|
1014
|
+
heavyLaneIds: laneAuthority.getCurrentResourceAdmission()
|
|
1015
|
+
? new Set(lanes.map((lane) => lane.id))
|
|
1016
|
+
: undefined,
|
|
1017
|
+
signal,
|
|
1018
|
+
launchLane: async ({ laneId, signal: laneSignal }) => {
|
|
1019
|
+
const index = laneIndexById.get(laneId);
|
|
1020
|
+
if (index === undefined) return;
|
|
1021
|
+
const t = params.tasks?.[index];
|
|
1022
|
+
if (!t) return;
|
|
1023
|
+
const result = await runSingleAgent(
|
|
1024
|
+
ctx.cwd,
|
|
1025
|
+
agents,
|
|
1026
|
+
t.agent,
|
|
1027
|
+
t.task,
|
|
1028
|
+
t.cwd,
|
|
1029
|
+
undefined,
|
|
1030
|
+
laneSignal,
|
|
1031
|
+
(partial) => {
|
|
1032
|
+
if (partial.details?.results[0]) {
|
|
1033
|
+
allResults[index] = partial.details.results[0];
|
|
1034
|
+
emitParallelUpdate();
|
|
1035
|
+
}
|
|
1036
|
+
},
|
|
1037
|
+
makeDetails("parallel"),
|
|
1038
|
+
executionPolicy.unbounded,
|
|
1039
|
+
executionBudget,
|
|
1040
|
+
profileStore,
|
|
1041
|
+
1,
|
|
1042
|
+
);
|
|
1043
|
+
allResults[index] = result;
|
|
1044
|
+
emitParallelUpdate();
|
|
1045
|
+
return laneResult(result);
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
if (dispatch.blockers.length > 0) {
|
|
1049
|
+
return {
|
|
1050
|
+
content: [{ type: "text", text: `Lane dispatch blocked: ${dispatch.blockers.join("; ")}` }],
|
|
1051
|
+
details: makeDetails("parallel")([]),
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
// Req2.4 — lanes that never launched still yield a typed outcome,
|
|
1055
|
+
// never an empty-success. Convert non-launched outcomes to failed
|
|
1056
|
+
// results so the summary is honest.
|
|
1057
|
+
for (const outcome of dispatch.outcomes) {
|
|
1058
|
+
if (outcome.status === "completed") continue;
|
|
1059
|
+
const index = laneIndexById.get(outcome.laneId);
|
|
1060
|
+
if (index === undefined) continue;
|
|
1061
|
+
if (allResults[index].exitCode === -1) {
|
|
1062
|
+
allResults[index] = {
|
|
1063
|
+
agent: params.tasks[index].agent,
|
|
1064
|
+
agentSource: "unknown",
|
|
1065
|
+
task: params.tasks[index].task,
|
|
1066
|
+
exitCode: 1,
|
|
1067
|
+
messages: [],
|
|
1068
|
+
stderr: outcome.diagnostic ?? outcome.status,
|
|
1069
|
+
stopReason: outcome.status,
|
|
1070
|
+
usage: emptyUsage(),
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
results = allResults;
|
|
1075
|
+
} else {
|
|
1076
|
+
results = await mapWithConcurrencyLimit(params.tasks, executionPolicy.concurrency, async (t, index) => {
|
|
943
1077
|
const result = await runSingleAgent(
|
|
944
1078
|
ctx.cwd,
|
|
945
1079
|
agents,
|
|
@@ -964,8 +1098,8 @@ export default function (omk: ExtensionAPI) {
|
|
|
964
1098
|
allResults[index] = result;
|
|
965
1099
|
emitParallelUpdate();
|
|
966
1100
|
return result;
|
|
967
|
-
}
|
|
968
|
-
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
969
1103
|
|
|
970
1104
|
const successCount = results.filter((r) => !isFailedResult(r)).length;
|
|
971
1105
|
const summaries = results.map((r) => {
|
|
@@ -983,6 +1117,7 @@ export default function (omk: ExtensionAPI) {
|
|
|
983
1117
|
},
|
|
984
1118
|
],
|
|
985
1119
|
details: makeDetails("parallel")(results),
|
|
1120
|
+
isError: results.some(isFailedResult),
|
|
986
1121
|
};
|
|
987
1122
|
}
|
|
988
1123
|
|
|
@@ -1184,8 +1319,8 @@ export default function (omk: ExtensionAPI) {
|
|
|
1184
1319
|
const failed = details.results.some(isFailedResult);
|
|
1185
1320
|
const icon = failed ? theme.fg("error", "✗") : theme.fg("success", "✓");
|
|
1186
1321
|
let text = `${icon} ${theme.fg("toolTitle", theme.bold("graph "))}${theme.fg("accent", `${completed}/${total} nodes · ${waves} waves`)}`;
|
|
1187
|
-
for (const
|
|
1188
|
-
const id =
|
|
1322
|
+
for (const result of details.results) {
|
|
1323
|
+
const id = result.nodeId ?? result.agent;
|
|
1189
1324
|
const resultIcon = isFailedResult(result) ? theme.fg("error", "✗") : theme.fg("success", "✓");
|
|
1190
1325
|
text += `\n${theme.fg("muted", "─── ")}${theme.fg("accent", id)} ${resultIcon}`;
|
|
1191
1326
|
if (expanded) text += `\n${theme.fg("toolOutput", getResultOutput(result))}`;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ChildProcess, spawn } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
/** EPERM and other observation errors cannot prove that a group is gone. */
|
|
4
|
+
export function processGroupState(pid: number): "alive" | "gone" | "unknown" {
|
|
5
|
+
if (process.platform === "win32" || pid < 1) return "gone";
|
|
6
|
+
try {
|
|
7
|
+
process.kill(-pid, 0);
|
|
8
|
+
return "alive";
|
|
9
|
+
} catch (error) {
|
|
10
|
+
return (error as NodeJS.ErrnoException).code === "ESRCH" ? "gone" : "unknown";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Requests termination, never confirms it. Only signal the child owned by this invocation. */
|
|
15
|
+
export function signalProcessTree(child: ChildProcess, signal: "SIGTERM" | "SIGKILL", processGroup: boolean): void {
|
|
16
|
+
const pid = child.pid;
|
|
17
|
+
if (pid === undefined) return;
|
|
18
|
+
if (process.platform === "win32" && signal === "SIGKILL") {
|
|
19
|
+
try {
|
|
20
|
+
const killer = spawn("taskkill", ["/F", "/T", "/PID", String(pid)], {
|
|
21
|
+
detached: true,
|
|
22
|
+
stdio: "ignore",
|
|
23
|
+
windowsHide: true,
|
|
24
|
+
});
|
|
25
|
+
killer.on("error", () => {});
|
|
26
|
+
killer.unref();
|
|
27
|
+
return;
|
|
28
|
+
} catch {
|
|
29
|
+
// Fall back to the owned direct child, without claiming descendant containment.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
if (process.platform === "win32") child.kill(signal);
|
|
34
|
+
else process.kill(processGroup ? -pid : pid, signal);
|
|
35
|
+
} catch {
|
|
36
|
+
try {
|
|
37
|
+
child.kill(signal);
|
|
38
|
+
} catch {
|
|
39
|
+
/* Termination remains unconfirmed. */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -18,6 +18,30 @@ async function processExists(pid: number): Promise<boolean> {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
describe("managed subagent process lifecycle", () => {
|
|
21
|
+
it.skipIf(process.platform === "win32").each(["SIGTERM", "SIGKILL"] as const)(
|
|
22
|
+
"does not report %s termination as success",
|
|
23
|
+
async (signal) => {
|
|
24
|
+
const result = await runManagedProcess({
|
|
25
|
+
command: process.execPath,
|
|
26
|
+
args: ["-e", `process.kill(process.pid, ${JSON.stringify(signal)})`],
|
|
27
|
+
cwd: process.cwd(),
|
|
28
|
+
cutoffMs: 5_000,
|
|
29
|
+
});
|
|
30
|
+
expect(result.signal).toBe(signal);
|
|
31
|
+
expect(result.exitCode).not.toBe(0);
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
it("preserves an explicit nonzero exit", async () => {
|
|
36
|
+
const result = await runManagedProcess({
|
|
37
|
+
command: process.execPath,
|
|
38
|
+
args: ["-e", "process.exit(7)"],
|
|
39
|
+
cwd: process.cwd(),
|
|
40
|
+
cutoffMs: 5_000,
|
|
41
|
+
});
|
|
42
|
+
expect(result.exitCode).toBe(7);
|
|
43
|
+
expect(result.signal).toBeNull();
|
|
44
|
+
});
|
|
21
45
|
it("escalates a cutoff from SIGTERM to SIGKILL and reaps the process tree", async () => {
|
|
22
46
|
let stdout = "";
|
|
23
47
|
const result = await runManagedProcess({
|