@caupulican/pi-adaptative 0.81.39 → 0.81.41

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 (884) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +3 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +4 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
  13. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
  14. package/dist/cli/args.d.ts +4 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +31 -1
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-directory-layout.d.ts +15 -0
  19. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  20. package/dist/core/agent-directory-layout.js +72 -0
  21. package/dist/core/agent-directory-layout.js.map +1 -0
  22. package/dist/core/agent-paths.d.ts +25 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +79 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-contracts.d.ts +293 -0
  27. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  28. package/dist/core/agent-session-contracts.js +26 -0
  29. package/dist/core/agent-session-contracts.js.map +1 -0
  30. package/dist/core/agent-session-runtime.d.ts +52 -8
  31. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  32. package/dist/core/agent-session-runtime.js +400 -79
  33. package/dist/core/agent-session-runtime.js.map +1 -1
  34. package/dist/core/agent-session-services.d.ts +1 -0
  35. package/dist/core/agent-session-services.d.ts.map +1 -1
  36. package/dist/core/agent-session-services.js +1 -0
  37. package/dist/core/agent-session-services.js.map +1 -1
  38. package/dist/core/agent-session.d.ts +74 -518
  39. package/dist/core/agent-session.d.ts.map +1 -1
  40. package/dist/core/agent-session.js +370 -1432
  41. package/dist/core/agent-session.js.map +1 -1
  42. package/dist/core/auth-storage.d.ts.map +1 -1
  43. package/dist/core/auth-storage.js +3 -1
  44. package/dist/core/auth-storage.js.map +1 -1
  45. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  46. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  47. package/dist/core/autonomy/approval-gate.js +6 -28
  48. package/dist/core/autonomy/approval-gate.js.map +1 -1
  49. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  50. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  51. package/dist/core/autonomy/bounded-completion.js +1 -1
  52. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  53. package/dist/core/autonomy/contracts.d.ts +20 -12
  54. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  55. package/dist/core/autonomy/contracts.js.map +1 -1
  56. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  57. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  58. package/dist/core/autonomy/foreground-envelope.js +8 -25
  59. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  60. package/dist/core/autonomy/gates.d.ts.map +1 -1
  61. package/dist/core/autonomy/gates.js +8 -10
  62. package/dist/core/autonomy/gates.js.map +1 -1
  63. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  64. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  65. package/dist/core/autonomy/lane-private-paths.js +16 -0
  66. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  67. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  68. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  69. package/dist/core/autonomy/lane-tool-surface.js +48 -9
  70. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  71. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  72. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  73. package/dist/core/autonomy/lane-tracker.js +38 -0
  74. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  75. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  76. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  77. package/dist/core/autonomy/risk-assessment.js +1 -123
  78. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  79. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  80. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  81. package/dist/core/autonomy/session-lane-record.js +16 -29
  82. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  83. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  84. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  85. package/dist/core/autonomy/telemetry-events.js +1 -1
  86. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  87. package/dist/core/autonomy-telemetry.d.ts +7 -7
  88. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  89. package/dist/core/autonomy-telemetry.js +9 -9
  90. package/dist/core/autonomy-telemetry.js.map +1 -1
  91. package/dist/core/background-lane-controller.d.ts +56 -236
  92. package/dist/core/background-lane-controller.d.ts.map +1 -1
  93. package/dist/core/background-lane-controller.js +141 -1273
  94. package/dist/core/background-lane-controller.js.map +1 -1
  95. package/dist/core/bedrock-sso-login.d.ts +16 -0
  96. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  97. package/dist/core/bedrock-sso-login.js +98 -0
  98. package/dist/core/bedrock-sso-login.js.map +1 -0
  99. package/dist/core/capability-contract.d.ts +4 -0
  100. package/dist/core/capability-contract.d.ts.map +1 -0
  101. package/dist/core/capability-contract.js +28 -0
  102. package/dist/core/capability-contract.js.map +1 -0
  103. package/dist/core/compaction-controller.d.ts +90 -0
  104. package/dist/core/compaction-controller.d.ts.map +1 -0
  105. package/dist/core/compaction-controller.js +452 -0
  106. package/dist/core/compaction-controller.js.map +1 -0
  107. package/dist/core/compaction-support.d.ts +13 -17
  108. package/dist/core/compaction-support.d.ts.map +1 -1
  109. package/dist/core/compaction-support.js +3 -3
  110. package/dist/core/compaction-support.js.map +1 -1
  111. package/dist/core/context/context-artifacts.d.ts +6 -2
  112. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  113. package/dist/core/context/context-artifacts.js +34 -2
  114. package/dist/core/context/context-artifacts.js.map +1 -1
  115. package/dist/core/context/context-store-retention.d.ts +8 -2
  116. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  117. package/dist/core/context/context-store-retention.js +158 -35
  118. package/dist/core/context/context-store-retention.js.map +1 -1
  119. package/dist/core/context/okf-memory.d.ts.map +1 -1
  120. package/dist/core/context/okf-memory.js +9 -11
  121. package/dist/core/context/okf-memory.js.map +1 -1
  122. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  123. package/dist/core/context/sqlite-runtime-index.js +6 -8
  124. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  125. package/dist/core/context-gc.d.ts +3 -0
  126. package/dist/core/context-gc.d.ts.map +1 -1
  127. package/dist/core/context-gc.js +10 -5
  128. package/dist/core/context-gc.js.map +1 -1
  129. package/dist/core/context-pipeline.d.ts +1 -1
  130. package/dist/core/context-pipeline.d.ts.map +1 -1
  131. package/dist/core/context-pipeline.js +16 -37
  132. package/dist/core/context-pipeline.js.map +1 -1
  133. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  134. package/dist/core/cost/cost-summary.js +5 -3
  135. package/dist/core/cost/cost-summary.js.map +1 -1
  136. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  137. package/dist/core/cost/daily-usage.js +4 -5
  138. package/dist/core/cost/daily-usage.js.map +1 -1
  139. package/dist/core/default-tool-surface.d.ts.map +1 -1
  140. package/dist/core/default-tool-surface.js +2 -0
  141. package/dist/core/default-tool-surface.js.map +1 -1
  142. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  143. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  144. package/dist/core/delegation/managed-lane-controller.js +217 -0
  145. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  146. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  147. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-claim.js +98 -0
  149. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  150. package/dist/core/delegation/worker-actions.d.ts +7 -5
  151. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  152. package/dist/core/delegation/worker-actions.js +20 -4
  153. package/dist/core/delegation/worker-actions.js.map +1 -1
  154. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  155. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  156. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  157. package/dist/core/delegation/worker-claim.js.map +1 -0
  158. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  159. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  160. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  161. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  162. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  163. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  164. package/dist/core/delegation/worker-delegation-request.js +2 -0
  165. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  166. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  167. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  168. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  169. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  170. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  171. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  172. package/dist/core/delegation/worker-execution-policy.js +160 -0
  173. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  174. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  175. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  176. package/dist/core/delegation/worker-lane-projection.js +100 -0
  177. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  178. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  179. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  180. package/dist/core/delegation/worker-lifecycle.js +339 -0
  181. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  182. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  183. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  184. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  185. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  186. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  187. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  188. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  189. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  190. package/dist/core/delegation/worker-runner.d.ts +25 -14
  191. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  192. package/dist/core/delegation/worker-runner.js +122 -53
  193. package/dist/core/delegation/worker-runner.js.map +1 -1
  194. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  195. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  196. package/dist/core/delegation/worker-task-label.js +11 -0
  197. package/dist/core/delegation/worker-task-label.js.map +1 -0
  198. package/dist/core/doctor.d.ts +8 -0
  199. package/dist/core/doctor.d.ts.map +1 -1
  200. package/dist/core/doctor.js +32 -1
  201. package/dist/core/doctor.js.map +1 -1
  202. package/dist/core/extension-import-authority.d.ts +6 -0
  203. package/dist/core/extension-import-authority.d.ts.map +1 -0
  204. package/dist/core/extension-import-authority.js +10 -0
  205. package/dist/core/extension-import-authority.js.map +1 -0
  206. package/dist/core/extensions/index.d.ts +1 -1
  207. package/dist/core/extensions/index.d.ts.map +1 -1
  208. package/dist/core/extensions/index.js.map +1 -1
  209. package/dist/core/extensions/loader.d.ts +5 -1
  210. package/dist/core/extensions/loader.d.ts.map +1 -1
  211. package/dist/core/extensions/loader.js +52 -18
  212. package/dist/core/extensions/loader.js.map +1 -1
  213. package/dist/core/extensions/runner.d.ts +3 -0
  214. package/dist/core/extensions/runner.d.ts.map +1 -1
  215. package/dist/core/extensions/runner.js +20 -5
  216. package/dist/core/extensions/runner.js.map +1 -1
  217. package/dist/core/extensions/stale-context.d.ts +2 -0
  218. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  219. package/dist/core/extensions/stale-context.js +2 -0
  220. package/dist/core/extensions/stale-context.js.map +1 -0
  221. package/dist/core/extensions/storage.d.ts +8 -0
  222. package/dist/core/extensions/storage.d.ts.map +1 -0
  223. package/dist/core/extensions/storage.js +28 -0
  224. package/dist/core/extensions/storage.js.map +1 -0
  225. package/dist/core/extensions/types.d.ts +78 -21
  226. package/dist/core/extensions/types.d.ts.map +1 -1
  227. package/dist/core/extensions/types.js.map +1 -1
  228. package/dist/core/failure-corpus.d.ts +1 -15
  229. package/dist/core/failure-corpus.d.ts.map +1 -1
  230. package/dist/core/failure-corpus.js +9 -37
  231. package/dist/core/failure-corpus.js.map +1 -1
  232. package/dist/core/foreground-recovery-controller.d.ts +53 -0
  233. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  234. package/dist/core/foreground-recovery-controller.js +111 -0
  235. package/dist/core/foreground-recovery-controller.js.map +1 -0
  236. package/dist/core/gateways/channel-provider.d.ts +3 -0
  237. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  238. package/dist/core/gateways/channel-provider.js +31 -6
  239. package/dist/core/gateways/channel-provider.js.map +1 -1
  240. package/dist/core/goal-loop-controller.d.ts +14 -9
  241. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  242. package/dist/core/goal-loop-controller.js +47 -75
  243. package/dist/core/goal-loop-controller.js.map +1 -1
  244. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  245. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  246. package/dist/core/goals/compact-goal-context.js +59 -0
  247. package/dist/core/goals/compact-goal-context.js.map +1 -0
  248. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  249. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  250. package/dist/core/goals/goal-acceptance.js +27 -0
  251. package/dist/core/goals/goal-acceptance.js.map +1 -0
  252. package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
  253. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  254. package/dist/core/goals/goal-auto-continue-controller.js +90 -0
  255. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  256. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  257. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  258. package/dist/core/goals/goal-continuation-controller.js +52 -11
  259. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  260. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  261. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  262. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  263. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  264. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  265. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  266. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  267. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  268. package/dist/core/goals/goal-lifecycle.d.ts +43 -0
  269. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  270. package/dist/core/goals/goal-lifecycle.js +102 -0
  271. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  272. package/dist/core/goals/goal-record.d.ts +17 -0
  273. package/dist/core/goals/goal-record.d.ts.map +1 -0
  274. package/dist/core/goals/goal-record.js +31 -0
  275. package/dist/core/goals/goal-record.js.map +1 -0
  276. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  277. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  278. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  279. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  280. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  281. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  282. package/dist/core/goals/goal-session-controller.js +128 -0
  283. package/dist/core/goals/goal-session-controller.js.map +1 -0
  284. package/dist/core/goals/goal-state.d.ts +46 -25
  285. package/dist/core/goals/goal-state.d.ts.map +1 -1
  286. package/dist/core/goals/goal-state.js +91 -24
  287. package/dist/core/goals/goal-state.js.map +1 -1
  288. package/dist/core/goals/goal-tool-core.d.ts +9 -10
  289. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  290. package/dist/core/goals/goal-tool-core.js +60 -75
  291. package/dist/core/goals/goal-tool-core.js.map +1 -1
  292. package/dist/core/goals/session-goal-state.d.ts +20 -12
  293. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  294. package/dist/core/goals/session-goal-state.js +133 -33
  295. package/dist/core/goals/session-goal-state.js.map +1 -1
  296. package/dist/core/human-input-controller.d.ts +47 -0
  297. package/dist/core/human-input-controller.d.ts.map +1 -0
  298. package/dist/core/human-input-controller.js +181 -0
  299. package/dist/core/human-input-controller.js.map +1 -0
  300. package/dist/core/human-input.d.ts +100 -0
  301. package/dist/core/human-input.d.ts.map +1 -0
  302. package/dist/core/human-input.js +362 -0
  303. package/dist/core/human-input.js.map +1 -0
  304. package/dist/core/index.d.ts +9 -1
  305. package/dist/core/index.d.ts.map +1 -1
  306. package/dist/core/index.js +9 -1
  307. package/dist/core/index.js.map +1 -1
  308. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  309. package/dist/core/install-telemetry.d.ts.map +1 -0
  310. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  311. package/dist/core/install-telemetry.js.map +1 -0
  312. package/dist/core/keybindings.d.ts +17 -1
  313. package/dist/core/keybindings.d.ts.map +1 -1
  314. package/dist/core/keybindings.js +24 -6
  315. package/dist/core/keybindings.js.map +1 -1
  316. package/dist/core/learning/learning-audit.d.ts +2 -4
  317. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  318. package/dist/core/learning/learning-audit.js +9 -29
  319. package/dist/core/learning/learning-audit.js.map +1 -1
  320. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  321. package/dist/core/learning/learning-gate.js +1 -6
  322. package/dist/core/learning/learning-gate.js.map +1 -1
  323. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  324. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  325. package/dist/core/learning/session-learning-decision.js +9 -29
  326. package/dist/core/learning/session-learning-decision.js.map +1 -1
  327. package/dist/core/local-runtime-controller.d.ts +1 -1
  328. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  329. package/dist/core/local-runtime-controller.js.map +1 -1
  330. package/dist/core/memory-controller.d.ts.map +1 -1
  331. package/dist/core/memory-controller.js +4 -4
  332. package/dist/core/memory-controller.js.map +1 -1
  333. package/dist/core/model-capability.d.ts +0 -19
  334. package/dist/core/model-capability.d.ts.map +1 -1
  335. package/dist/core/model-capability.js +1 -19
  336. package/dist/core/model-capability.js.map +1 -1
  337. package/dist/core/model-registry.d.ts +6 -1
  338. package/dist/core/model-registry.d.ts.map +1 -1
  339. package/dist/core/model-registry.js +13 -5
  340. package/dist/core/model-registry.js.map +1 -1
  341. package/dist/core/model-resolver.d.ts +17 -2
  342. package/dist/core/model-resolver.d.ts.map +1 -1
  343. package/dist/core/model-resolver.js +38 -25
  344. package/dist/core/model-resolver.js.map +1 -1
  345. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  346. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  347. package/dist/core/model-router/intent-classifier.js +1 -156
  348. package/dist/core/model-router/intent-classifier.js.map +1 -1
  349. package/dist/core/model-router-controller.d.ts +1 -1
  350. package/dist/core/model-router-controller.d.ts.map +1 -1
  351. package/dist/core/model-router-controller.js +2 -2
  352. package/dist/core/model-router-controller.js.map +1 -1
  353. package/dist/core/model-selection-controller.d.ts +5 -5
  354. package/dist/core/model-selection-controller.d.ts.map +1 -1
  355. package/dist/core/model-selection-controller.js.map +1 -1
  356. package/dist/core/model-tool-protocol.d.ts +23 -0
  357. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  358. package/dist/core/model-tool-protocol.js +43 -0
  359. package/dist/core/model-tool-protocol.js.map +1 -0
  360. package/dist/core/models/adaptation-store.d.ts +4 -6
  361. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  362. package/dist/core/models/adaptation-store.js +95 -83
  363. package/dist/core/models/adaptation-store.js.map +1 -1
  364. package/dist/core/models/fitness-store.d.ts +2 -12
  365. package/dist/core/models/fitness-store.d.ts.map +1 -1
  366. package/dist/core/models/fitness-store.js +84 -57
  367. package/dist/core/models/fitness-store.js.map +1 -1
  368. package/dist/core/models/host-state-store.d.ts +34 -0
  369. package/dist/core/models/host-state-store.d.ts.map +1 -0
  370. package/dist/core/models/host-state-store.js +86 -0
  371. package/dist/core/models/host-state-store.js.map +1 -0
  372. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  373. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  374. package/dist/core/orchestration/agent-resume.js +90 -0
  375. package/dist/core/orchestration/agent-resume.js.map +1 -0
  376. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  377. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  378. package/dist/core/orchestration/capability-gateway.js +152 -0
  379. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  380. package/dist/core/orchestration/contracts.d.ts +343 -0
  381. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  382. package/dist/core/orchestration/contracts.js +135 -0
  383. package/dist/core/orchestration/contracts.js.map +1 -0
  384. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  385. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  386. package/dist/core/orchestration/delegation-ledger.js +200 -0
  387. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  388. package/dist/core/orchestration/event-store.d.ts +83 -0
  389. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  390. package/dist/core/orchestration/event-store.js +560 -0
  391. package/dist/core/orchestration/event-store.js.map +1 -0
  392. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  393. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  394. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  395. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  396. package/dist/core/orchestration/model-binding.d.ts +15 -0
  397. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  398. package/dist/core/orchestration/model-binding.js +29 -0
  399. package/dist/core/orchestration/model-binding.js.map +1 -0
  400. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  401. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  402. package/dist/core/orchestration/policy-compiler.js +191 -0
  403. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  404. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  405. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  406. package/dist/core/orchestration/policy-gate.js +24 -0
  407. package/dist/core/orchestration/policy-gate.js.map +1 -0
  408. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  409. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  410. package/dist/core/orchestration/profile-registry.js +393 -0
  411. package/dist/core/orchestration/profile-registry.js.map +1 -0
  412. package/dist/core/orchestration/profile-store.d.ts +31 -0
  413. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  414. package/dist/core/orchestration/profile-store.js +136 -0
  415. package/dist/core/orchestration/profile-store.js.map +1 -0
  416. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  417. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  418. package/dist/core/orchestration/risk-budget.js +48 -0
  419. package/dist/core/orchestration/risk-budget.js.map +1 -0
  420. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  421. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  422. package/dist/core/orchestration/task-runtime.js +1600 -0
  423. package/dist/core/orchestration/task-runtime.js.map +1 -0
  424. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  425. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  426. package/dist/core/orchestration/work-state-projection.js +116 -0
  427. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  428. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  429. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  430. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  431. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  432. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  433. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  434. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  435. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  436. package/dist/core/package-manager.d.ts.map +1 -1
  437. package/dist/core/package-manager.js +20 -3
  438. package/dist/core/package-manager.js.map +1 -1
  439. package/dist/core/process-identity.d.ts +11 -0
  440. package/dist/core/process-identity.d.ts.map +1 -0
  441. package/dist/core/process-identity.js +26 -0
  442. package/dist/core/process-identity.js.map +1 -0
  443. package/dist/core/process-matrix/codes.d.ts +14 -3
  444. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  445. package/dist/core/process-matrix/codes.js.map +1 -1
  446. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  447. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  448. package/dist/core/process-matrix/resume-launcher.js +62 -0
  449. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  450. package/dist/core/process-matrix/runtime.d.ts +37 -22
  451. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  452. package/dist/core/process-matrix/runtime.js +399 -76
  453. package/dist/core/process-matrix/runtime.js.map +1 -1
  454. package/dist/core/process-matrix/store.d.ts +5 -2
  455. package/dist/core/process-matrix/store.d.ts.map +1 -1
  456. package/dist/core/process-matrix/store.js +123 -14
  457. package/dist/core/process-matrix/store.js.map +1 -1
  458. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  459. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  460. package/dist/core/process-matrix/supervisor.js +45 -14
  461. package/dist/core/process-matrix/supervisor.js.map +1 -1
  462. package/dist/core/profile-filter-controller.d.ts +8 -1
  463. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  464. package/dist/core/profile-filter-controller.js +23 -5
  465. package/dist/core/profile-filter-controller.js.map +1 -1
  466. package/dist/core/profile-registry.d.ts.map +1 -1
  467. package/dist/core/profile-registry.js +6 -8
  468. package/dist/core/profile-registry.js.map +1 -1
  469. package/dist/core/prompt-templates.d.ts +1 -0
  470. package/dist/core/prompt-templates.d.ts.map +1 -1
  471. package/dist/core/prompt-templates.js +18 -29
  472. package/dist/core/prompt-templates.js.map +1 -1
  473. package/dist/core/reflection-controller.d.ts +5 -5
  474. package/dist/core/reflection-controller.d.ts.map +1 -1
  475. package/dist/core/reflection-controller.js +5 -2
  476. package/dist/core/reflection-controller.js.map +1 -1
  477. package/dist/core/reload-blockers.d.ts.map +1 -1
  478. package/dist/core/reload-blockers.js +6 -8
  479. package/dist/core/reload-blockers.js.map +1 -1
  480. package/dist/core/request-auth.d.ts +7 -0
  481. package/dist/core/request-auth.d.ts.map +1 -0
  482. package/dist/core/request-auth.js +8 -0
  483. package/dist/core/request-auth.js.map +1 -0
  484. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  485. package/dist/core/research/evidence-bundle.js +1 -6
  486. package/dist/core/research/evidence-bundle.js.map +1 -1
  487. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  488. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  489. package/dist/core/research/lane-model-resolver.js +65 -0
  490. package/dist/core/research/lane-model-resolver.js.map +1 -0
  491. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  492. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  493. package/dist/core/research/model-fitness-controller.js +106 -0
  494. package/dist/core/research/model-fitness-controller.js.map +1 -0
  495. package/dist/core/research/model-fitness.d.ts +1 -1
  496. package/dist/core/research/model-fitness.d.ts.map +1 -1
  497. package/dist/core/research/model-fitness.js +4 -4
  498. package/dist/core/research/model-fitness.js.map +1 -1
  499. package/dist/core/research/research-gate.d.ts.map +1 -1
  500. package/dist/core/research/research-gate.js +7 -7
  501. package/dist/core/research/research-gate.js.map +1 -1
  502. package/dist/core/research/research-lane-controller.d.ts +62 -0
  503. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  504. package/dist/core/research/research-lane-controller.js +292 -0
  505. package/dist/core/research/research-lane-controller.js.map +1 -0
  506. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  507. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  508. package/dist/core/research/session-evidence-bundle.js +10 -46
  509. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  510. package/dist/core/resource-loader.d.ts.map +1 -1
  511. package/dist/core/resource-loader.js +23 -8
  512. package/dist/core/resource-loader.js.map +1 -1
  513. package/dist/core/risk-classifier.d.ts +6 -0
  514. package/dist/core/risk-classifier.d.ts.map +1 -0
  515. package/dist/core/risk-classifier.js +233 -0
  516. package/dist/core/risk-classifier.js.map +1 -0
  517. package/dist/core/runtime-builder.d.ts +41 -23
  518. package/dist/core/runtime-builder.d.ts.map +1 -1
  519. package/dist/core/runtime-builder.js +365 -253
  520. package/dist/core/runtime-builder.js.map +1 -1
  521. package/dist/core/sdk.d.ts +6 -3
  522. package/dist/core/sdk.d.ts.map +1 -1
  523. package/dist/core/sdk.js +68 -25
  524. package/dist/core/sdk.js.map +1 -1
  525. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  526. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  527. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  528. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  529. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  530. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  531. package/dist/core/secrets/secret-dotenv.js +183 -0
  532. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  533. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  534. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  535. package/dist/core/secrets/secret-vault-format.js +397 -0
  536. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  537. package/dist/core/secrets/secret-vault.d.ts +72 -0
  538. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  539. package/dist/core/secrets/secret-vault.js +671 -0
  540. package/dist/core/secrets/secret-vault.js.map +1 -0
  541. package/dist/core/session-analytics.d.ts +4 -23
  542. package/dist/core/session-analytics.d.ts.map +1 -1
  543. package/dist/core/session-analytics.js +67 -70
  544. package/dist/core/session-analytics.js.map +1 -1
  545. package/dist/core/session-image-store.d.ts +33 -0
  546. package/dist/core/session-image-store.d.ts.map +1 -0
  547. package/dist/core/session-image-store.js +283 -0
  548. package/dist/core/session-image-store.js.map +1 -0
  549. package/dist/core/session-role.d.ts +11 -4
  550. package/dist/core/session-role.d.ts.map +1 -1
  551. package/dist/core/session-role.js +24 -5
  552. package/dist/core/session-role.js.map +1 -1
  553. package/dist/core/session-snapshot.d.ts +34 -0
  554. package/dist/core/session-snapshot.d.ts.map +1 -0
  555. package/dist/core/session-snapshot.js +68 -0
  556. package/dist/core/session-snapshot.js.map +1 -0
  557. package/dist/core/session-supervision-runtime.d.ts +31 -0
  558. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  559. package/dist/core/session-supervision-runtime.js +97 -0
  560. package/dist/core/session-supervision-runtime.js.map +1 -0
  561. package/dist/core/session-tree-navigator.d.ts +4 -6
  562. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  563. package/dist/core/session-tree-navigator.js +4 -1
  564. package/dist/core/session-tree-navigator.js.map +1 -1
  565. package/dist/core/settings-manager.d.ts +10 -5
  566. package/dist/core/settings-manager.d.ts.map +1 -1
  567. package/dist/core/settings-manager.js +81 -29
  568. package/dist/core/settings-manager.js.map +1 -1
  569. package/dist/core/slash-commands.d.ts.map +1 -1
  570. package/dist/core/slash-commands.js +2 -2
  571. package/dist/core/slash-commands.js.map +1 -1
  572. package/dist/core/tasks/session-task-state.d.ts +2 -4
  573. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  574. package/dist/core/tasks/session-task-state.js +10 -28
  575. package/dist/core/tasks/session-task-state.js.map +1 -1
  576. package/dist/core/tasks/task-projection.d.ts +20 -0
  577. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  578. package/dist/core/tasks/task-projection.js +47 -0
  579. package/dist/core/tasks/task-projection.js.map +1 -0
  580. package/dist/core/tasks/task-state.d.ts +4 -0
  581. package/dist/core/tasks/task-state.d.ts.map +1 -1
  582. package/dist/core/tasks/task-state.js +28 -11
  583. package/dist/core/tasks/task-state.js.map +1 -1
  584. package/dist/core/tool-capability-policy.d.ts +13 -0
  585. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  586. package/dist/core/tool-capability-policy.js +86 -0
  587. package/dist/core/tool-capability-policy.js.map +1 -0
  588. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  589. package/dist/core/tool-gate-controller.js +8 -2
  590. package/dist/core/tool-gate-controller.js.map +1 -1
  591. package/dist/core/tool-protocol-controller.d.ts +89 -0
  592. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  593. package/dist/core/tool-protocol-controller.js +512 -0
  594. package/dist/core/tool-protocol-controller.js.map +1 -0
  595. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  596. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  597. package/dist/core/tool-recovery-log-records.js +9 -35
  598. package/dist/core/tool-recovery-log-records.js.map +1 -1
  599. package/dist/core/tool-recovery-stats.d.ts +21 -1
  600. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  601. package/dist/core/tool-recovery-stats.js.map +1 -1
  602. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  603. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  604. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  605. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  606. package/dist/core/tools/ask-question.d.ts +124 -0
  607. package/dist/core/tools/ask-question.d.ts.map +1 -0
  608. package/dist/core/tools/ask-question.js +693 -0
  609. package/dist/core/tools/ask-question.js.map +1 -0
  610. package/dist/core/tools/bash.d.ts +5 -0
  611. package/dist/core/tools/bash.d.ts.map +1 -1
  612. package/dist/core/tools/bash.js +59 -5
  613. package/dist/core/tools/bash.js.map +1 -1
  614. package/dist/core/tools/delegate-status.d.ts +31 -3
  615. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  616. package/dist/core/tools/delegate-status.js +148 -29
  617. package/dist/core/tools/delegate-status.js.map +1 -1
  618. package/dist/core/tools/delegate.d.ts +15 -13
  619. package/dist/core/tools/delegate.d.ts.map +1 -1
  620. package/dist/core/tools/delegate.js +106 -23
  621. package/dist/core/tools/delegate.js.map +1 -1
  622. package/dist/core/tools/extensionify.d.ts.map +1 -1
  623. package/dist/core/tools/extensionify.js +1 -0
  624. package/dist/core/tools/extensionify.js.map +1 -1
  625. package/dist/core/tools/git-filter.d.ts +1 -8
  626. package/dist/core/tools/git-filter.d.ts.map +1 -1
  627. package/dist/core/tools/git-filter.js +2 -63
  628. package/dist/core/tools/git-filter.js.map +1 -1
  629. package/dist/core/tools/goal.d.ts +10 -8
  630. package/dist/core/tools/goal.d.ts.map +1 -1
  631. package/dist/core/tools/goal.js +106 -28
  632. package/dist/core/tools/goal.js.map +1 -1
  633. package/dist/core/tools/index.d.ts +1 -0
  634. package/dist/core/tools/index.d.ts.map +1 -1
  635. package/dist/core/tools/index.js +1 -0
  636. package/dist/core/tools/index.js.map +1 -1
  637. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  638. package/dist/core/tools/model-fitness.js +2 -2
  639. package/dist/core/tools/model-fitness.js.map +1 -1
  640. package/dist/core/tools/orchestration-panel.d.ts +40 -0
  641. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  642. package/dist/core/tools/orchestration-panel.js +124 -0
  643. package/dist/core/tools/orchestration-panel.js.map +1 -0
  644. package/dist/core/tools/output-accumulator.d.ts +11 -0
  645. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  646. package/dist/core/tools/output-accumulator.js +36 -3
  647. package/dist/core/tools/output-accumulator.js.map +1 -1
  648. package/dist/core/tools/python.d.ts +2 -0
  649. package/dist/core/tools/python.d.ts.map +1 -1
  650. package/dist/core/tools/python.js +3 -1
  651. package/dist/core/tools/python.js.map +1 -1
  652. package/dist/core/tools/read.d.ts.map +1 -1
  653. package/dist/core/tools/read.js +1 -1
  654. package/dist/core/tools/read.js.map +1 -1
  655. package/dist/core/tools/run-process.d.ts +26 -0
  656. package/dist/core/tools/run-process.d.ts.map +1 -0
  657. package/dist/core/tools/run-process.js +138 -0
  658. package/dist/core/tools/run-process.js.map +1 -0
  659. package/dist/core/tools/search-command-guard.d.ts +14 -0
  660. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  661. package/dist/core/tools/search-command-guard.js +333 -0
  662. package/dist/core/tools/search-command-guard.js.map +1 -0
  663. package/dist/core/tools/secret-store.d.ts +38 -0
  664. package/dist/core/tools/secret-store.d.ts.map +1 -0
  665. package/dist/core/tools/secret-store.js +412 -0
  666. package/dist/core/tools/secret-store.js.map +1 -0
  667. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  668. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  669. package/dist/core/tools/shell-command-parser.js +113 -0
  670. package/dist/core/tools/shell-command-parser.js.map +1 -0
  671. package/dist/core/tools/task-steps.d.ts +2 -0
  672. package/dist/core/tools/task-steps.d.ts.map +1 -1
  673. package/dist/core/tools/task-steps.js +99 -0
  674. package/dist/core/tools/task-steps.js.map +1 -1
  675. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  676. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  677. package/dist/core/tools/tmux-dispatch.js +4 -4
  678. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  679. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  680. package/dist/core/tools/windows-shell-engine.js +4 -6
  681. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  682. package/dist/core/util/atomic-file.d.ts +6 -2
  683. package/dist/core/util/atomic-file.d.ts.map +1 -1
  684. package/dist/core/util/atomic-file.js +4 -4
  685. package/dist/core/util/atomic-file.js.map +1 -1
  686. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  687. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  688. package/dist/core/util/bounded-jsonl.js +75 -0
  689. package/dist/core/util/bounded-jsonl.js.map +1 -0
  690. package/dist/core/util/value-guards.d.ts +5 -0
  691. package/dist/core/util/value-guards.d.ts.map +1 -0
  692. package/dist/core/util/value-guards.js +12 -0
  693. package/dist/core/util/value-guards.js.map +1 -0
  694. package/dist/core/worktree-sync/store.d.ts +3 -3
  695. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  696. package/dist/core/worktree-sync/store.js +10 -5
  697. package/dist/core/worktree-sync/store.js.map +1 -1
  698. package/dist/index.d.ts +15 -4
  699. package/dist/index.d.ts.map +1 -1
  700. package/dist/index.js +14 -3
  701. package/dist/index.js.map +1 -1
  702. package/dist/main.d.ts.map +1 -1
  703. package/dist/main.js +149 -51
  704. package/dist/main.js.map +1 -1
  705. package/dist/migrations.d.ts +4 -6
  706. package/dist/migrations.d.ts.map +1 -1
  707. package/dist/migrations.js +186 -28
  708. package/dist/migrations.js.map +1 -1
  709. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  710. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  711. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  712. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  713. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  714. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  715. package/dist/modes/interactive/clipboard-input.js +44 -6
  716. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  717. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  718. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  719. package/dist/modes/interactive/components/activity-lane.js +304 -0
  720. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  721. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  722. package/dist/modes/interactive/components/assistant-message.js +19 -10
  723. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  724. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  725. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  726. package/dist/modes/interactive/components/expandable-text.js +17 -0
  727. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  728. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  729. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  730. package/dist/modes/interactive/components/extension-editor.js +30 -21
  731. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  732. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  733. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  734. package/dist/modes/interactive/components/extension-input.js +6 -1
  735. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  736. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  737. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  738. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  739. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  740. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  741. package/dist/modes/interactive/components/settings-selector.js +6 -6
  742. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  743. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  744. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  745. package/dist/modes/interactive/components/tool-execution.js +53 -20
  746. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  747. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  748. package/dist/modes/interactive/components/tool-group.js +3 -0
  749. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  750. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  751. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  752. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  753. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  754. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  755. package/dist/modes/interactive/config-backup.js +5 -4
  756. package/dist/modes/interactive/config-backup.js.map +1 -1
  757. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  758. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  759. package/dist/modes/interactive/extension-ui-host.js +77 -15
  760. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  761. package/dist/modes/interactive/external-editor.d.ts +15 -0
  762. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  763. package/dist/modes/interactive/external-editor.js +27 -19
  764. package/dist/modes/interactive/external-editor.js.map +1 -1
  765. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  766. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  767. package/dist/modes/interactive/history-reload-math.js +10 -5
  768. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  769. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  770. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  771. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  772. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  773. package/dist/modes/interactive/interactive-mode.d.ts +22 -24
  774. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  775. package/dist/modes/interactive/interactive-mode.js +245 -595
  776. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  777. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  778. package/dist/modes/interactive/key-handlers.js +1 -1
  779. package/dist/modes/interactive/key-handlers.js.map +1 -1
  780. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  781. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  782. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  783. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  784. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  785. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  786. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  787. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  788. package/dist/modes/interactive/report-commands.js +21 -0
  789. package/dist/modes/interactive/report-commands.js.map +1 -1
  790. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  791. package/dist/modes/interactive/resource-display.js +8 -2
  792. package/dist/modes/interactive/resource-display.js.map +1 -1
  793. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  794. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  795. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  796. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  797. package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
  798. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  799. package/dist/modes/interactive/session-flow-commands.js +150 -64
  800. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  801. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  802. package/dist/modes/interactive/session-io-commands.js +16 -6
  803. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  804. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  805. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  806. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  807. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  808. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  809. package/dist/modes/interactive/startup-checks.js +1 -1
  810. package/dist/modes/interactive/startup-checks.js.map +1 -1
  811. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  812. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  813. package/dist/modes/interactive/usage-commands.js +225 -0
  814. package/dist/modes/interactive/usage-commands.js.map +1 -0
  815. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  816. package/dist/modes/rpc/rpc-mode.js +82 -23
  817. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  818. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  819. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  820. package/dist/modes/rpc/rpc-types.js +138 -1
  821. package/dist/modes/rpc/rpc-types.js.map +1 -1
  822. package/dist/utils/clipboard-image.d.ts.map +1 -1
  823. package/dist/utils/clipboard-image.js +2 -13
  824. package/dist/utils/clipboard-image.js.map +1 -1
  825. package/dist/utils/clipboard-native.d.ts +1 -0
  826. package/dist/utils/clipboard-native.d.ts.map +1 -1
  827. package/dist/utils/clipboard-native.js.map +1 -1
  828. package/dist/utils/clipboard.d.ts +1 -0
  829. package/dist/utils/clipboard.d.ts.map +1 -1
  830. package/dist/utils/clipboard.js +52 -1
  831. package/dist/utils/clipboard.js.map +1 -1
  832. package/dist/utils/platform.d.ts +3 -0
  833. package/dist/utils/platform.d.ts.map +1 -0
  834. package/dist/utils/platform.js +8 -0
  835. package/dist/utils/platform.js.map +1 -0
  836. package/dist/utils/shell.d.ts.map +1 -1
  837. package/dist/utils/shell.js +5 -3
  838. package/dist/utils/shell.js.map +1 -1
  839. package/dist/utils/version-check.d.ts.map +1 -1
  840. package/dist/utils/version-check.js +3 -1
  841. package/dist/utils/version-check.js.map +1 -1
  842. package/dist/utils/work-directory.d.ts +11 -0
  843. package/dist/utils/work-directory.d.ts.map +1 -1
  844. package/dist/utils/work-directory.js +30 -9
  845. package/dist/utils/work-directory.js.map +1 -1
  846. package/docs/UI_POLISH_ORCHESTRATION.md +38 -0
  847. package/docs/UI_QUALITY_ORCHESTRATION.md +28 -0
  848. package/docs/docs.json +4 -0
  849. package/docs/extensions.md +62 -2
  850. package/docs/harness-architecture.md +156 -0
  851. package/docs/keybindings.md +11 -1
  852. package/docs/process-matrix.md +59 -26
  853. package/docs/providers.md +9 -1
  854. package/docs/rpc.md +45 -2
  855. package/docs/sessions.md +15 -0
  856. package/docs/settings.md +125 -11
  857. package/docs/task-steps.md +8 -0
  858. package/docs/telemetry.md +19 -0
  859. package/docs/tmux-agent-manager.md +10 -3
  860. package/docs/ui-reference/README.md +9 -0
  861. package/docs/ui-reference/orchestration-after.txt +14 -0
  862. package/docs/ui-reference/orchestration-before.txt +13 -0
  863. package/docs/ui-reference/orchestration-reference.txt +16 -0
  864. package/docs/usage.md +22 -2
  865. package/docs/work-directory.md +19 -8
  866. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  867. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  868. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  869. package/examples/extensions/question.ts +34 -245
  870. package/examples/extensions/questionnaire.ts +41 -407
  871. package/examples/extensions/sandbox/package-lock.json +2 -2
  872. package/examples/extensions/sandbox/package.json +1 -1
  873. package/examples/extensions/with-deps/package-lock.json +2 -2
  874. package/examples/extensions/with-deps/package.json +1 -1
  875. package/npm-shrinkwrap.json +13 -13
  876. package/package.json +4 -4
  877. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  878. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  879. package/dist/core/delegation/session-worker-result.js +0 -113
  880. package/dist/core/delegation/session-worker-result.js.map +0 -1
  881. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  882. package/dist/core/delegation/worker-result.js.map +0 -1
  883. package/dist/core/telemetry.d.ts.map +0 -1
  884. package/dist/core/telemetry.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"profile-registry.js","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type {\n\tModelRouterSettings,\n\tProfileDefinitionInput,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n\tSettings,\n} from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"external-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\tmodelRouter?: ModelRouterSettings;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ProfileDefinitionInput>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\n/** Name of the built-in, always-available profile that enables every discovered resource. */\nexport const ALL_ACTIVE_PROFILE_NAME = \"all-active\";\n\nfunction buildAllActiveResources(): ResourceProfileSettings {\n\tconst resources: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tresources[kind] = { allow: [\"*\"] };\n\t}\n\treturn resources;\n}\n\n/**\n * The built-in \"all-active\" profile. Registered as the weakest candidate in\n * `collectCandidates()` so any user-defined profile of the same name overrides it.\n */\nexport const ALL_ACTIVE_BUILTIN_PROFILE: NormalizedProfile = {\n\tname: ALL_ACTIVE_PROFILE_NAME,\n\tdescription: \"Everything on: all discovered extensions, skills, prompts, themes, agents, and tools\",\n\tresources: buildAllActiveResources(),\n\tsource: \"embedded\",\n};\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecord(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecord(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh, max, ultra`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeModelRouterSettings(value: unknown): ModelRouterSettings | undefined {\n\tif (!isRecord(value)) return undefined;\n\tconst settings: ModelRouterSettings = {};\n\tfor (const key of [\"enabled\", \"judgeEnabled\", \"fitnessGate\"] as const) {\n\t\tconst candidate = value[key];\n\t\tif (typeof candidate === \"boolean\") settings[key] = candidate;\n\t}\n\tfor (const key of [\n\t\t\"cheapModel\",\n\t\t\"mediumModel\",\n\t\t\"expensiveModel\",\n\t\t\"learningModel\",\n\t\t\"judgeModel\",\n\t\t\"executorModel\",\n\t] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (candidate) settings[key] = candidate;\n\t}\n\tfor (const key of [\n\t\t\"cheapThinking\",\n\t\t\"mediumThinking\",\n\t\t\"expensiveThinking\",\n\t\t\"executorThinking\",\n\t\t\"judgeThinking\",\n\t] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (!candidate) continue;\n\t\tif (!isValidThinkingLevel(candidate)) {\n\t\t\tthrow new Error(`${key} must be one of off, minimal, low, medium, high, xhigh, max, ultra`);\n\t\t}\n\t\tsettings[key] = candidate;\n\t}\n\treturn Object.keys(settings).length > 0 ? settings : undefined;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecord(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst modelRouter = normalizeModelRouterSettings(options.value.modelRouter);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tmodelRouter,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n\tbaseDir?: string,\n\tsourcePath?: string,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, definition] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tif (isRecord(definition) && Object.hasOwn(definition, \"resources\")) {\n\t\t\tprofiles.push(\n\t\t\t\tnormalizeWrapperProfile({\n\t\t\t\t\tvalue: { ...definition, name },\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tbaseDir,\n\t\t\t\t\tfallbackName: name,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tprofiles.push({\n\t\t\tname,\n\t\t\tresources: mergeResourceProfileSettings(undefined, definition as ResourceProfileSettings),\n\t\t\tsourcePath,\n\t\t\tbaseDir,\n\t\t});\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeInlineDefinitions(\n\tdefinitions: Record<string, ProfileDefinitionInput>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, definition] of Object.entries(definitions)) {\n\t\ttry {\n\t\t\tprofiles.push(\n\t\t\t\tnormalizeWrapperProfile({\n\t\t\t\t\tvalue: { ...definition, name },\n\t\t\t\t\tsource,\n\t\t\t\t\tfallbackName: name,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch {\n\t\t\t// Inline names/definitions are validated at the SettingsManager API boundary.\n\t\t}\n\t}\n\treturn profiles;\n}\n\nfunction loadSettingsFileProfiles(sourcePath: string, source: ProfileSource): NormalizedProfile[] {\n\ttry {\n\t\tconst stats = statSync(sourcePath);\n\t\tif (!stats.isFile()) return [];\n\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\")) as Settings;\n\t\treturn normalizeSettingsProfiles(parsed, source, dirname(resolve(sourcePath)), resolve(sourcePath)).map(\n\t\t\t(profile) => ({\n\t\t\t\t...profile,\n\t\t\t\tsource,\n\t\t\t}),\n\t\t);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeInlineDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of this.loadExternalSettingsProfiles()) {\n\t\t\tadd(profile, 4.2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\t\tadd(ALL_ACTIVE_BUILTIN_PROFILE, 7);\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadExternalSettingsProfiles(): NormalizedProfile[] {\n\t\tconst profiles: NormalizedProfile[] = [];\n\t\tfor (const root of this.options.externalResourceRoots ?? []) {\n\t\t\tprofiles.push(...loadSettingsFileProfiles(join(root, \"settings.json\"), \"external-settings\"));\n\t\t}\n\t\treturn profiles;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"profile-registry.js","sourceRoot":"","sources":["../../src/core/profile-registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAQ5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AA0CxD,MAAM,sBAAsB,GAA0B,CAAC,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAEvH,6FAA6F;AAC7F,MAAM,CAAC,MAAM,uBAAuB,GAAG,YAAY,CAAC;AAEpD,SAAS,uBAAuB,GAA4B;IAC3D,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,sBAAsB,EAAE,CAAC;QAC3C,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IAC5D,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,sFAAsF;IACnG,SAAS,EAAE,uBAAuB,EAAE;IACpC,MAAM,EAAE,UAAU;CAClB,CAAC;AAQF,SAAS,gBAAgB,CAAC,KAAc,EAAsB;IAC7D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACvF;AAED,SAAS,aAAa,CAAC,KAAc,EAAwB;IAC5D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3G,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAChD;AAED,SAAS,2BAA2B,CAAC,OAAe,EAAW;IAC9D,OAAO,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAAA,CAC7D;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAE,OAA2B,EAAU;IAC/E,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO,IAAI,CAAC,2BAA2B,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACtE,OAAO,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAAA,CACrD;AAED,SAAS,oBAAoB,CAAC,KAAc,EAAE,OAA2B,EAAwB;IAChG,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,CACpE;AAED,SAAS,gCAAgC,CAAC,KAAc,EAAE,OAA2B,EAA2B;IAC/G,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,sBAAsB,EAAE,CAAC;QAC3C,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,WAAW,KAAK,SAAS;YAAE,SAAS;QACxC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC/D,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,mBAAmB,CAAC,IAAY,EAAY;IACpD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AAAA,CAC/B;AAED,SAAS,iBAAiB,CAAC,KAAc,EAA6B;IACrE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,SAAS,4BAA4B,CAAC,KAAc,EAAmC;IACtF,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,aAAa,CAAU,EAAE,CAAC;QACvE,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,OAAO,SAAS,KAAK,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC/D,CAAC;IACD,KAAK,MAAM,GAAG,IAAI;QACjB,YAAY;QACZ,aAAa;QACb,gBAAgB;QAChB,eAAe;QACf,YAAY;QACZ,eAAe;KACN,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,IAAI,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC1C,CAAC;IACD,KAAK,MAAM,GAAG,IAAI;QACjB,eAAe;QACf,gBAAgB;QAChB,mBAAmB;QACnB,kBAAkB;QAClB,eAAe;KACN,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,oEAAoE,CAAC,CAAC;QAC7F,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAC/D;AAED,SAAS,uBAAuB,CAAC,OAMhC,EAAqB;IACrB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC;IAC1E,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,SAAS,GAAG,gCAAgC,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACnG,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,4BAA4B,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO;QACN,IAAI;QACJ,WAAW;QACX,KAAK;QACL,QAAQ;QACR,WAAW;QACX,IAAI;QACJ,SAAS;QACT,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;KACxB,CAAC;AAAA,CACF;AAED,SAAS,yBAAyB,CACjC,QAAkB,EAClB,MAAqB,EACrB,OAAgB,EAChB,UAAmB,EACqD;IACxE,MAAM,QAAQ,GAA0E,EAAE,CAAC;IAC3F,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,CAAC;QAClF,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACpC,IAAI,cAAc,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;YAC1E,QAAQ,CAAC,IAAI,CACZ,uBAAuB,CAAC;gBACvB,KAAK,EAAE,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE;gBAC9B,MAAM;gBACN,UAAU;gBACV,OAAO;gBACP,YAAY,EAAE,IAAI;aAClB,CAAC,CACF,CAAC;YACF,SAAS;QACV,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC;YACb,IAAI;YACJ,SAAS,EAAE,4BAA4B,CAAC,SAAS,EAAE,UAAqC,CAAC;YACzF,UAAU;YACV,OAAO;SACP,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,CAC3D;AAED,SAAS,0BAA0B,CAClC,WAAmD,EACnD,MAAqB,EACC;IACtB,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC;YACJ,QAAQ,CAAC,IAAI,CACZ,uBAAuB,CAAC;gBACvB,KAAK,EAAE,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE;gBAC9B,MAAM;gBACN,YAAY,EAAE,IAAI;aAClB,CAAC,CACF,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACR,8EAA8E;QAC/E,CAAC;IACF,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,SAAS,wBAAwB,CAAC,UAAkB,EAAE,MAAqB,EAAuB;IACjG,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAa,CAAC;QACzE,OAAO,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CACtG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACb,GAAG,OAAO;YACV,MAAM;SACN,CAAC,CACF,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,SAAS,oBAAoB,CAC5B,WAAoD,EACpD,MAAqB,EACC;IACtB,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7D,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,4BAA4B,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,MAAM,OAAO,eAAe;IACnB,OAAO,CAAyB;IAChC,WAAW,GAAgC,EAAE,CAAC;IAEtD,YAAY,OAA+B,EAAE;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAAA,CACvB;IAED,eAAe,GAAgC;QAC9C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;IAAA,CAC7B;IAED,YAAY,GAAwB;QACnC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;QACpD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACrD,IACC,CAAC,QAAQ;gBACT,SAAS,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU;gBAC1C,CAAC,SAAS,CAAC,UAAU,KAAK,QAAQ,CAAC,UAAU,IAAI,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,EACjF,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAChD,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;aACjC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;aAC5D,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAAA,CACxC;IAED,UAAU,CAAC,IAAY,EAAiC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAAA,CACvE;IAED,iBAAiB,CAAC,GAAW,EAAE,OAAe,EAAiC;QAC9E,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC;QACrE,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAAA,CAChC;IAEO,iBAAiB,GAAuB;QAC/C,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,MAAM,UAAU,GAAuB,EAAE,CAAC;QAC1C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,GAAG,GAAG,CAAC,OAA0B,EAAE,UAAkB,EAAQ,EAAE,CAAC;YACrE,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAAA,CACzD,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,gCAAgC,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC3G,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,EAAE,CAAC;YAC7G,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,kBAAkB,CAAC,EAAE,CAAC;YACnG,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;YAC/C,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,4BAA4B,EAAE,EAAE,CAAC;YAC3D,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,iBAAiB,CAAC,EAAE,CAAC;YACjG,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC;QACnD,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,oCAAoC,EAAE,UAAU,CAAC,EAAE,CAAC;YAC3G,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACjB,CAAC;QACD,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAEnC,OAAO,UAAU,CAAC;IAAA,CAClB;IAEO,gBAAgB,GAAuB;QAC9C,MAAM,UAAU,GAAuB,EAAE,CAAC;QAC1C,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;QAC7C,IAAI,WAAW,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC;qBACtC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;qBAC1C,IAAI,EAAE,CAAC;gBACT,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;oBAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;oBACzE,IAAI,MAAM,EAAE,CAAC;wBACZ,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC/C,CAAC;gBACF,CAAC;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9F,CAAC;QACF,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,IAAI,EAAE,CAAC;QAC/D,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YAClC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAC9C,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC;oBACJ,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC;yBACzC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;yBAC1C,IAAI,EAAE,CAAC;oBACT,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;wBAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;wBAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;wBACzE,IAAI,MAAM,EAAE,CAAC;4BACZ,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;wBACjD,CAAC;oBACF,CAAC;gBACF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACjG,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,UAAU,CAAC;IAAA,CAClB;IAEO,4BAA4B,GAAwB;QAC3D,MAAM,QAAQ,GAAwB,EAAE,CAAC;QACzC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,qBAAqB,IAAI,EAAE,EAAE,CAAC;YAC7D,QAAQ,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,QAAQ,CAAC;IAAA,CAChB;IAEO,eAAe,CAAC,UAAkB,EAAE,MAAqB,EAAE,KAAa,EAAgC;QAC/G,IAAI,CAAC;YACJ,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;gBAAE,OAAO,SAAS,CAAC;YACtC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;YAC7D,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACnD,OAAO;gBACN,OAAO,EAAE,uBAAuB,CAAC;oBAChC,KAAK,EAAE,MAAM;oBACb,MAAM;oBACN,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC;oBAC/B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBACrC,YAAY;iBACZ,CAAC;gBACF,UAAU,EAAE,CAAC;gBACb,KAAK;aACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7D,OAAO,SAAS,CAAC;QAClB,CAAC;IAAA,CACD;CACD","sourcesContent":["import type { ThinkingLevel } from \"@caupulican/pi-agent-core\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { isValidThinkingLevel } from \"../cli/args.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { mergeResourceProfileSettings } from \"./resource-profile-blocks.ts\";\nimport type {\n\tModelRouterSettings,\n\tProfileDefinitionInput,\n\tResourceProfileKind,\n\tResourceProfileSettings,\n\tSettings,\n} from \"./settings-manager.ts\";\nimport { validateSkillName } from \"./skills.ts\";\nimport { isRecordObject } from \"./util/value-guards.ts\";\n\nexport type ProfileSource =\n\t| \"global-settings\"\n\t| \"project-settings\"\n\t| \"external-settings\"\n\t| \"profile-file\"\n\t| \"directory-overlay\"\n\t| \"inline\"\n\t| \"embedded\"\n\t| \"bundle\";\n\nexport interface NormalizedProfile {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n\tmodelRouter?: ModelRouterSettings;\n\t/** Situational identity injected into the system prompt while this profile is active (R6). */\n\tsoul?: string;\n\tresources: ResourceProfileSettings;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n}\n\nexport interface ProfileRegistryDiagnostic {\n\tsource: ProfileSource;\n\tpath?: string;\n\tmessage: string;\n}\n\nexport interface ProfileRegistryOptions {\n\tglobalSettings: Settings;\n\tprojectSettings: Settings;\n\tdirectoryProfileSettings: Settings;\n\tinlineResourceProfileDefinitions: Record<string, ProfileDefinitionInput>;\n\tdiscoveredResourceProfileDefinitions: Record<string, ResourceProfileSettings>;\n\tprofilesDir?: string;\n\texternalResourceRoots?: string[];\n}\n\nconst RESOURCE_PROFILE_KINDS: ResourceProfileKind[] = [\"extensions\", \"skills\", \"prompts\", \"themes\", \"agents\", \"tools\"];\n\n/** Name of the built-in, always-available profile that enables every discovered resource. */\nexport const ALL_ACTIVE_PROFILE_NAME = \"all-active\";\n\nfunction buildAllActiveResources(): ResourceProfileSettings {\n\tconst resources: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tresources[kind] = { allow: [\"*\"] };\n\t}\n\treturn resources;\n}\n\n/**\n * The built-in \"all-active\" profile. Registered as the weakest candidate in\n * `collectCandidates()` so any user-defined profile of the same name overrides it.\n */\nexport const ALL_ACTIVE_BUILTIN_PROFILE: NormalizedProfile = {\n\tname: ALL_ACTIVE_PROFILE_NAME,\n\tdescription: \"Everything on: all discovered extensions, skills, prompts, themes, agents, and tools\",\n\tresources: buildAllActiveResources(),\n\tsource: \"embedded\",\n};\n\ninterface ProfileCandidate {\n\tprofile: NormalizedProfile;\n\tprecedence: number;\n\torder: number;\n}\n\nfunction asNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction asStringArray(value: unknown): string[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tconst strings = value.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0);\n\treturn strings.length > 0 ? strings : undefined;\n}\n\nfunction shouldResolveAgainstBaseDir(pattern: string): boolean {\n\treturn pattern.startsWith(\"./\") || pattern.startsWith(\"../\");\n}\n\nfunction normalizePattern(pattern: string, baseDir: string | undefined): string {\n\tconst trimmed = pattern.trim();\n\tif (!baseDir || !shouldResolveAgainstBaseDir(trimmed)) return trimmed;\n\treturn resolvePath(trimmed, baseDir, { trim: true });\n}\n\nfunction normalizeStringArray(value: unknown, baseDir: string | undefined): string[] | undefined {\n\tconst strings = asStringArray(value);\n\tif (!strings) return undefined;\n\treturn strings.map((pattern) => normalizePattern(pattern, baseDir));\n}\n\nfunction normalizeResourceProfileSettings(value: unknown, baseDir: string | undefined): ResourceProfileSettings {\n\tif (!isRecordObject(value)) {\n\t\tthrow new Error(\"resources must be an object\");\n\t}\n\tconst result: ResourceProfileSettings = {};\n\tfor (const kind of RESOURCE_PROFILE_KINDS) {\n\t\tconst filterValue = value[kind];\n\t\tif (filterValue === undefined) continue;\n\t\tif (!isRecordObject(filterValue)) {\n\t\t\tthrow new Error(`${kind} filter must be an object`);\n\t\t}\n\t\tconst allow = normalizeStringArray(filterValue.allow, baseDir);\n\t\tconst block = normalizeStringArray(filterValue.block, baseDir);\n\t\tresult[kind] = { allow, block };\n\t}\n\treturn result;\n}\n\nfunction validateProfileName(name: string): string[] {\n\treturn validateSkillName(name);\n}\n\nfunction normalizeThinking(value: unknown): ThinkingLevel | undefined {\n\tconst thinking = asNonEmptyString(value);\n\tif (!thinking) return undefined;\n\tif (!isValidThinkingLevel(thinking)) {\n\t\tthrow new Error(`thinking must be one of off, minimal, low, medium, high, xhigh, max, ultra`);\n\t}\n\treturn thinking;\n}\n\nfunction normalizeModelRouterSettings(value: unknown): ModelRouterSettings | undefined {\n\tif (!isRecordObject(value)) return undefined;\n\tconst settings: ModelRouterSettings = {};\n\tfor (const key of [\"enabled\", \"judgeEnabled\", \"fitnessGate\"] as const) {\n\t\tconst candidate = value[key];\n\t\tif (typeof candidate === \"boolean\") settings[key] = candidate;\n\t}\n\tfor (const key of [\n\t\t\"cheapModel\",\n\t\t\"mediumModel\",\n\t\t\"expensiveModel\",\n\t\t\"learningModel\",\n\t\t\"judgeModel\",\n\t\t\"executorModel\",\n\t] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (candidate) settings[key] = candidate;\n\t}\n\tfor (const key of [\n\t\t\"cheapThinking\",\n\t\t\"mediumThinking\",\n\t\t\"expensiveThinking\",\n\t\t\"executorThinking\",\n\t\t\"judgeThinking\",\n\t] as const) {\n\t\tconst candidate = asNonEmptyString(value[key]);\n\t\tif (!candidate) continue;\n\t\tif (!isValidThinkingLevel(candidate)) {\n\t\t\tthrow new Error(`${key} must be one of off, minimal, low, medium, high, xhigh, max, ultra`);\n\t\t}\n\t\tsettings[key] = candidate;\n\t}\n\treturn Object.keys(settings).length > 0 ? settings : undefined;\n}\n\nfunction normalizeWrapperProfile(options: {\n\tvalue: unknown;\n\tsource: ProfileSource;\n\tsourcePath?: string;\n\tbaseDir?: string;\n\tfallbackName?: string;\n}): NormalizedProfile {\n\tif (!isRecordObject(options.value)) {\n\t\tthrow new Error(\"profile JSON must be an object\");\n\t}\n\tconst name = asNonEmptyString(options.value.name) ?? options.fallbackName;\n\tif (!name) {\n\t\tthrow new Error(\"profile name is required\");\n\t}\n\tconst nameErrors = validateProfileName(name);\n\tif (nameErrors.length > 0) {\n\t\tthrow new Error(`invalid profile name \"${name}\": ${nameErrors.join(\", \")}`);\n\t}\n\tconst resources = normalizeResourceProfileSettings(options.value.resources ?? {}, options.baseDir);\n\tconst description = asNonEmptyString(options.value.description);\n\tconst model = asNonEmptyString(options.value.model);\n\tconst thinking = normalizeThinking(options.value.thinking);\n\tconst modelRouter = normalizeModelRouterSettings(options.value.modelRouter);\n\tconst soul = asNonEmptyString(options.value.soul);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\tmodel,\n\t\tthinking,\n\t\tmodelRouter,\n\t\tsoul,\n\t\tresources,\n\t\tsource: options.source,\n\t\tsourcePath: options.sourcePath,\n\t\tbaseDir: options.baseDir,\n\t};\n}\n\nfunction normalizeSettingsProfiles(\n\tsettings: Settings,\n\tsource: ProfileSource,\n\tbaseDir?: string,\n\tsourcePath?: string,\n): Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> {\n\tconst profiles: Array<Omit<NormalizedProfile, \"source\"> & { source?: ProfileSource }> = [];\n\tfor (const [name, definition] of Object.entries(settings.resourceProfiles ?? {})) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tif (isRecordObject(definition) && Object.hasOwn(definition, \"resources\")) {\n\t\t\tprofiles.push(\n\t\t\t\tnormalizeWrapperProfile({\n\t\t\t\t\tvalue: { ...definition, name },\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath,\n\t\t\t\t\tbaseDir,\n\t\t\t\t\tfallbackName: name,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tprofiles.push({\n\t\t\tname,\n\t\t\tresources: mergeResourceProfileSettings(undefined, definition as ResourceProfileSettings),\n\t\t\tsourcePath,\n\t\t\tbaseDir,\n\t\t});\n\t}\n\treturn profiles.map((profile) => ({ ...profile, source }));\n}\n\nfunction normalizeInlineDefinitions(\n\tdefinitions: Record<string, ProfileDefinitionInput>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, definition] of Object.entries(definitions)) {\n\t\ttry {\n\t\t\tprofiles.push(\n\t\t\t\tnormalizeWrapperProfile({\n\t\t\t\t\tvalue: { ...definition, name },\n\t\t\t\t\tsource,\n\t\t\t\t\tfallbackName: name,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch {\n\t\t\t// Inline names/definitions are validated at the SettingsManager API boundary.\n\t\t}\n\t}\n\treturn profiles;\n}\n\nfunction loadSettingsFileProfiles(sourcePath: string, source: ProfileSource): NormalizedProfile[] {\n\ttry {\n\t\tconst stats = statSync(sourcePath);\n\t\tif (!stats.isFile()) return [];\n\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\")) as Settings;\n\t\treturn normalizeSettingsProfiles(parsed, source, dirname(resolve(sourcePath)), resolve(sourcePath)).map(\n\t\t\t(profile) => ({\n\t\t\t\t...profile,\n\t\t\t\tsource,\n\t\t\t}),\n\t\t);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction normalizeDefinitions(\n\tdefinitions: Record<string, ResourceProfileSettings>,\n\tsource: ProfileSource,\n): NormalizedProfile[] {\n\tconst profiles: NormalizedProfile[] = [];\n\tfor (const [name, resources] of Object.entries(definitions)) {\n\t\tconst nameErrors = validateProfileName(name);\n\t\tif (nameErrors.length > 0) continue;\n\t\tprofiles.push({ name, resources: mergeResourceProfileSettings(undefined, resources), source });\n\t}\n\treturn profiles;\n}\n\nexport class ProfileRegistry {\n\tprivate options: ProfileRegistryOptions;\n\tprivate diagnostics: ProfileRegistryDiagnostic[] = [];\n\n\tconstructor(options: ProfileRegistryOptions) {\n\t\tthis.options = options;\n\t}\n\n\tlistDiagnostics(): ProfileRegistryDiagnostic[] {\n\t\tthis.collectCandidates();\n\t\treturn [...this.diagnostics];\n\t}\n\n\tlistProfiles(): NormalizedProfile[] {\n\t\tconst candidates = this.collectCandidates();\n\t\tconst winners = new Map<string, ProfileCandidate>();\n\t\tfor (const candidate of candidates) {\n\t\t\tconst existing = winners.get(candidate.profile.name);\n\t\t\tif (\n\t\t\t\t!existing ||\n\t\t\t\tcandidate.precedence < existing.precedence ||\n\t\t\t\t(candidate.precedence === existing.precedence && candidate.order < existing.order)\n\t\t\t) {\n\t\t\t\twinners.set(candidate.profile.name, candidate);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(winners.values())\n\t\t\t.sort((a, b) => a.profile.name.localeCompare(b.profile.name))\n\t\t\t.map((candidate) => candidate.profile);\n\t}\n\n\tgetProfile(name: string): NormalizedProfile | undefined {\n\t\tconst trimmed = name.trim();\n\t\tif (!trimmed) return undefined;\n\t\treturn this.listProfiles().find((profile) => profile.name === trimmed);\n\t}\n\n\tresolveProfileRef(ref: string, fromDir: string): NormalizedProfile | undefined {\n\t\tconst trimmed = ref.trim();\n\t\tif (!trimmed) return undefined;\n\t\tif (trimmed.startsWith(\"./\") || trimmed.startsWith(\"../\")) {\n\t\t\tconst sourcePath = resolvePath(trimmed, fromDir, { trim: true });\n\t\t\treturn this.loadProfileFile(sourcePath, \"profile-file\", 0)?.profile;\n\t\t}\n\t\treturn this.getProfile(trimmed);\n\t}\n\n\tprivate collectCandidates(): ProfileCandidate[] {\n\t\tthis.diagnostics = [];\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\t\tconst add = (profile: NormalizedProfile, precedence: number): void => {\n\t\t\tcandidates.push({ profile, precedence, order: order++ });\n\t\t};\n\n\t\tfor (const profile of normalizeInlineDefinitions(this.options.inlineResourceProfileDefinitions, \"inline\")) {\n\t\t\tadd(profile, 1);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.directoryProfileSettings, \"directory-overlay\")) {\n\t\t\tadd({ ...profile, source: \"directory-overlay\" }, 2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.projectSettings, \"project-settings\")) {\n\t\t\tadd({ ...profile, source: \"project-settings\" }, 3);\n\t\t}\n\t\tfor (const profile of this.loadProfileFiles()) {\n\t\t\tadd(profile.profile, profile.precedence);\n\t\t}\n\t\tfor (const profile of this.loadExternalSettingsProfiles()) {\n\t\t\tadd(profile, 4.2);\n\t\t}\n\t\tfor (const profile of normalizeSettingsProfiles(this.options.globalSettings, \"global-settings\")) {\n\t\t\tadd({ ...profile, source: \"global-settings\" }, 5);\n\t\t}\n\t\tfor (const profile of normalizeDefinitions(this.options.discoveredResourceProfileDefinitions, \"embedded\")) {\n\t\t\tadd(profile, 6);\n\t\t}\n\t\tadd(ALL_ACTIVE_BUILTIN_PROFILE, 7);\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadProfileFiles(): ProfileCandidate[] {\n\t\tconst candidates: ProfileCandidate[] = [];\n\t\tlet order = 0;\n\n\t\tconst profilesDir = this.options.profilesDir;\n\t\tif (profilesDir && existsSync(profilesDir)) {\n\t\t\ttry {\n\t\t\t\tconst entries = readdirSync(profilesDir)\n\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t.sort();\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tconst sourcePath = join(profilesDir, entry);\n\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4 });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: profilesDir, message: String(error) });\n\t\t\t}\n\t\t}\n\n\t\tconst externalRoots = this.options.externalResourceRoots ?? [];\n\t\tfor (const root of externalRoots) {\n\t\t\tconst extProfilesDir = join(root, \"profiles\");\n\t\t\tif (existsSync(extProfilesDir)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst entries = readdirSync(extProfilesDir)\n\t\t\t\t\t\t.filter((entry) => entry.endsWith(\".json\"))\n\t\t\t\t\t\t.sort();\n\t\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\t\tconst sourcePath = join(extProfilesDir, entry);\n\t\t\t\t\t\tconst loaded = this.loadProfileFile(sourcePath, \"profile-file\", order++);\n\t\t\t\t\t\tif (loaded) {\n\t\t\t\t\t\t\tcandidates.push({ ...loaded, precedence: 4.1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.diagnostics.push({ source: \"profile-file\", path: extProfilesDir, message: String(error) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates;\n\t}\n\n\tprivate loadExternalSettingsProfiles(): NormalizedProfile[] {\n\t\tconst profiles: NormalizedProfile[] = [];\n\t\tfor (const root of this.options.externalResourceRoots ?? []) {\n\t\t\tprofiles.push(...loadSettingsFileProfiles(join(root, \"settings.json\"), \"external-settings\"));\n\t\t}\n\t\treturn profiles;\n\t}\n\n\tprivate loadProfileFile(sourcePath: string, source: ProfileSource, order: number): ProfileCandidate | undefined {\n\t\ttry {\n\t\t\tconst stats = statSync(sourcePath);\n\t\t\tif (!stats.isFile()) return undefined;\n\t\t\tconst parsed = JSON.parse(readFileSync(sourcePath, \"utf-8\"));\n\t\t\tconst fallbackName = basename(sourcePath, \".json\");\n\t\t\treturn {\n\t\t\t\tprofile: normalizeWrapperProfile({\n\t\t\t\t\tvalue: parsed,\n\t\t\t\t\tsource,\n\t\t\t\t\tsourcePath: resolve(sourcePath),\n\t\t\t\t\tbaseDir: dirname(resolve(sourcePath)),\n\t\t\t\t\tfallbackName,\n\t\t\t\t}),\n\t\t\t\tprecedence: 0,\n\t\t\t\torder,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.diagnostics.push({ source, path: sourcePath, message });\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
@@ -21,6 +21,7 @@ export declare function parseCommandArgs(argsString: string): string[];
21
21
  * - $1, $2, ... for positional args
22
22
  * - $@ and $ARGUMENTS for all parsed args joined with spaces
23
23
  * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name
24
+ * - ${N:-default}, ${@:-default}, and ${ARGUMENTS:-default} for fallback values
24
25
  * - ${@:N} for args from Nth onwards (bash-style slicing)
25
26
  * - ${@:N:L} for L args starting from Nth
26
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-templates.d.ts","sourceRoot":"","sources":["../../src/core/prompt-templates.ts"],"names":[],"mappings":"AAMA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CA+B7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAwCxF;AAoFD,MAAM,WAAW,0BAA0B;IAC1C,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0CAA0C;IAC1C,eAAe,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,cAAc,EAAE,CAyEzF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,CAgBtF","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\n/**\n * Represents a prompt template loaded from a markdown file\n */\nexport interface PromptTemplate {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n\tcontent: string;\n\tsourceInfo: SourceInfo;\n\tfilePath: string; // Absolute path to the template file\n}\n\n/**\n * Parse command arguments respecting quoted strings (bash-style)\n * Returns array of arguments\n */\nexport function parseCommandArgs(argsString: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet inQuote: string | null = null;\n\n\tfor (let i = 0; i < argsString.length; i++) {\n\t\tconst char = argsString[i];\n\n\t\tif (inQuote) {\n\t\t\tif (char === inQuote) {\n\t\t\t\tinQuote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t} else if (char === '\"' || char === \"'\") {\n\t\t\tinQuote = char;\n\t\t} else if (/\\s/.test(char)) {\n\t\t\tif (current) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += char;\n\t\t}\n\t}\n\n\tif (current) {\n\t\targs.push(current);\n\t}\n\n\treturn args;\n}\n\n/**\n * Substitute argument placeholders in template content\n * Supports:\n * - $1, $2, ... for positional args\n * - $@ and $ARGUMENTS for all parsed args joined with spaces\n * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name\n * - ${@:N} for args from Nth onwards (bash-style slicing)\n * - ${@:N:L} for L args starting from Nth\n *\n * Note: Replacement happens on the template string only. Argument values\n * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.\n */\nexport function substituteArgs(content: string, args: string[], rawArgs?: string): string {\n\tlet result = content;\n\n\t// Replace $1, $2, etc. with positional args FIRST (before wildcards)\n\t// This prevents wildcard replacement values containing $<digit> patterns from being re-substituted\n\tresult = result.replace(/\\$(\\d+)/g, (_, num) => {\n\t\tconst index = parseInt(num, 10) - 1;\n\t\treturn args[index] ?? \"\";\n\t});\n\n\t// Replace ${@:start} or ${@:start:length} with sliced args (bash-style)\n\t// Process BEFORE simple $@ to avoid conflicts\n\tresult = result.replace(/\\$\\{@:(\\d+)(?::(\\d+))?\\}/g, (_, startStr, lengthStr) => {\n\t\tlet start = parseInt(startStr, 10) - 1; // Convert to 0-indexed (user provides 1-indexed)\n\t\t// Treat 0 as 1 (bash convention: args start at 1)\n\t\tif (start < 0) start = 0;\n\n\t\tif (lengthStr) {\n\t\t\tconst length = parseInt(lengthStr, 10);\n\t\t\treturn args.slice(start, start + length).join(\" \");\n\t\t}\n\t\treturn args.slice(start).join(\" \");\n\t});\n\n\t// Pre-compute all args joined (optimization)\n\tconst allArgs = args.join(\" \");\n\n\tconst rawArgumentText = rawArgs ?? allArgs;\n\n\t// Replace raw-argument aliases before $ARGUMENTS so the shared prefix does not partially match.\n\tresult = result.replace(/\\$ARGUMENTS_RAW/g, rawArgumentText);\n\tresult = result.replace(/\\$RAW_ARGUMENTS/g, rawArgumentText);\n\n\t// Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)\n\tresult = result.replace(/\\$ARGUMENTS/g, allArgs);\n\n\t// Replace $@ with all args joined (existing syntax)\n\tresult = result.replace(/\\$@/g, allArgs);\n\n\treturn result;\n}\n\nfunction loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, body: rawBody } = parseFrontmatter<Record<string, string>>(rawContent);\n\t\tconst body = stripResourceProfileBlocks(rawBody);\n\n\t\tconst name = basename(filePath).replace(/\\.md$/, \"\");\n\n\t\t// Get description from frontmatter or first non-empty line\n\t\tlet description = frontmatter.description || \"\";\n\t\tif (!description) {\n\t\t\tconst firstLine = body.split(\"\\n\").find((line) => line.trim());\n\t\t\tif (firstLine) {\n\t\t\t\t// Truncate if too long\n\t\t\t\tdescription = firstLine.slice(0, 60);\n\t\t\t\tif (firstLine.length > 60) description += \"...\";\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription,\n\t\t\t...(frontmatter[\"argument-hint\"] && { argumentHint: frontmatter[\"argument-hint\"] }),\n\t\t\tcontent: body,\n\t\t\tsourceInfo,\n\t\t\tfilePath,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Scan a directory for .md files (non-recursive) and load them as prompt templates.\n */\nfunction loadTemplatesFromDir(\n\tdir: string,\n\tgetSourceInfo: (filePath: string) => SourceInfo,\n\tisPathAllowed?: (path: string) => boolean,\n): PromptTemplate[] {\n\tconst templates: PromptTemplate[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn templates;\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\t// For symlinks, check if they point to a file\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\t// Broken symlink, skip it\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isFile && entry.name.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (isPathAllowed && !isPathAllowed(fullPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(fullPath, getSourceInfo(fullPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn templates;\n\t}\n\n\treturn templates;\n}\n\nexport interface LoadPromptTemplatesOptions {\n\t/** Working directory for project-local templates. */\n\tcwd: string;\n\t/** Agent config directory for global templates. */\n\tagentDir: string;\n\t/** Explicit prompt template paths (files or directories). */\n\tpromptPaths: string[];\n\t/** Include default prompt directories. */\n\tincludeDefaults: boolean;\n\t/** Profile UAC gate: when provided, files it denies are never read from disk. */\n\tisPathAllowed?: (path: string) => boolean;\n}\n\n/**\n * Load all prompt templates from:\n * 1. Global: agentDir/prompts/\n * 2. Project: cwd/{CONFIG_DIR_NAME}/prompts/\n * 3. Explicit prompt paths\n */\nexport function loadPromptTemplates(options: LoadPromptTemplatesOptions): PromptTemplate[] {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\tconst promptPaths = options.promptPaths;\n\tconst includeDefaults = options.includeDefaults;\n\n\tconst templates: PromptTemplate[] = [];\n\n\tconst globalPromptsDir = join(resolvedAgentDir, \"prompts\");\n\tconst projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, \"prompts\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSourceInfo = (resolvedPath: string): SourceInfo => {\n\t\tif (isUnderPath(resolvedPath, globalPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"user\",\n\t\t\t\tbaseDir: globalPromptsDir,\n\t\t\t});\n\t\t}\n\t\tif (isUnderPath(resolvedPath, projectPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"project\",\n\t\t\t\tbaseDir: projectPromptsDir,\n\t\t\t});\n\t\t}\n\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\tsource: \"local\",\n\t\t\tbaseDir: statSync(resolvedPath).isDirectory() ? resolvedPath : dirname(resolvedPath),\n\t\t});\n\t};\n\n\tif (includeDefaults) {\n\t\ttemplates.push(...loadTemplatesFromDir(globalPromptsDir, getSourceInfo, options.isPathAllowed));\n\t\ttemplates.push(...loadTemplatesFromDir(projectPromptsDir, getSourceInfo, options.isPathAllowed));\n\t}\n\n\t// 3. Load explicit prompt paths\n\tfor (const rawPath of promptPaths) {\n\t\tconst resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\ttemplates.push(...loadTemplatesFromDir(resolvedPath, getSourceInfo, options.isPathAllowed));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (options.isPathAllowed && !options.isPathAllowed(resolvedPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(resolvedPath, getSourceInfo(resolvedPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read failures\n\t\t}\n\t}\n\n\treturn templates;\n}\n\n/**\n * Expand a prompt template if it matches a template name.\n * Returns the expanded content or the original text if not a template.\n */\nexport function expandPromptTemplate(text: string, templates: PromptTemplate[]): string {\n\tif (!text.startsWith(\"/\")) return text;\n\n\tconst match = text.match(/^\\/([^\\s]+)(?:\\s+([\\s\\S]*))?$/);\n\tif (!match) return text;\n\n\tconst templateName = match[1];\n\tconst argsString = match[2] ?? \"\";\n\n\tconst template = templates.find((t) => t.name === templateName);\n\tif (template) {\n\t\tconst args = parseCommandArgs(argsString);\n\t\treturn substituteArgs(template.content, args, argsString);\n\t}\n\n\treturn text;\n}\n"]}
1
+ {"version":3,"file":"prompt-templates.d.ts","sourceRoot":"","sources":["../../src/core/prompt-templates.ts"],"names":[],"mappings":"AAMA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CA+B7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAyBxF;AAoFD,MAAM,WAAW,0BAA0B;IAC1C,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0CAA0C;IAC1C,eAAe,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,cAAc,EAAE,CAyEzF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,CAgBtF","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\n/**\n * Represents a prompt template loaded from a markdown file\n */\nexport interface PromptTemplate {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n\tcontent: string;\n\tsourceInfo: SourceInfo;\n\tfilePath: string; // Absolute path to the template file\n}\n\n/**\n * Parse command arguments respecting quoted strings (bash-style)\n * Returns array of arguments\n */\nexport function parseCommandArgs(argsString: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet inQuote: string | null = null;\n\n\tfor (let i = 0; i < argsString.length; i++) {\n\t\tconst char = argsString[i];\n\n\t\tif (inQuote) {\n\t\t\tif (char === inQuote) {\n\t\t\t\tinQuote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t} else if (char === '\"' || char === \"'\") {\n\t\t\tinQuote = char;\n\t\t} else if (/\\s/.test(char)) {\n\t\t\tif (current) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += char;\n\t\t}\n\t}\n\n\tif (current) {\n\t\targs.push(current);\n\t}\n\n\treturn args;\n}\n\n/**\n * Substitute argument placeholders in template content\n * Supports:\n * - $1, $2, ... for positional args\n * - $@ and $ARGUMENTS for all parsed args joined with spaces\n * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name\n * - ${N:-default}, ${@:-default}, and ${ARGUMENTS:-default} for fallback values\n * - ${@:N} for args from Nth onwards (bash-style slicing)\n * - ${@:N:L} for L args starting from Nth\n *\n * Note: Replacement happens on the template string only. Argument values\n * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.\n */\nexport function substituteArgs(content: string, args: string[], rawArgs?: string): string {\n\tconst allArgs = args.join(\" \");\n\tconst rawArgumentText = rawArgs ?? allArgs;\n\n\treturn content.replace(\n\t\t/\\$\\{(\\d+|ARGUMENTS|@):-([^}]*)\\}|\\$\\{@:(\\d+)(?::(\\d+))?\\}|\\$(ARGUMENTS_RAW|RAW_ARGUMENTS|ARGUMENTS|@|\\d+)/g,\n\t\t(_match, defaultTarget, defaultValue, sliceStart, sliceLength, simple) => {\n\t\t\tif (defaultTarget) {\n\t\t\t\tconst value =\n\t\t\t\t\tdefaultTarget === \"@\" || defaultTarget === \"ARGUMENTS\" ? allArgs : args[parseInt(defaultTarget, 10) - 1];\n\t\t\t\treturn value || defaultValue;\n\t\t\t}\n\n\t\t\tif (sliceStart) {\n\t\t\t\tconst start = Math.max(0, parseInt(sliceStart, 10) - 1);\n\t\t\t\treturn sliceLength\n\t\t\t\t\t? args.slice(start, start + parseInt(sliceLength, 10)).join(\" \")\n\t\t\t\t\t: args.slice(start).join(\" \");\n\t\t\t}\n\n\t\t\tif (simple === \"ARGUMENTS_RAW\" || simple === \"RAW_ARGUMENTS\") return rawArgumentText;\n\t\t\tif (simple === \"ARGUMENTS\" || simple === \"@\") return allArgs;\n\t\t\treturn args[parseInt(simple, 10) - 1] ?? \"\";\n\t\t},\n\t);\n}\n\nfunction loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, body: rawBody } = parseFrontmatter<Record<string, string>>(rawContent);\n\t\tconst body = stripResourceProfileBlocks(rawBody);\n\n\t\tconst name = basename(filePath).replace(/\\.md$/, \"\");\n\n\t\t// Get description from frontmatter or first non-empty line\n\t\tlet description = frontmatter.description || \"\";\n\t\tif (!description) {\n\t\t\tconst firstLine = body.split(\"\\n\").find((line) => line.trim());\n\t\t\tif (firstLine) {\n\t\t\t\t// Truncate if too long\n\t\t\t\tdescription = firstLine.slice(0, 60);\n\t\t\t\tif (firstLine.length > 60) description += \"...\";\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription,\n\t\t\t...(frontmatter[\"argument-hint\"] && { argumentHint: frontmatter[\"argument-hint\"] }),\n\t\t\tcontent: body,\n\t\t\tsourceInfo,\n\t\t\tfilePath,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Scan a directory for .md files (non-recursive) and load them as prompt templates.\n */\nfunction loadTemplatesFromDir(\n\tdir: string,\n\tgetSourceInfo: (filePath: string) => SourceInfo,\n\tisPathAllowed?: (path: string) => boolean,\n): PromptTemplate[] {\n\tconst templates: PromptTemplate[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn templates;\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\t// For symlinks, check if they point to a file\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\t// Broken symlink, skip it\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isFile && entry.name.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (isPathAllowed && !isPathAllowed(fullPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(fullPath, getSourceInfo(fullPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn templates;\n\t}\n\n\treturn templates;\n}\n\nexport interface LoadPromptTemplatesOptions {\n\t/** Working directory for project-local templates. */\n\tcwd: string;\n\t/** Agent config directory for global templates. */\n\tagentDir: string;\n\t/** Explicit prompt template paths (files or directories). */\n\tpromptPaths: string[];\n\t/** Include default prompt directories. */\n\tincludeDefaults: boolean;\n\t/** Profile UAC gate: when provided, files it denies are never read from disk. */\n\tisPathAllowed?: (path: string) => boolean;\n}\n\n/**\n * Load all prompt templates from:\n * 1. Global: agentDir/prompts/\n * 2. Project: cwd/{CONFIG_DIR_NAME}/prompts/\n * 3. Explicit prompt paths\n */\nexport function loadPromptTemplates(options: LoadPromptTemplatesOptions): PromptTemplate[] {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\tconst promptPaths = options.promptPaths;\n\tconst includeDefaults = options.includeDefaults;\n\n\tconst templates: PromptTemplate[] = [];\n\n\tconst globalPromptsDir = join(resolvedAgentDir, \"prompts\");\n\tconst projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, \"prompts\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSourceInfo = (resolvedPath: string): SourceInfo => {\n\t\tif (isUnderPath(resolvedPath, globalPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"user\",\n\t\t\t\tbaseDir: globalPromptsDir,\n\t\t\t});\n\t\t}\n\t\tif (isUnderPath(resolvedPath, projectPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"project\",\n\t\t\t\tbaseDir: projectPromptsDir,\n\t\t\t});\n\t\t}\n\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\tsource: \"local\",\n\t\t\tbaseDir: statSync(resolvedPath).isDirectory() ? resolvedPath : dirname(resolvedPath),\n\t\t});\n\t};\n\n\tif (includeDefaults) {\n\t\ttemplates.push(...loadTemplatesFromDir(globalPromptsDir, getSourceInfo, options.isPathAllowed));\n\t\ttemplates.push(...loadTemplatesFromDir(projectPromptsDir, getSourceInfo, options.isPathAllowed));\n\t}\n\n\t// 3. Load explicit prompt paths\n\tfor (const rawPath of promptPaths) {\n\t\tconst resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\ttemplates.push(...loadTemplatesFromDir(resolvedPath, getSourceInfo, options.isPathAllowed));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (options.isPathAllowed && !options.isPathAllowed(resolvedPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(resolvedPath, getSourceInfo(resolvedPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read failures\n\t\t}\n\t}\n\n\treturn templates;\n}\n\n/**\n * Expand a prompt template if it matches a template name.\n * Returns the expanded content or the original text if not a template.\n */\nexport function expandPromptTemplate(text: string, templates: PromptTemplate[]): string {\n\tif (!text.startsWith(\"/\")) return text;\n\n\tconst match = text.match(/^\\/([^\\s]+)(?:\\s+([\\s\\S]*))?$/);\n\tif (!match) return text;\n\n\tconst templateName = match[1];\n\tconst argsString = match[2] ?? \"\";\n\n\tconst template = templates.find((t) => t.name === templateName);\n\tif (template) {\n\t\tconst args = parseCommandArgs(argsString);\n\t\treturn substituteArgs(template.content, args, argsString);\n\t}\n\n\treturn text;\n}\n"]}
@@ -47,6 +47,7 @@ export function parseCommandArgs(argsString) {
47
47
  * - $1, $2, ... for positional args
48
48
  * - $@ and $ARGUMENTS for all parsed args joined with spaces
49
49
  * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name
50
+ * - ${N:-default}, ${@:-default}, and ${ARGUMENTS:-default} for fallback values
50
51
  * - ${@:N} for args from Nth onwards (bash-style slicing)
51
52
  * - ${@:N:L} for L args starting from Nth
52
53
  *
@@ -54,37 +55,25 @@ export function parseCommandArgs(argsString) {
54
55
  * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.
55
56
  */
56
57
  export function substituteArgs(content, args, rawArgs) {
57
- let result = content;
58
- // Replace $1, $2, etc. with positional args FIRST (before wildcards)
59
- // This prevents wildcard replacement values containing $<digit> patterns from being re-substituted
60
- result = result.replace(/\$(\d+)/g, (_, num) => {
61
- const index = parseInt(num, 10) - 1;
62
- return args[index] ?? "";
63
- });
64
- // Replace ${@:start} or ${@:start:length} with sliced args (bash-style)
65
- // Process BEFORE simple $@ to avoid conflicts
66
- result = result.replace(/\$\{@:(\d+)(?::(\d+))?\}/g, (_, startStr, lengthStr) => {
67
- let start = parseInt(startStr, 10) - 1; // Convert to 0-indexed (user provides 1-indexed)
68
- // Treat 0 as 1 (bash convention: args start at 1)
69
- if (start < 0)
70
- start = 0;
71
- if (lengthStr) {
72
- const length = parseInt(lengthStr, 10);
73
- return args.slice(start, start + length).join(" ");
74
- }
75
- return args.slice(start).join(" ");
76
- });
77
- // Pre-compute all args joined (optimization)
78
58
  const allArgs = args.join(" ");
79
59
  const rawArgumentText = rawArgs ?? allArgs;
80
- // Replace raw-argument aliases before $ARGUMENTS so the shared prefix does not partially match.
81
- result = result.replace(/\$ARGUMENTS_RAW/g, rawArgumentText);
82
- result = result.replace(/\$RAW_ARGUMENTS/g, rawArgumentText);
83
- // Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)
84
- result = result.replace(/\$ARGUMENTS/g, allArgs);
85
- // Replace $@ with all args joined (existing syntax)
86
- result = result.replace(/\$@/g, allArgs);
87
- return result;
60
+ return content.replace(/\$\{(\d+|ARGUMENTS|@):-([^}]*)\}|\$\{@:(\d+)(?::(\d+))?\}|\$(ARGUMENTS_RAW|RAW_ARGUMENTS|ARGUMENTS|@|\d+)/g, (_match, defaultTarget, defaultValue, sliceStart, sliceLength, simple) => {
61
+ if (defaultTarget) {
62
+ const value = defaultTarget === "@" || defaultTarget === "ARGUMENTS" ? allArgs : args[parseInt(defaultTarget, 10) - 1];
63
+ return value || defaultValue;
64
+ }
65
+ if (sliceStart) {
66
+ const start = Math.max(0, parseInt(sliceStart, 10) - 1);
67
+ return sliceLength
68
+ ? args.slice(start, start + parseInt(sliceLength, 10)).join(" ")
69
+ : args.slice(start).join(" ");
70
+ }
71
+ if (simple === "ARGUMENTS_RAW" || simple === "RAW_ARGUMENTS")
72
+ return rawArgumentText;
73
+ if (simple === "ARGUMENTS" || simple === "@")
74
+ return allArgs;
75
+ return args[parseInt(simple, 10) - 1] ?? "";
76
+ });
88
77
  }
89
78
  function loadTemplateFromFile(filePath, sourceInfo) {
90
79
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-templates.js","sourceRoot":"","sources":["../../src/core/prompt-templates.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\n/**\n * Represents a prompt template loaded from a markdown file\n */\nexport interface PromptTemplate {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n\tcontent: string;\n\tsourceInfo: SourceInfo;\n\tfilePath: string; // Absolute path to the template file\n}\n\n/**\n * Parse command arguments respecting quoted strings (bash-style)\n * Returns array of arguments\n */\nexport function parseCommandArgs(argsString: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet inQuote: string | null = null;\n\n\tfor (let i = 0; i < argsString.length; i++) {\n\t\tconst char = argsString[i];\n\n\t\tif (inQuote) {\n\t\t\tif (char === inQuote) {\n\t\t\t\tinQuote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t} else if (char === '\"' || char === \"'\") {\n\t\t\tinQuote = char;\n\t\t} else if (/\\s/.test(char)) {\n\t\t\tif (current) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += char;\n\t\t}\n\t}\n\n\tif (current) {\n\t\targs.push(current);\n\t}\n\n\treturn args;\n}\n\n/**\n * Substitute argument placeholders in template content\n * Supports:\n * - $1, $2, ... for positional args\n * - $@ and $ARGUMENTS for all parsed args joined with spaces\n * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name\n * - ${@:N} for args from Nth onwards (bash-style slicing)\n * - ${@:N:L} for L args starting from Nth\n *\n * Note: Replacement happens on the template string only. Argument values\n * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.\n */\nexport function substituteArgs(content: string, args: string[], rawArgs?: string): string {\n\tlet result = content;\n\n\t// Replace $1, $2, etc. with positional args FIRST (before wildcards)\n\t// This prevents wildcard replacement values containing $<digit> patterns from being re-substituted\n\tresult = result.replace(/\\$(\\d+)/g, (_, num) => {\n\t\tconst index = parseInt(num, 10) - 1;\n\t\treturn args[index] ?? \"\";\n\t});\n\n\t// Replace ${@:start} or ${@:start:length} with sliced args (bash-style)\n\t// Process BEFORE simple $@ to avoid conflicts\n\tresult = result.replace(/\\$\\{@:(\\d+)(?::(\\d+))?\\}/g, (_, startStr, lengthStr) => {\n\t\tlet start = parseInt(startStr, 10) - 1; // Convert to 0-indexed (user provides 1-indexed)\n\t\t// Treat 0 as 1 (bash convention: args start at 1)\n\t\tif (start < 0) start = 0;\n\n\t\tif (lengthStr) {\n\t\t\tconst length = parseInt(lengthStr, 10);\n\t\t\treturn args.slice(start, start + length).join(\" \");\n\t\t}\n\t\treturn args.slice(start).join(\" \");\n\t});\n\n\t// Pre-compute all args joined (optimization)\n\tconst allArgs = args.join(\" \");\n\n\tconst rawArgumentText = rawArgs ?? allArgs;\n\n\t// Replace raw-argument aliases before $ARGUMENTS so the shared prefix does not partially match.\n\tresult = result.replace(/\\$ARGUMENTS_RAW/g, rawArgumentText);\n\tresult = result.replace(/\\$RAW_ARGUMENTS/g, rawArgumentText);\n\n\t// Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)\n\tresult = result.replace(/\\$ARGUMENTS/g, allArgs);\n\n\t// Replace $@ with all args joined (existing syntax)\n\tresult = result.replace(/\\$@/g, allArgs);\n\n\treturn result;\n}\n\nfunction loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, body: rawBody } = parseFrontmatter<Record<string, string>>(rawContent);\n\t\tconst body = stripResourceProfileBlocks(rawBody);\n\n\t\tconst name = basename(filePath).replace(/\\.md$/, \"\");\n\n\t\t// Get description from frontmatter or first non-empty line\n\t\tlet description = frontmatter.description || \"\";\n\t\tif (!description) {\n\t\t\tconst firstLine = body.split(\"\\n\").find((line) => line.trim());\n\t\t\tif (firstLine) {\n\t\t\t\t// Truncate if too long\n\t\t\t\tdescription = firstLine.slice(0, 60);\n\t\t\t\tif (firstLine.length > 60) description += \"...\";\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription,\n\t\t\t...(frontmatter[\"argument-hint\"] && { argumentHint: frontmatter[\"argument-hint\"] }),\n\t\t\tcontent: body,\n\t\t\tsourceInfo,\n\t\t\tfilePath,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Scan a directory for .md files (non-recursive) and load them as prompt templates.\n */\nfunction loadTemplatesFromDir(\n\tdir: string,\n\tgetSourceInfo: (filePath: string) => SourceInfo,\n\tisPathAllowed?: (path: string) => boolean,\n): PromptTemplate[] {\n\tconst templates: PromptTemplate[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn templates;\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\t// For symlinks, check if they point to a file\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\t// Broken symlink, skip it\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isFile && entry.name.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (isPathAllowed && !isPathAllowed(fullPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(fullPath, getSourceInfo(fullPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn templates;\n\t}\n\n\treturn templates;\n}\n\nexport interface LoadPromptTemplatesOptions {\n\t/** Working directory for project-local templates. */\n\tcwd: string;\n\t/** Agent config directory for global templates. */\n\tagentDir: string;\n\t/** Explicit prompt template paths (files or directories). */\n\tpromptPaths: string[];\n\t/** Include default prompt directories. */\n\tincludeDefaults: boolean;\n\t/** Profile UAC gate: when provided, files it denies are never read from disk. */\n\tisPathAllowed?: (path: string) => boolean;\n}\n\n/**\n * Load all prompt templates from:\n * 1. Global: agentDir/prompts/\n * 2. Project: cwd/{CONFIG_DIR_NAME}/prompts/\n * 3. Explicit prompt paths\n */\nexport function loadPromptTemplates(options: LoadPromptTemplatesOptions): PromptTemplate[] {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\tconst promptPaths = options.promptPaths;\n\tconst includeDefaults = options.includeDefaults;\n\n\tconst templates: PromptTemplate[] = [];\n\n\tconst globalPromptsDir = join(resolvedAgentDir, \"prompts\");\n\tconst projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, \"prompts\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSourceInfo = (resolvedPath: string): SourceInfo => {\n\t\tif (isUnderPath(resolvedPath, globalPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"user\",\n\t\t\t\tbaseDir: globalPromptsDir,\n\t\t\t});\n\t\t}\n\t\tif (isUnderPath(resolvedPath, projectPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"project\",\n\t\t\t\tbaseDir: projectPromptsDir,\n\t\t\t});\n\t\t}\n\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\tsource: \"local\",\n\t\t\tbaseDir: statSync(resolvedPath).isDirectory() ? resolvedPath : dirname(resolvedPath),\n\t\t});\n\t};\n\n\tif (includeDefaults) {\n\t\ttemplates.push(...loadTemplatesFromDir(globalPromptsDir, getSourceInfo, options.isPathAllowed));\n\t\ttemplates.push(...loadTemplatesFromDir(projectPromptsDir, getSourceInfo, options.isPathAllowed));\n\t}\n\n\t// 3. Load explicit prompt paths\n\tfor (const rawPath of promptPaths) {\n\t\tconst resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\ttemplates.push(...loadTemplatesFromDir(resolvedPath, getSourceInfo, options.isPathAllowed));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (options.isPathAllowed && !options.isPathAllowed(resolvedPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(resolvedPath, getSourceInfo(resolvedPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read failures\n\t\t}\n\t}\n\n\treturn templates;\n}\n\n/**\n * Expand a prompt template if it matches a template name.\n * Returns the expanded content or the original text if not a template.\n */\nexport function expandPromptTemplate(text: string, templates: PromptTemplate[]): string {\n\tif (!text.startsWith(\"/\")) return text;\n\n\tconst match = text.match(/^\\/([^\\s]+)(?:\\s+([\\s\\S]*))?$/);\n\tif (!match) return text;\n\n\tconst templateName = match[1];\n\tconst argsString = match[2] ?? \"\";\n\n\tconst template = templates.find((t) => t.name === templateName);\n\tif (template) {\n\t\tconst args = parseCommandArgs(argsString);\n\t\treturn substituteArgs(template.content, args, argsString);\n\t}\n\n\treturn text;\n}\n"]}
1
+ {"version":3,"file":"prompt-templates.js","sourceRoot":"","sources":["../../src/core/prompt-templates.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { createSyntheticSourceInfo, type SourceInfo } from \"./source-info.ts\";\n\n/**\n * Represents a prompt template loaded from a markdown file\n */\nexport interface PromptTemplate {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n\tcontent: string;\n\tsourceInfo: SourceInfo;\n\tfilePath: string; // Absolute path to the template file\n}\n\n/**\n * Parse command arguments respecting quoted strings (bash-style)\n * Returns array of arguments\n */\nexport function parseCommandArgs(argsString: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet inQuote: string | null = null;\n\n\tfor (let i = 0; i < argsString.length; i++) {\n\t\tconst char = argsString[i];\n\n\t\tif (inQuote) {\n\t\t\tif (char === inQuote) {\n\t\t\t\tinQuote = null;\n\t\t\t} else {\n\t\t\t\tcurrent += char;\n\t\t\t}\n\t\t} else if (char === '\"' || char === \"'\") {\n\t\t\tinQuote = char;\n\t\t} else if (/\\s/.test(char)) {\n\t\t\tif (current) {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += char;\n\t\t}\n\t}\n\n\tif (current) {\n\t\targs.push(current);\n\t}\n\n\treturn args;\n}\n\n/**\n * Substitute argument placeholders in template content\n * Supports:\n * - $1, $2, ... for positional args\n * - $@ and $ARGUMENTS for all parsed args joined with spaces\n * - $ARGUMENTS_RAW and $RAW_ARGUMENTS for the raw tail after the template name\n * - ${N:-default}, ${@:-default}, and ${ARGUMENTS:-default} for fallback values\n * - ${@:N} for args from Nth onwards (bash-style slicing)\n * - ${@:N:L} for L args starting from Nth\n *\n * Note: Replacement happens on the template string only. Argument values\n * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.\n */\nexport function substituteArgs(content: string, args: string[], rawArgs?: string): string {\n\tconst allArgs = args.join(\" \");\n\tconst rawArgumentText = rawArgs ?? allArgs;\n\n\treturn content.replace(\n\t\t/\\$\\{(\\d+|ARGUMENTS|@):-([^}]*)\\}|\\$\\{@:(\\d+)(?::(\\d+))?\\}|\\$(ARGUMENTS_RAW|RAW_ARGUMENTS|ARGUMENTS|@|\\d+)/g,\n\t\t(_match, defaultTarget, defaultValue, sliceStart, sliceLength, simple) => {\n\t\t\tif (defaultTarget) {\n\t\t\t\tconst value =\n\t\t\t\t\tdefaultTarget === \"@\" || defaultTarget === \"ARGUMENTS\" ? allArgs : args[parseInt(defaultTarget, 10) - 1];\n\t\t\t\treturn value || defaultValue;\n\t\t\t}\n\n\t\t\tif (sliceStart) {\n\t\t\t\tconst start = Math.max(0, parseInt(sliceStart, 10) - 1);\n\t\t\t\treturn sliceLength\n\t\t\t\t\t? args.slice(start, start + parseInt(sliceLength, 10)).join(\" \")\n\t\t\t\t\t: args.slice(start).join(\" \");\n\t\t\t}\n\n\t\t\tif (simple === \"ARGUMENTS_RAW\" || simple === \"RAW_ARGUMENTS\") return rawArgumentText;\n\t\t\tif (simple === \"ARGUMENTS\" || simple === \"@\") return allArgs;\n\t\t\treturn args[parseInt(simple, 10) - 1] ?? \"\";\n\t\t},\n\t);\n}\n\nfunction loadTemplateFromFile(filePath: string, sourceInfo: SourceInfo): PromptTemplate | null {\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, body: rawBody } = parseFrontmatter<Record<string, string>>(rawContent);\n\t\tconst body = stripResourceProfileBlocks(rawBody);\n\n\t\tconst name = basename(filePath).replace(/\\.md$/, \"\");\n\n\t\t// Get description from frontmatter or first non-empty line\n\t\tlet description = frontmatter.description || \"\";\n\t\tif (!description) {\n\t\t\tconst firstLine = body.split(\"\\n\").find((line) => line.trim());\n\t\t\tif (firstLine) {\n\t\t\t\t// Truncate if too long\n\t\t\t\tdescription = firstLine.slice(0, 60);\n\t\t\t\tif (firstLine.length > 60) description += \"...\";\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription,\n\t\t\t...(frontmatter[\"argument-hint\"] && { argumentHint: frontmatter[\"argument-hint\"] }),\n\t\t\tcontent: body,\n\t\t\tsourceInfo,\n\t\t\tfilePath,\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Scan a directory for .md files (non-recursive) and load them as prompt templates.\n */\nfunction loadTemplatesFromDir(\n\tdir: string,\n\tgetSourceInfo: (filePath: string) => SourceInfo,\n\tisPathAllowed?: (path: string) => boolean,\n): PromptTemplate[] {\n\tconst templates: PromptTemplate[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn templates;\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\t// For symlinks, check if they point to a file\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\t// Broken symlink, skip it\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isFile && entry.name.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (isPathAllowed && !isPathAllowed(fullPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(fullPath, getSourceInfo(fullPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn templates;\n\t}\n\n\treturn templates;\n}\n\nexport interface LoadPromptTemplatesOptions {\n\t/** Working directory for project-local templates. */\n\tcwd: string;\n\t/** Agent config directory for global templates. */\n\tagentDir: string;\n\t/** Explicit prompt template paths (files or directories). */\n\tpromptPaths: string[];\n\t/** Include default prompt directories. */\n\tincludeDefaults: boolean;\n\t/** Profile UAC gate: when provided, files it denies are never read from disk. */\n\tisPathAllowed?: (path: string) => boolean;\n}\n\n/**\n * Load all prompt templates from:\n * 1. Global: agentDir/prompts/\n * 2. Project: cwd/{CONFIG_DIR_NAME}/prompts/\n * 3. Explicit prompt paths\n */\nexport function loadPromptTemplates(options: LoadPromptTemplatesOptions): PromptTemplate[] {\n\tconst resolvedCwd = resolvePath(options.cwd);\n\tconst resolvedAgentDir = resolvePath(options.agentDir);\n\tconst promptPaths = options.promptPaths;\n\tconst includeDefaults = options.includeDefaults;\n\n\tconst templates: PromptTemplate[] = [];\n\n\tconst globalPromptsDir = join(resolvedAgentDir, \"prompts\");\n\tconst projectPromptsDir = resolve(resolvedCwd, CONFIG_DIR_NAME, \"prompts\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSourceInfo = (resolvedPath: string): SourceInfo => {\n\t\tif (isUnderPath(resolvedPath, globalPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"user\",\n\t\t\t\tbaseDir: globalPromptsDir,\n\t\t\t});\n\t\t}\n\t\tif (isUnderPath(resolvedPath, projectPromptsDir)) {\n\t\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\t\tsource: \"local\",\n\t\t\t\tscope: \"project\",\n\t\t\t\tbaseDir: projectPromptsDir,\n\t\t\t});\n\t\t}\n\t\treturn createSyntheticSourceInfo(resolvedPath, {\n\t\t\tsource: \"local\",\n\t\t\tbaseDir: statSync(resolvedPath).isDirectory() ? resolvedPath : dirname(resolvedPath),\n\t\t});\n\t};\n\n\tif (includeDefaults) {\n\t\ttemplates.push(...loadTemplatesFromDir(globalPromptsDir, getSourceInfo, options.isPathAllowed));\n\t\ttemplates.push(...loadTemplatesFromDir(projectPromptsDir, getSourceInfo, options.isPathAllowed));\n\t}\n\n\t// 3. Load explicit prompt paths\n\tfor (const rawPath of promptPaths) {\n\t\tconst resolvedPath = resolvePath(rawPath, resolvedCwd, { trim: true });\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\ttemplates.push(...loadTemplatesFromDir(resolvedPath, getSourceInfo, options.isPathAllowed));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\t// Profile UAC: a denied template file is never read from disk.\n\t\t\t\tif (options.isPathAllowed && !options.isPathAllowed(resolvedPath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst template = loadTemplateFromFile(resolvedPath, getSourceInfo(resolvedPath));\n\t\t\t\tif (template) {\n\t\t\t\t\ttemplates.push(template);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore read failures\n\t\t}\n\t}\n\n\treturn templates;\n}\n\n/**\n * Expand a prompt template if it matches a template name.\n * Returns the expanded content or the original text if not a template.\n */\nexport function expandPromptTemplate(text: string, templates: PromptTemplate[]): string {\n\tif (!text.startsWith(\"/\")) return text;\n\n\tconst match = text.match(/^\\/([^\\s]+)(?:\\s+([\\s\\S]*))?$/);\n\tif (!match) return text;\n\n\tconst templateName = match[1];\n\tconst argsString = match[2] ?? \"\";\n\n\tconst template = templates.find((t) => t.name === templateName);\n\tif (template) {\n\t\tconst args = parseCommandArgs(argsString);\n\t\treturn substituteArgs(template.content, args, argsString);\n\t}\n\n\treturn text;\n}\n"]}
@@ -11,8 +11,8 @@
11
11
  */
12
12
  import { type Agent, type ThinkingLevel } from "@caupulican/pi-agent-core";
13
13
  import type { SessionManager } from "@caupulican/pi-agent-core/node";
14
- import type { Api, Model, SimpleStreamOptions, Usage } from "@caupulican/pi-ai";
15
- import { type IsolatedCompletionOptions, type IsolatedCompletionResult } from "./agent-session.ts";
14
+ import { type Api, type Model, type SimpleStreamOptions, type Usage } from "@caupulican/pi-ai";
15
+ import { type IsolatedCompletionOptions, type IsolatedCompletionResult } from "./agent-session-contracts.ts";
16
16
  import type { LearningDecision } from "./autonomy/contracts.ts";
17
17
  import { type AutonomyTelemetryEvent } from "./autonomy/telemetry-events.ts";
18
18
  import { type LearningAuditRecord } from "./learning/learning-audit.ts";
@@ -22,7 +22,7 @@ import type { ModelRegistry } from "./model-registry.ts";
22
22
  import type { SettingsManager } from "./settings-manager.ts";
23
23
  export interface ReflectionControllerDeps {
24
24
  /** Current session model (fallback for an isolated call that omits its own model). */
25
- getModel(): Model<any> | undefined;
25
+ getModel(): Model<Api> | undefined;
26
26
  /** The underlying agent — its `streamFn` runs the isolated completion. */
27
27
  getAgent(): Agent;
28
28
  /** True when the session's stream fn is the raw `streamSimple` provider (auth must be injected). */
@@ -58,7 +58,7 @@ export interface ReflectionControllerDeps {
58
58
  /** Resolve text-tool fallback for the selected isolated model, not the foreground model. */
59
59
  resolveTextToolCallProtocol(model: Model<Api>): SimpleStreamOptions["textToolCallProtocol"];
60
60
  /** Ensure a managed-local model is running/resident before any isolated lane calls it. */
61
- ensureModelReady(model: Model<any>): Promise<void>;
61
+ ensureModelReady(model: Model<Api>): Promise<void>;
62
62
  /**
63
63
  * Session working directory — feeds the skill-overlap audit's project-local skill discovery, the
64
64
  * same `cwd` the model-invoked `skillify`/`skill_audit` tools already receive (tools/index.ts).
@@ -99,7 +99,7 @@ export declare class ReflectionController {
99
99
  runReflectionPass(input: {
100
100
  signals: DemandSignals;
101
101
  recentTurnText: string;
102
- model?: Model<any>;
102
+ model?: Model<Api>;
103
103
  thinkingLevel?: ThinkingLevel;
104
104
  signal?: AbortSignal;
105
105
  /** Stable id so a duplicate scheduling/retry of the same pass can't double-count its cost. */
@@ -1 +1 @@
1
- {"version":3,"file":"reflection-controller.d.ts","sourceRoot":"","sources":["../../src/core/reflection-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Native reflection + learning-write controller.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the end-of-loop reflection\n * pass (R2), the isolated-completion primitive it runs on, and the learning-apply/rollback path that\n * turns reflection writes into gated, audited durable memory/skill changes. It mutates NO session\n * fields — every durable effect goes through the bundled memory tool, the session log (via deps), or\n * the skills dir; the whole pass is best-effort and never throws into the turn loop. Reads live\n * session state (model/agent/registry/memory/settings) through narrow deps accessors rather than the\n * whole AgentSession.\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\ttype Agent,\n\ttype AgentContext,\n\ttype AgentLoopConfig,\n\trunAgentLoop,\n\ttype ThinkingLevel,\n} from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, AssistantMessage, Context, Model, SimpleStreamOptions, TextContent, Usage } from \"@caupulican/pi-ai\";\nimport {\n\tcomputeLaneAffinityKey,\n\tDEFAULT_ISOLATED_LANE_KIND,\n\ttype IsolatedCompletionOptions,\n\ttype IsolatedCompletionResult,\n} from \"./agent-session.ts\";\nimport type { LearningDecision } from \"./autonomy/contracts.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"./autonomy/telemetry-events.ts\";\nimport {\n\tAPPLY_WRITE_REFUSED_REASON_CODE,\n\tappendLearningAuditSnapshot,\n\tcontradictionsForReflectionWrite,\n\tgetLearningAuditSnapshots,\n\ttype LearningAuditRecord,\n\tproposalFromReflectionWrite,\n\trollbackPlanForReflectionWrite,\n} from \"./learning/learning-audit.ts\";\nimport { evaluateLearningDecision } from \"./learning/learning-gate.ts\";\nimport { ObservationStore, observationKey } from \"./learning/observation-store.ts\";\nimport {\n\ttype DemandSignals,\n\tdecideDemand,\n\tReflectionEngine,\n\ttype ReflectionResult,\n\ttype ReflectionWrite,\n} from \"./learning/reflection-engine.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { registerInFlightWork } from \"./reload-blockers.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { runSkillAudit } from \"./tools/skill-audit.ts\";\n\nexport interface ReflectionControllerDeps {\n\t/** Current session model (fallback for an isolated call that omits its own model). */\n\tgetModel(): Model<any> | undefined;\n\t/** The underlying agent — its `streamFn` runs the isolated completion. */\n\tgetAgent(): Agent;\n\t/** True when the session's stream fn is the raw `streamSimple` provider (auth must be injected). */\n\tisRawStreamSimple(): boolean;\n\t/** Model registry for API-key/header resolution on the raw-provider path. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Memory subsystem — the bundled `memory` tool applies durable writes; fresh block feeds reflection. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Settings — the learning-apply policy (gate thresholds, auto-apply layers) is read here. */\n\tgetSettingsManager(): SettingsManager;\n\t/** Session log — audit snapshots and learning-audit reads go through this. */\n\tgetSessionManager(): SessionManager;\n\t/** Agent dir — reflection-promoted skills are written under `<agentDir>/skills/`. */\n\tgetAgentDir(): string;\n\t/** Child sessions must not learn — the pass returns null for them. */\n\tisChildSession(): boolean;\n\t/** Disposal short-circuits: no completion, no writes against a dead session. */\n\tisDisposed(): boolean;\n\t/** Session-lifetime abort signal — aborts an in-flight reflection completion on dispose. */\n\tgetReflectionSignal(): AbortSignal;\n\t/** Archive a promoted skill (rollback of a `promote_skill` write). */\n\tarchivePromotedSkill(name: string): boolean;\n\t/** G3/G8 autonomy telemetry sink for learning-gate outcomes and approval requests. */\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\t/** Account the reflection pass's token spend into the cost roll-up (idempotent on reportId). */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** Persist a learning-gate decision snapshot to the session log. */\n\tsaveLearningDecisionSnapshot(decision: LearningDecision): string;\n\t/** Resolve text-tool fallback for the selected isolated model, not the foreground model. */\n\tresolveTextToolCallProtocol(model: Model<Api>): SimpleStreamOptions[\"textToolCallProtocol\"];\n\t/** Ensure a managed-local model is running/resident before any isolated lane calls it. */\n\tensureModelReady(model: Model<any>): Promise<void>;\n\t/**\n\t * Session working directory — feeds the skill-overlap audit's project-local skill discovery, the\n\t * same `cwd` the model-invoked `skillify`/`skill_audit` tools already receive (tools/index.ts).\n\t * Optional so a host that has not wired it yet still resolves (falls back to `process.cwd()`,\n\t * mirroring the existing profile-resolution fallback in settings-manager.ts).\n\t */\n\tgetCwd?(): string;\n}\n\n// reasonCode when an automatic skill promotion is blocked by an overlap with an existing skill\n// (skill_audit's similarity threshold) and routed to a consolidation proposal instead of a blind write.\nexport const SKILL_OVERLAP_CONSOLIDATION_REASON_CODE = \"skill_overlap_consolidation_proposed\";\n// reasonCode when the overlap audit itself fails — the promotion is held (not written unaudited)\n// rather than silently skipping the check.\nexport const SKILL_AUDIT_UNAVAILABLE_REASON_CODE = \"skill_audit_unavailable\";\n\nexport class ReflectionController {\n\tprivate readonly deps: ReflectionControllerDeps;\n\n\tconstructor(deps: ReflectionControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/**\n\t * Run an LLM completion fully ISOLATED from the main session — the load-bearing primitive for\n\t * reflection and bounded child lanes (adaptive-agent design §6c/§7).\n\t *\n\t * Isolation invariants (audited by codex): builds fresh context (no main history), defaults to no\n\t * tools, and passes **no real `sessionId`** — only a deterministic SYNTHETIC cache-affinity key\n\t * (see {@link computeLaneAffinityKey}) derived from `(laneKind, model, systemPrompt)`, which can never\n\t * equal or embed the real session id. A tool-enabled call receives only caller-owned tools and hooks,\n\t * and is turn-bounded. It cannot mutate `agent.state.messages`, append session entries, or touch the\n\t * foreground tool registry. Mirrors `generateSummary()`'s one-shot mechanics otherwise.\n\t *\n\t * Returns the result even on an error/aborted stop reason (callers — e.g. a background reflection\n\t * microtask — decide whether to act); it does not throw on a model-level error.\n\t */\n\tasync runIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult> {\n\t\tconst model = opts.model ?? this.deps.getModel();\n\t\tif (!model) {\n\t\t\tthrow new Error(\"runIsolatedCompletion: no model available\");\n\t\t}\n\t\tawait this.deps.ensureModelReady(model);\n\t\tconst thinkingLevel = opts.thinkingLevel ?? \"off\";\n\n\t\t// Registered for the full isolated-completion call (one-shot or child-loop) so the\n\t\t// reload gate waits it out — this is the SINGLE choke point every isolated completion in the\n\t\t// codebase runs through (reflection, research/worker/fitness lanes, context-pipeline curation,\n\t\t// model-router judge calls). registerInFlightWork is a pure sync map op (cannot throw), so\n\t\t// placing it as the last statement before `try` still guarantees the matching finally always\n\t\t// runs, on every return path below and on any thrown error.\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"isolated-completion\",\n\t\t\topts.laneKind ?? DEFAULT_ISOLATED_LANE_KIND,\n\t\t);\n\t\ttry {\n\t\t\t// Fresh, isolated context: explicit messages, caller-owned tools only, nothing from the main session.\n\t\t\tconst context: Context = {\n\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\tmessages: opts.messages,\n\t\t\t\ttools: opts.tools ?? [],\n\t\t\t};\n\n\t\t\t// Isolate the prompt cache from the main session by DELIBERATELY never sending the real\n\t\t\t// sessionId. In its place, a deterministic SYNTHETIC affinity key lets providers with\n\t\t\t// session-affinity headers / prompt_cache_key route repeat calls from the SAME lane (same\n\t\t\t// laneKind+model+systemPrompt) to the same cache-warm backend, without entangling this call\n\t\t\t// with — or leaking any identity of — the main session.\n\t\t\tconst affinityKey = computeLaneAffinityKey(\n\t\t\t\topts.laneKind ?? DEFAULT_ISOLATED_LANE_KIND,\n\t\t\t\tmodel,\n\t\t\t\topts.systemPrompt,\n\t\t\t);\n\t\t\tconst options: SimpleStreamOptions = {\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t\tsignal: opts.signal,\n\t\t\t\tcacheRetention: opts.cacheRetention,\n\t\t\t\treasoning: thinkingLevel,\n\t\t\t\tsessionId: affinityKey,\n\t\t\t};\n\n\t\t\t// When streamFn is the raw streamSimple (e.g. in tests), auth must be injected explicitly.\n\t\t\t// Throw only when auth genuinely fails — providers that authenticate without an API key\n\t\t\t// (OAuth, local no-key) legitimately return ok with an undefined apiKey.\n\t\t\tif (this.deps.isRawStreamSimple()) {\n\t\t\t\tconst auth = await this.deps.getModelRegistry().getApiKeyAndHeaders(model);\n\t\t\t\tif (!auth.ok) {\n\t\t\t\t\tthrow new Error(auth.error);\n\t\t\t\t}\n\t\t\t\toptions.apiKey = auth.apiKey;\n\t\t\t\toptions.headers = auth.headers;\n\t\t\t}\n\n\t\t\tif (opts.tools && opts.tools.length > 0) {\n\t\t\t\tconst agent = this.deps.getAgent();\n\t\t\t\tconst foregroundModel = agent.state.model;\n\t\t\t\tconst usesForegroundModel = foregroundModel?.provider === model.provider && foregroundModel.id === model.id;\n\t\t\t\tconst textToolCallProtocol = this.deps.resolveTextToolCallProtocol(model);\n\t\t\t\tconst requestedMaxTurns =\n\t\t\t\t\ttypeof opts.maxTurns === \"number\" && Number.isFinite(opts.maxTurns) ? Math.floor(opts.maxTurns) : 6;\n\t\t\t\tconst maxTurns = Math.max(1, Math.min(12, requestedMaxTurns));\n\t\t\t\tlet completedTurns = 0;\n\t\t\t\tconst childContext: AgentContext = {\n\t\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\t\tmessages: [],\n\t\t\t\t\ttools: [...opts.tools],\n\t\t\t\t};\n\t\t\t\tconst loopConfig: AgentLoopConfig = {\n\t\t\t\t\tmodel,\n\t\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t\t\tcacheRetention: opts.cacheRetention,\n\t\t\t\t\treasoning: thinkingLevel,\n\t\t\t\t\t// Same synthetic per-lane affinity key as the one-shot path above — never the real sessionId.\n\t\t\t\t\tsessionId: affinityKey,\n\t\t\t\t\t...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n\t\t\t\t\t...(options.headers !== undefined ? { headers: options.headers } : {}),\n\t\t\t\t\ttemperature: textToolCallProtocol ? 0 : undefined,\n\t\t\t\t\ttextToolCallProtocol,\n\t\t\t\t\tonTextToolProtocolParse: usesForegroundModel ? agent.onTextToolProtocolParse : undefined,\n\t\t\t\t\ttransport: agent.transport,\n\t\t\t\t\tthinkingBudgets: agent.thinkingBudgets,\n\t\t\t\t\tmaxRetryDelayMs: agent.maxRetryDelayMs,\n\t\t\t\t\tmaxStallTurns: Math.max(2, Math.min(maxTurns, agent.maxStallTurns ?? maxTurns)),\n\t\t\t\t\tonRunawayStop: usesForegroundModel ? agent.onRunawayStop : undefined,\n\t\t\t\t\ttoolExecution: \"sequential\",\n\t\t\t\t\ttoolArgumentTeachEnabled: agent.toolArgumentTeachEnabled,\n\t\t\t\t\tonToolArgumentValidation: usesForegroundModel ? agent.onToolArgumentValidation : undefined,\n\t\t\t\t\ttoolValidationEscalationThreshold: agent.toolValidationEscalationThreshold,\n\t\t\t\t\tonToolValidationEscalation: usesForegroundModel ? agent.onToolValidationEscalation : undefined,\n\t\t\t\t\tbeforeToolCall: opts.beforeToolCall,\n\t\t\t\t\tafterToolCall: opts.afterToolCall,\n\t\t\t\t\tshouldStopAfterTurn: () => {\n\t\t\t\t\t\tcompletedTurns += 1;\n\t\t\t\t\t\treturn completedTurns >= maxTurns;\n\t\t\t\t\t},\n\t\t\t\t\tconvertToLlm: agent.convertToLlm,\n\t\t\t\t};\n\t\t\t\tconst messages = await runAgentLoop(\n\t\t\t\t\topts.messages,\n\t\t\t\t\tchildContext,\n\t\t\t\t\tloopConfig,\n\t\t\t\t\t() => {},\n\t\t\t\t\topts.signal,\n\t\t\t\t\tagent.streamFn,\n\t\t\t\t);\n\t\t\t\tconst assistantMessages = messages.filter(\n\t\t\t\t\t(message): message is AssistantMessage => message.role === \"assistant\",\n\t\t\t\t);\n\t\t\t\tlet finalAssistant = assistantMessages.at(-1);\n\t\t\t\tif (!finalAssistant) {\n\t\t\t\t\tthrow new Error(\"runIsolatedCompletion: child loop produced no assistant message\");\n\t\t\t\t}\n\n\t\t\t\tconst hasFinalText = finalAssistant.content.some(\n\t\t\t\t\t(content) => content.type === \"text\" && content.text.trim().length > 0,\n\t\t\t\t);\n\t\t\t\tconst endedOnToolCall = finalAssistant.content.some((content) => content.type === \"toolCall\");\n\t\t\t\tif (opts.finalTextPrompt && !hasFinalText && endedOnToolCall && !opts.signal?.aborted) {\n\t\t\t\t\t// A hard turn bound may stop immediately after successful tool execution. Preserve that bound,\n\t\t\t\t\t// then allow exactly one tool-free synthesis call so the gathered work is not thrown away.\n\t\t\t\t\tconst finalizationMessages = await agent.convertToLlm(messages);\n\t\t\t\t\tconst finalizationStream = await agent.streamFn(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\t\t\t\tmessages: [\n\t\t\t\t\t\t\t\t...finalizationMessages,\n\t\t\t\t\t\t\t\t{ role: \"user\", content: opts.finalTextPrompt, timestamp: Date.now() },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\ttools: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\toptions,\n\t\t\t\t\t);\n\t\t\t\t\tfinalAssistant = await finalizationStream.result();\n\t\t\t\t\tassistantMessages.push(finalAssistant);\n\t\t\t\t}\n\n\t\t\t\tconst usage = assistantMessages.reduce<Usage>(\n\t\t\t\t\t(total, message) => ({\n\t\t\t\t\t\tinput: total.input + message.usage.input,\n\t\t\t\t\t\toutput: total.output + message.usage.output,\n\t\t\t\t\t\tcacheRead: total.cacheRead + message.usage.cacheRead,\n\t\t\t\t\t\tcacheWrite: total.cacheWrite + message.usage.cacheWrite,\n\t\t\t\t\t\ttotalTokens: total.totalTokens + message.usage.totalTokens,\n\t\t\t\t\t\tcost: {\n\t\t\t\t\t\t\tinput: total.cost.input + message.usage.cost.input,\n\t\t\t\t\t\t\toutput: total.cost.output + message.usage.cost.output,\n\t\t\t\t\t\t\tcacheRead: total.cost.cacheRead + message.usage.cost.cacheRead,\n\t\t\t\t\t\t\tcacheWrite: total.cost.cacheWrite + message.usage.cost.cacheWrite,\n\t\t\t\t\t\t\ttotal: total.cost.total + message.usage.cost.total,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst text = finalAssistant.content\n\t\t\t\t\t.filter((content): content is TextContent => content.type === \"text\")\n\t\t\t\t\t.map((content) => content.text)\n\t\t\t\t\t.join(\"\");\n\t\t\t\treturn { text, usage, stopReason: finalAssistant.stopReason };\n\t\t\t}\n\n\t\t\tconst stream = await this.deps.getAgent().streamFn(model, context, options);\n\t\t\tconst result = await stream.result();\n\t\t\tconst text = result.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t\tconst usage: Usage = result.usage ?? {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\treturn { text, usage, stopReason: result.stopReason };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\t/**\n\t * Native end-of-loop reflection pass (R2). Demand-gates (zero-I/O), and when warranted runs the\n\t * {@link ReflectionEngine} via an isolated completion ({@link runIsolatedCompletion}), applies the\n\t * resulting memory writes through the bundled `memory` tool, and accounts the reflection's token\n\t * cost via the cost-aggregation surface so it stays visible and net-negative-auditable.\n\t *\n\t * Returns `null` when the gate skips (or in a child session, which must not learn). The whole pass\n\t * is best-effort: a model/parse error yields no writes, never throws into the caller.\n\t */\n\tasync runReflectionPass(input: {\n\t\tsignals: DemandSignals;\n\t\trecentTurnText: string;\n\t\tmodel?: Model<any>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t\tsignal?: AbortSignal;\n\t\t/** Stable id so a duplicate scheduling/retry of the same pass can't double-count its cost. */\n\t\treportId?: string;\n\t}): Promise<ReflectionResult | null> {\n\t\tif (this.deps.isChildSession() || this.deps.isDisposed()) return null;\n\t\tconst plan = decideDemand(input.signals);\n\t\tif (plan.act === \"skip\") return null;\n\n\t\t// Bug #21: tie this background pass to the session lifetime. Disposing the session aborts the\n\t\t// in-flight completion (input.signal can add a more specific abort).\n\t\tconst signal = input.signal\n\t\t\t? AbortSignal.any([input.signal, this.deps.getReflectionSignal()])\n\t\t\t: this.deps.getReflectionSignal();\n\n\t\tconst complete = (systemPrompt: string, userPrompt: string) =>\n\t\t\tthis.runIsolatedCompletion({\n\t\t\t\tsystemPrompt,\n\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\tmodel: input.model,\n\t\t\t\tthinkingLevel: input.thinkingLevel ?? \"low\",\n\t\t\t\tmaxTokens: plan.tokenBudget,\n\t\t\t\tsignal,\n\t\t\t\t// The reflection system prompt is static (#33) — let the provider cache the prefix so\n\t\t\t\t// repeated passes only pay for the variable tail.\n\t\t\t\tcacheRetention: \"short\",\n\t\t\t\tlaneKind: \"reflection\",\n\t\t\t});\n\n\t\tconst result = await new ReflectionEngine().reflect({\n\t\t\trecentTurnText: input.recentTurnText,\n\t\t\t// Read memory FRESH (not the prefix-cache-frozen system-prompt block) so confront-before-write\n\t\t\t// sees writes made earlier this session.\n\t\t\texistingMemory: this.deps.getMemoryManager().buildSystemPromptBlockFresh() || \"\",\n\t\t\tplan,\n\t\t\tcomplete,\n\t\t});\n\n\t\t// Bug #21: if the session was disposed while the completion was in flight, do NOT write memory\n\t\t// or skills against the dead session.\n\t\tif (this.deps.isDisposed()) return result;\n\n\t\t// Learning apply policy: every durable write is converted to a proposal, decided by the\n\t\t// learning gate, and audited with a rollback plan. With the policy disabled (default) the\n\t\t// legacy direct-apply behavior is preserved — but now leaves audit records with rollback info.\n\t\tconst policy = this.deps.getSettingsManager().getLearningPolicySettings();\n\t\t// The audit id sequence counts STORED snapshots only: it reseeds from the stored count on\n\t\t// every pass, so advancing it for a no-op (which stores nothing) would make later passes\n\t\t// reuse ids — and rollback keys on the id, so a collision blocks or misdirects rollback.\n\t\tlet auditSequence = getLearningAuditSnapshots(this.deps.getSessionManager().getEntries()).length;\n\t\t// G6 evidence strength: durable proposals accumulate observation counts across passes/sessions\n\t\t// so the gate can distinguish a one-off cue from a repeatedly-confirmed lesson. Built once per\n\t\t// pass; every increment is best-effort (store IO must never break reflection).\n\t\tconst observationStore = ObservationStore.forAgentDir(this.deps.getAgentDir());\n\t\tlet writeIndex = 0;\n\t\tfor (const write of result.writes) {\n\t\t\twriteIndex += 1;\n\t\t\tconst proposalId = `${input.reportId ?? \"reflection\"}-w${writeIndex}`;\n\t\t\tconst proposal = proposalFromReflectionWrite(write, proposalId);\n\t\t\tconst rollback = rollbackPlanForReflectionWrite(write);\n\t\t\tlet observations = 1;\n\t\t\tif (policy.enabled) {\n\t\t\t\ttry {\n\t\t\t\t\tobservations = observationStore.increment(observationKey(proposal.layer, proposal.summary));\n\t\t\t\t} catch {\n\t\t\t\t\t// A store read/write failure falls back to a fresh count of 1, which keeps the gate\n\t\t\t\t\t// proposal-first (never spuriously auto-applies) rather than crashing the pass.\n\t\t\t\t\tobservations = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst decision: LearningDecision = policy.enabled\n\t\t\t\t? evaluateLearningDecision({\n\t\t\t\t\t\tproposal,\n\t\t\t\t\t\tconfidence: policy.reflectionSourceConfidence,\n\t\t\t\t\t\tobservations,\n\t\t\t\t\t\t// A replace/remove supersedes an existing durable fact — the reflection engine's\n\t\t\t\t\t\t// confront-before-write conflict signal — so it routes through approval instead of\n\t\t\t\t\t\t// silently overwriting prior memory. Additive writes contradict nothing.\n\t\t\t\t\t\tcontradictions: contradictionsForReflectionWrite(write),\n\t\t\t\t\t\tsettings: {\n\t\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\t\tautoApplyEnabled: policy.autoApplyEnabled,\n\t\t\t\t\t\t\tconfidenceThreshold: policy.confidenceThreshold,\n\t\t\t\t\t\t\tminObservations: policy.minObservations,\n\t\t\t\t\t\t\tallowedAutoApplyLayers: policy.allowedAutoApplyLayers,\n\t\t\t\t\t\t\trequireRollbackPlan: policy.requireRollbackPlan,\n\t\t\t\t\t\t\tautoApplySupersessions: policy.autoApplySupersessions,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t: {\n\t\t\t\t\t\tkind: \"apply\",\n\t\t\t\t\t\treasonCode: \"learning_policy_disabled_legacy_apply\",\n\t\t\t\t\t\tconfidence: 0,\n\t\t\t\t\t\tsummary: proposal.summary,\n\t\t\t\t\t\trequiresApproval: false,\n\t\t\t\t\t};\n\n\t\t\tthis.deps.saveLearningDecisionSnapshot(decision);\n\t\t\t// G3: learning-gate outcome. Codes/numbers only — never the proposal summary/memory text.\n\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.learningDecision,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tpayload: {\n\t\t\t\t\tkind: decision.kind,\n\t\t\t\t\treasonCode: decision.reasonCode,\n\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\tconfidence: decision.confidence,\n\t\t\t\t\trequiresApproval: decision.requiresApproval,\n\t\t\t\t},\n\t\t\t});\n\t\t\t// G8: a proposal that needs human sign-off is an approval REQUEST. Codes/layer only —\n\t\t\t// never the proposal summary/memory text (those live only in the audit snapshot).\n\t\t\tif (decision.requiresApproval) {\n\t\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.approvalRequest,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tkind: decision.kind,\n\t\t\t\t\t\treasonCode: decision.reasonCode,\n\t\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\t// An automatic skill promotion the gate would otherwise apply must still clear the same\n\t\t\t// skill_audit overlap check the model-invoked `skillify` tool enforces — otherwise reflection\n\t\t\t// can silently write a near-duplicate SKILL.md. A non-overlapping skill is unaffected\n\t\t\t// (skillPromotionBlock stays undefined) and promotes exactly as before.\n\t\t\tconst skillPromotionBlock =\n\t\t\t\twrite.kind === \"promote_skill\" && decision.kind === \"apply\"\n\t\t\t\t\t? this._checkSkillPromotionOverlap(write)\n\t\t\t\t\t: undefined;\n\n\t\t\t// The gate's decision and the write's actual outcome are two different questions: the memory\n\t\t\t// tool can refuse a write (budget exceeded, drift, threat) via details.success:false without\n\t\t\t// throwing. Capture that outcome instead of assuming \"decision.kind === apply\" means it landed\n\t\t\t// — otherwise a refused write leaves a phantom \"apply\" audit whose rollback later fails\n\t\t\t// not-found (or, worse, misfires against whatever now occupies that text).\n\t\t\tconst applied =\n\t\t\t\tdecision.kind === \"apply\" && !skillPromotionBlock ? await this._applyReflectionWrite(write, signal) : false;\n\t\t\tconst writeFailed = decision.kind === \"apply\" && !skillPromotionBlock && !applied;\n\t\t\tif (decision.kind !== \"no-op\") {\n\t\t\t\tauditSequence += 1;\n\t\t\t\tappendLearningAuditSnapshot(this.deps.getSessionManager(), {\n\t\t\t\t\tid: `audit-${auditSequence}`,\n\t\t\t\t\tproposalId,\n\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\taction: skillPromotionBlock\n\t\t\t\t\t\t? \"propose\"\n\t\t\t\t\t\t: writeFailed\n\t\t\t\t\t\t\t? \"apply_failed\"\n\t\t\t\t\t\t\t: decision.kind === \"apply\"\n\t\t\t\t\t\t\t\t? \"apply\"\n\t\t\t\t\t\t\t\t: \"propose\",\n\t\t\t\t\tsummary: skillPromotionBlock ? `${proposal.summary} — ${skillPromotionBlock.note}` : proposal.summary,\n\t\t\t\t\treasonCode: skillPromotionBlock\n\t\t\t\t\t\t? skillPromotionBlock.reasonCode\n\t\t\t\t\t\t: writeFailed\n\t\t\t\t\t\t\t? APPLY_WRITE_REFUSED_REASON_CODE\n\t\t\t\t\t\t\t: decision.reasonCode,\n\t\t\t\t\tdecision,\n\t\t\t\t\t// No rollback plan on a failed apply or a held/proposed promotion — nothing durable\n\t\t\t\t\t// landed in either case, so there is nothing to undo.\n\t\t\t\t\trollback: skillPromotionBlock || writeFailed ? undefined : rollback,\n\t\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Account the reflection's spend so it surfaces in the footer roll-up (net-token visibility).\n\t\t// Idempotent on reportId so a retried/duplicated pass cannot double-count.\n\t\tif (result.usage.cost.total > 0 || result.usage.totalTokens > 0) {\n\t\t\tthis.deps.addSpawnedUsage(result.usage, { label: \"reflection\", reportId: input.reportId });\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetLearningAuditRecords(): LearningAuditRecord[] {\n\t\treturn getLearningAuditSnapshots(this.deps.getSessionManager().getEntries());\n\t}\n\n\t/**\n\t * Roll back one applied durable learning change by executing the inverse operation recorded in\n\t * its audit record (memory ops run through the same bundled memory-tool path as the original\n\t * apply; promoted skills are archived). Appends a linked \"rollback\" audit record on success so\n\t * the change history stays complete and a change cannot be rolled back twice.\n\t */\n\tasync rollbackLearningWrite(auditId: string): Promise<{ ok: boolean; reason: string }> {\n\t\tif (this.deps.isDisposed()) return { ok: false, reason: \"session_disposed\" };\n\n\t\tconst audits = this.getLearningAuditRecords();\n\t\tconst audit = audits.find((record) => record.id === auditId);\n\t\tif (!audit) return { ok: false, reason: \"audit_not_found\" };\n\t\tif (audit.action !== \"apply\") return { ok: false, reason: \"not_an_applied_change\" };\n\t\tif (audits.some((record) => record.action === \"rollback\" && record.rollbackOf === auditId)) {\n\t\t\treturn { ok: false, reason: \"already_rolled_back\" };\n\t\t}\n\t\tconst rollback = audit.rollback;\n\t\tif (!rollback) return { ok: false, reason: \"no_rollback_plan\" };\n\n\t\t// Every inverse must be VERIFIED-applied before the rollback audit is appended: a silently\n\t\t// failed inverse that still recorded \"rollback\" would permanently self-lock the change\n\t\t// behind already_rolled_back while the durable write is in fact still live.\n\t\tswitch (rollback.kind) {\n\t\t\tcase \"memory_remove\": {\n\t\t\t\tif (!rollback.target) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tif (!(await this._applyReflectionWrite({ kind: \"memory_remove\", target: rollback.target }))) {\n\t\t\t\t\treturn { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"memory_restore\": {\n\t\t\t\tif (!rollback.target || rollback.previous === undefined) {\n\t\t\t\t\treturn { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\t}\n\t\t\t\tconst applied = await this._applyReflectionWrite({\n\t\t\t\t\tkind: \"memory_replace\",\n\t\t\t\t\ttarget: rollback.target,\n\t\t\t\t\ttext: rollback.previous,\n\t\t\t\t});\n\t\t\t\tif (!applied) return { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"memory_add\": {\n\t\t\t\tif (rollback.previous === undefined) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tconst applied = await this._applyReflectionWrite({\n\t\t\t\t\tkind: \"memory_add\",\n\t\t\t\t\tsection: \"MEMORY\",\n\t\t\t\t\ttext: rollback.previous,\n\t\t\t\t});\n\t\t\t\tif (!applied) return { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"archive_skill\": {\n\t\t\t\tif (!rollback.target) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tif (!this.deps.archivePromotedSkill(rollback.target)) {\n\t\t\t\t\treturn { ok: false, reason: \"skill_archive_failed\" };\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tappendLearningAuditSnapshot(this.deps.getSessionManager(), {\n\t\t\tid: `${audit.id}-rollback`,\n\t\t\tproposalId: audit.proposalId,\n\t\t\tlayer: audit.layer,\n\t\t\taction: \"rollback\",\n\t\t\tsummary: `Rolled back: ${audit.summary}`,\n\t\t\treasonCode: \"user_requested_rollback\",\n\t\t\tdecision: audit.decision,\n\t\t\trollbackOf: audit.id,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t});\n\t\treturn { ok: true, reason: \"rollback_applied\" };\n\t}\n\n\t/**\n\t * Apply one reflection write through the bundled `memory` tool. `memory_replace`/`memory_remove`\n\t * don't carry a target file, so we try MEMORY.md first and fall back to USER.md when the substring\n\t * isn't found there. Never throws (reflection must never break a turn); returns whether the write\n\t * actually applied so callers that MUST know — rollback's once-only accounting — can react instead\n\t * of recording a success that never happened.\n\t */\n\tprivate async _applyReflectionWrite(write: ReflectionWrite, signal?: AbortSignal): Promise<boolean> {\n\t\t// R7 memory-to-behavior: a recurring procedure is compiled into an executable skill file rather\n\t\t// than stored as a flat fact. Written under the agent skills dir so it loads like any user skill.\n\t\tif (write.kind === \"promote_skill\") {\n\t\t\treturn this._promoteReflectionSkill(write.name, write.description, write.body);\n\t\t}\n\n\t\ttype MemResult = { details?: { success?: boolean; error?: string } };\n\t\ttype MemExec = (\n\t\t\ttoolCallId: string,\n\t\t\tparams: { action: string; target: string; content?: string; oldContent?: string },\n\t\t\tsignal: AbortSignal | undefined,\n\t\t\tonUpdate: undefined,\n\t\t\tctx: undefined,\n\t\t) => Promise<MemResult>;\n\t\tconst memTool = this.deps\n\t\t\t.getMemoryManager()\n\t\t\t.getToolDefinitions()\n\t\t\t.find((t) => t.name === \"memory\");\n\t\tconst exec = memTool?.execute as unknown as MemExec | undefined;\n\t\tif (!exec) return false;\n\n\t\tconst run = (params: Parameters<MemExec>[1]) => exec(\"reflection\", params, signal, undefined, undefined);\n\n\t\tif (write.kind === \"memory_add\") {\n\t\t\ttry {\n\t\t\t\tconst res = await run({\n\t\t\t\t\taction: \"add\",\n\t\t\t\t\ttarget: write.section === \"USER\" ? \"user\" : \"memory\",\n\t\t\t\t\tcontent: write.text,\n\t\t\t\t});\n\t\t\t\treturn res?.details?.success === true;\n\t\t\t} catch {\n\t\t\t\t// best-effort; reflection writes must never throw into the turn loop\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// replace / remove carry no target file — try MEMORY.md, then USER.md. The memory tool reports\n\t\t// outcomes via `details.success` (it catches its own errors rather than throwing). Only a\n\t\t// genuine \"not found in the file\" justifies trying the other file; a real failure for a file\n\t\t// (budget exceeded / drift) must NOT fall through and mutate the wrong target.\n\t\tfor (const target of [\"memory\", \"user\"] as const) {\n\t\t\ttry {\n\t\t\t\tconst params =\n\t\t\t\t\twrite.kind === \"memory_replace\"\n\t\t\t\t\t\t? { action: \"replace\", target, oldContent: write.target, content: write.text }\n\t\t\t\t\t\t: { action: \"remove\", target, oldContent: write.target };\n\t\t\t\tconst res = await run(params);\n\t\t\t\tif (res?.details?.success === true) return true; // applied\n\t\t\t\tif (!/not found/i.test(String(res?.details?.error ?? \"\"))) return false; // real failure — don't misapply\n\t\t\t\t// substring simply absent from this file — try the next target\n\t\t\t} catch {\n\t\t\t\t// defensive: if the tool ever does throw, try the next target\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * The same skill_audit overlap check the model-invoked `skillify` tool enforces\n\t * (tools/skillify.ts → tools/skill-audit.ts's `runSkillAudit`), run before an AUTOMATIC promotion\n\t * so the reflection engine can never silently write a near-duplicate SKILL.md. Reuses the audit\n\t * seam unchanged (never duplicated) against the same already-loaded skills universe skillify\n\t * compares a draft against. Returns a block reason when the draft overlaps an existing skill above\n\t * the audit's own similarity threshold, or when the audit itself fails (the promotion is held, not\n\t * written unaudited); undefined when clear to promote. Never throws — mirrors every other\n\t * best-effort check in this file.\n\t */\n\tprivate _checkSkillPromotionOverlap(write: {\n\t\tname: string;\n\t\tdescription: string;\n\t\tbody: string;\n\t}): { reasonCode: string; note: string } | undefined {\n\t\ttry {\n\t\t\tconst cwd = this.deps.getCwd?.() ?? process.cwd();\n\t\t\tconst audit = runSkillAudit(cwd, write);\n\t\t\tconst overlap = audit.nearDuplicates.find((d) => d.a === \"[draft]\" || d.b === \"[draft]\");\n\t\t\tif (!overlap) return undefined;\n\t\t\tconst otherPath = overlap.a === \"[draft]\" ? overlap.b : overlap.a;\n\t\t\t// Every skill file is named \"SKILL.md\" — unlike skillify's own display formatter (which takes\n\t\t\t// the path's last segment and always shows that literal filename), look up the declared\n\t\t\t// frontmatter name so the proposal actually names the skill it overlaps with.\n\t\t\tconst otherName = audit.skills.find((s) => s.path === otherPath)?.name ?? otherPath;\n\t\t\treturn {\n\t\t\t\treasonCode: SKILL_OVERLAP_CONSOLIDATION_REASON_CODE,\n\t\t\t\tnote: `overlaps existing skill \"${otherName}\" (${(overlap.similarity * 100).toFixed(0)}% similar) — consolidation proposed instead of a duplicate write`,\n\t\t\t};\n\t\t} catch {\n\t\t\t// Bounded, observable degradation via the promote path's existing error-reporting shape: an\n\t\t\t// audit failure must never throw into the reflection pass, but it also must not silently\n\t\t\t// fall through to an unaudited write — hold the promotion and record why.\n\t\t\treturn {\n\t\t\t\treasonCode: SKILL_AUDIT_UNAVAILABLE_REASON_CODE,\n\t\t\t\tnote: \"skill overlap audit failed; promotion held rather than written unaudited\",\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * R7: write a reflection-promoted skill as `<agentDir>/skills/<name>/SKILL.md` so it loads like any\n\t * user skill. Best-effort; never clobbers an existing (hand-authored) skill of the same name. The\n\t * overlap audit runs at the call site in {@link runReflectionPass} — a write only reaches here\n\t * once the draft has already cleared it.\n\t */\n\tprivate _promoteReflectionSkill(rawName: string, description: string, body: string): boolean {\n\t\tconst name = rawName\n\t\t\t.trim()\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9-]+/g, \"-\")\n\t\t\t.replace(/^-+|-+$/g, \"\")\n\t\t\t.slice(0, 64);\n\t\tif (!name || !body.trim()) return false;\n\t\ttry {\n\t\t\tconst dir = join(this.deps.getAgentDir(), \"skills\", name);\n\t\t\tconst file = join(dir, \"SKILL.md\");\n\t\t\tif (existsSync(file)) return false; // do not overwrite an existing skill\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\tconst safeDescription = description.replace(/[\\r\\n]+/g, \" \").trim();\n\t\t\t// `promoted: true` marks this as reflection-generated so the curator (#32) can lifecycle-manage\n\t\t\t// it (archive/consolidate) WITHOUT ever touching hand-authored user skills.\n\t\t\tconst content = `---\\nname: ${name}\\ndescription: ${safeDescription}\\npromoted: true\\n---\\n\\n<!-- Auto-generated by the reflection engine (R7 memory-to-behavior). Review and refine. -->\\n\\n${body.trim()}\\n`;\n\t\t\twriteFileSync(file, content, \"utf-8\");\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// promotion must never break a turn\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"reflection-controller.d.ts","sourceRoot":"","sources":["../../src/core/reflection-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Native reflection + learning-write controller.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Owns the end-of-loop reflection\n * pass (R2), the isolated-completion primitive it runs on, and the learning-apply/rollback path that\n * turns reflection writes into gated, audited durable memory/skill changes. It mutates NO session\n * fields — every durable effect goes through the bundled memory tool, the session log (via deps), or\n * the skills dir; the whole pass is best-effort and never throws into the turn loop. Reads live\n * session state (model/agent/registry/memory/settings) through narrow deps accessors rather than the\n * whole AgentSession.\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\ttype Agent,\n\ttype AgentContext,\n\ttype AgentLoopConfig,\n\trunAgentLoop,\n\ttype ThinkingLevel,\n} from \"@caupulican/pi-agent-core\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport {\n\ttype Api,\n\ttype AssistantMessage,\n\ttype Context,\n\ttype Model,\n\tresolveModelThinkingLevel,\n\ttype SimpleStreamOptions,\n\ttype TextContent,\n\ttype Usage,\n} from \"@caupulican/pi-ai\";\nimport {\n\tcomputeLaneAffinityKey,\n\tDEFAULT_ISOLATED_LANE_KIND,\n\ttype IsolatedCompletionOptions,\n\ttype IsolatedCompletionResult,\n} from \"./agent-session-contracts.ts\";\nimport type { LearningDecision } from \"./autonomy/contracts.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"./autonomy/telemetry-events.ts\";\nimport {\n\tAPPLY_WRITE_REFUSED_REASON_CODE,\n\tappendLearningAuditSnapshot,\n\tcontradictionsForReflectionWrite,\n\tgetLearningAuditSnapshots,\n\ttype LearningAuditRecord,\n\tproposalFromReflectionWrite,\n\trollbackPlanForReflectionWrite,\n} from \"./learning/learning-audit.ts\";\nimport { evaluateLearningDecision } from \"./learning/learning-gate.ts\";\nimport { ObservationStore, observationKey } from \"./learning/observation-store.ts\";\nimport {\n\ttype DemandSignals,\n\tdecideDemand,\n\tReflectionEngine,\n\ttype ReflectionResult,\n\ttype ReflectionWrite,\n} from \"./learning/reflection-engine.ts\";\nimport type { MemoryManager } from \"./memory/memory-manager.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport { registerInFlightWork } from \"./reload-blockers.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\nimport { runSkillAudit } from \"./tools/skill-audit.ts\";\n\nexport interface ReflectionControllerDeps {\n\t/** Current session model (fallback for an isolated call that omits its own model). */\n\tgetModel(): Model<Api> | undefined;\n\t/** The underlying agent — its `streamFn` runs the isolated completion. */\n\tgetAgent(): Agent;\n\t/** True when the session's stream fn is the raw `streamSimple` provider (auth must be injected). */\n\tisRawStreamSimple(): boolean;\n\t/** Model registry for API-key/header resolution on the raw-provider path. */\n\tgetModelRegistry(): ModelRegistry;\n\t/** Memory subsystem — the bundled `memory` tool applies durable writes; fresh block feeds reflection. */\n\tgetMemoryManager(): MemoryManager;\n\t/** Settings — the learning-apply policy (gate thresholds, auto-apply layers) is read here. */\n\tgetSettingsManager(): SettingsManager;\n\t/** Session log — audit snapshots and learning-audit reads go through this. */\n\tgetSessionManager(): SessionManager;\n\t/** Agent dir — reflection-promoted skills are written under `<agentDir>/skills/`. */\n\tgetAgentDir(): string;\n\t/** Child sessions must not learn — the pass returns null for them. */\n\tisChildSession(): boolean;\n\t/** Disposal short-circuits: no completion, no writes against a dead session. */\n\tisDisposed(): boolean;\n\t/** Session-lifetime abort signal — aborts an in-flight reflection completion on dispose. */\n\tgetReflectionSignal(): AbortSignal;\n\t/** Archive a promoted skill (rollback of a `promote_skill` write). */\n\tarchivePromotedSkill(name: string): boolean;\n\t/** G3/G8 autonomy telemetry sink for learning-gate outcomes and approval requests. */\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\t/** Account the reflection pass's token spend into the cost roll-up (idempotent on reportId). */\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts?: { label?: string; sourceSessionId?: string; reportId?: string },\n\t): string | undefined;\n\t/** Persist a learning-gate decision snapshot to the session log. */\n\tsaveLearningDecisionSnapshot(decision: LearningDecision): string;\n\t/** Resolve text-tool fallback for the selected isolated model, not the foreground model. */\n\tresolveTextToolCallProtocol(model: Model<Api>): SimpleStreamOptions[\"textToolCallProtocol\"];\n\t/** Ensure a managed-local model is running/resident before any isolated lane calls it. */\n\tensureModelReady(model: Model<Api>): Promise<void>;\n\t/**\n\t * Session working directory — feeds the skill-overlap audit's project-local skill discovery, the\n\t * same `cwd` the model-invoked `skillify`/`skill_audit` tools already receive (tools/index.ts).\n\t * Optional so a host that has not wired it yet still resolves (falls back to `process.cwd()`,\n\t * mirroring the existing profile-resolution fallback in settings-manager.ts).\n\t */\n\tgetCwd?(): string;\n}\n\n// reasonCode when an automatic skill promotion is blocked by an overlap with an existing skill\n// (skill_audit's similarity threshold) and routed to a consolidation proposal instead of a blind write.\nexport const SKILL_OVERLAP_CONSOLIDATION_REASON_CODE = \"skill_overlap_consolidation_proposed\";\n// reasonCode when the overlap audit itself fails — the promotion is held (not written unaudited)\n// rather than silently skipping the check.\nexport const SKILL_AUDIT_UNAVAILABLE_REASON_CODE = \"skill_audit_unavailable\";\n\nexport class ReflectionController {\n\tprivate readonly deps: ReflectionControllerDeps;\n\n\tconstructor(deps: ReflectionControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\t/**\n\t * Run an LLM completion fully ISOLATED from the main session — the load-bearing primitive for\n\t * reflection and bounded child lanes (adaptive-agent design §6c/§7).\n\t *\n\t * Isolation invariants (audited by codex): builds fresh context (no main history), defaults to no\n\t * tools, and passes **no real `sessionId`** — only a deterministic SYNTHETIC cache-affinity key\n\t * (see {@link computeLaneAffinityKey}) derived from `(laneKind, model, systemPrompt)`, which can never\n\t * equal or embed the real session id. A tool-enabled call receives only caller-owned tools and hooks,\n\t * and is turn-bounded. It cannot mutate `agent.state.messages`, append session entries, or touch the\n\t * foreground tool registry. Mirrors `generateSummary()`'s one-shot mechanics otherwise.\n\t *\n\t * Returns the result even on an error/aborted stop reason (callers — e.g. a background reflection\n\t * microtask — decide whether to act); it does not throw on a model-level error.\n\t */\n\tasync runIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult> {\n\t\tconst model = opts.model ?? this.deps.getModel();\n\t\tif (!model) {\n\t\t\tthrow new Error(\"runIsolatedCompletion: no model available\");\n\t\t}\n\t\tawait this.deps.ensureModelReady(model);\n\t\tconst thinkingLevel = resolveModelThinkingLevel(model, opts.thinkingLevel, \"off\");\n\n\t\t// Registered for the full isolated-completion call (one-shot or child-loop) so the\n\t\t// reload gate waits it out — this is the SINGLE choke point every isolated completion in the\n\t\t// codebase runs through (reflection, research/worker/fitness lanes, context-pipeline curation,\n\t\t// model-router judge calls). registerInFlightWork is a pure sync map op (cannot throw), so\n\t\t// placing it as the last statement before `try` still guarantees the matching finally always\n\t\t// runs, on every return path below and on any thrown error.\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"isolated-completion\",\n\t\t\topts.laneKind ?? DEFAULT_ISOLATED_LANE_KIND,\n\t\t);\n\t\ttry {\n\t\t\t// Fresh, isolated context: explicit messages, caller-owned tools only, nothing from the main session.\n\t\t\tconst context: Context = {\n\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\tmessages: opts.messages,\n\t\t\t\ttools: opts.tools ?? [],\n\t\t\t};\n\n\t\t\t// Isolate the prompt cache from the main session by DELIBERATELY never sending the real\n\t\t\t// sessionId. In its place, a deterministic SYNTHETIC affinity key lets providers with\n\t\t\t// session-affinity headers / prompt_cache_key route repeat calls from the SAME lane (same\n\t\t\t// laneKind+model+systemPrompt) to the same cache-warm backend, without entangling this call\n\t\t\t// with — or leaking any identity of — the main session.\n\t\t\tconst affinityKey = computeLaneAffinityKey(\n\t\t\t\topts.laneKind ?? DEFAULT_ISOLATED_LANE_KIND,\n\t\t\t\tmodel,\n\t\t\t\topts.systemPrompt,\n\t\t\t);\n\t\t\tconst options: SimpleStreamOptions = {\n\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t\tsignal: opts.signal,\n\t\t\t\tinteractionMode: \"background\",\n\t\t\t\tcacheRetention: opts.cacheRetention,\n\t\t\t\treasoning: thinkingLevel,\n\t\t\t\tsessionId: affinityKey,\n\t\t\t};\n\n\t\t\t// When streamFn is the raw streamSimple (e.g. in tests), auth must be injected explicitly.\n\t\t\t// Throw only when auth genuinely fails — providers that authenticate without an API key\n\t\t\t// (OAuth, local no-key) legitimately return ok with an undefined apiKey.\n\t\t\tif (this.deps.isRawStreamSimple()) {\n\t\t\t\tconst auth = await this.deps.getModelRegistry().getApiKeyAndHeaders(model);\n\t\t\t\tif (!auth.ok) {\n\t\t\t\t\tthrow new Error(auth.error);\n\t\t\t\t}\n\t\t\t\toptions.apiKey = auth.apiKey;\n\t\t\t\toptions.headers = auth.headers;\n\t\t\t}\n\n\t\t\tif (opts.tools && opts.tools.length > 0) {\n\t\t\t\tconst agent = this.deps.getAgent();\n\t\t\t\tconst foregroundModel = agent.state.model;\n\t\t\t\tconst usesForegroundModel = foregroundModel?.provider === model.provider && foregroundModel.id === model.id;\n\t\t\t\tconst textToolCallProtocol = this.deps.resolveTextToolCallProtocol(model);\n\t\t\t\tconst requestedMaxTurns =\n\t\t\t\t\ttypeof opts.maxTurns === \"number\" && Number.isFinite(opts.maxTurns) ? Math.floor(opts.maxTurns) : 6;\n\t\t\t\tconst maxTurns = Math.max(1, Math.min(12, requestedMaxTurns));\n\t\t\t\tlet completedTurns = 0;\n\t\t\t\tconst childContext: AgentContext = {\n\t\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\t\tmessages: [],\n\t\t\t\t\ttools: [...opts.tools],\n\t\t\t\t};\n\t\t\t\tconst loopConfig: AgentLoopConfig = {\n\t\t\t\t\tmodel,\n\t\t\t\t\tinteractionMode: \"background\",\n\t\t\t\t\tmaxTokens: opts.maxTokens,\n\t\t\t\t\tcacheRetention: opts.cacheRetention,\n\t\t\t\t\treasoning: thinkingLevel,\n\t\t\t\t\t// Same synthetic per-lane affinity key as the one-shot path above — never the real sessionId.\n\t\t\t\t\tsessionId: affinityKey,\n\t\t\t\t\t...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),\n\t\t\t\t\t...(options.headers !== undefined ? { headers: options.headers } : {}),\n\t\t\t\t\ttemperature: textToolCallProtocol ? 0 : undefined,\n\t\t\t\t\ttextToolCallProtocol,\n\t\t\t\t\tonTextToolProtocolParse: usesForegroundModel ? agent.onTextToolProtocolParse : undefined,\n\t\t\t\t\ttransport: agent.transport,\n\t\t\t\t\tthinkingBudgets: agent.thinkingBudgets,\n\t\t\t\t\tmaxRetryDelayMs: agent.maxRetryDelayMs,\n\t\t\t\t\tmaxStallTurns: Math.max(2, Math.min(maxTurns, agent.maxStallTurns ?? maxTurns)),\n\t\t\t\t\tonRunawayStop: usesForegroundModel ? agent.onRunawayStop : undefined,\n\t\t\t\t\ttoolExecution: \"sequential\",\n\t\t\t\t\ttoolArgumentTeachEnabled: agent.toolArgumentTeachEnabled,\n\t\t\t\t\tonToolArgumentValidation: usesForegroundModel ? agent.onToolArgumentValidation : undefined,\n\t\t\t\t\ttoolValidationEscalationThreshold: agent.toolValidationEscalationThreshold,\n\t\t\t\t\tonToolValidationEscalation: usesForegroundModel ? agent.onToolValidationEscalation : undefined,\n\t\t\t\t\tbeforeToolCall: opts.beforeToolCall,\n\t\t\t\t\tafterToolCall: opts.afterToolCall,\n\t\t\t\t\tshouldStopAfterTurn: () => {\n\t\t\t\t\t\tcompletedTurns += 1;\n\t\t\t\t\t\treturn completedTurns >= maxTurns;\n\t\t\t\t\t},\n\t\t\t\t\tconvertToLlm: agent.convertToLlm,\n\t\t\t\t};\n\t\t\t\tconst messages = await runAgentLoop(\n\t\t\t\t\topts.messages,\n\t\t\t\t\tchildContext,\n\t\t\t\t\tloopConfig,\n\t\t\t\t\t() => {},\n\t\t\t\t\topts.signal,\n\t\t\t\t\tagent.streamFn,\n\t\t\t\t);\n\t\t\t\tconst assistantMessages = messages.filter(\n\t\t\t\t\t(message): message is AssistantMessage => message.role === \"assistant\",\n\t\t\t\t);\n\t\t\t\tlet finalAssistant = assistantMessages.at(-1);\n\t\t\t\tif (!finalAssistant) {\n\t\t\t\t\tthrow new Error(\"runIsolatedCompletion: child loop produced no assistant message\");\n\t\t\t\t}\n\n\t\t\t\tconst hasFinalText = finalAssistant.content.some(\n\t\t\t\t\t(content) => content.type === \"text\" && content.text.trim().length > 0,\n\t\t\t\t);\n\t\t\t\tconst endedOnToolCall = finalAssistant.content.some((content) => content.type === \"toolCall\");\n\t\t\t\tif (opts.finalTextPrompt && !hasFinalText && endedOnToolCall && !opts.signal?.aborted) {\n\t\t\t\t\t// A hard turn bound may stop immediately after successful tool execution. Preserve that bound,\n\t\t\t\t\t// then allow exactly one tool-free synthesis call so the gathered work is not thrown away.\n\t\t\t\t\tconst finalizationMessages = await agent.convertToLlm(messages);\n\t\t\t\t\tconst finalizationStream = await agent.streamFn(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsystemPrompt: opts.systemPrompt,\n\t\t\t\t\t\t\tmessages: [\n\t\t\t\t\t\t\t\t...finalizationMessages,\n\t\t\t\t\t\t\t\t{ role: \"user\", content: opts.finalTextPrompt, timestamp: Date.now() },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\ttools: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\toptions,\n\t\t\t\t\t);\n\t\t\t\t\tfinalAssistant = await finalizationStream.result();\n\t\t\t\t\tassistantMessages.push(finalAssistant);\n\t\t\t\t}\n\n\t\t\t\tconst usage = assistantMessages.reduce<Usage>(\n\t\t\t\t\t(total, message) => ({\n\t\t\t\t\t\tinput: total.input + message.usage.input,\n\t\t\t\t\t\toutput: total.output + message.usage.output,\n\t\t\t\t\t\tcacheRead: total.cacheRead + message.usage.cacheRead,\n\t\t\t\t\t\tcacheWrite: total.cacheWrite + message.usage.cacheWrite,\n\t\t\t\t\t\ttotalTokens: total.totalTokens + message.usage.totalTokens,\n\t\t\t\t\t\tcost: {\n\t\t\t\t\t\t\tinput: total.cost.input + message.usage.cost.input,\n\t\t\t\t\t\t\toutput: total.cost.output + message.usage.cost.output,\n\t\t\t\t\t\t\tcacheRead: total.cost.cacheRead + message.usage.cost.cacheRead,\n\t\t\t\t\t\t\tcacheWrite: total.cost.cacheWrite + message.usage.cost.cacheWrite,\n\t\t\t\t\t\t\ttotal: total.cost.total + message.usage.cost.total,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tconst text = finalAssistant.content\n\t\t\t\t\t.filter((content): content is TextContent => content.type === \"text\")\n\t\t\t\t\t.map((content) => content.text)\n\t\t\t\t\t.join(\"\");\n\t\t\t\treturn { text, usage, stopReason: finalAssistant.stopReason };\n\t\t\t}\n\n\t\t\tconst stream = await this.deps.getAgent().streamFn(model, context, options);\n\t\t\tconst result = await stream.result();\n\t\t\tconst text = result.content\n\t\t\t\t.filter((c): c is TextContent => c.type === \"text\")\n\t\t\t\t.map((c) => c.text)\n\t\t\t\t.join(\"\");\n\t\t\tconst usage: Usage = result.usage ?? {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t};\n\t\t\treturn { text, usage, stopReason: result.stopReason };\n\t\t} finally {\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\t/**\n\t * Native end-of-loop reflection pass (R2). Demand-gates (zero-I/O), and when warranted runs the\n\t * {@link ReflectionEngine} via an isolated completion ({@link runIsolatedCompletion}), applies the\n\t * resulting memory writes through the bundled `memory` tool, and accounts the reflection's token\n\t * cost via the cost-aggregation surface so it stays visible and net-negative-auditable.\n\t *\n\t * Returns `null` when the gate skips (or in a child session, which must not learn). The whole pass\n\t * is best-effort: a model/parse error yields no writes, never throws into the caller.\n\t */\n\tasync runReflectionPass(input: {\n\t\tsignals: DemandSignals;\n\t\trecentTurnText: string;\n\t\tmodel?: Model<Api>;\n\t\tthinkingLevel?: ThinkingLevel;\n\t\tsignal?: AbortSignal;\n\t\t/** Stable id so a duplicate scheduling/retry of the same pass can't double-count its cost. */\n\t\treportId?: string;\n\t}): Promise<ReflectionResult | null> {\n\t\tif (this.deps.isChildSession() || this.deps.isDisposed()) return null;\n\t\tconst plan = decideDemand(input.signals);\n\t\tif (plan.act === \"skip\") return null;\n\n\t\t// Bug #21: tie this background pass to the session lifetime. Disposing the session aborts the\n\t\t// in-flight completion (input.signal can add a more specific abort).\n\t\tconst signal = input.signal\n\t\t\t? AbortSignal.any([input.signal, this.deps.getReflectionSignal()])\n\t\t\t: this.deps.getReflectionSignal();\n\n\t\tconst complete = (systemPrompt: string, userPrompt: string) =>\n\t\t\tthis.runIsolatedCompletion({\n\t\t\t\tsystemPrompt,\n\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\tmodel: input.model,\n\t\t\t\tthinkingLevel: input.thinkingLevel ?? \"low\",\n\t\t\t\tmaxTokens: plan.tokenBudget,\n\t\t\t\tsignal,\n\t\t\t\t// The reflection system prompt is static (#33) — let the provider cache the prefix so\n\t\t\t\t// repeated passes only pay for the variable tail.\n\t\t\t\tcacheRetention: \"short\",\n\t\t\t\tlaneKind: \"reflection\",\n\t\t\t});\n\n\t\tconst result = await new ReflectionEngine().reflect({\n\t\t\trecentTurnText: input.recentTurnText,\n\t\t\t// Read memory FRESH (not the prefix-cache-frozen system-prompt block) so confront-before-write\n\t\t\t// sees writes made earlier this session.\n\t\t\texistingMemory: this.deps.getMemoryManager().buildSystemPromptBlockFresh() || \"\",\n\t\t\tplan,\n\t\t\tcomplete,\n\t\t});\n\n\t\t// Bug #21: if the session was disposed while the completion was in flight, do NOT write memory\n\t\t// or skills against the dead session.\n\t\tif (this.deps.isDisposed()) return result;\n\n\t\t// Learning apply policy: every durable write is converted to a proposal, decided by the\n\t\t// learning gate, and audited with a rollback plan. With the policy disabled (default) the\n\t\t// legacy direct-apply behavior is preserved — but now leaves audit records with rollback info.\n\t\tconst policy = this.deps.getSettingsManager().getLearningPolicySettings();\n\t\t// The audit id sequence counts STORED snapshots only: it reseeds from the stored count on\n\t\t// every pass, so advancing it for a no-op (which stores nothing) would make later passes\n\t\t// reuse ids — and rollback keys on the id, so a collision blocks or misdirects rollback.\n\t\tlet auditSequence = getLearningAuditSnapshots(this.deps.getSessionManager().getEntries()).length;\n\t\t// G6 evidence strength: durable proposals accumulate observation counts across passes/sessions\n\t\t// so the gate can distinguish a one-off cue from a repeatedly-confirmed lesson. Built once per\n\t\t// pass; every increment is best-effort (store IO must never break reflection).\n\t\tconst observationStore = ObservationStore.forAgentDir(this.deps.getAgentDir());\n\t\tlet writeIndex = 0;\n\t\tfor (const write of result.writes) {\n\t\t\twriteIndex += 1;\n\t\t\tconst proposalId = `${input.reportId ?? \"reflection\"}-w${writeIndex}`;\n\t\t\tconst proposal = proposalFromReflectionWrite(write, proposalId);\n\t\t\tconst rollback = rollbackPlanForReflectionWrite(write);\n\t\t\tlet observations = 1;\n\t\t\tif (policy.enabled) {\n\t\t\t\ttry {\n\t\t\t\t\tobservations = observationStore.increment(observationKey(proposal.layer, proposal.summary));\n\t\t\t\t} catch {\n\t\t\t\t\t// A store read/write failure falls back to a fresh count of 1, which keeps the gate\n\t\t\t\t\t// proposal-first (never spuriously auto-applies) rather than crashing the pass.\n\t\t\t\t\tobservations = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst decision: LearningDecision = policy.enabled\n\t\t\t\t? evaluateLearningDecision({\n\t\t\t\t\t\tproposal,\n\t\t\t\t\t\tconfidence: policy.reflectionSourceConfidence,\n\t\t\t\t\t\tobservations,\n\t\t\t\t\t\t// A replace/remove supersedes an existing durable fact — the reflection engine's\n\t\t\t\t\t\t// confront-before-write conflict signal — so it routes through approval instead of\n\t\t\t\t\t\t// silently overwriting prior memory. Additive writes contradict nothing.\n\t\t\t\t\t\tcontradictions: contradictionsForReflectionWrite(write),\n\t\t\t\t\t\tsettings: {\n\t\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\t\tautoApplyEnabled: policy.autoApplyEnabled,\n\t\t\t\t\t\t\tconfidenceThreshold: policy.confidenceThreshold,\n\t\t\t\t\t\t\tminObservations: policy.minObservations,\n\t\t\t\t\t\t\tallowedAutoApplyLayers: policy.allowedAutoApplyLayers,\n\t\t\t\t\t\t\trequireRollbackPlan: policy.requireRollbackPlan,\n\t\t\t\t\t\t\tautoApplySupersessions: policy.autoApplySupersessions,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t: {\n\t\t\t\t\t\tkind: \"apply\",\n\t\t\t\t\t\treasonCode: \"learning_policy_disabled_legacy_apply\",\n\t\t\t\t\t\tconfidence: 0,\n\t\t\t\t\t\tsummary: proposal.summary,\n\t\t\t\t\t\trequiresApproval: false,\n\t\t\t\t\t};\n\n\t\t\tthis.deps.saveLearningDecisionSnapshot(decision);\n\t\t\t// G3: learning-gate outcome. Codes/numbers only — never the proposal summary/memory text.\n\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.learningDecision,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tpayload: {\n\t\t\t\t\tkind: decision.kind,\n\t\t\t\t\treasonCode: decision.reasonCode,\n\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\tconfidence: decision.confidence,\n\t\t\t\t\trequiresApproval: decision.requiresApproval,\n\t\t\t\t},\n\t\t\t});\n\t\t\t// G8: a proposal that needs human sign-off is an approval REQUEST. Codes/layer only —\n\t\t\t// never the proposal summary/memory text (those live only in the audit snapshot).\n\t\t\tif (decision.requiresApproval) {\n\t\t\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.approvalRequest,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tkind: decision.kind,\n\t\t\t\t\t\treasonCode: decision.reasonCode,\n\t\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\t// An automatic skill promotion the gate would otherwise apply must still clear the same\n\t\t\t// skill_audit overlap check the model-invoked `skillify` tool enforces — otherwise reflection\n\t\t\t// can silently write a near-duplicate SKILL.md. A non-overlapping skill is unaffected\n\t\t\t// (skillPromotionBlock stays undefined) and promotes exactly as before.\n\t\t\tconst skillPromotionBlock =\n\t\t\t\twrite.kind === \"promote_skill\" && decision.kind === \"apply\"\n\t\t\t\t\t? this._checkSkillPromotionOverlap(write)\n\t\t\t\t\t: undefined;\n\n\t\t\t// The gate's decision and the write's actual outcome are two different questions: the memory\n\t\t\t// tool can refuse a write (budget exceeded, drift, threat) via details.success:false without\n\t\t\t// throwing. Capture that outcome instead of assuming \"decision.kind === apply\" means it landed\n\t\t\t// — otherwise a refused write leaves a phantom \"apply\" audit whose rollback later fails\n\t\t\t// not-found (or, worse, misfires against whatever now occupies that text).\n\t\t\tconst applied =\n\t\t\t\tdecision.kind === \"apply\" && !skillPromotionBlock ? await this._applyReflectionWrite(write, signal) : false;\n\t\t\tconst writeFailed = decision.kind === \"apply\" && !skillPromotionBlock && !applied;\n\t\t\tif (decision.kind !== \"no-op\") {\n\t\t\t\tauditSequence += 1;\n\t\t\t\tappendLearningAuditSnapshot(this.deps.getSessionManager(), {\n\t\t\t\t\tid: `audit-${auditSequence}`,\n\t\t\t\t\tproposalId,\n\t\t\t\t\tlayer: proposal.layer,\n\t\t\t\t\taction: skillPromotionBlock\n\t\t\t\t\t\t? \"propose\"\n\t\t\t\t\t\t: writeFailed\n\t\t\t\t\t\t\t? \"apply_failed\"\n\t\t\t\t\t\t\t: decision.kind === \"apply\"\n\t\t\t\t\t\t\t\t? \"apply\"\n\t\t\t\t\t\t\t\t: \"propose\",\n\t\t\t\t\tsummary: skillPromotionBlock ? `${proposal.summary} — ${skillPromotionBlock.note}` : proposal.summary,\n\t\t\t\t\treasonCode: skillPromotionBlock\n\t\t\t\t\t\t? skillPromotionBlock.reasonCode\n\t\t\t\t\t\t: writeFailed\n\t\t\t\t\t\t\t? APPLY_WRITE_REFUSED_REASON_CODE\n\t\t\t\t\t\t\t: decision.reasonCode,\n\t\t\t\t\tdecision,\n\t\t\t\t\t// No rollback plan on a failed apply or a held/proposed promotion — nothing durable\n\t\t\t\t\t// landed in either case, so there is nothing to undo.\n\t\t\t\t\trollback: skillPromotionBlock || writeFailed ? undefined : rollback,\n\t\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Account the reflection's spend so it surfaces in the footer roll-up (net-token visibility).\n\t\t// Idempotent on reportId so a retried/duplicated pass cannot double-count.\n\t\tif (result.usage.cost.total > 0 || result.usage.totalTokens > 0) {\n\t\t\tthis.deps.addSpawnedUsage(result.usage, { label: \"reflection\", reportId: input.reportId });\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetLearningAuditRecords(): LearningAuditRecord[] {\n\t\treturn getLearningAuditSnapshots(this.deps.getSessionManager().getEntries());\n\t}\n\n\t/**\n\t * Roll back one applied durable learning change by executing the inverse operation recorded in\n\t * its audit record (memory ops run through the same bundled memory-tool path as the original\n\t * apply; promoted skills are archived). Appends a linked \"rollback\" audit record on success so\n\t * the change history stays complete and a change cannot be rolled back twice.\n\t */\n\tasync rollbackLearningWrite(auditId: string): Promise<{ ok: boolean; reason: string }> {\n\t\tif (this.deps.isDisposed()) return { ok: false, reason: \"session_disposed\" };\n\n\t\tconst audits = this.getLearningAuditRecords();\n\t\tconst audit = audits.find((record) => record.id === auditId);\n\t\tif (!audit) return { ok: false, reason: \"audit_not_found\" };\n\t\tif (audit.action !== \"apply\") return { ok: false, reason: \"not_an_applied_change\" };\n\t\tif (audits.some((record) => record.action === \"rollback\" && record.rollbackOf === auditId)) {\n\t\t\treturn { ok: false, reason: \"already_rolled_back\" };\n\t\t}\n\t\tconst rollback = audit.rollback;\n\t\tif (!rollback) return { ok: false, reason: \"no_rollback_plan\" };\n\n\t\t// Every inverse must be VERIFIED-applied before the rollback audit is appended: a silently\n\t\t// failed inverse that still recorded \"rollback\" would permanently self-lock the change\n\t\t// behind already_rolled_back while the durable write is in fact still live.\n\t\tswitch (rollback.kind) {\n\t\t\tcase \"memory_remove\": {\n\t\t\t\tif (!rollback.target) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tif (!(await this._applyReflectionWrite({ kind: \"memory_remove\", target: rollback.target }))) {\n\t\t\t\t\treturn { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"memory_restore\": {\n\t\t\t\tif (!rollback.target || rollback.previous === undefined) {\n\t\t\t\t\treturn { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\t}\n\t\t\t\tconst applied = await this._applyReflectionWrite({\n\t\t\t\t\tkind: \"memory_replace\",\n\t\t\t\t\ttarget: rollback.target,\n\t\t\t\t\ttext: rollback.previous,\n\t\t\t\t});\n\t\t\t\tif (!applied) return { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"memory_add\": {\n\t\t\t\tif (rollback.previous === undefined) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tconst applied = await this._applyReflectionWrite({\n\t\t\t\t\tkind: \"memory_add\",\n\t\t\t\t\tsection: \"MEMORY\",\n\t\t\t\t\ttext: rollback.previous,\n\t\t\t\t});\n\t\t\t\tif (!applied) return { ok: false, reason: \"rollback_apply_failed\" };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"archive_skill\": {\n\t\t\t\tif (!rollback.target) return { ok: false, reason: \"missing_rollback_target\" };\n\t\t\t\tif (!this.deps.archivePromotedSkill(rollback.target)) {\n\t\t\t\t\treturn { ok: false, reason: \"skill_archive_failed\" };\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tappendLearningAuditSnapshot(this.deps.getSessionManager(), {\n\t\t\tid: `${audit.id}-rollback`,\n\t\t\tproposalId: audit.proposalId,\n\t\t\tlayer: audit.layer,\n\t\t\taction: \"rollback\",\n\t\t\tsummary: `Rolled back: ${audit.summary}`,\n\t\t\treasonCode: \"user_requested_rollback\",\n\t\t\tdecision: audit.decision,\n\t\t\trollbackOf: audit.id,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t});\n\t\treturn { ok: true, reason: \"rollback_applied\" };\n\t}\n\n\t/**\n\t * Apply one reflection write through the bundled `memory` tool. `memory_replace`/`memory_remove`\n\t * don't carry a target file, so we try MEMORY.md first and fall back to USER.md when the substring\n\t * isn't found there. Never throws (reflection must never break a turn); returns whether the write\n\t * actually applied so callers that MUST know — rollback's once-only accounting — can react instead\n\t * of recording a success that never happened.\n\t */\n\tprivate async _applyReflectionWrite(write: ReflectionWrite, signal?: AbortSignal): Promise<boolean> {\n\t\t// R7 memory-to-behavior: a recurring procedure is compiled into an executable skill file rather\n\t\t// than stored as a flat fact. Written under the agent skills dir so it loads like any user skill.\n\t\tif (write.kind === \"promote_skill\") {\n\t\t\treturn this._promoteReflectionSkill(write.name, write.description, write.body);\n\t\t}\n\n\t\ttype MemResult = { details?: { success?: boolean; error?: string } };\n\t\ttype MemExec = (\n\t\t\ttoolCallId: string,\n\t\t\tparams: { action: string; target: string; content?: string; oldContent?: string },\n\t\t\tsignal: AbortSignal | undefined,\n\t\t\tonUpdate: undefined,\n\t\t\tctx: undefined,\n\t\t) => Promise<MemResult>;\n\t\tconst memTool = this.deps\n\t\t\t.getMemoryManager()\n\t\t\t.getToolDefinitions()\n\t\t\t.find((t) => t.name === \"memory\");\n\t\tconst exec = memTool?.execute as unknown as MemExec | undefined;\n\t\tif (!exec) return false;\n\n\t\tconst run = (params: Parameters<MemExec>[1]) => exec(\"reflection\", params, signal, undefined, undefined);\n\n\t\tif (write.kind === \"memory_add\") {\n\t\t\ttry {\n\t\t\t\tconst res = await run({\n\t\t\t\t\taction: \"add\",\n\t\t\t\t\ttarget: write.section === \"USER\" ? \"user\" : \"memory\",\n\t\t\t\t\tcontent: write.text,\n\t\t\t\t});\n\t\t\t\treturn res?.details?.success === true;\n\t\t\t} catch {\n\t\t\t\t// best-effort; reflection writes must never throw into the turn loop\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// replace / remove carry no target file — try MEMORY.md, then USER.md. The memory tool reports\n\t\t// outcomes via `details.success` (it catches its own errors rather than throwing). Only a\n\t\t// genuine \"not found in the file\" justifies trying the other file; a real failure for a file\n\t\t// (budget exceeded / drift) must NOT fall through and mutate the wrong target.\n\t\tfor (const target of [\"memory\", \"user\"] as const) {\n\t\t\ttry {\n\t\t\t\tconst params =\n\t\t\t\t\twrite.kind === \"memory_replace\"\n\t\t\t\t\t\t? { action: \"replace\", target, oldContent: write.target, content: write.text }\n\t\t\t\t\t\t: { action: \"remove\", target, oldContent: write.target };\n\t\t\t\tconst res = await run(params);\n\t\t\t\tif (res?.details?.success === true) return true; // applied\n\t\t\t\tif (!/not found/i.test(String(res?.details?.error ?? \"\"))) return false; // real failure — don't misapply\n\t\t\t\t// substring simply absent from this file — try the next target\n\t\t\t} catch {\n\t\t\t\t// defensive: if the tool ever does throw, try the next target\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * The same skill_audit overlap check the model-invoked `skillify` tool enforces\n\t * (tools/skillify.ts → tools/skill-audit.ts's `runSkillAudit`), run before an AUTOMATIC promotion\n\t * so the reflection engine can never silently write a near-duplicate SKILL.md. Reuses the audit\n\t * seam unchanged (never duplicated) against the same already-loaded skills universe skillify\n\t * compares a draft against. Returns a block reason when the draft overlaps an existing skill above\n\t * the audit's own similarity threshold, or when the audit itself fails (the promotion is held, not\n\t * written unaudited); undefined when clear to promote. Never throws — mirrors every other\n\t * best-effort check in this file.\n\t */\n\tprivate _checkSkillPromotionOverlap(write: {\n\t\tname: string;\n\t\tdescription: string;\n\t\tbody: string;\n\t}): { reasonCode: string; note: string } | undefined {\n\t\ttry {\n\t\t\tconst cwd = this.deps.getCwd?.() ?? process.cwd();\n\t\t\tconst audit = runSkillAudit(cwd, write);\n\t\t\tconst overlap = audit.nearDuplicates.find((d) => d.a === \"[draft]\" || d.b === \"[draft]\");\n\t\t\tif (!overlap) return undefined;\n\t\t\tconst otherPath = overlap.a === \"[draft]\" ? overlap.b : overlap.a;\n\t\t\t// Every skill file is named \"SKILL.md\" — unlike skillify's own display formatter (which takes\n\t\t\t// the path's last segment and always shows that literal filename), look up the declared\n\t\t\t// frontmatter name so the proposal actually names the skill it overlaps with.\n\t\t\tconst otherName = audit.skills.find((s) => s.path === otherPath)?.name ?? otherPath;\n\t\t\treturn {\n\t\t\t\treasonCode: SKILL_OVERLAP_CONSOLIDATION_REASON_CODE,\n\t\t\t\tnote: `overlaps existing skill \"${otherName}\" (${(overlap.similarity * 100).toFixed(0)}% similar) — consolidation proposed instead of a duplicate write`,\n\t\t\t};\n\t\t} catch {\n\t\t\t// Bounded, observable degradation via the promote path's existing error-reporting shape: an\n\t\t\t// audit failure must never throw into the reflection pass, but it also must not silently\n\t\t\t// fall through to an unaudited write — hold the promotion and record why.\n\t\t\treturn {\n\t\t\t\treasonCode: SKILL_AUDIT_UNAVAILABLE_REASON_CODE,\n\t\t\t\tnote: \"skill overlap audit failed; promotion held rather than written unaudited\",\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * R7: write a reflection-promoted skill as `<agentDir>/skills/<name>/SKILL.md` so it loads like any\n\t * user skill. Best-effort; never clobbers an existing (hand-authored) skill of the same name. The\n\t * overlap audit runs at the call site in {@link runReflectionPass} — a write only reaches here\n\t * once the draft has already cleared it.\n\t */\n\tprivate _promoteReflectionSkill(rawName: string, description: string, body: string): boolean {\n\t\tconst name = rawName\n\t\t\t.trim()\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9-]+/g, \"-\")\n\t\t\t.replace(/^-+|-+$/g, \"\")\n\t\t\t.slice(0, 64);\n\t\tif (!name || !body.trim()) return false;\n\t\ttry {\n\t\t\tconst dir = join(this.deps.getAgentDir(), \"skills\", name);\n\t\t\tconst file = join(dir, \"SKILL.md\");\n\t\t\tif (existsSync(file)) return false; // do not overwrite an existing skill\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t\tconst safeDescription = description.replace(/[\\r\\n]+/g, \" \").trim();\n\t\t\t// `promoted: true` marks this as reflection-generated so the curator (#32) can lifecycle-manage\n\t\t\t// it (archive/consolidate) WITHOUT ever touching hand-authored user skills.\n\t\t\tconst content = `---\\nname: ${name}\\ndescription: ${safeDescription}\\npromoted: true\\n---\\n\\n<!-- Auto-generated by the reflection engine (R7 memory-to-behavior). Review and refine. -->\\n\\n${body.trim()}\\n`;\n\t\t\twriteFileSync(file, content, \"utf-8\");\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// promotion must never break a turn\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"]}