@duckmind/dm-windows-x64 0.61.4 → 0.61.9
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/dm.exe +0 -0
- package/extensions/.dm-extensions.json +211 -67
- package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
- package/extensions/dm-subagents/agents/claude-code.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
- package/extensions/dm-subagents/agents/codex-exec.md +15 -0
- package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
- package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
- package/extensions/dm-subagents/agents/delegate.md +3 -2
- package/extensions/dm-subagents/agents/oracle.md +10 -5
- package/extensions/dm-subagents/agents/researcher.md +2 -2
- package/extensions/dm-subagents/agents/reviewer.md +17 -7
- package/extensions/dm-subagents/agents/scout.md +5 -5
- package/extensions/dm-subagents/agents/worker.md +6 -2
- package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
- package/extensions/dm-subagents/index.js +4 -0
- package/extensions/dm-subagents/inspector-runner.mjs +10 -0
- package/extensions/dm-subagents/install.mjs +3 -2
- package/extensions/dm-subagents/package.json +2 -2
- package/extensions/dm-subagents/prompts/council.md +60 -0
- package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
- package/extensions/dm-subagents/prompts/review-loop.md +13 -7
- package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
- package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
- package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
- package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
- package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
- package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
- package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
- package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
- package/extensions/dm-subagents/src/agents/agents.js +1447 -299
- package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
- package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
- package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
- package/extensions/dm-subagents/src/agents/identity.js +1 -1
- package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
- package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
- package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
- package/extensions/dm-subagents/src/agents/skills.js +52 -35
- package/extensions/dm-subagents/src/api/agents.js +6 -0
- package/extensions/dm-subagents/src/api/background-work.js +151 -0
- package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
- package/extensions/dm-subagents/src/api/control-channel.js +3 -0
- package/extensions/dm-subagents/src/api/delegation.js +5 -0
- package/extensions/dm-subagents/src/api/dm-args.js +3 -0
- package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
- package/extensions/dm-subagents/src/api/external-runs.js +233 -0
- package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
- package/extensions/dm-subagents/src/api/preflight.js +322 -0
- package/extensions/dm-subagents/src/api/project-panes.js +11 -0
- package/extensions/dm-subagents/src/api/shared-types.js +4 -0
- package/extensions/dm-subagents/src/extension/config.js +175 -0
- package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
- package/extensions/dm-subagents/src/extension/doctor.js +71 -17
- package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
- package/extensions/dm-subagents/src/extension/index.js +711 -265
- package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
- package/extensions/dm-subagents/src/extension/rpc.js +427 -22
- package/extensions/dm-subagents/src/extension/schemas.js +158 -65
- package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
- package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
- package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
- package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
- package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
- package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
- package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
- package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
- package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
- package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
- package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
- package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
- package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
- package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
- package/extensions/dm-subagents/src/missions/actions.js +394 -0
- package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
- package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
- package/extensions/dm-subagents/src/missions/store.js +548 -0
- package/extensions/dm-subagents/src/missions/types.js +9 -0
- package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
- package/extensions/dm-subagents/src/policy/authority.js +37 -0
- package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
- package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
- package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
- package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
- package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
- package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
- package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
- package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
- package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
- package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
- package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
- package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
- package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
- package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
- package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
- package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
- package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
- package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
- package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
- package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
- package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
- package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
- package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
- package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
- package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
- package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
- package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
- package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
- package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
- package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
- package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
- package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
- package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
- package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
- package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
- package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
- package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
- package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
- package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
- package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
- package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
- package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
- package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
- package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
- package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
- package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
- package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
- package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
- package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
- package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
- package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
- package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
- package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
- package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
- package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
- package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
- package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
- package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
- package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
- package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
- package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
- package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
- package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
- package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
- package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
- package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
- package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
- package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
- package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
- package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
- package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
- package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
- package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
- package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
- package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
- package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
- package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
- package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
- package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
- package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
- package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
- package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
- package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
- package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
- package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
- package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
- package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
- package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
- package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
- package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
- package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
- package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
- package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
- package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
- package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
- package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
- package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
- package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
- package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
- package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
- package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
- package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
- package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
- package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
- package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
- package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
- package/extensions/dm-subagents/src/shared/display-text.js +142 -0
- package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
- package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
- package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
- package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
- package/extensions/dm-subagents/src/shared/formatters.js +21 -7
- package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
- package/extensions/dm-subagents/src/shared/model-info.js +10 -5
- package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
- package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
- package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
- package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
- package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
- package/extensions/dm-subagents/src/shared/settings.js +39 -47
- package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
- package/extensions/dm-subagents/src/shared/status-format.js +9 -2
- package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
- package/extensions/dm-subagents/src/shared/types.js +47 -7
- package/extensions/dm-subagents/src/shared/utf8.js +12 -0
- package/extensions/dm-subagents/src/shared/utils.js +151 -131
- package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
- package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
- package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
- package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
- package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
- package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
- package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
- package/extensions/dm-subagents/src/slash/selector.js +101 -0
- package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
- package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
- package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
- package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
- package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
- package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
- package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
- package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
- package/extensions/dm-subagents/src/tui/render.js +1511 -261
- package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
- package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
- package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
- package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
- package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
- package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
- package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
- package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
- package/extensions/dm-subagents/src/watchdog/render.js +54 -0
- package/extensions/dm-subagents/src/watchdog/review.js +251 -0
- package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
- package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
- package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
- package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
- package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
- package/extensions/dm-subagents/src/watchdog/types.js +29 -0
- package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
- package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
- package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
- package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
- package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
- package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
- package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
- package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
- package/package.json +4 -3
- package/extensions/dm-fff/package.json +0 -21
- package/extensions/dm-fff/src/index.js +0 -691
- package/extensions/dm-fff/src/query.js +0 -60
- package/extensions/dm-subagents/agents/context-builder.md +0 -46
- package/extensions/dm-subagents/agents/planner.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
- package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
- package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
- package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
- package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
|
@@ -1,25 +1,219 @@
|
|
|
1
|
-
import { buildCompletionKey,
|
|
1
|
+
import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.js";
|
|
2
2
|
import {
|
|
3
3
|
createCompletionBatcher,
|
|
4
4
|
resolveCompletionBatchConfig
|
|
5
5
|
} from "./completion-batcher.js";
|
|
6
|
-
import { SUBAGENT_ASYNC_COMPLETE_EVENT } from "../../shared/types.js";
|
|
6
|
+
import { SUBAGENT_ASYNC_COMPLETE_EVENT, SUBAGENT_FOREGROUND_COMPLETE_EVENT } from "../../shared/types.js";
|
|
7
|
+
import { safeTerminalText } from "../../shared/display-text.js";
|
|
8
|
+
import { resolveSubagentResultStatus } from "../../intercom/result-intercom.js";
|
|
9
|
+
import { isUnexplainedProcessSignal } from "../shared/process-signal.js";
|
|
10
|
+
const CHILD_OUTPUT_PREVIEW_MAX_BYTES = 4 * 1024;
|
|
11
|
+
const CHILD_OUTPUT_PREVIEW_COUNT = 8;
|
|
12
|
+
const PREVIEW_TRUNCATION_MARKER = "...[preview truncated]";
|
|
13
|
+
function truncateUtf8Head(value, maxBytes) {
|
|
14
|
+
const bytes = Buffer.from(value, "utf8");
|
|
15
|
+
if (bytes.length <= maxBytes)
|
|
16
|
+
return { text: value, truncated: false };
|
|
17
|
+
const markerBytes = Buffer.byteLength(PREVIEW_TRUNCATION_MARKER, "utf8");
|
|
18
|
+
const contentBytes = Math.max(0, maxBytes - markerBytes);
|
|
19
|
+
let end = contentBytes;
|
|
20
|
+
while (end > 0 && (bytes[end] & 192) === 128)
|
|
21
|
+
end -= 1;
|
|
22
|
+
return {
|
|
23
|
+
text: `${bytes.subarray(0, end).toString("utf8")}${PREVIEW_TRUNCATION_MARKER}`,
|
|
24
|
+
truncated: true
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function boundedSafeText(value, maxBytes = 1024) {
|
|
28
|
+
return truncateUtf8Head(safeTerminalText(value).replace(/\n/g, "\\n"), maxBytes).text;
|
|
29
|
+
}
|
|
30
|
+
function outputPathFromReference(value) {
|
|
31
|
+
if (typeof value === "string" && value.trim())
|
|
32
|
+
return value.trim();
|
|
33
|
+
if (value && typeof value === "object" && typeof value.path === "string" && value.path.trim())
|
|
34
|
+
return value.path.trim();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
function childSavedOutputPath(child) {
|
|
38
|
+
return outputPathFromReference(child.outputReference);
|
|
39
|
+
}
|
|
40
|
+
function childStatus(child, workflowState) {
|
|
41
|
+
const knownStatus = child.status === "complete" ? "completed" : child.status === "completed" || child.status === "failed" || child.status === "paused" || child.status === "stopped" || child.status === "detached" ? child.status : undefined;
|
|
42
|
+
if (knownStatus)
|
|
43
|
+
return knownStatus;
|
|
44
|
+
return resolveSubagentResultStatus({
|
|
45
|
+
success: child.success,
|
|
46
|
+
state: child.state ?? (child.success === undefined ? workflowState : undefined),
|
|
47
|
+
interrupted: child.interrupted,
|
|
48
|
+
detached: child.detached,
|
|
49
|
+
processSignal: child.processSignal,
|
|
50
|
+
timedOut: child.timedOut,
|
|
51
|
+
stopped: child.stopped,
|
|
52
|
+
turnBudgetExceeded: child.turnBudgetExceeded,
|
|
53
|
+
exitCode: typeof child.exitCode === "number" ? child.exitCode : undefined
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function structuredOutputText(value) {
|
|
57
|
+
if (value === undefined)
|
|
58
|
+
return;
|
|
59
|
+
try {
|
|
60
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
61
|
+
return typeof serialized === "string" ? serialized : undefined;
|
|
62
|
+
} catch {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function childInlinePreview(child) {
|
|
67
|
+
const output = typeof child.output === "string" ? child.output : "";
|
|
68
|
+
const outputReference = childSavedOutputPath(child);
|
|
69
|
+
const referenceOnly = Boolean(outputReference && output.trim().startsWith("Output saved to:"));
|
|
70
|
+
const raw = child.outputState === "absent" || referenceOnly ? structuredOutputText(child.structuredOutput) : output || structuredOutputText(child.structuredOutput);
|
|
71
|
+
if (!raw?.trim()) {
|
|
72
|
+
return { unavailableReason: referenceOnly ? "saved output is file-only" : "no safe inline output" };
|
|
73
|
+
}
|
|
74
|
+
const safe = safeTerminalText(raw);
|
|
75
|
+
if (!safe.trim())
|
|
76
|
+
return { unavailableReason: "no safe inline output" };
|
|
77
|
+
const bounded = truncateUtf8Head(safe, CHILD_OUTPUT_PREVIEW_MAX_BYTES);
|
|
78
|
+
return { preview: bounded.text, ...bounded.truncated ? { truncated: true } : {} };
|
|
79
|
+
}
|
|
80
|
+
function formatChildOutputBlock(children) {
|
|
81
|
+
if (!children?.length)
|
|
82
|
+
return;
|
|
83
|
+
const lines = ["Child outputs:"];
|
|
84
|
+
for (let index = 0;index < children.length; index++) {
|
|
85
|
+
const child = children[index];
|
|
86
|
+
const key = child.workflowKey ? boundedSafeText(child.workflowKey) : "unavailable";
|
|
87
|
+
const runId = child.runId ? boundedSafeText(child.runId) : "unavailable";
|
|
88
|
+
const status = boundedSafeText(child.status) || "unavailable";
|
|
89
|
+
lines.push(`- key=${key} run=${runId} status=${status}`);
|
|
90
|
+
lines.push(` Saved output: ${child.savedOutputPath ? boundedSafeText(child.savedOutputPath) : "unavailable"}`);
|
|
91
|
+
if (index >= CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
92
|
+
lines.push(" Preview: unavailable (notice preview budget exceeded)");
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (!child.preview) {
|
|
96
|
+
lines.push(` Preview: unavailable (${child.previewUnavailableReason ?? "no safe inline output"})`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
lines.push(" Preview:");
|
|
100
|
+
for (const line of child.preview.split(`
|
|
101
|
+
`))
|
|
102
|
+
lines.push(` | ${line}`);
|
|
103
|
+
}
|
|
104
|
+
if (children.length > CHILD_OUTPUT_PREVIEW_COUNT) {
|
|
105
|
+
lines.push(`- ${children.length - CHILD_OUTPUT_PREVIEW_COUNT} additional child preview(s) omitted by notice budget; child run metadata is retained below.`);
|
|
106
|
+
}
|
|
107
|
+
return lines.join(`
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
function formatResultPreview(details) {
|
|
111
|
+
const summary = details.resultPreview.trim() ? details.resultPreview : "(no output)";
|
|
112
|
+
const childOutputs = formatChildOutputBlock(details.childOutputs);
|
|
113
|
+
return childOutputs ? `${summary}
|
|
114
|
+
|
|
115
|
+
${childOutputs}` : summary;
|
|
116
|
+
}
|
|
7
117
|
function formatSessionLine(details) {
|
|
8
118
|
if (!details.sessionValue)
|
|
9
119
|
return;
|
|
10
120
|
return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;
|
|
11
121
|
}
|
|
122
|
+
function formatChildRun(child) {
|
|
123
|
+
const label = child.workflowKey ?? child.agent;
|
|
124
|
+
const status = child.status ? ` (${child.status})` : "";
|
|
125
|
+
return `${label ? `${label}=` : ""}${child.runId}${status}`;
|
|
126
|
+
}
|
|
127
|
+
function formatCorrelationLines(details) {
|
|
128
|
+
return [
|
|
129
|
+
details.workflowRunId ? `Workflow run: ${details.workflowRunId}` : undefined,
|
|
130
|
+
details.childRuns?.length ? `Child runs: ${details.childRuns.map(formatChildRun).join(", ")}` : undefined,
|
|
131
|
+
details.reconciledFromDetachedChild ? `Reconciled detached child: ${details.reconciledFromDetachedChild}` : undefined
|
|
132
|
+
].filter((line) => line !== undefined);
|
|
133
|
+
}
|
|
12
134
|
export function formatSingleCompletion(details) {
|
|
13
135
|
const sessionLine = formatSessionLine(details);
|
|
136
|
+
const correlationLines = formatCorrelationLines(details);
|
|
137
|
+
const taskKind = details.source === "foreground" ? "Detached foreground task" : "Background task";
|
|
138
|
+
const scheduleLine = details.scheduleOrigin ? `Scheduled run from **${details.scheduleOrigin.name ?? details.scheduleOrigin.id}** (schedule ${details.scheduleOrigin.id}).` : undefined;
|
|
14
139
|
return [
|
|
15
|
-
|
|
140
|
+
`${taskKind} ${details.status}: **${details.agent}**${details.taskInfo ?? ""}`,
|
|
16
141
|
"",
|
|
17
|
-
|
|
142
|
+
scheduleLine,
|
|
143
|
+
scheduleLine ? "" : undefined,
|
|
144
|
+
formatResultPreview(details),
|
|
145
|
+
details.handoffPath ? "" : undefined,
|
|
146
|
+
details.handoffPath ? `Parallel handoff: ${details.handoffPath}` : undefined,
|
|
147
|
+
correlationLines.length && !details.handoffPath ? "" : undefined,
|
|
148
|
+
...correlationLines,
|
|
18
149
|
sessionLine ? "" : undefined,
|
|
19
150
|
sessionLine
|
|
20
151
|
].filter((line) => line !== undefined).join(`
|
|
21
152
|
`);
|
|
22
153
|
}
|
|
154
|
+
export function parseSubagentNotifyContent(content) {
|
|
155
|
+
const lines = content.split(`
|
|
156
|
+
`);
|
|
157
|
+
const match = (lines[0] ?? "").match(/^(Background task|Detached foreground task) (completed|failed|paused|stopped): \*\*(.+?)\*\*(?:\s+(\([^)]*\)))?$/);
|
|
158
|
+
if (!match)
|
|
159
|
+
return;
|
|
160
|
+
let body = lines.slice(2);
|
|
161
|
+
const scheduleMatch = (body[0] ?? "").match(/^Scheduled run from \*\*(.+?)\*\* \(schedule (.+?)\)\.$/);
|
|
162
|
+
let parsedScheduleOrigin;
|
|
163
|
+
if (scheduleMatch) {
|
|
164
|
+
const label = scheduleMatch[1];
|
|
165
|
+
const id = scheduleMatch[2];
|
|
166
|
+
parsedScheduleOrigin = { id, ...label === id ? {} : { name: label } };
|
|
167
|
+
body = body.slice(body[1]?.trim() === "" ? 2 : 1);
|
|
168
|
+
}
|
|
169
|
+
let sessionIndex = -1;
|
|
170
|
+
for (let i = body.length - 1;i >= 1; i--) {
|
|
171
|
+
if (body[i - 1]?.trim() === "" && /^(Session|Session file|Session share error):\s+/.test(body[i])) {
|
|
172
|
+
sessionIndex = i;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const sessionLine = sessionIndex >= 0 ? body[sessionIndex] : undefined;
|
|
177
|
+
const handoffIndex = body.findIndex((line) => line.startsWith("Parallel handoff: "));
|
|
178
|
+
const workflowRunIndex = body.findIndex((line) => line.startsWith("Workflow run: "));
|
|
179
|
+
const childRunsIndex = body.findIndex((line) => line.startsWith("Child runs: "));
|
|
180
|
+
const reconciledIndex = body.findIndex((line) => line.startsWith("Reconciled detached child: "));
|
|
181
|
+
const metadataIndexes = [sessionIndex, handoffIndex, workflowRunIndex, childRunsIndex, reconciledIndex].filter((index) => index >= 0);
|
|
182
|
+
const firstMetadataIndex = metadataIndexes.length ? Math.min(...metadataIndexes) : body.length;
|
|
183
|
+
const resultEnd = firstMetadataIndex > 0 && body[firstMetadataIndex - 1]?.trim() === "" ? firstMetadataIndex - 1 : firstMetadataIndex;
|
|
184
|
+
const resultPreview = body.slice(0, resultEnd).join(`
|
|
185
|
+
`).trim() || "(no output)";
|
|
186
|
+
const handoffPath = handoffIndex >= 0 ? body[handoffIndex].slice("Parallel handoff: ".length).trim() : undefined;
|
|
187
|
+
const workflowRunId = workflowRunIndex >= 0 ? body[workflowRunIndex].slice("Workflow run: ".length).trim() : undefined;
|
|
188
|
+
const childRuns = childRunsIndex >= 0 ? body[childRunsIndex].slice("Child runs: ".length).split(", ").map((part) => {
|
|
189
|
+
const trimmed = part.trim();
|
|
190
|
+
const statusMatch = trimmed.match(/^(.*?)(?: \(([^)]*)\))?$/);
|
|
191
|
+
const raw = statusMatch?.[1] ?? trimmed;
|
|
192
|
+
const separator = raw.indexOf("=");
|
|
193
|
+
return separator >= 0 ? { workflowKey: raw.slice(0, separator), runId: raw.slice(separator + 1), ...statusMatch?.[2] ? { status: statusMatch[2] } : {} } : { runId: raw, ...statusMatch?.[2] ? { status: statusMatch[2] } : {} };
|
|
194
|
+
}).filter((child) => child.runId) : undefined;
|
|
195
|
+
const reconciledFromDetachedChild = reconciledIndex >= 0 ? body[reconciledIndex].slice("Reconciled detached child: ".length).trim() : undefined;
|
|
196
|
+
let sessionLabel;
|
|
197
|
+
let sessionValue;
|
|
198
|
+
if (sessionLine) {
|
|
199
|
+
const separator = sessionLine.indexOf(":");
|
|
200
|
+
sessionLabel = sessionLine.slice(0, separator).toLowerCase();
|
|
201
|
+
sessionValue = sessionLine.slice(separator + 1).trim();
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
agent: match[3],
|
|
205
|
+
status: match[2],
|
|
206
|
+
...match[1] === "Detached foreground task" ? { source: "foreground" } : {},
|
|
207
|
+
...match[4] ? { taskInfo: match[4] } : {},
|
|
208
|
+
...parsedScheduleOrigin ? { scheduleOrigin: parsedScheduleOrigin } : {},
|
|
209
|
+
resultPreview,
|
|
210
|
+
...handoffPath ? { handoffPath } : {},
|
|
211
|
+
...workflowRunId ? { workflowRunId } : {},
|
|
212
|
+
...childRuns?.length ? { childRuns } : {},
|
|
213
|
+
...reconciledFromDetachedChild ? { reconciledFromDetachedChild } : {},
|
|
214
|
+
...sessionLabel && sessionValue ? { sessionLabel, sessionValue } : {}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
23
217
|
export function formatGroupedCompletion(details) {
|
|
24
218
|
const header = `Background tasks completed (${details.length}): ${details.map((d) => `**${d.agent}**${d.taskInfo ?? ""}`).join(", ")}`;
|
|
25
219
|
const blocks = [header, ""];
|
|
@@ -28,8 +222,11 @@ export function formatGroupedCompletion(details) {
|
|
|
28
222
|
if (!detail)
|
|
29
223
|
continue;
|
|
30
224
|
const sessionLine = formatSessionLine(detail);
|
|
31
|
-
blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ""}`);
|
|
32
|
-
blocks.push(
|
|
225
|
+
blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ""}${detail.scheduleOrigin ? ` — scheduled run from ${detail.scheduleOrigin.name ?? detail.scheduleOrigin.id} (schedule ${detail.scheduleOrigin.id})` : ""}`);
|
|
226
|
+
blocks.push(formatResultPreview(detail));
|
|
227
|
+
if (detail.handoffPath)
|
|
228
|
+
blocks.push(`Parallel handoff: ${detail.handoffPath}`);
|
|
229
|
+
blocks.push(...formatCorrelationLines(detail));
|
|
33
230
|
if (sessionLine)
|
|
34
231
|
blocks.push(sessionLine);
|
|
35
232
|
blocks.push("");
|
|
@@ -37,15 +234,22 @@ export function formatGroupedCompletion(details) {
|
|
|
37
234
|
return blocks.join(`
|
|
38
235
|
`).trimEnd();
|
|
39
236
|
}
|
|
40
|
-
function sendCompletion(
|
|
41
|
-
if (
|
|
42
|
-
return;
|
|
237
|
+
function sendCompletion(dm, items) {
|
|
238
|
+
if (items.length === 0)
|
|
239
|
+
return true;
|
|
240
|
+
const details = items.map((item) => item.details);
|
|
43
241
|
const content = details.length === 1 ? formatSingleCompletion(details[0]) : formatGroupedCompletion(details);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
242
|
+
const display = details.some((detail) => detail.source === "foreground" || detail.status !== "completed" || detail.scheduleOrigin !== undefined);
|
|
243
|
+
try {
|
|
244
|
+
dm.sendMessage({
|
|
245
|
+
customType: "subagent-notify",
|
|
246
|
+
content,
|
|
247
|
+
display
|
|
248
|
+
}, { triggerTurn: items.some((item) => item.triggerTurn) });
|
|
249
|
+
return true;
|
|
250
|
+
} catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
49
253
|
}
|
|
50
254
|
function completionBatchKey(result) {
|
|
51
255
|
const sessionId = typeof result.sessionId === "string" ? result.sessionId.trim() : "";
|
|
@@ -57,73 +261,169 @@ function completionBatchKey(result) {
|
|
|
57
261
|
export function buildCompletionDetails(result) {
|
|
58
262
|
const agent = result.agent ?? "unknown";
|
|
59
263
|
const summary = typeof result.summary === "string" ? result.summary : "";
|
|
60
|
-
const
|
|
61
|
-
const
|
|
264
|
+
const stopped = result.stopped === true || result.state === "stopped" || result.success !== true && result.exitCode !== 0 && isUnexplainedProcessSignal(result) || result.results?.some((child) => child.stopped === true || child.status === "stopped" || child.success !== true && child.exitCode !== 0 && isUnexplainedProcessSignal(child)) === true;
|
|
265
|
+
const paused = !stopped && !result.success && (result.exitCode === 0 || result.state === "paused" || result.interrupted === true || summary.startsWith("Paused after interrupt."));
|
|
266
|
+
const status = stopped ? "stopped" : paused ? "paused" : result.success ? "completed" : "failed";
|
|
62
267
|
const taskInfo = result.taskIndex !== undefined && result.totalTasks !== undefined ? ` (${result.taskIndex + 1}/${result.totalTasks})` : undefined;
|
|
268
|
+
const parallelHandoff = result.parallelHandoff && typeof result.parallelHandoff === "object" ? result.parallelHandoff : undefined;
|
|
269
|
+
const handoffPath = typeof parallelHandoff?.path === "string" ? parallelHandoff.path : undefined;
|
|
270
|
+
const rawRunId = typeof result.runId === "string" ? result.runId : typeof result.id === "string" ? result.id : undefined;
|
|
271
|
+
const workflowRunId = (result.mode === "workflow" || agent === "workflow") && rawRunId ? rawRunId : undefined;
|
|
272
|
+
const childRuns = result.results?.flatMap((child) => {
|
|
273
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
274
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
275
|
+
if (!runId && (!workflowRunId || !workflowKey))
|
|
276
|
+
return [];
|
|
277
|
+
return [{
|
|
278
|
+
runId: runId ?? "unavailable",
|
|
279
|
+
...workflowKey ? { workflowKey } : {},
|
|
280
|
+
...typeof child.agent === "string" ? { agent: child.agent } : {},
|
|
281
|
+
status: childStatus(child, workflowRunId ? result.state : undefined)
|
|
282
|
+
}];
|
|
283
|
+
}) ?? [];
|
|
284
|
+
const childOutputs = workflowRunId && result.results?.length ? result.results.map((child) => {
|
|
285
|
+
const inline = childInlinePreview(child);
|
|
286
|
+
const workflowKey = typeof child.workflowKey === "string" && child.workflowKey.trim() ? child.workflowKey.trim() : undefined;
|
|
287
|
+
const runId = typeof child.runId === "string" && child.runId.trim() ? child.runId.trim() : undefined;
|
|
288
|
+
const savedOutputPath = childSavedOutputPath(child);
|
|
289
|
+
return {
|
|
290
|
+
...workflowKey ? { workflowKey } : {},
|
|
291
|
+
...runId ? { runId } : {},
|
|
292
|
+
...typeof child.agent === "string" ? { agent: child.agent } : {},
|
|
293
|
+
status: childStatus(child, result.state),
|
|
294
|
+
...savedOutputPath ? { savedOutputPath } : {},
|
|
295
|
+
...inline.preview ? { preview: inline.preview } : { preview: "" },
|
|
296
|
+
...inline.truncated ? { previewTruncated: true } : {},
|
|
297
|
+
...inline.unavailableReason ? { previewUnavailableReason: inline.unavailableReason } : {}
|
|
298
|
+
};
|
|
299
|
+
}) : undefined;
|
|
300
|
+
const reconciledFromDetachedChild = typeof result.reconciledFromDetachedChild === "string" ? result.reconciledFromDetachedChild : undefined;
|
|
63
301
|
const session = result.shareUrl ? { label: "Session", value: result.shareUrl } : result.shareError ? { label: "Session share error", value: result.shareError } : result.sessionFile ? { label: "Session file", value: result.sessionFile } : undefined;
|
|
302
|
+
const rawOrigin = result.scheduleOrigin;
|
|
303
|
+
const scheduleOrigin = rawOrigin && typeof rawOrigin.id === "string" ? { id: rawOrigin.id, ...typeof rawOrigin.name === "string" ? { name: rawOrigin.name } : {} } : undefined;
|
|
64
304
|
return {
|
|
65
305
|
agent,
|
|
66
306
|
status,
|
|
307
|
+
...scheduleOrigin ? { scheduleOrigin } : {},
|
|
308
|
+
...result.source ? { source: result.source } : {},
|
|
67
309
|
...taskInfo ? { taskInfo } : {},
|
|
68
310
|
resultPreview: summary,
|
|
69
311
|
...typeof result.durationMs === "number" ? { durationMs: result.durationMs } : {},
|
|
312
|
+
...handoffPath ? { handoffPath } : {},
|
|
313
|
+
...workflowRunId ? { workflowRunId } : {},
|
|
314
|
+
...childRuns.length ? { childRuns } : {},
|
|
315
|
+
...childOutputs?.length ? { childOutputs } : {},
|
|
316
|
+
...reconciledFromDetachedChild ? { reconciledFromDetachedChild } : {},
|
|
70
317
|
...session ? { sessionLabel: session.label, sessionValue: session.value } : {}
|
|
71
318
|
};
|
|
72
319
|
}
|
|
73
|
-
export default function registerSubagentNotify(
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const globalStore = globalThis;
|
|
77
|
-
const previousUnsubscribe = globalStore[unsubscribeStoreKey];
|
|
78
|
-
if (typeof previousUnsubscribe === "function") {
|
|
79
|
-
try {
|
|
80
|
-
previousUnsubscribe();
|
|
81
|
-
} catch {}
|
|
82
|
-
}
|
|
83
|
-
const previousBatcher = globalStore[batcherStoreKey];
|
|
84
|
-
if (previousBatcher && typeof previousBatcher.dispose === "function") {
|
|
85
|
-
try {
|
|
86
|
-
previousBatcher.dispose();
|
|
87
|
-
} catch {}
|
|
88
|
-
}
|
|
89
|
-
const seen = getGlobalSeenMap("__pi_subagents_notify_seen__");
|
|
320
|
+
export default function registerSubagentNotify(dm, state, options = {}) {
|
|
321
|
+
const seen = new Map;
|
|
322
|
+
const pending = new Map;
|
|
90
323
|
const ttlMs = 10 * 60 * 1000;
|
|
91
|
-
const
|
|
324
|
+
const now = options.now ?? Date.now;
|
|
92
325
|
const batchConfig = resolveCompletionBatchConfig(options.batchConfig);
|
|
93
326
|
const batchers = new Map;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
327
|
+
let disposed = false;
|
|
328
|
+
const ownsResult = options.ownership?.owns ?? ((sessionId, completionOwnerId) => sessionId === state.currentSessionId && typeof completionOwnerId === "string" && completionOwnerId === state.completionOwnerId);
|
|
329
|
+
const settle = (items, accepted) => {
|
|
330
|
+
for (const item of items) {
|
|
331
|
+
pending.delete(item.key);
|
|
332
|
+
if (accepted)
|
|
333
|
+
markSeenWithTtl(seen, item.key, now(), ttlMs);
|
|
334
|
+
item.resolve(accepted);
|
|
99
335
|
}
|
|
100
336
|
};
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
337
|
+
const emit = (items) => {
|
|
338
|
+
const accepted = [];
|
|
339
|
+
const rejected = [];
|
|
340
|
+
for (const item of items) {
|
|
341
|
+
const owned = item.details.source === "foreground" ? item.sessionId === state.currentSessionId : ownsResult(item.sessionId, item.completionOwnerId);
|
|
342
|
+
(owned ? accepted : rejected).push(item);
|
|
343
|
+
}
|
|
344
|
+
settle(rejected, false);
|
|
345
|
+
settle(accepted, sendCompletion(dm, accepted));
|
|
346
|
+
};
|
|
347
|
+
const getBatcher = (result) => {
|
|
348
|
+
const key = completionBatchKey(result);
|
|
349
|
+
let batcher = batchers.get(key);
|
|
112
350
|
if (!batcher) {
|
|
113
351
|
batcher = createCompletionBatcher({
|
|
114
352
|
config: batchConfig,
|
|
115
|
-
emit
|
|
353
|
+
emit,
|
|
116
354
|
...options.timers ? { timers: options.timers } : {},
|
|
117
|
-
now
|
|
355
|
+
now
|
|
118
356
|
});
|
|
119
|
-
batchers.set(
|
|
357
|
+
batchers.set(key, batcher);
|
|
358
|
+
}
|
|
359
|
+
return batcher;
|
|
360
|
+
};
|
|
361
|
+
const deliver = (result) => {
|
|
362
|
+
if (disposed || typeof result.sessionId !== "string")
|
|
363
|
+
return Promise.resolve(false);
|
|
364
|
+
if (result.source === "foreground") {
|
|
365
|
+
if (result.sessionId !== state.currentSessionId)
|
|
366
|
+
return Promise.resolve(false);
|
|
367
|
+
} else if (!ownsResult(result.sessionId, result.completionOwnerId))
|
|
368
|
+
return Promise.resolve(false);
|
|
369
|
+
if (result.intercomDelivered === true)
|
|
370
|
+
return Promise.resolve(true);
|
|
371
|
+
const key = buildCompletionKey(result, "notify");
|
|
372
|
+
const seenAt = seen.get(key);
|
|
373
|
+
if (seenAt !== undefined && now() - seenAt <= ttlMs)
|
|
374
|
+
return Promise.resolve(true);
|
|
375
|
+
if (seenAt !== undefined)
|
|
376
|
+
seen.delete(key);
|
|
377
|
+
const inFlight = pending.get(key);
|
|
378
|
+
if (inFlight)
|
|
379
|
+
return inFlight;
|
|
380
|
+
const details = buildCompletionDetails(result);
|
|
381
|
+
let resolve;
|
|
382
|
+
const completion = new Promise((settleCompletion) => {
|
|
383
|
+
resolve = settleCompletion;
|
|
384
|
+
});
|
|
385
|
+
pending.set(key, completion);
|
|
386
|
+
const item = {
|
|
387
|
+
key,
|
|
388
|
+
details,
|
|
389
|
+
sessionId: result.sessionId,
|
|
390
|
+
completionOwnerId: result.completionOwnerId,
|
|
391
|
+
triggerTurn: result.triggerTurn !== false,
|
|
392
|
+
resolve
|
|
393
|
+
};
|
|
394
|
+
if (details.source === "foreground") {
|
|
395
|
+
emit([item]);
|
|
396
|
+
return completion;
|
|
120
397
|
}
|
|
398
|
+
const batcher = getBatcher(result);
|
|
121
399
|
if (details.status !== "completed") {
|
|
122
400
|
batcher.flush();
|
|
123
|
-
|
|
124
|
-
return;
|
|
401
|
+
emit([item]);
|
|
402
|
+
return completion;
|
|
403
|
+
}
|
|
404
|
+
batcher.push(item);
|
|
405
|
+
return completion;
|
|
406
|
+
};
|
|
407
|
+
const unsubscribeAsync = dm.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, (data) => {
|
|
408
|
+
deliver(data);
|
|
409
|
+
});
|
|
410
|
+
const unsubscribeForeground = dm.events.on(SUBAGENT_FOREGROUND_COMPLETE_EVENT, (data) => {
|
|
411
|
+
deliver(data);
|
|
412
|
+
});
|
|
413
|
+
return {
|
|
414
|
+
deliver,
|
|
415
|
+
dispose() {
|
|
416
|
+
if (disposed)
|
|
417
|
+
return;
|
|
418
|
+
disposed = true;
|
|
419
|
+
for (const batcher of batchers.values())
|
|
420
|
+
settle(batcher.dispose(), false);
|
|
421
|
+
batchers.clear();
|
|
422
|
+
for (const unsubscribe of [unsubscribeAsync, unsubscribeForeground]) {
|
|
423
|
+
try {
|
|
424
|
+
unsubscribe?.();
|
|
425
|
+
} catch {}
|
|
426
|
+
}
|
|
125
427
|
}
|
|
126
|
-
batcher.push(details);
|
|
127
428
|
};
|
|
128
|
-
globalStore[unsubscribeStoreKey] = pi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, handleComplete);
|
|
129
429
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
const DEFAULT_TERM_GRACE_MS = 3000;
|
|
3
|
+
const DEFAULT_KILL_VERIFY_MS = 1000;
|
|
4
|
+
const VERIFY_INTERVAL_MS = 25;
|
|
5
|
+
function diagnostic(error) {
|
|
6
|
+
return error instanceof Error ? error.message : String(error);
|
|
7
|
+
}
|
|
8
|
+
function signalProcess(id, signal) {
|
|
9
|
+
try {
|
|
10
|
+
process.kill(id, signal);
|
|
11
|
+
return "sent";
|
|
12
|
+
} catch (error) {
|
|
13
|
+
if (error.code === "ESRCH")
|
|
14
|
+
return "absent";
|
|
15
|
+
return { diagnostic: diagnostic(error) };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function activeProcessGroupMembers(processGroupId) {
|
|
19
|
+
const result = spawnSync("ps", ["-axo", "pid=,pgid=,stat="], { encoding: "utf-8" });
|
|
20
|
+
if (result.error || result.status !== 0) {
|
|
21
|
+
return { diagnostic: result.error ? diagnostic(result.error) : result.stderr.trim() || `ps exited with ${result.status}` };
|
|
22
|
+
}
|
|
23
|
+
const members = [];
|
|
24
|
+
for (const line of result.stdout.split(`
|
|
25
|
+
`)) {
|
|
26
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(\S+)/.exec(line);
|
|
27
|
+
if (!match || Number(match[2]) !== processGroupId || match[3].startsWith("Z"))
|
|
28
|
+
continue;
|
|
29
|
+
members.push(Number(match[1]));
|
|
30
|
+
}
|
|
31
|
+
return members;
|
|
32
|
+
}
|
|
33
|
+
async function waitUntilGroupTerminal(processGroupId, timeoutMs) {
|
|
34
|
+
const deadline = Date.now() + timeoutMs;
|
|
35
|
+
while (true) {
|
|
36
|
+
const members = activeProcessGroupMembers(processGroupId);
|
|
37
|
+
if (Array.isArray(members) && members.length === 0)
|
|
38
|
+
return false;
|
|
39
|
+
const remaining = deadline - Date.now();
|
|
40
|
+
if (remaining <= 0) {
|
|
41
|
+
if (!Array.isArray(members))
|
|
42
|
+
return { state: "enumeration-failed", diagnostic: members.diagnostic };
|
|
43
|
+
return { state: "still-active", diagnostic: `Process group ${processGroupId} still has active members: ${members.join(", ")}.` };
|
|
44
|
+
}
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(VERIFY_INTERVAL_MS, remaining)));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function observed(processGroupId) {
|
|
49
|
+
return { state: "observed", mechanism: "posix-process-group", processGroupId, verifiedAt: Date.now() };
|
|
50
|
+
}
|
|
51
|
+
export function createOwnedProcessTreeController(pid, options = {}) {
|
|
52
|
+
let termination;
|
|
53
|
+
const posixGroupOwned = process.platform !== "win32";
|
|
54
|
+
const target = posixGroupOwned ? -pid : pid;
|
|
55
|
+
const terminate = () => {
|
|
56
|
+
if (termination)
|
|
57
|
+
return termination;
|
|
58
|
+
termination = (async () => {
|
|
59
|
+
if (!posixGroupOwned) {
|
|
60
|
+
signalProcess(target, "SIGTERM");
|
|
61
|
+
return { state: "unknown", reason: "unsupported-platform" };
|
|
62
|
+
}
|
|
63
|
+
const term = signalProcess(target, "SIGTERM");
|
|
64
|
+
if (term !== "sent" && term !== "absent") {
|
|
65
|
+
return { state: "unknown", reason: "signal-failed", diagnostic: term.diagnostic };
|
|
66
|
+
}
|
|
67
|
+
const termExit = await waitUntilGroupTerminal(pid, options.termGraceMs ?? DEFAULT_TERM_GRACE_MS);
|
|
68
|
+
if (termExit === false)
|
|
69
|
+
return observed(pid);
|
|
70
|
+
const kill = signalProcess(target, "SIGKILL");
|
|
71
|
+
if (kill !== "sent" && kill !== "absent") {
|
|
72
|
+
const members = activeProcessGroupMembers(pid);
|
|
73
|
+
if (!Array.isArray(members) || members.length > 0) {
|
|
74
|
+
return { state: "unknown", reason: "signal-failed", diagnostic: kill.diagnostic };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const killExit = await waitUntilGroupTerminal(pid, options.killVerifyMs ?? DEFAULT_KILL_VERIFY_MS);
|
|
78
|
+
if (killExit !== false) {
|
|
79
|
+
return { state: "unknown", reason: "verification-failed", diagnostic: killExit.diagnostic };
|
|
80
|
+
}
|
|
81
|
+
return observed(pid);
|
|
82
|
+
})();
|
|
83
|
+
return termination;
|
|
84
|
+
};
|
|
85
|
+
return { terminate, finishAfterWriterClose: terminate };
|
|
86
|
+
}
|