@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
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { buildCompletionKey, markSeenWithTtl } from "./completion-dedupe.js";
|
|
4
4
|
import { createFileCoalescer } from "../../shared/file-coalescer.js";
|
|
5
|
+
import { shouldUseNativeFsWatch } from "../../shared/watch-strategy.js";
|
|
5
6
|
import {
|
|
6
7
|
SUBAGENT_ASYNC_COMPLETE_EVENT
|
|
7
8
|
} from "../../shared/types.js";
|
|
@@ -13,8 +14,37 @@ import {
|
|
|
13
14
|
resolveSubagentResultStatus
|
|
14
15
|
} from "../../intercom/result-intercom.js";
|
|
15
16
|
import { projectNestedRegistryForRoot, sanitizeSummary } from "../shared/nested-events.js";
|
|
17
|
+
import { resolveWatchPath } from "../../shared/utils.js";
|
|
18
|
+
import { recordWaitCompletion } from "./wait-completions.js";
|
|
19
|
+
import { MISSION_BINDING_FILE, syncMissionFromAsyncCompletion } from "../../missions/lifecycle.js";
|
|
20
|
+
import { missionObserverResultCandidateFiles, promotePendingResultFile, removeMissionObserverIndex, removeResultIndex, resultCandidateFilesForSession, resultPayloadPathForIndexedRun, resultPayloadPathForMissionObserverRun, resultPayloadPathForSessionRun, writeAsyncResultFile, writeResultIndexForData } from "./result-files.js";
|
|
16
21
|
const WATCHER_RESTART_DELAY_MS = 3000;
|
|
17
22
|
const POLL_INTERVAL_MS = 3000;
|
|
23
|
+
const HEALTHY_SCAN_INTERVAL_MS = 60000;
|
|
24
|
+
const RETRY_DELAY_MS = 100;
|
|
25
|
+
const SLOW_RESULT_SCAN_MS = 500;
|
|
26
|
+
function jsonStringProperty(raw, property) {
|
|
27
|
+
const matches = raw.matchAll(new RegExp(`"${property}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*")`, "g"));
|
|
28
|
+
let encoded;
|
|
29
|
+
for (const match of matches)
|
|
30
|
+
encoded = match[1];
|
|
31
|
+
if (!encoded)
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
const value = JSON.parse(encoded);
|
|
35
|
+
return typeof value === "string" && value ? value : undefined;
|
|
36
|
+
} catch {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function resultFileIdentity(raw, file) {
|
|
41
|
+
return {
|
|
42
|
+
sessionId: jsonStringProperty(raw, "sessionId"),
|
|
43
|
+
completionOwnerId: jsonStringProperty(raw, "completionOwnerId"),
|
|
44
|
+
runId: file.replace(/\.json$/i, ""),
|
|
45
|
+
asyncDir: jsonStringProperty(raw, "asyncDir")
|
|
46
|
+
};
|
|
47
|
+
}
|
|
18
48
|
function sanitizeNestedResultChildren(value, resultPath, label) {
|
|
19
49
|
if (value === undefined)
|
|
20
50
|
return;
|
|
@@ -28,35 +58,282 @@ function sanitizeNestedResultChildren(value, resultPath, label) {
|
|
|
28
58
|
}
|
|
29
59
|
return children.length ? children : undefined;
|
|
30
60
|
}
|
|
31
|
-
function
|
|
61
|
+
function errorCode(error) {
|
|
32
62
|
return typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
|
|
33
63
|
}
|
|
34
|
-
function
|
|
35
|
-
return
|
|
64
|
+
function isNotFound(error) {
|
|
65
|
+
return errorCode(error) === "ENOENT";
|
|
66
|
+
}
|
|
67
|
+
function isAbsentResultCandidate(error) {
|
|
68
|
+
return isNotFound(error) || errorCode(error) === "ENAMETOOLONG";
|
|
36
69
|
}
|
|
37
|
-
function
|
|
38
|
-
const code =
|
|
70
|
+
function isAccessDenied(error) {
|
|
71
|
+
const code = errorCode(error);
|
|
72
|
+
return code === "EPERM" || code === "EACCES";
|
|
73
|
+
}
|
|
74
|
+
function shouldPoll(error) {
|
|
75
|
+
const code = errorCode(error);
|
|
39
76
|
return code === "EMFILE" || code === "ENOSPC";
|
|
40
77
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
78
|
+
function hasDeliveredNotification(data) {
|
|
79
|
+
return typeof data.notificationDeliveredAt === "number" && Number.isFinite(data.notificationDeliveredAt);
|
|
80
|
+
}
|
|
81
|
+
function resultPayloadWasReplaced(delivered, disk) {
|
|
82
|
+
if (!disk)
|
|
83
|
+
return false;
|
|
84
|
+
const deliveredState = typeof delivered.state === "string" ? delivered.state : undefined;
|
|
85
|
+
if (disk.state && deliveredState && disk.state !== deliveredState)
|
|
86
|
+
return true;
|
|
87
|
+
const deliveredTimestamp = typeof delivered.timestamp === "number" && Number.isFinite(delivered.timestamp) ? delivered.timestamp : undefined;
|
|
88
|
+
return disk.timestamp !== undefined && deliveredTimestamp !== undefined && disk.timestamp !== deliveredTimestamp;
|
|
47
89
|
}
|
|
48
|
-
|
|
90
|
+
function markDeliveredNotification(resultPath, data, runId, now) {
|
|
91
|
+
const marked = { ...data, runId, notificationDeliveredAt: now };
|
|
92
|
+
writeAsyncResultFile(resultPath, marked);
|
|
93
|
+
return marked;
|
|
94
|
+
}
|
|
95
|
+
export function createResultWatcher(dm, state, resultsDir, completionTtlMs, deps = {}) {
|
|
49
96
|
const fsApi = deps.fs ?? fs;
|
|
50
97
|
const timers = deps.timers ?? { setTimeout, clearTimeout, setInterval, clearInterval };
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
98
|
+
const notifier = deps.notifier ?? { deliver: async () => true };
|
|
99
|
+
const parseResult = deps.parseResult ?? ((raw) => JSON.parse(raw));
|
|
100
|
+
const deliverIntercomResults = deps.deliverIntercomResults !== false;
|
|
101
|
+
const pendingTriggerTurn = new Map;
|
|
102
|
+
const processing = new Set;
|
|
103
|
+
const identityCache = new Map;
|
|
104
|
+
let deliveryActive = true;
|
|
105
|
+
let deliveryEpoch = 0;
|
|
106
|
+
let resultScanTimer = null;
|
|
107
|
+
let activeSessionId = null;
|
|
108
|
+
const ownsResult = deps.ownership?.owns ?? ((sessionId, completionOwnerId) => sessionId === state.currentSessionId && typeof completionOwnerId === "string" && completionOwnerId === state.completionOwnerId);
|
|
109
|
+
const claimedSessionIds = () => deps.ownership?.claimedSessionIds() ?? [];
|
|
110
|
+
const ownsCompletion = (sessionId, completionOwnerId, epoch) => {
|
|
111
|
+
if (!deliveryActive || epoch !== deliveryEpoch)
|
|
112
|
+
return false;
|
|
113
|
+
if (!activeSessionId && state.currentSessionId)
|
|
114
|
+
activeSessionId = state.currentSessionId;
|
|
115
|
+
return activeSessionId === state.currentSessionId && ownsResult(sessionId, completionOwnerId);
|
|
116
|
+
};
|
|
117
|
+
const scheduleResult = (file, triggerTurn, delayMs = 0) => {
|
|
118
|
+
const pendingMode = pendingTriggerTurn.get(file);
|
|
119
|
+
pendingTriggerTurn.set(file, pendingMode === false || !triggerTurn ? false : true);
|
|
120
|
+
state.resultFileCoalescer.schedule(file, delayMs);
|
|
121
|
+
};
|
|
122
|
+
const publicResultPath = (file) => path.join(resultsDir, file);
|
|
123
|
+
const publicResultFileExists = (file) => {
|
|
124
|
+
try {
|
|
125
|
+
return fsApi.statSync(publicResultPath(file)).isFile();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (!isAbsentResultCandidate(error))
|
|
128
|
+
console.error(`Failed to inspect subagent result file '${publicResultPath(file)}':`, error);
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const resultPayloadPath = (file, observed) => {
|
|
133
|
+
if (file !== path.basename(file) || !file.endsWith(".json"))
|
|
134
|
+
return;
|
|
135
|
+
const runId = file.replace(/\.json$/i, "");
|
|
136
|
+
for (const sessionId of [state.currentSessionId, ...claimedSessionIds()]) {
|
|
137
|
+
if (!sessionId)
|
|
138
|
+
continue;
|
|
139
|
+
const sessionResult = resultPayloadPathForSessionRun(resultsDir, sessionId, runId);
|
|
140
|
+
if (sessionResult)
|
|
141
|
+
return sessionResult;
|
|
142
|
+
}
|
|
143
|
+
const observerResult = resultPayloadPathForMissionObserverRun(resultsDir, runId);
|
|
144
|
+
if (observerResult)
|
|
145
|
+
return observerResult;
|
|
146
|
+
if (observed?.has(runId)) {
|
|
147
|
+
const indexedResult = resultPayloadPathForIndexedRun(resultsDir, runId);
|
|
148
|
+
if (indexedResult)
|
|
149
|
+
return indexedResult;
|
|
150
|
+
}
|
|
151
|
+
return publicResultFileExists(file) ? publicResultPath(file) : undefined;
|
|
152
|
+
};
|
|
153
|
+
const resultSignature = (file, observed) => {
|
|
154
|
+
const resultPath = resultPayloadPath(file, observed);
|
|
155
|
+
if (!resultPath) {
|
|
156
|
+
identityCache.delete(file);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const stat = fsApi.statSync(resultPath);
|
|
161
|
+
if (!stat.isFile())
|
|
162
|
+
return;
|
|
163
|
+
return `${resultPath}:${stat.size}:${stat.mtimeMs}`;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
identityCache.delete(file);
|
|
166
|
+
if (isAccessDenied(error))
|
|
167
|
+
throw error;
|
|
168
|
+
if (!isAbsentResultCandidate(error))
|
|
169
|
+
console.error(`Failed to inspect subagent result file '${resultPath}':`, error);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const inspectResult = (file, knownSignature, observed) => {
|
|
174
|
+
const resultPath = resultPayloadPath(file, observed);
|
|
175
|
+
if (!resultPath)
|
|
54
176
|
return;
|
|
55
177
|
try {
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
178
|
+
const signature = knownSignature ?? resultSignature(file, observed);
|
|
179
|
+
if (!signature)
|
|
58
180
|
return;
|
|
181
|
+
const cached = identityCache.get(file);
|
|
182
|
+
if (cached?.signature === signature)
|
|
183
|
+
return { identity: cached.identity, signature };
|
|
184
|
+
const identity = resultFileIdentity(fsApi.readFileSync(resultPath, "utf-8"), file);
|
|
185
|
+
identityCache.set(file, { signature, identity });
|
|
186
|
+
return { identity, signature };
|
|
187
|
+
} catch (error) {
|
|
188
|
+
identityCache.delete(file);
|
|
189
|
+
if (isAccessDenied(error))
|
|
190
|
+
throw error;
|
|
191
|
+
if (!isAbsentResultCandidate(error))
|
|
192
|
+
console.error(`Failed to inspect subagent result file '${resultPath}':`, error);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const observedRunIds = () => {
|
|
197
|
+
try {
|
|
198
|
+
return new Set(deps.observedCompletionRunIds?.() ?? []);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error("Failed to inspect observed subagent completion ids:", error);
|
|
201
|
+
return new Set;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
const shouldProcessResult = (file, observed, knownSignature) => {
|
|
205
|
+
const inspected = inspectResult(file, knownSignature, observed);
|
|
206
|
+
if (!inspected)
|
|
207
|
+
return false;
|
|
208
|
+
const { identity } = inspected;
|
|
209
|
+
if (!identity.sessionId)
|
|
210
|
+
return true;
|
|
211
|
+
if (ownsResult(identity.sessionId, identity.completionOwnerId))
|
|
212
|
+
return true;
|
|
213
|
+
if (identity.asyncDir && fsApi.existsSync(path.join(identity.asyncDir, MISSION_BINDING_FILE)))
|
|
214
|
+
return true;
|
|
215
|
+
if (identity.runId && (observed ?? observedRunIds()).has(identity.runId))
|
|
216
|
+
return true;
|
|
217
|
+
return Boolean(deps.observeCompletion && !deps.observedCompletionRunIds);
|
|
218
|
+
};
|
|
219
|
+
const removeDeliveredResult = (file, sessionId, runId, toolCallId) => {
|
|
220
|
+
try {
|
|
221
|
+
if (publicResultFileExists(file))
|
|
222
|
+
fsApi.unlinkSync(publicResultPath(file));
|
|
223
|
+
identityCache.delete(file);
|
|
224
|
+
removeResultIndex(resultsDir, sessionId, runId, toolCallId);
|
|
225
|
+
return true;
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (!isAbsentResultCandidate(error)) {
|
|
228
|
+
console.error(`Failed to remove delivered subagent result '${publicResultPath(file)}'; will retry:`, error);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const handleResult = async (file, triggerTurn) => {
|
|
235
|
+
if (processing.has(file))
|
|
236
|
+
return;
|
|
237
|
+
let observed;
|
|
238
|
+
try {
|
|
239
|
+
if (!shouldProcessResult(file)) {
|
|
240
|
+
const runId = file === path.basename(file) && file.endsWith(".json") ? file.replace(/\.json$/i, "") : undefined;
|
|
241
|
+
observed = observedRunIds();
|
|
242
|
+
if (!runId || !observed.has(runId) || !shouldProcessResult(file, observed))
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (!isAccessDenied(error))
|
|
247
|
+
throw error;
|
|
248
|
+
console.error(`Failed to inspect subagent result file '${publicResultPath(file)}'; will retry:`, error);
|
|
249
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
processing.add(file);
|
|
253
|
+
let rereadReplacedPayload = false;
|
|
254
|
+
let resultPath = publicResultPath(file);
|
|
255
|
+
const readPublicResultIdentity = () => {
|
|
256
|
+
if (!publicResultFileExists(file))
|
|
257
|
+
return;
|
|
258
|
+
const parsed = JSON.parse(fsApi.readFileSync(publicResultPath(file), "utf-8"));
|
|
259
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
260
|
+
return;
|
|
261
|
+
const record = parsed;
|
|
262
|
+
const state = typeof record.state === "string" && record.state ? record.state : undefined;
|
|
263
|
+
const timestamp = typeof record.timestamp === "number" && Number.isFinite(record.timestamp) ? record.timestamp : undefined;
|
|
264
|
+
if (!state && timestamp === undefined)
|
|
265
|
+
return;
|
|
266
|
+
return { state, timestamp };
|
|
267
|
+
};
|
|
268
|
+
try {
|
|
269
|
+
const payloadPath = resultPayloadPath(file, observed);
|
|
270
|
+
if (!payloadPath)
|
|
271
|
+
return;
|
|
272
|
+
resultPath = payloadPath;
|
|
273
|
+
let raw = fsApi.readFileSync(resultPath, "utf-8");
|
|
274
|
+
let identity = resultFileIdentity(raw, file);
|
|
275
|
+
if (identity.sessionId && identity.runId) {
|
|
276
|
+
const pendingState = promotePendingResultFile(resultsDir, identity.sessionId, identity.runId, file);
|
|
277
|
+
if (pendingState === "promoted") {
|
|
278
|
+
identityCache.delete(file);
|
|
279
|
+
resultPath = publicResultPath(file);
|
|
280
|
+
raw = fsApi.readFileSync(resultPath, "utf-8");
|
|
281
|
+
identity = resultFileIdentity(raw, file);
|
|
282
|
+
} else if (pendingState === "pending") {
|
|
283
|
+
const pendingPath = resultPayloadPathForSessionRun(resultsDir, identity.sessionId, identity.runId);
|
|
284
|
+
if (!pendingPath) {
|
|
285
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
resultPath = pendingPath;
|
|
289
|
+
raw = fsApi.readFileSync(resultPath, "utf-8");
|
|
290
|
+
identity = resultFileIdentity(raw, file);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
let data = parseResult(raw);
|
|
294
|
+
const markReplacedPayload = () => {
|
|
295
|
+
try {
|
|
296
|
+
if (!resultPayloadWasReplaced(data, readPublicResultIdentity()))
|
|
297
|
+
return false;
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (isAccessDenied(error))
|
|
300
|
+
throw error;
|
|
301
|
+
if (isAbsentResultCandidate(error))
|
|
302
|
+
return false;
|
|
303
|
+
console.error(`Failed to re-read subagent result file '${publicResultPath(file)}':`, error);
|
|
304
|
+
}
|
|
305
|
+
identityCache.delete(file);
|
|
306
|
+
rereadReplacedPayload = true;
|
|
307
|
+
return true;
|
|
308
|
+
};
|
|
309
|
+
if (typeof data.sessionId !== "string" || !data.sessionId)
|
|
310
|
+
return;
|
|
311
|
+
const sessionId = data.sessionId;
|
|
312
|
+
const completionOwnerId = data.completionOwnerId;
|
|
59
313
|
const runId = data.runId ?? data.id ?? file.replace(/\.json$/i, "");
|
|
314
|
+
const toolCallId = typeof data.toolCallId === "string" ? data.toolCallId : undefined;
|
|
315
|
+
let observerSucceeded = true;
|
|
316
|
+
try {
|
|
317
|
+
syncMissionFromAsyncCompletion({ ...data, runId });
|
|
318
|
+
} catch (error) {
|
|
319
|
+
observerSucceeded = false;
|
|
320
|
+
console.error(`Mission completion sync failed for '${resultPath}':`, error);
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
deps.observeCompletion?.({ ...data, runId });
|
|
324
|
+
} catch (error) {
|
|
325
|
+
observerSucceeded = false;
|
|
326
|
+
console.error(`Completion observer failed for '${resultPath}':`, error);
|
|
327
|
+
}
|
|
328
|
+
if (observerSucceeded)
|
|
329
|
+
removeMissionObserverIndex(resultsDir, runId);
|
|
330
|
+
const epoch = deliveryEpoch;
|
|
331
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
332
|
+
return;
|
|
333
|
+
recordWaitCompletion(state, runId, data, Date.now(), completionTtlMs, {
|
|
334
|
+
resultsDir,
|
|
335
|
+
sessionId
|
|
336
|
+
});
|
|
60
337
|
const hasExplicitNestedChildren = data.nestedChildren !== undefined;
|
|
61
338
|
let nestedChildren = compactNestedResultChildren(sanitizeNestedResultChildren(data.nestedChildren, resultPath, "nestedChildren"));
|
|
62
339
|
if (!nestedChildren?.length && !hasExplicitNestedChildren) {
|
|
@@ -64,37 +341,56 @@ export function createResultWatcher(pi, state, resultsDir, completionTtlMs, deps
|
|
|
64
341
|
nestedChildren = compactNestedResultChildren(projectNestedRegistryForRoot(runId)?.children);
|
|
65
342
|
} catch (error) {
|
|
66
343
|
console.error(`Failed to enrich subagent result file '${resultPath}' with nested registry children; will retry later:`, error);
|
|
344
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
67
345
|
return;
|
|
68
346
|
}
|
|
69
347
|
}
|
|
70
|
-
const now = Date.now();
|
|
71
348
|
const completionKey = buildCompletionKey(data, `result:${file}`);
|
|
72
|
-
|
|
73
|
-
|
|
349
|
+
const alreadyDelivered = hasDeliveredNotification(data);
|
|
350
|
+
const lastSeenAt = state.completionSeen.get(completionKey);
|
|
351
|
+
if (lastSeenAt !== undefined && Date.now() - lastSeenAt > completionTtlMs) {
|
|
352
|
+
state.completionSeen.delete(completionKey);
|
|
353
|
+
} else if (lastSeenAt !== undefined) {
|
|
354
|
+
if (!observerSucceeded) {
|
|
355
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
359
|
+
return;
|
|
360
|
+
if (markReplacedPayload())
|
|
361
|
+
return;
|
|
362
|
+
if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
|
|
363
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
74
364
|
return;
|
|
75
365
|
}
|
|
76
366
|
const hasResultChildren = Array.isArray(data.results) && data.results.length > 0;
|
|
77
|
-
const resultChildren = hasResultChildren ? data.results : [{
|
|
78
|
-
agent: data.agent,
|
|
79
|
-
output: data.summary,
|
|
80
|
-
success: data.success
|
|
81
|
-
}];
|
|
367
|
+
const resultChildren = hasResultChildren ? data.results : [{ agent: data.agent ?? undefined, output: data.summary, outputState: "unknown", success: data.success }];
|
|
82
368
|
const normalizedChildren = attachNestedChildrenToResultChildren(runId, resultChildren.map((result = {}, index) => {
|
|
83
|
-
const baseOutput = result.output ?? data.summary;
|
|
369
|
+
const baseOutput = hasResultChildren ? result.output : result.output ?? data.summary;
|
|
84
370
|
const hasRealOutput = typeof baseOutput === "string" && baseOutput.trim().length > 0;
|
|
85
|
-
const
|
|
371
|
+
const structuredPreview = result.structuredOutput === undefined ? undefined : JSON.stringify(result.structuredOutput, null, 2).slice(0, 4000);
|
|
372
|
+
const output = hasRealOutput ? baseOutput : structuredPreview ? `Structured output:
|
|
373
|
+
${structuredPreview}` : "(no output)";
|
|
86
374
|
const summary = result.success === false && result.error ? `${result.error}${hasRealOutput ? `
|
|
87
375
|
|
|
88
376
|
Output:
|
|
89
377
|
${baseOutput}` : ""}` : output;
|
|
90
378
|
const sessionPath = result.sessionFile ?? (resultChildren.length === 1 ? data.sessionFile : undefined);
|
|
91
379
|
const childNestedChildren = sanitizeNestedResultChildren(result.children, resultPath, `results[${index}].children`);
|
|
380
|
+
const childState = result.state === "paused" || result.state === "stopped" ? result.state : result.stopped === true ? "stopped" : data.state === "paused" || !hasResultChildren && (data.state === "stopped" || typeof result.success !== "boolean") ? data.state : undefined;
|
|
92
381
|
return {
|
|
93
382
|
agent: result.agent ?? data.agent ?? `step-${index + 1}`,
|
|
383
|
+
...result.sessionName ? { sessionName: result.sessionName } : {},
|
|
94
384
|
status: resolveSubagentResultStatus({
|
|
95
385
|
success: result.success,
|
|
96
|
-
state:
|
|
386
|
+
state: childState,
|
|
387
|
+
interrupted: result.interrupted,
|
|
388
|
+
timedOut: result.timedOut,
|
|
389
|
+
stopped: result.stopped,
|
|
390
|
+
turnBudgetExceeded: result.turnBudgetExceeded,
|
|
391
|
+
processSignal: result.processSignal
|
|
97
392
|
}),
|
|
393
|
+
outputState: result.outputState === "present" || result.outputState === "absent" || result.outputState === "unknown" ? result.outputState : "unknown",
|
|
98
394
|
summary,
|
|
99
395
|
index,
|
|
100
396
|
artifactPath: result.artifactPaths?.outputPath,
|
|
@@ -103,26 +399,45 @@ ${baseOutput}` : ""}` : output;
|
|
|
103
399
|
...childNestedChildren ? { children: childNestedChildren } : {}
|
|
104
400
|
};
|
|
105
401
|
}), nestedChildren);
|
|
402
|
+
if (alreadyDelivered) {
|
|
403
|
+
markSeenWithTtl(state.completionSeen, completionKey, Date.now(), completionTtlMs);
|
|
404
|
+
if (!observerSucceeded) {
|
|
405
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
409
|
+
return;
|
|
410
|
+
if (markReplacedPayload())
|
|
411
|
+
return;
|
|
412
|
+
if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
|
|
413
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
106
416
|
const intercomTarget = data.intercomTarget?.trim();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
417
|
+
let intercomDelivered = false;
|
|
418
|
+
if (deliverIntercomResults && intercomTarget && triggerTurn) {
|
|
419
|
+
const mode = data.mode === "single" || data.mode === "parallel" || data.mode === "chain" || data.mode === "workflow" ? data.mode : resultChildren.length > 1 ? "chain" : "single";
|
|
420
|
+
intercomDelivered = await deliverSubagentResultIntercomEvent(dm.events, buildSubagentResultIntercomPayload({
|
|
110
421
|
to: intercomTarget,
|
|
111
422
|
runId,
|
|
112
423
|
mode,
|
|
113
424
|
source: "async",
|
|
114
425
|
children: normalizedChildren,
|
|
115
|
-
asyncId: data.id,
|
|
116
|
-
asyncDir: data.asyncDir
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!
|
|
426
|
+
asyncId: data.id ?? undefined,
|
|
427
|
+
asyncDir: data.asyncDir,
|
|
428
|
+
...data.parallelHandoff ? { parallelHandoff: data.parallelHandoff } : {}
|
|
429
|
+
}));
|
|
430
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
431
|
+
return;
|
|
432
|
+
if (!intercomDelivered)
|
|
120
433
|
console.error(`Subagent async grouped result intercom delivery was not acknowledged for '${resultPath}'.`);
|
|
121
|
-
}
|
|
122
434
|
}
|
|
123
|
-
|
|
435
|
+
const accepted = await notifier.deliver({
|
|
124
436
|
...data,
|
|
437
|
+
id: data.id ?? runId,
|
|
125
438
|
runId,
|
|
439
|
+
triggerTurn,
|
|
440
|
+
intercomDelivered,
|
|
126
441
|
...nestedChildren?.length ? { nestedChildren } : {},
|
|
127
442
|
...Array.isArray(data.results) ? {
|
|
128
443
|
results: hasResultChildren ? normalizedChildren.map((child, index) => ({
|
|
@@ -137,36 +452,165 @@ ${baseOutput}` : ""}` : output;
|
|
|
137
452
|
})) : []
|
|
138
453
|
} : {}
|
|
139
454
|
});
|
|
140
|
-
|
|
141
|
-
} catch (error) {
|
|
142
|
-
if (isNotFoundError(error))
|
|
455
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
143
456
|
return;
|
|
144
|
-
|
|
457
|
+
if (!accepted) {
|
|
458
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (markReplacedPayload())
|
|
462
|
+
return;
|
|
463
|
+
try {
|
|
464
|
+
data = markDeliveredNotification(publicResultPath(file), data, runId, Date.now());
|
|
465
|
+
identityCache.delete(file);
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error(`Failed to mark subagent result notification delivered for '${resultPath}'; will retry:`, error);
|
|
468
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
markSeenWithTtl(state.completionSeen, completionKey, Date.now(), completionTtlMs);
|
|
472
|
+
try {
|
|
473
|
+
dm.events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
|
|
474
|
+
...data,
|
|
475
|
+
runId,
|
|
476
|
+
triggerTurn,
|
|
477
|
+
intercomDelivered,
|
|
478
|
+
...nestedChildren?.length ? { nestedChildren } : {},
|
|
479
|
+
...Array.isArray(data.results) ? {
|
|
480
|
+
results: hasResultChildren ? normalizedChildren.map((child, index) => ({
|
|
481
|
+
...data.results[index],
|
|
482
|
+
agent: child.agent,
|
|
483
|
+
status: child.status,
|
|
484
|
+
summary: child.summary,
|
|
485
|
+
index: child.index,
|
|
486
|
+
artifactPath: child.artifactPath,
|
|
487
|
+
sessionPath: child.sessionPath,
|
|
488
|
+
children: child.children
|
|
489
|
+
})) : []
|
|
490
|
+
} : {}
|
|
491
|
+
});
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.error(`Completion observer failed for '${resultPath}':`, error);
|
|
494
|
+
}
|
|
495
|
+
if (!observerSucceeded) {
|
|
496
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (!ownsCompletion(sessionId, completionOwnerId, epoch))
|
|
500
|
+
return;
|
|
501
|
+
if (!removeDeliveredResult(file, sessionId, runId, toolCallId))
|
|
502
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
503
|
+
} catch (error) {
|
|
504
|
+
if (isAccessDenied(error)) {
|
|
505
|
+
console.error(`Failed to process subagent result file '${resultPath}'; will retry:`, error);
|
|
506
|
+
scheduleResult(file, triggerTurn, RETRY_DELAY_MS);
|
|
507
|
+
} else if (!isNotFound(error))
|
|
508
|
+
console.error(`Failed to process subagent result file '${resultPath}':`, error);
|
|
509
|
+
} finally {
|
|
510
|
+
processing.delete(file);
|
|
511
|
+
if (rereadReplacedPayload)
|
|
512
|
+
scheduleResult(file, triggerTurn);
|
|
145
513
|
}
|
|
146
514
|
};
|
|
147
515
|
state.resultFileCoalescer = createFileCoalescer((file) => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
516
|
+
const triggerTurn = pendingTriggerTurn.get(file) !== false;
|
|
517
|
+
pendingTriggerTurn.delete(file);
|
|
518
|
+
handleResult(file, triggerTurn);
|
|
519
|
+
}, deps.coalesceDelayMs ?? 50);
|
|
520
|
+
const logScanStats = (stats) => {
|
|
521
|
+
const elapsed = Date.now() - stats.startedAt;
|
|
522
|
+
if (elapsed < SLOW_RESULT_SCAN_MS)
|
|
523
|
+
return;
|
|
524
|
+
const resultScanLogging = deps.resultScanLogging ?? "activity";
|
|
525
|
+
if (resultScanLogging === "off")
|
|
526
|
+
return;
|
|
527
|
+
if (resultScanLogging === "activity" && stats.files === 0 && stats.scheduled === 0)
|
|
528
|
+
return;
|
|
529
|
+
console.error(`Subagent result scan inspected ${stats.files} indexed result file(s), scheduled ${stats.scheduled} in ${elapsed}ms (${resultsDir}).`);
|
|
530
|
+
};
|
|
531
|
+
const indexedResultCandidates = (observed) => {
|
|
532
|
+
const files = new Set;
|
|
533
|
+
for (const sessionId of [state.currentSessionId, ...claimedSessionIds()]) {
|
|
534
|
+
if (!sessionId)
|
|
535
|
+
continue;
|
|
536
|
+
for (const file of resultCandidateFilesForSession(resultsDir, sessionId))
|
|
537
|
+
files.add(file);
|
|
538
|
+
}
|
|
539
|
+
for (const runId of state.asyncJobs.keys())
|
|
540
|
+
files.add(`${runId}.json`);
|
|
541
|
+
for (const file of missionObserverResultCandidateFiles(resultsDir))
|
|
542
|
+
files.add(file);
|
|
543
|
+
for (const runId of observed)
|
|
544
|
+
files.add(`${runId}.json`);
|
|
545
|
+
return [...files];
|
|
546
|
+
};
|
|
547
|
+
const primeExistingResults = (options = {}) => {
|
|
151
548
|
try {
|
|
152
|
-
|
|
549
|
+
const triggerTurn = options.triggerTurn !== false;
|
|
550
|
+
const stats = { files: 0, scheduled: 0, startedAt: Date.now() };
|
|
551
|
+
const observed = observedRunIds();
|
|
552
|
+
for (const file of indexedResultCandidates(observed)) {
|
|
553
|
+
stats.files += 1;
|
|
554
|
+
const signature = resultSignature(file, observed);
|
|
555
|
+
if (!signature)
|
|
556
|
+
continue;
|
|
557
|
+
if (!shouldProcessResult(file, observed, signature))
|
|
558
|
+
continue;
|
|
559
|
+
stats.scheduled += 1;
|
|
560
|
+
scheduleResult(file, triggerTurn);
|
|
561
|
+
}
|
|
562
|
+
logScanStats(stats);
|
|
153
563
|
} catch (error) {
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
564
|
+
if (!isNotFound(error))
|
|
565
|
+
console.error(`Failed to scan subagent result index in '${resultsDir}':`, error);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const clearResultScan = () => {
|
|
569
|
+
if (resultScanTimer)
|
|
570
|
+
timers.clearInterval(resultScanTimer);
|
|
571
|
+
resultScanTimer = null;
|
|
572
|
+
};
|
|
573
|
+
const useNativeWatcher = () => shouldUseNativeFsWatch("result-delivery", deps.platform);
|
|
574
|
+
const hasDeliveryDemand = () => {
|
|
575
|
+
try {
|
|
576
|
+
return deps.hasDeliveryDemand?.() === true;
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.error("Failed to inspect subagent result delivery demand:", error);
|
|
579
|
+
return false;
|
|
157
580
|
}
|
|
158
581
|
};
|
|
159
|
-
const
|
|
582
|
+
const clearResultPoller = () => {
|
|
583
|
+
if (!state.watcherRestartTimer)
|
|
584
|
+
return;
|
|
585
|
+
timers.clearTimeout(state.watcherRestartTimer);
|
|
586
|
+
timers.clearInterval(state.watcherRestartTimer);
|
|
587
|
+
state.watcherRestartTimer = null;
|
|
588
|
+
};
|
|
589
|
+
const startDemandPolling = () => {
|
|
590
|
+
if (!deliveryActive || useNativeWatcher() || state.watcherRestartTimer)
|
|
591
|
+
return;
|
|
592
|
+
if (!hasDeliveryDemand())
|
|
593
|
+
return;
|
|
594
|
+
state.watcherRestartTimer = timers.setInterval(() => {
|
|
595
|
+
primeExistingResults();
|
|
596
|
+
if (!hasDeliveryDemand())
|
|
597
|
+
clearResultPoller();
|
|
598
|
+
}, POLL_INTERVAL_MS);
|
|
599
|
+
state.watcherRestartTimer.unref?.();
|
|
600
|
+
};
|
|
601
|
+
const startPolling = (reason) => {
|
|
160
602
|
state.watcher?.close();
|
|
161
603
|
state.watcher = null;
|
|
604
|
+
clearResultScan();
|
|
162
605
|
if (state.watcherRestartTimer)
|
|
163
606
|
return;
|
|
164
|
-
console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${
|
|
607
|
+
console.error(`Subagent result watcher for '${resultsDir}' fell back to polling because native fs.watch is unavailable (${errorCode(reason) ?? "unknown error"}).`);
|
|
165
608
|
primeExistingResults();
|
|
166
609
|
state.watcherRestartTimer = timers.setInterval(primeExistingResults, POLL_INTERVAL_MS);
|
|
167
610
|
state.watcherRestartTimer.unref?.();
|
|
168
611
|
};
|
|
169
612
|
const scheduleRestart = () => {
|
|
613
|
+
clearResultScan();
|
|
170
614
|
if (state.watcherRestartTimer)
|
|
171
615
|
return;
|
|
172
616
|
state.watcherRestartTimer = timers.setTimeout(() => {
|
|
@@ -175,10 +619,8 @@ ${baseOutput}` : ""}` : output;
|
|
|
175
619
|
fsApi.mkdirSync(resultsDir, { recursive: true });
|
|
176
620
|
startResultWatcher();
|
|
177
621
|
} catch (error) {
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
622
|
+
if (shouldPoll(error))
|
|
623
|
+
return startPolling(error);
|
|
182
624
|
console.error(`Failed to restart subagent result watcher for '${resultsDir}':`, error);
|
|
183
625
|
scheduleRestart();
|
|
184
626
|
}
|
|
@@ -188,51 +630,74 @@ ${baseOutput}` : ""}` : output;
|
|
|
188
630
|
const startResultWatcher = () => {
|
|
189
631
|
if (state.watcher)
|
|
190
632
|
return;
|
|
633
|
+
activeSessionId = state.currentSessionId;
|
|
634
|
+
deliveryActive = true;
|
|
635
|
+
deliveryEpoch += 1;
|
|
191
636
|
if (state.watcherRestartTimer) {
|
|
192
637
|
timers.clearTimeout(state.watcherRestartTimer);
|
|
193
638
|
timers.clearInterval(state.watcherRestartTimer);
|
|
194
639
|
state.watcherRestartTimer = null;
|
|
195
640
|
}
|
|
641
|
+
if (!useNativeWatcher()) {
|
|
642
|
+
startDemandPolling();
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
196
645
|
try {
|
|
197
|
-
const watchDir =
|
|
198
|
-
state.watcher = fsApi.watch(watchDir, (
|
|
199
|
-
if (
|
|
646
|
+
const watchDir = resolveWatchPath(resultsDir, fsApi.realpathSync.native);
|
|
647
|
+
state.watcher = fsApi.watch(watchDir, (_event, file) => {
|
|
648
|
+
if (!file) {
|
|
649
|
+
primeExistingResults();
|
|
200
650
|
return;
|
|
651
|
+
}
|
|
201
652
|
const fileName = file.toString();
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
653
|
+
if (fileName.endsWith(".json")) {
|
|
654
|
+
identityCache.delete(fileName);
|
|
655
|
+
try {
|
|
656
|
+
writeResultIndexForData(path.join(resultsDir, fileName), JSON.parse(fsApi.readFileSync(path.join(resultsDir, fileName), "utf-8")));
|
|
657
|
+
} catch {}
|
|
658
|
+
scheduleResult(fileName, true);
|
|
659
|
+
}
|
|
205
660
|
});
|
|
206
661
|
state.watcher.on("error", (error) => {
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
662
|
+
if (shouldPoll(error))
|
|
663
|
+
return startPolling(error);
|
|
211
664
|
console.error(`Subagent result watcher failed for '${resultsDir}':`, error);
|
|
212
665
|
state.watcher?.close();
|
|
213
666
|
state.watcher = null;
|
|
214
667
|
scheduleRestart();
|
|
215
668
|
});
|
|
216
669
|
state.watcher.unref?.();
|
|
670
|
+
resultScanTimer = timers.setInterval(primeExistingResults, HEALTHY_SCAN_INTERVAL_MS);
|
|
671
|
+
resultScanTimer.unref?.();
|
|
217
672
|
} catch (error) {
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
673
|
+
if (shouldPoll(error))
|
|
674
|
+
return startPolling(error);
|
|
222
675
|
console.error(`Failed to start subagent result watcher for '${resultsDir}':`, error);
|
|
223
676
|
state.watcher = null;
|
|
224
677
|
scheduleRestart();
|
|
225
678
|
}
|
|
226
679
|
};
|
|
680
|
+
const transitionResultDelivery = () => {
|
|
681
|
+
deliveryActive = true;
|
|
682
|
+
activeSessionId = state.currentSessionId;
|
|
683
|
+
deliveryEpoch += 1;
|
|
684
|
+
identityCache.clear();
|
|
685
|
+
};
|
|
227
686
|
const stopResultWatcher = () => {
|
|
687
|
+
deliveryActive = false;
|
|
688
|
+
activeSessionId = null;
|
|
689
|
+
deliveryEpoch += 1;
|
|
228
690
|
state.watcher?.close();
|
|
229
691
|
state.watcher = null;
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
timers.clearInterval(state.watcherRestartTimer);
|
|
233
|
-
}
|
|
234
|
-
state.watcherRestartTimer = null;
|
|
692
|
+
clearResultPoller();
|
|
693
|
+
clearResultScan();
|
|
235
694
|
state.resultFileCoalescer.clear();
|
|
695
|
+
pendingTriggerTurn.clear();
|
|
696
|
+
processing.clear();
|
|
697
|
+
identityCache.clear();
|
|
236
698
|
};
|
|
237
|
-
return { startResultWatcher, primeExistingResults, stopResultWatcher
|
|
699
|
+
return { startResultWatcher, transitionResultDelivery, primeExistingResults, stopResultWatcher, refreshResultDelivery: () => {
|
|
700
|
+
primeExistingResults();
|
|
701
|
+
startDemandPolling();
|
|
702
|
+
} };
|
|
238
703
|
}
|