@caupulican/pi-adaptative 0.80.86 → 0.80.89

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 (353) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/dist/core/agent-session.d.ts +412 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +2053 -41
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/approval-gate.d.ts +4 -0
  7. package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
  8. package/dist/core/autonomy/approval-gate.js +27 -0
  9. package/dist/core/autonomy/approval-gate.js.map +1 -0
  10. package/dist/core/autonomy/bounded-completion.d.ts +27 -0
  11. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
  12. package/dist/core/autonomy/bounded-completion.js +44 -0
  13. package/dist/core/autonomy/bounded-completion.js.map +1 -0
  14. package/dist/core/autonomy/contracts.d.ts +129 -0
  15. package/dist/core/autonomy/contracts.d.ts.map +1 -0
  16. package/dist/core/autonomy/contracts.js +2 -0
  17. package/dist/core/autonomy/contracts.js.map +1 -0
  18. package/dist/core/autonomy/gates.d.ts +15 -0
  19. package/dist/core/autonomy/gates.d.ts.map +1 -0
  20. package/dist/core/autonomy/gates.js +205 -0
  21. package/dist/core/autonomy/gates.js.map +1 -0
  22. package/dist/core/autonomy/lane-tracker.d.ts +48 -0
  23. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
  24. package/dist/core/autonomy/lane-tracker.js +125 -0
  25. package/dist/core/autonomy/lane-tracker.js.map +1 -0
  26. package/dist/core/autonomy/path-scope.d.ts +9 -0
  27. package/dist/core/autonomy/path-scope.d.ts.map +1 -0
  28. package/dist/core/autonomy/path-scope.js +122 -0
  29. package/dist/core/autonomy/path-scope.js.map +1 -0
  30. package/dist/core/autonomy/risk-assessment.d.ts +3 -0
  31. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
  32. package/dist/core/autonomy/risk-assessment.js +122 -0
  33. package/dist/core/autonomy/risk-assessment.js.map +1 -0
  34. package/dist/core/autonomy/session-lane-record.d.ts +10 -0
  35. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
  36. package/dist/core/autonomy/session-lane-record.js +36 -0
  37. package/dist/core/autonomy/session-lane-record.js.map +1 -0
  38. package/dist/core/autonomy/status.d.ts +40 -0
  39. package/dist/core/autonomy/status.d.ts.map +1 -0
  40. package/dist/core/autonomy/status.js +107 -0
  41. package/dist/core/autonomy/status.js.map +1 -0
  42. package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
  43. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
  44. package/dist/core/autonomy/subagent-prompt.js +28 -0
  45. package/dist/core/autonomy/subagent-prompt.js.map +1 -0
  46. package/dist/core/autonomy/telemetry-events.d.ts +18 -0
  47. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
  48. package/dist/core/autonomy/telemetry-events.js +60 -0
  49. package/dist/core/autonomy/telemetry-events.js.map +1 -0
  50. package/dist/core/context/artifact-retrieval.d.ts +49 -0
  51. package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
  52. package/dist/core/context/artifact-retrieval.js +49 -0
  53. package/dist/core/context/artifact-retrieval.js.map +1 -0
  54. package/dist/core/context/brain-curator.d.ts +88 -0
  55. package/dist/core/context/brain-curator.d.ts.map +1 -0
  56. package/dist/core/context/brain-curator.js +192 -0
  57. package/dist/core/context/brain-curator.js.map +1 -0
  58. package/dist/core/context/context-artifacts.d.ts +94 -0
  59. package/dist/core/context/context-artifacts.d.ts.map +1 -0
  60. package/dist/core/context/context-artifacts.js +307 -0
  61. package/dist/core/context/context-artifacts.js.map +1 -0
  62. package/dist/core/context/context-audit.d.ts +66 -0
  63. package/dist/core/context/context-audit.d.ts.map +1 -0
  64. package/dist/core/context/context-audit.js +173 -0
  65. package/dist/core/context/context-audit.js.map +1 -0
  66. package/dist/core/context/context-composition.d.ts +122 -0
  67. package/dist/core/context/context-composition.d.ts.map +1 -0
  68. package/dist/core/context/context-composition.js +163 -0
  69. package/dist/core/context/context-composition.js.map +1 -0
  70. package/dist/core/context/context-item.d.ts +117 -0
  71. package/dist/core/context/context-item.d.ts.map +1 -0
  72. package/dist/core/context/context-item.js +36 -0
  73. package/dist/core/context/context-item.js.map +1 -0
  74. package/dist/core/context/context-prompt-enforcement.d.ts +86 -0
  75. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
  76. package/dist/core/context/context-prompt-enforcement.js +168 -0
  77. package/dist/core/context/context-prompt-enforcement.js.map +1 -0
  78. package/dist/core/context/context-prompt-policy.d.ts +90 -0
  79. package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
  80. package/dist/core/context/context-prompt-policy.js +73 -0
  81. package/dist/core/context/context-prompt-policy.js.map +1 -0
  82. package/dist/core/context/context-retention.d.ts +36 -0
  83. package/dist/core/context/context-retention.d.ts.map +1 -0
  84. package/dist/core/context/context-retention.js +108 -0
  85. package/dist/core/context/context-retention.js.map +1 -0
  86. package/dist/core/context/context-store.d.ts +37 -0
  87. package/dist/core/context/context-store.d.ts.map +1 -0
  88. package/dist/core/context/context-store.js +45 -0
  89. package/dist/core/context/context-store.js.map +1 -0
  90. package/dist/core/context/memory-diagnostics.d.ts +50 -0
  91. package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
  92. package/dist/core/context/memory-diagnostics.js +43 -0
  93. package/dist/core/context/memory-diagnostics.js.map +1 -0
  94. package/dist/core/context/memory-index-store.d.ts +28 -0
  95. package/dist/core/context/memory-index-store.d.ts.map +1 -0
  96. package/dist/core/context/memory-index-store.js +38 -0
  97. package/dist/core/context/memory-index-store.js.map +1 -0
  98. package/dist/core/context/memory-prompt-block.d.ts +34 -0
  99. package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
  100. package/dist/core/context/memory-prompt-block.js +58 -0
  101. package/dist/core/context/memory-prompt-block.js.map +1 -0
  102. package/dist/core/context/memory-provider-contract.d.ts +114 -0
  103. package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
  104. package/dist/core/context/memory-provider-contract.js +121 -0
  105. package/dist/core/context/memory-provider-contract.js.map +1 -0
  106. package/dist/core/context/memory-retrieval.d.ts +27 -0
  107. package/dist/core/context/memory-retrieval.d.ts.map +1 -0
  108. package/dist/core/context/memory-retrieval.js +91 -0
  109. package/dist/core/context/memory-retrieval.js.map +1 -0
  110. package/dist/core/context/okf-memory-provider.d.ts +26 -0
  111. package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
  112. package/dist/core/context/okf-memory-provider.js +154 -0
  113. package/dist/core/context/okf-memory-provider.js.map +1 -0
  114. package/dist/core/context/okf-memory.d.ts +42 -0
  115. package/dist/core/context/okf-memory.d.ts.map +1 -0
  116. package/dist/core/context/okf-memory.js +175 -0
  117. package/dist/core/context/okf-memory.js.map +1 -0
  118. package/dist/core/context/policy-engine.d.ts +66 -0
  119. package/dist/core/context/policy-engine.d.ts.map +1 -0
  120. package/dist/core/context/policy-engine.js +171 -0
  121. package/dist/core/context/policy-engine.js.map +1 -0
  122. package/dist/core/context/policy-types.d.ts +102 -0
  123. package/dist/core/context/policy-types.d.ts.map +1 -0
  124. package/dist/core/context/policy-types.js +7 -0
  125. package/dist/core/context/policy-types.js.map +1 -0
  126. package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
  127. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
  128. package/dist/core/context/sqlite-runtime-index.js +344 -0
  129. package/dist/core/context/sqlite-runtime-index.js.map +1 -0
  130. package/dist/core/context/storage-authority.d.ts +20 -0
  131. package/dist/core/context/storage-authority.d.ts.map +1 -0
  132. package/dist/core/context/storage-authority.js +51 -0
  133. package/dist/core/context/storage-authority.js.map +1 -0
  134. package/dist/core/context/tool-output-packer.d.ts +75 -0
  135. package/dist/core/context/tool-output-packer.d.ts.map +1 -0
  136. package/dist/core/context/tool-output-packer.js +77 -0
  137. package/dist/core/context/tool-output-packer.js.map +1 -0
  138. package/dist/core/context-gc.d.ts +13 -0
  139. package/dist/core/context-gc.d.ts.map +1 -1
  140. package/dist/core/context-gc.js +6 -0
  141. package/dist/core/context-gc.js.map +1 -1
  142. package/dist/core/cost/session-usage.d.ts +20 -0
  143. package/dist/core/cost/session-usage.d.ts.map +1 -0
  144. package/dist/core/cost/session-usage.js +164 -0
  145. package/dist/core/cost/session-usage.js.map +1 -0
  146. package/dist/core/delegation/session-worker-result.d.ts +10 -0
  147. package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-result.js +36 -0
  149. package/dist/core/delegation/session-worker-result.js.map +1 -0
  150. package/dist/core/delegation/worker-result.d.ts +9 -0
  151. package/dist/core/delegation/worker-result.d.ts.map +1 -0
  152. package/dist/core/delegation/worker-result.js +152 -0
  153. package/dist/core/delegation/worker-result.js.map +1 -0
  154. package/dist/core/delegation/worker-runner.d.ts +58 -0
  155. package/dist/core/delegation/worker-runner.d.ts.map +1 -0
  156. package/dist/core/delegation/worker-runner.js +188 -0
  157. package/dist/core/delegation/worker-runner.js.map +1 -0
  158. package/dist/core/extensions/builtin.d.ts +5 -1
  159. package/dist/core/extensions/builtin.d.ts.map +1 -1
  160. package/dist/core/extensions/builtin.js +23 -1
  161. package/dist/core/extensions/builtin.js.map +1 -1
  162. package/dist/core/footer-data-provider.d.ts +5 -1
  163. package/dist/core/footer-data-provider.d.ts.map +1 -1
  164. package/dist/core/footer-data-provider.js +13 -0
  165. package/dist/core/footer-data-provider.js.map +1 -1
  166. package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
  167. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
  168. package/dist/core/goals/goal-continuation-controller.js +88 -0
  169. package/dist/core/goals/goal-continuation-controller.js.map +1 -0
  170. package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
  171. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
  172. package/dist/core/goals/goal-continuation-defaults.js +10 -0
  173. package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
  174. package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
  175. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
  176. package/dist/core/goals/goal-continuation-prompt.js +141 -0
  177. package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
  178. package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
  179. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
  180. package/dist/core/goals/goal-runtime-snapshot.js +23 -0
  181. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
  182. package/dist/core/goals/goal-state.d.ts +87 -0
  183. package/dist/core/goals/goal-state.d.ts.map +1 -0
  184. package/dist/core/goals/goal-state.js +259 -0
  185. package/dist/core/goals/goal-state.js.map +1 -0
  186. package/dist/core/goals/goal-tool-core.d.ts +66 -0
  187. package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
  188. package/dist/core/goals/goal-tool-core.js +146 -0
  189. package/dist/core/goals/goal-tool-core.js.map +1 -0
  190. package/dist/core/goals/session-goal-state.d.ts +10 -0
  191. package/dist/core/goals/session-goal-state.d.ts.map +1 -0
  192. package/dist/core/goals/session-goal-state.js +35 -0
  193. package/dist/core/goals/session-goal-state.js.map +1 -0
  194. package/dist/core/learning/learning-audit.d.ts +45 -0
  195. package/dist/core/learning/learning-audit.d.ts.map +1 -0
  196. package/dist/core/learning/learning-audit.js +139 -0
  197. package/dist/core/learning/learning-audit.js.map +1 -0
  198. package/dist/core/learning/learning-gate.d.ts +29 -0
  199. package/dist/core/learning/learning-gate.d.ts.map +1 -0
  200. package/dist/core/learning/learning-gate.js +150 -0
  201. package/dist/core/learning/learning-gate.js.map +1 -0
  202. package/dist/core/learning/session-learning-decision.d.ts +10 -0
  203. package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
  204. package/dist/core/learning/session-learning-decision.js +36 -0
  205. package/dist/core/learning/session-learning-decision.js.map +1 -0
  206. package/dist/core/model-capability.d.ts +41 -0
  207. package/dist/core/model-capability.d.ts.map +1 -0
  208. package/dist/core/model-capability.js +101 -0
  209. package/dist/core/model-capability.js.map +1 -0
  210. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  211. package/dist/core/model-router/config-diagnostics.js +1 -0
  212. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  213. package/dist/core/model-router/intent-classifier.d.ts +2 -0
  214. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  215. package/dist/core/model-router/intent-classifier.js +154 -9
  216. package/dist/core/model-router/intent-classifier.js.map +1 -1
  217. package/dist/core/model-router/route-judge.d.ts +54 -0
  218. package/dist/core/model-router/route-judge.d.ts.map +1 -0
  219. package/dist/core/model-router/route-judge.js +128 -0
  220. package/dist/core/model-router/route-judge.js.map +1 -0
  221. package/dist/core/model-router/status.d.ts +4 -1
  222. package/dist/core/model-router/status.d.ts.map +1 -1
  223. package/dist/core/model-router/status.js +30 -6
  224. package/dist/core/model-router/status.js.map +1 -1
  225. package/dist/core/model-router/tool-escalation.d.ts +4 -6
  226. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  227. package/dist/core/model-router/tool-escalation.js +1 -1
  228. package/dist/core/model-router/tool-escalation.js.map +1 -1
  229. package/dist/core/models/fitness-store.d.ts +40 -0
  230. package/dist/core/models/fitness-store.d.ts.map +1 -0
  231. package/dist/core/models/fitness-store.js +61 -0
  232. package/dist/core/models/fitness-store.js.map +1 -0
  233. package/dist/core/profile-registry.d.ts.map +1 -1
  234. package/dist/core/profile-registry.js +1 -1
  235. package/dist/core/profile-registry.js.map +1 -1
  236. package/dist/core/prompt-templates.d.ts +2 -0
  237. package/dist/core/prompt-templates.d.ts.map +1 -1
  238. package/dist/core/prompt-templates.js +12 -4
  239. package/dist/core/prompt-templates.js.map +1 -1
  240. package/dist/core/research/automata-provider.d.ts +5 -0
  241. package/dist/core/research/automata-provider.d.ts.map +1 -0
  242. package/dist/core/research/automata-provider.js +15 -0
  243. package/dist/core/research/automata-provider.js.map +1 -0
  244. package/dist/core/research/evidence-bundle.d.ts +10 -0
  245. package/dist/core/research/evidence-bundle.d.ts.map +1 -0
  246. package/dist/core/research/evidence-bundle.js +116 -0
  247. package/dist/core/research/evidence-bundle.js.map +1 -0
  248. package/dist/core/research/model-fitness.d.ts +82 -0
  249. package/dist/core/research/model-fitness.d.ts.map +1 -0
  250. package/dist/core/research/model-fitness.js +308 -0
  251. package/dist/core/research/model-fitness.js.map +1 -0
  252. package/dist/core/research/research-gate.d.ts +11 -0
  253. package/dist/core/research/research-gate.d.ts.map +1 -0
  254. package/dist/core/research/research-gate.js +82 -0
  255. package/dist/core/research/research-gate.js.map +1 -0
  256. package/dist/core/research/research-runner.d.ts +59 -0
  257. package/dist/core/research/research-runner.d.ts.map +1 -0
  258. package/dist/core/research/research-runner.js +155 -0
  259. package/dist/core/research/research-runner.js.map +1 -0
  260. package/dist/core/research/session-evidence-bundle.d.ts +11 -0
  261. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
  262. package/dist/core/research/session-evidence-bundle.js +55 -0
  263. package/dist/core/research/session-evidence-bundle.js.map +1 -0
  264. package/dist/core/resource-loader.d.ts.map +1 -1
  265. package/dist/core/resource-loader.js +4 -0
  266. package/dist/core/resource-loader.js.map +1 -1
  267. package/dist/core/settings-manager.d.ts +160 -4
  268. package/dist/core/settings-manager.d.ts.map +1 -1
  269. package/dist/core/settings-manager.js +304 -9
  270. package/dist/core/settings-manager.js.map +1 -1
  271. package/dist/core/skills.d.ts +4 -0
  272. package/dist/core/skills.d.ts.map +1 -1
  273. package/dist/core/skills.js +18 -6
  274. package/dist/core/skills.js.map +1 -1
  275. package/dist/core/slash-commands.d.ts.map +1 -1
  276. package/dist/core/slash-commands.js +10 -1
  277. package/dist/core/slash-commands.js.map +1 -1
  278. package/dist/core/toolkit/script-registry.d.ts +34 -0
  279. package/dist/core/toolkit/script-registry.d.ts.map +1 -0
  280. package/dist/core/toolkit/script-registry.js +71 -0
  281. package/dist/core/toolkit/script-registry.js.map +1 -0
  282. package/dist/core/toolkit/script-runner.d.ts +28 -0
  283. package/dist/core/toolkit/script-runner.d.ts.map +1 -0
  284. package/dist/core/toolkit/script-runner.js +48 -0
  285. package/dist/core/toolkit/script-runner.js.map +1 -0
  286. package/dist/core/tools/artifact-retrieve.d.ts +23 -0
  287. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
  288. package/dist/core/tools/artifact-retrieve.js +110 -0
  289. package/dist/core/tools/artifact-retrieve.js.map +1 -0
  290. package/dist/core/tools/delegate.d.ts +32 -0
  291. package/dist/core/tools/delegate.d.ts.map +1 -0
  292. package/dist/core/tools/delegate.js +60 -0
  293. package/dist/core/tools/delegate.js.map +1 -0
  294. package/dist/core/tools/fff-search-backend.d.ts +103 -0
  295. package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
  296. package/dist/core/tools/fff-search-backend.js +151 -0
  297. package/dist/core/tools/fff-search-backend.js.map +1 -0
  298. package/dist/core/tools/find.d.ts +21 -1
  299. package/dist/core/tools/find.d.ts.map +1 -1
  300. package/dist/core/tools/find.js +183 -10
  301. package/dist/core/tools/find.js.map +1 -1
  302. package/dist/core/tools/goal.d.ts +35 -0
  303. package/dist/core/tools/goal.d.ts.map +1 -0
  304. package/dist/core/tools/goal.js +122 -0
  305. package/dist/core/tools/goal.js.map +1 -0
  306. package/dist/core/tools/grep.d.ts +21 -1
  307. package/dist/core/tools/grep.d.ts.map +1 -1
  308. package/dist/core/tools/grep.js +272 -27
  309. package/dist/core/tools/grep.js.map +1 -1
  310. package/dist/core/tools/index.d.ts +4 -1
  311. package/dist/core/tools/index.d.ts.map +1 -1
  312. package/dist/core/tools/index.js +9 -0
  313. package/dist/core/tools/index.js.map +1 -1
  314. package/dist/core/tools/model-fitness.d.ts +30 -0
  315. package/dist/core/tools/model-fitness.d.ts.map +1 -0
  316. package/dist/core/tools/model-fitness.js +38 -0
  317. package/dist/core/tools/model-fitness.js.map +1 -0
  318. package/dist/core/tools/run-toolkit-script.d.ts +24 -0
  319. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
  320. package/dist/core/tools/run-toolkit-script.js +103 -0
  321. package/dist/core/tools/run-toolkit-script.js.map +1 -0
  322. package/dist/core/tools/search-router.d.ts +75 -0
  323. package/dist/core/tools/search-router.d.ts.map +1 -0
  324. package/dist/core/tools/search-router.js +85 -0
  325. package/dist/core/tools/search-router.js.map +1 -0
  326. package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
  327. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
  328. package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
  329. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
  330. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/footer.js +18 -16
  332. package/dist/modes/interactive/components/footer.js.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.d.ts +16 -1
  334. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/settings-selector.js +555 -11
  336. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  337. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  338. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +308 -39
  340. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  341. package/dist/utils/tools-manager.d.ts +2 -0
  342. package/dist/utils/tools-manager.d.ts.map +1 -1
  343. package/dist/utils/tools-manager.js +154 -2
  344. package/dist/utils/tools-manager.js.map +1 -1
  345. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  346. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  347. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  348. package/examples/extensions/sandbox/package-lock.json +2 -2
  349. package/examples/extensions/sandbox/package.json +1 -1
  350. package/examples/extensions/with-deps/package-lock.json +2 -2
  351. package/examples/extensions/with-deps/package.json +1 -1
  352. package/npm-shrinkwrap.json +368 -12
  353. package/package.json +5 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-tracker.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/lane-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1D,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,kBAAkB,CAAC;AAEtG,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,kBAAkB,CAAC;AAEnE,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAehE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAExE;AAKD,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IAEpC,YAAY,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAE,EAE3C;IAED,kGAAkG;IAClG,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIvC;IAED,OAAO,CAAC,iBAAiB;IAgBzB,KAAK,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAW3D;IAED,QAAQ,CACP,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GACnG,UAAU,GAAG,SAAS,CAcxB;IAED,cAAc,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAQtC;IAED,UAAU,IAAI,UAAU,EAAE,CAEzB;CACD","sourcesContent":["/**\n * Live lane registry for autonomous background work (research/worker/learning lanes).\n *\n * This is the first real concurrency tracker behind `AutonomyStatusSnapshot.activeLaneCount`:\n * counts reflect lanes actually running in THIS process, never inferred/faked from historical\n * snapshots. Terminal lane records are persisted separately via `session-lane-record.ts`.\n */\n\nexport type LaneType = \"research\" | \"worker\" | \"learning\";\n\nexport type LaneTerminalStatus = \"succeeded\" | \"failed\" | \"canceled\" | \"timeout\" | \"budget_exhausted\";\n\nexport type LaneStatus = \"queued\" | \"running\" | LaneTerminalStatus;\n\nexport interface LaneRecord {\n\tlaneId: string;\n\ttype: LaneType;\n\tstatus: LaneStatus;\n\treasonCode?: string;\n\tstartedAt?: string;\n\tcompletedAt?: string;\n\tcostUsd?: number;\n\tgoalId?: string;\n\tevidenceEntryId?: string;\n}\n\nconst LANE_TYPES: readonly string[] = [\"research\", \"worker\", \"learning\"];\nconst TERMINAL_STATUSES: readonly string[] = [\"succeeded\", \"failed\", \"canceled\", \"timeout\", \"budget_exhausted\"];\nconst LANE_STATUSES: readonly string[] = [\"queued\", \"running\", ...TERMINAL_STATUSES];\n\nexport function isLaneTerminalStatus(value: unknown): value is LaneTerminalStatus {\n\treturn typeof value === \"string\" && TERMINAL_STATUSES.includes(value);\n}\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nexport function isLaneRecord(value: unknown): value is LaneRecord {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst record = value as Record<string, unknown>;\n\tif (typeof record.laneId !== \"string\" || record.laneId.length === 0) return false;\n\tif (typeof record.type !== \"string\" || !LANE_TYPES.includes(record.type)) return false;\n\tif (typeof record.status !== \"string\" || !LANE_STATUSES.includes(record.status)) return false;\n\tif (!isOptionalString(record.reasonCode)) return false;\n\tif (!isOptionalString(record.startedAt)) return false;\n\tif (!isOptionalString(record.completedAt)) return false;\n\tif (record.costUsd !== undefined && (typeof record.costUsd !== \"number\" || !Number.isFinite(record.costUsd))) {\n\t\treturn false;\n\t}\n\tif (!isOptionalString(record.goalId)) return false;\n\tif (!isOptionalString(record.evidenceEntryId)) return false;\n\treturn true;\n}\n\nexport function cloneLaneRecordForStorage(record: LaneRecord): LaneRecord {\n\treturn { ...record };\n}\n\n/** Terminal records kept in memory for diagnostics; older ones are evicted (the session log holds history). */\nconst MAX_TERMINAL_LANES_IN_MEMORY = 100;\n\nexport class LaneTracker {\n\tprivate readonly _lanes = new Map<string, LaneRecord>();\n\tprivate _nextLaneNumber = 1;\n\tprivate readonly _now: () => string;\n\n\tconstructor(options?: { now?: () => string }) {\n\t\tthis._now = options?.now ?? (() => new Date().toISOString());\n\t}\n\n\t/** Seed the id counter (e.g. from persisted lane records) so resumed sessions don't reuse ids. */\n\tensureCounterAtLeast(next: number): void {\n\t\tif (Number.isFinite(next) && next > this._nextLaneNumber) {\n\t\t\tthis._nextLaneNumber = Math.floor(next);\n\t\t}\n\t}\n\n\tprivate _evictOldTerminal(): void {\n\t\tlet terminal = 0;\n\t\tfor (const record of this._lanes.values()) {\n\t\t\tif (isLaneTerminalStatus(record.status)) terminal++;\n\t\t}\n\t\tif (terminal <= MAX_TERMINAL_LANES_IN_MEMORY) return;\n\t\t// Map iteration is insertion-ordered: drop oldest terminal records first.\n\t\tfor (const [laneId, record] of this._lanes) {\n\t\t\tif (terminal <= MAX_TERMINAL_LANES_IN_MEMORY) break;\n\t\t\tif (isLaneTerminalStatus(record.status)) {\n\t\t\t\tthis._lanes.delete(laneId);\n\t\t\t\tterminal--;\n\t\t\t}\n\t\t}\n\t}\n\n\tstart(args: { type: LaneType; goalId?: string }): LaneRecord {\n\t\tconst laneId = `${args.type}-${this._nextLaneNumber++}`;\n\t\tconst record: LaneRecord = {\n\t\t\tlaneId,\n\t\t\ttype: args.type,\n\t\t\tstatus: \"running\",\n\t\t\tstartedAt: this._now(),\n\t\t};\n\t\tif (args.goalId !== undefined) record.goalId = args.goalId;\n\t\tthis._lanes.set(laneId, record);\n\t\treturn { ...record };\n\t}\n\n\tcomplete(\n\t\tlaneId: string,\n\t\targs: { status: LaneTerminalStatus; reasonCode?: string; costUsd?: number; evidenceEntryId?: string },\n\t): LaneRecord | undefined {\n\t\tconst record = this._lanes.get(laneId);\n\t\tif (!record || isLaneTerminalStatus(record.status)) return undefined;\n\t\tconst next: LaneRecord = {\n\t\t\t...record,\n\t\t\tstatus: args.status,\n\t\t\tcompletedAt: this._now(),\n\t\t};\n\t\tif (args.reasonCode !== undefined) next.reasonCode = args.reasonCode;\n\t\tif (args.costUsd !== undefined) next.costUsd = args.costUsd;\n\t\tif (args.evidenceEntryId !== undefined) next.evidenceEntryId = args.evidenceEntryId;\n\t\tthis._lanes.set(laneId, next);\n\t\tthis._evictOldTerminal();\n\t\treturn { ...next };\n\t}\n\n\tgetActiveCount(type?: LaneType): number {\n\t\tlet count = 0;\n\t\tfor (const record of this._lanes.values()) {\n\t\t\tif (isLaneTerminalStatus(record.status)) continue;\n\t\t\tif (type !== undefined && record.type !== type) continue;\n\t\t\tcount++;\n\t\t}\n\t\treturn count;\n\t}\n\n\tgetRecords(): LaneRecord[] {\n\t\treturn [...this._lanes.values()].map((record) => ({ ...record }));\n\t}\n}\n"]}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Live lane registry for autonomous background work (research/worker/learning lanes).
3
+ *
4
+ * This is the first real concurrency tracker behind `AutonomyStatusSnapshot.activeLaneCount`:
5
+ * counts reflect lanes actually running in THIS process, never inferred/faked from historical
6
+ * snapshots. Terminal lane records are persisted separately via `session-lane-record.ts`.
7
+ */
8
+ const LANE_TYPES = ["research", "worker", "learning"];
9
+ const TERMINAL_STATUSES = ["succeeded", "failed", "canceled", "timeout", "budget_exhausted"];
10
+ const LANE_STATUSES = ["queued", "running", ...TERMINAL_STATUSES];
11
+ export function isLaneTerminalStatus(value) {
12
+ return typeof value === "string" && TERMINAL_STATUSES.includes(value);
13
+ }
14
+ function isOptionalString(value) {
15
+ return value === undefined || typeof value === "string";
16
+ }
17
+ export function isLaneRecord(value) {
18
+ if (!value || typeof value !== "object" || Array.isArray(value))
19
+ return false;
20
+ const record = value;
21
+ if (typeof record.laneId !== "string" || record.laneId.length === 0)
22
+ return false;
23
+ if (typeof record.type !== "string" || !LANE_TYPES.includes(record.type))
24
+ return false;
25
+ if (typeof record.status !== "string" || !LANE_STATUSES.includes(record.status))
26
+ return false;
27
+ if (!isOptionalString(record.reasonCode))
28
+ return false;
29
+ if (!isOptionalString(record.startedAt))
30
+ return false;
31
+ if (!isOptionalString(record.completedAt))
32
+ return false;
33
+ if (record.costUsd !== undefined && (typeof record.costUsd !== "number" || !Number.isFinite(record.costUsd))) {
34
+ return false;
35
+ }
36
+ if (!isOptionalString(record.goalId))
37
+ return false;
38
+ if (!isOptionalString(record.evidenceEntryId))
39
+ return false;
40
+ return true;
41
+ }
42
+ export function cloneLaneRecordForStorage(record) {
43
+ return { ...record };
44
+ }
45
+ /** Terminal records kept in memory for diagnostics; older ones are evicted (the session log holds history). */
46
+ const MAX_TERMINAL_LANES_IN_MEMORY = 100;
47
+ export class LaneTracker {
48
+ _lanes = new Map();
49
+ _nextLaneNumber = 1;
50
+ _now;
51
+ constructor(options) {
52
+ this._now = options?.now ?? (() => new Date().toISOString());
53
+ }
54
+ /** Seed the id counter (e.g. from persisted lane records) so resumed sessions don't reuse ids. */
55
+ ensureCounterAtLeast(next) {
56
+ if (Number.isFinite(next) && next > this._nextLaneNumber) {
57
+ this._nextLaneNumber = Math.floor(next);
58
+ }
59
+ }
60
+ _evictOldTerminal() {
61
+ let terminal = 0;
62
+ for (const record of this._lanes.values()) {
63
+ if (isLaneTerminalStatus(record.status))
64
+ terminal++;
65
+ }
66
+ if (terminal <= MAX_TERMINAL_LANES_IN_MEMORY)
67
+ return;
68
+ // Map iteration is insertion-ordered: drop oldest terminal records first.
69
+ for (const [laneId, record] of this._lanes) {
70
+ if (terminal <= MAX_TERMINAL_LANES_IN_MEMORY)
71
+ break;
72
+ if (isLaneTerminalStatus(record.status)) {
73
+ this._lanes.delete(laneId);
74
+ terminal--;
75
+ }
76
+ }
77
+ }
78
+ start(args) {
79
+ const laneId = `${args.type}-${this._nextLaneNumber++}`;
80
+ const record = {
81
+ laneId,
82
+ type: args.type,
83
+ status: "running",
84
+ startedAt: this._now(),
85
+ };
86
+ if (args.goalId !== undefined)
87
+ record.goalId = args.goalId;
88
+ this._lanes.set(laneId, record);
89
+ return { ...record };
90
+ }
91
+ complete(laneId, args) {
92
+ const record = this._lanes.get(laneId);
93
+ if (!record || isLaneTerminalStatus(record.status))
94
+ return undefined;
95
+ const next = {
96
+ ...record,
97
+ status: args.status,
98
+ completedAt: this._now(),
99
+ };
100
+ if (args.reasonCode !== undefined)
101
+ next.reasonCode = args.reasonCode;
102
+ if (args.costUsd !== undefined)
103
+ next.costUsd = args.costUsd;
104
+ if (args.evidenceEntryId !== undefined)
105
+ next.evidenceEntryId = args.evidenceEntryId;
106
+ this._lanes.set(laneId, next);
107
+ this._evictOldTerminal();
108
+ return { ...next };
109
+ }
110
+ getActiveCount(type) {
111
+ let count = 0;
112
+ for (const record of this._lanes.values()) {
113
+ if (isLaneTerminalStatus(record.status))
114
+ continue;
115
+ if (type !== undefined && record.type !== type)
116
+ continue;
117
+ count++;
118
+ }
119
+ return count;
120
+ }
121
+ getRecords() {
122
+ return [...this._lanes.values()].map((record) => ({ ...record }));
123
+ }
124
+ }
125
+ //# sourceMappingURL=lane-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane-tracker.js","sourceRoot":"","sources":["../../../src/core/autonomy/lane-tracker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Live lane registry for autonomous background work (research/worker/learning lanes).\n *\n * This is the first real concurrency tracker behind `AutonomyStatusSnapshot.activeLaneCount`:\n * counts reflect lanes actually running in THIS process, never inferred/faked from historical\n * snapshots. Terminal lane records are persisted separately via `session-lane-record.ts`.\n */\n\nexport type LaneType = \"research\" | \"worker\" | \"learning\";\n\nexport type LaneTerminalStatus = \"succeeded\" | \"failed\" | \"canceled\" | \"timeout\" | \"budget_exhausted\";\n\nexport type LaneStatus = \"queued\" | \"running\" | LaneTerminalStatus;\n\nexport interface LaneRecord {\n\tlaneId: string;\n\ttype: LaneType;\n\tstatus: LaneStatus;\n\treasonCode?: string;\n\tstartedAt?: string;\n\tcompletedAt?: string;\n\tcostUsd?: number;\n\tgoalId?: string;\n\tevidenceEntryId?: string;\n}\n\nconst LANE_TYPES: readonly string[] = [\"research\", \"worker\", \"learning\"];\nconst TERMINAL_STATUSES: readonly string[] = [\"succeeded\", \"failed\", \"canceled\", \"timeout\", \"budget_exhausted\"];\nconst LANE_STATUSES: readonly string[] = [\"queued\", \"running\", ...TERMINAL_STATUSES];\n\nexport function isLaneTerminalStatus(value: unknown): value is LaneTerminalStatus {\n\treturn typeof value === \"string\" && TERMINAL_STATUSES.includes(value);\n}\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nexport function isLaneRecord(value: unknown): value is LaneRecord {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst record = value as Record<string, unknown>;\n\tif (typeof record.laneId !== \"string\" || record.laneId.length === 0) return false;\n\tif (typeof record.type !== \"string\" || !LANE_TYPES.includes(record.type)) return false;\n\tif (typeof record.status !== \"string\" || !LANE_STATUSES.includes(record.status)) return false;\n\tif (!isOptionalString(record.reasonCode)) return false;\n\tif (!isOptionalString(record.startedAt)) return false;\n\tif (!isOptionalString(record.completedAt)) return false;\n\tif (record.costUsd !== undefined && (typeof record.costUsd !== \"number\" || !Number.isFinite(record.costUsd))) {\n\t\treturn false;\n\t}\n\tif (!isOptionalString(record.goalId)) return false;\n\tif (!isOptionalString(record.evidenceEntryId)) return false;\n\treturn true;\n}\n\nexport function cloneLaneRecordForStorage(record: LaneRecord): LaneRecord {\n\treturn { ...record };\n}\n\n/** Terminal records kept in memory for diagnostics; older ones are evicted (the session log holds history). */\nconst MAX_TERMINAL_LANES_IN_MEMORY = 100;\n\nexport class LaneTracker {\n\tprivate readonly _lanes = new Map<string, LaneRecord>();\n\tprivate _nextLaneNumber = 1;\n\tprivate readonly _now: () => string;\n\n\tconstructor(options?: { now?: () => string }) {\n\t\tthis._now = options?.now ?? (() => new Date().toISOString());\n\t}\n\n\t/** Seed the id counter (e.g. from persisted lane records) so resumed sessions don't reuse ids. */\n\tensureCounterAtLeast(next: number): void {\n\t\tif (Number.isFinite(next) && next > this._nextLaneNumber) {\n\t\t\tthis._nextLaneNumber = Math.floor(next);\n\t\t}\n\t}\n\n\tprivate _evictOldTerminal(): void {\n\t\tlet terminal = 0;\n\t\tfor (const record of this._lanes.values()) {\n\t\t\tif (isLaneTerminalStatus(record.status)) terminal++;\n\t\t}\n\t\tif (terminal <= MAX_TERMINAL_LANES_IN_MEMORY) return;\n\t\t// Map iteration is insertion-ordered: drop oldest terminal records first.\n\t\tfor (const [laneId, record] of this._lanes) {\n\t\t\tif (terminal <= MAX_TERMINAL_LANES_IN_MEMORY) break;\n\t\t\tif (isLaneTerminalStatus(record.status)) {\n\t\t\t\tthis._lanes.delete(laneId);\n\t\t\t\tterminal--;\n\t\t\t}\n\t\t}\n\t}\n\n\tstart(args: { type: LaneType; goalId?: string }): LaneRecord {\n\t\tconst laneId = `${args.type}-${this._nextLaneNumber++}`;\n\t\tconst record: LaneRecord = {\n\t\t\tlaneId,\n\t\t\ttype: args.type,\n\t\t\tstatus: \"running\",\n\t\t\tstartedAt: this._now(),\n\t\t};\n\t\tif (args.goalId !== undefined) record.goalId = args.goalId;\n\t\tthis._lanes.set(laneId, record);\n\t\treturn { ...record };\n\t}\n\n\tcomplete(\n\t\tlaneId: string,\n\t\targs: { status: LaneTerminalStatus; reasonCode?: string; costUsd?: number; evidenceEntryId?: string },\n\t): LaneRecord | undefined {\n\t\tconst record = this._lanes.get(laneId);\n\t\tif (!record || isLaneTerminalStatus(record.status)) return undefined;\n\t\tconst next: LaneRecord = {\n\t\t\t...record,\n\t\t\tstatus: args.status,\n\t\t\tcompletedAt: this._now(),\n\t\t};\n\t\tif (args.reasonCode !== undefined) next.reasonCode = args.reasonCode;\n\t\tif (args.costUsd !== undefined) next.costUsd = args.costUsd;\n\t\tif (args.evidenceEntryId !== undefined) next.evidenceEntryId = args.evidenceEntryId;\n\t\tthis._lanes.set(laneId, next);\n\t\tthis._evictOldTerminal();\n\t\treturn { ...next };\n\t}\n\n\tgetActiveCount(type?: LaneType): number {\n\t\tlet count = 0;\n\t\tfor (const record of this._lanes.values()) {\n\t\t\tif (isLaneTerminalStatus(record.status)) continue;\n\t\t\tif (type !== undefined && record.type !== type) continue;\n\t\t\tcount++;\n\t\t}\n\t\treturn count;\n\t}\n\n\tgetRecords(): LaneRecord[] {\n\t\treturn [...this._lanes.values()].map((record) => ({ ...record }));\n\t}\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { PathScope, PathScopeDecision } from "./contracts.ts";
2
+ /**
3
+ * Resolves the real path of a target. If the target does not exist, it recursively
4
+ * resolves the deepest existing parent directory and then appends the non-existent
5
+ * remainder, ensuring that any symlinks in the existing path prefix are expanded.
6
+ */
7
+ export declare function safeRealpathSync(targetPath: string): string;
8
+ export declare function checkPathScope(scope: PathScope, targetPath: string): PathScopeDecision;
9
+ //# sourceMappingURL=path-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-scope.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/path-scope.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAe3D;AAOD,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAqGtF","sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { PathScope, PathScopeDecision } from \"./contracts.ts\";\n\n/**\n * Resolves the real path of a target. If the target does not exist, it recursively\n * resolves the deepest existing parent directory and then appends the non-existent\n * remainder, ensuring that any symlinks in the existing path prefix are expanded.\n */\nexport function safeRealpathSync(targetPath: string): string {\n\tconst absolutePath = path.resolve(targetPath);\n\n\tif (fs.existsSync(absolutePath)) {\n\t\treturn fs.realpathSync(absolutePath);\n\t}\n\n\tconst parent = path.dirname(absolutePath);\n\t// Base case: if parent is the same as absolutePath, we've hit the root\n\tif (parent === absolutePath) {\n\t\treturn absolutePath;\n\t}\n\n\tconst resolvedParent = safeRealpathSync(parent);\n\treturn path.join(resolvedParent, path.basename(absolutePath));\n}\n\nfunction isPathInside(target: string, root: string): boolean {\n\tconst rootWithSep = root.endsWith(path.sep) ? root : `${root}${path.sep}`;\n\treturn target === root || target.startsWith(rootWithSep);\n}\n\nexport function checkPathScope(scope: PathScope, targetPath: string): PathScopeDecision {\n\tif (!targetPath) {\n\t\treturn {\n\t\t\tkind: \"missing\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"empty_path\",\n\t\t};\n\t}\n\n\tlet resolvedTarget: string;\n\ttry {\n\t\tresolvedTarget = safeRealpathSync(targetPath);\n\t} catch {\n\t\t// If we can't resolve the path at all (e.g. permission error), fail safely\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"unresolvable_target\",\n\t\t};\n\t}\n\n\tlet resolvedRoot: string;\n\ttry {\n\t\tresolvedRoot = safeRealpathSync(scope.root);\n\t} catch {\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"unresolvable_root\",\n\t\t};\n\t}\n\n\t// First, it must be inside the main root\n\tif (!isPathInside(resolvedTarget, resolvedRoot)) {\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\tresolvedPath: resolvedTarget,\n\t\t\treasonCode: \"outside_root\",\n\t\t};\n\t}\n\n\t// Check deniedPaths (overrides allowedPaths)\n\tif (scope.deniedPaths && scope.deniedPaths.length > 0) {\n\t\tfor (const denied of scope.deniedPaths) {\n\t\t\ttry {\n\t\t\t\tconst resolvedDenied = safeRealpathSync(denied);\n\t\t\t\tif (isPathInside(resolvedTarget, resolvedDenied)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: \"denied\",\n\t\t\t\t\t\tpath: targetPath,\n\t\t\t\t\t\tresolvedPath: resolvedTarget,\n\t\t\t\t\t\tmatchedRule: denied,\n\t\t\t\t\t\treasonCode: \"matches_denied_path\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\t// Check allowedPaths\n\tif (scope.allowedPaths && scope.allowedPaths.length > 0) {\n\t\tlet isAllowed = false;\n\t\tlet matchedAllowed: string | undefined;\n\n\t\tfor (const allowed of scope.allowedPaths) {\n\t\t\ttry {\n\t\t\t\tconst resolvedAllowed = safeRealpathSync(allowed);\n\t\t\t\tif (isPathInside(resolvedTarget, resolvedAllowed)) {\n\t\t\t\t\tisAllowed = true;\n\t\t\t\t\tmatchedAllowed = allowed;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (!isAllowed) {\n\t\t\treturn {\n\t\t\t\tkind: \"outside\",\n\t\t\t\tpath: targetPath,\n\t\t\t\tresolvedPath: resolvedTarget,\n\t\t\t\treasonCode: \"outside_allowed_paths\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tkind: \"inside\",\n\t\t\tpath: targetPath,\n\t\t\tresolvedPath: resolvedTarget,\n\t\t\tmatchedRule: matchedAllowed,\n\t\t\treasonCode: \"inside_allowed_paths\",\n\t\t};\n\t}\n\n\treturn {\n\t\tkind: \"inside\",\n\t\tpath: targetPath,\n\t\tresolvedPath: resolvedTarget,\n\t\tmatchedRule: scope.root,\n\t\treasonCode: \"inside_root\",\n\t};\n}\n"]}
@@ -0,0 +1,122 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ /**
4
+ * Resolves the real path of a target. If the target does not exist, it recursively
5
+ * resolves the deepest existing parent directory and then appends the non-existent
6
+ * remainder, ensuring that any symlinks in the existing path prefix are expanded.
7
+ */
8
+ export function safeRealpathSync(targetPath) {
9
+ const absolutePath = path.resolve(targetPath);
10
+ if (fs.existsSync(absolutePath)) {
11
+ return fs.realpathSync(absolutePath);
12
+ }
13
+ const parent = path.dirname(absolutePath);
14
+ // Base case: if parent is the same as absolutePath, we've hit the root
15
+ if (parent === absolutePath) {
16
+ return absolutePath;
17
+ }
18
+ const resolvedParent = safeRealpathSync(parent);
19
+ return path.join(resolvedParent, path.basename(absolutePath));
20
+ }
21
+ function isPathInside(target, root) {
22
+ const rootWithSep = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
23
+ return target === root || target.startsWith(rootWithSep);
24
+ }
25
+ export function checkPathScope(scope, targetPath) {
26
+ if (!targetPath) {
27
+ return {
28
+ kind: "missing",
29
+ path: targetPath,
30
+ reasonCode: "empty_path",
31
+ };
32
+ }
33
+ let resolvedTarget;
34
+ try {
35
+ resolvedTarget = safeRealpathSync(targetPath);
36
+ }
37
+ catch {
38
+ // If we can't resolve the path at all (e.g. permission error), fail safely
39
+ return {
40
+ kind: "outside",
41
+ path: targetPath,
42
+ reasonCode: "unresolvable_target",
43
+ };
44
+ }
45
+ let resolvedRoot;
46
+ try {
47
+ resolvedRoot = safeRealpathSync(scope.root);
48
+ }
49
+ catch {
50
+ return {
51
+ kind: "outside",
52
+ path: targetPath,
53
+ reasonCode: "unresolvable_root",
54
+ };
55
+ }
56
+ // First, it must be inside the main root
57
+ if (!isPathInside(resolvedTarget, resolvedRoot)) {
58
+ return {
59
+ kind: "outside",
60
+ path: targetPath,
61
+ resolvedPath: resolvedTarget,
62
+ reasonCode: "outside_root",
63
+ };
64
+ }
65
+ // Check deniedPaths (overrides allowedPaths)
66
+ if (scope.deniedPaths && scope.deniedPaths.length > 0) {
67
+ for (const denied of scope.deniedPaths) {
68
+ try {
69
+ const resolvedDenied = safeRealpathSync(denied);
70
+ if (isPathInside(resolvedTarget, resolvedDenied)) {
71
+ return {
72
+ kind: "denied",
73
+ path: targetPath,
74
+ resolvedPath: resolvedTarget,
75
+ matchedRule: denied,
76
+ reasonCode: "matches_denied_path",
77
+ };
78
+ }
79
+ }
80
+ catch { }
81
+ }
82
+ }
83
+ // Check allowedPaths
84
+ if (scope.allowedPaths && scope.allowedPaths.length > 0) {
85
+ let isAllowed = false;
86
+ let matchedAllowed;
87
+ for (const allowed of scope.allowedPaths) {
88
+ try {
89
+ const resolvedAllowed = safeRealpathSync(allowed);
90
+ if (isPathInside(resolvedTarget, resolvedAllowed)) {
91
+ isAllowed = true;
92
+ matchedAllowed = allowed;
93
+ break;
94
+ }
95
+ }
96
+ catch { }
97
+ }
98
+ if (!isAllowed) {
99
+ return {
100
+ kind: "outside",
101
+ path: targetPath,
102
+ resolvedPath: resolvedTarget,
103
+ reasonCode: "outside_allowed_paths",
104
+ };
105
+ }
106
+ return {
107
+ kind: "inside",
108
+ path: targetPath,
109
+ resolvedPath: resolvedTarget,
110
+ matchedRule: matchedAllowed,
111
+ reasonCode: "inside_allowed_paths",
112
+ };
113
+ }
114
+ return {
115
+ kind: "inside",
116
+ path: targetPath,
117
+ resolvedPath: resolvedTarget,
118
+ matchedRule: scope.root,
119
+ reasonCode: "inside_root",
120
+ };
121
+ }
122
+ //# sourceMappingURL=path-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-scope.js","sourceRoot":"","sources":["../../../src/core/autonomy/path-scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAU;IAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1C,uEAAuE;IACvE,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;AAAA,CAC9D;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,IAAY,EAAW;IAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC1E,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAAA,CACzD;AAED,MAAM,UAAU,cAAc,CAAC,KAAgB,EAAE,UAAkB,EAAqB;IACvF,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,YAAY;SACxB,CAAC;IACH,CAAC;IAED,IAAI,cAAsB,CAAC;IAC3B,IAAI,CAAC;QACJ,cAAc,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,2EAA2E;QAC3E,OAAO;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,qBAAqB;SACjC,CAAC;IACH,CAAC;IAED,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACJ,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,UAAU;YAChB,UAAU,EAAE,mBAAmB;SAC/B,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,YAAY,CAAC,EAAE,CAAC;QACjD,OAAO;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,cAAc;YAC5B,UAAU,EAAE,cAAc;SAC1B,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,CAAC;gBACJ,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;gBAChD,IAAI,YAAY,CAAC,cAAc,EAAE,cAAc,CAAC,EAAE,CAAC;oBAClD,OAAO;wBACN,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,UAAU;wBAChB,YAAY,EAAE,cAAc;wBAC5B,WAAW,EAAE,MAAM;wBACnB,UAAU,EAAE,qBAAqB;qBACjC,CAAC;gBACH,CAAC;YACF,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACX,CAAC;IACF,CAAC;IAED,qBAAqB;IACrB,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,cAAkC,CAAC;QAEvC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACJ,MAAM,eAAe,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAClD,IAAI,YAAY,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE,CAAC;oBACnD,SAAS,GAAG,IAAI,CAAC;oBACjB,cAAc,GAAG,OAAO,CAAC;oBACzB,MAAM;gBACP,CAAC;YACF,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACX,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO;gBACN,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,YAAY,EAAE,cAAc;gBAC5B,UAAU,EAAE,uBAAuB;aACnC,CAAC;QACH,CAAC;QAED,OAAO;YACN,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,cAAc;YAC5B,WAAW,EAAE,cAAc;YAC3B,UAAU,EAAE,sBAAsB;SAClC,CAAC;IACH,CAAC;IAED,OAAO;QACN,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,UAAU;QAChB,YAAY,EAAE,cAAc;QAC5B,WAAW,EAAE,KAAK,CAAC,IAAI;QACvB,UAAU,EAAE,aAAa;KACzB,CAAC;AAAA,CACF","sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { PathScope, PathScopeDecision } from \"./contracts.ts\";\n\n/**\n * Resolves the real path of a target. If the target does not exist, it recursively\n * resolves the deepest existing parent directory and then appends the non-existent\n * remainder, ensuring that any symlinks in the existing path prefix are expanded.\n */\nexport function safeRealpathSync(targetPath: string): string {\n\tconst absolutePath = path.resolve(targetPath);\n\n\tif (fs.existsSync(absolutePath)) {\n\t\treturn fs.realpathSync(absolutePath);\n\t}\n\n\tconst parent = path.dirname(absolutePath);\n\t// Base case: if parent is the same as absolutePath, we've hit the root\n\tif (parent === absolutePath) {\n\t\treturn absolutePath;\n\t}\n\n\tconst resolvedParent = safeRealpathSync(parent);\n\treturn path.join(resolvedParent, path.basename(absolutePath));\n}\n\nfunction isPathInside(target: string, root: string): boolean {\n\tconst rootWithSep = root.endsWith(path.sep) ? root : `${root}${path.sep}`;\n\treturn target === root || target.startsWith(rootWithSep);\n}\n\nexport function checkPathScope(scope: PathScope, targetPath: string): PathScopeDecision {\n\tif (!targetPath) {\n\t\treturn {\n\t\t\tkind: \"missing\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"empty_path\",\n\t\t};\n\t}\n\n\tlet resolvedTarget: string;\n\ttry {\n\t\tresolvedTarget = safeRealpathSync(targetPath);\n\t} catch {\n\t\t// If we can't resolve the path at all (e.g. permission error), fail safely\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"unresolvable_target\",\n\t\t};\n\t}\n\n\tlet resolvedRoot: string;\n\ttry {\n\t\tresolvedRoot = safeRealpathSync(scope.root);\n\t} catch {\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\treasonCode: \"unresolvable_root\",\n\t\t};\n\t}\n\n\t// First, it must be inside the main root\n\tif (!isPathInside(resolvedTarget, resolvedRoot)) {\n\t\treturn {\n\t\t\tkind: \"outside\",\n\t\t\tpath: targetPath,\n\t\t\tresolvedPath: resolvedTarget,\n\t\t\treasonCode: \"outside_root\",\n\t\t};\n\t}\n\n\t// Check deniedPaths (overrides allowedPaths)\n\tif (scope.deniedPaths && scope.deniedPaths.length > 0) {\n\t\tfor (const denied of scope.deniedPaths) {\n\t\t\ttry {\n\t\t\t\tconst resolvedDenied = safeRealpathSync(denied);\n\t\t\t\tif (isPathInside(resolvedTarget, resolvedDenied)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: \"denied\",\n\t\t\t\t\t\tpath: targetPath,\n\t\t\t\t\t\tresolvedPath: resolvedTarget,\n\t\t\t\t\t\tmatchedRule: denied,\n\t\t\t\t\t\treasonCode: \"matches_denied_path\",\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\t// Check allowedPaths\n\tif (scope.allowedPaths && scope.allowedPaths.length > 0) {\n\t\tlet isAllowed = false;\n\t\tlet matchedAllowed: string | undefined;\n\n\t\tfor (const allowed of scope.allowedPaths) {\n\t\t\ttry {\n\t\t\t\tconst resolvedAllowed = safeRealpathSync(allowed);\n\t\t\t\tif (isPathInside(resolvedTarget, resolvedAllowed)) {\n\t\t\t\t\tisAllowed = true;\n\t\t\t\t\tmatchedAllowed = allowed;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch {}\n\t\t}\n\n\t\tif (!isAllowed) {\n\t\t\treturn {\n\t\t\t\tkind: \"outside\",\n\t\t\t\tpath: targetPath,\n\t\t\t\tresolvedPath: resolvedTarget,\n\t\t\t\treasonCode: \"outside_allowed_paths\",\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tkind: \"inside\",\n\t\t\tpath: targetPath,\n\t\t\tresolvedPath: resolvedTarget,\n\t\t\tmatchedRule: matchedAllowed,\n\t\t\treasonCode: \"inside_allowed_paths\",\n\t\t};\n\t}\n\n\treturn {\n\t\tkind: \"inside\",\n\t\tpath: targetPath,\n\t\tresolvedPath: resolvedTarget,\n\t\tmatchedRule: scope.root,\n\t\treasonCode: \"inside_root\",\n\t};\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { RiskAssessment, RiskAssessmentInput } from "./contracts.ts";
2
+ export declare function assessOperationRisk(input: RiskAssessmentInput): RiskAssessment;
3
+ //# sourceMappingURL=risk-assessment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-assessment.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/risk-assessment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AA4B1E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAmH9E","sourcesContent":["import type { RiskAssessment, RiskAssessmentInput } from \"./contracts.ts\";\n\nconst RELEASE_PUBLISH_RE = /\\b(publish|release|push|deploy|tag)\\b/i;\nconst SECURITY_AUTH_RE = /\\b(auth|token|credential|credentials|secret|api[-_]key)\\b/i;\nconst DESTRUCTIVE_RE = /\\b(delete|reset|rm\\s+-rf|clean)\\b/i;\n\nconst SELF_MOD_MUTATE_RE =\n\t/\\b(modify|change|write|update|edit|delete|add|remove|set)\\s+.*\\b(skills|prompts|settings|tools|behavior)\\b|self[-_]modification/i;\nconst ARCHITECTURE_MUTATE_RE = /\\b(rewrite|redesign|change|modify|rearchitect)\\s+.*\\b(architecture|architect)\\b/i;\n\nconst READ_ONLY_QUESTION_RE =\n\t/^(?:(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+)?(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show|search|find|view|read|locate)\\b/i;\n\nconst EXPLICIT_MODIFY_REQUEST_RE =\n\t/^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+.*\\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write|publish|release|push|deploy|tag|reset|clean|rewrite)\\b/i;\n\n// Shell parsing helpers\nconst DESTRUCTIVE_CMD_RE =\n\t/\\b(rm(\\s+-r|\\s+-f|\\s+-rf|\\s+-fr)?|mv|cp|chmod|chown|install)\\b|>\\s*\\/dev\\/(sda|hda|vda)|\\b(dd\\s+if=)/i;\nconst GIT_MUTATE_CMD_RE = /\\bgit\\s+(commit|push|reset|clean|stash|rebase)\\b/i;\nconst PKG_MUTATE_CMD_RE = /\\b(npm|pnpm|yarn|bun)\\s+(install|i|update|up|publish|run|remove|rm|uninstall)\\b/i;\nconst RELEASE_DEPLOY_CMD_RE = /\\b(release|deploy)\\b/i;\nconst REDIRECTION_RE = /[<>]/;\n\nfunction stripSingleQuotes(cmd: string): string {\n\treturn cmd.replace(/'[^']*'/g, \"''\");\n}\n\nexport function assessOperationRisk(input: RiskAssessmentInput): RiskAssessment {\n\tconst operation = input.operation.trim();\n\tconst command = input.command?.trim() ?? \"\";\n\tconst cleanCommand = command ? stripSingleQuotes(command) : \"\";\n\tconst fullText = `${operation} ${command}`.trim();\n\tconst cleanFullText = `${operation} ${cleanCommand}`.trim();\n\n\tif (fullText.length === 0) {\n\t\treturn {\n\t\t\trisk: \"read-only\",\n\t\t\treasonCode: \"empty_operation\",\n\t\t\treasons: [\"Empty operation\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 1. Explicit read-only operations\n\tif (READ_ONLY_QUESTION_RE.test(operation) && !EXPLICIT_MODIFY_REQUEST_RE.test(operation)) {\n\t\treturn {\n\t\t\trisk: \"read-only\",\n\t\t\treasonCode: \"read_only_operation\",\n\t\t\treasons: [\"Operation is explicitly read-only (list/show/read/search)\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 2. High-risk actions\n\tif (RELEASE_PUBLISH_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"release_publish_operation\",\n\t\t\treasons: [\"Operation mentions releasing, publishing, or deploying\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (SECURITY_AUTH_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\", // updated based on user instruction: \"high-impact or approval-required\"\n\t\t\treasonCode: \"security_auth_operation\",\n\t\t\treasons: [\"Operation mentions authentication or credentials\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (DESTRUCTIVE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"destructive_operation\",\n\t\t\treasons: [\"Operation involves deleting, resetting, or cleaning\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (SELF_MOD_MUTATE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"self_modification_operation\",\n\t\t\treasons: [\"Operation modifies settings, tools, skills, or prompts\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (ARCHITECTURE_MUTATE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"high-impact\",\n\t\t\treasonCode: \"architecture_mutation_operation\",\n\t\t\treasons: [\"Operation mentions rewriting or rearchitecting core parts\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 3. Command risks\n\tif (command) {\n\t\tconst cleanCmd = stripSingleQuotes(command);\n\t\tif (\n\t\t\tDESTRUCTIVE_CMD_RE.test(cleanCmd) ||\n\t\t\tGIT_MUTATE_CMD_RE.test(cleanCmd) ||\n\t\t\tPKG_MUTATE_CMD_RE.test(cleanCmd) ||\n\t\t\tRELEASE_DEPLOY_CMD_RE.test(cleanCmd) ||\n\t\t\tREDIRECTION_RE.test(cleanCmd)\n\t\t) {\n\t\t\treturn {\n\t\t\t\trisk: \"approval-required\",\n\t\t\t\treasonCode: \"mutating_command\",\n\t\t\t\treasons: [\"Command executes a destructive, mutating, or publish operation\"],\n\t\t\t\trequiresApproval: true,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Default to scoped-write for any generic mutating tool action if it has a toolName or isn't read-only\n\t// or read-only if it's purely a non-mutating intent (but since it didn't match read-only above, we default to scoped-write)\n\tif (\n\t\tinput.toolName &&\n\t\t![\"read_file\", \"search_web\", \"list_dir\", \"grep_search\", \"view_file\"].includes(input.toolName)\n\t) {\n\t\treturn {\n\t\t\trisk: \"scoped-write\",\n\t\t\treasonCode: \"generic_mutation\",\n\t\t\treasons: [\"Generic mutating operation or command\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\tif (command) {\n\t\t// Even if not explicitly destructive, shell commands could be anything, but we assume read-only if it's just 'ls', 'git status' etc.\n\t\t// For now, if no mutating patterns matched, we assume read-only if there's no toolName, but wait, normal file edits are scoped-write.\n\t\t// If there is a command, and it doesn't match the mutating patterns, we fall through to read-only.\n\t\t// Wait, user says \"Risk shell read-only commands like git status, rg, ls, npm view do not require approval.\"\n\t\t// And \"ordinary file edits inside allowed scope are scoped-write.\" (Handled by tools)\n\t}\n\n\treturn {\n\t\trisk: \"read-only\",\n\t\treasonCode: \"default_read_only\",\n\t\treasons: [\"No mutating or high-risk patterns detected\"],\n\t\trequiresApproval: false,\n\t};\n}\n"]}
@@ -0,0 +1,122 @@
1
+ const RELEASE_PUBLISH_RE = /\b(publish|release|push|deploy|tag)\b/i;
2
+ const SECURITY_AUTH_RE = /\b(auth|token|credential|credentials|secret|api[-_]key)\b/i;
3
+ const DESTRUCTIVE_RE = /\b(delete|reset|rm\s+-rf|clean)\b/i;
4
+ const SELF_MOD_MUTATE_RE = /\b(modify|change|write|update|edit|delete|add|remove|set)\s+.*\b(skills|prompts|settings|tools|behavior)\b|self[-_]modification/i;
5
+ const ARCHITECTURE_MUTATE_RE = /\b(rewrite|redesign|change|modify|rearchitect)\s+.*\b(architecture|architect)\b/i;
6
+ const READ_ONLY_QUESTION_RE = /^(?:(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\s+)?(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show|search|find|view|read|locate)\b/i;
7
+ const EXPLICIT_MODIFY_REQUEST_RE = /^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\s+.*\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write|publish|release|push|deploy|tag|reset|clean|rewrite)\b/i;
8
+ // Shell parsing helpers
9
+ const DESTRUCTIVE_CMD_RE = /\b(rm(\s+-r|\s+-f|\s+-rf|\s+-fr)?|mv|cp|chmod|chown|install)\b|>\s*\/dev\/(sda|hda|vda)|\b(dd\s+if=)/i;
10
+ const GIT_MUTATE_CMD_RE = /\bgit\s+(commit|push|reset|clean|stash|rebase)\b/i;
11
+ const PKG_MUTATE_CMD_RE = /\b(npm|pnpm|yarn|bun)\s+(install|i|update|up|publish|run|remove|rm|uninstall)\b/i;
12
+ const RELEASE_DEPLOY_CMD_RE = /\b(release|deploy)\b/i;
13
+ const REDIRECTION_RE = /[<>]/;
14
+ function stripSingleQuotes(cmd) {
15
+ return cmd.replace(/'[^']*'/g, "''");
16
+ }
17
+ export function assessOperationRisk(input) {
18
+ const operation = input.operation.trim();
19
+ const command = input.command?.trim() ?? "";
20
+ const cleanCommand = command ? stripSingleQuotes(command) : "";
21
+ const fullText = `${operation} ${command}`.trim();
22
+ const cleanFullText = `${operation} ${cleanCommand}`.trim();
23
+ if (fullText.length === 0) {
24
+ return {
25
+ risk: "read-only",
26
+ reasonCode: "empty_operation",
27
+ reasons: ["Empty operation"],
28
+ requiresApproval: false,
29
+ };
30
+ }
31
+ // 1. Explicit read-only operations
32
+ if (READ_ONLY_QUESTION_RE.test(operation) && !EXPLICIT_MODIFY_REQUEST_RE.test(operation)) {
33
+ return {
34
+ risk: "read-only",
35
+ reasonCode: "read_only_operation",
36
+ reasons: ["Operation is explicitly read-only (list/show/read/search)"],
37
+ requiresApproval: false,
38
+ };
39
+ }
40
+ // 2. High-risk actions
41
+ if (RELEASE_PUBLISH_RE.test(cleanFullText)) {
42
+ return {
43
+ risk: "approval-required",
44
+ reasonCode: "release_publish_operation",
45
+ reasons: ["Operation mentions releasing, publishing, or deploying"],
46
+ requiresApproval: true,
47
+ };
48
+ }
49
+ if (SECURITY_AUTH_RE.test(cleanFullText)) {
50
+ return {
51
+ risk: "approval-required", // updated based on user instruction: "high-impact or approval-required"
52
+ reasonCode: "security_auth_operation",
53
+ reasons: ["Operation mentions authentication or credentials"],
54
+ requiresApproval: true,
55
+ };
56
+ }
57
+ if (DESTRUCTIVE_RE.test(cleanFullText)) {
58
+ return {
59
+ risk: "approval-required",
60
+ reasonCode: "destructive_operation",
61
+ reasons: ["Operation involves deleting, resetting, or cleaning"],
62
+ requiresApproval: true,
63
+ };
64
+ }
65
+ if (SELF_MOD_MUTATE_RE.test(cleanFullText)) {
66
+ return {
67
+ risk: "approval-required",
68
+ reasonCode: "self_modification_operation",
69
+ reasons: ["Operation modifies settings, tools, skills, or prompts"],
70
+ requiresApproval: true,
71
+ };
72
+ }
73
+ if (ARCHITECTURE_MUTATE_RE.test(cleanFullText)) {
74
+ return {
75
+ risk: "high-impact",
76
+ reasonCode: "architecture_mutation_operation",
77
+ reasons: ["Operation mentions rewriting or rearchitecting core parts"],
78
+ requiresApproval: false,
79
+ };
80
+ }
81
+ // 3. Command risks
82
+ if (command) {
83
+ const cleanCmd = stripSingleQuotes(command);
84
+ if (DESTRUCTIVE_CMD_RE.test(cleanCmd) ||
85
+ GIT_MUTATE_CMD_RE.test(cleanCmd) ||
86
+ PKG_MUTATE_CMD_RE.test(cleanCmd) ||
87
+ RELEASE_DEPLOY_CMD_RE.test(cleanCmd) ||
88
+ REDIRECTION_RE.test(cleanCmd)) {
89
+ return {
90
+ risk: "approval-required",
91
+ reasonCode: "mutating_command",
92
+ reasons: ["Command executes a destructive, mutating, or publish operation"],
93
+ requiresApproval: true,
94
+ };
95
+ }
96
+ }
97
+ // Default to scoped-write for any generic mutating tool action if it has a toolName or isn't read-only
98
+ // or read-only if it's purely a non-mutating intent (but since it didn't match read-only above, we default to scoped-write)
99
+ if (input.toolName &&
100
+ !["read_file", "search_web", "list_dir", "grep_search", "view_file"].includes(input.toolName)) {
101
+ return {
102
+ risk: "scoped-write",
103
+ reasonCode: "generic_mutation",
104
+ reasons: ["Generic mutating operation or command"],
105
+ requiresApproval: false,
106
+ };
107
+ }
108
+ if (command) {
109
+ // Even if not explicitly destructive, shell commands could be anything, but we assume read-only if it's just 'ls', 'git status' etc.
110
+ // For now, if no mutating patterns matched, we assume read-only if there's no toolName, but wait, normal file edits are scoped-write.
111
+ // If there is a command, and it doesn't match the mutating patterns, we fall through to read-only.
112
+ // Wait, user says "Risk shell read-only commands like git status, rg, ls, npm view do not require approval."
113
+ // And "ordinary file edits inside allowed scope are scoped-write." (Handled by tools)
114
+ }
115
+ return {
116
+ risk: "read-only",
117
+ reasonCode: "default_read_only",
118
+ reasons: ["No mutating or high-risk patterns detected"],
119
+ requiresApproval: false,
120
+ };
121
+ }
122
+ //# sourceMappingURL=risk-assessment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk-assessment.js","sourceRoot":"","sources":["../../../src/core/autonomy/risk-assessment.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RiskAssessment, RiskAssessmentInput } from \"./contracts.ts\";\n\nconst RELEASE_PUBLISH_RE = /\\b(publish|release|push|deploy|tag)\\b/i;\nconst SECURITY_AUTH_RE = /\\b(auth|token|credential|credentials|secret|api[-_]key)\\b/i;\nconst DESTRUCTIVE_RE = /\\b(delete|reset|rm\\s+-rf|clean)\\b/i;\n\nconst SELF_MOD_MUTATE_RE =\n\t/\\b(modify|change|write|update|edit|delete|add|remove|set)\\s+.*\\b(skills|prompts|settings|tools|behavior)\\b|self[-_]modification/i;\nconst ARCHITECTURE_MUTATE_RE = /\\b(rewrite|redesign|change|modify|rearchitect)\\s+.*\\b(architecture|architect)\\b/i;\n\nconst READ_ONLY_QUESTION_RE =\n\t/^(?:(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+)?(?:how|what|why|when|where|which|who|explain|summarize|compare|describe|list|show|search|find|view|read|locate)\\b/i;\n\nconst EXPLICIT_MODIFY_REQUEST_RE =\n\t/^(?:can you|could you|please|pls|go ahead and|let'?s|i need you to|we need to|you should)\\s+.*\\b(add|apply|build|change|commit|create|delete|edit|fix|generate|implement|install|modify|patch|refactor|remove|rename|replace|run|test|update|write|publish|release|push|deploy|tag|reset|clean|rewrite)\\b/i;\n\n// Shell parsing helpers\nconst DESTRUCTIVE_CMD_RE =\n\t/\\b(rm(\\s+-r|\\s+-f|\\s+-rf|\\s+-fr)?|mv|cp|chmod|chown|install)\\b|>\\s*\\/dev\\/(sda|hda|vda)|\\b(dd\\s+if=)/i;\nconst GIT_MUTATE_CMD_RE = /\\bgit\\s+(commit|push|reset|clean|stash|rebase)\\b/i;\nconst PKG_MUTATE_CMD_RE = /\\b(npm|pnpm|yarn|bun)\\s+(install|i|update|up|publish|run|remove|rm|uninstall)\\b/i;\nconst RELEASE_DEPLOY_CMD_RE = /\\b(release|deploy)\\b/i;\nconst REDIRECTION_RE = /[<>]/;\n\nfunction stripSingleQuotes(cmd: string): string {\n\treturn cmd.replace(/'[^']*'/g, \"''\");\n}\n\nexport function assessOperationRisk(input: RiskAssessmentInput): RiskAssessment {\n\tconst operation = input.operation.trim();\n\tconst command = input.command?.trim() ?? \"\";\n\tconst cleanCommand = command ? stripSingleQuotes(command) : \"\";\n\tconst fullText = `${operation} ${command}`.trim();\n\tconst cleanFullText = `${operation} ${cleanCommand}`.trim();\n\n\tif (fullText.length === 0) {\n\t\treturn {\n\t\t\trisk: \"read-only\",\n\t\t\treasonCode: \"empty_operation\",\n\t\t\treasons: [\"Empty operation\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 1. Explicit read-only operations\n\tif (READ_ONLY_QUESTION_RE.test(operation) && !EXPLICIT_MODIFY_REQUEST_RE.test(operation)) {\n\t\treturn {\n\t\t\trisk: \"read-only\",\n\t\t\treasonCode: \"read_only_operation\",\n\t\t\treasons: [\"Operation is explicitly read-only (list/show/read/search)\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 2. High-risk actions\n\tif (RELEASE_PUBLISH_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"release_publish_operation\",\n\t\t\treasons: [\"Operation mentions releasing, publishing, or deploying\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (SECURITY_AUTH_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\", // updated based on user instruction: \"high-impact or approval-required\"\n\t\t\treasonCode: \"security_auth_operation\",\n\t\t\treasons: [\"Operation mentions authentication or credentials\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (DESTRUCTIVE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"destructive_operation\",\n\t\t\treasons: [\"Operation involves deleting, resetting, or cleaning\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (SELF_MOD_MUTATE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"approval-required\",\n\t\t\treasonCode: \"self_modification_operation\",\n\t\t\treasons: [\"Operation modifies settings, tools, skills, or prompts\"],\n\t\t\trequiresApproval: true,\n\t\t};\n\t}\n\tif (ARCHITECTURE_MUTATE_RE.test(cleanFullText)) {\n\t\treturn {\n\t\t\trisk: \"high-impact\",\n\t\t\treasonCode: \"architecture_mutation_operation\",\n\t\t\treasons: [\"Operation mentions rewriting or rearchitecting core parts\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\t// 3. Command risks\n\tif (command) {\n\t\tconst cleanCmd = stripSingleQuotes(command);\n\t\tif (\n\t\t\tDESTRUCTIVE_CMD_RE.test(cleanCmd) ||\n\t\t\tGIT_MUTATE_CMD_RE.test(cleanCmd) ||\n\t\t\tPKG_MUTATE_CMD_RE.test(cleanCmd) ||\n\t\t\tRELEASE_DEPLOY_CMD_RE.test(cleanCmd) ||\n\t\t\tREDIRECTION_RE.test(cleanCmd)\n\t\t) {\n\t\t\treturn {\n\t\t\t\trisk: \"approval-required\",\n\t\t\t\treasonCode: \"mutating_command\",\n\t\t\t\treasons: [\"Command executes a destructive, mutating, or publish operation\"],\n\t\t\t\trequiresApproval: true,\n\t\t\t};\n\t\t}\n\t}\n\n\t// Default to scoped-write for any generic mutating tool action if it has a toolName or isn't read-only\n\t// or read-only if it's purely a non-mutating intent (but since it didn't match read-only above, we default to scoped-write)\n\tif (\n\t\tinput.toolName &&\n\t\t![\"read_file\", \"search_web\", \"list_dir\", \"grep_search\", \"view_file\"].includes(input.toolName)\n\t) {\n\t\treturn {\n\t\t\trisk: \"scoped-write\",\n\t\t\treasonCode: \"generic_mutation\",\n\t\t\treasons: [\"Generic mutating operation or command\"],\n\t\t\trequiresApproval: false,\n\t\t};\n\t}\n\n\tif (command) {\n\t\t// Even if not explicitly destructive, shell commands could be anything, but we assume read-only if it's just 'ls', 'git status' etc.\n\t\t// For now, if no mutating patterns matched, we assume read-only if there's no toolName, but wait, normal file edits are scoped-write.\n\t\t// If there is a command, and it doesn't match the mutating patterns, we fall through to read-only.\n\t\t// Wait, user says \"Risk shell read-only commands like git status, rg, ls, npm view do not require approval.\"\n\t\t// And \"ordinary file edits inside allowed scope are scoped-write.\" (Handled by tools)\n\t}\n\n\treturn {\n\t\trisk: \"read-only\",\n\t\treasonCode: \"default_read_only\",\n\t\treasons: [\"No mutating or high-risk patterns detected\"],\n\t\trequiresApproval: false,\n\t};\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { SessionEntry, SessionManager } from "../session-manager.ts";
2
+ import { type LaneRecord } from "./lane-tracker.ts";
3
+ export declare const LANE_RECORD_CUSTOM_TYPE = "lane_record";
4
+ export interface LaneRecordSnapshotPayload {
5
+ version: 1;
6
+ record: LaneRecord;
7
+ }
8
+ export declare function appendLaneRecordSnapshot(sessionManager: Pick<SessionManager, "appendCustomEntry">, record: LaneRecord): string;
9
+ export declare function getLaneRecordSnapshots(entries: readonly SessionEntry[]): LaneRecord[];
10
+ //# sourceMappingURL=session-lane-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-lane-record.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/session-lane-record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAA2C,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7F,eAAO,MAAM,uBAAuB,gBAAgB,CAAC;AAErD,MAAM,WAAW,yBAAyB;IACzC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,wBAAwB,CACvC,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,MAAM,EAAE,UAAU,GAChB,MAAM,CAMR;AAQD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,UAAU,EAAE,CAmBrF","sourcesContent":["import type { SessionEntry, SessionManager } from \"../session-manager.ts\";\nimport { cloneLaneRecordForStorage, isLaneRecord, type LaneRecord } from \"./lane-tracker.ts\";\n\nexport const LANE_RECORD_CUSTOM_TYPE = \"lane_record\";\n\nexport interface LaneRecordSnapshotPayload {\n\tversion: 1;\n\trecord: LaneRecord;\n}\n\nexport function appendLaneRecordSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\trecord: LaneRecord,\n): string {\n\tconst payload: LaneRecordSnapshotPayload = {\n\t\tversion: 1,\n\t\trecord: cloneLaneRecordForStorage(record),\n\t};\n\treturn sessionManager.appendCustomEntry(LANE_RECORD_CUSTOM_TYPE, payload);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nexport function getLaneRecordSnapshots(entries: readonly SessionEntry[]): LaneRecord[] {\n\tconst records: LaneRecord[] = [];\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== LANE_RECORD_CUSTOM_TYPE) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst payload = entry.data;\n\t\tif (!isPlainRecord(payload)) continue;\n\t\tif (payload.version !== 1) continue;\n\t\tif (!(\"record\" in payload)) continue;\n\t\tconst record = payload.record;\n\t\tif (isLaneRecord(record)) {\n\t\t\trecords.push(cloneLaneRecordForStorage(record));\n\t\t}\n\t}\n\n\treturn records;\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import { cloneLaneRecordForStorage, isLaneRecord } from "./lane-tracker.js";
2
+ export const LANE_RECORD_CUSTOM_TYPE = "lane_record";
3
+ export function appendLaneRecordSnapshot(sessionManager, record) {
4
+ const payload = {
5
+ version: 1,
6
+ record: cloneLaneRecordForStorage(record),
7
+ };
8
+ return sessionManager.appendCustomEntry(LANE_RECORD_CUSTOM_TYPE, payload);
9
+ }
10
+ function isPlainRecord(value) {
11
+ if (!value || typeof value !== "object" || Array.isArray(value))
12
+ return false;
13
+ const prototype = Object.getPrototypeOf(value);
14
+ return prototype === Object.prototype || prototype === null;
15
+ }
16
+ export function getLaneRecordSnapshots(entries) {
17
+ const records = [];
18
+ for (const entry of entries) {
19
+ if (entry.type !== "custom" || entry.customType !== LANE_RECORD_CUSTOM_TYPE) {
20
+ continue;
21
+ }
22
+ const payload = entry.data;
23
+ if (!isPlainRecord(payload))
24
+ continue;
25
+ if (payload.version !== 1)
26
+ continue;
27
+ if (!("record" in payload))
28
+ continue;
29
+ const record = payload.record;
30
+ if (isLaneRecord(record)) {
31
+ records.push(cloneLaneRecordForStorage(record));
32
+ }
33
+ }
34
+ return records;
35
+ }
36
+ //# sourceMappingURL=session-lane-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-lane-record.js","sourceRoot":"","sources":["../../../src/core/autonomy/session-lane-record.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,YAAY,EAAmB,MAAM,mBAAmB,CAAC;AAE7F,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAOrD,MAAM,UAAU,wBAAwB,CACvC,cAAyD,EACzD,MAAkB,EACT;IACT,MAAM,OAAO,GAA8B;QAC1C,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,yBAAyB,CAAC,MAAM,CAAC;KACzC,CAAC;IACF,OAAO,cAAc,CAAC,iBAAiB,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;AAAA,CAC1E;AAED,SAAS,aAAa,CAAC,KAAc,EAAoC;IACxE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAAA,CAC5D;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgC,EAAgB;IACtF,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,KAAK,uBAAuB,EAAE,CAAC;YAC7E,SAAS;QACV,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC;YAAE,SAAS;QACpC,IAAI,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC;YAAE,SAAS;QACrC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAAA,CACf","sourcesContent":["import type { SessionEntry, SessionManager } from \"../session-manager.ts\";\nimport { cloneLaneRecordForStorage, isLaneRecord, type LaneRecord } from \"./lane-tracker.ts\";\n\nexport const LANE_RECORD_CUSTOM_TYPE = \"lane_record\";\n\nexport interface LaneRecordSnapshotPayload {\n\tversion: 1;\n\trecord: LaneRecord;\n}\n\nexport function appendLaneRecordSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\trecord: LaneRecord,\n): string {\n\tconst payload: LaneRecordSnapshotPayload = {\n\t\tversion: 1,\n\t\trecord: cloneLaneRecordForStorage(record),\n\t};\n\treturn sessionManager.appendCustomEntry(LANE_RECORD_CUSTOM_TYPE, payload);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === Object.prototype || prototype === null;\n}\n\nexport function getLaneRecordSnapshots(entries: readonly SessionEntry[]): LaneRecord[] {\n\tconst records: LaneRecord[] = [];\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== LANE_RECORD_CUSTOM_TYPE) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst payload = entry.data;\n\t\tif (!isPlainRecord(payload)) continue;\n\t\tif (payload.version !== 1) continue;\n\t\tif (!(\"record\" in payload)) continue;\n\t\tconst record = payload.record;\n\t\tif (isLaneRecord(record)) {\n\t\t\trecords.push(cloneLaneRecordForStorage(record));\n\t\t}\n\t}\n\n\treturn records;\n}\n"]}
@@ -0,0 +1,40 @@
1
+ export interface AutonomyStatusSnapshot {
2
+ latestRoute?: {
3
+ tier: string;
4
+ reasonCode: string;
5
+ risk?: string;
6
+ };
7
+ latestGate?: {
8
+ outcome: string;
9
+ gate: string;
10
+ reasonCode: string;
11
+ };
12
+ currentCostUsd?: number;
13
+ dailyCostUsd?: number;
14
+ spawnedCostUsd?: number;
15
+ activeGoal?: {
16
+ goalId: string;
17
+ status: string;
18
+ openRequirements?: number;
19
+ stallTurns?: number;
20
+ };
21
+ activeLaneCount?: number;
22
+ }
23
+ export interface DiagnosticEntry {
24
+ title: string;
25
+ summary?: string;
26
+ reasonCode?: string;
27
+ metadata?: Record<string, unknown>;
28
+ }
29
+ export interface AutonomyDiagnosticSnapshot {
30
+ routes?: readonly DiagnosticEntry[];
31
+ gates?: readonly DiagnosticEntry[];
32
+ costs?: readonly DiagnosticEntry[];
33
+ research?: readonly DiagnosticEntry[];
34
+ delegation?: readonly DiagnosticEntry[];
35
+ learning?: readonly DiagnosticEntry[];
36
+ goals?: readonly DiagnosticEntry[];
37
+ }
38
+ export declare function formatAutonomyStatus(args: AutonomyStatusSnapshot): string;
39
+ export declare function formatAutonomyDiagnostics(args: AutonomyDiagnosticSnapshot): string;
40
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/core/autonomy/status.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACtC,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChG,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,0BAA0B;IAC1C,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACnC,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACtC,UAAU,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACxC,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACtC,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CACnC;AA+CD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAuCzE;AAsBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,0BAA0B,GAAG,MAAM,CAalF","sourcesContent":["export interface AutonomyStatusSnapshot {\n\tlatestRoute?: { tier: string; reasonCode: string; risk?: string };\n\tlatestGate?: { outcome: string; gate: string; reasonCode: string };\n\tcurrentCostUsd?: number;\n\tdailyCostUsd?: number;\n\tspawnedCostUsd?: number;\n\tactiveGoal?: { goalId: string; status: string; openRequirements?: number; stallTurns?: number };\n\tactiveLaneCount?: number;\n}\n\nexport interface DiagnosticEntry {\n\ttitle: string;\n\tsummary?: string;\n\treasonCode?: string;\n\tmetadata?: Record<string, unknown>;\n}\n\nexport interface AutonomyDiagnosticSnapshot {\n\troutes?: readonly DiagnosticEntry[];\n\tgates?: readonly DiagnosticEntry[];\n\tcosts?: readonly DiagnosticEntry[];\n\tresearch?: readonly DiagnosticEntry[];\n\tdelegation?: readonly DiagnosticEntry[];\n\tlearning?: readonly DiagnosticEntry[];\n\tgoals?: readonly DiagnosticEntry[];\n}\n\nconst REDACTED = \"[REDACTED]\";\nconst CIRCULAR = \"[Circular]\";\nconst MAX_STRING_LENGTH = 200;\nconst SENSITIVE_KEYS = [\"token\", \"secret\", \"key\", \"credential\", \"password\", \"authorization\"];\nconst SENSITIVE_VALUE_REGEX = /bearer\\s+[\\w\\-._]+|api[-_]?key[-_]?[\\w\\-._]+|sk-[\\w\\-._]+/i;\n\nfunction formatCost(value: number): string {\n\treturn Number.isFinite(value) ? `$${value.toFixed(4)}` : \"$0.0000\";\n}\n\nfunction redactAndTruncateString(value: string): string {\n\tif (SENSITIVE_VALUE_REGEX.test(value)) return REDACTED;\n\tif (value.length <= MAX_STRING_LENGTH) return value;\n\treturn `${value.slice(0, MAX_STRING_LENGTH - 1)}…`;\n}\n\nfunction isSensitiveKey(key: string): boolean {\n\tconst lowerKey = key.toLowerCase();\n\treturn SENSITIVE_KEYS.some((sensitiveKey) => lowerKey.includes(sensitiveKey));\n}\n\nfunction sanitizeMetadataValue(value: unknown, seen: WeakSet<object>): unknown {\n\tif (typeof value === \"string\") return redactAndTruncateString(value);\n\tif (typeof value !== \"object\" || value === null) return value;\n\tif (seen.has(value)) return CIRCULAR;\n\tif (Array.isArray(value)) {\n\t\tseen.add(value);\n\t\treturn value.map((item) => sanitizeMetadataValue(item, seen));\n\t}\n\treturn sanitizeMetadata(value as Record<string, unknown>, seen);\n}\n\nfunction sanitizeMetadata(\n\tobj: Record<string, unknown>,\n\tseen: WeakSet<object> = new WeakSet(),\n): Record<string, unknown> {\n\tif (seen.has(obj)) return { value: CIRCULAR };\n\tseen.add(obj);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tresult[key] = isSensitiveKey(key) ? REDACTED : sanitizeMetadataValue(value, seen);\n\t}\n\treturn result;\n}\n\nexport function formatAutonomyStatus(args: AutonomyStatusSnapshot): string {\n\tconst parts: string[] = [];\n\n\tif (args.latestRoute) {\n\t\tconst risk = args.latestRoute.risk ? ` (${redactAndTruncateString(args.latestRoute.risk)})` : \"\";\n\t\tparts.push(\n\t\t\t`Route: ${redactAndTruncateString(args.latestRoute.tier)}${risk} - ${redactAndTruncateString(args.latestRoute.reasonCode)}`,\n\t\t);\n\t}\n\n\tif (args.latestGate) {\n\t\tparts.push(\n\t\t\t`Gate: ${redactAndTruncateString(args.latestGate.gate)} = ${redactAndTruncateString(args.latestGate.outcome)} (${redactAndTruncateString(args.latestGate.reasonCode)})`,\n\t\t);\n\t}\n\n\tconst costs: string[] = [];\n\tif (args.currentCostUsd !== undefined) costs.push(`current: ${formatCost(args.currentCostUsd)}`);\n\tif (args.dailyCostUsd !== undefined) costs.push(`daily: ${formatCost(args.dailyCostUsd)}`);\n\tif (args.spawnedCostUsd !== undefined) costs.push(`spawned: ${formatCost(args.spawnedCostUsd)}`);\n\tif (costs.length > 0) {\n\t\tparts.push(`Costs: ${costs.join(\", \")}`);\n\t}\n\n\tif (args.activeGoal) {\n\t\tconst goal = args.activeGoal;\n\t\tconst requirements = goal.openRequirements !== undefined ? `, open reqs: ${goal.openRequirements}` : \"\";\n\t\tconst stalls = goal.stallTurns !== undefined ? `, stalls: ${goal.stallTurns}` : \"\";\n\t\tparts.push(\n\t\t\t`Goal [${redactAndTruncateString(goal.goalId)}]: ${redactAndTruncateString(goal.status)}${requirements}${stalls}`,\n\t\t);\n\t}\n\n\tif (args.activeLaneCount !== undefined) {\n\t\tparts.push(`Lanes: ${args.activeLaneCount}`);\n\t}\n\n\tif (parts.length === 0) return \"Autonomy: idle\";\n\treturn parts.join(\" | \");\n}\n\nfunction formatDiagnosticSection(name: string, entries?: readonly DiagnosticEntry[]): string | undefined {\n\tif (!entries || entries.length === 0) return undefined;\n\n\tconst lines: string[] = [`--- ${name} ---`];\n\tfor (const entry of entries) {\n\t\tlet header = `- ${redactAndTruncateString(entry.title)}`;\n\t\tif (entry.reasonCode) header += ` [${redactAndTruncateString(entry.reasonCode)}]`;\n\t\tlines.push(header);\n\n\t\tif (entry.summary) {\n\t\t\tlines.push(` Summary: ${redactAndTruncateString(entry.summary)}`);\n\t\t}\n\n\t\tif (entry.metadata) {\n\t\t\tlines.push(` Metadata: ${JSON.stringify(sanitizeMetadata(entry.metadata))}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function formatAutonomyDiagnostics(args: AutonomyDiagnosticSnapshot): string {\n\tconst sections = [\n\t\tformatDiagnosticSection(\"Routes\", args.routes),\n\t\tformatDiagnosticSection(\"Gates\", args.gates),\n\t\tformatDiagnosticSection(\"Costs\", args.costs),\n\t\tformatDiagnosticSection(\"Research\", args.research),\n\t\tformatDiagnosticSection(\"Delegation\", args.delegation),\n\t\tformatDiagnosticSection(\"Learning\", args.learning),\n\t\tformatDiagnosticSection(\"Goals\", args.goals),\n\t].filter((section): section is string => Boolean(section));\n\n\tif (sections.length === 0) return \"No diagnostics available.\";\n\treturn sections.join(\"\\n\\n\");\n}\n"]}