@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,9 +2,12 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
+
import { resolveAuthorityDecision } from "../../policy/authority.js";
|
|
6
|
+
import { PROJECT_SUBAGENTS_RELATIVE_DIR } from "../../shared/artifacts.js";
|
|
7
|
+
import { getAgentDir } from "../../shared/utils.js";
|
|
5
8
|
const DEFAULT_WORKTREE_SETUP_HOOK_TIMEOUT_MS = 30000;
|
|
6
9
|
function runGit(cwd, args) {
|
|
7
|
-
const result = spawnSync("git", ["-C", cwd, ...args], { encoding: "utf-8" });
|
|
10
|
+
const result = spawnSync("git", ["-C", cwd, ...args], { encoding: "utf-8", windowsHide: true });
|
|
8
11
|
return {
|
|
9
12
|
stdout: result.stdout ?? "",
|
|
10
13
|
stderr: result.stderr ?? "",
|
|
@@ -23,7 +26,7 @@ function runGitChecked(cwd, args) {
|
|
|
23
26
|
function resolveRepoState(cwd) {
|
|
24
27
|
const cwdRelative = resolveRepoCwdRelative(cwd);
|
|
25
28
|
const toplevel = runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim();
|
|
26
|
-
const status = runGitChecked(toplevel, ["status", "--porcelain"]);
|
|
29
|
+
const status = runGitChecked(toplevel, ["status", "--porcelain", "--", `:!${PROJECT_SUBAGENTS_RELATIVE_DIR}`]);
|
|
27
30
|
if (status.trim().length > 0) {
|
|
28
31
|
throw new Error("worktree isolation requires a clean git working tree. Commit or stash changes first.");
|
|
29
32
|
}
|
|
@@ -32,10 +35,18 @@ function resolveRepoState(cwd) {
|
|
|
32
35
|
}
|
|
33
36
|
function normalizeComparableCwd(cwd) {
|
|
34
37
|
const resolved = path.resolve(cwd);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
let existing = resolved;
|
|
39
|
+
const missingSegments = [];
|
|
40
|
+
while (true) {
|
|
41
|
+
try {
|
|
42
|
+
return path.join(fs.realpathSync(existing), ...missingSegments.reverse());
|
|
43
|
+
} catch {
|
|
44
|
+
const parent = path.dirname(existing);
|
|
45
|
+
if (parent === existing)
|
|
46
|
+
return resolved;
|
|
47
|
+
missingSegments.push(path.basename(existing));
|
|
48
|
+
existing = parent;
|
|
49
|
+
}
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
export function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
|
|
@@ -69,6 +80,11 @@ function resolveWorktreeBaseDir(configuredBaseDir, repoRoot) {
|
|
|
69
80
|
throw new Error("worktree base directory cannot be empty");
|
|
70
81
|
const expanded = trimmed.startsWith("~/") ? path.join(os.homedir(), trimmed.slice(2)) : trimmed;
|
|
71
82
|
const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(repoRoot, expanded);
|
|
83
|
+
const extensionsDir = normalizeComparableCwd(path.join(getAgentDir(), "extensions"));
|
|
84
|
+
const relativeToExtensions = path.relative(extensionsDir, normalizeComparableCwd(resolved));
|
|
85
|
+
if (!relativeToExtensions || !relativeToExtensions.startsWith(`..${path.sep}`) && relativeToExtensions !== ".." && !path.isAbsolute(relativeToExtensions)) {
|
|
86
|
+
throw new Error(`worktree base directory cannot be inside DM extensions directory: ${extensionsDir}. Choose a directory outside it.`);
|
|
87
|
+
}
|
|
72
88
|
try {
|
|
73
89
|
fs.mkdirSync(resolved, { recursive: true });
|
|
74
90
|
} catch (error) {
|
|
@@ -181,6 +197,7 @@ function parseWorktreeSetupHookOutput(rawStdout) {
|
|
|
181
197
|
}
|
|
182
198
|
function runWorktreeSetupHook(hook, input) {
|
|
183
199
|
const result = spawnSync(hook.hookPath, [], {
|
|
200
|
+
windowsHide: true,
|
|
184
201
|
cwd: input.worktreePath,
|
|
185
202
|
encoding: "utf-8",
|
|
186
203
|
input: JSON.stringify(input),
|
|
@@ -297,7 +314,7 @@ function removeSyntheticPathsBeforeDiff(worktree) {
|
|
|
297
314
|
removeSyntheticPath(worktree, syntheticPath);
|
|
298
315
|
}
|
|
299
316
|
}
|
|
300
|
-
function emptyDiff(index, agent, branch, patchPath) {
|
|
317
|
+
function emptyDiff(index, agent, branch, patchPath, error) {
|
|
301
318
|
return {
|
|
302
319
|
index,
|
|
303
320
|
agent,
|
|
@@ -306,7 +323,8 @@ function emptyDiff(index, agent, branch, patchPath) {
|
|
|
306
323
|
filesChanged: 0,
|
|
307
324
|
insertions: 0,
|
|
308
325
|
deletions: 0,
|
|
309
|
-
patchPath
|
|
326
|
+
patchPath,
|
|
327
|
+
...error ? { error } : {}
|
|
310
328
|
};
|
|
311
329
|
}
|
|
312
330
|
function parseNumstat(numstat) {
|
|
@@ -354,13 +372,113 @@ function writeEmptyPatch(patchPath) {
|
|
|
354
372
|
fs.writeFileSync(patchPath, "", "utf-8");
|
|
355
373
|
} catch {}
|
|
356
374
|
}
|
|
357
|
-
function
|
|
375
|
+
function handoffRecordsPatch(manifestPath, patchPath) {
|
|
376
|
+
if (!manifestPath || !fs.existsSync(manifestPath))
|
|
377
|
+
return false;
|
|
358
378
|
try {
|
|
359
|
-
|
|
360
|
-
|
|
379
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
380
|
+
if (manifest.version !== 1 || !Array.isArray(manifest.groups))
|
|
381
|
+
return false;
|
|
382
|
+
const resolvedPatchPath = path.resolve(patchPath);
|
|
383
|
+
return manifest.groups.some((group) => Array.isArray(group.children) && group.children.some((child) => child.patch?.error === undefined && typeof child.patch?.path === "string" && path.resolve(child.patch.path) === resolvedPatchPath));
|
|
384
|
+
} catch {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function cleanupSingleWorktree(setup, worktree, intent) {
|
|
389
|
+
const errors = [];
|
|
390
|
+
let worktreeRemoved = false;
|
|
391
|
+
let branchRemoved = false;
|
|
392
|
+
if (intent.kind === "preserve" && intent.cleanupBlocker) {
|
|
393
|
+
return {
|
|
394
|
+
index: worktree.index,
|
|
395
|
+
path: worktree.path,
|
|
396
|
+
branch: worktree.branch,
|
|
397
|
+
worktreeRemoved: false,
|
|
398
|
+
branchRemoved: false,
|
|
399
|
+
preserved: true,
|
|
400
|
+
reason: intent.cleanupBlocker
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (intent.kind !== "setup-rollback") {
|
|
404
|
+
try {
|
|
405
|
+
removeSyntheticPathsBeforeDiff(worktree);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
errors.push(`synthetic path cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
408
|
+
}
|
|
409
|
+
const status = runGit(worktree.path, ["status", "--porcelain"]);
|
|
410
|
+
const baseDiff = runGit(worktree.path, ["diff", "--quiet", setup.baseCommit, "--"]);
|
|
411
|
+
if (status.status !== 0 || baseDiff.status !== 0 && baseDiff.status !== 1) {
|
|
412
|
+
const reason = status.status !== 0 ? status.stderr.trim() || status.stdout.trim() || "git status failed" : baseDiff.stderr.trim() || baseDiff.stdout.trim() || "git diff check failed";
|
|
413
|
+
return {
|
|
414
|
+
index: worktree.index,
|
|
415
|
+
path: worktree.path,
|
|
416
|
+
branch: worktree.branch,
|
|
417
|
+
worktreeRemoved: false,
|
|
418
|
+
branchRemoved: false,
|
|
419
|
+
preserved: true,
|
|
420
|
+
reason: "cleanup safety check failed",
|
|
421
|
+
errors: [...errors, `cleanup refused: ${reason}`]
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
const hasWork = status.stdout.trim().length > 0 || baseDiff.status === 1;
|
|
425
|
+
if (hasWork && intent.kind === "preserve") {
|
|
426
|
+
const captured = (intent.capturedDiffs ?? setup.capturedDiffs)?.find((diff) => diff.index === worktree.index);
|
|
427
|
+
const patchCaptured = captured !== undefined && captured.error === undefined && fs.existsSync(captured.patchPath) && fs.statSync(captured.patchPath).size > 0 && handoffRecordsPatch(intent.handoffManifestPath, captured.patchPath);
|
|
428
|
+
if (!patchCaptured) {
|
|
429
|
+
const reason = "worktree contains changes that are not represented by a captured handoff patch";
|
|
430
|
+
return {
|
|
431
|
+
index: worktree.index,
|
|
432
|
+
path: worktree.path,
|
|
433
|
+
branch: worktree.branch,
|
|
434
|
+
worktreeRemoved: false,
|
|
435
|
+
branchRemoved: false,
|
|
436
|
+
preserved: true,
|
|
437
|
+
reason,
|
|
438
|
+
errors: [...errors, `cleanup refused: ${reason}; preserved ${worktree.path}`]
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (hasWork && intent.kind === "discard") {
|
|
443
|
+
const decision = resolveAuthorityDecision({ action: "discardWorktree", policy: intent.authorization.policy });
|
|
444
|
+
const authorized = decision === "auto" || decision === "confirm" && intent.authorization.kind === "confirmed";
|
|
445
|
+
if (!authorized) {
|
|
446
|
+
const reason = decision === "forbid" ? "authority policy forbids worktree discard" : "worktree discard requires explicit user confirmation";
|
|
447
|
+
return {
|
|
448
|
+
index: worktree.index,
|
|
449
|
+
path: worktree.path,
|
|
450
|
+
branch: worktree.branch,
|
|
451
|
+
worktreeRemoved: false,
|
|
452
|
+
branchRemoved: false,
|
|
453
|
+
preserved: true,
|
|
454
|
+
reason,
|
|
455
|
+
errors: [...errors, `cleanup refused: ${reason}; preserved ${worktree.path}`]
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
361
460
|
try {
|
|
362
|
-
runGitChecked(
|
|
363
|
-
|
|
461
|
+
runGitChecked(setup.cwd, ["worktree", "remove", "--force", worktree.path]);
|
|
462
|
+
worktreeRemoved = true;
|
|
463
|
+
} catch (error) {
|
|
464
|
+
errors.push(`worktree removal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
465
|
+
}
|
|
466
|
+
if (worktreeRemoved) {
|
|
467
|
+
try {
|
|
468
|
+
runGitChecked(setup.cwd, ["branch", "-D", worktree.branch]);
|
|
469
|
+
branchRemoved = true;
|
|
470
|
+
} catch (error) {
|
|
471
|
+
errors.push(`branch removal failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return {
|
|
475
|
+
index: worktree.index,
|
|
476
|
+
path: worktree.path,
|
|
477
|
+
branch: worktree.branch,
|
|
478
|
+
worktreeRemoved,
|
|
479
|
+
branchRemoved,
|
|
480
|
+
...errors.length ? { errors } : {}
|
|
481
|
+
};
|
|
364
482
|
}
|
|
365
483
|
function hasWorktreeChanges(diff) {
|
|
366
484
|
return diff.filesChanged > 0 || diff.insertions > 0 || diff.deletions > 0 || diff.diffStat.trim().length > 0;
|
|
@@ -369,6 +487,22 @@ export function createWorktrees(cwd, runId, count, options) {
|
|
|
369
487
|
const repo = resolveRepoState(cwd);
|
|
370
488
|
const setupHook = resolveWorktreeSetupHook(repo.toplevel, options?.setupHook);
|
|
371
489
|
const baseDir = resolveWorktreeBaseDir(options?.baseDir, repo.toplevel);
|
|
490
|
+
const plannedSetup = {
|
|
491
|
+
cwd: repo.toplevel,
|
|
492
|
+
baseCommit: repo.baseCommit,
|
|
493
|
+
worktrees: Array.from({ length: count }, (_, index) => {
|
|
494
|
+
const worktreePath = buildWorktreePath(baseDir, runId, index);
|
|
495
|
+
return {
|
|
496
|
+
path: worktreePath,
|
|
497
|
+
agentCwd: repo.cwdRelative ? path.join(worktreePath, repo.cwdRelative) : worktreePath,
|
|
498
|
+
branch: buildWorktreeBranch(runId, index),
|
|
499
|
+
index,
|
|
500
|
+
nodeModulesLinked: false,
|
|
501
|
+
syntheticPaths: []
|
|
502
|
+
};
|
|
503
|
+
})
|
|
504
|
+
};
|
|
505
|
+
options?.beforeCreate?.(plannedSetup);
|
|
372
506
|
const worktrees = [];
|
|
373
507
|
try {
|
|
374
508
|
for (let index = 0;index < count; index++) {
|
|
@@ -379,7 +513,7 @@ export function createWorktrees(cwd, runId, count, options) {
|
|
|
379
513
|
cwd: repo.toplevel,
|
|
380
514
|
worktrees,
|
|
381
515
|
baseCommit: repo.baseCommit
|
|
382
|
-
});
|
|
516
|
+
}, { kind: "setup-rollback" });
|
|
383
517
|
throw error;
|
|
384
518
|
}
|
|
385
519
|
return {
|
|
@@ -401,20 +535,35 @@ export function diffWorktrees(setup, agents, diffsDir) {
|
|
|
401
535
|
const patchPath = path.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
|
|
402
536
|
try {
|
|
403
537
|
diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
|
|
404
|
-
} catch {
|
|
538
|
+
} catch (error) {
|
|
405
539
|
writeEmptyPatch(patchPath);
|
|
406
|
-
diffs.push(emptyDiff(index, agent, worktree.branch, patchPath));
|
|
540
|
+
diffs.push(emptyDiff(index, agent, worktree.branch, patchPath, error instanceof Error ? error.message : String(error)));
|
|
407
541
|
}
|
|
408
542
|
}
|
|
543
|
+
setup.capturedDiffs = diffs;
|
|
409
544
|
return diffs;
|
|
410
545
|
}
|
|
411
|
-
export function cleanupWorktrees(setup) {
|
|
546
|
+
export function cleanupWorktrees(setup, intent = { kind: "preserve", ...setup.capturedDiffs ? { capturedDiffs: setup.capturedDiffs } : {} }) {
|
|
547
|
+
const tasks = [];
|
|
412
548
|
for (let index = setup.worktrees.length - 1;index >= 0; index--) {
|
|
413
|
-
cleanupSingleWorktree(setup
|
|
549
|
+
tasks.push(cleanupSingleWorktree(setup, setup.worktrees[index], intent));
|
|
414
550
|
}
|
|
551
|
+
tasks.sort((left, right) => left.index - right.index);
|
|
552
|
+
const errors = [];
|
|
553
|
+
let pruned = false;
|
|
415
554
|
try {
|
|
416
555
|
runGitChecked(setup.cwd, ["worktree", "prune"]);
|
|
417
|
-
|
|
556
|
+
pruned = true;
|
|
557
|
+
} catch (error) {
|
|
558
|
+
errors.push(`worktree prune failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
559
|
+
}
|
|
560
|
+
const state = tasks.every((task) => task.worktreeRemoved && task.branchRemoved) && pruned ? "complete" : "partial";
|
|
561
|
+
return {
|
|
562
|
+
state,
|
|
563
|
+
tasks,
|
|
564
|
+
pruned,
|
|
565
|
+
...errors.length ? { errors } : {}
|
|
566
|
+
};
|
|
418
567
|
}
|
|
419
568
|
export function formatWorktreeDiffSummary(diffs) {
|
|
420
569
|
const changed = diffs.filter(hasWorktreeChanges);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS, runFileSystemOperationWithRetry, waitForFileSystemRetry } from "./file-system-retry.js";
|
|
3
|
+
export function ensureAccessibleDir(dirPath, options = {}) {
|
|
4
|
+
const fsImpl = options.fs ?? fs;
|
|
5
|
+
const pid = options.pid ?? process.pid;
|
|
6
|
+
const retryDirectoryErrors = options.retryDirectoryErrors ?? process.platform === "win32";
|
|
7
|
+
const retryDelaysMs = retryDirectoryErrors ? options.retryDelaysMs ?? DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS : [];
|
|
8
|
+
const wait = options.wait ?? waitForFileSystemRetry;
|
|
9
|
+
const mkdirWithRetry = (target) => {
|
|
10
|
+
runFileSystemOperationWithRetry(() => {
|
|
11
|
+
fsImpl.mkdirSync(target, { recursive: true });
|
|
12
|
+
}, { retryDelaysMs, wait });
|
|
13
|
+
};
|
|
14
|
+
const accessWithRetry = (target) => {
|
|
15
|
+
runFileSystemOperationWithRetry(() => {
|
|
16
|
+
fsImpl.accessSync(target, fs.constants.R_OK | fs.constants.W_OK);
|
|
17
|
+
}, { retryDelaysMs, wait });
|
|
18
|
+
};
|
|
19
|
+
const fallbackPath = () => {
|
|
20
|
+
const fallback = `${dirPath}-${pid}`;
|
|
21
|
+
mkdirWithRetry(fallback);
|
|
22
|
+
accessWithRetry(fallback);
|
|
23
|
+
return fallback;
|
|
24
|
+
};
|
|
25
|
+
try {
|
|
26
|
+
mkdirWithRetry(dirPath);
|
|
27
|
+
accessWithRetry(dirPath);
|
|
28
|
+
return dirPath;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
const code = error?.code;
|
|
31
|
+
if (code !== "EPERM" && code !== "EACCES")
|
|
32
|
+
throw error;
|
|
33
|
+
return fallbackPath();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,11 +1,133 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { TEMP_ARTIFACTS_DIR } from "./types.js";
|
|
3
|
+
import { CHAIN_RUNS_DIR, TEMP_ARTIFACTS_DIR } from "./types.js";
|
|
4
4
|
import { getAgentDir } from "./utils.js";
|
|
5
5
|
const CLEANUP_MARKER_FILE = ".last-cleanup";
|
|
6
|
-
const
|
|
6
|
+
export const PROJECT_SUBAGENTS_RELATIVE_DIR = ".dm/subagents";
|
|
7
|
+
const PROJECT_ARTIFACT_PATHS = [
|
|
8
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/output.md`,
|
|
9
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_input.md`,
|
|
10
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_output.md`,
|
|
11
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker.jsonl`,
|
|
12
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_transcript.jsonl`,
|
|
13
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/run_worker_meta.json`,
|
|
14
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/progress/run/progress.md`,
|
|
15
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/outputs/output.md`,
|
|
16
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/artifacts/outputs/run/output.md`,
|
|
17
|
+
`${PROJECT_SUBAGENTS_RELATIVE_DIR}/chain-runs/run.json`
|
|
18
|
+
];
|
|
19
|
+
function globMatchesPath(pattern, filePath) {
|
|
20
|
+
let expression = "^";
|
|
21
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
22
|
+
const character = pattern[index];
|
|
23
|
+
if (character === undefined)
|
|
24
|
+
break;
|
|
25
|
+
if (character === "*" && pattern[index + 1] === "*") {
|
|
26
|
+
index += 1;
|
|
27
|
+
if (pattern[index + 1] === "/") {
|
|
28
|
+
index += 1;
|
|
29
|
+
expression += "(?:.*/)?";
|
|
30
|
+
} else {
|
|
31
|
+
expression += ".*";
|
|
32
|
+
}
|
|
33
|
+
} else if (character === "*") {
|
|
34
|
+
expression += "[^/]*";
|
|
35
|
+
} else if (character === "?") {
|
|
36
|
+
expression += "[^/]";
|
|
37
|
+
} else if (character === "[") {
|
|
38
|
+
const end = pattern.indexOf("]", index + 1);
|
|
39
|
+
if (end === -1)
|
|
40
|
+
expression += "\\[";
|
|
41
|
+
else {
|
|
42
|
+
expression += pattern.slice(index, end + 1);
|
|
43
|
+
index = end;
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
expression += character.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return new RegExp(`${expression}$`).test(filePath);
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function normalizePattern(pattern) {
|
|
56
|
+
return pattern.replace(/^\.\//, "").replace(/^\//, "").replace(/\/+$/, "");
|
|
57
|
+
}
|
|
58
|
+
function patternMatchesArtifactPath(pattern, artifactPath) {
|
|
59
|
+
const normalized = normalizePattern(pattern);
|
|
60
|
+
return normalized === PROJECT_SUBAGENTS_RELATIVE_DIR || normalized === "*" || artifactPath.startsWith(`${normalized}/`) || globMatchesPath(normalized, artifactPath);
|
|
61
|
+
}
|
|
62
|
+
function ignoreFileExcludesProjectArtifacts(filePath) {
|
|
63
|
+
if (!fs.existsSync(filePath))
|
|
64
|
+
return false;
|
|
65
|
+
try {
|
|
66
|
+
const excluded = new Set;
|
|
67
|
+
for (const rawLine of fs.readFileSync(filePath, "utf-8").split(/\r?\n/)) {
|
|
68
|
+
const line = rawLine.trim();
|
|
69
|
+
if (!line || line.startsWith("#"))
|
|
70
|
+
continue;
|
|
71
|
+
const negated = line.startsWith("!");
|
|
72
|
+
const pattern = negated ? line.slice(1) : line;
|
|
73
|
+
for (const artifactPath of PROJECT_ARTIFACT_PATHS) {
|
|
74
|
+
if (!patternMatchesArtifactPath(pattern, artifactPath))
|
|
75
|
+
continue;
|
|
76
|
+
if (negated)
|
|
77
|
+
excluded.delete(artifactPath);
|
|
78
|
+
else
|
|
79
|
+
excluded.add(artifactPath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return excluded.size === PROJECT_ARTIFACT_PATHS.length;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function filesIncludeProjectArtifacts(files) {
|
|
88
|
+
if (!Array.isArray(files))
|
|
89
|
+
return;
|
|
90
|
+
const included = new Set;
|
|
91
|
+
for (const entry of files) {
|
|
92
|
+
if (typeof entry !== "string")
|
|
93
|
+
continue;
|
|
94
|
+
const negated = entry.startsWith("!");
|
|
95
|
+
const pattern = negated ? entry.slice(1) : entry;
|
|
96
|
+
for (const artifactPath of PROJECT_ARTIFACT_PATHS) {
|
|
97
|
+
if (!patternMatchesArtifactPath(pattern, artifactPath))
|
|
98
|
+
continue;
|
|
99
|
+
if (negated)
|
|
100
|
+
included.delete(artifactPath);
|
|
101
|
+
else
|
|
102
|
+
included.add(artifactPath);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return included.size > 0;
|
|
106
|
+
}
|
|
107
|
+
export function getProjectArtifactPackagingWarning(cwd) {
|
|
108
|
+
const packagePath = path.join(cwd, "package.json");
|
|
109
|
+
if (!fs.existsSync(packagePath))
|
|
110
|
+
return;
|
|
111
|
+
let packageJson;
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
114
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
115
|
+
return;
|
|
116
|
+
packageJson = parsed;
|
|
117
|
+
} catch {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const filesIncludeArtifacts = filesIncludeProjectArtifacts(packageJson.files);
|
|
121
|
+
if (filesIncludeArtifacts === false)
|
|
122
|
+
return;
|
|
123
|
+
const npmIgnorePath = path.join(cwd, ".npmignore");
|
|
124
|
+
const ignorePath = fs.existsSync(npmIgnorePath) ? npmIgnorePath : path.join(cwd, ".gitignore");
|
|
125
|
+
if (filesIncludeArtifacts === undefined && ignoreFileExcludesProjectArtifacts(ignorePath))
|
|
126
|
+
return;
|
|
127
|
+
return "Project-scoped subagent artifacts can be included when this package is published. Add '.dm/subagents/' to .npmignore, restrict package.json files, or set artifactDir to 'session' or 'temp'.";
|
|
128
|
+
}
|
|
7
129
|
export function getProjectSubagentsDir(cwd) {
|
|
8
|
-
return path.join(cwd,
|
|
130
|
+
return path.join(cwd, PROJECT_SUBAGENTS_RELATIVE_DIR);
|
|
9
131
|
}
|
|
10
132
|
export function getProjectArtifactsDir(cwd) {
|
|
11
133
|
return path.join(getProjectSubagentsDir(cwd), "artifacts");
|
|
@@ -13,14 +135,38 @@ export function getProjectArtifactsDir(cwd) {
|
|
|
13
135
|
export function getProjectChainRunsDir(cwd) {
|
|
14
136
|
return path.join(getProjectSubagentsDir(cwd), "chain-runs");
|
|
15
137
|
}
|
|
16
|
-
export function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
138
|
+
export function getChainRunsDir(projectCwd, dirPreference = "session") {
|
|
139
|
+
switch (dirPreference) {
|
|
140
|
+
case "project":
|
|
141
|
+
return getProjectChainRunsDir(projectCwd);
|
|
142
|
+
case "session":
|
|
143
|
+
case "temp":
|
|
144
|
+
return CHAIN_RUNS_DIR;
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Unsupported artifactDir ${JSON.stringify(dirPreference)}; expected "project", "session", or "temp".`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function getArtifactsDir(sessionFile, projectCwd, dirPreference = "session") {
|
|
150
|
+
switch (dirPreference) {
|
|
151
|
+
case "session":
|
|
152
|
+
if (sessionFile) {
|
|
153
|
+
const sessionDir = path.dirname(sessionFile);
|
|
154
|
+
return path.join(sessionDir, "subagent-artifacts");
|
|
155
|
+
}
|
|
156
|
+
return TEMP_ARTIFACTS_DIR;
|
|
157
|
+
case "temp":
|
|
158
|
+
return TEMP_ARTIFACTS_DIR;
|
|
159
|
+
case "project":
|
|
160
|
+
if (projectCwd)
|
|
161
|
+
return getProjectArtifactsDir(projectCwd);
|
|
162
|
+
if (sessionFile) {
|
|
163
|
+
const sessionDir = path.dirname(sessionFile);
|
|
164
|
+
return path.join(sessionDir, "subagent-artifacts");
|
|
165
|
+
}
|
|
166
|
+
return TEMP_ARTIFACTS_DIR;
|
|
167
|
+
default:
|
|
168
|
+
throw new Error(`Unsupported artifactDir ${JSON.stringify(dirPreference)}; expected "project", "session", or "temp".`);
|
|
22
169
|
}
|
|
23
|
-
return TEMP_ARTIFACTS_DIR;
|
|
24
170
|
}
|
|
25
171
|
export function getArtifactPaths(artifactsDir, runId, agent, index) {
|
|
26
172
|
const suffix = index !== undefined ? `_${index}` : "";
|
|
@@ -38,9 +184,22 @@ export function ensureArtifactsDir(dir) {
|
|
|
38
184
|
fs.mkdirSync(dir, { recursive: true });
|
|
39
185
|
}
|
|
40
186
|
export function writeArtifact(filePath, content) {
|
|
187
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
41
188
|
fs.writeFileSync(filePath, content, "utf-8");
|
|
42
189
|
}
|
|
190
|
+
export function formatOutputArtifactContent(input) {
|
|
191
|
+
if (input.output.trim() || !input.error)
|
|
192
|
+
return input.output;
|
|
193
|
+
const lines = ["Subagent run failed before producing output.", "", "Error:", input.error];
|
|
194
|
+
if (input.transcriptPath)
|
|
195
|
+
lines.push("", `Transcript: ${input.transcriptPath}`);
|
|
196
|
+
if (input.metadataPath)
|
|
197
|
+
lines.push(`Metadata: ${input.metadataPath}`);
|
|
198
|
+
return lines.join(`
|
|
199
|
+
`);
|
|
200
|
+
}
|
|
43
201
|
export function writeMetadata(filePath, metadata) {
|
|
202
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
44
203
|
fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
45
204
|
}
|
|
46
205
|
export function appendJsonl(filePath, line) {
|
|
@@ -48,7 +207,7 @@ export function appendJsonl(filePath, line) {
|
|
|
48
207
|
`);
|
|
49
208
|
}
|
|
50
209
|
export function cleanupOldArtifacts(dir, maxAgeDays) {
|
|
51
|
-
if (!fs.existsSync(dir))
|
|
210
|
+
if (maxAgeDays <= 0 || !fs.existsSync(dir))
|
|
52
211
|
return;
|
|
53
212
|
const markerPath = path.join(dir, CLEANUP_MARKER_FILE);
|
|
54
213
|
const now = Date.now();
|
|
@@ -1,55 +1,53 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const WAIT_BUFFER = typeof SharedArrayBuffer !== "undefined" ? new SharedArrayBuffer(4) : undefined;
|
|
6
|
-
const WAIT_VIEW = WAIT_BUFFER ? new Int32Array(WAIT_BUFFER) : undefined;
|
|
7
|
-
function waitSync(delayMs) {
|
|
8
|
-
if (delayMs <= 0)
|
|
9
|
-
return;
|
|
10
|
-
if (WAIT_VIEW) {
|
|
11
|
-
try {
|
|
12
|
-
Atomics.wait(WAIT_VIEW, 0, 0, delayMs);
|
|
13
|
-
return;
|
|
14
|
-
} catch {}
|
|
15
|
-
}
|
|
16
|
-
const end = Date.now() + delayMs;
|
|
17
|
-
while (Date.now() < end) {}
|
|
18
|
-
}
|
|
19
|
-
function isRetryableRenameError(error) {
|
|
20
|
-
const code = error?.code;
|
|
21
|
-
return typeof code === "string" && RETRYABLE_RENAME_ERROR_CODES.has(code);
|
|
22
|
-
}
|
|
4
|
+
import { DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS, runFileSystemOperationWithRetry, waitForFileSystemRetry } from "./file-system-retry.js";
|
|
5
|
+
const MAX_PATH_COMPONENT_BYTES = 255;
|
|
23
6
|
function renameWithRetry(fsImpl, sourcePath, targetPath, retryDelaysMs, wait) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
7
|
+
runFileSystemOperationWithRetry(() => {
|
|
8
|
+
fsImpl.renameSync(sourcePath, targetPath);
|
|
9
|
+
}, { retryDelaysMs, wait });
|
|
10
|
+
}
|
|
11
|
+
function tempBaseName(filePath, pid, nowMs, randomId) {
|
|
12
|
+
const suffix = `.${pid}.${nowMs}.${randomId}.tmp`;
|
|
13
|
+
const preferred = `.${path.basename(filePath)}${suffix}`;
|
|
14
|
+
if (Buffer.byteLength(preferred, "utf-8") <= MAX_PATH_COMPONENT_BYTES)
|
|
15
|
+
return preferred;
|
|
16
|
+
return `.${createHash("sha256").update(path.basename(filePath)).digest("hex")}${suffix}`;
|
|
35
17
|
}
|
|
36
18
|
export function createAtomicJsonWriter(options = {}) {
|
|
37
19
|
const fsImpl = options.fs ?? fs;
|
|
38
20
|
const now = options.now ?? Date.now;
|
|
39
21
|
const pid = options.pid ?? process.pid;
|
|
40
22
|
const random = options.random ?? Math.random;
|
|
23
|
+
const mode = options.mode;
|
|
41
24
|
const retryRenameErrors = options.retryRenameErrors ?? process.platform === "win32";
|
|
42
|
-
const
|
|
43
|
-
const
|
|
25
|
+
const retryDirectoryErrors = options.retryDirectoryErrors ?? retryRenameErrors;
|
|
26
|
+
const retryDelaysMs = options.retryDelaysMs ?? DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS;
|
|
27
|
+
const renameRetryDelaysMs = retryRenameErrors ? retryDelaysMs : [];
|
|
28
|
+
const directoryRetryDelaysMs = retryDirectoryErrors ? retryDelaysMs : [];
|
|
29
|
+
const wait = options.wait ?? waitForFileSystemRetry;
|
|
44
30
|
return (filePath, payload) => {
|
|
45
|
-
|
|
46
|
-
|
|
31
|
+
runFileSystemOperationWithRetry(() => {
|
|
32
|
+
fsImpl.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
33
|
+
}, { retryDelaysMs: directoryRetryDelaysMs, wait });
|
|
34
|
+
const tempPath = path.join(path.dirname(filePath), tempBaseName(filePath, pid, now(), random().toString(36).slice(2)));
|
|
35
|
+
let writeError;
|
|
47
36
|
try {
|
|
48
|
-
fsImpl.writeFileSync(tempPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
49
|
-
renameWithRetry(fsImpl, tempPath, filePath,
|
|
37
|
+
fsImpl.writeFileSync(tempPath, JSON.stringify(payload, null, 2), mode === undefined ? "utf-8" : { encoding: "utf-8", mode });
|
|
38
|
+
renameWithRetry(fsImpl, tempPath, filePath, renameRetryDelaysMs, wait);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
writeError = error;
|
|
41
|
+
throw error;
|
|
50
42
|
} finally {
|
|
51
|
-
|
|
43
|
+
try {
|
|
44
|
+
fsImpl.rmSync(tempPath, { force: true });
|
|
45
|
+
} catch (cleanupError) {
|
|
46
|
+
if (writeError === undefined)
|
|
47
|
+
throw cleanupError;
|
|
48
|
+
}
|
|
52
49
|
}
|
|
53
50
|
};
|
|
54
51
|
}
|
|
55
52
|
export const writeAtomicJson = createAtomicJsonWriter();
|
|
53
|
+
export const writePrivateAtomicJson = createAtomicJsonWriter({ mode: 384 });
|