@duckmind/dm-windows-x64 0.60.6 → 0.60.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.
Files changed (197) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +70 -123
  3. package/extensions/dm-9router-ext/src/index.js +410 -5
  4. package/extensions/dm-caveman/extensions/caveman.js +283 -12
  5. package/extensions/dm-cliproxy/index.js +182 -2
  6. package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
  7. package/extensions/dm-cliproxy/src/apply.js +228 -1
  8. package/extensions/dm-cliproxy/src/cache.js +42 -1
  9. package/extensions/dm-cliproxy/src/commands.js +50 -2
  10. package/extensions/dm-cliproxy/src/compat.js +81 -1
  11. package/extensions/dm-cliproxy/src/config.js +192 -2
  12. package/extensions/dm-cliproxy/src/conflicts.js +46 -1
  13. package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
  14. package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
  15. package/extensions/dm-cliproxy/src/log.js +23 -1
  16. package/extensions/dm-cliproxy/src/status-quota.js +77 -1
  17. package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
  18. package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
  19. package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
  20. package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
  21. package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
  22. package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
  23. package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
  24. package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
  25. package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
  26. package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
  27. package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
  28. package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
  29. package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
  30. package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
  31. package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
  32. package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
  33. package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
  34. package/extensions/dm-context/src/context.js +144 -1
  35. package/extensions/dm-context/src/index.js +339 -7
  36. package/extensions/dm-context/src/utils.js +9 -1
  37. package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
  38. package/extensions/dm-cua/index.js +75 -6
  39. package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
  40. package/extensions/dm-cua/src/browser-install.mjs +331 -2
  41. package/extensions/dm-fff/src/index.js +688 -12
  42. package/extensions/dm-fff/src/query.js +60 -1
  43. package/extensions/dm-goal/src/goal.js +894 -23
  44. package/extensions/dm-image2/index.js +103 -9
  45. package/extensions/dm-image2/src/image-lib.mjs +1275 -8
  46. package/extensions/dm-subagents/install.mjs +62 -8
  47. package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
  48. package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
  49. package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
  50. package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
  51. package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
  52. package/extensions/dm-subagents/src/agents/agents.js +1139 -11
  53. package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
  54. package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
  55. package/extensions/dm-subagents/src/agents/identity.js +29 -1
  56. package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
  57. package/extensions/dm-subagents/src/agents/skills.js +614 -6
  58. package/extensions/dm-subagents/src/extension/config.js +35 -2
  59. package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
  60. package/extensions/dm-subagents/src/extension/doctor.js +172 -15
  61. package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
  62. package/extensions/dm-subagents/src/extension/index.js +521 -359
  63. package/extensions/dm-subagents/src/extension/rpc.js +266 -7
  64. package/extensions/dm-subagents/src/extension/schemas.js +275 -1
  65. package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
  66. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
  67. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
  68. package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
  69. package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
  70. package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
  71. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
  72. package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
  73. package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
  74. package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
  75. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
  76. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
  77. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
  78. package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
  79. package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
  80. package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
  81. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
  82. package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
  83. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
  84. package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
  85. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
  86. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
  87. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
  88. package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
  89. package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
  90. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
  91. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
  92. package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
  93. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
  94. package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
  95. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
  96. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
  97. package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
  98. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
  99. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
  100. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
  101. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
  102. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
  103. package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
  104. package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
  105. package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
  106. package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
  107. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
  108. package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
  109. package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
  110. package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
  111. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
  112. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
  113. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
  114. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
  115. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
  116. package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
  117. package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
  118. package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
  119. package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
  120. package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
  121. package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
  122. package/extensions/dm-subagents/src/shared/formatters.js +98 -7
  123. package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
  124. package/extensions/dm-subagents/src/shared/model-info.js +62 -1
  125. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
  126. package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
  127. package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
  128. package/extensions/dm-subagents/src/shared/settings.js +198 -11
  129. package/extensions/dm-subagents/src/shared/status-format.js +53 -1
  130. package/extensions/dm-subagents/src/shared/types.js +184 -6
  131. package/extensions/dm-subagents/src/shared/utils.js +462 -2
  132. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
  133. package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
  134. package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
  135. package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
  136. package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
  137. package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
  138. package/extensions/dm-subagents/src/tui/render.js +1542 -4
  139. package/extensions/dm-usage/index.js +1294 -9
  140. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
  141. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
  142. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
  143. package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
  144. package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
  145. package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
  146. package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
  147. package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
  148. package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
  149. package/extensions/greedysearch-dm/bin/search.mjs +620 -540
  150. package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
  151. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
  152. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
  153. package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
  154. package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
  155. package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
  156. package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
  157. package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
  158. package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
  159. package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
  160. package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
  161. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
  162. package/extensions/greedysearch-dm/index.js +123 -23
  163. package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
  164. package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
  165. package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
  166. package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
  167. package/extensions/greedysearch-dm/src/github.mjs +222 -7
  168. package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
  169. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
  170. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
  171. package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
  172. package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
  173. package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
  174. package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
  175. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
  176. package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
  177. package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
  178. package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
  179. package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
  180. package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
  181. package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
  182. package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
  183. package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
  184. package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
  185. package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
  186. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
  187. package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
  188. package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
  189. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
  190. package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
  191. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
  192. package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
  193. package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
  194. package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
  195. package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
  196. package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
  197. package/package.json +1 -1
@@ -1,3 +1,435 @@
1
- import{spawnSync as T}from"node:child_process";import*as F from"node:fs";import*as W from"node:os";import*as Z from"node:path";var M=30000;function O(j,Q){let J=T("git",["-C",j,...Q],{encoding:"utf-8"});return{stdout:J.stdout??"",stderr:J.stderr??"",status:J.status}}function A(j,Q){let J=O(j,Q);if(J.status!==0){let X=`git -C ${j} ${Q.join(" ")}`,V=J.stderr.trim()||J.stdout.trim()||`${X} failed`;throw Error(V)}return J.stdout}function G(j){let Q=S(j),J=A(j,["rev-parse","--show-toplevel"]).trim();if(A(J,["status","--porcelain"]).trim().length>0)throw Error("worktree isolation requires a clean git working tree. Commit or stash changes first.");let V=A(J,["rev-parse","HEAD"]).trim();return{toplevel:J,cwdRelative:Q,baseCommit:V}}function _(j){let Q=Z.resolve(j);try{return F.realpathSync(Q)}catch{return Q}}function i(j,Q){let J=_(Q);for(let X=0;X<j.length;X++){let V=j[X];if(!V.cwd)continue;let Y=Z.isAbsolute(V.cwd)?V.cwd:Z.resolve(Q,V.cwd);if(_(Y)===J)continue;return{index:X,agent:V.agent,cwd:V.cwd}}return}function d(j,Q){return`worktree isolation uses the shared cwd (${Q}); task ${j.index+1} (${j.agent}) sets cwd to ${j.cwd}. Remove task-level cwd overrides or disable worktree.`}function R(j){return j.replace(/[^\w.-]/g,"_")}function I(j,Q){return`dm-parallel-${j}-${Q}`}function z(j,Q){let J=j??process.env.DM_SUBAGENTS_WORKTREE_DIR;if(J===void 0)return W.tmpdir();let X=J.trim();if(!X)throw Error("worktree base directory cannot be empty");let V=X.startsWith("~/")?Z.join(W.homedir(),X.slice(2)):X,Y=Z.isAbsolute(V)?V:Z.resolve(Q,V);try{F.mkdirSync(Y,{recursive:!0})}catch($){let q=$ instanceof Error?$.message:String($);throw Error(`failed to create worktree base directory ${Y}: ${q}`)}return Y}function H(j,Q,J){return Z.join(j,`dm-worktree-${Q}-${J}`)}function S(j){let Q=O(j,["rev-parse","--is-inside-work-tree"]);if(Q.status!==0||Q.stdout.trim()!=="true")throw Error("worktree isolation requires a git repository");let J=A(j,["rev-parse","--show-prefix"]).trim(),X=J?Z.normalize(J.replace(/[\\/]+$/,"")):"";return X==="."?"":X}function a(j,Q,J,X){let V=S(j),Y=A(j,["rev-parse","--show-toplevel"]).trim(),$=H(z(X,Y),Q,J);return V?Z.join($,V):$}function D(j,Q){let J=Z.join(j,"node_modules"),X=Z.join(Q,"node_modules");if(!F.existsSync(J)||F.existsSync(X))return!1;try{return F.symlinkSync(J,X),!0}catch{return!1}}function C(j){if(j===void 0)return M;if(!Number.isInteger(j)||j<=0)throw Error("worktree setup hook timeout must be an integer greater than 0");return j}function g(j,Q){if(!Q)return;let J=Q.hookPath.trim();if(!J)throw Error("worktree setup hook path cannot be empty");let X=J.startsWith("~/")?Z.join(W.homedir(),J.slice(2)):J,V;if(Z.isAbsolute(X))V=X;else if(X.includes("/")||X.includes("\\"))V=Z.resolve(j,X);else throw Error("worktree setup hook must be an absolute path or a repo-relative path");if(!F.existsSync(V))throw Error(`worktree setup hook not found: ${V}`);if(F.statSync(V).isDirectory())throw Error(`worktree setup hook must be a file, got directory: ${V}`);return{hookPath:V,timeoutMs:C(Q.timeoutMs)}}function x(j,Q){let J=Q.trim();if(!J)throw Error("synthetic path cannot be empty");if(Z.isAbsolute(J))throw Error(`synthetic path must be relative: ${Q}`);let X=Z.resolve(j,J),V=Z.relative(j,X);if(!V||V===".")throw Error(`synthetic path cannot target the worktree root: ${Q}`);if(V===".."||V.startsWith(`..${Z.sep}`)||Z.isAbsolute(V))throw Error(`synthetic path escapes the worktree root: ${Q}`);return Z.normalize(V)}function m(j,Q){let J=O(j,["ls-files","--",Q]);return J.status===0&&J.stdout.trim().length>0}function v(j){let Q=j.trim();if(!Q)throw Error("worktree setup hook returned empty stdout; expected JSON object");let J;try{J=JSON.parse(Q)}catch(X){let V=X instanceof Error?X.message:String(X);throw Error(`worktree setup hook returned invalid JSON: ${V}`)}if(!J||typeof J!=="object"||Array.isArray(J))throw Error("worktree setup hook stdout must be a JSON object");return J}function f(j,Q){let J=T(j.hookPath,[],{cwd:Q.worktreePath,encoding:"utf-8",input:JSON.stringify(Q),timeout:j.timeoutMs,shell:!1});if(J.error){if(("code"in J.error?J.error.code:void 0)==="ETIMEDOUT")throw Error(`worktree setup hook timed out after ${j.timeoutMs}ms`);throw Error(`worktree setup hook failed: ${J.error.message}`)}if(J.status!==0){let Y=J.stderr.trim()||J.stdout.trim()||"no output";throw Error(`worktree setup hook failed with exit code ${J.status}: ${Y}`)}let X=v(J.stdout);if(X.syntheticPaths===void 0)return[];if(!Array.isArray(X.syntheticPaths))throw Error("worktree setup hook output field 'syntheticPaths' must be an array of relative paths");let V=new Set;for(let Y of X.syntheticPaths){if(typeof Y!=="string")throw Error("worktree setup hook output field 'syntheticPaths' must contain only strings");let $=x(Q.worktreePath,Y);if(m(Q.worktreePath,$))throw Error(`worktree setup hook cannot mark tracked paths as synthetic: ${$}`);V.add($)}return[...V]}function P(j,Q,J,X,V,Y,$,q){let K=I(J,X),N=H(q,J,X),B=O(j,["worktree","add",N,"-b",K,"HEAD"]);if(B.status!==0){let U=B.stderr.trim()||B.stdout.trim()||`failed to create worktree ${N}`;throw Error(U)}let E=Q?Z.join(N,Q):N;try{let U=D(j,N),L=U?["node_modules"]:[];if(Y){let b=f(Y,{version:1,repoRoot:j,worktreePath:N,agentCwd:E,branch:K,index:X,runId:J,baseCommit:V,agent:$});L.push(...b)}return{path:N,agentCwd:E,branch:K,index:X,nodeModulesLinked:U,syntheticPaths:L}}catch(U){try{A(j,["worktree","remove","--force",N])}catch{}try{A(j,["branch","-D",K])}catch{}throw U}}function c(j,Q){let J=Z.resolve(j.path,Q),X=Z.relative(j.path,J);if(!X||X==="."||X===".."||X.startsWith(`..${Z.sep}`)||Z.isAbsolute(X))return;let V;try{V=F.lstatSync(J)}catch(Y){if((Y&&typeof Y==="object"&&"code"in Y?Y.code:void 0)==="ENOENT")return;throw Y}if(V.isSymbolicLink()){F.unlinkSync(J);return}if(V.isDirectory()){F.rmSync(J,{recursive:!0,force:!0});return}F.rmSync(J,{force:!0})}function k(j){if(j.syntheticPaths.length===0)return;let Q=new Set;for(let J of j.syntheticPaths){if(Q.has(J))continue;Q.add(J),c(j,J)}}function y(j,Q,J,X){return{index:j,agent:Q,branch:J,diffStat:"",filesChanged:0,insertions:0,deletions:0,patchPath:X}}function p(j){let Q=j.split(`
2
- `).map((Y)=>Y.trim()).filter(Boolean),J=0,X=0,V=0;for(let Y of Q){let[$,q]=Y.split("\t");if($===void 0||q===void 0)continue;if(J++,/^\d+$/.test($))X+=parseInt($,10);if(/^\d+$/.test(q))V+=parseInt(q,10)}return{filesChanged:J,insertions:X,deletions:V}}function u(j,Q,J,X){k(Q),A(Q.path,["add","-A"]);let V=A(Q.path,["diff","--cached","--stat",j.baseCommit]).trim(),Y=A(Q.path,["diff","--cached",j.baseCommit]),$=A(Q.path,["diff","--cached","--numstat",j.baseCommit]);if(F.writeFileSync(X,Y,"utf-8"),!Y.trim())return y(Q.index,J,Q.branch,X);let q=p($);return{index:Q.index,agent:J,branch:Q.branch,diffStat:V,filesChanged:q.filesChanged,insertions:q.insertions,deletions:q.deletions,patchPath:X}}function w(j){try{F.writeFileSync(j,"","utf-8")}catch{}}function l(j,Q){try{A(j,["worktree","remove","--force",Q.path])}catch{}try{A(j,["branch","-D",Q.branch])}catch{}}function h(j){return j.filesChanged>0||j.insertions>0||j.deletions>0||j.diffStat.trim().length>0}function o(j,Q,J,X){let V=G(j),Y=g(V.toplevel,X?.setupHook),$=z(X?.baseDir,V.toplevel),q=[];try{for(let K=0;K<J;K++)q.push(P(V.toplevel,V.cwdRelative,Q,K,V.baseCommit,Y,X?.agents?.[K],$))}catch(K){throw n({cwd:V.toplevel,worktrees:q,baseCommit:V.baseCommit}),K}return{cwd:V.toplevel,worktrees:q,baseCommit:V.baseCommit}}function r(j,Q,J){try{F.mkdirSync(J,{recursive:!0})}catch{return[]}let X=[];for(let V=0;V<j.worktrees.length;V++){let Y=j.worktrees[V],$=Q[V]??`task-${V+1}`,q=Z.join(J,`task-${V}-${R($)}.patch`);try{X.push(u(j,Y,$,q))}catch{w(q),X.push(y(V,$,Y.branch,q))}}return X}function n(j){for(let Q=j.worktrees.length-1;Q>=0;Q--)l(j.cwd,j.worktrees[Q]);try{A(j.cwd,["worktree","prune"])}catch{}}function t(j){let Q=j.filter(h);if(Q.length===0)return"";let J=["=== Worktree Changes ===",""];for(let V of Q){if(J.push(`--- Task ${V.index+1} (${V.agent}): ${V.filesChanged} files changed, +${V.insertions} -${V.deletions} ---`),V.diffStat.trim().length>0)J.push(V.diffStat);J.push("")}let X=Z.dirname(Q[0].patchPath);return J.push(`Full patches: ${X}`),J.join(`
3
- `).trimEnd()}export{a as resolveExpectedWorktreeAgentCwd,d as formatWorktreeTaskCwdConflict,t as formatWorktreeDiffSummary,i as findWorktreeTaskCwdConflict,r as diffWorktrees,o as createWorktrees,n as cleanupWorktrees};
1
+ import { spawnSync } from "node:child_process";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ const DEFAULT_WORKTREE_SETUP_HOOK_TIMEOUT_MS = 30000;
6
+ function runGit(cwd, args) {
7
+ const result = spawnSync("git", ["-C", cwd, ...args], { encoding: "utf-8" });
8
+ return {
9
+ stdout: result.stdout ?? "",
10
+ stderr: result.stderr ?? "",
11
+ status: result.status
12
+ };
13
+ }
14
+ function runGitChecked(cwd, args) {
15
+ const result = runGit(cwd, args);
16
+ if (result.status !== 0) {
17
+ const command = `git -C ${cwd} ${args.join(" ")}`;
18
+ const message = result.stderr.trim() || result.stdout.trim() || `${command} failed`;
19
+ throw new Error(message);
20
+ }
21
+ return result.stdout;
22
+ }
23
+ function resolveRepoState(cwd) {
24
+ const cwdRelative = resolveRepoCwdRelative(cwd);
25
+ const toplevel = runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim();
26
+ const status = runGitChecked(toplevel, ["status", "--porcelain"]);
27
+ if (status.trim().length > 0) {
28
+ throw new Error("worktree isolation requires a clean git working tree. Commit or stash changes first.");
29
+ }
30
+ const baseCommit = runGitChecked(toplevel, ["rev-parse", "HEAD"]).trim();
31
+ return { toplevel, cwdRelative, baseCommit };
32
+ }
33
+ function normalizeComparableCwd(cwd) {
34
+ const resolved = path.resolve(cwd);
35
+ try {
36
+ return fs.realpathSync(resolved);
37
+ } catch {
38
+ return resolved;
39
+ }
40
+ }
41
+ export function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
42
+ const normalizedSharedCwd = normalizeComparableCwd(sharedCwd);
43
+ for (let index = 0;index < tasks.length; index++) {
44
+ const task = tasks[index];
45
+ if (!task.cwd)
46
+ continue;
47
+ const taskCwd = path.isAbsolute(task.cwd) ? task.cwd : path.resolve(sharedCwd, task.cwd);
48
+ if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
49
+ continue;
50
+ return { index, agent: task.agent, cwd: task.cwd };
51
+ }
52
+ return;
53
+ }
54
+ export function formatWorktreeTaskCwdConflict(conflict, sharedCwd) {
55
+ return `worktree isolation uses the shared cwd (${sharedCwd}); task ${conflict.index + 1} (${conflict.agent}) sets cwd to ${conflict.cwd}. Remove task-level cwd overrides or disable worktree.`;
56
+ }
57
+ function safePatchAgentName(agent) {
58
+ return agent.replace(/[^\w.-]/g, "_");
59
+ }
60
+ function buildWorktreeBranch(runId, index) {
61
+ return `dm-parallel-${runId}-${index}`;
62
+ }
63
+ function resolveWorktreeBaseDir(configuredBaseDir, repoRoot) {
64
+ const rawBaseDir = configuredBaseDir ?? process.env.DM_SUBAGENTS_WORKTREE_DIR;
65
+ if (rawBaseDir === undefined)
66
+ return os.tmpdir();
67
+ const trimmed = rawBaseDir.trim();
68
+ if (!trimmed)
69
+ throw new Error("worktree base directory cannot be empty");
70
+ const expanded = trimmed.startsWith("~/") ? path.join(os.homedir(), trimmed.slice(2)) : trimmed;
71
+ const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(repoRoot, expanded);
72
+ try {
73
+ fs.mkdirSync(resolved, { recursive: true });
74
+ } catch (error) {
75
+ const message = error instanceof Error ? error.message : String(error);
76
+ throw new Error(`failed to create worktree base directory ${resolved}: ${message}`);
77
+ }
78
+ return resolved;
79
+ }
80
+ function buildWorktreePath(baseDir, runId, index) {
81
+ return path.join(baseDir, `dm-worktree-${runId}-${index}`);
82
+ }
83
+ function resolveRepoCwdRelative(cwd) {
84
+ const repoCheck = runGit(cwd, ["rev-parse", "--is-inside-work-tree"]);
85
+ if (repoCheck.status !== 0 || repoCheck.stdout.trim() !== "true") {
86
+ throw new Error("worktree isolation requires a git repository");
87
+ }
88
+ const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
89
+ const normalizedPrefix = rawPrefix ? path.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
90
+ return normalizedPrefix === "." ? "" : normalizedPrefix;
91
+ }
92
+ export function resolveExpectedWorktreeAgentCwd(cwd, runId, index, baseDir) {
93
+ const cwdRelative = resolveRepoCwdRelative(cwd);
94
+ const repoRoot = runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim();
95
+ const worktreePath = buildWorktreePath(resolveWorktreeBaseDir(baseDir, repoRoot), runId, index);
96
+ return cwdRelative ? path.join(worktreePath, cwdRelative) : worktreePath;
97
+ }
98
+ function linkNodeModulesIfPresent(toplevel, worktreePath) {
99
+ const nodeModulesPath = path.join(toplevel, "node_modules");
100
+ const nodeModulesLinkPath = path.join(worktreePath, "node_modules");
101
+ if (!fs.existsSync(nodeModulesPath) || fs.existsSync(nodeModulesLinkPath))
102
+ return false;
103
+ try {
104
+ fs.symlinkSync(nodeModulesPath, nodeModulesLinkPath);
105
+ return true;
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+ function parseHookTimeout(timeoutMs) {
111
+ if (timeoutMs === undefined)
112
+ return DEFAULT_WORKTREE_SETUP_HOOK_TIMEOUT_MS;
113
+ if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
114
+ throw new Error("worktree setup hook timeout must be an integer greater than 0");
115
+ }
116
+ return timeoutMs;
117
+ }
118
+ function resolveWorktreeSetupHook(repoRoot, config) {
119
+ if (!config)
120
+ return;
121
+ const hookPath = config.hookPath.trim();
122
+ if (!hookPath) {
123
+ throw new Error("worktree setup hook path cannot be empty");
124
+ }
125
+ const expandedHookPath = hookPath.startsWith("~/") ? path.join(os.homedir(), hookPath.slice(2)) : hookPath;
126
+ let resolvedPath;
127
+ if (path.isAbsolute(expandedHookPath)) {
128
+ resolvedPath = expandedHookPath;
129
+ } else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
130
+ resolvedPath = path.resolve(repoRoot, expandedHookPath);
131
+ } else {
132
+ throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
133
+ }
134
+ if (!fs.existsSync(resolvedPath)) {
135
+ throw new Error(`worktree setup hook not found: ${resolvedPath}`);
136
+ }
137
+ if (fs.statSync(resolvedPath).isDirectory()) {
138
+ throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
139
+ }
140
+ return {
141
+ hookPath: resolvedPath,
142
+ timeoutMs: parseHookTimeout(config.timeoutMs)
143
+ };
144
+ }
145
+ function normalizeSyntheticPath(worktreePath, rawPath) {
146
+ const trimmed = rawPath.trim();
147
+ if (!trimmed)
148
+ throw new Error("synthetic path cannot be empty");
149
+ if (path.isAbsolute(trimmed))
150
+ throw new Error(`synthetic path must be relative: ${rawPath}`);
151
+ const resolved = path.resolve(worktreePath, trimmed);
152
+ const relative = path.relative(worktreePath, resolved);
153
+ if (!relative || relative === ".") {
154
+ throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
155
+ }
156
+ if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
157
+ throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
158
+ }
159
+ return path.normalize(relative);
160
+ }
161
+ function hasTrackedEntries(worktreePath, relativePath) {
162
+ const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
163
+ return result.status === 0 && result.stdout.trim().length > 0;
164
+ }
165
+ function parseWorktreeSetupHookOutput(rawStdout) {
166
+ const trimmed = rawStdout.trim();
167
+ if (!trimmed) {
168
+ throw new Error("worktree setup hook returned empty stdout; expected JSON object");
169
+ }
170
+ let parsed;
171
+ try {
172
+ parsed = JSON.parse(trimmed);
173
+ } catch (error) {
174
+ const message = error instanceof Error ? error.message : String(error);
175
+ throw new Error(`worktree setup hook returned invalid JSON: ${message}`);
176
+ }
177
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
178
+ throw new Error("worktree setup hook stdout must be a JSON object");
179
+ }
180
+ return parsed;
181
+ }
182
+ function runWorktreeSetupHook(hook, input) {
183
+ const result = spawnSync(hook.hookPath, [], {
184
+ cwd: input.worktreePath,
185
+ encoding: "utf-8",
186
+ input: JSON.stringify(input),
187
+ timeout: hook.timeoutMs,
188
+ shell: false
189
+ });
190
+ if (result.error) {
191
+ const code = "code" in result.error ? result.error.code : undefined;
192
+ if (code === "ETIMEDOUT") {
193
+ throw new Error(`worktree setup hook timed out after ${hook.timeoutMs}ms`);
194
+ }
195
+ throw new Error(`worktree setup hook failed: ${result.error.message}`);
196
+ }
197
+ if (result.status !== 0) {
198
+ const details = result.stderr.trim() || result.stdout.trim() || "no output";
199
+ throw new Error(`worktree setup hook failed with exit code ${result.status}: ${details}`);
200
+ }
201
+ const output = parseWorktreeSetupHookOutput(result.stdout);
202
+ if (output.syntheticPaths === undefined)
203
+ return [];
204
+ if (!Array.isArray(output.syntheticPaths)) {
205
+ throw new Error("worktree setup hook output field 'syntheticPaths' must be an array of relative paths");
206
+ }
207
+ const uniquePaths = new Set;
208
+ for (const candidate of output.syntheticPaths) {
209
+ if (typeof candidate !== "string") {
210
+ throw new Error("worktree setup hook output field 'syntheticPaths' must contain only strings");
211
+ }
212
+ const normalizedPath = normalizeSyntheticPath(input.worktreePath, candidate);
213
+ if (hasTrackedEntries(input.worktreePath, normalizedPath)) {
214
+ throw new Error(`worktree setup hook cannot mark tracked paths as synthetic: ${normalizedPath}`);
215
+ }
216
+ uniquePaths.add(normalizedPath);
217
+ }
218
+ return [...uniquePaths];
219
+ }
220
+ function createSingleWorktree(toplevel, cwdRelative, runId, index, baseCommit, setupHook, agent, baseDir) {
221
+ const branch = buildWorktreeBranch(runId, index);
222
+ const worktreePath = buildWorktreePath(baseDir, runId, index);
223
+ const add = runGit(toplevel, ["worktree", "add", worktreePath, "-b", branch, "HEAD"]);
224
+ if (add.status !== 0) {
225
+ const message = add.stderr.trim() || add.stdout.trim() || `failed to create worktree ${worktreePath}`;
226
+ throw new Error(message);
227
+ }
228
+ const agentCwd = cwdRelative ? path.join(worktreePath, cwdRelative) : worktreePath;
229
+ try {
230
+ const nodeModulesLinked = linkNodeModulesIfPresent(toplevel, worktreePath);
231
+ const syntheticPaths = nodeModulesLinked ? ["node_modules"] : [];
232
+ if (setupHook) {
233
+ const hookSyntheticPaths = runWorktreeSetupHook(setupHook, {
234
+ version: 1,
235
+ repoRoot: toplevel,
236
+ worktreePath,
237
+ agentCwd,
238
+ branch,
239
+ index,
240
+ runId,
241
+ baseCommit,
242
+ agent
243
+ });
244
+ syntheticPaths.push(...hookSyntheticPaths);
245
+ }
246
+ return {
247
+ path: worktreePath,
248
+ agentCwd,
249
+ branch,
250
+ index,
251
+ nodeModulesLinked,
252
+ syntheticPaths
253
+ };
254
+ } catch (error) {
255
+ try {
256
+ runGitChecked(toplevel, ["worktree", "remove", "--force", worktreePath]);
257
+ } catch {}
258
+ try {
259
+ runGitChecked(toplevel, ["branch", "-D", branch]);
260
+ } catch {}
261
+ throw error;
262
+ }
263
+ }
264
+ function removeSyntheticPath(worktree, syntheticPath) {
265
+ const resolved = path.resolve(worktree.path, syntheticPath);
266
+ const relative = path.relative(worktree.path, resolved);
267
+ if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
268
+ return;
269
+ }
270
+ let stat;
271
+ try {
272
+ stat = fs.lstatSync(resolved);
273
+ } catch (error) {
274
+ const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
275
+ if (code === "ENOENT")
276
+ return;
277
+ throw error;
278
+ }
279
+ if (stat.isSymbolicLink()) {
280
+ fs.unlinkSync(resolved);
281
+ return;
282
+ }
283
+ if (stat.isDirectory()) {
284
+ fs.rmSync(resolved, { recursive: true, force: true });
285
+ return;
286
+ }
287
+ fs.rmSync(resolved, { force: true });
288
+ }
289
+ function removeSyntheticPathsBeforeDiff(worktree) {
290
+ if (worktree.syntheticPaths.length === 0)
291
+ return;
292
+ const seen = new Set;
293
+ for (const syntheticPath of worktree.syntheticPaths) {
294
+ if (seen.has(syntheticPath))
295
+ continue;
296
+ seen.add(syntheticPath);
297
+ removeSyntheticPath(worktree, syntheticPath);
298
+ }
299
+ }
300
+ function emptyDiff(index, agent, branch, patchPath) {
301
+ return {
302
+ index,
303
+ agent,
304
+ branch,
305
+ diffStat: "",
306
+ filesChanged: 0,
307
+ insertions: 0,
308
+ deletions: 0,
309
+ patchPath
310
+ };
311
+ }
312
+ function parseNumstat(numstat) {
313
+ const lines = numstat.split(`
314
+ `).map((line) => line.trim()).filter(Boolean);
315
+ let filesChanged = 0;
316
+ let insertions = 0;
317
+ let deletions = 0;
318
+ for (const line of lines) {
319
+ const [rawInsertions, rawDeletions] = line.split("\t");
320
+ if (rawInsertions === undefined || rawDeletions === undefined)
321
+ continue;
322
+ filesChanged++;
323
+ if (/^\d+$/.test(rawInsertions))
324
+ insertions += parseInt(rawInsertions, 10);
325
+ if (/^\d+$/.test(rawDeletions))
326
+ deletions += parseInt(rawDeletions, 10);
327
+ }
328
+ return { filesChanged, insertions, deletions };
329
+ }
330
+ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
331
+ removeSyntheticPathsBeforeDiff(worktree);
332
+ runGitChecked(worktree.path, ["add", "-A"]);
333
+ const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
334
+ const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
335
+ const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
336
+ fs.writeFileSync(patchPath, patch, "utf-8");
337
+ if (!patch.trim()) {
338
+ return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
339
+ }
340
+ const parsed = parseNumstat(numstat);
341
+ return {
342
+ index: worktree.index,
343
+ agent,
344
+ branch: worktree.branch,
345
+ diffStat,
346
+ filesChanged: parsed.filesChanged,
347
+ insertions: parsed.insertions,
348
+ deletions: parsed.deletions,
349
+ patchPath
350
+ };
351
+ }
352
+ function writeEmptyPatch(patchPath) {
353
+ try {
354
+ fs.writeFileSync(patchPath, "", "utf-8");
355
+ } catch {}
356
+ }
357
+ function cleanupSingleWorktree(repoCwd, worktree) {
358
+ try {
359
+ runGitChecked(repoCwd, ["worktree", "remove", "--force", worktree.path]);
360
+ } catch {}
361
+ try {
362
+ runGitChecked(repoCwd, ["branch", "-D", worktree.branch]);
363
+ } catch {}
364
+ }
365
+ function hasWorktreeChanges(diff) {
366
+ return diff.filesChanged > 0 || diff.insertions > 0 || diff.deletions > 0 || diff.diffStat.trim().length > 0;
367
+ }
368
+ export function createWorktrees(cwd, runId, count, options) {
369
+ const repo = resolveRepoState(cwd);
370
+ const setupHook = resolveWorktreeSetupHook(repo.toplevel, options?.setupHook);
371
+ const baseDir = resolveWorktreeBaseDir(options?.baseDir, repo.toplevel);
372
+ const worktrees = [];
373
+ try {
374
+ for (let index = 0;index < count; index++) {
375
+ worktrees.push(createSingleWorktree(repo.toplevel, repo.cwdRelative, runId, index, repo.baseCommit, setupHook, options?.agents?.[index], baseDir));
376
+ }
377
+ } catch (error) {
378
+ cleanupWorktrees({
379
+ cwd: repo.toplevel,
380
+ worktrees,
381
+ baseCommit: repo.baseCommit
382
+ });
383
+ throw error;
384
+ }
385
+ return {
386
+ cwd: repo.toplevel,
387
+ worktrees,
388
+ baseCommit: repo.baseCommit
389
+ };
390
+ }
391
+ export function diffWorktrees(setup, agents, diffsDir) {
392
+ try {
393
+ fs.mkdirSync(diffsDir, { recursive: true });
394
+ } catch {
395
+ return [];
396
+ }
397
+ const diffs = [];
398
+ for (let index = 0;index < setup.worktrees.length; index++) {
399
+ const worktree = setup.worktrees[index];
400
+ const agent = agents[index] ?? `task-${index + 1}`;
401
+ const patchPath = path.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
402
+ try {
403
+ diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
404
+ } catch {
405
+ writeEmptyPatch(patchPath);
406
+ diffs.push(emptyDiff(index, agent, worktree.branch, patchPath));
407
+ }
408
+ }
409
+ return diffs;
410
+ }
411
+ export function cleanupWorktrees(setup) {
412
+ for (let index = setup.worktrees.length - 1;index >= 0; index--) {
413
+ cleanupSingleWorktree(setup.cwd, setup.worktrees[index]);
414
+ }
415
+ try {
416
+ runGitChecked(setup.cwd, ["worktree", "prune"]);
417
+ } catch {}
418
+ }
419
+ export function formatWorktreeDiffSummary(diffs) {
420
+ const changed = diffs.filter(hasWorktreeChanges);
421
+ if (changed.length === 0)
422
+ return "";
423
+ const lines = ["=== Worktree Changes ===", ""];
424
+ for (const diff of changed) {
425
+ lines.push(`--- Task ${diff.index + 1} (${diff.agent}): ${diff.filesChanged} files changed, +${diff.insertions} -${diff.deletions} ---`);
426
+ if (diff.diffStat.trim().length > 0) {
427
+ lines.push(diff.diffStat);
428
+ }
429
+ lines.push("");
430
+ }
431
+ const patchesDir = path.dirname(changed[0].patchPath);
432
+ lines.push(`Full patches: ${patchesDir}`);
433
+ return lines.join(`
434
+ `).trimEnd();
435
+ }
@@ -1,2 +1,92 @@
1
- import*as Z from"node:fs";import*as J from"node:path";import*as V from"node:os";import*as G from"node:path";function z(Q){return Q.trim().replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function N(Q){let Y=Q?.env??process.env,$=Q&&Object.hasOwn(Q,"getuid")?Q.getuid:process.getuid?.bind(process);if(typeof $==="function")return`uid-${$()}`;for(let W of["USERNAME","USER","LOGNAME"]){let j=Y[W];if(j)return`user-${z(j)}`}let X=Q&&Object.hasOwn(Q,"userInfo")?Q.userInfo:V.userInfo;try{let W=X?.().username;if(W)return`user-${z(W)}`}catch{}let B=Y.USERPROFILE??Y.HOME;if(B)return`home-${z(B)}`;let K=Q&&Object.hasOwn(Q,"homedir")?Q.homedir:V.homedir;try{let W=K?.();if(W)return`home-${z(W)}`}catch{}return"shared"}var L=G.join(V.tmpdir(),`dm-subagents-${N()}`),P=G.join(L,"async-subagent-results"),f=G.join(L,"async-subagent-runs"),R=G.join(L,"chain-runs"),_=G.join(L,"artifacts");import*as q from"node:fs";import*as H from"node:os";import*as U from"node:path";var I=".dm",C="@duckmind/dm-coding-agent",b="DM_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT";function F(Q){return typeof Q==="string"&&Q.trim()?Q:void 0}function E(Q){if(!Q)return;try{let Y=JSON.parse(q.readFileSync(U.join(Q,"package.json"),"utf-8"));if(Y.name!==C)return;return F(Y.piConfig?.configDir)}catch{return}}function w(Q=process.argv[1],Y=process.env[b]){let $=E(Y);if($)return $;if(!Q)return;try{let X=U.dirname(q.realpathSync(Q));while(X!==U.dirname(X)){let B=E(X);if(B)return B;X=U.dirname(X)}}catch{}return}function S(Q,Y,$){return(Q&&typeof Q==="object"?F(Q.CONFIG_DIR_NAME):void 0)??w(Y,$)??I}function y(){return S()}function M(){let Q=process.env.DM_CODING_AGENT_DIR;if(Q==="~")return H.homedir();if(Q?.startsWith("~/"))return U.join(H.homedir(),Q.slice(2));return Q||U.join(H.homedir(),y(),"agent")}var O=".last-cleanup",x=".dm-subagents";function A(Q){return J.join(Q,x)}function D(Q){return J.join(A(Q),"artifacts")}function UQ(Q){return J.join(A(Q),"chain-runs")}function VQ(Q,Y){if(Y)return D(Y);if(Q){let $=J.dirname(Q);return J.join($,"subagent-artifacts")}return _}function GQ(Q,Y,$,X){let B=X!==void 0?`_${X}`:"",K=$.replace(/[^\w.-]/g,"_"),W=`${Y}_${K}${B}`;return{inputPath:J.join(Q,`${W}_input.md`),outputPath:J.join(Q,`${W}_output.md`),jsonlPath:J.join(Q,`${W}.jsonl`),transcriptPath:J.join(Q,`${W}_transcript.jsonl`),metadataPath:J.join(Q,`${W}_meta.json`)}}function KQ(Q){Z.mkdirSync(Q,{recursive:!0})}function jQ(Q,Y){Z.writeFileSync(Q,Y,"utf-8")}function HQ(Q,Y){Z.writeFileSync(Q,JSON.stringify(Y,null,2),"utf-8")}function zQ(Q,Y){Z.appendFileSync(Q,`${Y}
2
- `)}function T(Q,Y){if(!Z.existsSync(Q))return;let $=J.join(Q,O),X=Date.now();if(Z.existsSync($)){let W=Z.statSync($);if(X-W.mtimeMs<86400000)return}let B=Y*24*60*60*1000,K=X-B;for(let W of Z.readdirSync(Q)){if(W===O)continue;let j=J.join(Q,W);try{if(Z.statSync(j).mtimeMs<K)Z.unlinkSync(j)}catch{}}Z.writeFileSync($,String(X))}function LQ(Q){T(_,Q);let Y=J.join(M(),"sessions");if(!Z.existsSync(Y))return;let $;try{$=Z.readdirSync(Y)}catch{return}for(let X of $){let B=J.join(Y,X,"subagent-artifacts");try{T(B,Q)}catch{}}}export{HQ as writeMetadata,jQ as writeArtifact,A as getProjectSubagentsDir,UQ as getProjectChainRunsDir,D as getProjectArtifactsDir,VQ as getArtifactsDir,GQ as getArtifactPaths,KQ as ensureArtifactsDir,T as cleanupOldArtifacts,LQ as cleanupAllArtifactDirs,zQ as appendJsonl};
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { TEMP_ARTIFACTS_DIR } from "./types.js";
4
+ import { getAgentDir } from "./utils.js";
5
+ const CLEANUP_MARKER_FILE = ".last-cleanup";
6
+ const PROJECT_ARTIFACT_ROOT = ".dm-subagents";
7
+ export function getProjectSubagentsDir(cwd) {
8
+ return path.join(cwd, PROJECT_ARTIFACT_ROOT);
9
+ }
10
+ export function getProjectArtifactsDir(cwd) {
11
+ return path.join(getProjectSubagentsDir(cwd), "artifacts");
12
+ }
13
+ export function getProjectChainRunsDir(cwd) {
14
+ return path.join(getProjectSubagentsDir(cwd), "chain-runs");
15
+ }
16
+ export function getArtifactsDir(sessionFile, projectCwd) {
17
+ if (projectCwd)
18
+ return getProjectArtifactsDir(projectCwd);
19
+ if (sessionFile) {
20
+ const sessionDir = path.dirname(sessionFile);
21
+ return path.join(sessionDir, "subagent-artifacts");
22
+ }
23
+ return TEMP_ARTIFACTS_DIR;
24
+ }
25
+ export function getArtifactPaths(artifactsDir, runId, agent, index) {
26
+ const suffix = index !== undefined ? `_${index}` : "";
27
+ const safeAgent = agent.replace(/[^\w.-]/g, "_");
28
+ const base = `${runId}_${safeAgent}${suffix}`;
29
+ return {
30
+ inputPath: path.join(artifactsDir, `${base}_input.md`),
31
+ outputPath: path.join(artifactsDir, `${base}_output.md`),
32
+ jsonlPath: path.join(artifactsDir, `${base}.jsonl`),
33
+ transcriptPath: path.join(artifactsDir, `${base}_transcript.jsonl`),
34
+ metadataPath: path.join(artifactsDir, `${base}_meta.json`)
35
+ };
36
+ }
37
+ export function ensureArtifactsDir(dir) {
38
+ fs.mkdirSync(dir, { recursive: true });
39
+ }
40
+ export function writeArtifact(filePath, content) {
41
+ fs.writeFileSync(filePath, content, "utf-8");
42
+ }
43
+ export function writeMetadata(filePath, metadata) {
44
+ fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2), "utf-8");
45
+ }
46
+ export function appendJsonl(filePath, line) {
47
+ fs.appendFileSync(filePath, `${line}
48
+ `);
49
+ }
50
+ export function cleanupOldArtifacts(dir, maxAgeDays) {
51
+ if (!fs.existsSync(dir))
52
+ return;
53
+ const markerPath = path.join(dir, CLEANUP_MARKER_FILE);
54
+ const now = Date.now();
55
+ if (fs.existsSync(markerPath)) {
56
+ const stat = fs.statSync(markerPath);
57
+ if (now - stat.mtimeMs < 24 * 60 * 60 * 1000)
58
+ return;
59
+ }
60
+ const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
61
+ const cutoff = now - maxAgeMs;
62
+ for (const file of fs.readdirSync(dir)) {
63
+ if (file === CLEANUP_MARKER_FILE)
64
+ continue;
65
+ const filePath = path.join(dir, file);
66
+ try {
67
+ const stat = fs.statSync(filePath);
68
+ if (stat.mtimeMs < cutoff) {
69
+ fs.unlinkSync(filePath);
70
+ }
71
+ } catch {}
72
+ }
73
+ fs.writeFileSync(markerPath, String(now));
74
+ }
75
+ export function cleanupAllArtifactDirs(maxAgeDays) {
76
+ cleanupOldArtifacts(TEMP_ARTIFACTS_DIR, maxAgeDays);
77
+ const sessionsBase = path.join(getAgentDir(), "sessions");
78
+ if (!fs.existsSync(sessionsBase))
79
+ return;
80
+ let dirs;
81
+ try {
82
+ dirs = fs.readdirSync(sessionsBase);
83
+ } catch {
84
+ return;
85
+ }
86
+ for (const dir of dirs) {
87
+ const artifactsDir = path.join(sessionsBase, dir, "subagent-artifacts");
88
+ try {
89
+ cleanupOldArtifacts(artifactsDir, maxAgeDays);
90
+ } catch {}
91
+ }
92
+ }
@@ -1 +1,55 @@
1
- import*as J from"node:fs";import*as x from"node:path";var g=[10,25,50,100,200,500,1000,2000,4000],N=new Set(["EACCES","EBUSY","EPERM"]),k=typeof SharedArrayBuffer<"u"?new SharedArrayBuffer(4):void 0,v=k?new Int32Array(k):void 0;function O(j){if(j<=0)return;if(v)try{Atomics.wait(v,0,0,j);return}catch{}let q=Date.now()+j;while(Date.now()<q);}function V(j){let q=j?.code;return typeof q==="string"&&N.has(q)}function B(j,q,K,Q,X){for(let Z=0;;Z++)try{j.renameSync(q,K);return}catch(z){let G=Q[Z];if(G===void 0||!V(z))throw z;X(G)}}function L(j={}){let q=j.fs??J,K=j.now??Date.now,Q=j.pid??process.pid,X=j.random??Math.random,z=j.retryRenameErrors??process.platform==="win32"?j.retryDelaysMs??g:[],G=j.wait??O;return(H,C)=>{q.mkdirSync(x.dirname(H),{recursive:!0});let $=x.join(x.dirname(H),`.${x.basename(H)}.${Q}.${K()}.${X().toString(36).slice(2)}.tmp`);try{q.writeFileSync($,JSON.stringify(C,null,2),"utf-8"),B(q,$,H,z,G)}finally{q.rmSync($,{force:!0})}}}var U=L();export{U as writeAtomicJson,L as createAtomicJsonWriter};
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ const DEFAULT_RENAME_RETRY_DELAYS_MS = [10, 25, 50, 100, 200, 500, 1000, 2000, 4000];
4
+ const RETRYABLE_RENAME_ERROR_CODES = new Set(["EACCES", "EBUSY", "EPERM"]);
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
+ }
23
+ function renameWithRetry(fsImpl, sourcePath, targetPath, retryDelaysMs, wait) {
24
+ for (let attempt = 0;; attempt++) {
25
+ try {
26
+ fsImpl.renameSync(sourcePath, targetPath);
27
+ return;
28
+ } catch (error) {
29
+ const delayMs = retryDelaysMs[attempt];
30
+ if (delayMs === undefined || !isRetryableRenameError(error))
31
+ throw error;
32
+ wait(delayMs);
33
+ }
34
+ }
35
+ }
36
+ export function createAtomicJsonWriter(options = {}) {
37
+ const fsImpl = options.fs ?? fs;
38
+ const now = options.now ?? Date.now;
39
+ const pid = options.pid ?? process.pid;
40
+ const random = options.random ?? Math.random;
41
+ const retryRenameErrors = options.retryRenameErrors ?? process.platform === "win32";
42
+ const retryDelaysMs = retryRenameErrors ? options.retryDelaysMs ?? DEFAULT_RENAME_RETRY_DELAYS_MS : [];
43
+ const wait = options.wait ?? waitSync;
44
+ return (filePath, payload) => {
45
+ fsImpl.mkdirSync(path.dirname(filePath), { recursive: true });
46
+ const tempPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${pid}.${now()}.${random().toString(36).slice(2)}.tmp`);
47
+ try {
48
+ fsImpl.writeFileSync(tempPath, JSON.stringify(payload, null, 2), "utf-8");
49
+ renameWithRetry(fsImpl, tempPath, filePath, retryDelaysMs, wait);
50
+ } finally {
51
+ fsImpl.rmSync(tempPath, { force: true });
52
+ }
53
+ };
54
+ }
55
+ export const writeAtomicJson = createAtomicJsonWriter();