@caupulican/pi-adaptative 0.84.1 → 0.85.3

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 (214) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +14 -8
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +14 -8
  6. package/dist/bundled-resources/runtimes/pi-shell-engine/arithmetic.py +364 -0
  7. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +2 -1
  8. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +16 -0
  9. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +137 -14
  10. package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +23 -2
  11. package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +134 -6
  12. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +25 -2
  13. package/dist/bundled-resources/skills/deduplicate-by-evidence/SKILL.md +7 -5
  14. package/dist/bundled-resources/skills/worker-profile-writer/SKILL.md +63 -0
  15. package/dist/core/agent-session.d.ts.map +1 -1
  16. package/dist/core/agent-session.js +8 -0
  17. package/dist/core/agent-session.js.map +1 -1
  18. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  19. package/dist/core/autonomy/lane-tool-surface.js +4 -2
  20. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  21. package/dist/core/background-lane-controller.d.ts +3 -0
  22. package/dist/core/background-lane-controller.d.ts.map +1 -1
  23. package/dist/core/background-lane-controller.js +6 -0
  24. package/dist/core/background-lane-controller.js.map +1 -1
  25. package/dist/core/compaction-controller.d.ts +2 -0
  26. package/dist/core/compaction-controller.d.ts.map +1 -1
  27. package/dist/core/compaction-controller.js +35 -13
  28. package/dist/core/compaction-controller.js.map +1 -1
  29. package/dist/core/default-tool-surface.d.ts.map +1 -1
  30. package/dist/core/default-tool-surface.js +1 -0
  31. package/dist/core/default-tool-surface.js.map +1 -1
  32. package/dist/core/delegation/worker-delegation-controller.d.ts +7 -0
  33. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
  34. package/dist/core/delegation/worker-delegation-controller.js +28 -0
  35. package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
  36. package/dist/core/delegation/worker-profile-resolver.d.ts +2 -0
  37. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -1
  38. package/dist/core/delegation/worker-profile-resolver.js +46 -11
  39. package/dist/core/delegation/worker-profile-resolver.js.map +1 -1
  40. package/dist/core/doctor.d.ts +1 -1
  41. package/dist/core/doctor.d.ts.map +1 -1
  42. package/dist/core/doctor.js +5 -4
  43. package/dist/core/doctor.js.map +1 -1
  44. package/dist/core/failure-corpus.d.ts +26 -1
  45. package/dist/core/failure-corpus.d.ts.map +1 -1
  46. package/dist/core/failure-corpus.js +17 -0
  47. package/dist/core/failure-corpus.js.map +1 -1
  48. package/dist/core/model-capability.d.ts.map +1 -1
  49. package/dist/core/model-capability.js +1 -0
  50. package/dist/core/model-capability.js.map +1 -1
  51. package/dist/core/model-tool-protocol.d.ts +3 -2
  52. package/dist/core/model-tool-protocol.d.ts.map +1 -1
  53. package/dist/core/model-tool-protocol.js +5 -1
  54. package/dist/core/model-tool-protocol.js.map +1 -1
  55. package/dist/core/models/runtime-process.d.ts +7 -1
  56. package/dist/core/models/runtime-process.d.ts.map +1 -1
  57. package/dist/core/models/runtime-process.js +4 -2
  58. package/dist/core/models/runtime-process.js.map +1 -1
  59. package/dist/core/orchestration/lane-tool-manifests.d.ts +1 -1
  60. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -1
  61. package/dist/core/orchestration/lane-tool-manifests.js +6 -1
  62. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -1
  63. package/dist/core/orchestration/session-task-profile-store.d.ts +31 -0
  64. package/dist/core/orchestration/session-task-profile-store.d.ts.map +1 -0
  65. package/dist/core/orchestration/session-task-profile-store.js +138 -0
  66. package/dist/core/orchestration/session-task-profile-store.js.map +1 -0
  67. package/dist/core/orchestration/task-profile-writer.d.ts +58 -0
  68. package/dist/core/orchestration/task-profile-writer.d.ts.map +1 -0
  69. package/dist/core/orchestration/task-profile-writer.js +165 -0
  70. package/dist/core/orchestration/task-profile-writer.js.map +1 -0
  71. package/dist/core/process-matrix/runtime.js +43 -11
  72. package/dist/core/process-matrix/runtime.js.map +1 -1
  73. package/dist/core/resource-loader.d.ts +2 -0
  74. package/dist/core/resource-loader.d.ts.map +1 -1
  75. package/dist/core/resource-loader.js +18 -6
  76. package/dist/core/resource-loader.js.map +1 -1
  77. package/dist/core/runtime-builder.d.ts +3 -1
  78. package/dist/core/runtime-builder.d.ts.map +1 -1
  79. package/dist/core/runtime-builder.js +14 -0
  80. package/dist/core/runtime-builder.js.map +1 -1
  81. package/dist/core/security/untrusted-boundary.d.ts.map +1 -1
  82. package/dist/core/security/untrusted-boundary.js +4 -6
  83. package/dist/core/security/untrusted-boundary.js.map +1 -1
  84. package/dist/core/session-role.d.ts.map +1 -1
  85. package/dist/core/session-role.js +1 -0
  86. package/dist/core/session-role.js.map +1 -1
  87. package/dist/core/system-prompt.d.ts.map +1 -1
  88. package/dist/core/system-prompt.js +21 -23
  89. package/dist/core/system-prompt.js.map +1 -1
  90. package/dist/core/tool-capability-policy.js +1 -1
  91. package/dist/core/tool-capability-policy.js.map +1 -1
  92. package/dist/core/tool-recovery-log-records.d.ts +33 -1
  93. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  94. package/dist/core/tool-recovery-log-records.js +59 -12
  95. package/dist/core/tool-recovery-log-records.js.map +1 -1
  96. package/dist/core/tool-recovery-logger.d.ts +12 -1
  97. package/dist/core/tool-recovery-logger.d.ts.map +1 -1
  98. package/dist/core/tool-recovery-logger.js +24 -1
  99. package/dist/core/tool-recovery-logger.js.map +1 -1
  100. package/dist/core/tool-repair-health.d.ts.map +1 -1
  101. package/dist/core/tool-repair-health.js +6 -0
  102. package/dist/core/tool-repair-health.js.map +1 -1
  103. package/dist/core/tools/bash.d.ts +3 -8
  104. package/dist/core/tools/bash.d.ts.map +1 -1
  105. package/dist/core/tools/bash.js +4 -28
  106. package/dist/core/tools/bash.js.map +1 -1
  107. package/dist/core/tools/delegate.js +4 -4
  108. package/dist/core/tools/delegate.js.map +1 -1
  109. package/dist/core/tools/edit-diff.d.ts +32 -5
  110. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  111. package/dist/core/tools/edit-diff.js +137 -69
  112. package/dist/core/tools/edit-diff.js.map +1 -1
  113. package/dist/core/tools/edit.d.ts +22 -7
  114. package/dist/core/tools/edit.d.ts.map +1 -1
  115. package/dist/core/tools/edit.js +128 -55
  116. package/dist/core/tools/edit.js.map +1 -1
  117. package/dist/core/tools/file-mutation-intent.d.ts +70 -0
  118. package/dist/core/tools/file-mutation-intent.d.ts.map +1 -0
  119. package/dist/core/tools/file-mutation-intent.js +325 -0
  120. package/dist/core/tools/file-mutation-intent.js.map +1 -0
  121. package/dist/core/tools/find.d.ts +2 -1
  122. package/dist/core/tools/find.d.ts.map +1 -1
  123. package/dist/core/tools/find.js +2 -6
  124. package/dist/core/tools/find.js.map +1 -1
  125. package/dist/core/tools/goal.d.ts.map +1 -1
  126. package/dist/core/tools/goal.js +41 -18
  127. package/dist/core/tools/goal.js.map +1 -1
  128. package/dist/core/tools/grep.d.ts +2 -1
  129. package/dist/core/tools/grep.d.ts.map +1 -1
  130. package/dist/core/tools/grep.js +2 -6
  131. package/dist/core/tools/grep.js.map +1 -1
  132. package/dist/core/tools/index.d.ts +3 -1
  133. package/dist/core/tools/index.d.ts.map +1 -1
  134. package/dist/core/tools/index.js +31 -8
  135. package/dist/core/tools/index.js.map +1 -1
  136. package/dist/core/tools/managed-search-tool.d.ts +8 -0
  137. package/dist/core/tools/managed-search-tool.d.ts.map +1 -0
  138. package/dist/core/tools/managed-search-tool.js +10 -0
  139. package/dist/core/tools/managed-search-tool.js.map +1 -0
  140. package/dist/core/tools/profile-writer.d.ts +33 -0
  141. package/dist/core/tools/profile-writer.d.ts.map +1 -0
  142. package/dist/core/tools/profile-writer.js +67 -0
  143. package/dist/core/tools/profile-writer.js.map +1 -0
  144. package/dist/core/tools/shell-command-parser.d.ts +4 -3
  145. package/dist/core/tools/shell-command-parser.d.ts.map +1 -1
  146. package/dist/core/tools/shell-command-parser.js +32 -7
  147. package/dist/core/tools/shell-command-parser.js.map +1 -1
  148. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  149. package/dist/core/tools/shell-contract-router.js +23 -1
  150. package/dist/core/tools/shell-contract-router.js.map +1 -1
  151. package/dist/core/tools/task-steps.d.ts.map +1 -1
  152. package/dist/core/tools/task-steps.js +6 -11
  153. package/dist/core/tools/task-steps.js.map +1 -1
  154. package/dist/core/tools/tmux-dispatch.d.ts +2 -0
  155. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  156. package/dist/core/tools/tmux-dispatch.js +16 -2
  157. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  158. package/dist/core/tools/windows-shell-engine.js +1 -1
  159. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  160. package/dist/core/tools/write.d.ts +24 -7
  161. package/dist/core/tools/write.d.ts.map +1 -1
  162. package/dist/core/tools/write.js +182 -107
  163. package/dist/core/tools/write.js.map +1 -1
  164. package/dist/index.d.ts +1 -1
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +1 -1
  167. package/dist/index.js.map +1 -1
  168. package/dist/jscpd-cli.d.ts +3 -0
  169. package/dist/jscpd-cli.d.ts.map +1 -0
  170. package/dist/jscpd-cli.js +22 -0
  171. package/dist/jscpd-cli.js.map +1 -0
  172. package/dist/modes/interactive/components/profile-resource-editor.js +2 -2
  173. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  174. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  175. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  176. package/dist/modes/interactive/components/tool-execution.js +85 -3
  177. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  178. package/dist/modes/interactive/interactive-mode.js +1 -1
  179. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/dist/utils/bundled-jscpd.d.ts +20 -0
  181. package/dist/utils/bundled-jscpd.d.ts.map +1 -0
  182. package/dist/utils/bundled-jscpd.js +154 -0
  183. package/dist/utils/bundled-jscpd.js.map +1 -0
  184. package/dist/utils/paths.js +1 -1
  185. package/dist/utils/paths.js.map +1 -1
  186. package/dist/utils/shell.d.ts.map +1 -1
  187. package/dist/utils/shell.js +11 -0
  188. package/dist/utils/shell.js.map +1 -1
  189. package/dist/utils/tools-manager.d.ts +19 -2
  190. package/dist/utils/tools-manager.d.ts.map +1 -1
  191. package/dist/utils/tools-manager.js +92 -40
  192. package/dist/utils/tools-manager.js.map +1 -1
  193. package/docs/index.md +3 -0
  194. package/docs/managed-data-tools.md +15 -0
  195. package/docs/models.md +1 -1
  196. package/docs/quickstart.md +2 -2
  197. package/docs/settings.md +1 -1
  198. package/docs/tool-boundary-performance-roadmap-2026-08-02.md +166 -0
  199. package/docs/tool-repair.md +4 -4
  200. package/docs/windows.md +7 -5
  201. package/docs/worker-profiles.md +16 -0
  202. package/examples/extensions/built-in-tool-renderer.ts +12 -5
  203. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  204. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  205. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  206. package/examples/extensions/minimal-mode.ts +8 -7
  207. package/examples/extensions/prompt-customizer.ts +4 -2
  208. package/examples/extensions/sandbox/package-lock.json +2 -2
  209. package/examples/extensions/sandbox/package.json +1 -1
  210. package/examples/extensions/ssh.ts +113 -24
  211. package/examples/extensions/with-deps/package-lock.json +2 -2
  212. package/examples/extensions/with-deps/package.json +1 -1
  213. package/npm-shrinkwrap.json +112 -12
  214. package/package.json +7 -5
@@ -6,6 +6,8 @@ import type { LaneWorkerRefusal } from "../model-capability.ts";
6
6
  * with no direct dependency on `AgentSession`/`ExtensionRunner`/`BackgroundLaneController`.
7
7
  */
8
8
  export interface TmuxDispatchDeps {
9
+ /** Runtime platform seam. Native Windows has no supported tmux backend; WSL reports `linux`. */
10
+ platform?: NodeJS.Platform;
9
11
  /** Look up a registered tool by name -- the SAME seam the model's own tool calls resolve
10
12
  * through (`AgentSession.getToolDefinition` -> `RuntimeBuilder.getToolDefinition`). `undefined`
11
13
  * when the tmux extension is not loaded in this session -- an honest, non-fatal skip, not a
@@ -1 +1 @@
1
- {"version":3,"file":"tmux-dispatch.d.ts","sourceRoot":"","sources":["../../../src/core/tools/tmux-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;uCAGmC;IACnC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAChE;;0BAEsB;IACtB,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;IAC/C;;;;OAIG;IACH,oBAAoB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnE;;iDAE6C;IAC7C,SAAS,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACtB,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAC;CAChE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG5D;AASD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqEnD"}
1
+ {"version":3,"file":"tmux-dispatch.d.ts","sourceRoot":"","sources":["../../../src/core/tools/tmux-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAChC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B;;;uCAGmC;IACnC,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAChE;;0BAEsB;IACtB,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;IAC/C;;;;OAIG;IACH,oBAAoB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnE;;iDAE6C;IAC7C,SAAS,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACtB,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAAC;CAChE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG5D;AAaD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA+EnD"}
@@ -30,12 +30,27 @@ export async function dispatchTmuxWorker(deps, args) {
30
30
  if (deps.evaluateWorkerLaneRefusal?.() !== undefined) {
31
31
  return { skipReason: "worker_capability_insufficient" };
32
32
  }
33
+ if ((deps.platform ?? process.platform) === "win32")
34
+ return { skipReason: "tmux_unavailable" };
33
35
  const toolDef = deps.getToolDefinition("tmux_agent_manager");
34
36
  if (!toolDef)
35
37
  return { skipReason: "tmux_extension_not_loaded" };
36
38
  const goalId = deps.getGoalId();
37
39
  const ctx = deps.createExtensionContext();
38
- // Lane-first: when worktree-sync is wired, create the lane BEFORE any fire_task call so a
40
+ const toolCallId = `goal-dispatch:${goalId ?? "?"}:${args.requirementId}`;
41
+ try {
42
+ const guardResult = await toolDef.execute(`${toolCallId}:guard`, { action: "guard" }, ctx.signal, undefined, ctx);
43
+ const guard = guardResult.details?.guard;
44
+ if (guard?.allowed !== true)
45
+ return { skipReason: "tmux_unavailable" };
46
+ }
47
+ catch {
48
+ // A guard failure is side-effect free. Treat it as backend unavailability so the goal owner can
49
+ // safely choose its native worker fallback without fabricating a tmux lane.
50
+ return { skipReason: "tmux_unavailable" };
51
+ }
52
+ // Availability first, then lane-first: when worktree-sync is wired, create the lane only after
53
+ // tmux's pure guard succeeds and BEFORE any fire_task call so a
39
54
  // creation refusal (max lanes, invalid key, git error, ...) aborts cleanly with no tmux/pane side
40
55
  // effect ever having run. The specific engine refusal code is deliberately collapsed onto the one
41
56
  // stable `worktree_create_failed` skip reason -- same narrow `{laneId?, skipReason?}` contract
@@ -67,7 +82,6 @@ export async function dispatchTmuxWorker(deps, args) {
67
82
  : { provider: "pi", name: "goal-worker" },
68
83
  ],
69
84
  };
70
- const toolCallId = `goal-dispatch:${goalId ?? "?"}:${args.requirementId}`;
71
85
  let result;
72
86
  try {
73
87
  result = await toolDef.execute(toolCallId, params, ctx.signal, undefined, ctx);
@@ -1 +1 @@
1
- {"version":3,"file":"tmux-dispatch.js","sourceRoot":"","sources":["../../../src/core/tools/tmux-dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport type { LaneWorkerRefusal } from \"../model-capability.ts\";\n\n/**\n * Dependencies for {@link dispatchTmuxWorker}, injected from the construction site\n * (`RuntimeBuilder`) so the adapter itself stays a small, unit-testable, faux-tool-driven module\n * with no direct dependency on `AgentSession`/`ExtensionRunner`/`BackgroundLaneController`.\n */\nexport interface TmuxDispatchDeps {\n\t/** Look up a registered tool by name -- the SAME seam the model's own tool calls resolve\n\t * through (`AgentSession.getToolDefinition` -> `RuntimeBuilder.getToolDefinition`). `undefined`\n\t * when the tmux extension is not loaded in this session -- an honest, non-fatal skip, not a\n\t * crash and not a silent no-op. */\n\tgetToolDefinition: (name: string) => ToolDefinition | undefined;\n\t/** Build a fresh, non-turn-bound `ExtensionContext` for this call\n\t * (`ExtensionRunner.createContext()`) -- safe to invoke from the goal/idle path, outside any\n\t * live model turn. */\n\tcreateExtensionContext: () => ExtensionContext;\n\t/**\n\t * Confirm that the tmux extension's caller-chosen lane id (reconstructed below from the\n\t * `fire_task` result's `details.job`) was durably registered by the host. The returned id is\n\t * identity-preserving and is the same value `Requirement.boundLaneId` uses.\n\t */\n\tresolveManagedLaneId: (callerLaneId: string) => string | undefined;\n\t/** Active goal id, threaded onto the `fire_task` call so the dispatched lane is goal-tagged\n\t * (`ManagedLaneEvent.goalId`) -- `undefined` when no goal is active (dispatch still proceeds;\n\t * the resulting lane is simply untagged). */\n\tgetGoalId: () => string | undefined;\n\t/**\n\t * Worktree-sync lane-first dispatch (opt-in -- wired ONLY inside `runtime-builder.ts`'s\n\t * `worktreeSync.enabled` block, via the engine's `createLane`): when present, `dispatchTmuxWorker`\n\t * creates a fresh worktree-sync lane for this requirement BEFORE issuing any `fire_task` call, so\n\t * a creation refusal aborts cleanly before any tmux/pane side effect ever runs -- never a\n\t * half-made lane, never a fabricated worktree. On success the dispatched agent's `cwd` is the new\n\t * lane worktree and it carries `worktreeLane` (threaded to the tmux extension's launch profile --\n\t * see `dispatch-grant.ts`'s `buildLaunchProfileFlags`). Absent dep -> existing byte-identical\n\t * `params.agents` (no `cwd`/`worktreeLane`), exactly as before this field existed.\n\t */\n\tcreateLaneWorktree?: (args: {\n\t\tgoalId?: string;\n\t\trequirementId: string;\n\t}) => Promise<{ laneKey: string; worktreePath: string } | { skipReason: string }>;\n\t/**\n\t * Lane-worker capability eligibility (opt-in -- wired only from `runtime-builder.ts`, backed by\n\t * `AgentSession.getLaneWorkerRefusal`): checked FIRST, before `createLaneWorktree`, so an\n\t * ineligible model's dispatch is refused before any lane/pane side effect ever runs. This is the\n\t * parent's best-effort check only -- the dispatched child session refuses authoritatively at its\n\t * own startup (main.ts) regardless of what the parent decides here. Absent dep -> no capability\n\t * check runs, byte-identical to before this field existed.\n\t */\n\tevaluateWorkerLaneRefusal?: () => LaneWorkerRefusal | undefined;\n}\n\n/**\n * Classify a `fire_task` launch failure into an honest, stable skip reason. For an UNATTENDED\n * caller (`ctx.hasUI === false`, always true from the goal/idle path) `authorizeLaunch`'s ONLY\n * refusal throw is the no-standing-grant error (`tmux-agent-manager/index.ts`'s `authorizeLaunch`,\n * message containing the stable phrase \"no standing grant\") -- matched here by substring since the\n * extension throws a plain `Error`, not a tagged error code (documented follow-up hardening, not\n * blocking). Every other thrown error (a bad jobId, a live session-name collision,\n * an environment failure) maps onto the generic `\"tmux_dispatch_failed\"` -- still surfaced through\n * the existing `dispatchSkipReason` contract, never a crash and never a silently-ignored failure.\n */\nexport function classifyDispatchError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : String(error);\n\treturn message.includes(\"no standing grant\") ? \"no_standing_grant\" : \"tmux_dispatch_failed\";\n}\n\ninterface FireTaskResultDetails {\n\tjob?: {\n\t\tid?: string;\n\t\tagents?: ReadonlyArray<{ id?: string }>;\n\t};\n}\n\n/**\n * Structurally dispatch ONE persistent tmux worker agent for a single goal requirement, by\n * invoking the SAME `tmux_agent_manager` `fire_task` tool call the model itself would make. Core\n * -- not model discretion -- decides WHEN this fires (the goal tool's `dispatchTarget:\"tmux\"`\n * routing gates the call); the launch itself always still goes through the extension's own\n * grant-gated `authorizeLaunch`, so an ungranted unattended call is honestly refused here (never a\n * silent launch, never a fabricated laneId) and the refusal is surfaced through the existing\n * `dispatchSkipReason` contract on the goal tool's response.\n */\nexport async function dispatchTmuxWorker(\n\tdeps: TmuxDispatchDeps,\n\targs: { requirementId: string; instructions: string },\n): Promise<{ laneId?: string; skipReason?: string }> {\n\t// Capability check FIRST -- before the tool-definition lookup and before createLaneWorktree --\n\t// so an ineligible model's dispatch is refused with zero lane/pane/tool side effect. The coarse\n\t// \"worker_capability_insufficient\" skip reason is the stable contract code on the goal tool's\n\t// response; the granular reason (class/window/tool-calling) lives only in the refusal object\n\t// itself, surfaced by the caller for logging (see model-capability.ts's formatLaneWorkerRefusal).\n\tif (deps.evaluateWorkerLaneRefusal?.() !== undefined) {\n\t\treturn { skipReason: \"worker_capability_insufficient\" };\n\t}\n\n\tconst toolDef = deps.getToolDefinition(\"tmux_agent_manager\");\n\tif (!toolDef) return { skipReason: \"tmux_extension_not_loaded\" };\n\n\tconst goalId = deps.getGoalId();\n\tconst ctx = deps.createExtensionContext();\n\n\t// Lane-first: when worktree-sync is wired, create the lane BEFORE any fire_task call so a\n\t// creation refusal (max lanes, invalid key, git error, ...) aborts cleanly with no tmux/pane side\n\t// effect ever having run. The specific engine refusal code is deliberately collapsed onto the one\n\t// stable `worktree_create_failed` skip reason -- same narrow `{laneId?, skipReason?}` contract\n\t// every other skip path here already uses; the engine's own detail lives in its audit log, not in\n\t// this narrow return.\n\tlet laneWorktree: { laneKey: string; worktreePath: string } | undefined;\n\tif (deps.createLaneWorktree) {\n\t\tconst created = await deps.createLaneWorktree({ goalId, requirementId: args.requirementId });\n\t\tif (\"skipReason\" in created) return { skipReason: \"worktree_create_failed\" };\n\t\tlaneWorktree = created;\n\t}\n\n\t// Single-agent 1:1 mapping: a bare fire_task with no `agents` defaults to a THREE-agent\n\t// team (pi/agy/codex -- `DEFAULT_AGENT_PROVIDERS`), which would mint three lanes for one\n\t// requirement. A goal-bound dispatch must map to exactly one lane, so `agents` is always\n\t// passed explicitly here.\n\tconst params = {\n\t\taction: \"fire_task\",\n\t\ttask: args.instructions,\n\t\tgoalId,\n\t\tagents: [\n\t\t\tlaneWorktree\n\t\t\t\t? {\n\t\t\t\t\t\tprovider: \"pi\",\n\t\t\t\t\t\tname: \"goal-worker\",\n\t\t\t\t\t\tcwd: laneWorktree.worktreePath,\n\t\t\t\t\t\tworktreeLane: laneWorktree.laneKey,\n\t\t\t\t\t}\n\t\t\t\t: { provider: \"pi\", name: \"goal-worker\" },\n\t\t],\n\t};\n\tconst toolCallId = `goal-dispatch:${goalId ?? \"?\"}:${args.requirementId}`;\n\n\tlet result: Awaited<ReturnType<ToolDefinition[\"execute\"]>>;\n\ttry {\n\t\tresult = await toolDef.execute(toolCallId, params, ctx.signal, undefined, ctx);\n\t} catch (error) {\n\t\treturn { skipReason: classifyDispatchError(error) };\n\t}\n\n\t// Correlate: the extension reports its dispatch under its OWN caller-chosen laneId\n\t// (`tmux:${job.id}:${agent.id}`, reconstructed here from the tool result's `details.job` --\n\t// the same format `agentLaneId` builds extension-side) which the host's `recordManagedLane`\n\t// bridge preserves as the canonical durable id; `resolveManagedLaneId` confirms that the\n\t// matching dispatch report reached the host before the goal binds it.\n\tconst job = (result.details as FireTaskResultDetails | undefined)?.job;\n\tconst primary = job?.agents?.[0];\n\tif (!job?.id || !primary?.id) return { skipReason: \"tmux_dispatch_incomplete\" };\n\n\tconst callerLaneId = `tmux:${job.id}:${primary.id}`;\n\tconst registeredLaneId = deps.resolveManagedLaneId(callerLaneId);\n\treturn registeredLaneId === callerLaneId ? { laneId: callerLaneId } : { skipReason: \"lane_correlation_failed\" };\n}\n"]}
1
+ {"version":3,"file":"tmux-dispatch.js","sourceRoot":"","sources":["../../../src/core/tools/tmux-dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport type { LaneWorkerRefusal } from \"../model-capability.ts\";\n\n/**\n * Dependencies for {@link dispatchTmuxWorker}, injected from the construction site\n * (`RuntimeBuilder`) so the adapter itself stays a small, unit-testable, faux-tool-driven module\n * with no direct dependency on `AgentSession`/`ExtensionRunner`/`BackgroundLaneController`.\n */\nexport interface TmuxDispatchDeps {\n\t/** Runtime platform seam. Native Windows has no supported tmux backend; WSL reports `linux`. */\n\tplatform?: NodeJS.Platform;\n\t/** Look up a registered tool by name -- the SAME seam the model's own tool calls resolve\n\t * through (`AgentSession.getToolDefinition` -> `RuntimeBuilder.getToolDefinition`). `undefined`\n\t * when the tmux extension is not loaded in this session -- an honest, non-fatal skip, not a\n\t * crash and not a silent no-op. */\n\tgetToolDefinition: (name: string) => ToolDefinition | undefined;\n\t/** Build a fresh, non-turn-bound `ExtensionContext` for this call\n\t * (`ExtensionRunner.createContext()`) -- safe to invoke from the goal/idle path, outside any\n\t * live model turn. */\n\tcreateExtensionContext: () => ExtensionContext;\n\t/**\n\t * Confirm that the tmux extension's caller-chosen lane id (reconstructed below from the\n\t * `fire_task` result's `details.job`) was durably registered by the host. The returned id is\n\t * identity-preserving and is the same value `Requirement.boundLaneId` uses.\n\t */\n\tresolveManagedLaneId: (callerLaneId: string) => string | undefined;\n\t/** Active goal id, threaded onto the `fire_task` call so the dispatched lane is goal-tagged\n\t * (`ManagedLaneEvent.goalId`) -- `undefined` when no goal is active (dispatch still proceeds;\n\t * the resulting lane is simply untagged). */\n\tgetGoalId: () => string | undefined;\n\t/**\n\t * Worktree-sync lane-first dispatch (opt-in -- wired ONLY inside `runtime-builder.ts`'s\n\t * `worktreeSync.enabled` block, via the engine's `createLane`): when present, `dispatchTmuxWorker`\n\t * creates a fresh worktree-sync lane for this requirement BEFORE issuing any `fire_task` call, so\n\t * a creation refusal aborts cleanly before any tmux/pane side effect ever runs -- never a\n\t * half-made lane, never a fabricated worktree. On success the dispatched agent's `cwd` is the new\n\t * lane worktree and it carries `worktreeLane` (threaded to the tmux extension's launch profile --\n\t * see `dispatch-grant.ts`'s `buildLaunchProfileFlags`). Absent dep -> existing byte-identical\n\t * `params.agents` (no `cwd`/`worktreeLane`), exactly as before this field existed.\n\t */\n\tcreateLaneWorktree?: (args: {\n\t\tgoalId?: string;\n\t\trequirementId: string;\n\t}) => Promise<{ laneKey: string; worktreePath: string } | { skipReason: string }>;\n\t/**\n\t * Lane-worker capability eligibility (opt-in -- wired only from `runtime-builder.ts`, backed by\n\t * `AgentSession.getLaneWorkerRefusal`): checked FIRST, before `createLaneWorktree`, so an\n\t * ineligible model's dispatch is refused before any lane/pane side effect ever runs. This is the\n\t * parent's best-effort check only -- the dispatched child session refuses authoritatively at its\n\t * own startup (main.ts) regardless of what the parent decides here. Absent dep -> no capability\n\t * check runs, byte-identical to before this field existed.\n\t */\n\tevaluateWorkerLaneRefusal?: () => LaneWorkerRefusal | undefined;\n}\n\n/**\n * Classify a `fire_task` launch failure into an honest, stable skip reason. For an UNATTENDED\n * caller (`ctx.hasUI === false`, always true from the goal/idle path) `authorizeLaunch`'s ONLY\n * refusal throw is the no-standing-grant error (`tmux-agent-manager/index.ts`'s `authorizeLaunch`,\n * message containing the stable phrase \"no standing grant\") -- matched here by substring since the\n * extension throws a plain `Error`, not a tagged error code (documented follow-up hardening, not\n * blocking). Every other thrown error (a bad jobId, a live session-name collision,\n * an environment failure) maps onto the generic `\"tmux_dispatch_failed\"` -- still surfaced through\n * the existing `dispatchSkipReason` contract, never a crash and never a silently-ignored failure.\n */\nexport function classifyDispatchError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : String(error);\n\treturn message.includes(\"no standing grant\") ? \"no_standing_grant\" : \"tmux_dispatch_failed\";\n}\n\ninterface FireTaskResultDetails {\n\tjob?: {\n\t\tid?: string;\n\t\tagents?: ReadonlyArray<{ id?: string }>;\n\t};\n}\n\ninterface TmuxGuardResultDetails {\n\tguard?: { allowed?: boolean };\n}\n\n/**\n * Structurally dispatch ONE persistent tmux worker agent for a single goal requirement, by\n * invoking the SAME `tmux_agent_manager` `fire_task` tool call the model itself would make. Core\n * -- not model discretion -- decides WHEN this fires (the goal tool's `dispatchTarget:\"tmux\"`\n * routing gates the call); the launch itself always still goes through the extension's own\n * grant-gated `authorizeLaunch`, so an ungranted unattended call is honestly refused here (never a\n * silent launch, never a fabricated laneId) and the refusal is surfaced through the existing\n * `dispatchSkipReason` contract on the goal tool's response.\n */\nexport async function dispatchTmuxWorker(\n\tdeps: TmuxDispatchDeps,\n\targs: { requirementId: string; instructions: string },\n): Promise<{ laneId?: string; skipReason?: string }> {\n\t// Capability check FIRST -- before the tool-definition lookup and before createLaneWorktree --\n\t// so an ineligible model's dispatch is refused with zero lane/pane/tool side effect. The coarse\n\t// \"worker_capability_insufficient\" skip reason is the stable contract code on the goal tool's\n\t// response; the granular reason (class/window/tool-calling) lives only in the refusal object\n\t// itself, surfaced by the caller for logging (see model-capability.ts's formatLaneWorkerRefusal).\n\tif (deps.evaluateWorkerLaneRefusal?.() !== undefined) {\n\t\treturn { skipReason: \"worker_capability_insufficient\" };\n\t}\n\tif ((deps.platform ?? process.platform) === \"win32\") return { skipReason: \"tmux_unavailable\" };\n\n\tconst toolDef = deps.getToolDefinition(\"tmux_agent_manager\");\n\tif (!toolDef) return { skipReason: \"tmux_extension_not_loaded\" };\n\n\tconst goalId = deps.getGoalId();\n\tconst ctx = deps.createExtensionContext();\n\tconst toolCallId = `goal-dispatch:${goalId ?? \"?\"}:${args.requirementId}`;\n\ttry {\n\t\tconst guardResult = await toolDef.execute(`${toolCallId}:guard`, { action: \"guard\" }, ctx.signal, undefined, ctx);\n\t\tconst guard = (guardResult.details as TmuxGuardResultDetails | undefined)?.guard;\n\t\tif (guard?.allowed !== true) return { skipReason: \"tmux_unavailable\" };\n\t} catch {\n\t\t// A guard failure is side-effect free. Treat it as backend unavailability so the goal owner can\n\t\t// safely choose its native worker fallback without fabricating a tmux lane.\n\t\treturn { skipReason: \"tmux_unavailable\" };\n\t}\n\n\t// Availability first, then lane-first: when worktree-sync is wired, create the lane only after\n\t// tmux's pure guard succeeds and BEFORE any fire_task call so a\n\t// creation refusal (max lanes, invalid key, git error, ...) aborts cleanly with no tmux/pane side\n\t// effect ever having run. The specific engine refusal code is deliberately collapsed onto the one\n\t// stable `worktree_create_failed` skip reason -- same narrow `{laneId?, skipReason?}` contract\n\t// every other skip path here already uses; the engine's own detail lives in its audit log, not in\n\t// this narrow return.\n\tlet laneWorktree: { laneKey: string; worktreePath: string } | undefined;\n\tif (deps.createLaneWorktree) {\n\t\tconst created = await deps.createLaneWorktree({ goalId, requirementId: args.requirementId });\n\t\tif (\"skipReason\" in created) return { skipReason: \"worktree_create_failed\" };\n\t\tlaneWorktree = created;\n\t}\n\n\t// Single-agent 1:1 mapping: a bare fire_task with no `agents` defaults to a THREE-agent\n\t// team (pi/agy/codex -- `DEFAULT_AGENT_PROVIDERS`), which would mint three lanes for one\n\t// requirement. A goal-bound dispatch must map to exactly one lane, so `agents` is always\n\t// passed explicitly here.\n\tconst params = {\n\t\taction: \"fire_task\",\n\t\ttask: args.instructions,\n\t\tgoalId,\n\t\tagents: [\n\t\t\tlaneWorktree\n\t\t\t\t? {\n\t\t\t\t\t\tprovider: \"pi\",\n\t\t\t\t\t\tname: \"goal-worker\",\n\t\t\t\t\t\tcwd: laneWorktree.worktreePath,\n\t\t\t\t\t\tworktreeLane: laneWorktree.laneKey,\n\t\t\t\t\t}\n\t\t\t\t: { provider: \"pi\", name: \"goal-worker\" },\n\t\t],\n\t};\n\tlet result: Awaited<ReturnType<ToolDefinition[\"execute\"]>>;\n\ttry {\n\t\tresult = await toolDef.execute(toolCallId, params, ctx.signal, undefined, ctx);\n\t} catch (error) {\n\t\treturn { skipReason: classifyDispatchError(error) };\n\t}\n\n\t// Correlate: the extension reports its dispatch under its OWN caller-chosen laneId\n\t// (`tmux:${job.id}:${agent.id}`, reconstructed here from the tool result's `details.job` --\n\t// the same format `agentLaneId` builds extension-side) which the host's `recordManagedLane`\n\t// bridge preserves as the canonical durable id; `resolveManagedLaneId` confirms that the\n\t// matching dispatch report reached the host before the goal binds it.\n\tconst job = (result.details as FireTaskResultDetails | undefined)?.job;\n\tconst primary = job?.agents?.[0];\n\tif (!job?.id || !primary?.id) return { skipReason: \"tmux_dispatch_incomplete\" };\n\n\tconst callerLaneId = `tmux:${job.id}:${primary.id}`;\n\tconst registeredLaneId = deps.resolveManagedLaneId(callerLaneId);\n\treturn registeredLaneId === callerLaneId ? { laneId: callerLaneId } : { skipReason: \"lane_correlation_failed\" };\n}\n"]}
@@ -99,7 +99,7 @@ function parseControlFrame(buffer) {
99
99
  return { kind: "invalid" };
100
100
  }
101
101
  function degradationError(outcome) {
102
- return new Error(`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore pipelines, redirection, expansion, and chaining.`);
102
+ return new Error(`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore for loops, portable builtins such as printf, pipelines, redirection, expansion, and chaining.`);
103
103
  }
104
104
  class PersistentWindowsShellEngineSession {
105
105
  constructor(key, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"windows-shell-engine.js","sourceRoot":"","sources":["../../../src/core/tools/windows-shell-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent Windows Python shell-engine sessions.\n *\n * One coordinator process is keyed to each agent session. Requests are serialized as JSON lines;\n * Node remains the sole owner of cwd/environment state and derives each request only after the\n * preceding terminal frame has been applied. Command bytes stream on stdout, followed by a\n * request-specific output barrier. A correlated control frame arrives on stderr. Requiring both\n * channels before settlement prevents cross-pipe tail loss and stale-frame reuse.\n *\n * Timeout, abort, protocol failure, or coordinator death resets the whole process tree. The next\n * request starts a clean coordinator from the last state Node actually acknowledged.\n */\n\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { getBundledResourcesDir } from \"../../config.ts\";\nimport { spawnProcess } from \"../../utils/child-process.ts\";\nimport { getShellConfig, getShellEnv } from \"../../utils/shell.ts\";\nimport { ensurePythonRuntime, type PythonRuntimeOutcome } from \"../python-runtime.ts\";\nimport { isRecordObject } from \"../util/value-guards.ts\";\nimport type { BashOperations } from \"./bash.ts\";\nimport { PersistentProcessCoordinator } from \"./persistent-process-coordinator.ts\";\nimport { tokenizeShellCommand } from \"./shell-command-parser.ts\";\nimport {\n\tapplyEngineFrame,\n\tgetOrCreateWindowsShellState,\n\tmergeEffectiveEnv,\n\tresolveEffectiveCwd,\n\ttype WindowsShellState,\n} from \"./windows-shell-state.ts\";\n\nconst ENGINE_FRAME_SENTINEL = 0x1e;\nconst MAX_CONTROL_FRAME_BYTES = 64 * 1024;\nconst SOFT_DEADLINE_HEADSTART_MS = 100;\n\n/** State/result fields returned for every completed engine command. */\nexport interface WindowsShellEngineFrame {\n\texitCode: number;\n\tcwd: string;\n\tenvDelta: Record<string, string | null>;\n\tunsupported: { code: \"unsupported\"; construct: string; message: string } | null;\n}\n\ninterface WindowsShellEngineControlFrame extends WindowsShellEngineFrame {\n\trequestId: string;\n}\n\ninterface WindowsShellEngineRequest {\n\trequestId: string;\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n\tpowershellPath?: string;\n\ttimeoutMs?: number;\n}\n\ninterface ParsedControlFrame {\n\tkind: \"frame\";\n\tframe: WindowsShellEngineControlFrame;\n\tframeStart: number;\n\tframeEnd: number;\n}\n\ninterface InvalidControlFrame {\n\tkind: \"invalid\";\n}\n\ninterface ActiveEngineExec {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonChildClose(code: number | null): void;\n\tfail(error: Error): void;\n}\n\nexport class WindowsShellEngineFailure extends Error {\n\treadonly capturedOutput: string;\n\n\tconstructor(message: string, capturedOutput: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WindowsShellEngineFailure\";\n\t\tthis.capturedOutput = capturedOutput;\n\t}\n}\n\nfunction resolveEngineScriptPath(): string {\n\treturn join(getBundledResourcesDir(), \"runtimes\", \"pi-shell-engine\", \"main.py\");\n}\n\nfunction invokesPowerShellScript(command: string): boolean {\n\tconst tokens = tokenizeShellCommand(command);\n\t// An unparseable command is already heading to the authoritative Python parser;\n\t// resolve conservatively so script adaptation cannot lose an explicit host choice.\n\tif (!tokens) return /\\.ps1\\b/iu.test(command);\n\n\tlet atCommandStart = true;\n\tlet skipRedirectTarget = false;\n\tfor (const token of tokens) {\n\t\tif (token.kind === \"operator\" || token.kind === \"pipe\") {\n\t\t\tatCommandStart = true;\n\t\t\tskipRedirectTarget = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.kind === \"redirect\") {\n\t\t\tskipRedirectTarget = !/^\\d*[<>]&[\\d-]+$/u.test(token.value);\n\t\t\tcontinue;\n\t\t}\n\t\tif (skipRedirectTarget) {\n\t\t\tskipRedirectTarget = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!atCommandStart || /^[A-Za-z_][A-Za-z0-9_]*=/u.test(token.value)) continue;\n\t\tif (token.value.toLowerCase().endsWith(\".ps1\")) return true;\n\t\tatCommandStart = false;\n\t}\n\treturn false;\n}\n\nfunction parseControlFrame(buffer: Buffer): ParsedControlFrame | InvalidControlFrame | undefined {\n\tconst frameStart = buffer.indexOf(ENGINE_FRAME_SENTINEL);\n\tif (frameStart === -1) return undefined;\n\tconst closeIndex = buffer.indexOf(ENGINE_FRAME_SENTINEL, frameStart + 1);\n\tif (closeIndex === -1) return undefined;\n\ttry {\n\t\tconst raw: unknown = JSON.parse(buffer.subarray(frameStart + 1, closeIndex).toString(\"utf8\"));\n\t\tif (\n\t\t\tisRecordObject(raw) &&\n\t\t\ttypeof raw.requestId === \"string\" &&\n\t\t\t/^[0-9a-f]{16}$/u.test(raw.requestId) &&\n\t\t\ttypeof raw.exitCode === \"number\" &&\n\t\t\tNumber.isInteger(raw.exitCode) &&\n\t\t\ttypeof raw.cwd === \"string\" &&\n\t\t\tisRecordObject(raw.envDelta) &&\n\t\t\t(raw.unsupported === null || isRecordObject(raw.unsupported)) &&\n\t\t\t(raw.unsupported === null ||\n\t\t\t\t(raw.unsupported.code === \"unsupported\" &&\n\t\t\t\t\ttypeof raw.unsupported.construct === \"string\" &&\n\t\t\t\t\ttypeof raw.unsupported.message === \"string\")) &&\n\t\t\tObject.values(raw.envDelta).every((value) => value === null || typeof value === \"string\")\n\t\t) {\n\t\t\treturn {\n\t\t\t\tkind: \"frame\",\n\t\t\t\tframe: raw as unknown as WindowsShellEngineControlFrame,\n\t\t\t\tframeStart,\n\t\t\t\tframeEnd: closeIndex + 1,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// A complete delimited record that is not JSON is a terminal protocol fault.\n\t}\n\treturn { kind: \"invalid\" };\n}\n\nexport interface WindowsShellEngineOptions {\n\t/** Override for tests: resolves the Python runtime outcome. Default: `ensurePythonRuntime`. */\n\tresolveRuntime?: () => Promise<PythonRuntimeOutcome>;\n\t/** Override for tests: absolute path to the engine's `main.py`. Default: the bundled runtime. */\n\tengineScriptPath?: string;\n\t/** Override for tests: the per-session state store lookup. Default: the shared module store. */\n\tgetState?: (sessionKey: string) => WindowsShellState;\n\t/** Override for tests: spawns the persistent coordinator. Default: `spawnProcess`. */\n\tspawn?: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\t/** Override for tests: selected PowerShell host used to adapt `.ps1` external commands. */\n\tresolvePowerShellPath?: () => string;\n}\n\nfunction degradationError(\n\toutcome: Extract<PythonRuntimeOutcome, { status: \"offline\" | \"uv-unavailable\" | \"python-unavailable\" }>,\n): Error {\n\treturn new Error(\n\t\t`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore pipelines, redirection, expansion, and chaining.`,\n\t);\n}\n\nclass PersistentWindowsShellEngineSession {\n\tprivate readonly key: string;\n\tprivate readonly resolveRuntime: () => Promise<PythonRuntimeOutcome>;\n\tprivate readonly engineScriptPath: string;\n\tprivate readonly getState: (sessionKey: string) => WindowsShellState;\n\tprivate readonly spawn: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\tprivate readonly resolvePowerShellPath: () => string;\n\tprivate readonly coordinator = new PersistentProcessCoordinator();\n\tprivate activeExec: ActiveEngineExec | null = null;\n\tprivate disposed = false;\n\n\tconstructor(key: string, options: WindowsShellEngineOptions) {\n\t\tthis.key = key;\n\t\tthis.resolveRuntime = options.resolveRuntime ?? (() => ensurePythonRuntime({ silent: true }));\n\t\tthis.engineScriptPath = options.engineScriptPath ?? resolveEngineScriptPath();\n\t\tthis.getState = options.getState ?? getOrCreateWindowsShellState;\n\t\tthis.spawn = options.spawn ?? spawnProcess;\n\t\tthis.resolvePowerShellPath =\n\t\t\toptions.resolvePowerShellPath ??\n\t\t\t(() => (process.platform === \"win32\" ? getShellConfig(undefined, \"powershell\").shell : \"powershell\"));\n\t}\n\n\texec(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: Parameters<BashOperations[\"exec\"]>[2],\n\t): Promise<{ exitCode: number | null }> {\n\t\treturn this.coordinator.runSerialized(() => this.execNow(command, cwd, options));\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tconst active = this.activeExec;\n\t\tthis.coordinator.dispose();\n\t\tactive?.fail(new Error(`Windows shell engine session \"${this.key}\" is disposed`));\n\t}\n\n\tprivate async execNow(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\t{ onData, signal, timeout, env }: Parameters<BashOperations[\"exec\"]>[2],\n\t): Promise<{ exitCode: number | null }> {\n\t\tif (this.disposed) throw new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\n\t\tconst state = this.getState(this.key);\n\t\tconst effectiveCwd = resolveEffectiveCwd(state, cwd);\n\t\tconst effectiveEnv = mergeEffectiveEnv(state, env ?? getShellEnv());\n\t\tconst child = await this.ensureChild(effectiveEnv);\n\t\tif (this.disposed) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\t\t}\n\t\tif (signal?.aborted) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(\"aborted\");\n\t\t}\n\t\tif (!child.stdin || !child.stdout || !child.stderr || child !== this.coordinator.child) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(\"Failed to start Windows shell engine coordinator\");\n\t\t}\n\n\t\tconst timeoutMs = timeout !== undefined && timeout > 0 ? timeout * 1000 : undefined;\n\t\tconst requestTimeoutMs =\n\t\t\ttimeoutMs !== undefined ? Math.max(timeoutMs - SOFT_DEADLINE_HEADSTART_MS, 1) : undefined;\n\t\tconst requestId = randomBytes(8).toString(\"hex\");\n\t\tconst request: WindowsShellEngineRequest = {\n\t\t\trequestId,\n\t\t\tcommand,\n\t\t\tcwd: effectiveCwd,\n\t\t\tenv: effectiveEnv,\n\t\t\t...(invokesPowerShellScript(command) ? { powershellPath: this.resolvePowerShellPath() } : {}),\n\t\t\t...(requestTimeoutMs !== undefined ? { timeoutMs: requestTimeoutMs } : {}),\n\t\t};\n\t\tconst outputBarrier = Buffer.from(`\\x1e${requestId}\\x1e`, \"latin1\");\n\n\t\tthis.coordinator.setLoopRef(true);\n\t\ttry {\n\t\t\treturn await new Promise<{ exitCode: number | null }>((resolve, reject) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tlet pendingOutput: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n\t\t\t\tlet controlBuffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n\t\t\t\tlet controlOverflow = false;\n\t\t\t\tlet sawOutputBarrier = false;\n\t\t\t\tlet controlFrame: WindowsShellEngineControlFrame | undefined;\n\t\t\t\tlet completionScheduled = false;\n\t\t\t\tlet timeoutTimer: NodeJS.Timeout | undefined;\n\n\t\t\t\tconst settle = (finish: () => void): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (this.activeExec === active) this.activeExec = null;\n\t\t\t\t\tfinish();\n\t\t\t\t};\n\n\t\t\t\tconst emitPending = (upTo: number): void => {\n\t\t\t\t\tif (upTo <= 0) return;\n\t\t\t\t\tonData(pendingOutput.subarray(0, upTo));\n\t\t\t\t\tpendingOutput = pendingOutput.subarray(upTo);\n\t\t\t\t};\n\n\t\t\t\tconst capturedControl = (): string =>\n\t\t\t\t\tcontrolOverflow\n\t\t\t\t\t\t? `control frame exceeded ${MAX_CONTROL_FRAME_BYTES} bytes`\n\t\t\t\t\t\t: controlBuffer.toString(\"utf8\");\n\n\t\t\t\tconst failAndReset = (error: Error): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\temitPending(pendingOutput.length);\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t};\n\n\t\t\t\tconst protocolFailure = (message: string): WindowsShellEngineFailure => {\n\t\t\t\t\tconst capturedOutput = capturedControl();\n\t\t\t\t\treturn new WindowsShellEngineFailure(`${message}\\n${capturedOutput}`, capturedOutput);\n\t\t\t\t};\n\n\t\t\t\tconst maybeComplete = (): void => {\n\t\t\t\t\tif (!sawOutputBarrier || !controlFrame || settled || completionScheduled) return;\n\t\t\t\t\tcompletionScheduled = true;\n\t\t\t\t\t// stdout and stderr are independent pipes. Keep this request active through the\n\t\t\t\t\t// next check phase so already-delivered post-barrier bytes are rejected here,\n\t\t\t\t\t// never forwarded into a queued request that starts in a promise microtask.\n\t\t\t\t\tsetImmediate(() => {\n\t\t\t\t\t\tif (settled || this.activeExec !== active || !controlFrame) return;\n\t\t\t\t\t\tapplyEngineFrame(state, controlFrame);\n\t\t\t\t\t\tif (controlFrame.unsupported) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\treject(new Error(controlFrame?.unsupported?.message ?? \"Unsupported shell construct\")),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsettle(() => resolve({ exitCode: controlFrame?.exitCode ?? null }));\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tconst onAbort = (): void => failAndReset(new Error(\"aborted\"));\n\n\t\t\t\tconst active: ActiveEngineExec = {\n\t\t\t\t\tonStdout: (data) => {\n\t\t\t\t\t\tif (sawOutputBarrier) {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted output after its terminal barrier.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpendingOutput = pendingOutput.length === 0 ? data : Buffer.concat([pendingOutput, data]);\n\t\t\t\t\t\tconst barrierIndex = pendingOutput.indexOf(outputBarrier);\n\t\t\t\t\t\tif (barrierIndex !== -1) {\n\t\t\t\t\t\t\temitPending(barrierIndex);\n\t\t\t\t\t\t\tpendingOutput = pendingOutput.subarray(outputBarrier.length);\n\t\t\t\t\t\t\tif (pendingOutput.length > 0) {\n\t\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted bytes after its terminal barrier.\"));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsawOutputBarrier = true;\n\t\t\t\t\t\t\tmaybeComplete();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\temitPending(pendingOutput.length - (outputBarrier.length - 1));\n\t\t\t\t\t},\n\t\t\t\t\tonStderr: (data) => {\n\t\t\t\t\t\tif (controlOverflow) return;\n\t\t\t\t\t\tif (controlBuffer.length + data.length > MAX_CONTROL_FRAME_BYTES) {\n\t\t\t\t\t\t\tcontrolOverflow = true;\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine control frame overflowed.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontrolBuffer = controlBuffer.length === 0 ? data : Buffer.concat([controlBuffer, data]);\n\t\t\t\t\t\tconst parsed = parseControlFrame(controlBuffer);\n\t\t\t\t\t\tif (!parsed) return;\n\t\t\t\t\t\tif (parsed.kind === \"invalid\") {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine returned a malformed control frame.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (parsed.frame.requestId !== requestId) {\n\t\t\t\t\t\t\tfailAndReset(\n\t\t\t\t\t\t\t\tprotocolFailure(\n\t\t\t\t\t\t\t\t\t`Windows shell engine returned stale control frame ${parsed.frame.requestId}; expected ${requestId}.`,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (controlBuffer.subarray(parsed.frameEnd).toString(\"utf8\").trim().length > 0) {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted trailing control bytes.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontrolFrame = parsed.frame;\n\t\t\t\t\t\tmaybeComplete();\n\t\t\t\t\t},\n\t\t\t\t\tonChildClose: (code) => {\n\t\t\t\t\t\tconst capturedOutput = capturedControl();\n\t\t\t\t\t\temitPending(pendingOutput.length);\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew WindowsShellEngineFailure(\n\t\t\t\t\t\t\t\t\t`Windows shell engine coordinator exited (${code ?? \"null\"}) before a complete terminal handoff.\\n${capturedOutput}`,\n\t\t\t\t\t\t\t\t\tcapturedOutput,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tfail: (error) => failAndReset(error),\n\t\t\t\t};\n\n\t\t\t\tthis.activeExec = active;\n\t\t\t\tif (signal) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutTimer = setTimeout(() => failAndReset(new Error(`timeout:${timeout}`)), timeoutMs);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tchild.stdin?.write(`${JSON.stringify(request)}\\n`, \"utf8\", (error) => {\n\t\t\t\t\t\tif (!error) return;\n\t\t\t\t\t\tfailAndReset(new Error(`Failed to write to Windows shell engine coordinator: ${error.message}`));\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tfailAndReset(new Error(`Failed to write to Windows shell engine coordinator: ${message}`));\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.coordinator.setLoopRef(false);\n\t\t}\n\t}\n\n\tprivate async ensureChild(env: NodeJS.ProcessEnv): Promise<ChildProcess> {\n\t\tif (this.coordinator.child) return this.coordinator.child;\n\t\tconst runtime = await this.resolveRuntime();\n\t\tif (runtime.status !== \"ready\") throw degradationError(runtime);\n\t\tif (this.disposed) throw new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\n\t\tconst child = this.spawn(runtime.pythonPath, [\"-B\", this.engineScriptPath, \"--server\"], {\n\t\t\tcwd: dirname(this.engineScriptPath),\n\t\t\tenv: {\n\t\t\t\t...env,\n\t\t\t\tPYTHONDONTWRITEBYTECODE: \"1\",\n\t\t\t\tPYTHONIOENCODING: \"utf-8\",\n\t\t\t\tPYTHONUNBUFFERED: \"1\",\n\t\t\t\tPYTHONUTF8: \"1\",\n\t\t\t},\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: true,\n\t\t});\n\t\tthis.coordinator.attach(child, {\n\t\t\tonStdout: (data) => {\n\t\t\t\tconst active = this.activeExec;\n\t\t\t\tif (active) active.onStdout(data);\n\t\t\t\telse if (data.length > 0) this.killChild();\n\t\t\t},\n\t\t\tonStderr: (data) => {\n\t\t\t\tconst active = this.activeExec;\n\t\t\t\tif (active) active.onStderr(data);\n\t\t\t\telse if (data.length > 0) this.killChild();\n\t\t\t},\n\t\t\tonError: (error) => this.activeExec?.fail(error),\n\t\t\tonClose: (code) => this.activeExec?.onChildClose(code),\n\t\t});\n\t\treturn child;\n\t}\n\n\tprivate killChild(): void {\n\t\tthis.coordinator.kill();\n\t}\n}\n\nconst engineSessions = new Map<string, PersistentWindowsShellEngineSession>();\n\nfunction acquireWindowsShellEngineSession(\n\tkey: string,\n\toptions: WindowsShellEngineOptions,\n): PersistentWindowsShellEngineSession {\n\tconst existing = engineSessions.get(key);\n\tif (existing) return existing;\n\tconst session = new PersistentWindowsShellEngineSession(key, options);\n\tengineSessions.set(key, session);\n\treturn session;\n}\n\n/** Kill and forget a Python coordinator. The next call for this key starts a clean process. */\nexport function disposeWindowsShellEngineSession(key: string): void {\n\tconst session = engineSessions.get(key);\n\tif (!session) return;\n\tengineSessions.delete(key);\n\tsession.dispose();\n}\n\n/** Create the Python-engine tier for one bash-tool session. */\nexport function createWindowsShellEngineOperations(\n\tsessionKey: string,\n\toptions: WindowsShellEngineOptions = {},\n): BashOperations {\n\treturn {\n\t\t// Resolve through the registry for every command. Session teardown (for example after\n\t\t// credential/environment changes) deletes only this tenant's entry; an already-built tool\n\t\t// then lazily acquires a fresh coordinator instead of retaining the disposed instance.\n\t\texec: (command, cwd, execOptions) =>\n\t\t\tacquireWindowsShellEngineSession(sessionKey, options).exec(command, cwd, execOptions),\n\t};\n}\n"]}
1
+ {"version":3,"file":"windows-shell-engine.js","sourceRoot":"","sources":["../../../src/core/tools/windows-shell-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent Windows Python shell-engine sessions.\n *\n * One coordinator process is keyed to each agent session. Requests are serialized as JSON lines;\n * Node remains the sole owner of cwd/environment state and derives each request only after the\n * preceding terminal frame has been applied. Command bytes stream on stdout, followed by a\n * request-specific output barrier. A correlated control frame arrives on stderr. Requiring both\n * channels before settlement prevents cross-pipe tail loss and stale-frame reuse.\n *\n * Timeout, abort, protocol failure, or coordinator death resets the whole process tree. The next\n * request starts a clean coordinator from the last state Node actually acknowledged.\n */\n\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { getBundledResourcesDir } from \"../../config.ts\";\nimport { spawnProcess } from \"../../utils/child-process.ts\";\nimport { getShellConfig, getShellEnv } from \"../../utils/shell.ts\";\nimport { ensurePythonRuntime, type PythonRuntimeOutcome } from \"../python-runtime.ts\";\nimport { isRecordObject } from \"../util/value-guards.ts\";\nimport type { BashOperations } from \"./bash.ts\";\nimport { PersistentProcessCoordinator } from \"./persistent-process-coordinator.ts\";\nimport { tokenizeShellCommand } from \"./shell-command-parser.ts\";\nimport {\n\tapplyEngineFrame,\n\tgetOrCreateWindowsShellState,\n\tmergeEffectiveEnv,\n\tresolveEffectiveCwd,\n\ttype WindowsShellState,\n} from \"./windows-shell-state.ts\";\n\nconst ENGINE_FRAME_SENTINEL = 0x1e;\nconst MAX_CONTROL_FRAME_BYTES = 64 * 1024;\nconst SOFT_DEADLINE_HEADSTART_MS = 100;\n\n/** State/result fields returned for every completed engine command. */\nexport interface WindowsShellEngineFrame {\n\texitCode: number;\n\tcwd: string;\n\tenvDelta: Record<string, string | null>;\n\tunsupported: { code: \"unsupported\"; construct: string; message: string } | null;\n}\n\ninterface WindowsShellEngineControlFrame extends WindowsShellEngineFrame {\n\trequestId: string;\n}\n\ninterface WindowsShellEngineRequest {\n\trequestId: string;\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n\tpowershellPath?: string;\n\ttimeoutMs?: number;\n}\n\ninterface ParsedControlFrame {\n\tkind: \"frame\";\n\tframe: WindowsShellEngineControlFrame;\n\tframeStart: number;\n\tframeEnd: number;\n}\n\ninterface InvalidControlFrame {\n\tkind: \"invalid\";\n}\n\ninterface ActiveEngineExec {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonChildClose(code: number | null): void;\n\tfail(error: Error): void;\n}\n\nexport class WindowsShellEngineFailure extends Error {\n\treadonly capturedOutput: string;\n\n\tconstructor(message: string, capturedOutput: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WindowsShellEngineFailure\";\n\t\tthis.capturedOutput = capturedOutput;\n\t}\n}\n\nfunction resolveEngineScriptPath(): string {\n\treturn join(getBundledResourcesDir(), \"runtimes\", \"pi-shell-engine\", \"main.py\");\n}\n\nfunction invokesPowerShellScript(command: string): boolean {\n\tconst tokens = tokenizeShellCommand(command);\n\t// An unparseable command is already heading to the authoritative Python parser;\n\t// resolve conservatively so script adaptation cannot lose an explicit host choice.\n\tif (!tokens) return /\\.ps1\\b/iu.test(command);\n\n\tlet atCommandStart = true;\n\tlet skipRedirectTarget = false;\n\tfor (const token of tokens) {\n\t\tif (token.kind === \"operator\" || token.kind === \"pipe\") {\n\t\t\tatCommandStart = true;\n\t\t\tskipRedirectTarget = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.kind === \"redirect\") {\n\t\t\tskipRedirectTarget = !/^\\d*[<>]&[\\d-]+$/u.test(token.value);\n\t\t\tcontinue;\n\t\t}\n\t\tif (skipRedirectTarget) {\n\t\t\tskipRedirectTarget = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!atCommandStart || /^[A-Za-z_][A-Za-z0-9_]*=/u.test(token.value)) continue;\n\t\tif (token.value.toLowerCase().endsWith(\".ps1\")) return true;\n\t\tatCommandStart = false;\n\t}\n\treturn false;\n}\n\nfunction parseControlFrame(buffer: Buffer): ParsedControlFrame | InvalidControlFrame | undefined {\n\tconst frameStart = buffer.indexOf(ENGINE_FRAME_SENTINEL);\n\tif (frameStart === -1) return undefined;\n\tconst closeIndex = buffer.indexOf(ENGINE_FRAME_SENTINEL, frameStart + 1);\n\tif (closeIndex === -1) return undefined;\n\ttry {\n\t\tconst raw: unknown = JSON.parse(buffer.subarray(frameStart + 1, closeIndex).toString(\"utf8\"));\n\t\tif (\n\t\t\tisRecordObject(raw) &&\n\t\t\ttypeof raw.requestId === \"string\" &&\n\t\t\t/^[0-9a-f]{16}$/u.test(raw.requestId) &&\n\t\t\ttypeof raw.exitCode === \"number\" &&\n\t\t\tNumber.isInteger(raw.exitCode) &&\n\t\t\ttypeof raw.cwd === \"string\" &&\n\t\t\tisRecordObject(raw.envDelta) &&\n\t\t\t(raw.unsupported === null || isRecordObject(raw.unsupported)) &&\n\t\t\t(raw.unsupported === null ||\n\t\t\t\t(raw.unsupported.code === \"unsupported\" &&\n\t\t\t\t\ttypeof raw.unsupported.construct === \"string\" &&\n\t\t\t\t\ttypeof raw.unsupported.message === \"string\")) &&\n\t\t\tObject.values(raw.envDelta).every((value) => value === null || typeof value === \"string\")\n\t\t) {\n\t\t\treturn {\n\t\t\t\tkind: \"frame\",\n\t\t\t\tframe: raw as unknown as WindowsShellEngineControlFrame,\n\t\t\t\tframeStart,\n\t\t\t\tframeEnd: closeIndex + 1,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// A complete delimited record that is not JSON is a terminal protocol fault.\n\t}\n\treturn { kind: \"invalid\" };\n}\n\nexport interface WindowsShellEngineOptions {\n\t/** Override for tests: resolves the Python runtime outcome. Default: `ensurePythonRuntime`. */\n\tresolveRuntime?: () => Promise<PythonRuntimeOutcome>;\n\t/** Override for tests: absolute path to the engine's `main.py`. Default: the bundled runtime. */\n\tengineScriptPath?: string;\n\t/** Override for tests: the per-session state store lookup. Default: the shared module store. */\n\tgetState?: (sessionKey: string) => WindowsShellState;\n\t/** Override for tests: spawns the persistent coordinator. Default: `spawnProcess`. */\n\tspawn?: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\t/** Override for tests: selected PowerShell host used to adapt `.ps1` external commands. */\n\tresolvePowerShellPath?: () => string;\n}\n\nfunction degradationError(\n\toutcome: Extract<PythonRuntimeOutcome, { status: \"offline\" | \"uv-unavailable\" | \"python-unavailable\" }>,\n): Error {\n\treturn new Error(\n\t\t`The Windows shell engine (Python) is unavailable: ${outcome.reason} The simple-command PowerShell floor still works; fix the Python runtime (uv/network) to restore for loops, portable builtins such as printf, pipelines, redirection, expansion, and chaining.`,\n\t);\n}\n\nclass PersistentWindowsShellEngineSession {\n\tprivate readonly key: string;\n\tprivate readonly resolveRuntime: () => Promise<PythonRuntimeOutcome>;\n\tprivate readonly engineScriptPath: string;\n\tprivate readonly getState: (sessionKey: string) => WindowsShellState;\n\tprivate readonly spawn: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\tprivate readonly resolvePowerShellPath: () => string;\n\tprivate readonly coordinator = new PersistentProcessCoordinator();\n\tprivate activeExec: ActiveEngineExec | null = null;\n\tprivate disposed = false;\n\n\tconstructor(key: string, options: WindowsShellEngineOptions) {\n\t\tthis.key = key;\n\t\tthis.resolveRuntime = options.resolveRuntime ?? (() => ensurePythonRuntime({ silent: true }));\n\t\tthis.engineScriptPath = options.engineScriptPath ?? resolveEngineScriptPath();\n\t\tthis.getState = options.getState ?? getOrCreateWindowsShellState;\n\t\tthis.spawn = options.spawn ?? spawnProcess;\n\t\tthis.resolvePowerShellPath =\n\t\t\toptions.resolvePowerShellPath ??\n\t\t\t(() => (process.platform === \"win32\" ? getShellConfig(undefined, \"powershell\").shell : \"powershell\"));\n\t}\n\n\texec(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: Parameters<BashOperations[\"exec\"]>[2],\n\t): Promise<{ exitCode: number | null }> {\n\t\treturn this.coordinator.runSerialized(() => this.execNow(command, cwd, options));\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tconst active = this.activeExec;\n\t\tthis.coordinator.dispose();\n\t\tactive?.fail(new Error(`Windows shell engine session \"${this.key}\" is disposed`));\n\t}\n\n\tprivate async execNow(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\t{ onData, signal, timeout, env }: Parameters<BashOperations[\"exec\"]>[2],\n\t): Promise<{ exitCode: number | null }> {\n\t\tif (this.disposed) throw new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\n\t\tconst state = this.getState(this.key);\n\t\tconst effectiveCwd = resolveEffectiveCwd(state, cwd);\n\t\tconst effectiveEnv = mergeEffectiveEnv(state, env ?? getShellEnv());\n\t\tconst child = await this.ensureChild(effectiveEnv);\n\t\tif (this.disposed) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\t\t}\n\t\tif (signal?.aborted) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(\"aborted\");\n\t\t}\n\t\tif (!child.stdin || !child.stdout || !child.stderr || child !== this.coordinator.child) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(\"Failed to start Windows shell engine coordinator\");\n\t\t}\n\n\t\tconst timeoutMs = timeout !== undefined && timeout > 0 ? timeout * 1000 : undefined;\n\t\tconst requestTimeoutMs =\n\t\t\ttimeoutMs !== undefined ? Math.max(timeoutMs - SOFT_DEADLINE_HEADSTART_MS, 1) : undefined;\n\t\tconst requestId = randomBytes(8).toString(\"hex\");\n\t\tconst request: WindowsShellEngineRequest = {\n\t\t\trequestId,\n\t\t\tcommand,\n\t\t\tcwd: effectiveCwd,\n\t\t\tenv: effectiveEnv,\n\t\t\t...(invokesPowerShellScript(command) ? { powershellPath: this.resolvePowerShellPath() } : {}),\n\t\t\t...(requestTimeoutMs !== undefined ? { timeoutMs: requestTimeoutMs } : {}),\n\t\t};\n\t\tconst outputBarrier = Buffer.from(`\\x1e${requestId}\\x1e`, \"latin1\");\n\n\t\tthis.coordinator.setLoopRef(true);\n\t\ttry {\n\t\t\treturn await new Promise<{ exitCode: number | null }>((resolve, reject) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tlet pendingOutput: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n\t\t\t\tlet controlBuffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);\n\t\t\t\tlet controlOverflow = false;\n\t\t\t\tlet sawOutputBarrier = false;\n\t\t\t\tlet controlFrame: WindowsShellEngineControlFrame | undefined;\n\t\t\t\tlet completionScheduled = false;\n\t\t\t\tlet timeoutTimer: NodeJS.Timeout | undefined;\n\n\t\t\t\tconst settle = (finish: () => void): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tif (this.activeExec === active) this.activeExec = null;\n\t\t\t\t\tfinish();\n\t\t\t\t};\n\n\t\t\t\tconst emitPending = (upTo: number): void => {\n\t\t\t\t\tif (upTo <= 0) return;\n\t\t\t\t\tonData(pendingOutput.subarray(0, upTo));\n\t\t\t\t\tpendingOutput = pendingOutput.subarray(upTo);\n\t\t\t\t};\n\n\t\t\t\tconst capturedControl = (): string =>\n\t\t\t\t\tcontrolOverflow\n\t\t\t\t\t\t? `control frame exceeded ${MAX_CONTROL_FRAME_BYTES} bytes`\n\t\t\t\t\t\t: controlBuffer.toString(\"utf8\");\n\n\t\t\t\tconst failAndReset = (error: Error): void => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\temitPending(pendingOutput.length);\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t};\n\n\t\t\t\tconst protocolFailure = (message: string): WindowsShellEngineFailure => {\n\t\t\t\t\tconst capturedOutput = capturedControl();\n\t\t\t\t\treturn new WindowsShellEngineFailure(`${message}\\n${capturedOutput}`, capturedOutput);\n\t\t\t\t};\n\n\t\t\t\tconst maybeComplete = (): void => {\n\t\t\t\t\tif (!sawOutputBarrier || !controlFrame || settled || completionScheduled) return;\n\t\t\t\t\tcompletionScheduled = true;\n\t\t\t\t\t// stdout and stderr are independent pipes. Keep this request active through the\n\t\t\t\t\t// next check phase so already-delivered post-barrier bytes are rejected here,\n\t\t\t\t\t// never forwarded into a queued request that starts in a promise microtask.\n\t\t\t\t\tsetImmediate(() => {\n\t\t\t\t\t\tif (settled || this.activeExec !== active || !controlFrame) return;\n\t\t\t\t\t\tapplyEngineFrame(state, controlFrame);\n\t\t\t\t\t\tif (controlFrame.unsupported) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\treject(new Error(controlFrame?.unsupported?.message ?? \"Unsupported shell construct\")),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsettle(() => resolve({ exitCode: controlFrame?.exitCode ?? null }));\n\t\t\t\t\t});\n\t\t\t\t};\n\n\t\t\t\tconst onAbort = (): void => failAndReset(new Error(\"aborted\"));\n\n\t\t\t\tconst active: ActiveEngineExec = {\n\t\t\t\t\tonStdout: (data) => {\n\t\t\t\t\t\tif (sawOutputBarrier) {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted output after its terminal barrier.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpendingOutput = pendingOutput.length === 0 ? data : Buffer.concat([pendingOutput, data]);\n\t\t\t\t\t\tconst barrierIndex = pendingOutput.indexOf(outputBarrier);\n\t\t\t\t\t\tif (barrierIndex !== -1) {\n\t\t\t\t\t\t\temitPending(barrierIndex);\n\t\t\t\t\t\t\tpendingOutput = pendingOutput.subarray(outputBarrier.length);\n\t\t\t\t\t\t\tif (pendingOutput.length > 0) {\n\t\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted bytes after its terminal barrier.\"));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsawOutputBarrier = true;\n\t\t\t\t\t\t\tmaybeComplete();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\temitPending(pendingOutput.length - (outputBarrier.length - 1));\n\t\t\t\t\t},\n\t\t\t\t\tonStderr: (data) => {\n\t\t\t\t\t\tif (controlOverflow) return;\n\t\t\t\t\t\tif (controlBuffer.length + data.length > MAX_CONTROL_FRAME_BYTES) {\n\t\t\t\t\t\t\tcontrolOverflow = true;\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine control frame overflowed.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontrolBuffer = controlBuffer.length === 0 ? data : Buffer.concat([controlBuffer, data]);\n\t\t\t\t\t\tconst parsed = parseControlFrame(controlBuffer);\n\t\t\t\t\t\tif (!parsed) return;\n\t\t\t\t\t\tif (parsed.kind === \"invalid\") {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine returned a malformed control frame.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (parsed.frame.requestId !== requestId) {\n\t\t\t\t\t\t\tfailAndReset(\n\t\t\t\t\t\t\t\tprotocolFailure(\n\t\t\t\t\t\t\t\t\t`Windows shell engine returned stale control frame ${parsed.frame.requestId}; expected ${requestId}.`,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (controlBuffer.subarray(parsed.frameEnd).toString(\"utf8\").trim().length > 0) {\n\t\t\t\t\t\t\tfailAndReset(protocolFailure(\"Windows shell engine emitted trailing control bytes.\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontrolFrame = parsed.frame;\n\t\t\t\t\t\tmaybeComplete();\n\t\t\t\t\t},\n\t\t\t\t\tonChildClose: (code) => {\n\t\t\t\t\t\tconst capturedOutput = capturedControl();\n\t\t\t\t\t\temitPending(pendingOutput.length);\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\treject(\n\t\t\t\t\t\t\t\tnew WindowsShellEngineFailure(\n\t\t\t\t\t\t\t\t\t`Windows shell engine coordinator exited (${code ?? \"null\"}) before a complete terminal handoff.\\n${capturedOutput}`,\n\t\t\t\t\t\t\t\t\tcapturedOutput,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tfail: (error) => failAndReset(error),\n\t\t\t\t};\n\n\t\t\t\tthis.activeExec = active;\n\t\t\t\tif (signal) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutTimer = setTimeout(() => failAndReset(new Error(`timeout:${timeout}`)), timeoutMs);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tchild.stdin?.write(`${JSON.stringify(request)}\\n`, \"utf8\", (error) => {\n\t\t\t\t\t\tif (!error) return;\n\t\t\t\t\t\tfailAndReset(new Error(`Failed to write to Windows shell engine coordinator: ${error.message}`));\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tfailAndReset(new Error(`Failed to write to Windows shell engine coordinator: ${message}`));\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.coordinator.setLoopRef(false);\n\t\t}\n\t}\n\n\tprivate async ensureChild(env: NodeJS.ProcessEnv): Promise<ChildProcess> {\n\t\tif (this.coordinator.child) return this.coordinator.child;\n\t\tconst runtime = await this.resolveRuntime();\n\t\tif (runtime.status !== \"ready\") throw degradationError(runtime);\n\t\tif (this.disposed) throw new Error(`Windows shell engine session \"${this.key}\" is disposed`);\n\n\t\tconst child = this.spawn(runtime.pythonPath, [\"-B\", this.engineScriptPath, \"--server\"], {\n\t\t\tcwd: dirname(this.engineScriptPath),\n\t\t\tenv: {\n\t\t\t\t...env,\n\t\t\t\tPYTHONDONTWRITEBYTECODE: \"1\",\n\t\t\t\tPYTHONIOENCODING: \"utf-8\",\n\t\t\t\tPYTHONUNBUFFERED: \"1\",\n\t\t\t\tPYTHONUTF8: \"1\",\n\t\t\t},\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: true,\n\t\t});\n\t\tthis.coordinator.attach(child, {\n\t\t\tonStdout: (data) => {\n\t\t\t\tconst active = this.activeExec;\n\t\t\t\tif (active) active.onStdout(data);\n\t\t\t\telse if (data.length > 0) this.killChild();\n\t\t\t},\n\t\t\tonStderr: (data) => {\n\t\t\t\tconst active = this.activeExec;\n\t\t\t\tif (active) active.onStderr(data);\n\t\t\t\telse if (data.length > 0) this.killChild();\n\t\t\t},\n\t\t\tonError: (error) => this.activeExec?.fail(error),\n\t\t\tonClose: (code) => this.activeExec?.onChildClose(code),\n\t\t});\n\t\treturn child;\n\t}\n\n\tprivate killChild(): void {\n\t\tthis.coordinator.kill();\n\t}\n}\n\nconst engineSessions = new Map<string, PersistentWindowsShellEngineSession>();\n\nfunction acquireWindowsShellEngineSession(\n\tkey: string,\n\toptions: WindowsShellEngineOptions,\n): PersistentWindowsShellEngineSession {\n\tconst existing = engineSessions.get(key);\n\tif (existing) return existing;\n\tconst session = new PersistentWindowsShellEngineSession(key, options);\n\tengineSessions.set(key, session);\n\treturn session;\n}\n\n/** Kill and forget a Python coordinator. The next call for this key starts a clean process. */\nexport function disposeWindowsShellEngineSession(key: string): void {\n\tconst session = engineSessions.get(key);\n\tif (!session) return;\n\tengineSessions.delete(key);\n\tsession.dispose();\n}\n\n/** Create the Python-engine tier for one bash-tool session. */\nexport function createWindowsShellEngineOperations(\n\tsessionKey: string,\n\toptions: WindowsShellEngineOptions = {},\n): BashOperations {\n\treturn {\n\t\t// Resolve through the registry for every command. Session teardown (for example after\n\t\t// credential/environment changes) deletes only this tenant's entry; an already-built tool\n\t\t// then lazily acquires a fresh coordinator instead of retaining the disposed instance.\n\t\texec: (command, cwd, execOptions) =>\n\t\t\tacquireWindowsShellEngineSession(sessionKey, options).exec(command, cwd, execOptions),\n\t};\n}\n"]}
@@ -1,28 +1,45 @@
1
1
  import type { AgentTool } from "@caupulican/pi-agent-core";
2
2
  import { type Static, Type } from "typebox";
3
3
  import type { ToolDefinition } from "../extensions/types.ts";
4
- declare const writeSchema: Type.TObject<{
4
+ import { FileMutationIntentController } from "./file-mutation-intent.ts";
5
+ declare const writeSchema: Type.TUnion<[Type.TObject<{
6
+ action: Type.TLiteral<"prepare">;
5
7
  path: Type.TString;
8
+ }>, Type.TObject<{
9
+ action: Type.TLiteral<"commit">;
10
+ path: Type.TString;
11
+ intentId: Type.TString;
6
12
  content: Type.TString;
7
- }>;
13
+ }>, Type.TObject<{
14
+ action: Type.TLiteral<"commit">;
15
+ path: Type.TString;
16
+ intentId: Type.TString;
17
+ contentRef: Type.TString;
18
+ }>]>;
8
19
  export type WriteToolInput = Static<typeof writeSchema>;
9
20
  /**
10
21
  * Pluggable operations for the write tool.
11
22
  * Override these to delegate file writing to remote systems (for example SSH).
12
23
  */
13
24
  export interface WriteOperations {
14
- /** Write content to a file */
15
- writeFile: (absolutePath: string, content: string) => Promise<void>;
16
- /** Read existing file contents when available for encoding preservation */
17
- readFile?: (absolutePath: string) => Promise<Buffer>;
25
+ /** Atomically create a new file and fail if any entry already occupies the path. */
26
+ createFile: (absolutePath: string, content: string) => Promise<void>;
18
27
  /** Create directory recursively */
19
28
  mkdir: (dir: string) => Promise<void>;
20
29
  }
21
30
  export interface WriteToolOptions {
22
31
  /** Custom operations for file writing. Default: local filesystem */
23
32
  operations?: WriteOperations;
33
+ /** Session-owned two-phase intent and exact-content-reference authority. */
34
+ intentController?: FileMutationIntentController;
35
+ }
36
+ export interface WriteToolDetails {
37
+ phase: "prepared" | "committed";
38
+ intentId?: string;
39
+ contentRef?: string;
40
+ byteCount?: number;
24
41
  }
25
- export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition<typeof writeSchema, undefined>;
42
+ export declare function createWriteToolDefinition(cwd: string, options?: WriteToolOptions): ToolDefinition<typeof writeSchema, WriteToolDetails>;
26
43
  export declare function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema>;
27
44
  export {};
28
45
  //# sourceMappingURL=write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAOtF,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAQD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AA6ID,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,OAAO,WAAW,EAAE,SAAS,CAAC,CAkG/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAA6B,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAYpG,QAAA,MAAM,WAAW;;;;;;;;;;;;;IAsBf,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,oFAAoF;IACpF,UAAU,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAOD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,4BAA4B,CAAC;CAChD;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,UAAU,GAAG,WAAW,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AA8LD,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,OAAO,WAAW,EAAE,gBAAgB,CAAC,CAkItD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG"}