@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
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isStorageCapacityError } from "./file-system-retry.js";
|
|
2
|
+
import { writeAtomicJson } from "./atomic-json.js";
|
|
3
|
+
const defaultTimerApi = {
|
|
4
|
+
setTimeout: (handler, delayMs) => setTimeout(handler, delayMs),
|
|
5
|
+
clearTimeout: (handle) => clearTimeout(handle)
|
|
6
|
+
};
|
|
7
|
+
export function createCapacityResilientJsonWriter(options = {}) {
|
|
8
|
+
const defaultWrite = options.write ?? writeAtomicJson;
|
|
9
|
+
const keepAlive = options.keepAlive ?? false;
|
|
10
|
+
const retryDelayMs = options.retryDelayMs ?? 1000;
|
|
11
|
+
const timerApi = options.timerApi ?? defaultTimerApi;
|
|
12
|
+
const onError = options.onError ?? ((error, filePath) => console.error(`Failed to persist JSON '${filePath}':`, error));
|
|
13
|
+
const onSuccess = options.onSuccess;
|
|
14
|
+
const reportError = (error, filePath) => {
|
|
15
|
+
try {
|
|
16
|
+
onError(error, filePath);
|
|
17
|
+
} catch (callbackError) {
|
|
18
|
+
console.error(`Failed to report JSON persistence error for '${filePath}':`, callbackError);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const notifySuccess = (filePath, payload) => {
|
|
22
|
+
if (!onSuccess)
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
onSuccess(filePath, payload);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
reportError(error, filePath);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const pending = new Map;
|
|
31
|
+
let retryTimer;
|
|
32
|
+
const scheduleRetry = () => {
|
|
33
|
+
if (retryTimer !== undefined)
|
|
34
|
+
return;
|
|
35
|
+
retryTimer = timerApi.setTimeout(() => {
|
|
36
|
+
retryTimer = undefined;
|
|
37
|
+
for (const [filePath, entry] of pending) {
|
|
38
|
+
try {
|
|
39
|
+
entry.write(filePath, entry.payload);
|
|
40
|
+
pending.delete(filePath);
|
|
41
|
+
notifySuccess(filePath, entry.payload);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (isStorageCapacityError(error))
|
|
44
|
+
continue;
|
|
45
|
+
pending.delete(filePath);
|
|
46
|
+
reportError(error, filePath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (pending.size > 0)
|
|
50
|
+
scheduleRetry();
|
|
51
|
+
}, retryDelayMs);
|
|
52
|
+
if (!keepAlive && typeof retryTimer === "object" && retryTimer !== null && "unref" in retryTimer && typeof retryTimer.unref === "function") {
|
|
53
|
+
retryTimer.unref();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
write(filePath, payload, writeOperation = defaultWrite) {
|
|
58
|
+
try {
|
|
59
|
+
writeOperation(filePath, payload);
|
|
60
|
+
pending.delete(filePath);
|
|
61
|
+
notifySuccess(filePath, payload);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (!isStorageCapacityError(error))
|
|
64
|
+
throw error;
|
|
65
|
+
pending.set(filePath, { payload, write: writeOperation });
|
|
66
|
+
scheduleRetry();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
pendingCount: () => pending.size,
|
|
70
|
+
dispose: () => {
|
|
71
|
+
if (retryTimer !== undefined)
|
|
72
|
+
timerApi.clearTimeout(retryTimer);
|
|
73
|
+
retryTimer = undefined;
|
|
74
|
+
pending.clear();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { previewDisplayText } from "./display-text.js";
|
|
2
|
+
import { PROMPT_REDACTED } from "./utils.js";
|
|
3
|
+
const TASK_EXCERPT_MAX_CHARS = 60;
|
|
4
|
+
export const CHILD_SESSION_NAME_MAX_CHARS = 80;
|
|
5
|
+
export function deriveChildSessionName(input) {
|
|
6
|
+
const agent = input.agent?.trim() ?? "";
|
|
7
|
+
const rawLabel = input.label?.trim() ?? "";
|
|
8
|
+
const rawTask = input.task?.trim() ?? "";
|
|
9
|
+
const excerptSource = rawLabel && rawLabel !== PROMPT_REDACTED ? rawLabel : rawTask && rawTask !== PROMPT_REDACTED ? rawTask : "";
|
|
10
|
+
const excerpt = excerptSource ? previewDisplayText(excerptSource, TASK_EXCERPT_MAX_CHARS) : "";
|
|
11
|
+
const base = agent && excerpt ? `${agent}: ${excerpt}` : agent || excerpt;
|
|
12
|
+
if (!base)
|
|
13
|
+
return;
|
|
14
|
+
return previewDisplayText(base, CHILD_SESSION_NAME_MAX_CHARS);
|
|
15
|
+
}
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { extractTextFromContent, extractToolArgsPreview } from "./utils.js";
|
|
4
|
+
const MAX_TOOL_PAYLOAD_BYTES = 32 * 1024;
|
|
5
|
+
const TOOL_PAYLOAD_TRUNCATION_MARKER = `
|
|
6
|
+
|
|
7
|
+
… payload truncated`;
|
|
8
|
+
function boundedPayload(value, maxBytes = MAX_TOOL_PAYLOAD_BYTES) {
|
|
9
|
+
let text;
|
|
10
|
+
if (typeof value === "string")
|
|
11
|
+
text = value;
|
|
12
|
+
else {
|
|
13
|
+
try {
|
|
14
|
+
const serialized = JSON.stringify(value, null, 2);
|
|
15
|
+
if (serialized === undefined)
|
|
16
|
+
return;
|
|
17
|
+
text = serialized;
|
|
18
|
+
} catch {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!text.trim())
|
|
23
|
+
return;
|
|
24
|
+
const payload = Buffer.from(text, "utf-8");
|
|
25
|
+
if (payload.length <= maxBytes)
|
|
26
|
+
return text;
|
|
27
|
+
const markerBytes = Buffer.byteLength(TOOL_PAYLOAD_TRUNCATION_MARKER, "utf-8");
|
|
28
|
+
let end = Math.max(0, maxBytes - markerBytes);
|
|
29
|
+
while (end > 0 && (payload[end] & 192) === 128)
|
|
30
|
+
end--;
|
|
31
|
+
return `${payload.subarray(0, end).toString("utf-8")}${TOOL_PAYLOAD_TRUNCATION_MARKER}`;
|
|
32
|
+
}
|
|
4
33
|
export const CHILD_TRANSCRIPT_ARTIFACT_VERSION = 1;
|
|
5
34
|
const DEFAULT_MAX_CHILD_TRANSCRIPT_BYTES = 50 * 1024 * 1024;
|
|
6
35
|
function errorMessage(error) {
|
|
@@ -100,6 +129,27 @@ export function createChildTranscriptWriter(input) {
|
|
|
100
129
|
}
|
|
101
130
|
const writeMessage = (sourceEventType, message) => {
|
|
102
131
|
const text = extractTextFromContent(message.content);
|
|
132
|
+
if (message.role === "toolResult") {
|
|
133
|
+
const output = boundedPayload(text);
|
|
134
|
+
writeRecord({
|
|
135
|
+
...baseRecord("message"),
|
|
136
|
+
sourceEventType,
|
|
137
|
+
role: message.role,
|
|
138
|
+
toolCallId: message.toolCallId,
|
|
139
|
+
toolName: message.toolName,
|
|
140
|
+
isError: message.isError,
|
|
141
|
+
...output ? { text: output, outputTruncated: output.includes("… payload truncated") } : {},
|
|
142
|
+
message: {
|
|
143
|
+
role: message.role,
|
|
144
|
+
toolCallId: message.toolCallId,
|
|
145
|
+
toolName: message.toolName,
|
|
146
|
+
isError: message.isError,
|
|
147
|
+
content: output ? [{ type: "text", text: output }] : [],
|
|
148
|
+
...message.timestamp !== undefined ? { timestamp: message.timestamp } : {}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
103
153
|
writeRecord({
|
|
104
154
|
...baseRecord("message"),
|
|
105
155
|
sourceEventType,
|
|
@@ -130,11 +180,14 @@ export function createChildTranscriptWriter(input) {
|
|
|
130
180
|
}
|
|
131
181
|
if (event.type === "tool_execution_start" && event.toolName) {
|
|
132
182
|
const args = eventArgs(event);
|
|
183
|
+
const argsPayload = boundedPayload(args);
|
|
133
184
|
writeRecord({
|
|
134
185
|
...baseRecord("tool_start"),
|
|
135
186
|
sourceEventType: event.type,
|
|
187
|
+
...event.toolCallId ? { toolCallId: event.toolCallId } : {},
|
|
136
188
|
toolName: event.toolName,
|
|
137
|
-
...Object.keys(args).length > 0 ? { argsPreview: extractToolArgsPreview(args) } : {}
|
|
189
|
+
...Object.keys(args).length > 0 ? { argsPreview: extractToolArgsPreview(args) } : {},
|
|
190
|
+
...argsPayload ? { argsPayload } : {}
|
|
138
191
|
});
|
|
139
192
|
return;
|
|
140
193
|
}
|
|
@@ -142,7 +195,9 @@ export function createChildTranscriptWriter(input) {
|
|
|
142
195
|
writeRecord({
|
|
143
196
|
...baseRecord("tool_end"),
|
|
144
197
|
sourceEventType: event.type,
|
|
145
|
-
...event.
|
|
198
|
+
...event.toolCallId ? { toolCallId: event.toolCallId } : {},
|
|
199
|
+
...event.toolName ? { toolName: event.toolName } : {},
|
|
200
|
+
...typeof event.isError === "boolean" ? { isError: event.isError } : {}
|
|
146
201
|
});
|
|
147
202
|
}
|
|
148
203
|
},
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
const COMPLETION_OWNER_KEY = Symbol.for("dm-subagents.completion-owner-id");
|
|
3
|
+
export function currentCompletionOwnerId() {
|
|
4
|
+
const runtime = globalThis;
|
|
5
|
+
runtime[COMPLETION_OWNER_KEY] ??= randomUUID();
|
|
6
|
+
return runtime[COMPLETION_OWNER_KEY];
|
|
7
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
function codePointWidth(codePoint) {
|
|
2
|
+
return codePoint > 65535 ? 2 : 1;
|
|
3
|
+
}
|
|
4
|
+
function isWhitespaceOrControl(codePoint) {
|
|
5
|
+
if (codePoint <= 32 || codePoint >= 127 && codePoint <= 159)
|
|
6
|
+
return true;
|
|
7
|
+
if (codePoint >= 55296 && codePoint <= 57343)
|
|
8
|
+
return true;
|
|
9
|
+
return String.fromCodePoint(codePoint).trim().length === 0;
|
|
10
|
+
}
|
|
11
|
+
function consumeControlString(value, index, osc) {
|
|
12
|
+
while (index < value.length) {
|
|
13
|
+
const codePoint = value.codePointAt(index);
|
|
14
|
+
const width = codePointWidth(codePoint);
|
|
15
|
+
if (osc && codePoint === 7)
|
|
16
|
+
return index + width;
|
|
17
|
+
if (codePoint === 156)
|
|
18
|
+
return index + width;
|
|
19
|
+
if (codePoint === 27 && value.charCodeAt(index + 1) === 92)
|
|
20
|
+
return index + 2;
|
|
21
|
+
index += width;
|
|
22
|
+
}
|
|
23
|
+
return value.length;
|
|
24
|
+
}
|
|
25
|
+
function consumeCsi(value, index) {
|
|
26
|
+
while (index < value.length) {
|
|
27
|
+
const codePoint = value.codePointAt(index);
|
|
28
|
+
const width = codePointWidth(codePoint);
|
|
29
|
+
if (codePoint >= 64 && codePoint <= 126)
|
|
30
|
+
return index + width;
|
|
31
|
+
index += width;
|
|
32
|
+
}
|
|
33
|
+
return value.length;
|
|
34
|
+
}
|
|
35
|
+
export function sanitizeDisplayText(value) {
|
|
36
|
+
const output = [];
|
|
37
|
+
let pendingSpace = false;
|
|
38
|
+
const appendSpace = () => {
|
|
39
|
+
if (output.length > 0)
|
|
40
|
+
pendingSpace = true;
|
|
41
|
+
};
|
|
42
|
+
const appendText = (text) => {
|
|
43
|
+
if (pendingSpace)
|
|
44
|
+
output.push(" ");
|
|
45
|
+
output.push(text);
|
|
46
|
+
pendingSpace = false;
|
|
47
|
+
};
|
|
48
|
+
for (let index = 0;index < value.length; ) {
|
|
49
|
+
const codePoint = value.codePointAt(index);
|
|
50
|
+
const width = codePointWidth(codePoint);
|
|
51
|
+
if (codePoint === 27) {
|
|
52
|
+
const next = value.charCodeAt(index + 1);
|
|
53
|
+
appendSpace();
|
|
54
|
+
if (next === 91) {
|
|
55
|
+
index = consumeCsi(value, index + 2);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (next === 93 || next === 80 || next === 88 || next === 94 || next === 95) {
|
|
59
|
+
index = consumeControlString(value, index + 2, next === 93);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
index += next ? 2 : 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (codePoint === 155) {
|
|
66
|
+
appendSpace();
|
|
67
|
+
index = consumeCsi(value, index + width);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (codePoint === 144 || codePoint === 152 || codePoint === 157 || codePoint === 158 || codePoint === 159) {
|
|
71
|
+
appendSpace();
|
|
72
|
+
index = consumeControlString(value, index + width, codePoint === 157);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (isWhitespaceOrControl(codePoint))
|
|
76
|
+
appendSpace();
|
|
77
|
+
else
|
|
78
|
+
appendText(String.fromCodePoint(codePoint));
|
|
79
|
+
index += width;
|
|
80
|
+
}
|
|
81
|
+
return output.join("");
|
|
82
|
+
}
|
|
83
|
+
export function truncateDisplayText(value, maxLength) {
|
|
84
|
+
if (maxLength <= 0)
|
|
85
|
+
return "";
|
|
86
|
+
if (value.length <= maxLength)
|
|
87
|
+
return value;
|
|
88
|
+
let output = "";
|
|
89
|
+
for (const char of value) {
|
|
90
|
+
if (output.length + char.length > maxLength)
|
|
91
|
+
break;
|
|
92
|
+
output += char;
|
|
93
|
+
}
|
|
94
|
+
return output;
|
|
95
|
+
}
|
|
96
|
+
export function previewDisplayText(value, maxLength) {
|
|
97
|
+
const normalized = sanitizeDisplayText(value);
|
|
98
|
+
if (normalized.length <= maxLength)
|
|
99
|
+
return normalized;
|
|
100
|
+
if (maxLength <= 3)
|
|
101
|
+
return truncateDisplayText(normalized, maxLength);
|
|
102
|
+
return `${truncateDisplayText(normalized, maxLength - 3)}...`;
|
|
103
|
+
}
|
|
104
|
+
const BINARY_CONTENT_PLACEHOLDER = "[binary content omitted for safe display]";
|
|
105
|
+
function isUnsafeTerminalCodePoint(codePoint) {
|
|
106
|
+
const terminalControl = codePoint <= 31 && codePoint !== 9 && codePoint !== 10 || codePoint >= 127 && codePoint <= 159;
|
|
107
|
+
const bidiControl = codePoint === 1564 || codePoint === 8206 || codePoint === 8207 || codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8294 && codePoint <= 8297;
|
|
108
|
+
const privateUse = codePoint >= 57344 && codePoint <= 63743 || codePoint >= 983040 && codePoint <= 1048573 || codePoint >= 1048576 && codePoint <= 1114109;
|
|
109
|
+
const invalidScalar = codePoint >= 55296 && codePoint <= 57343;
|
|
110
|
+
const nonCharacter = codePoint >= 64976 && codePoint <= 65007 || (codePoint & 65535) === 65534 || (codePoint & 65535) === 65535;
|
|
111
|
+
return terminalControl || bidiControl || privateUse || invalidScalar || nonCharacter;
|
|
112
|
+
}
|
|
113
|
+
function looksLikeBinaryContent(text) {
|
|
114
|
+
if (text.includes("\x00"))
|
|
115
|
+
return true;
|
|
116
|
+
let suspiciousControls = 0;
|
|
117
|
+
let replacementCharacters = 0;
|
|
118
|
+
let codePoints = 0;
|
|
119
|
+
for (const character of text) {
|
|
120
|
+
codePoints++;
|
|
121
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
122
|
+
if (codePoint <= 8 || codePoint >= 14 && codePoint <= 31)
|
|
123
|
+
suspiciousControls++;
|
|
124
|
+
if (codePoint === 65533)
|
|
125
|
+
replacementCharacters++;
|
|
126
|
+
}
|
|
127
|
+
if (codePoints === 0)
|
|
128
|
+
return false;
|
|
129
|
+
return suspiciousControls >= 4 && suspiciousControls / codePoints >= 0.1 || replacementCharacters >= 3 && replacementCharacters / codePoints >= 0.1;
|
|
130
|
+
}
|
|
131
|
+
export function safeTerminalText(value) {
|
|
132
|
+
const normalized = value.replace(/\r\n/g, `
|
|
133
|
+
`);
|
|
134
|
+
if (looksLikeBinaryContent(normalized))
|
|
135
|
+
return BINARY_CONTENT_PLACEHOLDER;
|
|
136
|
+
let safe = "";
|
|
137
|
+
for (const character of normalized) {
|
|
138
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
139
|
+
safe += isUnsafeTerminalCodePoint(codePoint) ? `[U+${codePoint.toString(16).toUpperCase().padStart(4, "0")}]` : character;
|
|
140
|
+
}
|
|
141
|
+
return safe;
|
|
142
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function isStaleExtensionContextError(error) {
|
|
2
|
+
return error instanceof Error && /extension ctx is stale|extension context no longer active|stale after session replacement or reload/i.test(error.message);
|
|
3
|
+
}
|
|
4
|
+
export function withCachedUiContext(ctx, onStale, run) {
|
|
5
|
+
if (!ctx)
|
|
6
|
+
return;
|
|
7
|
+
try {
|
|
8
|
+
if (!ctx.hasUI)
|
|
9
|
+
return;
|
|
10
|
+
return run(ctx);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (!isStaleExtensionContextError(error))
|
|
13
|
+
throw error;
|
|
14
|
+
onStale();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -15,6 +15,15 @@ export function createFileCoalescer(handler, defaultDelayMs, timerApi = defaultT
|
|
|
15
15
|
pending.set(file, timer);
|
|
16
16
|
return true;
|
|
17
17
|
},
|
|
18
|
+
flush(file) {
|
|
19
|
+
const timer = pending.get(file);
|
|
20
|
+
if (timer === undefined)
|
|
21
|
+
return false;
|
|
22
|
+
timerApi.clearTimeout(timer);
|
|
23
|
+
pending.delete(file);
|
|
24
|
+
handler(file);
|
|
25
|
+
return true;
|
|
26
|
+
},
|
|
18
27
|
clear() {
|
|
19
28
|
for (const timer of pending.values()) {
|
|
20
29
|
timerApi.clearTimeout(timer);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const WAIT_BUFFER = typeof SharedArrayBuffer !== "undefined" ? new SharedArrayBuffer(4) : undefined;
|
|
2
|
+
const WAIT_VIEW = WAIT_BUFFER ? new Int32Array(WAIT_BUFFER) : undefined;
|
|
3
|
+
const RETRYABLE_FILE_SYSTEM_ERROR_CODES = new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
4
|
+
const STORAGE_CAPACITY_ERROR_CODES = new Set(["EDQUOT", "EMFILE", "ENFILE", "ENOSPC"]);
|
|
5
|
+
export const FS_RETRY_MAX_TOTAL_MS_ENV = "DM_SUBAGENT_FS_RETRY_MAX_TOTAL_MS";
|
|
6
|
+
const BASE_FILE_SYSTEM_RETRY_DELAYS_MS = [10, 25, 50, 100, 200, 500, 1000, 2000, 4000];
|
|
7
|
+
export function resolveFileSystemRetryDelays(env = process.env, base = BASE_FILE_SYSTEM_RETRY_DELAYS_MS) {
|
|
8
|
+
const raw = env[FS_RETRY_MAX_TOTAL_MS_ENV];
|
|
9
|
+
if (raw === undefined || raw.trim() === "")
|
|
10
|
+
return base;
|
|
11
|
+
const budget = Number(raw);
|
|
12
|
+
if (!Number.isInteger(budget) || budget < 0) {
|
|
13
|
+
throw new Error(`${FS_RETRY_MAX_TOTAL_MS_ENV} must be a non-negative integer number of milliseconds.`);
|
|
14
|
+
}
|
|
15
|
+
let spent = 0;
|
|
16
|
+
return base.map((delayMs) => {
|
|
17
|
+
const allowed = Math.max(0, Math.min(delayMs, budget - spent));
|
|
18
|
+
spent += allowed;
|
|
19
|
+
return allowed;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export const DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS = resolveFileSystemRetryDelays();
|
|
23
|
+
export function waitForFileSystemRetry(delayMs) {
|
|
24
|
+
if (delayMs <= 0)
|
|
25
|
+
return;
|
|
26
|
+
if (WAIT_VIEW) {
|
|
27
|
+
try {
|
|
28
|
+
Atomics.wait(WAIT_VIEW, 0, 0, delayMs);
|
|
29
|
+
return;
|
|
30
|
+
} catch {}
|
|
31
|
+
}
|
|
32
|
+
const end = Date.now() + delayMs;
|
|
33
|
+
while (Date.now() < end) {}
|
|
34
|
+
}
|
|
35
|
+
export function isRetryableFileSystemError(error) {
|
|
36
|
+
const code = error?.code;
|
|
37
|
+
return typeof code === "string" && RETRYABLE_FILE_SYSTEM_ERROR_CODES.has(code);
|
|
38
|
+
}
|
|
39
|
+
export function isStorageCapacityError(error) {
|
|
40
|
+
const code = error?.code;
|
|
41
|
+
return typeof code === "string" && STORAGE_CAPACITY_ERROR_CODES.has(code);
|
|
42
|
+
}
|
|
43
|
+
export function runFileSystemOperationWithRetry(operation, options = {}) {
|
|
44
|
+
const retryDelaysMs = options.retryDelaysMs ?? DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS;
|
|
45
|
+
const wait = options.wait ?? waitForFileSystemRetry;
|
|
46
|
+
for (let attempt = 0;; attempt++) {
|
|
47
|
+
try {
|
|
48
|
+
return operation();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const delayMs = retryDelaysMs[attempt];
|
|
51
|
+
if (delayMs === undefined || !isRetryableFileSystemError(error))
|
|
52
|
+
throw error;
|
|
53
|
+
wait(delayMs);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -2,9 +2,39 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { SessionManager } from "@duckmind/dm-coding-agent";
|
|
5
|
+
import { findModelInfo } from "./model-info.js";
|
|
5
6
|
export function resolveSubagentContext(value) {
|
|
6
7
|
return value === "fork" ? "fork" : "fresh";
|
|
7
8
|
}
|
|
9
|
+
export function resolveSubagentLaunchContext(input) {
|
|
10
|
+
if (input.explicitContext !== undefined)
|
|
11
|
+
return input.explicitContext;
|
|
12
|
+
const preferredContext = input.defaultSubagentContext ?? input.agentDefaultContext ?? "fresh";
|
|
13
|
+
return preferredContext === "fork" && input.canUseImplicitFork ? "fork" : "fresh";
|
|
14
|
+
}
|
|
15
|
+
export function canPreferFork(sessionManager) {
|
|
16
|
+
return canPreferForkFromSnapshot({
|
|
17
|
+
parentSessionFile: sessionManager.getSessionFile(),
|
|
18
|
+
leafId: sessionManager.getLeafId?.() ?? null
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function canPreferForkFromSnapshot(input) {
|
|
22
|
+
if (!input.parentSessionFile || !input.leafId)
|
|
23
|
+
return false;
|
|
24
|
+
try {
|
|
25
|
+
return fs.existsSync(input.parentSessionFile);
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function forkedChildRequiresThinkingOff(model, availableModels, preferredProvider) {
|
|
31
|
+
if (!model)
|
|
32
|
+
return true;
|
|
33
|
+
const info = findModelInfo(model, availableModels, preferredProvider);
|
|
34
|
+
if (!info)
|
|
35
|
+
return true;
|
|
36
|
+
return info.provider.toLowerCase() === "anthropic" || info.api?.toLowerCase() === "anthropic-messages";
|
|
37
|
+
}
|
|
8
38
|
function isUnsafeAnthropicThinkingBlock(message, block) {
|
|
9
39
|
if (!message || !block || typeof block !== "object" || !("type" in block))
|
|
10
40
|
return false;
|
|
@@ -16,8 +46,9 @@ function isUnsafeAnthropicThinkingBlock(message, block) {
|
|
|
16
46
|
return true;
|
|
17
47
|
if (block.type !== "thinking" || !isAnthropic)
|
|
18
48
|
return false;
|
|
19
|
-
const
|
|
20
|
-
|
|
49
|
+
const record = block;
|
|
50
|
+
const signature = "thinkingSignature" in record ? record.thinkingSignature : ("signature" in record) ? record.signature : undefined;
|
|
51
|
+
return record.redacted === true || typeof signature === "string" && signature.length > 0;
|
|
21
52
|
}
|
|
22
53
|
function createEntryId(entries) {
|
|
23
54
|
const ids = new Set(entries.map((entry) => entry.id).filter((id) => typeof id === "string"));
|
|
@@ -52,8 +83,6 @@ function sanitizeUnsafeThinkingBlocks(entries) {
|
|
|
52
83
|
entry.message.content = filtered;
|
|
53
84
|
sanitized = true;
|
|
54
85
|
}
|
|
55
|
-
if (sanitized)
|
|
56
|
-
appendThinkingOffEntry(entries);
|
|
57
86
|
return sanitized;
|
|
58
87
|
}
|
|
59
88
|
function readSessionEntries(sessionFile) {
|
|
@@ -68,9 +97,24 @@ function readSessionEntries(sessionFile) {
|
|
|
68
97
|
}
|
|
69
98
|
});
|
|
70
99
|
}
|
|
100
|
+
export function alignForkedSessionCwd(sessionFile, cwd) {
|
|
101
|
+
const entries = readSessionEntries(sessionFile);
|
|
102
|
+
const header = entries[0];
|
|
103
|
+
if (header?.type !== "session")
|
|
104
|
+
throw new Error(`Forked session ${sessionFile} does not start with a session header.`);
|
|
105
|
+
const resolvedCwd = path.resolve(cwd);
|
|
106
|
+
const effectiveCwd = fs.realpathSync.native(resolvedCwd);
|
|
107
|
+
if (header.cwd === effectiveCwd)
|
|
108
|
+
return;
|
|
109
|
+
header.cwd = effectiveCwd;
|
|
110
|
+
fs.writeFileSync(sessionFile, `${entries.map((entry) => JSON.stringify(entry)).join(`
|
|
111
|
+
`)}
|
|
112
|
+
`, "utf-8");
|
|
113
|
+
}
|
|
71
114
|
export function createForkContextResolver(sessionManager, requestedContext, options = {}) {
|
|
72
115
|
if (resolveSubagentContext(requestedContext) !== "fork") {
|
|
73
116
|
return {
|
|
117
|
+
prepareSessionForIndex: async () => {},
|
|
74
118
|
sessionFileForIndex: () => {
|
|
75
119
|
return;
|
|
76
120
|
},
|
|
@@ -87,10 +131,11 @@ export function createForkContextResolver(sessionManager, requestedContext, opti
|
|
|
87
131
|
if (!leafId) {
|
|
88
132
|
throw new Error("Forked subagent context requires a current leaf to fork from.");
|
|
89
133
|
}
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const sessionDir = sessionManager.getSessionDir?.();
|
|
134
|
+
const openSession = options.openSession ?? sessionManager.openSession ?? ((file, dir) => SessionManager.open(file, dir));
|
|
135
|
+
const sessionDir = path.join(path.dirname(parentSessionFile), path.basename(parentSessionFile, ".jsonl"), "forks");
|
|
93
136
|
const cachedResolutions = new Map;
|
|
137
|
+
const preparedIndexes = new Set;
|
|
138
|
+
const preparationPromises = new Map;
|
|
94
139
|
const resolveFork = (index = 0) => {
|
|
95
140
|
const cached = cachedResolutions.get(index);
|
|
96
141
|
if (cached)
|
|
@@ -99,47 +144,65 @@ export function createForkContextResolver(sessionManager, requestedContext, opti
|
|
|
99
144
|
if (!fs.existsSync(parentSessionFile)) {
|
|
100
145
|
throw new Error(`Parent session file does not exist: ${parentSessionFile}. DM has not persisted enough history to fork yet.`);
|
|
101
146
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
147
|
+
const sourceManager = openSession(parentSessionFile, sessionDir);
|
|
148
|
+
const sessionFile = sourceManager.createBranchedSession(leafId);
|
|
149
|
+
if (!sessionFile) {
|
|
150
|
+
throw new Error("Session manager did not return a forked session file.");
|
|
151
|
+
}
|
|
152
|
+
const forceThinkingOff = (sanitized) => sanitized && (options.forceThinkingOffForIndex?.(index) ?? true);
|
|
153
|
+
let thinkingOverride;
|
|
154
|
+
if (!fs.existsSync(sessionFile)) {
|
|
155
|
+
const header = sourceManager.getHeader?.();
|
|
156
|
+
const entries = sourceManager.getEntries?.();
|
|
157
|
+
if (!header || !entries) {
|
|
158
|
+
throw new Error(`Session manager returned a forked session file that does not exist and cannot be persisted by fallback: ${sessionFile}`);
|
|
107
159
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
if (sanitizeUnsafeThinkingBlocks(entries))
|
|
116
|
-
thinkingOverride = "off";
|
|
117
|
-
fs.mkdirSync(path.dirname(sessionFile), { recursive: true });
|
|
118
|
-
fs.writeFileSync(sessionFile, `${[header, ...entries].map((entry) => JSON.stringify(entry)).join(`
|
|
160
|
+
if (forceThinkingOff(sanitizeUnsafeThinkingBlocks(entries))) {
|
|
161
|
+
appendThinkingOffEntry(entries);
|
|
162
|
+
thinkingOverride = "off";
|
|
163
|
+
}
|
|
164
|
+
fs.mkdirSync(path.dirname(sessionFile), { recursive: true });
|
|
165
|
+
fs.writeFileSync(sessionFile, `${[header, ...entries].map((entry) => JSON.stringify(entry)).join(`
|
|
119
166
|
`)}
|
|
120
167
|
`, "utf-8");
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
168
|
+
} else {
|
|
169
|
+
const entries = readSessionEntries(sessionFile);
|
|
170
|
+
if (sanitizeUnsafeThinkingBlocks(entries)) {
|
|
171
|
+
if (forceThinkingOff(true)) {
|
|
172
|
+
appendThinkingOffEntry(entries);
|
|
124
173
|
thinkingOverride = "off";
|
|
125
|
-
|
|
174
|
+
}
|
|
175
|
+
fs.writeFileSync(sessionFile, `${entries.map((entry) => JSON.stringify(entry)).join(`
|
|
126
176
|
`)}
|
|
127
177
|
`, "utf-8");
|
|
128
|
-
}
|
|
129
178
|
}
|
|
130
|
-
const resolution = { sessionFile, ...thinkingOverride ? { thinkingOverride } : {} };
|
|
131
|
-
cachedResolutions.set(index, resolution);
|
|
132
|
-
return resolution;
|
|
133
|
-
} finally {
|
|
134
|
-
sourceManager?.dispose?.();
|
|
135
179
|
}
|
|
180
|
+
const resolution = { sessionFile, ...thinkingOverride ? { thinkingOverride } : {} };
|
|
181
|
+
cachedResolutions.set(index, resolution);
|
|
182
|
+
return resolution;
|
|
136
183
|
} catch (error) {
|
|
137
184
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
138
185
|
throw new Error(`Failed to create forked subagent session: ${cause.message}`, { cause });
|
|
139
186
|
}
|
|
140
187
|
};
|
|
141
188
|
return {
|
|
189
|
+
async prepareSessionForIndex(index = 0) {
|
|
190
|
+
const resolution = resolveFork(index);
|
|
191
|
+
if (!options.pruneSession || preparedIndexes.has(index))
|
|
192
|
+
return;
|
|
193
|
+
let preparation = preparationPromises.get(index);
|
|
194
|
+
if (!preparation) {
|
|
195
|
+
preparation = options.pruneSession(resolution.sessionFile).then(() => {
|
|
196
|
+
preparedIndexes.add(index);
|
|
197
|
+
});
|
|
198
|
+
preparationPromises.set(index, preparation);
|
|
199
|
+
}
|
|
200
|
+
await preparation;
|
|
201
|
+
},
|
|
142
202
|
sessionFileForIndex(index = 0) {
|
|
203
|
+
if (options.pruneSession && !preparedIndexes.has(index)) {
|
|
204
|
+
throw new Error(`Pruned fork session ${index} was used before pruning completed.`);
|
|
205
|
+
}
|
|
143
206
|
return resolveFork(index).sessionFile;
|
|
144
207
|
},
|
|
145
208
|
thinkingOverrideForIndex(index = 0) {
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { isDynamicParallelStep, isParallelStep } from "./settings.js";
|
|
4
|
+
import { previewDisplayText, sanitizeDisplayText } from "./display-text.js";
|
|
4
5
|
import { splitKnownThinkingSuffix, THINKING_LEVELS } from "./model-info.js";
|
|
5
6
|
export function formatTokens(n) {
|
|
6
|
-
|
|
7
|
+
if (n < 1000)
|
|
8
|
+
return String(n);
|
|
9
|
+
if (n < 1e4)
|
|
10
|
+
return `${(n / 1000).toFixed(1)}k`;
|
|
11
|
+
if (n < 999500)
|
|
12
|
+
return `${Math.round(n / 1000)}k`;
|
|
13
|
+
return `${Number((n / 1e6).toFixed(1))}M`;
|
|
14
|
+
}
|
|
15
|
+
export function formatTokenUsage(usage, legacyLabel = "tok") {
|
|
16
|
+
return usage.window !== undefined ? `${formatTokens(usage.window)} window · ${formatTokens(usage.total)} spent` : `${formatTokens(usage.total)} ${legacyLabel}`;
|
|
17
|
+
}
|
|
18
|
+
export function formatContextUsage(usage, contextLimit) {
|
|
19
|
+
if (usage.window === undefined || !Number.isFinite(usage.window) || !Number.isFinite(contextLimit) || contextLimit <= 0)
|
|
20
|
+
return;
|
|
21
|
+
const peak = usage.windowPeak !== undefined && Number.isFinite(usage.windowPeak) ? usage.windowPeak : usage.window;
|
|
22
|
+
const used = Math.max(0, usage.window, peak);
|
|
23
|
+
return `ctx ${formatTokens(used)}/${formatTokens(contextLimit)} (${Math.round(used / contextLimit * 100)}%)`;
|
|
7
24
|
}
|
|
8
25
|
export function formatModelThinking(model, thinking) {
|
|
9
26
|
const parsed = model ? splitKnownThinkingSuffix(model) : undefined;
|
|
@@ -75,19 +92,16 @@ export function formatToolCall(name, args, expanded = false) {
|
|
|
75
92
|
switch (name) {
|
|
76
93
|
case "bash": {
|
|
77
94
|
const command = typeof args.command === "string" ? args.command : "";
|
|
78
|
-
|
|
79
|
-
return `$ ${command.slice(0, maxLength)}${command.length > maxLength ? "..." : ""}`;
|
|
95
|
+
return `$ ${previewDisplayText(command, expanded ? 240 : 60)}`;
|
|
80
96
|
}
|
|
81
97
|
case "read":
|
|
82
98
|
case "write":
|
|
83
99
|
case "edit": {
|
|
84
100
|
const target = typeof args.path === "string" ? args.path : typeof args.file_path === "string" ? args.file_path : "";
|
|
85
|
-
return `${name} ${shortenPath(target)}`;
|
|
101
|
+
return `${name} ${sanitizeDisplayText(shortenPath(target))}`;
|
|
86
102
|
}
|
|
87
103
|
default: {
|
|
88
|
-
|
|
89
|
-
const maxLength = expanded ? 160 : 40;
|
|
90
|
-
return `${name} ${s.slice(0, maxLength)}${s.length > maxLength ? "..." : ""}`;
|
|
104
|
+
return `${name} ${previewDisplayText(JSON.stringify(args), expanded ? 160 : 40)}`;
|
|
91
105
|
}
|
|
92
106
|
}
|
|
93
107
|
}
|