@cleocode/core 2026.6.12 → 2026.6.13

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 (385) hide show
  1. package/dist/conduit/local-transport.d.ts +12 -0
  2. package/dist/conduit/local-transport.d.ts.map +1 -1
  3. package/dist/conduit/local-transport.js +53 -23
  4. package/dist/conduit/local-transport.js.map +1 -1
  5. package/dist/crypto/credentials.d.ts +37 -0
  6. package/dist/crypto/credentials.d.ts.map +1 -1
  7. package/dist/crypto/credentials.js +110 -0
  8. package/dist/crypto/credentials.js.map +1 -1
  9. package/dist/dispatch/contracts/derive-output-contract.d.ts +86 -0
  10. package/dist/dispatch/contracts/derive-output-contract.d.ts.map +1 -0
  11. package/dist/dispatch/contracts/derive-output-contract.js +347 -0
  12. package/dist/dispatch/contracts/derive-output-contract.js.map +1 -0
  13. package/dist/dispatch/contracts/ensures-schema.d.ts +77 -0
  14. package/dist/dispatch/contracts/ensures-schema.d.ts.map +1 -0
  15. package/dist/dispatch/contracts/ensures-schema.js +91 -0
  16. package/dist/dispatch/contracts/ensures-schema.js.map +1 -0
  17. package/dist/dispatch/contracts/output-contracts.d.ts +27 -5
  18. package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -1
  19. package/dist/dispatch/contracts/output-contracts.js +29 -6
  20. package/dist/dispatch/contracts/output-contracts.js.map +1 -1
  21. package/dist/docs/export-document.js +2294 -1250
  22. package/dist/docs/export-document.js.map +3 -3
  23. package/dist/go/driver.d.ts +132 -7
  24. package/dist/go/driver.d.ts.map +1 -1
  25. package/dist/go/driver.js +135 -10
  26. package/dist/go/driver.js.map +1 -1
  27. package/dist/go/index.d.ts +1 -1
  28. package/dist/go/index.d.ts.map +1 -1
  29. package/dist/go/index.js +1 -1
  30. package/dist/go/index.js.map +1 -1
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +5 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal.d.ts +13 -10
  36. package/dist/internal.d.ts.map +1 -1
  37. package/dist/internal.js +11 -11
  38. package/dist/internal.js.map +1 -1
  39. package/dist/lifecycle/engine-ops.d.ts.map +1 -1
  40. package/dist/lifecycle/engine-ops.js +7 -4
  41. package/dist/lifecycle/engine-ops.js.map +1 -1
  42. package/dist/lifecycle/ivtr-loop.d.ts +108 -183
  43. package/dist/lifecycle/ivtr-loop.d.ts.map +1 -1
  44. package/dist/lifecycle/ivtr-loop.js +207 -522
  45. package/dist/lifecycle/ivtr-loop.js.map +1 -1
  46. package/dist/llm/auxiliary-fallback.js +1 -1
  47. package/dist/llm/auxiliary-fallback.js.map +1 -1
  48. package/dist/llm/cli-ops.d.ts +14 -1
  49. package/dist/llm/cli-ops.d.ts.map +1 -1
  50. package/dist/llm/cli-ops.js +41 -12
  51. package/dist/llm/cli-ops.js.map +1 -1
  52. package/dist/llm/concrete-session.d.ts.map +1 -1
  53. package/dist/llm/concrete-session.js +4 -0
  54. package/dist/llm/concrete-session.js.map +1 -1
  55. package/dist/llm/credentials.d.ts +35 -0
  56. package/dist/llm/credentials.d.ts.map +1 -1
  57. package/dist/llm/credentials.js +49 -0
  58. package/dist/llm/credentials.js.map +1 -1
  59. package/dist/llm/index.d.ts +4 -0
  60. package/dist/llm/index.d.ts.map +1 -1
  61. package/dist/llm/index.js +4 -0
  62. package/dist/llm/index.js.map +1 -1
  63. package/dist/llm/pi/gondolin-loader.d.ts +241 -0
  64. package/dist/llm/pi/gondolin-loader.d.ts.map +1 -0
  65. package/dist/llm/pi/gondolin-loader.js +195 -0
  66. package/dist/llm/pi/gondolin-loader.js.map +1 -0
  67. package/dist/llm/pi/index.d.ts +28 -0
  68. package/dist/llm/pi/index.d.ts.map +1 -0
  69. package/dist/llm/pi/index.js +27 -0
  70. package/dist/llm/pi/index.js.map +1 -0
  71. package/dist/llm/pi/pi-agent-adapter.d.ts +135 -0
  72. package/dist/llm/pi/pi-agent-adapter.d.ts.map +1 -0
  73. package/dist/llm/pi/pi-agent-adapter.js +329 -0
  74. package/dist/llm/pi/pi-agent-adapter.js.map +1 -0
  75. package/dist/llm/pi/pi-errors.d.ts +161 -0
  76. package/dist/llm/pi/pi-errors.d.ts.map +1 -0
  77. package/dist/llm/pi/pi-errors.js +296 -0
  78. package/dist/llm/pi/pi-errors.js.map +1 -0
  79. package/dist/llm/pi/pi-execution-env.d.ts +286 -0
  80. package/dist/llm/pi/pi-execution-env.d.ts.map +1 -0
  81. package/dist/llm/pi/pi-execution-env.js +406 -0
  82. package/dist/llm/pi/pi-execution-env.js.map +1 -0
  83. package/dist/llm/pi/pi-gondolin-env.d.ts +227 -0
  84. package/dist/llm/pi/pi-gondolin-env.d.ts.map +1 -0
  85. package/dist/llm/pi/pi-gondolin-env.js +541 -0
  86. package/dist/llm/pi/pi-gondolin-env.js.map +1 -0
  87. package/dist/llm/pi/pi-session-storage.d.ts +154 -0
  88. package/dist/llm/pi/pi-session-storage.d.ts.map +1 -0
  89. package/dist/llm/pi/pi-session-storage.js +314 -0
  90. package/dist/llm/pi/pi-session-storage.js.map +1 -0
  91. package/dist/llm/pi/pi-stream-fn.d.ts +124 -0
  92. package/dist/llm/pi/pi-stream-fn.d.ts.map +1 -0
  93. package/dist/llm/pi/pi-stream-fn.js +504 -0
  94. package/dist/llm/pi/pi-stream-fn.js.map +1 -0
  95. package/dist/llm/pi/pi-tool-bridge.d.ts +99 -0
  96. package/dist/llm/pi/pi-tool-bridge.d.ts.map +1 -0
  97. package/dist/llm/pi/pi-tool-bridge.js +117 -0
  98. package/dist/llm/pi/pi-tool-bridge.js.map +1 -0
  99. package/dist/llm/pi/pi-types.d.ts +56 -0
  100. package/dist/llm/pi/pi-types.d.ts.map +1 -0
  101. package/dist/llm/pi/pi-types.js +16 -0
  102. package/dist/llm/pi/pi-types.js.map +1 -0
  103. package/dist/llm/pi/resolve-execution-env.d.ts +194 -0
  104. package/dist/llm/pi/resolve-execution-env.d.ts.map +1 -0
  105. package/dist/llm/pi/resolve-execution-env.js +132 -0
  106. package/dist/llm/pi/resolve-execution-env.js.map +1 -0
  107. package/dist/llm/plugin-facade.js +2253 -1151
  108. package/dist/llm/plugin-facade.js.map +3 -3
  109. package/dist/llm/role-executor.d.ts.map +1 -1
  110. package/dist/llm/role-executor.js +8 -5
  111. package/dist/llm/role-executor.js.map +1 -1
  112. package/dist/llm/role-resolver.d.ts +46 -14
  113. package/dist/llm/role-resolver.d.ts.map +1 -1
  114. package/dist/llm/role-resolver.js +178 -20
  115. package/dist/llm/role-resolver.js.map +1 -1
  116. package/dist/llm/sealed-credential.d.ts +125 -0
  117. package/dist/llm/sealed-credential.d.ts.map +1 -0
  118. package/dist/llm/sealed-credential.js +133 -0
  119. package/dist/llm/sealed-credential.js.map +1 -0
  120. package/dist/llm/session-factory.d.ts.map +1 -1
  121. package/dist/llm/session-factory.js +6 -2
  122. package/dist/llm/session-factory.js.map +1 -1
  123. package/dist/llm/system-key.d.ts +67 -0
  124. package/dist/llm/system-key.d.ts.map +1 -0
  125. package/dist/llm/system-key.js +87 -0
  126. package/dist/llm/system-key.js.map +1 -0
  127. package/dist/llm/system-of-use-registry.d.ts +119 -0
  128. package/dist/llm/system-of-use-registry.d.ts.map +1 -0
  129. package/dist/llm/system-of-use-registry.js +200 -0
  130. package/dist/llm/system-of-use-registry.js.map +1 -0
  131. package/dist/llm/system-resolver.d.ts +32 -10
  132. package/dist/llm/system-resolver.d.ts.map +1 -1
  133. package/dist/llm/system-resolver.js +70 -18
  134. package/dist/llm/system-resolver.js.map +1 -1
  135. package/dist/memory/brain-writer-thread.d.ts.map +1 -1
  136. package/dist/memory/brain-writer-thread.js +116 -11
  137. package/dist/memory/brain-writer-thread.js.map +1 -1
  138. package/dist/memory/claude-mem-migration.d.ts.map +1 -1
  139. package/dist/memory/claude-mem-migration.js +21 -0
  140. package/dist/memory/claude-mem-migration.js.map +1 -1
  141. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  142. package/dist/memory/graph-memory-bridge.js +32 -25
  143. package/dist/memory/graph-memory-bridge.js.map +1 -1
  144. package/dist/memory/llm-backend-resolver.js +23 -5
  145. package/dist/memory/llm-backend-resolver.js.map +1 -1
  146. package/dist/nexus/migrations/M-split-graph.d.ts.map +1 -1
  147. package/dist/nexus/migrations/M-split-graph.js +60 -53
  148. package/dist/nexus/migrations/M-split-graph.js.map +1 -1
  149. package/dist/orchestrate/pivot.d.ts.map +1 -1
  150. package/dist/orchestrate/pivot.js +20 -2
  151. package/dist/orchestrate/pivot.js.map +1 -1
  152. package/dist/release/engine-ops.js +2 -2
  153. package/dist/release/engine-ops.js.map +1 -1
  154. package/dist/routing/capability-matrix.d.ts.map +1 -1
  155. package/dist/routing/capability-matrix.js +0 -57
  156. package/dist/routing/capability-matrix.js.map +1 -1
  157. package/dist/selfimprove/budget.d.ts +206 -0
  158. package/dist/selfimprove/budget.d.ts.map +1 -0
  159. package/dist/selfimprove/budget.js +203 -0
  160. package/dist/selfimprove/budget.js.map +1 -0
  161. package/dist/selfimprove/dhq-adapter.d.ts +105 -0
  162. package/dist/selfimprove/dhq-adapter.d.ts.map +1 -0
  163. package/dist/selfimprove/dhq-adapter.js +95 -0
  164. package/dist/selfimprove/dhq-adapter.js.map +1 -0
  165. package/dist/selfimprove/draft-pr.d.ts +129 -0
  166. package/dist/selfimprove/draft-pr.d.ts.map +1 -0
  167. package/dist/selfimprove/draft-pr.js +158 -0
  168. package/dist/selfimprove/draft-pr.js.map +1 -0
  169. package/dist/selfimprove/envelope-diff.d.ts +162 -0
  170. package/dist/selfimprove/envelope-diff.d.ts.map +1 -0
  171. package/dist/selfimprove/envelope-diff.js +321 -0
  172. package/dist/selfimprove/envelope-diff.js.map +1 -0
  173. package/dist/selfimprove/replay.d.ts +121 -0
  174. package/dist/selfimprove/replay.d.ts.map +1 -0
  175. package/dist/selfimprove/replay.js +109 -0
  176. package/dist/selfimprove/replay.js.map +1 -0
  177. package/dist/selfimprove/run-loop.d.ts +148 -0
  178. package/dist/selfimprove/run-loop.d.ts.map +1 -0
  179. package/dist/selfimprove/run-loop.js +240 -0
  180. package/dist/selfimprove/run-loop.js.map +1 -0
  181. package/dist/selfimprove/scenario.d.ts +145 -0
  182. package/dist/selfimprove/scenario.d.ts.map +1 -0
  183. package/dist/selfimprove/scenario.js +243 -0
  184. package/dist/selfimprove/scenario.js.map +1 -0
  185. package/dist/sentient/daemon-entry.js +5 -0
  186. package/dist/sentient/daemon-entry.js.map +1 -1
  187. package/dist/sentient/daemon.d.ts.map +1 -1
  188. package/dist/sentient/daemon.js +19 -0
  189. package/dist/sentient/daemon.js.map +1 -1
  190. package/dist/sentient/hygiene-scan.d.ts.map +1 -1
  191. package/dist/sentient/hygiene-scan.js +14 -6
  192. package/dist/sentient/hygiene-scan.js.map +1 -1
  193. package/dist/sessions/briefing.d.ts.map +1 -1
  194. package/dist/sessions/briefing.js +13 -9
  195. package/dist/sessions/briefing.js.map +1 -1
  196. package/dist/sessions/connection-session-handle.d.ts +161 -0
  197. package/dist/sessions/connection-session-handle.d.ts.map +1 -0
  198. package/dist/sessions/connection-session-handle.js +168 -0
  199. package/dist/sessions/connection-session-handle.js.map +1 -0
  200. package/dist/sessions/handoff.d.ts.map +1 -1
  201. package/dist/sessions/handoff.js +9 -0
  202. package/dist/sessions/handoff.js.map +1 -1
  203. package/dist/sessions/index.d.ts +4 -1
  204. package/dist/sessions/index.d.ts.map +1 -1
  205. package/dist/sessions/index.js +31 -1
  206. package/dist/sessions/index.js.map +1 -1
  207. package/dist/sessions/session-id.d.ts +34 -0
  208. package/dist/sessions/session-id.d.ts.map +1 -1
  209. package/dist/sessions/session-id.js +37 -0
  210. package/dist/sessions/session-id.js.map +1 -1
  211. package/dist/sessions/session-manifest-mirror.d.ts +115 -0
  212. package/dist/sessions/session-manifest-mirror.d.ts.map +1 -0
  213. package/dist/sessions/session-manifest-mirror.js +250 -0
  214. package/dist/sessions/session-manifest-mirror.js.map +1 -0
  215. package/dist/sessions/session-switch.d.ts.map +1 -1
  216. package/dist/sessions/session-switch.js +5 -2
  217. package/dist/sessions/session-switch.js.map +1 -1
  218. package/dist/store/converters.d.ts.map +1 -1
  219. package/dist/store/converters.js +2 -0
  220. package/dist/store/converters.js.map +1 -1
  221. package/dist/store/db-helpers.d.ts.map +1 -1
  222. package/dist/store/db-helpers.js +2 -0
  223. package/dist/store/db-helpers.js.map +1 -1
  224. package/dist/store/dual-scope-db.d.ts.map +1 -1
  225. package/dist/store/dual-scope-db.js +87 -47
  226. package/dist/store/dual-scope-db.js.map +1 -1
  227. package/dist/store/pi-session-store.d.ts +151 -0
  228. package/dist/store/pi-session-store.d.ts.map +1 -0
  229. package/dist/store/pi-session-store.js +166 -0
  230. package/dist/store/pi-session-store.js.map +1 -0
  231. package/dist/store/safety-data-accessor.d.ts +1 -0
  232. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  233. package/dist/store/safety-data-accessor.js +5 -0
  234. package/dist/store/safety-data-accessor.js.map +1 -1
  235. package/dist/store/schema/cleo-global/accounts.d.ts +357 -0
  236. package/dist/store/schema/cleo-global/accounts.d.ts.map +1 -0
  237. package/dist/store/schema/cleo-global/accounts.js +136 -0
  238. package/dist/store/schema/cleo-global/accounts.js.map +1 -0
  239. package/dist/store/schema/cleo-global/index.d.ts +2 -0
  240. package/dist/store/schema/cleo-global/index.d.ts.map +1 -1
  241. package/dist/store/schema/cleo-global/index.js +2 -0
  242. package/dist/store/schema/cleo-global/index.js.map +1 -1
  243. package/dist/store/schema/cleo-global/session-manifest.d.ts +217 -0
  244. package/dist/store/schema/cleo-global/session-manifest.d.ts.map +1 -0
  245. package/dist/store/schema/cleo-global/session-manifest.js +99 -0
  246. package/dist/store/schema/cleo-global/session-manifest.js.map +1 -0
  247. package/dist/store/schema/cleo-project/tasks-core.d.ts +16 -0
  248. package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
  249. package/dist/store/schema/cleo-project/tasks-core.js +14 -0
  250. package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
  251. package/dist/store/schema/tasks.d.ts +16 -0
  252. package/dist/store/schema/tasks.d.ts.map +1 -1
  253. package/dist/store/schema/tasks.js +10 -0
  254. package/dist/store/schema/tasks.js.map +1 -1
  255. package/dist/store/selfimprove-dhq-schema.d.ts +284 -0
  256. package/dist/store/selfimprove-dhq-schema.d.ts.map +1 -0
  257. package/dist/store/selfimprove-dhq-schema.js +128 -0
  258. package/dist/store/selfimprove-dhq-schema.js.map +1 -0
  259. package/dist/store/selfimprove-dhq-store.d.ts +175 -0
  260. package/dist/store/selfimprove-dhq-store.d.ts.map +1 -0
  261. package/dist/store/selfimprove-dhq-store.js +182 -0
  262. package/dist/store/selfimprove-dhq-store.js.map +1 -0
  263. package/dist/store/session-store.d.ts +52 -13
  264. package/dist/store/session-store.d.ts.map +1 -1
  265. package/dist/store/session-store.js +71 -13
  266. package/dist/store/session-store.js.map +1 -1
  267. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  268. package/dist/store/sqlite-data-accessor.js +7 -0
  269. package/dist/store/sqlite-data-accessor.js.map +1 -1
  270. package/dist/store/umbrella-data-accessor.d.ts +1 -0
  271. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  272. package/dist/store/umbrella-data-accessor.js +5 -0
  273. package/dist/store/umbrella-data-accessor.js.map +1 -1
  274. package/dist/store/validation-schemas.d.ts +32 -0
  275. package/dist/store/validation-schemas.d.ts.map +1 -1
  276. package/dist/store/writer-lease-schema.d.ts +392 -0
  277. package/dist/store/writer-lease-schema.d.ts.map +1 -0
  278. package/dist/store/writer-lease-schema.js +142 -0
  279. package/dist/store/writer-lease-schema.js.map +1 -0
  280. package/dist/store/writer-lease.d.ts +368 -0
  281. package/dist/store/writer-lease.d.ts.map +1 -0
  282. package/dist/store/writer-lease.js +1002 -0
  283. package/dist/store/writer-lease.js.map +1 -0
  284. package/dist/tasks/backfill-child-projections.d.ts.map +1 -1
  285. package/dist/tasks/backfill-child-projections.js +14 -9
  286. package/dist/tasks/backfill-child-projections.js.map +1 -1
  287. package/dist/tasks/complete.d.ts.map +1 -1
  288. package/dist/tasks/complete.js +7 -10
  289. package/dist/tasks/complete.js.map +1 -1
  290. package/dist/tasks/duplicate-detector.d.ts.map +1 -1
  291. package/dist/tasks/duplicate-detector.js +14 -7
  292. package/dist/tasks/duplicate-detector.js.map +1 -1
  293. package/dist/telemetry/index.d.ts.map +1 -1
  294. package/dist/telemetry/index.js +10 -4
  295. package/dist/telemetry/index.js.map +1 -1
  296. package/dist/tools/agent-registry.d.ts +250 -0
  297. package/dist/tools/agent-registry.d.ts.map +1 -0
  298. package/dist/tools/agent-registry.js +292 -0
  299. package/dist/tools/agent-registry.js.map +1 -0
  300. package/dist/tools/agent-tool-families.d.ts +107 -0
  301. package/dist/tools/agent-tool-families.d.ts.map +1 -0
  302. package/dist/tools/agent-tool-families.js +527 -0
  303. package/dist/tools/agent-tool-families.js.map +1 -0
  304. package/dist/tools/browser-driver.d.ts +183 -0
  305. package/dist/tools/browser-driver.d.ts.map +1 -0
  306. package/dist/tools/browser-driver.js +242 -0
  307. package/dist/tools/browser-driver.js.map +1 -0
  308. package/dist/tools/builtin-agent-tools.d.ts +36 -0
  309. package/dist/tools/builtin-agent-tools.d.ts.map +1 -0
  310. package/dist/tools/builtin-agent-tools.js +150 -0
  311. package/dist/tools/builtin-agent-tools.js.map +1 -0
  312. package/dist/tools/dispatch.d.ts +370 -0
  313. package/dist/tools/dispatch.d.ts.map +1 -0
  314. package/dist/tools/dispatch.js +505 -0
  315. package/dist/tools/dispatch.js.map +1 -0
  316. package/dist/tools/env-scrub.d.ts +93 -0
  317. package/dist/tools/env-scrub.d.ts.map +1 -0
  318. package/dist/tools/env-scrub.js +176 -0
  319. package/dist/tools/env-scrub.js.map +1 -0
  320. package/dist/tools/fs.d.ts +30 -0
  321. package/dist/tools/fs.d.ts.map +1 -1
  322. package/dist/tools/fs.js +55 -2
  323. package/dist/tools/fs.js.map +1 -1
  324. package/dist/tools/guard.d.ts +15 -0
  325. package/dist/tools/guard.d.ts.map +1 -1
  326. package/dist/tools/guard.js +49 -12
  327. package/dist/tools/guard.js.map +1 -1
  328. package/dist/tools/index.d.ts +10 -0
  329. package/dist/tools/index.d.ts.map +1 -1
  330. package/dist/tools/index.js +37 -0
  331. package/dist/tools/index.js.map +1 -1
  332. package/dist/tools/pty.d.ts +45 -0
  333. package/dist/tools/pty.d.ts.map +1 -0
  334. package/dist/tools/pty.js +166 -0
  335. package/dist/tools/pty.js.map +1 -0
  336. package/dist/tools/schema-gen.d.ts +57 -0
  337. package/dist/tools/schema-gen.d.ts.map +1 -0
  338. package/dist/tools/schema-gen.js +52 -0
  339. package/dist/tools/schema-gen.js.map +1 -0
  340. package/dist/tools/shell.d.ts +12 -0
  341. package/dist/tools/shell.d.ts.map +1 -1
  342. package/dist/tools/shell.js +14 -1
  343. package/dist/tools/shell.js.map +1 -1
  344. package/dist/tools/web-agent-tools.d.ts +72 -0
  345. package/dist/tools/web-agent-tools.d.ts.map +1 -0
  346. package/dist/tools/web-agent-tools.js +393 -0
  347. package/dist/tools/web-agent-tools.js.map +1 -0
  348. package/dist/tools/web-search-backends.d.ts +156 -0
  349. package/dist/tools/web-search-backends.d.ts.map +1 -0
  350. package/dist/tools/web-search-backends.js +290 -0
  351. package/dist/tools/web-search-backends.js.map +1 -0
  352. package/dist/validation/ops.d.ts +1 -15
  353. package/dist/validation/ops.d.ts.map +1 -1
  354. package/dist/validation/ops.js +0 -20
  355. package/dist/validation/ops.js.map +1 -1
  356. package/migrations/drizzle-cleo-global/20260607000000_t11891-writer-leases/migration.sql +55 -0
  357. package/migrations/drizzle-cleo-global/20260607010000_t11639-session-manifest/migration.sql +43 -0
  358. package/migrations/drizzle-cleo-global/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
  359. package/migrations/drizzle-cleo-global/20260608010000_t11709-accounts-credential-pool/migration.sql +72 -0
  360. package/migrations/drizzle-cleo-global/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
  361. package/migrations/drizzle-cleo-project/20260607000000_t11891-writer-leases/migration.sql +55 -0
  362. package/migrations/drizzle-cleo-project/20260607010000_t11639-session-parent/migration.sql +22 -0
  363. package/migrations/drizzle-cleo-project/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
  364. package/migrations/drizzle-cleo-project/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
  365. package/package.json +15 -13
  366. package/dist/lifecycle/chain-composition.d.ts +0 -30
  367. package/dist/lifecycle/chain-composition.d.ts.map +0 -1
  368. package/dist/lifecycle/chain-composition.js +0 -152
  369. package/dist/lifecycle/chain-composition.js.map +0 -1
  370. package/dist/lifecycle/chain-store.d.ts +0 -70
  371. package/dist/lifecycle/chain-store.d.ts.map +0 -1
  372. package/dist/lifecycle/chain-store.js +0 -246
  373. package/dist/lifecycle/chain-store.js.map +0 -1
  374. package/dist/lifecycle/default-chain.d.ts +0 -39
  375. package/dist/lifecycle/default-chain.d.ts.map +0 -1
  376. package/dist/lifecycle/default-chain.js +0 -176
  377. package/dist/lifecycle/default-chain.js.map +0 -1
  378. package/dist/lifecycle/tessera-engine.d.ts +0 -48
  379. package/dist/lifecycle/tessera-engine.d.ts.map +0 -1
  380. package/dist/lifecycle/tessera-engine.js +0 -249
  381. package/dist/lifecycle/tessera-engine.js.map +0 -1
  382. package/dist/validation/chain-validation.d.ts +0 -43
  383. package/dist/validation/chain-validation.d.ts.map +0 -1
  384. package/dist/validation/chain-validation.js +0 -146
  385. package/dist/validation/chain-validation.js.map +0 -1
@@ -0,0 +1,505 @@
1
+ /**
2
+ * Agent tool-call dispatch engine (T1740 · epic T11456 · SG-TOOLS).
3
+ *
4
+ * The SINGLE chokepoint that turns a model-emitted tool-call `{ name, args }`
5
+ * into an executed, LLM-safe result. It is the SDK-side dispatch path the T1738
6
+ * architecture (D11141) names: **core DISPATCHES, cleo-os DRIVES**. Given a tool
7
+ * call from the agent loop, it:
8
+ *
9
+ * 1. **Looks up** the tool in the injected {@link AgentToolRegistry} (the
10
+ * name→descriptor catalog). An unknown name is a typed
11
+ * `tool-not-found` result — never a throw.
12
+ * 2. **Validates** the model-supplied arguments against the tool's Zod schema
13
+ * (defense in depth: the wire layer advertised the JSON-schema, but the
14
+ * model's emitted args are re-validated here before any side effect). A
15
+ * schema failure is a typed `invalid-args` result carrying the FLATTENED
16
+ * issue list — not the raw Zod error (no internals leak).
17
+ * 3. **Checks availability** for the current {@link ToolAvailabilityContext}
18
+ * (network egress, binaries on PATH, capability flags). An unavailable tool
19
+ * is a typed `guard-denied` result — the model is told the tool is not
20
+ * offered right now, with no precondition internals.
21
+ * 4. **Charges the budget** ({@link ToolCallBudget}) — per-call count / wall-time
22
+ * ceilings. An exhausted budget short-circuits with a typed `guard-denied`
23
+ * result BEFORE the tool runs; a per-call timeout races the execution and
24
+ * yields a typed `timeout` result.
25
+ * 5. **Executes** the bound {@link AgentToolExecutable} over the injected
26
+ * {@link GuardedToolSurface} — the deny-first chokepoint
27
+ * ({@link ./guard.js}). Every fs/shell side effect therefore still funnels
28
+ * through the guard's path allowlist + command denylist + env scrub; there
29
+ * is NO raw-primitive bypass.
30
+ * 6. **Formats** the outcome for LLM consumption ({@link formatToolResultForLlm})
31
+ * — a `tool_result`-shaped payload the Pi loop feeds back to the model. On
32
+ * ANY error the message is a redacted, classified summary; a raw secret,
33
+ * stack trace, or guard internal NEVER reaches the model-facing string.
34
+ *
35
+ * ## Sync + async handlers (AC2)
36
+ *
37
+ * A registered {@link AgentToolExecutable} returns a `Promise<unknown>`, but a
38
+ * synchronous handler that returns a plain value is equally supported: the
39
+ * engine `await`s the call so a non-thenable return is normalized to a resolved
40
+ * value, and a synchronous throw is caught the same as a rejected promise.
41
+ *
42
+ * ## Why it lives in `core/src/tools` (Gate-11)
43
+ *
44
+ * The dispatch engine is a CORE-SDK concern, built entirely against the frozen
45
+ * {@link AgentToolRegistry} + {@link GuardedToolSurface} contracts. It defines
46
+ * NO new atomic tool primitive (Gate-11 Tools-vs-Skills boundary) and makes NO
47
+ * LLM call (Gate-13): result-formatting is pure serialization. The harness
48
+ * (`cleo-os`) and the in-process Pi adapter merely SUPPLY the registry, the
49
+ * guard, and the workspace context, then read the {@link ToolDispatchResult}.
50
+ *
51
+ * @task T1740
52
+ * @epic T11456
53
+ * @see ./agent-registry.js — the name→descriptor catalog + availability checks
54
+ * @see ./guard.js — the deny-first surface every executable routes side effects through
55
+ * @see ../llm/pi/pi-tool-bridge.js — the AC6 consumer wiring this into the Pi loop
56
+ */
57
+ import { getLogger } from '../logger.js';
58
+ import { ALWAYS_AVAILABLE } from './agent-registry.js';
59
+ const log = getLogger('tool-dispatch');
60
+ /**
61
+ * Stable machine-readable error codes, one per {@link ToolDispatchErrorKind}.
62
+ * Surfaced on the failure envelope so a programmatic caller never string-matches
63
+ * the human message.
64
+ */
65
+ export const TOOL_DISPATCH_ERROR_CODE = {
66
+ 'tool-not-found': 'E_TOOL_NOT_FOUND',
67
+ 'invalid-args': 'E_TOOL_INVALID_ARGS',
68
+ 'guard-denied': 'E_TOOL_GUARD_DENIED',
69
+ 'execution-error': 'E_TOOL_EXECUTION_ERROR',
70
+ timeout: 'E_TOOL_TIMEOUT',
71
+ };
72
+ /**
73
+ * Per-run tool-call budget (AC5). Tracks call count + cumulative wall-time
74
+ * against the configured {@link ToolBudgetLimits}. The engine consults
75
+ * {@link admit} BEFORE running a tool (rejecting once a ceiling is hit) and
76
+ * {@link charge}s the elapsed time AFTER. A single budget instance is threaded
77
+ * across all calls of one run, so the count/time caps are run-scoped.
78
+ */
79
+ export class ToolCallBudget {
80
+ #limits;
81
+ #callsUsed = 0;
82
+ #timeUsedMs = 0;
83
+ /**
84
+ * @param limits - The ceilings this budget enforces (each optional → uncapped).
85
+ */
86
+ constructor(limits = {}) {
87
+ this.#limits = limits;
88
+ }
89
+ /** The per-call timeout ceiling in ms, or `undefined` when uncapped. */
90
+ get perCallTimeoutMs() {
91
+ return this.#limits.perCallTimeoutMs;
92
+ }
93
+ /**
94
+ * Whether another call is admitted right now. Returns a typed denial reason
95
+ * (or `null` when admitted) so the engine can map it onto the precise
96
+ * `guard-denied` message WITHOUT exposing the limit internals to the model.
97
+ *
98
+ * @returns `null` when a call is admitted; otherwise the human-readable reason.
99
+ */
100
+ admit() {
101
+ if (this.#limits.maxCalls !== undefined && this.#callsUsed >= this.#limits.maxCalls) {
102
+ return `tool-call budget exhausted (max ${this.#limits.maxCalls} calls)`;
103
+ }
104
+ if (this.#limits.totalTimeBudgetMs !== undefined &&
105
+ this.#timeUsedMs >= this.#limits.totalTimeBudgetMs) {
106
+ return `tool-call time budget exhausted (max ${this.#limits.totalTimeBudgetMs}ms)`;
107
+ }
108
+ return null;
109
+ }
110
+ /**
111
+ * Charge one completed call against the budget.
112
+ *
113
+ * @param elapsedMs - The call's measured wall-time in milliseconds.
114
+ */
115
+ charge(elapsedMs) {
116
+ this.#callsUsed += 1;
117
+ this.#timeUsedMs += Math.max(0, elapsedMs);
118
+ }
119
+ /** A read-only snapshot of current consumption (AC5). */
120
+ snapshot() {
121
+ const callsRemaining = this.#limits.maxCalls === undefined
122
+ ? Number.POSITIVE_INFINITY
123
+ : Math.max(0, this.#limits.maxCalls - this.#callsUsed);
124
+ const timeRemainingMs = this.#limits.totalTimeBudgetMs === undefined
125
+ ? Number.POSITIVE_INFINITY
126
+ : Math.max(0, this.#limits.totalTimeBudgetMs - this.#timeUsedMs);
127
+ return {
128
+ callsUsed: this.#callsUsed,
129
+ callsRemaining,
130
+ timeUsedMs: this.#timeUsedMs,
131
+ timeRemainingMs,
132
+ };
133
+ }
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // Engine
137
+ // ---------------------------------------------------------------------------
138
+ /** Maximum length of a formatted `tool_result` body before truncation (AC4). */
139
+ export const MAX_TOOL_RESULT_CHARS = 16_000;
140
+ /**
141
+ * The agent tool-call dispatch engine (AC1).
142
+ *
143
+ * One instance per agent run: it holds the frozen registry, the guarded surface,
144
+ * the availability context, and the run-scoped budget, and dispatches each
145
+ * model-emitted {@link ToolCall} to a classified {@link ToolDispatchResult}.
146
+ * {@link dispatch} NEVER throws — every failure mode is encoded as a typed
147
+ * {@link ToolDispatchFailure} (AC3), so the agent loop can always feed a
148
+ * `tool_result` back and continue.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * const registry = await createAgentToolRegistry();
153
+ * const tools = createToolGuard({ allowedRoots: [root], mode: 'enforce' });
154
+ * const engine = new ToolDispatchEngine({
155
+ * registry,
156
+ * tools,
157
+ * budget: new ToolCallBudget({ maxCalls: 50, perCallTimeoutMs: 30_000 }),
158
+ * });
159
+ * const result = await engine.dispatch({ id: 'c1', name: 'read_file_paged', arguments: { path } });
160
+ * // result.ok ? feed result.display : feed the classified result.message
161
+ * ```
162
+ */
163
+ export class ToolDispatchEngine {
164
+ #registry;
165
+ #tools;
166
+ #availability;
167
+ #budget;
168
+ /**
169
+ * @param deps - The registry, guarded surface, availability context, and
170
+ * optional run-scoped budget.
171
+ */
172
+ constructor(deps) {
173
+ this.#registry = deps.registry;
174
+ this.#tools = deps.tools;
175
+ this.#availability = deps.availability ?? {};
176
+ this.#budget = deps.budget ?? new ToolCallBudget();
177
+ }
178
+ /** A read-only snapshot of the run's budget consumption (AC5). */
179
+ budgetSnapshot() {
180
+ return this.#budget.snapshot();
181
+ }
182
+ /**
183
+ * Dispatch a single model-emitted tool call to a classified result (AC1–AC5).
184
+ *
185
+ * The full pipeline — lookup → validate → availability → budget admit →
186
+ * (timed) execute → charge → format — runs here. It NEVER throws: a thrown
187
+ * executable (incl. a deny-first `GuardDeniedError` during the side effect)
188
+ * becomes an `execution-error`, a slow executable a `timeout`, a cancelled call
189
+ * an `execution-error`, an unknown name a `tool-not-found`, bad args an
190
+ * `invalid-args`, and an unavailable tool / exhausted budget a `guard-denied`.
191
+ *
192
+ * ## Abort handling (honest contract)
193
+ *
194
+ * A `signal` (when supplied) is honoured REGARDLESS of whether a per-call
195
+ * timeout is configured — including the default no-budget production path: an
196
+ * already-aborted signal short-circuits before the executable is awaited, and
197
+ * an abort RACED in flight rejects with an `execution-error`. BUT this is
198
+ * abandon-the-promise cancellation, NOT preemptive kill: the frozen
199
+ * {@link AgentToolExecutable}/{@link GuardedToolSurface} contracts expose no
200
+ * signal channel, so a tool that already spawned an OS process keeps that
201
+ * process running until the tool's own internal bound fires. The engine
202
+ * returns promptly; the side effect may still be settling. See
203
+ * {@link ToolDispatchEngine.#runWithTimeout} for the full rationale.
204
+ *
205
+ * @param call - The model-emitted tool call (`{ id, name, arguments }`).
206
+ * @param signal - Optional abort signal honoured on every path (timeout or
207
+ * not); aborting yields an `execution-error` but cannot preemptively kill an
208
+ * in-flight OS process (frozen-contract limitation).
209
+ * @returns The terminal {@link ToolDispatchResult}.
210
+ */
211
+ async dispatch(call, signal) {
212
+ // 1. Lookup (AC1).
213
+ const descriptor = this.#registry.get(call.name);
214
+ if (!descriptor) {
215
+ return this.#fail(call.name, 'tool-not-found', `unknown tool "${call.name}"`);
216
+ }
217
+ // 2. Validate arguments against the tool's Zod schema (AC3 — defense in depth).
218
+ const parsed = descriptor.parameters.safeParse(call.arguments);
219
+ if (!parsed.success) {
220
+ const issues = flattenZodIssues(parsed.error);
221
+ return this.#fail(call.name, 'invalid-args', `arguments for "${call.name}" failed validation`, issues);
222
+ }
223
+ // 3. Availability check (AC5 — registry availability predicates).
224
+ const available = (descriptor.available ?? ALWAYS_AVAILABLE)(this.#availability);
225
+ if (!available) {
226
+ return this.#fail(call.name, 'guard-denied', `tool "${call.name}" is not available in the current context`);
227
+ }
228
+ // 4. Budget admit (AC5 — count/time ceilings BEFORE running).
229
+ const denial = this.#budget.admit();
230
+ if (denial !== null) {
231
+ return this.#fail(call.name, 'guard-denied', denial);
232
+ }
233
+ // 5. Timed execution through the guarded surface (AC2 sync/async + AC5 timeout).
234
+ // `parsed.data` is the schema-validated argument object; a tool's `parameters`
235
+ // is always a Zod object schema, so the validated value is a record. Coerce to
236
+ // the executable's input shape (the generic `z.ZodType` infers `unknown`).
237
+ const validatedArgs = isRecord(parsed.data)
238
+ ? parsed.data
239
+ : {};
240
+ const startedAt = Date.now();
241
+ try {
242
+ const value = await this.#runWithTimeout(descriptor, validatedArgs, signal);
243
+ this.#budget.charge(Date.now() - startedAt);
244
+ // 6. Format the success for LLM consumption (AC4).
245
+ return { ok: true, name: call.name, value, display: formatToolValueForLlm(value) };
246
+ }
247
+ catch (err) {
248
+ // Charge the elapsed time even on failure so a long-running failed call
249
+ // still counts against the time budget (AC5).
250
+ this.#budget.charge(Date.now() - startedAt);
251
+ if (err instanceof ToolTimeoutError) {
252
+ return this.#fail(call.name, 'timeout', err.message);
253
+ }
254
+ if (err instanceof ToolAbortError) {
255
+ // Cancellation is an execution-error (the call did not complete). The
256
+ // engine-authored abort message carries no secret, so it is safe verbatim.
257
+ log.debug({ tool: call.name, kind: 'execution-error' }, 'tool dispatch aborted');
258
+ return this.#fail(call.name, 'execution-error', err.message);
259
+ }
260
+ // Any thrown executable error (incl. a deny-first GuardDeniedError raised
261
+ // DURING the side effect) is an execution-error. The message is REDACTED
262
+ // (AC3) — no raw secret/stack reaches the model-facing result.
263
+ const redacted = redactErrorMessage(err);
264
+ log.debug({ tool: call.name, kind: 'execution-error' }, 'tool dispatch execution failed');
265
+ return this.#fail(call.name, 'execution-error', redacted);
266
+ }
267
+ }
268
+ /**
269
+ * Run the executable, racing it against the per-call timeout AND the abort
270
+ * signal whenever EITHER is present.
271
+ *
272
+ * Both a synchronous return value and a `Promise` are handled: `await`ing a
273
+ * non-thenable normalizes it to a resolved value, and a synchronous throw is
274
+ * caught by {@link dispatch}'s surrounding `try` exactly like a rejection
275
+ * (AC2). The timeout rejects with a {@link ToolTimeoutError} the caller maps
276
+ * to a `timeout` result; an abort rejects with a {@link ToolAbortError} the
277
+ * caller maps to an `execution-error` (the call was cancelled, not slow).
278
+ *
279
+ * ## Fast path
280
+ *
281
+ * When NO timeout is configured AND no `signal` is supplied there is nothing
282
+ * to race, so the executable promise is returned directly — the engine adds no
283
+ * overhead to the common bounded-by-the-loop case.
284
+ *
285
+ * ## Cancellation is cooperative-or-abandon, NOT preemptive
286
+ *
287
+ * Winning the race (timeout or abort) only ABANDONS the executable promise —
288
+ * it does NOT cancel the running tool. The frozen {@link AgentToolExecutable}
289
+ * signature (`(args, tools) => Promise<unknown>`) and the frozen
290
+ * {@link GuardedToolSurface} (whose `executeShell`/`executePty`/`runGit` carry
291
+ * no `AbortSignal` parameter) expose NO cancellation channel, so a tool that
292
+ * spawned a real OS process keeps that process running in the background until
293
+ * the tool's OWN internal bound (its per-call `timeoutMs`, when the model
294
+ * supplied one) fires. The engine therefore returns a `timeout`/`execution-error`
295
+ * result to the model PROMPTLY while the underlying side effect may still be
296
+ * settling. This is the honest contract: the dispatch-level cap bounds how long
297
+ * the LOOP waits, not how long the OS process lives. Wiring a real signal
298
+ * through to the surface requires evolving the frozen registry +
299
+ * `GuardedToolSurface` contracts (out of T1740's scope — tracked for the
300
+ * contract owner of #1013).
301
+ */
302
+ async #runWithTimeout(descriptor, args, signal) {
303
+ const timeoutMs = this.#budget.perCallTimeoutMs;
304
+ // `Promise.resolve(...)` normalizes a synchronous (non-thenable) return into
305
+ // a resolved promise; a synchronous throw inside `execute` rejects it.
306
+ const run = Promise.resolve(descriptor.execute(args, this.#tools));
307
+ // Fast path: nothing to race against → return the executable directly.
308
+ if (timeoutMs === undefined && signal === undefined)
309
+ return run;
310
+ // A pre-aborted signal short-circuits BEFORE awaiting the run — the abort was
311
+ // already requested, so the engine must not wait for (nor charge a full
312
+ // timeout for) the in-flight call. This is the default-production path the
313
+ // no-budget config exercises: the signal is honoured even with no timeout.
314
+ if (signal?.aborted) {
315
+ throw new ToolAbortError(`tool "${descriptor.name}" call aborted`);
316
+ }
317
+ let timer;
318
+ let onAbort;
319
+ const interrupt = new Promise((_resolve, reject) => {
320
+ // Wire the per-call timeout only when one is configured.
321
+ if (timeoutMs !== undefined) {
322
+ timer = setTimeout(() => reject(new ToolTimeoutError(`tool "${descriptor.name}" exceeded the per-call timeout of ${timeoutMs}ms`)), timeoutMs);
323
+ }
324
+ // Wire the abort listener whenever a (not-yet-aborted) signal is present —
325
+ // independent of whether a timeout is set, so the default no-budget path
326
+ // still honours containment-managed cancellation.
327
+ if (signal) {
328
+ onAbort = () => reject(new ToolAbortError(`tool "${descriptor.name}" call aborted`));
329
+ signal.addEventListener('abort', onAbort, { once: true });
330
+ }
331
+ });
332
+ try {
333
+ return await Promise.race([run, interrupt]);
334
+ }
335
+ finally {
336
+ if (timer)
337
+ clearTimeout(timer);
338
+ if (signal && onAbort)
339
+ signal.removeEventListener('abort', onAbort);
340
+ }
341
+ }
342
+ /** Build a classified {@link ToolDispatchFailure}. */
343
+ #fail(name, kind, message, issues) {
344
+ return {
345
+ ok: false,
346
+ name,
347
+ kind,
348
+ code: TOOL_DISPATCH_ERROR_CODE[kind],
349
+ message,
350
+ ...(issues !== undefined ? { issues } : {}),
351
+ };
352
+ }
353
+ }
354
+ /** Thrown internally when a tool call exceeds its per-call timeout (AC5). */
355
+ export class ToolTimeoutError extends Error {
356
+ /** Machine-readable code. */
357
+ code = 'E_TOOL_TIMEOUT';
358
+ constructor(message) {
359
+ super(message);
360
+ this.name = 'ToolTimeoutError';
361
+ }
362
+ }
363
+ /**
364
+ * Thrown internally when a tool call is cancelled via its {@link AbortSignal}
365
+ * (containment-managed run cancel / OOM-guard / budget kill). Distinct from
366
+ * {@link ToolTimeoutError}: a timeout means "the call was too slow", an abort
367
+ * means "the run was cancelled out from under the call". The engine maps it to a
368
+ * typed `execution-error` result (the call did not complete).
369
+ *
370
+ * @remarks Winning the abort race only ABANDONS the executable promise — it does
371
+ * NOT preemptively kill a tool that already spawned an OS process, because the
372
+ * frozen {@link AgentToolExecutable}/{@link GuardedToolSurface} contracts carry
373
+ * no signal channel (see {@link ToolDispatchEngine.dispatch}).
374
+ */
375
+ export class ToolAbortError extends Error {
376
+ /** Machine-readable code. */
377
+ code = 'E_TOOL_ABORTED';
378
+ constructor(message) {
379
+ super(message);
380
+ this.name = 'ToolAbortError';
381
+ }
382
+ }
383
+ // ---------------------------------------------------------------------------
384
+ // Result formatting (AC4)
385
+ // ---------------------------------------------------------------------------
386
+ /**
387
+ * Render a tool's raw return value into the LLM-facing `tool_result` body (AC4).
388
+ *
389
+ * A string passes through; everything else is JSON-serialized (pretty, stable).
390
+ * A circular / non-serializable value degrades to its `String(...)` form rather
391
+ * than throwing. The result is hard-capped at {@link MAX_TOOL_RESULT_CHARS} with
392
+ * a truncation marker so one tool call cannot blow the model's context window.
393
+ *
394
+ * @param value - The raw tool return.
395
+ * @returns The model-safe `tool_result` string.
396
+ */
397
+ export function formatToolValueForLlm(value) {
398
+ let rendered;
399
+ if (typeof value === 'string') {
400
+ rendered = value;
401
+ }
402
+ else if (value === undefined) {
403
+ rendered = '';
404
+ }
405
+ else {
406
+ try {
407
+ rendered = JSON.stringify(value, null, 2) ?? String(value);
408
+ }
409
+ catch {
410
+ // Circular / BigInt / non-serializable — degrade rather than throw.
411
+ rendered = String(value);
412
+ }
413
+ }
414
+ return truncateForLlm(rendered);
415
+ }
416
+ /**
417
+ * Project a terminal {@link ToolDispatchResult} onto the `tool_result` message
418
+ * shape the agent loop feeds back to the model (AC4).
419
+ *
420
+ * The `content` is `result.display` on success or the redacted, classified
421
+ * `result.message` on failure (with the flattened arg issues appended when
422
+ * present). `isError` lets the loop / transport mark the turn so the model knows
423
+ * the call did not succeed.
424
+ *
425
+ * @param result - The dispatch outcome.
426
+ * @returns A `{ toolCallId, toolName, content, isError }` envelope.
427
+ */
428
+ export function formatToolResultForLlm(call, result) {
429
+ if (result.ok) {
430
+ return { toolCallId: call.id, toolName: result.name, content: result.display, isError: false };
431
+ }
432
+ const issuesText = result.issues && result.issues.length > 0
433
+ ? `\n${result.issues.map((i) => `- ${i.path ? `${i.path}: ` : ''}${i.message}`).join('\n')}`
434
+ : '';
435
+ return {
436
+ toolCallId: call.id,
437
+ toolName: result.name,
438
+ content: `[${result.code}] ${result.message}${issuesText}`,
439
+ isError: true,
440
+ };
441
+ }
442
+ // ---------------------------------------------------------------------------
443
+ // Redaction + helpers
444
+ // ---------------------------------------------------------------------------
445
+ /** Truncate a rendered result to {@link MAX_TOOL_RESULT_CHARS} with a marker. */
446
+ function truncateForLlm(text) {
447
+ if (text.length <= MAX_TOOL_RESULT_CHARS)
448
+ return text;
449
+ const head = text.slice(0, MAX_TOOL_RESULT_CHARS);
450
+ const omitted = text.length - MAX_TOOL_RESULT_CHARS;
451
+ return `${head}\n…[truncated ${omitted} chars]`;
452
+ }
453
+ /**
454
+ * Produce a REDACTED, model-safe message from a thrown executable error (AC3).
455
+ *
456
+ * Only the error's single-line `message` is kept — never the stack trace (which
457
+ * can leak absolute paths / internal module structure) and never an attached
458
+ * `cause`. The message itself is scrubbed for obvious secret-looking tokens so a
459
+ * tool that interpolates a credential into its error string cannot leak it to
460
+ * the model. A non-`Error` throw degrades to a fixed, generic summary.
461
+ *
462
+ * @param err - The thrown value.
463
+ * @returns A single-line, secret-scrubbed message safe for the model.
464
+ */
465
+ export function redactErrorMessage(err) {
466
+ const raw = err instanceof Error ? err.message : typeof err === 'string' ? err : 'tool execution failed';
467
+ // Keep a single line (drop any embedded newlines/stack-like content) and cap
468
+ // the length so a runaway message cannot dominate the context window.
469
+ const firstLine = raw.split('\n', 1)[0] ?? 'tool execution failed';
470
+ return scrubSecrets(firstLine).slice(0, 500);
471
+ }
472
+ /**
473
+ * Best-effort secret scrub for a model-facing string. Masks the high-signal
474
+ * secret shapes (provider key prefixes, bearer tokens, long base64-ish blobs)
475
+ * so a leaked credential cannot reach the LLM-facing result. This is a
476
+ * defense-in-depth net on TOP of the architecture's rule that no plaintext key
477
+ * is ever in scope here — not a substitute for it.
478
+ *
479
+ * @param text - The candidate message.
480
+ * @returns The message with secret-looking tokens masked.
481
+ */
482
+ function scrubSecrets(text) {
483
+ return text
484
+ .replace(/\b(sk|pk|rk|ghp|gho|ghs|xoxb|xoxp|AKIA)[-_a-zA-Z0-9]{12,}\b/g, '[redacted]')
485
+ .replace(/\bBearer\s+[A-Za-z0-9._-]{12,}\b/gi, 'Bearer [redacted]')
486
+ .replace(/\beyJ[A-Za-z0-9._-]{20,}\b/g, '[redacted-jwt]');
487
+ }
488
+ /**
489
+ * Flatten a {@link z.ZodError} into the minimal, model-safe
490
+ * {@link ToolArgIssue}[] — path + reason only, no raw Zod internals.
491
+ *
492
+ * @param error - The Zod validation error.
493
+ * @returns The flattened issues.
494
+ */
495
+ export function flattenZodIssues(error) {
496
+ return error.issues.map((issue) => ({
497
+ path: issue.path.map(String).join('.'),
498
+ message: issue.message,
499
+ }));
500
+ }
501
+ /** Narrow an unknown to a plain (non-array) record. */
502
+ function isRecord(value) {
503
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
504
+ }
505
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/tools/dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Subprocess environment scrubbing (T11897 · S1 · security hardening).
3
+ *
4
+ * Building the environment a child process inherits is a SECURITY boundary, not
5
+ * a convenience. Two distinct threats are closed here:
6
+ *
7
+ * 1. **Sandbox escape via Pi-controlled env** — a model-driven loop that can
8
+ * set `LD_PRELOAD`, `NODE_OPTIONS`, `GIT_SSH_COMMAND`, `DYLD_*`, or a custom
9
+ * `PATH` gains arbitrary native code execution outside any command allowlist
10
+ * (the OS loader / Node honour them) and can satisfy a basename denylist with
11
+ * a workspace-resident impostor on a hijacked `PATH`. The scrubber NEVER
12
+ * forwards any of these dangerous variables and PINS `PATH` to a trusted
13
+ * absolute value.
14
+ * 2. **Daemon-secret exfiltration** — the daemon's own `process.env` carries
15
+ * resolved provider credentials (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …),
16
+ * OAuth headers, and vault material (`CLEO_VAULT_*`). Inheriting the full
17
+ * parent env into a Pi-spawned child means a single `env`/`printenv`/log line
18
+ * exfiltrates them. The scrubber builds a MINIMAL, explicitly-constructed env
19
+ * instead of inheriting `process.env`.
20
+ *
21
+ * The doctrine is **allowlist, not denylist**: the scrubbed env starts EMPTY and
22
+ * only a small set of benign, named variables are copied through from the parent
23
+ * (locale, terminal, home/user, tmp). Everything else — including every secret,
24
+ * every loader hook, and `PATH` itself — is reconstructed from trusted inputs.
25
+ *
26
+ * Pure function of input — no global/session coupling, import-time side-effect
27
+ * free (S1).
28
+ *
29
+ * @epic T10403
30
+ * @task T11761
31
+ * @task T11897
32
+ * @saga T11387
33
+ */
34
+ /**
35
+ * The trusted, absolute `PATH` a scrubbed subprocess runs under. A fixed list of
36
+ * standard system binary directories — NEVER the caller's (possibly Pi-poisoned)
37
+ * `PATH`. Pinning this defeats the "workspace-resident impostor on a hijacked
38
+ * PATH satisfies an allowed basename" escape: the workspace is not on it.
39
+ */
40
+ export declare const TRUSTED_PATH: string;
41
+ /** Options for {@link scrubSubprocessEnv}. */
42
+ export interface ScrubEnvOptions {
43
+ /**
44
+ * The parent environment to copy the benign {@link PASSTHROUGH_KEYS} from.
45
+ * Defaults to `process.env`. Injectable for tests so a clean env can be
46
+ * asserted without mutating the real process environment.
47
+ */
48
+ readonly parentEnv?: Readonly<Record<string, string | undefined>>;
49
+ /**
50
+ * Extra variables to set on the scrubbed env (e.g. a caller-supplied `env`
51
+ * merged ON TOP of the minimal base). These are themselves SCRUBBED — any
52
+ * dangerous key (loader hooks, `PATH`, secrets) is dropped, so an untrusted
53
+ * caller (Pi) cannot reintroduce an escape through this channel.
54
+ */
55
+ readonly extra?: Readonly<Record<string, string | undefined>>;
56
+ /**
57
+ * The trusted `PATH` to pin. Defaults to {@link TRUSTED_PATH}. Callers MUST
58
+ * pass an absolute, trusted value — never the inbound/Pi-controlled `PATH`.
59
+ */
60
+ readonly path?: string;
61
+ }
62
+ /**
63
+ * Whether a variable NAME is forbidden in a scrubbed subprocess env (a loader
64
+ * hook, `PATH`, or a credential).
65
+ *
66
+ * @param name - The environment variable name.
67
+ * @returns `true` when the variable must NOT be forwarded.
68
+ */
69
+ export declare function isForbiddenEnvName(name: string): boolean;
70
+ /**
71
+ * Build a MINIMAL, explicitly-constructed subprocess environment.
72
+ *
73
+ * The result starts EMPTY; only the benign {@link PASSTHROUGH_KEYS} present in
74
+ * `parentEnv` are copied, `PATH` is pinned to a trusted absolute value, and any
75
+ * caller-supplied `extra` is merged ON TOP after being filtered through
76
+ * {@link isForbiddenEnvName}. The daemon's secrets and any loader hooks in the
77
+ * parent environment are therefore NEVER visible to the child, and an untrusted
78
+ * caller cannot reintroduce an escape via `extra`.
79
+ *
80
+ * @param options - {@link ScrubEnvOptions}.
81
+ * @returns A fresh `Record<string, string>` safe to hand to `spawn(..., { env })`.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // A Pi-supplied env that tries to inject a loader hook + hijack PATH:
86
+ * const env = scrubSubprocessEnv({
87
+ * extra: { LD_PRELOAD: '/tmp/evil.so', PATH: '/workspace', SAFE: '1' },
88
+ * });
89
+ * // env has no LD_PRELOAD, PATH is the pinned TRUSTED_PATH, only SAFE survives.
90
+ * ```
91
+ */
92
+ export declare function scrubSubprocessEnv(options?: ScrubEnvOptions): Record<string, string>;
93
+ //# sourceMappingURL=env-scrub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-scrub.d.ts","sourceRoot":"","sources":["../../src/tools/env-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAOR,CAAC;AAsBlB,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAClE;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC9D;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAiDD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMxD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0BxF"}