@caupulican/pi-adaptative 0.81.32 → 0.81.37

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 (339) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +69 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +53 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -0
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +1282 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -0
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +1453 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/templates/builder-validator.json +14 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/templates/claude-trio.json +32 -0
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/templates/full-provider-review.json +15 -0
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/templates/provider-prompt-smoke.json +14 -0
  12. package/dist/bundled-resources/prompts/extensionify.md +5 -4
  13. package/dist/bundled-resources/prompts/skillify.md +5 -5
  14. package/dist/bundled-resources/skills/pi-harness-learning/SKILL.md +6 -3
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +10 -8
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/config.d.ts +5 -1
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +10 -2
  21. package/dist/config.js.map +1 -1
  22. package/dist/core/agent-session.d.ts +12 -0
  23. package/dist/core/agent-session.d.ts.map +1 -1
  24. package/dist/core/agent-session.js +42 -2
  25. package/dist/core/agent-session.js.map +1 -1
  26. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  27. package/dist/core/autonomy/approval-gate.js +2 -0
  28. package/dist/core/autonomy/approval-gate.js.map +1 -1
  29. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  30. package/dist/core/autonomy/foreground-envelope.js +2 -0
  31. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  32. package/dist/core/autonomy/gates.d.ts.map +1 -1
  33. package/dist/core/autonomy/gates.js +9 -2
  34. package/dist/core/autonomy/gates.js.map +1 -1
  35. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  36. package/dist/core/autonomy/risk-assessment.js +2 -0
  37. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  38. package/dist/core/background-lane-controller.d.ts +12 -3
  39. package/dist/core/background-lane-controller.d.ts.map +1 -1
  40. package/dist/core/background-lane-controller.js +67 -26
  41. package/dist/core/background-lane-controller.js.map +1 -1
  42. package/dist/core/bash-execution-controller.d.ts +9 -4
  43. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  44. package/dist/core/bash-execution-controller.js +7 -6
  45. package/dist/core/bash-execution-controller.js.map +1 -1
  46. package/dist/core/bash-executor.d.ts +2 -0
  47. package/dist/core/bash-executor.d.ts.map +1 -1
  48. package/dist/core/bash-executor.js +10 -5
  49. package/dist/core/bash-executor.js.map +1 -1
  50. package/dist/core/context/context-store-retention.d.ts +4 -1
  51. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  52. package/dist/core/context/context-store-retention.js +42 -151
  53. package/dist/core/context/context-store-retention.js.map +1 -1
  54. package/dist/core/context-pipeline.d.ts.map +1 -1
  55. package/dist/core/context-pipeline.js +6 -6
  56. package/dist/core/context-pipeline.js.map +1 -1
  57. package/dist/core/default-tool-surface.d.ts +7 -0
  58. package/dist/core/default-tool-surface.d.ts.map +1 -1
  59. package/dist/core/default-tool-surface.js +29 -10
  60. package/dist/core/default-tool-surface.js.map +1 -1
  61. package/dist/core/doctor.d.ts +10 -10
  62. package/dist/core/doctor.d.ts.map +1 -1
  63. package/dist/core/doctor.js +30 -20
  64. package/dist/core/doctor.js.map +1 -1
  65. package/dist/core/exec.d.ts +2 -0
  66. package/dist/core/exec.d.ts.map +1 -1
  67. package/dist/core/exec.js +26 -39
  68. package/dist/core/exec.js.map +1 -1
  69. package/dist/core/extensions/loader.d.ts +9 -2
  70. package/dist/core/extensions/loader.d.ts.map +1 -1
  71. package/dist/core/extensions/loader.js +105 -21
  72. package/dist/core/extensions/loader.js.map +1 -1
  73. package/dist/core/extensions/types.d.ts +13 -3
  74. package/dist/core/extensions/types.d.ts.map +1 -1
  75. package/dist/core/extensions/types.js +3 -0
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/footer-data-provider.d.ts.map +1 -1
  78. package/dist/core/footer-data-provider.js +2 -0
  79. package/dist/core/footer-data-provider.js.map +1 -1
  80. package/dist/core/goals/goal-state.d.ts +10 -0
  81. package/dist/core/goals/goal-state.d.ts.map +1 -1
  82. package/dist/core/goals/goal-state.js +37 -0
  83. package/dist/core/goals/goal-state.js.map +1 -1
  84. package/dist/core/goals/goal-tool-core.d.ts +11 -0
  85. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  86. package/dist/core/goals/goal-tool-core.js +51 -1
  87. package/dist/core/goals/goal-tool-core.js.map +1 -1
  88. package/dist/core/improvement-loop.d.ts.map +1 -1
  89. package/dist/core/improvement-loop.js +26 -5
  90. package/dist/core/improvement-loop.js.map +1 -1
  91. package/dist/core/memory/memory-manager.d.ts.map +1 -1
  92. package/dist/core/memory/memory-manager.js +1 -0
  93. package/dist/core/memory/memory-manager.js.map +1 -1
  94. package/dist/core/model-capability.d.ts.map +1 -1
  95. package/dist/core/model-capability.js +2 -0
  96. package/dist/core/model-capability.js.map +1 -1
  97. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  98. package/dist/core/model-router/tool-escalation.js +17 -3
  99. package/dist/core/model-router/tool-escalation.js.map +1 -1
  100. package/dist/core/models/fitness-store.d.ts.map +1 -1
  101. package/dist/core/models/fitness-store.js +1 -1
  102. package/dist/core/models/fitness-store.js.map +1 -1
  103. package/dist/core/models/local-runtime.d.ts +6 -4
  104. package/dist/core/models/local-runtime.d.ts.map +1 -1
  105. package/dist/core/models/local-runtime.js +108 -36
  106. package/dist/core/models/local-runtime.js.map +1 -1
  107. package/dist/core/output-guard.d.ts.map +1 -1
  108. package/dist/core/output-guard.js +23 -8
  109. package/dist/core/output-guard.js.map +1 -1
  110. package/dist/core/package-manager.d.ts.map +1 -1
  111. package/dist/core/package-manager.js +44 -59
  112. package/dist/core/package-manager.js.map +1 -1
  113. package/dist/core/profile-resource-selection.d.ts +16 -0
  114. package/dist/core/profile-resource-selection.d.ts.map +1 -1
  115. package/dist/core/profile-resource-selection.js +41 -0
  116. package/dist/core/profile-resource-selection.js.map +1 -1
  117. package/dist/core/python-runtime.d.ts +46 -0
  118. package/dist/core/python-runtime.d.ts.map +1 -0
  119. package/dist/core/python-runtime.js +157 -0
  120. package/dist/core/python-runtime.js.map +1 -0
  121. package/dist/core/reflection-controller.d.ts.map +1 -1
  122. package/dist/core/reflection-controller.js +18 -1
  123. package/dist/core/reflection-controller.js.map +1 -1
  124. package/dist/core/reload-blockers.d.ts +1 -0
  125. package/dist/core/reload-blockers.d.ts.map +1 -1
  126. package/dist/core/reload-blockers.js +6 -2
  127. package/dist/core/reload-blockers.js.map +1 -1
  128. package/dist/core/resource-loader.d.ts +2 -0
  129. package/dist/core/resource-loader.d.ts.map +1 -1
  130. package/dist/core/resource-loader.js +50 -28
  131. package/dist/core/resource-loader.js.map +1 -1
  132. package/dist/core/runtime-builder.d.ts +4 -0
  133. package/dist/core/runtime-builder.d.ts.map +1 -1
  134. package/dist/core/runtime-builder.js +31 -9
  135. package/dist/core/runtime-builder.js.map +1 -1
  136. package/dist/core/security/untrusted-boundary.d.ts +2 -2
  137. package/dist/core/security/untrusted-boundary.d.ts.map +1 -1
  138. package/dist/core/security/untrusted-boundary.js +4 -3
  139. package/dist/core/security/untrusted-boundary.js.map +1 -1
  140. package/dist/core/settings-manager.d.ts.map +1 -1
  141. package/dist/core/settings-manager.js +3 -1
  142. package/dist/core/settings-manager.js.map +1 -1
  143. package/dist/core/slash-commands.d.ts.map +1 -1
  144. package/dist/core/slash-commands.js +9 -1
  145. package/dist/core/slash-commands.js.map +1 -1
  146. package/dist/core/system-prompt.d.ts.map +1 -1
  147. package/dist/core/system-prompt.js +13 -2
  148. package/dist/core/system-prompt.js.map +1 -1
  149. package/dist/core/tasks/session-task-state.d.ts +10 -0
  150. package/dist/core/tasks/session-task-state.d.ts.map +1 -0
  151. package/dist/core/tasks/session-task-state.js +29 -0
  152. package/dist/core/tasks/session-task-state.js.map +1 -0
  153. package/dist/core/tasks/task-command.d.ts +30 -0
  154. package/dist/core/tasks/task-command.d.ts.map +1 -0
  155. package/dist/core/tasks/task-command.js +79 -0
  156. package/dist/core/tasks/task-command.js.map +1 -0
  157. package/dist/core/tasks/task-state.d.ts +71 -0
  158. package/dist/core/tasks/task-state.d.ts.map +1 -0
  159. package/dist/core/tasks/task-state.js +372 -0
  160. package/dist/core/tasks/task-state.js.map +1 -0
  161. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  162. package/dist/core/tool-selection/tool-selection-controller.js +1 -1
  163. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  164. package/dist/core/toolkit/script-runner.d.ts.map +1 -1
  165. package/dist/core/toolkit/script-runner.js +58 -24
  166. package/dist/core/toolkit/script-runner.js.map +1 -1
  167. package/dist/core/tools/bash.d.ts +20 -2
  168. package/dist/core/tools/bash.d.ts.map +1 -1
  169. package/dist/core/tools/bash.js +132 -220
  170. package/dist/core/tools/bash.js.map +1 -1
  171. package/dist/core/tools/extensionify.d.ts +2 -1
  172. package/dist/core/tools/extensionify.d.ts.map +1 -1
  173. package/dist/core/tools/extensionify.js +11 -8
  174. package/dist/core/tools/extensionify.js.map +1 -1
  175. package/dist/core/tools/find.d.ts.map +1 -1
  176. package/dist/core/tools/find.js +57 -48
  177. package/dist/core/tools/find.js.map +1 -1
  178. package/dist/core/tools/git-filter.d.ts.map +1 -1
  179. package/dist/core/tools/git-filter.js +20 -32
  180. package/dist/core/tools/git-filter.js.map +1 -1
  181. package/dist/core/tools/goal.d.ts +1 -1
  182. package/dist/core/tools/goal.d.ts.map +1 -1
  183. package/dist/core/tools/goal.js +10 -3
  184. package/dist/core/tools/goal.js.map +1 -1
  185. package/dist/core/tools/grep.d.ts.map +1 -1
  186. package/dist/core/tools/grep.js +92 -80
  187. package/dist/core/tools/grep.js.map +1 -1
  188. package/dist/core/tools/index.d.ts +9 -6
  189. package/dist/core/tools/index.d.ts.map +1 -1
  190. package/dist/core/tools/index.js +24 -9
  191. package/dist/core/tools/index.js.map +1 -1
  192. package/dist/core/tools/output-accumulator.d.ts +2 -0
  193. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  194. package/dist/core/tools/output-accumulator.js +7 -4
  195. package/dist/core/tools/output-accumulator.js.map +1 -1
  196. package/dist/core/tools/python.d.ts +64 -0
  197. package/dist/core/tools/python.d.ts.map +1 -0
  198. package/dist/core/tools/python.js +241 -0
  199. package/dist/core/tools/python.js.map +1 -0
  200. package/dist/core/tools/read.d.ts.map +1 -1
  201. package/dist/core/tools/read.js +4 -3
  202. package/dist/core/tools/read.js.map +1 -1
  203. package/dist/core/tools/shell-contract-router.d.ts +13 -0
  204. package/dist/core/tools/shell-contract-router.d.ts.map +1 -0
  205. package/dist/core/tools/shell-contract-router.js +295 -0
  206. package/dist/core/tools/shell-contract-router.js.map +1 -0
  207. package/dist/core/tools/task-steps.d.ts +46 -0
  208. package/dist/core/tools/task-steps.d.ts.map +1 -0
  209. package/dist/core/tools/task-steps.js +160 -0
  210. package/dist/core/tools/task-steps.js.map +1 -0
  211. package/dist/index.d.ts +2 -1
  212. package/dist/index.d.ts.map +1 -1
  213. package/dist/index.js +2 -1
  214. package/dist/index.js.map +1 -1
  215. package/dist/main.d.ts +2 -0
  216. package/dist/main.d.ts.map +1 -1
  217. package/dist/main.js +23 -4
  218. package/dist/main.js.map +1 -1
  219. package/dist/migrations.d.ts.map +1 -1
  220. package/dist/migrations.js +18 -4
  221. package/dist/migrations.js.map +1 -1
  222. package/dist/modes/interactive/auth-dialogs-controller.d.ts +10 -0
  223. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  224. package/dist/modes/interactive/auth-dialogs-controller.js +94 -27
  225. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  226. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  227. package/dist/modes/interactive/auto-learn-controller.js +2 -1
  228. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  229. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -0
  230. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/bordered-loader.js +8 -0
  232. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  233. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/extension-editor.js +6 -15
  235. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  236. package/dist/modes/interactive/components/login-dialog.d.ts +3 -1
  237. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  238. package/dist/modes/interactive/components/login-dialog.js +20 -8
  239. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  240. package/dist/modes/interactive/components/profile-resource-editor.d.ts +4 -1
  241. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  242. package/dist/modes/interactive/components/profile-resource-editor.js +22 -39
  243. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  244. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  245. package/dist/modes/interactive/components/session-selector.js +1 -1
  246. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  247. package/dist/modes/interactive/config-backup.d.ts +1 -0
  248. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  249. package/dist/modes/interactive/config-backup.js +14 -3
  250. package/dist/modes/interactive/config-backup.js.map +1 -1
  251. package/dist/modes/interactive/editor-overlay-host.d.ts +12 -0
  252. package/dist/modes/interactive/editor-overlay-host.d.ts.map +1 -1
  253. package/dist/modes/interactive/editor-overlay-host.js +55 -0
  254. package/dist/modes/interactive/editor-overlay-host.js.map +1 -1
  255. package/dist/modes/interactive/extension-ui-host.d.ts +2 -1
  256. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  257. package/dist/modes/interactive/extension-ui-host.js +161 -96
  258. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  259. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  260. package/dist/modes/interactive/external-editor.js +23 -28
  261. package/dist/modes/interactive/external-editor.js.map +1 -1
  262. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  263. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  264. package/dist/modes/interactive/interactive-mode.js +26 -8
  265. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  266. package/dist/modes/interactive/profile-menu-controller.d.ts +5 -1
  267. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  268. package/dist/modes/interactive/profile-menu-controller.js +118 -24
  269. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  270. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -0
  271. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  272. package/dist/modes/interactive/resource-shell-commands.js +5 -1
  273. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  274. package/dist/modes/interactive/session-flow-commands.d.ts +10 -0
  275. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  276. package/dist/modes/interactive/session-flow-commands.js +143 -7
  277. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  278. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  279. package/dist/modes/interactive/session-io-commands.js +80 -50
  280. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  281. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  282. package/dist/modes/interactive/startup-checks.js +14 -17
  283. package/dist/modes/interactive/startup-checks.js.map +1 -1
  284. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  285. package/dist/modes/rpc/rpc-client.js +20 -19
  286. package/dist/modes/rpc/rpc-client.js.map +1 -1
  287. package/dist/package-manager-cli.d.ts.map +1 -1
  288. package/dist/package-manager-cli.js +10 -19
  289. package/dist/package-manager-cli.js.map +1 -1
  290. package/dist/utils/child-process.d.ts +13 -7
  291. package/dist/utils/child-process.d.ts.map +1 -1
  292. package/dist/utils/child-process.js +56 -3
  293. package/dist/utils/child-process.js.map +1 -1
  294. package/dist/utils/clipboard-image.d.ts.map +1 -1
  295. package/dist/utils/clipboard-image.js +3 -2
  296. package/dist/utils/clipboard-image.js.map +1 -1
  297. package/dist/utils/clipboard.d.ts.map +1 -1
  298. package/dist/utils/clipboard.js +17 -10
  299. package/dist/utils/clipboard.js.map +1 -1
  300. package/dist/utils/external-editor-command.d.ts +8 -0
  301. package/dist/utils/external-editor-command.d.ts.map +1 -0
  302. package/dist/utils/external-editor-command.js +60 -0
  303. package/dist/utils/external-editor-command.js.map +1 -0
  304. package/dist/utils/paths.d.ts.map +1 -1
  305. package/dist/utils/paths.js +10 -2
  306. package/dist/utils/paths.js.map +1 -1
  307. package/dist/utils/shell.d.ts +6 -8
  308. package/dist/utils/shell.d.ts.map +1 -1
  309. package/dist/utils/shell.js +61 -70
  310. package/dist/utils/shell.js.map +1 -1
  311. package/dist/utils/tools-manager.d.ts +23 -3
  312. package/dist/utils/tools-manager.d.ts.map +1 -1
  313. package/dist/utils/tools-manager.js +117 -21
  314. package/dist/utils/tools-manager.js.map +1 -1
  315. package/dist/utils/work-directory.d.ts +36 -0
  316. package/dist/utils/work-directory.d.ts.map +1 -0
  317. package/dist/utils/work-directory.js +462 -0
  318. package/dist/utils/work-directory.js.map +1 -0
  319. package/docs/index.md +4 -0
  320. package/docs/python.md +43 -0
  321. package/docs/resources.md +2 -2
  322. package/docs/rpc.md +1 -1
  323. package/docs/settings.md +7 -3
  324. package/docs/task-steps.md +90 -0
  325. package/docs/termux.md +7 -0
  326. package/docs/tmux-agent-manager.md +48 -0
  327. package/docs/usage.md +5 -6
  328. package/docs/windows.md +104 -8
  329. package/docs/work-directory.md +41 -0
  330. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  331. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  332. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  333. package/examples/extensions/sandbox/package-lock.json +2 -2
  334. package/examples/extensions/sandbox/package.json +1 -1
  335. package/examples/extensions/with-deps/package-lock.json +2 -2
  336. package/examples/extensions/with-deps/package.json +1 -1
  337. package/npm-shrinkwrap.json +32 -37
  338. package/package.json +9 -7
  339. package/scripts/postinstall-python-runtime.mjs +20 -0
@@ -0,0 +1,462 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync, lstatSync, mkdirSync, opendirSync, readFileSync, rmdirSync, rmSync, unlinkSync, utimesSync, writeFileSync, } from "node:fs";
3
+ import { hostname } from "node:os";
4
+ import { join } from "node:path";
5
+ export const PI_WORK_ROOT_ENV = "PI_WORK_ROOT";
6
+ export const WORK_RUN_MANIFEST_FILE = ".pi-work-run.json";
7
+ const LEASES_DIRECTORY = ".leases";
8
+ const CLEANUP_MARKER_FILE = ".cleanup.json";
9
+ const MAX_METADATA_BYTES = 4 * 1024;
10
+ const MAX_LEASE_MARKERS = 256;
11
+ const MAX_DIRECTORY_DEPTH = 64;
12
+ const DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
13
+ const DEFAULT_MAX_RUNS = 64;
14
+ const DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;
15
+ const DEFAULT_MAX_SCANNED_ENTRIES = 100_000;
16
+ const DEFAULT_MAX_SCANNED_RUNS = 10_000;
17
+ const SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
18
+ const WINDOWS_RESERVED_NAMES = new Set([
19
+ "aux",
20
+ "clock$",
21
+ "con",
22
+ "nul",
23
+ "prn",
24
+ ...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),
25
+ ...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),
26
+ ]);
27
+ const processWorkRuns = new Map();
28
+ function nonNegativeLimit(value, fallback) {
29
+ return value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
30
+ }
31
+ function assertPortableSegment(label, value) {
32
+ if (!SEGMENT_PATTERN.test(value) || value.endsWith(".")) {
33
+ throw new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);
34
+ }
35
+ const stem = value.split(".", 1)[0];
36
+ if (stem && WINDOWS_RESERVED_NAMES.has(stem)) {
37
+ throw new Error(`${label} uses a Windows-reserved path name: ${value}`);
38
+ }
39
+ }
40
+ function ensureDirectory(path) {
41
+ try {
42
+ mkdirSync(path);
43
+ }
44
+ catch (error) {
45
+ if (error.code !== "EEXIST")
46
+ throw error;
47
+ }
48
+ const stats = lstatSync(path);
49
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
50
+ throw new Error(`Work path is not a real directory: ${path}`);
51
+ }
52
+ }
53
+ function ensureTenantDirectory(agentDir, category, tenant) {
54
+ mkdirSync(agentDir, { recursive: true });
55
+ const workRoot = getWorkRoot(agentDir);
56
+ ensureDirectory(workRoot);
57
+ const categoryDir = join(workRoot, category);
58
+ ensureDirectory(categoryDir);
59
+ const tenantDir = join(categoryDir, tenant);
60
+ ensureDirectory(tenantDir);
61
+ return tenantDir;
62
+ }
63
+ function readSmallJson(path) {
64
+ const stats = lstatSync(path);
65
+ if (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {
66
+ throw new Error(`Invalid work metadata file: ${path}`);
67
+ }
68
+ return JSON.parse(readFileSync(path, "utf8"));
69
+ }
70
+ function isManifest(value, category, tenant, runId) {
71
+ if (!value || typeof value !== "object")
72
+ return false;
73
+ const manifest = value;
74
+ return (manifest.version === 1 &&
75
+ manifest.category === category &&
76
+ manifest.tenant === tenant &&
77
+ manifest.runId === runId &&
78
+ typeof manifest.createdAt === "number" &&
79
+ Number.isFinite(manifest.createdAt));
80
+ }
81
+ function isMarker(value) {
82
+ if (!value || typeof value !== "object")
83
+ return false;
84
+ const marker = value;
85
+ return (marker.version === 1 &&
86
+ typeof marker.hostname === "string" &&
87
+ typeof marker.pid === "number" &&
88
+ Number.isSafeInteger(marker.pid) &&
89
+ marker.pid > 0 &&
90
+ typeof marker.createdAt === "number" &&
91
+ Number.isFinite(marker.createdAt));
92
+ }
93
+ function markerState(path) {
94
+ try {
95
+ const value = readSmallJson(path);
96
+ if (!isMarker(value))
97
+ return "unknown";
98
+ if (value.hostname !== hostname())
99
+ return "active";
100
+ try {
101
+ process.kill(value.pid, 0);
102
+ return "active";
103
+ }
104
+ catch (error) {
105
+ return error.code === "EPERM" ? "active" : "stale";
106
+ }
107
+ }
108
+ catch (error) {
109
+ return error.code === "ENOENT" ? "stale" : "unknown";
110
+ }
111
+ }
112
+ function removeFile(path) {
113
+ try {
114
+ unlinkSync(path);
115
+ }
116
+ catch { }
117
+ }
118
+ function cleanupMarkerBlocksAcquisition(runDir) {
119
+ const markerPath = join(runDir, CLEANUP_MARKER_FILE);
120
+ if (!existsSync(markerPath))
121
+ return false;
122
+ const state = markerState(markerPath);
123
+ if (state !== "stale")
124
+ return true;
125
+ removeFile(markerPath);
126
+ return existsSync(markerPath);
127
+ }
128
+ function hasActiveLease(runDir) {
129
+ const leasesDir = join(runDir, LEASES_DIRECTORY);
130
+ if (!existsSync(leasesDir))
131
+ return false;
132
+ let handle;
133
+ try {
134
+ handle = opendirSync(leasesDir);
135
+ let scanned = 0;
136
+ while (true) {
137
+ const entry = handle.readSync();
138
+ if (!entry)
139
+ break;
140
+ scanned++;
141
+ if (scanned > MAX_LEASE_MARKERS)
142
+ return true;
143
+ if (!entry.isFile())
144
+ return true;
145
+ const markerPath = join(leasesDir, entry.name);
146
+ const state = markerState(markerPath);
147
+ if (state === "active" || state === "unknown")
148
+ return true;
149
+ removeFile(markerPath);
150
+ }
151
+ }
152
+ catch {
153
+ return true;
154
+ }
155
+ finally {
156
+ try {
157
+ handle?.closeSync();
158
+ }
159
+ catch { }
160
+ }
161
+ try {
162
+ rmdirSync(leasesDir);
163
+ }
164
+ catch { }
165
+ return false;
166
+ }
167
+ function measureDirectory(path, budget, depth = 0) {
168
+ if (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0)
169
+ return { bytes: 0, complete: false };
170
+ let bytes = 0;
171
+ let complete = true;
172
+ let handle;
173
+ try {
174
+ handle = opendirSync(path);
175
+ while (true) {
176
+ const entry = handle.readSync();
177
+ if (!entry)
178
+ break;
179
+ if (budget.remaining <= 0)
180
+ return { bytes, complete: false };
181
+ budget.remaining--;
182
+ const childPath = join(path, entry.name);
183
+ try {
184
+ const stats = lstatSync(childPath);
185
+ if (stats.isDirectory() && !stats.isSymbolicLink()) {
186
+ const child = measureDirectory(childPath, budget, depth + 1);
187
+ bytes += child.bytes;
188
+ complete = complete && child.complete;
189
+ }
190
+ else {
191
+ bytes += stats.size;
192
+ }
193
+ }
194
+ catch {
195
+ complete = false;
196
+ }
197
+ }
198
+ }
199
+ catch {
200
+ return { bytes, complete: false };
201
+ }
202
+ finally {
203
+ try {
204
+ handle?.closeSync();
205
+ }
206
+ catch { }
207
+ }
208
+ return { bytes, complete };
209
+ }
210
+ function inspectRun(runPath, category, tenant, runId, budget, unknownBytes) {
211
+ try {
212
+ const stats = lstatSync(runPath);
213
+ if (!stats.isDirectory() || stats.isSymbolicLink())
214
+ return undefined;
215
+ const manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));
216
+ if (!isManifest(manifest, category, tenant, runId))
217
+ return undefined;
218
+ const measured = measureDirectory(runPath, budget);
219
+ return {
220
+ path: runPath,
221
+ mtimeMs: stats.mtimeMs,
222
+ bytes: measured.complete ? measured.bytes : unknownBytes,
223
+ };
224
+ }
225
+ catch {
226
+ return undefined;
227
+ }
228
+ }
229
+ function createCleanupMarker(runDir, now) {
230
+ const path = join(runDir, CLEANUP_MARKER_FILE);
231
+ const marker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };
232
+ try {
233
+ writeFileSync(path, JSON.stringify(marker), { encoding: "utf8", flag: "wx" });
234
+ return path;
235
+ }
236
+ catch (error) {
237
+ if (error.code !== "EEXIST")
238
+ return undefined;
239
+ if (markerState(path) !== "stale")
240
+ return undefined;
241
+ removeFile(path);
242
+ try {
243
+ writeFileSync(path, JSON.stringify(marker), { encoding: "utf8", flag: "wx" });
244
+ return path;
245
+ }
246
+ catch {
247
+ return undefined;
248
+ }
249
+ }
250
+ }
251
+ function removeRunIfInactive(runPath, now) {
252
+ const cleanupMarker = createCleanupMarker(runPath, now);
253
+ if (!cleanupMarker)
254
+ return false;
255
+ if (hasActiveLease(runPath)) {
256
+ removeFile(cleanupMarker);
257
+ return false;
258
+ }
259
+ try {
260
+ rmSync(runPath, { recursive: true, force: true });
261
+ return !existsSync(runPath);
262
+ }
263
+ catch {
264
+ removeFile(cleanupMarker);
265
+ return false;
266
+ }
267
+ }
268
+ export function getWorkRoot(agentDir) {
269
+ return join(agentDir, "work");
270
+ }
271
+ export function getWorkTenantDir(agentDir, category, tenant) {
272
+ assertPortableSegment("Work category", category);
273
+ assertPortableSegment("Work tenant", tenant);
274
+ return join(getWorkRoot(agentDir), category, tenant);
275
+ }
276
+ export function getWorkRunDir(agentDir, category, tenant, runId) {
277
+ assertPortableSegment("Work category", category);
278
+ assertPortableSegment("Work tenant", tenant);
279
+ assertPortableSegment("Work run id", runId);
280
+ return join(getWorkRoot(agentDir), category, tenant, runId);
281
+ }
282
+ export function createWorkRunId(now = Date.now()) {
283
+ return `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;
284
+ }
285
+ export function pruneWorkTenant(agentDir, category, tenant, options = {}) {
286
+ const tenantDir = getWorkTenantDir(agentDir, category, tenant);
287
+ if (!existsSync(tenantDir))
288
+ return [];
289
+ try {
290
+ const stats = lstatSync(tenantDir);
291
+ if (!stats.isDirectory() || stats.isSymbolicLink())
292
+ return [];
293
+ }
294
+ catch {
295
+ return [];
296
+ }
297
+ const now = options.now ?? Date.now();
298
+ const maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);
299
+ const maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);
300
+ const maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);
301
+ const maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);
302
+ const budget = {
303
+ remaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),
304
+ };
305
+ const unknownBytes = Math.max(1, maxTotalBytes + 1);
306
+ const runs = [];
307
+ let truncated = false;
308
+ let handle;
309
+ try {
310
+ handle = opendirSync(tenantDir);
311
+ while (true) {
312
+ const entry = handle.readSync();
313
+ if (!entry)
314
+ break;
315
+ if (entry.name.startsWith("."))
316
+ continue;
317
+ if (runs.length >= maxScannedRuns) {
318
+ truncated = true;
319
+ break;
320
+ }
321
+ if (!entry.isDirectory() || entry.isSymbolicLink())
322
+ continue;
323
+ const inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);
324
+ if (inspected)
325
+ runs.push(inspected);
326
+ }
327
+ }
328
+ catch {
329
+ return [];
330
+ }
331
+ finally {
332
+ try {
333
+ handle?.closeSync();
334
+ }
335
+ catch { }
336
+ }
337
+ const removed = [];
338
+ let retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);
339
+ let retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);
340
+ for (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {
341
+ const expired = now - run.mtimeMs > maxAgeMs;
342
+ const overCount = retainedCount > maxRuns;
343
+ const overBytes = retainedBytes > maxTotalBytes;
344
+ if (!expired && !overCount && !overBytes)
345
+ continue;
346
+ if (!removeRunIfInactive(run.path, now))
347
+ continue;
348
+ removed.push(run.path);
349
+ retainedCount--;
350
+ retainedBytes -= run.bytes;
351
+ }
352
+ return removed;
353
+ }
354
+ export function getProcessWorkRun(agentDir, category, tenant, runId) {
355
+ const key = `${agentDir}\0${category}\0${tenant}\0${runId ?? ""}`;
356
+ const existing = processWorkRuns.get(key);
357
+ if (existing && existsSync(existing.path))
358
+ return existing;
359
+ const acquired = acquireWorkRun({ agentDir, category, tenant, runId });
360
+ processWorkRuns.set(key, acquired);
361
+ return acquired;
362
+ }
363
+ export function acquireWorkRun(options) {
364
+ const now = options.now ?? Date.now();
365
+ const runId = options.runId ?? createWorkRunId(now);
366
+ assertPortableSegment("Work category", options.category);
367
+ assertPortableSegment("Work tenant", options.tenant);
368
+ assertPortableSegment("Work run id", runId);
369
+ const tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);
370
+ const runDir = join(tenantDir, runId);
371
+ let created = false;
372
+ try {
373
+ mkdirSync(runDir);
374
+ created = true;
375
+ }
376
+ catch (error) {
377
+ if (error.code !== "EEXIST")
378
+ throw error;
379
+ const stats = lstatSync(runDir);
380
+ if (!stats.isDirectory() || stats.isSymbolicLink()) {
381
+ throw new Error(`Work run path is not a real directory: ${runDir}`);
382
+ }
383
+ }
384
+ const manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);
385
+ if (created) {
386
+ const manifest = {
387
+ version: 1,
388
+ category: options.category,
389
+ tenant: options.tenant,
390
+ runId,
391
+ createdAt: now,
392
+ };
393
+ writeFileSync(manifestPath, JSON.stringify(manifest), { encoding: "utf8", flag: "wx" });
394
+ }
395
+ else {
396
+ let manifest;
397
+ try {
398
+ manifest = readSmallJson(manifestPath);
399
+ }
400
+ catch {
401
+ throw new Error(`Refusing to adopt unowned work directory: ${runDir}`);
402
+ }
403
+ if (!isManifest(manifest, options.category, options.tenant, runId)) {
404
+ throw new Error(`Work directory manifest does not match its path: ${runDir}`);
405
+ }
406
+ }
407
+ if (cleanupMarkerBlocksAcquisition(runDir)) {
408
+ throw new Error(`Work run is being cleaned: ${runDir}`);
409
+ }
410
+ const leasesDir = join(runDir, LEASES_DIRECTORY);
411
+ ensureDirectory(leasesDir);
412
+ const markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);
413
+ const marker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };
414
+ writeFileSync(markerPath, JSON.stringify(marker), { encoding: "utf8", flag: "wx" });
415
+ if (cleanupMarkerBlocksAcquisition(runDir)) {
416
+ removeFile(markerPath);
417
+ throw new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);
418
+ }
419
+ try {
420
+ utimesSync(runDir, new Date(now), new Date(now));
421
+ }
422
+ catch { }
423
+ if (options.retention !== false) {
424
+ try {
425
+ pruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);
426
+ }
427
+ catch { }
428
+ }
429
+ let released = false;
430
+ return {
431
+ path: runDir,
432
+ category: options.category,
433
+ tenant: options.tenant,
434
+ runId,
435
+ touch() {
436
+ if (released)
437
+ return;
438
+ const touchedAt = new Date();
439
+ try {
440
+ utimesSync(markerPath, touchedAt, touchedAt);
441
+ utimesSync(runDir, touchedAt, touchedAt);
442
+ }
443
+ catch { }
444
+ },
445
+ release() {
446
+ if (released)
447
+ return;
448
+ released = true;
449
+ removeFile(markerPath);
450
+ try {
451
+ rmdirSync(leasesDir);
452
+ }
453
+ catch { }
454
+ const touchedAt = new Date();
455
+ try {
456
+ utimesSync(runDir, touchedAt, touchedAt);
457
+ }
458
+ catch { }
459
+ },
460
+ };
461
+ }
462
+ //# sourceMappingURL=work-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-directory.js","sourceRoot":"","sources":["../../src/utils/work-directory.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\ttype Dir,\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\topendirSync,\n\treadFileSync,\n\trmdirSync,\n\trmSync,\n\tunlinkSync,\n\tutimesSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const PI_WORK_ROOT_ENV = \"PI_WORK_ROOT\";\nexport const WORK_RUN_MANIFEST_FILE = \".pi-work-run.json\";\n\nconst LEASES_DIRECTORY = \".leases\";\nconst CLEANUP_MARKER_FILE = \".cleanup.json\";\nconst MAX_METADATA_BYTES = 4 * 1024;\nconst MAX_LEASE_MARKERS = 256;\nconst MAX_DIRECTORY_DEPTH = 64;\nconst DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_RUNS = 64;\nconst DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_SCANNED_ENTRIES = 100_000;\nconst DEFAULT_MAX_SCANNED_RUNS = 10_000;\nconst SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst WINDOWS_RESERVED_NAMES = new Set([\n\t\"aux\",\n\t\"clock$\",\n\t\"con\",\n\t\"nul\",\n\t\"prn\",\n\t...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),\n\t...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),\n]);\n\ninterface WorkRunManifest {\n\tversion: 1;\n\tcategory: string;\n\ttenant: string;\n\trunId: string;\n\tcreatedAt: number;\n}\n\ninterface WorkMarker {\n\tversion: 1;\n\thostname: string;\n\tpid: number;\n\tcreatedAt: number;\n}\n\ninterface InspectedRun {\n\tpath: string;\n\tmtimeMs: number;\n\tbytes: number;\n}\n\ninterface ScanBudget {\n\tremaining: number;\n}\n\nexport interface WorkRetentionOptions {\n\tmaxAgeMs?: number;\n\tmaxRuns?: number;\n\tmaxTotalBytes?: number;\n\t/** Fixed tenant-wide cap for recursive file entries inspected during one prune. */\n\tmaxScannedEntries?: number;\n\t/** Fixed cap for run directories inspected during one prune. */\n\tmaxScannedRuns?: number;\n\tnow?: number;\n}\n\nexport interface AcquireWorkRunOptions {\n\tagentDir: string;\n\tcategory: string;\n\ttenant: string;\n\trunId?: string;\n\tretention?: WorkRetentionOptions | false;\n\tnow?: number;\n}\n\nexport interface WorkRunLease {\n\treadonly path: string;\n\treadonly category: string;\n\treadonly tenant: string;\n\treadonly runId: string;\n\ttouch(): void;\n\trelease(): void;\n}\n\nconst processWorkRuns = new Map<string, WorkRunLease>();\n\nfunction nonNegativeLimit(value: number | undefined, fallback: number): number {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;\n}\n\nfunction assertPortableSegment(label: string, value: string): void {\n\tif (!SEGMENT_PATTERN.test(value) || value.endsWith(\".\")) {\n\t\tthrow new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);\n\t}\n\tconst stem = value.split(\".\", 1)[0];\n\tif (stem && WINDOWS_RESERVED_NAMES.has(stem)) {\n\t\tthrow new Error(`${label} uses a Windows-reserved path name: ${value}`);\n\t}\n}\n\nfunction ensureDirectory(path: string): void {\n\ttry {\n\t\tmkdirSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t}\n\tconst stats = lstatSync(path);\n\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\tthrow new Error(`Work path is not a real directory: ${path}`);\n\t}\n}\n\nfunction ensureTenantDirectory(agentDir: string, category: string, tenant: string): string {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst workRoot = getWorkRoot(agentDir);\n\tensureDirectory(workRoot);\n\tconst categoryDir = join(workRoot, category);\n\tensureDirectory(categoryDir);\n\tconst tenantDir = join(categoryDir, tenant);\n\tensureDirectory(tenantDir);\n\treturn tenantDir;\n}\n\nfunction readSmallJson(path: string): unknown {\n\tconst stats = lstatSync(path);\n\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {\n\t\tthrow new Error(`Invalid work metadata file: ${path}`);\n\t}\n\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n}\n\nfunction isManifest(value: unknown, category: string, tenant: string, runId: string): value is WorkRunManifest {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst manifest = value as Partial<WorkRunManifest>;\n\treturn (\n\t\tmanifest.version === 1 &&\n\t\tmanifest.category === category &&\n\t\tmanifest.tenant === tenant &&\n\t\tmanifest.runId === runId &&\n\t\ttypeof manifest.createdAt === \"number\" &&\n\t\tNumber.isFinite(manifest.createdAt)\n\t);\n}\n\nfunction isMarker(value: unknown): value is WorkMarker {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst marker = value as Partial<WorkMarker>;\n\treturn (\n\t\tmarker.version === 1 &&\n\t\ttypeof marker.hostname === \"string\" &&\n\t\ttypeof marker.pid === \"number\" &&\n\t\tNumber.isSafeInteger(marker.pid) &&\n\t\tmarker.pid > 0 &&\n\t\ttypeof marker.createdAt === \"number\" &&\n\t\tNumber.isFinite(marker.createdAt)\n\t);\n}\n\nfunction markerState(path: string): \"active\" | \"stale\" | \"unknown\" {\n\ttry {\n\t\tconst value = readSmallJson(path);\n\t\tif (!isMarker(value)) return \"unknown\";\n\t\tif (value.hostname !== hostname()) return \"active\";\n\t\ttry {\n\t\t\tprocess.kill(value.pid, 0);\n\t\t\treturn \"active\";\n\t\t} catch (error) {\n\t\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\" ? \"active\" : \"stale\";\n\t\t}\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"ENOENT\" ? \"stale\" : \"unknown\";\n\t}\n}\n\nfunction removeFile(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch {}\n}\n\nfunction cleanupMarkerBlocksAcquisition(runDir: string): boolean {\n\tconst markerPath = join(runDir, CLEANUP_MARKER_FILE);\n\tif (!existsSync(markerPath)) return false;\n\tconst state = markerState(markerPath);\n\tif (state !== \"stale\") return true;\n\tremoveFile(markerPath);\n\treturn existsSync(markerPath);\n}\n\nfunction hasActiveLease(runDir: string): boolean {\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tif (!existsSync(leasesDir)) return false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(leasesDir);\n\t\tlet scanned = 0;\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tscanned++;\n\t\t\tif (scanned > MAX_LEASE_MARKERS) return true;\n\t\t\tif (!entry.isFile()) return true;\n\t\t\tconst markerPath = join(leasesDir, entry.name);\n\t\t\tconst state = markerState(markerPath);\n\t\t\tif (state === \"active\" || state === \"unknown\") return true;\n\t\t\tremoveFile(markerPath);\n\t\t}\n\t} catch {\n\t\treturn true;\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\ttry {\n\t\trmdirSync(leasesDir);\n\t} catch {}\n\treturn false;\n}\n\nfunction measureDirectory(path: string, budget: ScanBudget, depth = 0): { bytes: number; complete: boolean } {\n\tif (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0) return { bytes: 0, complete: false };\n\tlet bytes = 0;\n\tlet complete = true;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(path);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (budget.remaining <= 0) return { bytes, complete: false };\n\t\t\tbudget.remaining--;\n\t\t\tconst childPath = join(path, entry.name);\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(childPath);\n\t\t\t\tif (stats.isDirectory() && !stats.isSymbolicLink()) {\n\t\t\t\t\tconst child = measureDirectory(childPath, budget, depth + 1);\n\t\t\t\t\tbytes += child.bytes;\n\t\t\t\t\tcomplete = complete && child.complete;\n\t\t\t\t} else {\n\t\t\t\t\tbytes += stats.size;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcomplete = false;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { bytes, complete: false };\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\treturn { bytes, complete };\n}\n\nfunction inspectRun(\n\trunPath: string,\n\tcategory: string,\n\ttenant: string,\n\trunId: string,\n\tbudget: ScanBudget,\n\tunknownBytes: number,\n): InspectedRun | undefined {\n\ttry {\n\t\tconst stats = lstatSync(runPath);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return undefined;\n\t\tconst manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));\n\t\tif (!isManifest(manifest, category, tenant, runId)) return undefined;\n\t\tconst measured = measureDirectory(runPath, budget);\n\t\treturn {\n\t\t\tpath: runPath,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tbytes: measured.complete ? measured.bytes : unknownBytes,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction createCleanupMarker(runDir: string, now: number): string | undefined {\n\tconst path = join(runDir, CLEANUP_MARKER_FILE);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\ttry {\n\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\treturn path;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return undefined;\n\t\tif (markerState(path) !== \"stale\") return undefined;\n\t\tremoveFile(path);\n\t\ttry {\n\t\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\t\treturn path;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n\nfunction removeRunIfInactive(runPath: string, now: number): boolean {\n\tconst cleanupMarker = createCleanupMarker(runPath, now);\n\tif (!cleanupMarker) return false;\n\tif (hasActiveLease(runPath)) {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n\ttry {\n\t\trmSync(runPath, { recursive: true, force: true });\n\t\treturn !existsSync(runPath);\n\t} catch {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n}\n\nexport function getWorkRoot(agentDir: string): string {\n\treturn join(agentDir, \"work\");\n}\n\nexport function getWorkTenantDir(agentDir: string, category: string, tenant: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\treturn join(getWorkRoot(agentDir), category, tenant);\n}\n\nexport function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\treturn join(getWorkRoot(agentDir), category, tenant, runId);\n}\n\nexport function createWorkRunId(now = Date.now()): string {\n\treturn `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;\n}\n\nexport function pruneWorkTenant(\n\tagentDir: string,\n\tcategory: string,\n\ttenant: string,\n\toptions: WorkRetentionOptions = {},\n): string[] {\n\tconst tenantDir = getWorkTenantDir(agentDir, category, tenant);\n\tif (!existsSync(tenantDir)) return [];\n\ttry {\n\t\tconst stats = lstatSync(tenantDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return [];\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst now = options.now ?? Date.now();\n\tconst maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n\tconst maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);\n\tconst maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);\n\tconst maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);\n\tconst budget: ScanBudget = {\n\t\tremaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t};\n\tconst unknownBytes = Math.max(1, maxTotalBytes + 1);\n\tconst runs: InspectedRun[] = [];\n\tlet truncated = false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(tenantDir);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (runs.length >= maxScannedRuns) {\n\t\t\t\ttruncated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n\t\t\tconst inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);\n\t\t\tif (inspected) runs.push(inspected);\n\t\t}\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\n\tconst removed: string[] = [];\n\tlet retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);\n\tlet retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);\n\tfor (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n\t\tconst expired = now - run.mtimeMs > maxAgeMs;\n\t\tconst overCount = retainedCount > maxRuns;\n\t\tconst overBytes = retainedBytes > maxTotalBytes;\n\t\tif (!expired && !overCount && !overBytes) continue;\n\t\tif (!removeRunIfInactive(run.path, now)) continue;\n\t\tremoved.push(run.path);\n\t\tretainedCount--;\n\t\tretainedBytes -= run.bytes;\n\t}\n\treturn removed;\n}\n\nexport function getProcessWorkRun(agentDir: string, category: string, tenant: string, runId?: string): WorkRunLease {\n\tconst key = `${agentDir}\\0${category}\\0${tenant}\\0${runId ?? \"\"}`;\n\tconst existing = processWorkRuns.get(key);\n\tif (existing && existsSync(existing.path)) return existing;\n\tconst acquired = acquireWorkRun({ agentDir, category, tenant, runId });\n\tprocessWorkRuns.set(key, acquired);\n\treturn acquired;\n}\n\nexport function acquireWorkRun(options: AcquireWorkRunOptions): WorkRunLease {\n\tconst now = options.now ?? Date.now();\n\tconst runId = options.runId ?? createWorkRunId(now);\n\tassertPortableSegment(\"Work category\", options.category);\n\tassertPortableSegment(\"Work tenant\", options.tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\tconst tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);\n\tconst runDir = join(tenantDir, runId);\n\tlet created = false;\n\ttry {\n\t\tmkdirSync(runDir);\n\t\tcreated = true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\tconst stats = lstatSync(runDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`Work run path is not a real directory: ${runDir}`);\n\t\t}\n\t}\n\n\tconst manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);\n\tif (created) {\n\t\tconst manifest: WorkRunManifest = {\n\t\t\tversion: 1,\n\t\t\tcategory: options.category,\n\t\t\ttenant: options.tenant,\n\t\t\trunId,\n\t\t\tcreatedAt: now,\n\t\t};\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest), { encoding: \"utf8\", flag: \"wx\" });\n\t} else {\n\t\tlet manifest: unknown;\n\t\ttry {\n\t\t\tmanifest = readSmallJson(manifestPath);\n\t\t} catch {\n\t\t\tthrow new Error(`Refusing to adopt unowned work directory: ${runDir}`);\n\t\t}\n\t\tif (!isManifest(manifest, options.category, options.tenant, runId)) {\n\t\t\tthrow new Error(`Work directory manifest does not match its path: ${runDir}`);\n\t\t}\n\t}\n\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tthrow new Error(`Work run is being cleaned: ${runDir}`);\n\t}\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tensureDirectory(leasesDir);\n\tconst markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\twriteFileSync(markerPath, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tremoveFile(markerPath);\n\t\tthrow new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);\n\t}\n\ttry {\n\t\tutimesSync(runDir, new Date(now), new Date(now));\n\t} catch {}\n\n\tif (options.retention !== false) {\n\t\ttry {\n\t\t\tpruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);\n\t\t} catch {}\n\t}\n\n\tlet released = false;\n\treturn {\n\t\tpath: runDir,\n\t\tcategory: options.category,\n\t\ttenant: options.tenant,\n\t\trunId,\n\t\ttouch(): void {\n\t\t\tif (released) return;\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(markerPath, touchedAt, touchedAt);\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t\trelease(): void {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tremoveFile(markerPath);\n\t\t\ttry {\n\t\t\t\trmdirSync(leasesDir);\n\t\t\t} catch {}\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t};\n}\n"]}
package/docs/index.md CHANGED
@@ -47,10 +47,13 @@ For the full first-run flow, see [Quickstart](quickstart.md).
47
47
  - [Compaction](compaction.md) - context compaction and branch summarization.
48
48
  - [FastContext scout](scout.md) - read-only repository scout setup and 10 GB local profile.
49
49
  - [Tool repair](tool-repair.md) - repaired tool-call arguments, health diagnostics, kill switches, and replay workflow.
50
+ - [Task steps](task-steps.md) - native session checklist, slash commands, persistence, and delegation migration.
51
+ - [Native Python](python.md) - uv-managed bounded Python execution, provisioning, output limits, and cross-platform file guidance.
50
52
 
51
53
  ## Customization
52
54
 
53
55
  - [Extensions](extensions.md) - TypeScript modules for tools, commands, events, and custom UI.
56
+ - [tmux agent manager](tmux-agent-manager.md) - bundled event-driven external-provider teams with parent wake handoffs.
54
57
  - [Skills](skills.md) - Agent Skills for reusable on-demand capabilities.
55
58
  - [Resource profiles & library](resources.md) - curate extensions, skills, and agents per project or situation; share a catalog; install and back up.
56
59
  - [Self-adaptation](self-adaptation.md) - draft live skills/extensions and run evidence-backed Pi harness improvement loops.
@@ -74,6 +77,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
74
77
  ## Platform setup
75
78
 
76
79
  - [Windows](windows.md)
80
+ - [Transient work directory](work-directory.md) - multi-tenant runtime output, leases, and retention.
77
81
  - [Termux on Android](termux.md)
78
82
  - [tmux](tmux.md)
79
83
  - [Terminal setup](terminal-setup.md)
package/docs/python.md ADDED
@@ -0,0 +1,43 @@
1
+ # Native Python tool
2
+
3
+ Pi includes `python` as a built-in tool and activates it by default. The tool runs bounded Python code or a script directly, without shell interpolation.
4
+
5
+ ## Runtime provisioning
6
+
7
+ `python` is resolved through `uv`:
8
+
9
+ 1. Pi uses an existing `uv` on `PATH` when available.
10
+ 2. On Windows, macOS, and desktop Linux, Pi can install its pinned, SHA-256-verified `uv` release under `~/.pi/agent/bin`.
11
+ 3. On Android/Termux, Pi uses `pkg install -y uv` because upstream desktop Linux archives are incompatible with Android's Bionic libc.
12
+ 4. Pi asks `uv` to reuse an existing Python 3.10 or newer. If none is available and Pi is online, `uv python install 3.13` provisions it under `~/.pi/agent/runtimes/python`.
13
+ 5. The resolved interpreter path is cached, and normal tool calls spawn it directly instead of creating a fresh environment.
14
+
15
+ Provisioning runs best-effort after npm installation and `pi update`, is available through `pi doctor`, and retries on first tool use. Installation is bounded to five minutes and never uses `sudo` or an unpinned `curl | sh` installer. Offline mode skips downloads and reports an actionable diagnostic.
16
+
17
+ ## Tool input
18
+
19
+ Provide exactly one of:
20
+
21
+ - `code`: Python source sent on stdin
22
+ - `scriptPath`: an existing script; relative paths resolve from `cwd`
23
+
24
+ Optional fields:
25
+
26
+ - `args`: direct Python argv, with no shell expansion
27
+ - `cwd`: working directory, defaulting to Pi's current directory
28
+ - `timeoutSeconds`: wall-clock timeout; default 30 seconds, maximum 300
29
+ - `maxOutputBytes`: returned bytes per stream; maximum 200,000
30
+
31
+ Pi invokes Python with `-B` and UTF-8/unbuffered environment settings. This avoids `__pycache__` footprints and makes output behavior consistent across Windows and Unix-like systems.
32
+
33
+ ## Output and performance
34
+
35
+ Stdout and stderr are streamed through fixed-budget accumulators. Returned output is bounded by lines and bytes; complete truncated streams spill under the process work directory in `~/.pi/agent/work/outputs/...`, never into the repository. Timeout and cancellation terminate the process tree, including commands that continue producing output.
36
+
37
+ Use `python` for bounded data shaping, structured transformations, and cross-platform logic when it is clearer than shell pipelines. Keep searches purpose-driven and scoped to explicit roots. Do not recursively scan a home directory or filesystem without explicit user intent and a justified timeout.
38
+
39
+ For small exact source edits, prefer `read`, `edit`, and `write`. When a Python transformation is necessary, preserve encoding and newline style, write atomically, and inspect the resulting diff.
40
+
41
+ ## Safety
42
+
43
+ `python` requires the same `run_shell` capability as `bash` and executes under the file-mutation barrier. Destructive filesystem APIs and nested subprocess execution are classified as approval-required. Credentials, package publication, push/tag/release, and destructive operations still require explicit human approval.
package/docs/resources.md CHANGED
@@ -31,7 +31,7 @@ In interactive mode, open `/settings` and choose **Resources** to reach the **Re
31
31
  |------|--------------|
32
32
  | **Profile / Situation** | Select the active profile. |
33
33
  | **Manage Library** | Browse everything available and toggle what the active profile allows. |
34
- | **Manage Profiles / Situations** | Create, persist, or delete profile definitions. |
34
+ | **Manage Profiles / Situations** | Create, edit the pinned/inherited model, persist, or delete profile definitions. |
35
35
  | **Sources** | Register, trust, and remove external catalog directories. |
36
36
 
37
37
  When no source or profile exists yet, the hub surfaces a first-run nudge — **"Add your catalog directory →"** — pointing you at the setup step below.
@@ -45,7 +45,7 @@ A profile is a complete allow/block contract over six kinds: `extensions`, `skil
45
45
 
46
46
  Under strict UAC, an unmentioned kind is denied. Granting every resource of a kind must be explicit with `allow: ["*"]`; `block: ["*"]` means "none." This keeps a saved situation exact when new extensions, tools, or other resources are installed later.
47
47
 
48
- A profile may also bind a **model**, **thinking level**, **soul**, and **modelRouter** block that apply when the profile is active. Thinking is one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, or `ultra`. Ultra uses the model's strongest mapped reasoning level and reinforces proactive delegation when the `delegate` tool is granted; delegation itself remains available independently on capable models. Explicit CLI flags still win over a profile's foreground model/thinking, which in turn win over the settings default. A profile's `modelRouter` block overrides matching global/project router fields while that situation is active.
48
+ A profile may also bind a **model**, **thinking level**, **soul**, and **modelRouter** block that apply when the profile is active. When `model` is omitted, the profile inherits the session/settings model. Use `/settings` → **Resources** → **Manage Profiles / Situations** → **Edit profile model** to pin a model or return an existing profile to inherited behavior; editing the active profile applies immediately through transactional reload. Thinking is one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, or `ultra`. Ultra uses the model's strongest mapped reasoning level and reinforces proactive delegation when the `delegate` tool is granted; delegation itself remains available independently on capable models. Explicit CLI flags still win over a profile's foreground model/thinking, which in turn win over the settings default. A profile's `modelRouter` block overrides matching global/project router fields while that situation is active.
49
49
 
50
50
  Pi activates the complete situation as one runtime generation: model/router, thinking, soul, extensions, skills, prompts, agents, themes, and tools are reloaded together. A failed reload restores the prior valid generation instead of persisting a partial selection.
51
51
 
package/docs/rpc.md CHANGED
@@ -456,7 +456,7 @@ If output was truncated, includes `fullOutputPath`:
456
456
  "exitCode": 0,
457
457
  "cancelled": false,
458
458
  "truncated": true,
459
- "fullOutputPath": "/tmp/pi-bash-abc123.log"
459
+ "fullOutputPath": "~/.pi/agent/work/outputs/tool-streams/<run-id>/pi-bash-abc123.log"
460
460
  }
461
461
  }
462
462
  ```
package/docs/settings.md CHANGED
@@ -267,7 +267,7 @@ Context GC only rewrites the provider-bound context view. It does not delete or
267
267
  | `contextGc.enabled` | boolean | `true` | Enable provider-context packing for stale bulky context |
268
268
  | `contextGc.preserveRecentMessages` | number | `12` | Recent messages kept verbatim |
269
269
  | `contextGc.minToolResultChars` | number | `2500` | Minimum stale tool-result size before packing |
270
- | `contextGc.tools` | string[] | `read`, `bash`, `rg`, `grep`, `context_headroom_retrieve`, `headroom_retrieve` | Tool results eligible for stale-output packing |
270
+ | `contextGc.tools` | string[] | `read`, `bash`, `python`, `powershell`, `rg`, `grep`, `context_headroom_retrieve`, `headroom_retrieve` | Tool results eligible for stale-output packing |
271
271
  | `contextGc.semanticMemory.enabled` | boolean | `true` | Pack stale Automata/Mind semantic context pages from provider context |
272
272
  | `contextGc.semanticMemory.preserveRecentPages` | number | `2` | Newest semantic memory pages kept verbatim |
273
273
  | `contextGc.semanticMemory.minChars` | number | `1200` | Minimum semantic page size before packing |
@@ -373,10 +373,14 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
373
373
 
374
374
  | Setting | Type | Default | Description |
375
375
  |---------|------|---------|-------------|
376
- | `shellPath` | string | - | Custom shell path (e.g., for Cygwin on Windows) |
377
- | `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
376
+ | `shellPath` | string | platform default | Custom platform-shell path (`pwsh.exe`/`powershell.exe` on Windows; Bash-compatible shell elsewhere) |
377
+ | `shellCommandPrefix` | string | - | Platform-shell snippet prepended to every command (for example, `"shopt -s expand_aliases"` on Bash) |
378
378
  | `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@20", "--", "npm"]`) |
379
379
 
380
+ Pi exposes one stable `bash` contract to the model on every platform. On Windows, the tool router parses a finite simple-command grammar, converts supported Bash-like forms to literal-path PowerShell, and rejects pipelines, redirection, expansion, chaining, nested shells, POSIX scripts, and unsupported builtin forms instead of guessing. Legacy `powershell` tool/profile references map to `bash`. The Windows backend prefers PowerShell 7 (`pwsh.exe`), falls back to Windows PowerShell, and runs with `-NoLogo -NoProfile -NonInteractive -Command` plus UTF-8 console output setup. `shellCommandPrefix` uses backend-native syntax because Pi applies it after routing. Agent, interactive, and RPC shell calls default to a 120-second wall-clock deadline; agent-tool overrides cap at one hour.
381
+
382
+ The native `python` tool is active by default and resolves Python through pinned `uv`. Pi provisions missing uv/Python during package postinstall, `pi update`, `pi doctor`, or first tool use. Python calls default to 30 seconds and cap explicit overrides at 300 seconds. See [Native Python](python.md).
383
+
380
384
  ```json
381
385
  {
382
386
  "npmCommand": ["mise", "exec", "node@20", "--", "npm"]