@caupulican/pi-adaptative 0.80.86 → 0.80.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/dist/core/agent-session.d.ts +412 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +2053 -41
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/approval-gate.d.ts +4 -0
  7. package/dist/core/autonomy/approval-gate.d.ts.map +1 -0
  8. package/dist/core/autonomy/approval-gate.js +27 -0
  9. package/dist/core/autonomy/approval-gate.js.map +1 -0
  10. package/dist/core/autonomy/bounded-completion.d.ts +27 -0
  11. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -0
  12. package/dist/core/autonomy/bounded-completion.js +44 -0
  13. package/dist/core/autonomy/bounded-completion.js.map +1 -0
  14. package/dist/core/autonomy/contracts.d.ts +129 -0
  15. package/dist/core/autonomy/contracts.d.ts.map +1 -0
  16. package/dist/core/autonomy/contracts.js +2 -0
  17. package/dist/core/autonomy/contracts.js.map +1 -0
  18. package/dist/core/autonomy/gates.d.ts +15 -0
  19. package/dist/core/autonomy/gates.d.ts.map +1 -0
  20. package/dist/core/autonomy/gates.js +205 -0
  21. package/dist/core/autonomy/gates.js.map +1 -0
  22. package/dist/core/autonomy/lane-tracker.d.ts +48 -0
  23. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -0
  24. package/dist/core/autonomy/lane-tracker.js +125 -0
  25. package/dist/core/autonomy/lane-tracker.js.map +1 -0
  26. package/dist/core/autonomy/path-scope.d.ts +9 -0
  27. package/dist/core/autonomy/path-scope.d.ts.map +1 -0
  28. package/dist/core/autonomy/path-scope.js +122 -0
  29. package/dist/core/autonomy/path-scope.js.map +1 -0
  30. package/dist/core/autonomy/risk-assessment.d.ts +3 -0
  31. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -0
  32. package/dist/core/autonomy/risk-assessment.js +122 -0
  33. package/dist/core/autonomy/risk-assessment.js.map +1 -0
  34. package/dist/core/autonomy/session-lane-record.d.ts +10 -0
  35. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -0
  36. package/dist/core/autonomy/session-lane-record.js +36 -0
  37. package/dist/core/autonomy/session-lane-record.js.map +1 -0
  38. package/dist/core/autonomy/status.d.ts +40 -0
  39. package/dist/core/autonomy/status.d.ts.map +1 -0
  40. package/dist/core/autonomy/status.js +107 -0
  41. package/dist/core/autonomy/status.js.map +1 -0
  42. package/dist/core/autonomy/subagent-prompt.d.ts +21 -0
  43. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -0
  44. package/dist/core/autonomy/subagent-prompt.js +28 -0
  45. package/dist/core/autonomy/subagent-prompt.js.map +1 -0
  46. package/dist/core/autonomy/telemetry-events.d.ts +18 -0
  47. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -0
  48. package/dist/core/autonomy/telemetry-events.js +60 -0
  49. package/dist/core/autonomy/telemetry-events.js.map +1 -0
  50. package/dist/core/context/artifact-retrieval.d.ts +49 -0
  51. package/dist/core/context/artifact-retrieval.d.ts.map +1 -0
  52. package/dist/core/context/artifact-retrieval.js +49 -0
  53. package/dist/core/context/artifact-retrieval.js.map +1 -0
  54. package/dist/core/context/brain-curator.d.ts +88 -0
  55. package/dist/core/context/brain-curator.d.ts.map +1 -0
  56. package/dist/core/context/brain-curator.js +192 -0
  57. package/dist/core/context/brain-curator.js.map +1 -0
  58. package/dist/core/context/context-artifacts.d.ts +94 -0
  59. package/dist/core/context/context-artifacts.d.ts.map +1 -0
  60. package/dist/core/context/context-artifacts.js +307 -0
  61. package/dist/core/context/context-artifacts.js.map +1 -0
  62. package/dist/core/context/context-audit.d.ts +66 -0
  63. package/dist/core/context/context-audit.d.ts.map +1 -0
  64. package/dist/core/context/context-audit.js +173 -0
  65. package/dist/core/context/context-audit.js.map +1 -0
  66. package/dist/core/context/context-composition.d.ts +122 -0
  67. package/dist/core/context/context-composition.d.ts.map +1 -0
  68. package/dist/core/context/context-composition.js +163 -0
  69. package/dist/core/context/context-composition.js.map +1 -0
  70. package/dist/core/context/context-item.d.ts +117 -0
  71. package/dist/core/context/context-item.d.ts.map +1 -0
  72. package/dist/core/context/context-item.js +36 -0
  73. package/dist/core/context/context-item.js.map +1 -0
  74. package/dist/core/context/context-prompt-enforcement.d.ts +86 -0
  75. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -0
  76. package/dist/core/context/context-prompt-enforcement.js +168 -0
  77. package/dist/core/context/context-prompt-enforcement.js.map +1 -0
  78. package/dist/core/context/context-prompt-policy.d.ts +90 -0
  79. package/dist/core/context/context-prompt-policy.d.ts.map +1 -0
  80. package/dist/core/context/context-prompt-policy.js +73 -0
  81. package/dist/core/context/context-prompt-policy.js.map +1 -0
  82. package/dist/core/context/context-retention.d.ts +36 -0
  83. package/dist/core/context/context-retention.d.ts.map +1 -0
  84. package/dist/core/context/context-retention.js +108 -0
  85. package/dist/core/context/context-retention.js.map +1 -0
  86. package/dist/core/context/context-store.d.ts +37 -0
  87. package/dist/core/context/context-store.d.ts.map +1 -0
  88. package/dist/core/context/context-store.js +45 -0
  89. package/dist/core/context/context-store.js.map +1 -0
  90. package/dist/core/context/memory-diagnostics.d.ts +50 -0
  91. package/dist/core/context/memory-diagnostics.d.ts.map +1 -0
  92. package/dist/core/context/memory-diagnostics.js +43 -0
  93. package/dist/core/context/memory-diagnostics.js.map +1 -0
  94. package/dist/core/context/memory-index-store.d.ts +28 -0
  95. package/dist/core/context/memory-index-store.d.ts.map +1 -0
  96. package/dist/core/context/memory-index-store.js +38 -0
  97. package/dist/core/context/memory-index-store.js.map +1 -0
  98. package/dist/core/context/memory-prompt-block.d.ts +34 -0
  99. package/dist/core/context/memory-prompt-block.d.ts.map +1 -0
  100. package/dist/core/context/memory-prompt-block.js +58 -0
  101. package/dist/core/context/memory-prompt-block.js.map +1 -0
  102. package/dist/core/context/memory-provider-contract.d.ts +114 -0
  103. package/dist/core/context/memory-provider-contract.d.ts.map +1 -0
  104. package/dist/core/context/memory-provider-contract.js +121 -0
  105. package/dist/core/context/memory-provider-contract.js.map +1 -0
  106. package/dist/core/context/memory-retrieval.d.ts +27 -0
  107. package/dist/core/context/memory-retrieval.d.ts.map +1 -0
  108. package/dist/core/context/memory-retrieval.js +91 -0
  109. package/dist/core/context/memory-retrieval.js.map +1 -0
  110. package/dist/core/context/okf-memory-provider.d.ts +26 -0
  111. package/dist/core/context/okf-memory-provider.d.ts.map +1 -0
  112. package/dist/core/context/okf-memory-provider.js +154 -0
  113. package/dist/core/context/okf-memory-provider.js.map +1 -0
  114. package/dist/core/context/okf-memory.d.ts +42 -0
  115. package/dist/core/context/okf-memory.d.ts.map +1 -0
  116. package/dist/core/context/okf-memory.js +175 -0
  117. package/dist/core/context/okf-memory.js.map +1 -0
  118. package/dist/core/context/policy-engine.d.ts +66 -0
  119. package/dist/core/context/policy-engine.d.ts.map +1 -0
  120. package/dist/core/context/policy-engine.js +171 -0
  121. package/dist/core/context/policy-engine.js.map +1 -0
  122. package/dist/core/context/policy-types.d.ts +102 -0
  123. package/dist/core/context/policy-types.d.ts.map +1 -0
  124. package/dist/core/context/policy-types.js +7 -0
  125. package/dist/core/context/policy-types.js.map +1 -0
  126. package/dist/core/context/sqlite-runtime-index.d.ts +19 -0
  127. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -0
  128. package/dist/core/context/sqlite-runtime-index.js +344 -0
  129. package/dist/core/context/sqlite-runtime-index.js.map +1 -0
  130. package/dist/core/context/storage-authority.d.ts +20 -0
  131. package/dist/core/context/storage-authority.d.ts.map +1 -0
  132. package/dist/core/context/storage-authority.js +51 -0
  133. package/dist/core/context/storage-authority.js.map +1 -0
  134. package/dist/core/context/tool-output-packer.d.ts +75 -0
  135. package/dist/core/context/tool-output-packer.d.ts.map +1 -0
  136. package/dist/core/context/tool-output-packer.js +77 -0
  137. package/dist/core/context/tool-output-packer.js.map +1 -0
  138. package/dist/core/context-gc.d.ts +13 -0
  139. package/dist/core/context-gc.d.ts.map +1 -1
  140. package/dist/core/context-gc.js +6 -0
  141. package/dist/core/context-gc.js.map +1 -1
  142. package/dist/core/cost/session-usage.d.ts +20 -0
  143. package/dist/core/cost/session-usage.d.ts.map +1 -0
  144. package/dist/core/cost/session-usage.js +164 -0
  145. package/dist/core/cost/session-usage.js.map +1 -0
  146. package/dist/core/delegation/session-worker-result.d.ts +10 -0
  147. package/dist/core/delegation/session-worker-result.d.ts.map +1 -0
  148. package/dist/core/delegation/session-worker-result.js +36 -0
  149. package/dist/core/delegation/session-worker-result.js.map +1 -0
  150. package/dist/core/delegation/worker-result.d.ts +9 -0
  151. package/dist/core/delegation/worker-result.d.ts.map +1 -0
  152. package/dist/core/delegation/worker-result.js +152 -0
  153. package/dist/core/delegation/worker-result.js.map +1 -0
  154. package/dist/core/delegation/worker-runner.d.ts +58 -0
  155. package/dist/core/delegation/worker-runner.d.ts.map +1 -0
  156. package/dist/core/delegation/worker-runner.js +188 -0
  157. package/dist/core/delegation/worker-runner.js.map +1 -0
  158. package/dist/core/extensions/builtin.d.ts +5 -1
  159. package/dist/core/extensions/builtin.d.ts.map +1 -1
  160. package/dist/core/extensions/builtin.js +23 -1
  161. package/dist/core/extensions/builtin.js.map +1 -1
  162. package/dist/core/footer-data-provider.d.ts +5 -1
  163. package/dist/core/footer-data-provider.d.ts.map +1 -1
  164. package/dist/core/footer-data-provider.js +13 -0
  165. package/dist/core/footer-data-provider.js.map +1 -1
  166. package/dist/core/goals/goal-continuation-controller.d.ts +22 -0
  167. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -0
  168. package/dist/core/goals/goal-continuation-controller.js +88 -0
  169. package/dist/core/goals/goal-continuation-controller.js.map +1 -0
  170. package/dist/core/goals/goal-continuation-defaults.d.ts +10 -0
  171. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -0
  172. package/dist/core/goals/goal-continuation-defaults.js +10 -0
  173. package/dist/core/goals/goal-continuation-defaults.js.map +1 -0
  174. package/dist/core/goals/goal-continuation-prompt.d.ts +18 -0
  175. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -0
  176. package/dist/core/goals/goal-continuation-prompt.js +141 -0
  177. package/dist/core/goals/goal-continuation-prompt.js.map +1 -0
  178. package/dist/core/goals/goal-runtime-snapshot.d.ts +19 -0
  179. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -0
  180. package/dist/core/goals/goal-runtime-snapshot.js +23 -0
  181. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -0
  182. package/dist/core/goals/goal-state.d.ts +87 -0
  183. package/dist/core/goals/goal-state.d.ts.map +1 -0
  184. package/dist/core/goals/goal-state.js +259 -0
  185. package/dist/core/goals/goal-state.js.map +1 -0
  186. package/dist/core/goals/goal-tool-core.d.ts +66 -0
  187. package/dist/core/goals/goal-tool-core.d.ts.map +1 -0
  188. package/dist/core/goals/goal-tool-core.js +146 -0
  189. package/dist/core/goals/goal-tool-core.js.map +1 -0
  190. package/dist/core/goals/session-goal-state.d.ts +10 -0
  191. package/dist/core/goals/session-goal-state.d.ts.map +1 -0
  192. package/dist/core/goals/session-goal-state.js +35 -0
  193. package/dist/core/goals/session-goal-state.js.map +1 -0
  194. package/dist/core/learning/learning-audit.d.ts +45 -0
  195. package/dist/core/learning/learning-audit.d.ts.map +1 -0
  196. package/dist/core/learning/learning-audit.js +139 -0
  197. package/dist/core/learning/learning-audit.js.map +1 -0
  198. package/dist/core/learning/learning-gate.d.ts +29 -0
  199. package/dist/core/learning/learning-gate.d.ts.map +1 -0
  200. package/dist/core/learning/learning-gate.js +150 -0
  201. package/dist/core/learning/learning-gate.js.map +1 -0
  202. package/dist/core/learning/session-learning-decision.d.ts +10 -0
  203. package/dist/core/learning/session-learning-decision.d.ts.map +1 -0
  204. package/dist/core/learning/session-learning-decision.js +36 -0
  205. package/dist/core/learning/session-learning-decision.js.map +1 -0
  206. package/dist/core/model-capability.d.ts +41 -0
  207. package/dist/core/model-capability.d.ts.map +1 -0
  208. package/dist/core/model-capability.js +101 -0
  209. package/dist/core/model-capability.js.map +1 -0
  210. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  211. package/dist/core/model-router/config-diagnostics.js +1 -0
  212. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  213. package/dist/core/model-router/intent-classifier.d.ts +2 -0
  214. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  215. package/dist/core/model-router/intent-classifier.js +154 -9
  216. package/dist/core/model-router/intent-classifier.js.map +1 -1
  217. package/dist/core/model-router/route-judge.d.ts +54 -0
  218. package/dist/core/model-router/route-judge.d.ts.map +1 -0
  219. package/dist/core/model-router/route-judge.js +128 -0
  220. package/dist/core/model-router/route-judge.js.map +1 -0
  221. package/dist/core/model-router/status.d.ts +4 -1
  222. package/dist/core/model-router/status.d.ts.map +1 -1
  223. package/dist/core/model-router/status.js +30 -6
  224. package/dist/core/model-router/status.js.map +1 -1
  225. package/dist/core/model-router/tool-escalation.d.ts +4 -6
  226. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  227. package/dist/core/model-router/tool-escalation.js +1 -1
  228. package/dist/core/model-router/tool-escalation.js.map +1 -1
  229. package/dist/core/models/fitness-store.d.ts +40 -0
  230. package/dist/core/models/fitness-store.d.ts.map +1 -0
  231. package/dist/core/models/fitness-store.js +61 -0
  232. package/dist/core/models/fitness-store.js.map +1 -0
  233. package/dist/core/profile-registry.d.ts.map +1 -1
  234. package/dist/core/profile-registry.js +1 -1
  235. package/dist/core/profile-registry.js.map +1 -1
  236. package/dist/core/prompt-templates.d.ts +2 -0
  237. package/dist/core/prompt-templates.d.ts.map +1 -1
  238. package/dist/core/prompt-templates.js +12 -4
  239. package/dist/core/prompt-templates.js.map +1 -1
  240. package/dist/core/research/automata-provider.d.ts +5 -0
  241. package/dist/core/research/automata-provider.d.ts.map +1 -0
  242. package/dist/core/research/automata-provider.js +15 -0
  243. package/dist/core/research/automata-provider.js.map +1 -0
  244. package/dist/core/research/evidence-bundle.d.ts +10 -0
  245. package/dist/core/research/evidence-bundle.d.ts.map +1 -0
  246. package/dist/core/research/evidence-bundle.js +116 -0
  247. package/dist/core/research/evidence-bundle.js.map +1 -0
  248. package/dist/core/research/model-fitness.d.ts +82 -0
  249. package/dist/core/research/model-fitness.d.ts.map +1 -0
  250. package/dist/core/research/model-fitness.js +308 -0
  251. package/dist/core/research/model-fitness.js.map +1 -0
  252. package/dist/core/research/research-gate.d.ts +11 -0
  253. package/dist/core/research/research-gate.d.ts.map +1 -0
  254. package/dist/core/research/research-gate.js +82 -0
  255. package/dist/core/research/research-gate.js.map +1 -0
  256. package/dist/core/research/research-runner.d.ts +59 -0
  257. package/dist/core/research/research-runner.d.ts.map +1 -0
  258. package/dist/core/research/research-runner.js +155 -0
  259. package/dist/core/research/research-runner.js.map +1 -0
  260. package/dist/core/research/session-evidence-bundle.d.ts +11 -0
  261. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -0
  262. package/dist/core/research/session-evidence-bundle.js +55 -0
  263. package/dist/core/research/session-evidence-bundle.js.map +1 -0
  264. package/dist/core/resource-loader.d.ts.map +1 -1
  265. package/dist/core/resource-loader.js +4 -0
  266. package/dist/core/resource-loader.js.map +1 -1
  267. package/dist/core/settings-manager.d.ts +160 -4
  268. package/dist/core/settings-manager.d.ts.map +1 -1
  269. package/dist/core/settings-manager.js +304 -9
  270. package/dist/core/settings-manager.js.map +1 -1
  271. package/dist/core/skills.d.ts +4 -0
  272. package/dist/core/skills.d.ts.map +1 -1
  273. package/dist/core/skills.js +18 -6
  274. package/dist/core/skills.js.map +1 -1
  275. package/dist/core/slash-commands.d.ts.map +1 -1
  276. package/dist/core/slash-commands.js +10 -1
  277. package/dist/core/slash-commands.js.map +1 -1
  278. package/dist/core/toolkit/script-registry.d.ts +34 -0
  279. package/dist/core/toolkit/script-registry.d.ts.map +1 -0
  280. package/dist/core/toolkit/script-registry.js +71 -0
  281. package/dist/core/toolkit/script-registry.js.map +1 -0
  282. package/dist/core/toolkit/script-runner.d.ts +28 -0
  283. package/dist/core/toolkit/script-runner.d.ts.map +1 -0
  284. package/dist/core/toolkit/script-runner.js +48 -0
  285. package/dist/core/toolkit/script-runner.js.map +1 -0
  286. package/dist/core/tools/artifact-retrieve.d.ts +23 -0
  287. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -0
  288. package/dist/core/tools/artifact-retrieve.js +110 -0
  289. package/dist/core/tools/artifact-retrieve.js.map +1 -0
  290. package/dist/core/tools/delegate.d.ts +32 -0
  291. package/dist/core/tools/delegate.d.ts.map +1 -0
  292. package/dist/core/tools/delegate.js +60 -0
  293. package/dist/core/tools/delegate.js.map +1 -0
  294. package/dist/core/tools/fff-search-backend.d.ts +103 -0
  295. package/dist/core/tools/fff-search-backend.d.ts.map +1 -0
  296. package/dist/core/tools/fff-search-backend.js +151 -0
  297. package/dist/core/tools/fff-search-backend.js.map +1 -0
  298. package/dist/core/tools/find.d.ts +21 -1
  299. package/dist/core/tools/find.d.ts.map +1 -1
  300. package/dist/core/tools/find.js +183 -10
  301. package/dist/core/tools/find.js.map +1 -1
  302. package/dist/core/tools/goal.d.ts +35 -0
  303. package/dist/core/tools/goal.d.ts.map +1 -0
  304. package/dist/core/tools/goal.js +122 -0
  305. package/dist/core/tools/goal.js.map +1 -0
  306. package/dist/core/tools/grep.d.ts +21 -1
  307. package/dist/core/tools/grep.d.ts.map +1 -1
  308. package/dist/core/tools/grep.js +272 -27
  309. package/dist/core/tools/grep.js.map +1 -1
  310. package/dist/core/tools/index.d.ts +4 -1
  311. package/dist/core/tools/index.d.ts.map +1 -1
  312. package/dist/core/tools/index.js +9 -0
  313. package/dist/core/tools/index.js.map +1 -1
  314. package/dist/core/tools/model-fitness.d.ts +30 -0
  315. package/dist/core/tools/model-fitness.d.ts.map +1 -0
  316. package/dist/core/tools/model-fitness.js +38 -0
  317. package/dist/core/tools/model-fitness.js.map +1 -0
  318. package/dist/core/tools/run-toolkit-script.d.ts +24 -0
  319. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -0
  320. package/dist/core/tools/run-toolkit-script.js +103 -0
  321. package/dist/core/tools/run-toolkit-script.js.map +1 -0
  322. package/dist/core/tools/search-router.d.ts +75 -0
  323. package/dist/core/tools/search-router.d.ts.map +1 -0
  324. package/dist/core/tools/search-router.js +85 -0
  325. package/dist/core/tools/search-router.js.map +1 -0
  326. package/dist/modes/interactive/components/fitness-role-selector.d.ts +13 -0
  327. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -0
  328. package/dist/modes/interactive/components/fitness-role-selector.js +65 -0
  329. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -0
  330. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/footer.js +18 -16
  332. package/dist/modes/interactive/components/footer.js.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.d.ts +16 -1
  334. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/settings-selector.js +555 -11
  336. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  337. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  338. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  339. package/dist/modes/interactive/interactive-mode.js +308 -39
  340. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  341. package/dist/utils/tools-manager.d.ts +2 -0
  342. package/dist/utils/tools-manager.d.ts.map +1 -1
  343. package/dist/utils/tools-manager.js +154 -2
  344. package/dist/utils/tools-manager.js.map +1 -1
  345. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  346. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  347. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  348. package/examples/extensions/sandbox/package-lock.json +2 -2
  349. package/examples/extensions/sandbox/package.json +1 -1
  350. package/examples/extensions/with-deps/package-lock.json +2 -2
  351. package/examples/extensions/with-deps/package.json +1 -1
  352. package/npm-shrinkwrap.json +368 -12
  353. package/package.json +5 -4
@@ -0,0 +1,154 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+ import { PI_OKF_PROVIDER_ID, parseOkfMemoryDocument, } from "./okf-memory.js";
4
+ const DEFAULT_MAX_FILE_BYTES = 512_000;
5
+ const DEFAULT_MAX_DOCUMENTS = 1_000;
6
+ const OKF_EXTENSIONS = [".okf.md", ".okf", ".md"];
7
+ const OKF_PROVIDER_CAPABILITIES = {
8
+ search: true,
9
+ fetch: true,
10
+ write: false,
11
+ delete: false,
12
+ shortTerm: false,
13
+ longTerm: true,
14
+ graph: false,
15
+ citations: true,
16
+ scopes: ["session", "project", "user", "global"],
17
+ localOnly: true,
18
+ };
19
+ function isOkfPath(path) {
20
+ return OKF_EXTENSIONS.some((extension) => path.endsWith(extension));
21
+ }
22
+ function walkFiles(rootDir, maxDocuments) {
23
+ const files = [];
24
+ const pending = [rootDir];
25
+ while (pending.length > 0 && files.length < maxDocuments) {
26
+ const dir = pending.pop();
27
+ if (dir === undefined)
28
+ continue;
29
+ let entries;
30
+ try {
31
+ entries = readdirSync(dir).sort();
32
+ }
33
+ catch {
34
+ continue;
35
+ }
36
+ for (const entry of entries) {
37
+ const path = join(dir, entry);
38
+ let stat;
39
+ try {
40
+ stat = statSync(path);
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ if (stat.isDirectory()) {
46
+ pending.push(path);
47
+ }
48
+ else if (stat.isFile() && isOkfPath(path)) {
49
+ files.push(path);
50
+ if (files.length >= maxDocuments)
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ return files;
56
+ }
57
+ function tokenSet(text) {
58
+ return new Set(text.toLowerCase().match(/[a-z0-9_/-]+/g) ?? []);
59
+ }
60
+ function scoreItem(queryTokens, item) {
61
+ if (queryTokens.size === 0)
62
+ return 0;
63
+ const haystack = tokenSet([item.title, item.summary, item.content].filter((part) => part !== undefined).join("\n"));
64
+ let overlap = 0;
65
+ for (const token of queryTokens) {
66
+ if (haystack.has(token))
67
+ overlap++;
68
+ }
69
+ return overlap / queryTokens.size;
70
+ }
71
+ function matchesRequest(item, request) {
72
+ if (request.scope !== undefined && item.scope !== request.scope)
73
+ return false;
74
+ if (request.kinds !== undefined && !request.kinds.includes(item.kind))
75
+ return false;
76
+ return true;
77
+ }
78
+ function reasonForMatch(score, item) {
79
+ return `local OKF match score ${score.toFixed(3)} for ${item.providerId}/${item.scope}/${item.kind}`;
80
+ }
81
+ export function loadOkfMemoryBundle(options) {
82
+ const providerId = options.providerId ?? PI_OKF_PROVIDER_ID;
83
+ const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
84
+ const maxDocuments = options.maxDocuments ?? DEFAULT_MAX_DOCUMENTS;
85
+ const entries = [];
86
+ const diagnostics = [];
87
+ for (const path of walkFiles(options.rootDir, maxDocuments)) {
88
+ let stat;
89
+ try {
90
+ stat = statSync(path);
91
+ }
92
+ catch {
93
+ continue;
94
+ }
95
+ if (stat.size > maxFileBytes)
96
+ continue;
97
+ let content;
98
+ try {
99
+ content = readFileSync(path, "utf8");
100
+ }
101
+ catch {
102
+ continue;
103
+ }
104
+ const relativePath = relative(options.rootDir, path);
105
+ const parsed = parseOkfMemoryDocument(content, {
106
+ providerId,
107
+ uri: `okf:${relativePath}`,
108
+ fallbackId: relativePath,
109
+ });
110
+ if (parsed.diagnostics.length > 0)
111
+ diagnostics.push({ path, diagnostics: parsed.diagnostics });
112
+ if (parsed.item !== undefined)
113
+ entries.push({ path, relativePath, parsed });
114
+ }
115
+ return { entries, diagnostics };
116
+ }
117
+ export function createOkfMemoryProvider(options) {
118
+ let cachedReport;
119
+ function report() {
120
+ cachedReport ??= loadOkfMemoryBundle(options);
121
+ return cachedReport;
122
+ }
123
+ function items() {
124
+ return report().entries.flatMap((entry) => (entry.parsed.item === undefined ? [] : [entry.parsed.item]));
125
+ }
126
+ return {
127
+ id: options.providerId ?? PI_OKF_PROVIDER_ID,
128
+ label: "Pi OKF Memory",
129
+ source: "pi_native",
130
+ capabilities: OKF_PROVIDER_CAPABILITIES,
131
+ async search(request) {
132
+ const queryTokens = tokenSet(request.query);
133
+ return items()
134
+ .filter((item) => matchesRequest(item, request))
135
+ .map((item) => ({ item, score: scoreItem(queryTokens, item) }))
136
+ .filter((result) => result.score > 0)
137
+ .sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id))
138
+ .slice(0, request.maxResults)
139
+ .map((result) => ({ ...result, reason: reasonForMatch(result.score, result.item) }));
140
+ },
141
+ async fetch(ref) {
142
+ if (ref.providerId !== (options.providerId ?? PI_OKF_PROVIDER_ID))
143
+ return undefined;
144
+ return items().find((item) => item.id === ref.itemId && item.scope === ref.scope && item.kind === ref.kind);
145
+ },
146
+ };
147
+ }
148
+ export function listOkfMemoryScopes(report) {
149
+ return Array.from(new Set(report.entries.flatMap((entry) => (entry.parsed.item ? [entry.parsed.item.scope] : [])))).sort();
150
+ }
151
+ export function listOkfMemoryKinds(report) {
152
+ return Array.from(new Set(report.entries.flatMap((entry) => (entry.parsed.item ? [entry.parsed.item.kind] : [])))).sort();
153
+ }
154
+ //# sourceMappingURL=okf-memory-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okf-memory-provider.js","sourceRoot":"","sources":["../../../src/core/context/okf-memory-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync, type Stats, statSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport type { MemoryScope } from \"./context-item.ts\";\nimport type {\n\tMemoryItem,\n\tMemoryItemKind,\n\tMemoryProvider,\n\tMemoryProviderCapabilities,\n\tMemoryRef,\n\tMemorySearchRequest,\n\tMemorySearchResult,\n} from \"./memory-provider-contract.ts\";\nimport {\n\ttype OkfMemoryDiagnostic,\n\ttype ParsedOkfMemoryDocument,\n\tPI_OKF_PROVIDER_ID,\n\tparseOkfMemoryDocument,\n} from \"./okf-memory.ts\";\n\nexport interface OkfMemoryProviderOptions {\n\trootDir: string;\n\tproviderId?: string;\n\tmaxFileBytes?: number;\n\tmaxDocuments?: number;\n}\n\nexport interface OkfMemoryLoadEntry {\n\tpath: string;\n\trelativePath: string;\n\tparsed: ParsedOkfMemoryDocument;\n}\n\nexport interface OkfMemoryLoadReport {\n\tentries: OkfMemoryLoadEntry[];\n\tdiagnostics: Array<{ path: string; diagnostics: OkfMemoryDiagnostic[] }>;\n}\n\nconst DEFAULT_MAX_FILE_BYTES = 512_000;\nconst DEFAULT_MAX_DOCUMENTS = 1_000;\nconst OKF_EXTENSIONS = [\".okf.md\", \".okf\", \".md\"];\n\nconst OKF_PROVIDER_CAPABILITIES: MemoryProviderCapabilities = {\n\tsearch: true,\n\tfetch: true,\n\twrite: false,\n\tdelete: false,\n\tshortTerm: false,\n\tlongTerm: true,\n\tgraph: false,\n\tcitations: true,\n\tscopes: [\"session\", \"project\", \"user\", \"global\"],\n\tlocalOnly: true,\n};\n\nfunction isOkfPath(path: string): boolean {\n\treturn OKF_EXTENSIONS.some((extension) => path.endsWith(extension));\n}\n\nfunction walkFiles(rootDir: string, maxDocuments: number): string[] {\n\tconst files: string[] = [];\n\tconst pending = [rootDir];\n\twhile (pending.length > 0 && files.length < maxDocuments) {\n\t\tconst dir = pending.pop();\n\t\tif (dir === undefined) continue;\n\t\tlet entries: string[];\n\t\ttry {\n\t\t\tentries = readdirSync(dir).sort();\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries) {\n\t\t\tconst path = join(dir, entry);\n\t\t\tlet stat: Stats;\n\t\t\ttry {\n\t\t\t\tstat = statSync(path);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (stat.isDirectory()) {\n\t\t\t\tpending.push(path);\n\t\t\t} else if (stat.isFile() && isOkfPath(path)) {\n\t\t\t\tfiles.push(path);\n\t\t\t\tif (files.length >= maxDocuments) break;\n\t\t\t}\n\t\t}\n\t}\n\treturn files;\n}\n\nfunction tokenSet(text: string): Set<string> {\n\treturn new Set(text.toLowerCase().match(/[a-z0-9_/-]+/g) ?? []);\n}\n\nfunction scoreItem(queryTokens: Set<string>, item: MemoryItem): number {\n\tif (queryTokens.size === 0) return 0;\n\tconst haystack = tokenSet(\n\t\t[item.title, item.summary, item.content].filter((part): part is string => part !== undefined).join(\"\\n\"),\n\t);\n\tlet overlap = 0;\n\tfor (const token of queryTokens) {\n\t\tif (haystack.has(token)) overlap++;\n\t}\n\treturn overlap / queryTokens.size;\n}\n\nfunction matchesRequest(item: MemoryItem, request: MemorySearchRequest): boolean {\n\tif (request.scope !== undefined && item.scope !== request.scope) return false;\n\tif (request.kinds !== undefined && !request.kinds.includes(item.kind)) return false;\n\treturn true;\n}\n\nfunction reasonForMatch(score: number, item: MemoryItem): string {\n\treturn `local OKF match score ${score.toFixed(3)} for ${item.providerId}/${item.scope}/${item.kind}`;\n}\n\nexport function loadOkfMemoryBundle(options: OkfMemoryProviderOptions): OkfMemoryLoadReport {\n\tconst providerId = options.providerId ?? PI_OKF_PROVIDER_ID;\n\tconst maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;\n\tconst maxDocuments = options.maxDocuments ?? DEFAULT_MAX_DOCUMENTS;\n\tconst entries: OkfMemoryLoadEntry[] = [];\n\tconst diagnostics: Array<{ path: string; diagnostics: OkfMemoryDiagnostic[] }> = [];\n\n\tfor (const path of walkFiles(options.rootDir, maxDocuments)) {\n\t\tlet stat: Stats;\n\t\ttry {\n\t\t\tstat = statSync(path);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (stat.size > maxFileBytes) continue;\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = readFileSync(path, \"utf8\");\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst relativePath = relative(options.rootDir, path);\n\t\tconst parsed = parseOkfMemoryDocument(content, {\n\t\t\tproviderId,\n\t\t\turi: `okf:${relativePath}`,\n\t\t\tfallbackId: relativePath,\n\t\t});\n\t\tif (parsed.diagnostics.length > 0) diagnostics.push({ path, diagnostics: parsed.diagnostics });\n\t\tif (parsed.item !== undefined) entries.push({ path, relativePath, parsed });\n\t}\n\n\treturn { entries, diagnostics };\n}\n\nexport function createOkfMemoryProvider(options: OkfMemoryProviderOptions): MemoryProvider {\n\tlet cachedReport: OkfMemoryLoadReport | undefined;\n\n\tfunction report(): OkfMemoryLoadReport {\n\t\tcachedReport ??= loadOkfMemoryBundle(options);\n\t\treturn cachedReport;\n\t}\n\n\tfunction items(): MemoryItem[] {\n\t\treturn report().entries.flatMap((entry) => (entry.parsed.item === undefined ? [] : [entry.parsed.item]));\n\t}\n\n\treturn {\n\t\tid: options.providerId ?? PI_OKF_PROVIDER_ID,\n\t\tlabel: \"Pi OKF Memory\",\n\t\tsource: \"pi_native\",\n\t\tcapabilities: OKF_PROVIDER_CAPABILITIES,\n\n\t\tasync search(request: MemorySearchRequest): Promise<MemorySearchResult[]> {\n\t\t\tconst queryTokens = tokenSet(request.query);\n\t\t\treturn items()\n\t\t\t\t.filter((item) => matchesRequest(item, request))\n\t\t\t\t.map((item) => ({ item, score: scoreItem(queryTokens, item) }))\n\t\t\t\t.filter((result) => result.score > 0)\n\t\t\t\t.sort((left, right) => right.score - left.score || left.item.id.localeCompare(right.item.id))\n\t\t\t\t.slice(0, request.maxResults)\n\t\t\t\t.map((result) => ({ ...result, reason: reasonForMatch(result.score, result.item) }));\n\t\t},\n\n\t\tasync fetch(ref: MemoryRef): Promise<MemoryItem | undefined> {\n\t\t\tif (ref.providerId !== (options.providerId ?? PI_OKF_PROVIDER_ID)) return undefined;\n\t\t\treturn items().find((item) => item.id === ref.itemId && item.scope === ref.scope && item.kind === ref.kind);\n\t\t},\n\t};\n}\n\nexport function listOkfMemoryScopes(report: OkfMemoryLoadReport): MemoryScope[] {\n\treturn Array.from(\n\t\tnew Set(report.entries.flatMap((entry) => (entry.parsed.item ? [entry.parsed.item.scope] : []))),\n\t).sort();\n}\n\nexport function listOkfMemoryKinds(report: OkfMemoryLoadReport): MemoryItemKind[] {\n\treturn Array.from(\n\t\tnew Set(report.entries.flatMap((entry) => (entry.parsed.item ? [entry.parsed.item.kind] : []))),\n\t).sort();\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import type { MemoryScope } from "./context-item.ts";
2
+ import type { MemoryItem, MemoryWriteRequest } from "./memory-provider-contract.ts";
3
+ export declare const PI_OKF_PROVIDER_ID = "pi-okf";
4
+ export declare const PI_OKF_AUTHORITY = "durable_memory";
5
+ export declare const PI_OKF_TYPES: readonly ["Design Decision", "Architecture Concept", "Project Rule Candidate", "Implementation Note", "Debugging Finding", "Invalidated Assumption", "Tooling Playbook", "External Reference", "User Preference", "Capability Doc"];
6
+ export type PiOkfType = (typeof PI_OKF_TYPES)[number];
7
+ export type OkfMemoryDiagnosticCode = "missing_frontmatter" | "invalid_frontmatter" | "invalid_yaml" | "missing_type" | "unknown_type" | "missing_title" | "missing_description" | "missing_pi" | "invalid_scope" | "invalid_authority" | "invalid_evidence_refs";
8
+ export interface OkfMemoryDiagnostic {
9
+ code: OkfMemoryDiagnosticCode;
10
+ message: string;
11
+ }
12
+ export interface ParseOkfMemoryOptions {
13
+ providerId?: string;
14
+ uri?: string;
15
+ fallbackId?: string;
16
+ }
17
+ export interface ParsedOkfMemoryDocument {
18
+ item?: MemoryItem;
19
+ body: string;
20
+ diagnostics: OkfMemoryDiagnostic[];
21
+ }
22
+ export interface OkfMemoryDocumentInput {
23
+ type: PiOkfType;
24
+ title: string;
25
+ description: string;
26
+ scope: MemoryScope;
27
+ body: string;
28
+ tags?: string[];
29
+ timestamp?: string;
30
+ evidenceRefs?: string[];
31
+ }
32
+ export interface OkfProjectRulePromotionRequest {
33
+ item: MemoryItem;
34
+ approvalId?: string;
35
+ trustedConfigPath?: string;
36
+ }
37
+ export type OkfProjectRulePromotionRejection = "not_project_rule_candidate" | "missing_explicit_promotion_authority" | "stale_or_conflicting_memory";
38
+ export declare function parseOkfMemoryDocument(content: string, options?: ParseOkfMemoryOptions): ParsedOkfMemoryDocument;
39
+ export declare function formatOkfMemoryDocument(input: OkfMemoryDocumentInput): string;
40
+ export declare function okfMemoryItemToWriteRequest(item: MemoryItem, reason: string): MemoryWriteRequest;
41
+ export declare function validateOkfProjectRulePromotion(request: OkfProjectRulePromotionRequest): OkfProjectRulePromotionRejection[];
42
+ //# sourceMappingURL=okf-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okf-memory.d.ts","sourceRoot":"","sources":["../../../src/core/context/okf-memory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAEX,UAAU,EAGV,kBAAkB,EAClB,MAAM,+BAA+B,CAAC;AAEvC,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAE3C,eAAO,MAAM,gBAAgB,mBAAmB,CAAC;AAEjD,eAAO,MAAM,YAAY,qOAWf,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,MAAM,MAAM,uBAAuB,GAChC,qBAAqB,GACrB,qBAAqB,GACrB,cAAc,GACd,cAAc,GACd,cAAc,GACd,eAAe,GACf,qBAAqB,GACrB,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,uBAAuB,CAAC;AAE3B,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACvC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,8BAA8B;IAC9C,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,gCAAgC,GACzC,4BAA4B,GAC5B,sCAAsC,GACtC,6BAA6B,CAAC;AAkEjC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,uBAAuB,CA6EpH;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAc7E;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAYhG;AAED,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,8BAA8B,GACrC,gCAAgC,EAAE,CAQpC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { stringify } from \"yaml\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport type { MemoryScope } from \"./context-item.ts\";\nimport type {\n\tMemoryEvidenceRef,\n\tMemoryItem,\n\tMemoryItemKind,\n\tMemoryRef,\n\tMemoryWriteRequest,\n} from \"./memory-provider-contract.ts\";\n\nexport const PI_OKF_PROVIDER_ID = \"pi-okf\";\n\nexport const PI_OKF_AUTHORITY = \"durable_memory\";\n\nexport const PI_OKF_TYPES = [\n\t\"Design Decision\",\n\t\"Architecture Concept\",\n\t\"Project Rule Candidate\",\n\t\"Implementation Note\",\n\t\"Debugging Finding\",\n\t\"Invalidated Assumption\",\n\t\"Tooling Playbook\",\n\t\"External Reference\",\n\t\"User Preference\",\n\t\"Capability Doc\",\n] as const;\n\nexport type PiOkfType = (typeof PI_OKF_TYPES)[number];\n\nexport type OkfMemoryDiagnosticCode =\n\t| \"missing_frontmatter\"\n\t| \"invalid_frontmatter\"\n\t| \"invalid_yaml\"\n\t| \"missing_type\"\n\t| \"unknown_type\"\n\t| \"missing_title\"\n\t| \"missing_description\"\n\t| \"missing_pi\"\n\t| \"invalid_scope\"\n\t| \"invalid_authority\"\n\t| \"invalid_evidence_refs\";\n\nexport interface OkfMemoryDiagnostic {\n\tcode: OkfMemoryDiagnosticCode;\n\tmessage: string;\n}\n\nexport interface ParseOkfMemoryOptions {\n\tproviderId?: string;\n\turi?: string;\n\tfallbackId?: string;\n}\n\nexport interface ParsedOkfMemoryDocument {\n\titem?: MemoryItem;\n\tbody: string;\n\tdiagnostics: OkfMemoryDiagnostic[];\n}\n\nexport interface OkfMemoryDocumentInput {\n\ttype: PiOkfType;\n\ttitle: string;\n\tdescription: string;\n\tscope: MemoryScope;\n\tbody: string;\n\ttags?: string[];\n\ttimestamp?: string;\n\tevidenceRefs?: string[];\n}\n\nexport interface OkfProjectRulePromotionRequest {\n\titem: MemoryItem;\n\tapprovalId?: string;\n\ttrustedConfigPath?: string;\n}\n\nexport type OkfProjectRulePromotionRejection =\n\t| \"not_project_rule_candidate\"\n\t| \"missing_explicit_promotion_authority\"\n\t| \"stale_or_conflicting_memory\";\n\nconst OKF_TYPE_TO_MEMORY_KIND = new Map<PiOkfType, MemoryItemKind>([\n\t[\"Design Decision\", \"design_decision\"],\n\t[\"Architecture Concept\", \"architecture_concept\"],\n\t[\"Project Rule Candidate\", \"project_rule_candidate\"],\n\t[\"Implementation Note\", \"fact\"],\n\t[\"Debugging Finding\", \"debugging_finding\"],\n\t[\"Invalidated Assumption\", \"invalidated_assumption\"],\n\t[\"Tooling Playbook\", \"procedure\"],\n\t[\"External Reference\", \"reference\"],\n\t[\"User Preference\", \"user_preference\"],\n\t[\"Capability Doc\", \"reference\"],\n]);\n\nconst VALID_SCOPES: readonly MemoryScope[] = [\"session\", \"project\", \"user\", \"global\"];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(record: Record<string, unknown>, key: string): string | undefined {\n\tconst value = record[key];\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value : undefined;\n}\n\nfunction stringArrayField(record: Record<string, unknown>, key: string): string[] | undefined {\n\tconst value = record[key];\n\tif (value === undefined) return undefined;\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\") ? value : undefined;\n}\n\nfunction memoryItemKindForOkfType(type: string): MemoryItemKind | undefined {\n\treturn OKF_TYPE_TO_MEMORY_KIND.get(type as PiOkfType);\n}\n\nfunction memoryIdForDocument(\n\tproviderId: string,\n\turi: string | undefined,\n\ttitle: string,\n\ttimestamp: string | undefined,\n): string {\n\treturn createHash(\"sha256\")\n\t\t.update([providerId, uri ?? \"\", title, timestamp ?? \"\"].join(\"\\0\"))\n\t\t.digest(\"hex\")\n\t\t.slice(0, 24);\n}\n\nfunction evidenceRefsFromOkf(providerId: string, refs: string[] | undefined): MemoryEvidenceRef[] {\n\treturn (refs ?? []).map((ref) => ({ type: \"external\", id: ref, providerId, description: \"OKF evidence_ref\" }));\n}\n\nfunction buildMemoryRef(\n\tproviderId: string,\n\tid: string,\n\tscope: MemoryScope,\n\tkind: MemoryItemKind,\n\turi?: string,\n): MemoryRef {\n\treturn { providerId, itemId: id, scope, kind, uri };\n}\n\nfunction validScope(value: string | undefined): MemoryScope | undefined {\n\treturn value !== undefined && VALID_SCOPES.includes(value as MemoryScope) ? (value as MemoryScope) : undefined;\n}\n\nexport function parseOkfMemoryDocument(content: string, options: ParseOkfMemoryOptions = {}): ParsedOkfMemoryDocument {\n\tlet frontmatter: Record<string, unknown>;\n\tlet body: string;\n\ttry {\n\t\tconst parsed = parseFrontmatter(content);\n\t\tfrontmatter = parsed.frontmatter;\n\t\tbody = parsed.body;\n\t} catch (error) {\n\t\treturn {\n\t\t\tbody: content,\n\t\t\tdiagnostics: [{ code: \"invalid_yaml\", message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\n\tconst diagnostics: OkfMemoryDiagnostic[] = [];\n\tif (!isRecord(frontmatter) || Object.keys(frontmatter).length === 0) {\n\t\treturn { body, diagnostics: [{ code: \"missing_frontmatter\", message: \"OKF memory requires YAML frontmatter.\" }] };\n\t}\n\n\tconst type = stringField(frontmatter, \"type\");\n\tif (type === undefined) diagnostics.push({ code: \"missing_type\", message: \"OKF memory requires a type.\" });\n\tconst kind = type === undefined ? undefined : memoryItemKindForOkfType(type);\n\tif (type !== undefined && kind === undefined)\n\t\tdiagnostics.push({ code: \"unknown_type\", message: `Unknown Pi OKF type: ${type}` });\n\n\tconst title = stringField(frontmatter, \"title\");\n\tif (title === undefined) diagnostics.push({ code: \"missing_title\", message: \"OKF memory requires a title.\" });\n\tconst description = stringField(frontmatter, \"description\");\n\tif (description === undefined)\n\t\tdiagnostics.push({ code: \"missing_description\", message: \"OKF memory requires a description.\" });\n\n\tconst pi = frontmatter.pi;\n\tif (!isRecord(pi)) diagnostics.push({ code: \"missing_pi\", message: \"OKF memory requires a pi block.\" });\n\tconst scope = isRecord(pi) ? validScope(stringField(pi, \"scope\")) : undefined;\n\tif (isRecord(pi) && scope === undefined)\n\t\tdiagnostics.push({ code: \"invalid_scope\", message: \"pi.scope must be session, project, user, or global.\" });\n\tconst authority = isRecord(pi) ? stringField(pi, \"authority\") : undefined;\n\tif (isRecord(pi) && authority !== PI_OKF_AUTHORITY) {\n\t\tdiagnostics.push({ code: \"invalid_authority\", message: `pi.authority must be ${PI_OKF_AUTHORITY}.` });\n\t}\n\tconst evidenceRefs = isRecord(pi) ? stringArrayField(pi, \"evidence_refs\") : undefined;\n\tif (isRecord(pi) && pi.evidence_refs !== undefined && evidenceRefs === undefined) {\n\t\tdiagnostics.push({ code: \"invalid_evidence_refs\", message: \"pi.evidence_refs must be a string array.\" });\n\t}\n\n\tif (\n\t\tdiagnostics.length > 0 ||\n\t\tkind === undefined ||\n\t\ttitle === undefined ||\n\t\tdescription === undefined ||\n\t\tscope === undefined\n\t) {\n\t\treturn { body, diagnostics };\n\t}\n\n\tconst providerId = options.providerId ?? PI_OKF_PROVIDER_ID;\n\tconst timestamp = stringField(frontmatter, \"timestamp\");\n\tconst id = options.fallbackId ?? memoryIdForDocument(providerId, options.uri, title, timestamp);\n\tconst ref = buildMemoryRef(providerId, id, scope, kind, options.uri);\n\treturn {\n\t\tbody,\n\t\tdiagnostics,\n\t\titem: {\n\t\t\tid,\n\t\t\tproviderId,\n\t\t\tsource: \"pi_native\",\n\t\t\tkind,\n\t\t\tscope,\n\t\t\tdurability: \"durable\",\n\t\t\ttitle,\n\t\t\tsummary: description,\n\t\t\tcontent: body.length > 0 ? body : undefined,\n\t\t\trefs: [ref],\n\t\t\tevidenceRefs: evidenceRefsFromOkf(providerId, evidenceRefs),\n\t\t\ttimestamp,\n\t\t},\n\t};\n}\n\nexport function formatOkfMemoryDocument(input: OkfMemoryDocumentInput): string {\n\tconst frontmatter = {\n\t\ttype: input.type,\n\t\ttitle: input.title,\n\t\tdescription: input.description,\n\t\ttags: input.tags,\n\t\ttimestamp: input.timestamp,\n\t\tpi: {\n\t\t\tscope: input.scope,\n\t\t\tauthority: PI_OKF_AUTHORITY,\n\t\t\tevidence_refs: input.evidenceRefs ?? [],\n\t\t},\n\t};\n\treturn `---\\n${stringify(frontmatter).trim()}\\n---\\n\\n${input.body.trim()}\\n`;\n}\n\nexport function okfMemoryItemToWriteRequest(item: MemoryItem, reason: string): MemoryWriteRequest {\n\treturn {\n\t\tproviderId: item.providerId,\n\t\tscope: item.scope,\n\t\tkind: item.kind,\n\t\ttitle: item.title,\n\t\tsummary: item.summary,\n\t\tcontent: item.content,\n\t\tevidenceRefs: item.evidenceRefs,\n\t\tsensitivity: \"normal\",\n\t\treason,\n\t};\n}\n\nexport function validateOkfProjectRulePromotion(\n\trequest: OkfProjectRulePromotionRequest,\n): OkfProjectRulePromotionRejection[] {\n\tconst rejections: OkfProjectRulePromotionRejection[] = [];\n\tif (request.item.kind !== \"project_rule_candidate\") rejections.push(\"not_project_rule_candidate\");\n\tif (request.approvalId === undefined && request.trustedConfigPath === undefined) {\n\t\trejections.push(\"missing_explicit_promotion_authority\");\n\t}\n\tif (request.item.stale || request.item.conflict !== undefined) rejections.push(\"stale_or_conflicting_memory\");\n\treturn rejections;\n}\n"]}
@@ -0,0 +1,175 @@
1
+ import { createHash } from "node:crypto";
2
+ import { stringify } from "yaml";
3
+ import { parseFrontmatter } from "../../utils/frontmatter.js";
4
+ export const PI_OKF_PROVIDER_ID = "pi-okf";
5
+ export const PI_OKF_AUTHORITY = "durable_memory";
6
+ export const PI_OKF_TYPES = [
7
+ "Design Decision",
8
+ "Architecture Concept",
9
+ "Project Rule Candidate",
10
+ "Implementation Note",
11
+ "Debugging Finding",
12
+ "Invalidated Assumption",
13
+ "Tooling Playbook",
14
+ "External Reference",
15
+ "User Preference",
16
+ "Capability Doc",
17
+ ];
18
+ const OKF_TYPE_TO_MEMORY_KIND = new Map([
19
+ ["Design Decision", "design_decision"],
20
+ ["Architecture Concept", "architecture_concept"],
21
+ ["Project Rule Candidate", "project_rule_candidate"],
22
+ ["Implementation Note", "fact"],
23
+ ["Debugging Finding", "debugging_finding"],
24
+ ["Invalidated Assumption", "invalidated_assumption"],
25
+ ["Tooling Playbook", "procedure"],
26
+ ["External Reference", "reference"],
27
+ ["User Preference", "user_preference"],
28
+ ["Capability Doc", "reference"],
29
+ ]);
30
+ const VALID_SCOPES = ["session", "project", "user", "global"];
31
+ function isRecord(value) {
32
+ return typeof value === "object" && value !== null && !Array.isArray(value);
33
+ }
34
+ function stringField(record, key) {
35
+ const value = record[key];
36
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
37
+ }
38
+ function stringArrayField(record, key) {
39
+ const value = record[key];
40
+ if (value === undefined)
41
+ return undefined;
42
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : undefined;
43
+ }
44
+ function memoryItemKindForOkfType(type) {
45
+ return OKF_TYPE_TO_MEMORY_KIND.get(type);
46
+ }
47
+ function memoryIdForDocument(providerId, uri, title, timestamp) {
48
+ return createHash("sha256")
49
+ .update([providerId, uri ?? "", title, timestamp ?? ""].join("\0"))
50
+ .digest("hex")
51
+ .slice(0, 24);
52
+ }
53
+ function evidenceRefsFromOkf(providerId, refs) {
54
+ return (refs ?? []).map((ref) => ({ type: "external", id: ref, providerId, description: "OKF evidence_ref" }));
55
+ }
56
+ function buildMemoryRef(providerId, id, scope, kind, uri) {
57
+ return { providerId, itemId: id, scope, kind, uri };
58
+ }
59
+ function validScope(value) {
60
+ return value !== undefined && VALID_SCOPES.includes(value) ? value : undefined;
61
+ }
62
+ export function parseOkfMemoryDocument(content, options = {}) {
63
+ let frontmatter;
64
+ let body;
65
+ try {
66
+ const parsed = parseFrontmatter(content);
67
+ frontmatter = parsed.frontmatter;
68
+ body = parsed.body;
69
+ }
70
+ catch (error) {
71
+ return {
72
+ body: content,
73
+ diagnostics: [{ code: "invalid_yaml", message: error instanceof Error ? error.message : String(error) }],
74
+ };
75
+ }
76
+ const diagnostics = [];
77
+ if (!isRecord(frontmatter) || Object.keys(frontmatter).length === 0) {
78
+ return { body, diagnostics: [{ code: "missing_frontmatter", message: "OKF memory requires YAML frontmatter." }] };
79
+ }
80
+ const type = stringField(frontmatter, "type");
81
+ if (type === undefined)
82
+ diagnostics.push({ code: "missing_type", message: "OKF memory requires a type." });
83
+ const kind = type === undefined ? undefined : memoryItemKindForOkfType(type);
84
+ if (type !== undefined && kind === undefined)
85
+ diagnostics.push({ code: "unknown_type", message: `Unknown Pi OKF type: ${type}` });
86
+ const title = stringField(frontmatter, "title");
87
+ if (title === undefined)
88
+ diagnostics.push({ code: "missing_title", message: "OKF memory requires a title." });
89
+ const description = stringField(frontmatter, "description");
90
+ if (description === undefined)
91
+ diagnostics.push({ code: "missing_description", message: "OKF memory requires a description." });
92
+ const pi = frontmatter.pi;
93
+ if (!isRecord(pi))
94
+ diagnostics.push({ code: "missing_pi", message: "OKF memory requires a pi block." });
95
+ const scope = isRecord(pi) ? validScope(stringField(pi, "scope")) : undefined;
96
+ if (isRecord(pi) && scope === undefined)
97
+ diagnostics.push({ code: "invalid_scope", message: "pi.scope must be session, project, user, or global." });
98
+ const authority = isRecord(pi) ? stringField(pi, "authority") : undefined;
99
+ if (isRecord(pi) && authority !== PI_OKF_AUTHORITY) {
100
+ diagnostics.push({ code: "invalid_authority", message: `pi.authority must be ${PI_OKF_AUTHORITY}.` });
101
+ }
102
+ const evidenceRefs = isRecord(pi) ? stringArrayField(pi, "evidence_refs") : undefined;
103
+ if (isRecord(pi) && pi.evidence_refs !== undefined && evidenceRefs === undefined) {
104
+ diagnostics.push({ code: "invalid_evidence_refs", message: "pi.evidence_refs must be a string array." });
105
+ }
106
+ if (diagnostics.length > 0 ||
107
+ kind === undefined ||
108
+ title === undefined ||
109
+ description === undefined ||
110
+ scope === undefined) {
111
+ return { body, diagnostics };
112
+ }
113
+ const providerId = options.providerId ?? PI_OKF_PROVIDER_ID;
114
+ const timestamp = stringField(frontmatter, "timestamp");
115
+ const id = options.fallbackId ?? memoryIdForDocument(providerId, options.uri, title, timestamp);
116
+ const ref = buildMemoryRef(providerId, id, scope, kind, options.uri);
117
+ return {
118
+ body,
119
+ diagnostics,
120
+ item: {
121
+ id,
122
+ providerId,
123
+ source: "pi_native",
124
+ kind,
125
+ scope,
126
+ durability: "durable",
127
+ title,
128
+ summary: description,
129
+ content: body.length > 0 ? body : undefined,
130
+ refs: [ref],
131
+ evidenceRefs: evidenceRefsFromOkf(providerId, evidenceRefs),
132
+ timestamp,
133
+ },
134
+ };
135
+ }
136
+ export function formatOkfMemoryDocument(input) {
137
+ const frontmatter = {
138
+ type: input.type,
139
+ title: input.title,
140
+ description: input.description,
141
+ tags: input.tags,
142
+ timestamp: input.timestamp,
143
+ pi: {
144
+ scope: input.scope,
145
+ authority: PI_OKF_AUTHORITY,
146
+ evidence_refs: input.evidenceRefs ?? [],
147
+ },
148
+ };
149
+ return `---\n${stringify(frontmatter).trim()}\n---\n\n${input.body.trim()}\n`;
150
+ }
151
+ export function okfMemoryItemToWriteRequest(item, reason) {
152
+ return {
153
+ providerId: item.providerId,
154
+ scope: item.scope,
155
+ kind: item.kind,
156
+ title: item.title,
157
+ summary: item.summary,
158
+ content: item.content,
159
+ evidenceRefs: item.evidenceRefs,
160
+ sensitivity: "normal",
161
+ reason,
162
+ };
163
+ }
164
+ export function validateOkfProjectRulePromotion(request) {
165
+ const rejections = [];
166
+ if (request.item.kind !== "project_rule_candidate")
167
+ rejections.push("not_project_rule_candidate");
168
+ if (request.approvalId === undefined && request.trustedConfigPath === undefined) {
169
+ rejections.push("missing_explicit_promotion_authority");
170
+ }
171
+ if (request.item.stale || request.item.conflict !== undefined)
172
+ rejections.push("stale_or_conflicting_memory");
173
+ return rejections;
174
+ }
175
+ //# sourceMappingURL=okf-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okf-memory.js","sourceRoot":"","sources":["../../../src/core/context/okf-memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { stringify } from \"yaml\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport type { MemoryScope } from \"./context-item.ts\";\nimport type {\n\tMemoryEvidenceRef,\n\tMemoryItem,\n\tMemoryItemKind,\n\tMemoryRef,\n\tMemoryWriteRequest,\n} from \"./memory-provider-contract.ts\";\n\nexport const PI_OKF_PROVIDER_ID = \"pi-okf\";\n\nexport const PI_OKF_AUTHORITY = \"durable_memory\";\n\nexport const PI_OKF_TYPES = [\n\t\"Design Decision\",\n\t\"Architecture Concept\",\n\t\"Project Rule Candidate\",\n\t\"Implementation Note\",\n\t\"Debugging Finding\",\n\t\"Invalidated Assumption\",\n\t\"Tooling Playbook\",\n\t\"External Reference\",\n\t\"User Preference\",\n\t\"Capability Doc\",\n] as const;\n\nexport type PiOkfType = (typeof PI_OKF_TYPES)[number];\n\nexport type OkfMemoryDiagnosticCode =\n\t| \"missing_frontmatter\"\n\t| \"invalid_frontmatter\"\n\t| \"invalid_yaml\"\n\t| \"missing_type\"\n\t| \"unknown_type\"\n\t| \"missing_title\"\n\t| \"missing_description\"\n\t| \"missing_pi\"\n\t| \"invalid_scope\"\n\t| \"invalid_authority\"\n\t| \"invalid_evidence_refs\";\n\nexport interface OkfMemoryDiagnostic {\n\tcode: OkfMemoryDiagnosticCode;\n\tmessage: string;\n}\n\nexport interface ParseOkfMemoryOptions {\n\tproviderId?: string;\n\turi?: string;\n\tfallbackId?: string;\n}\n\nexport interface ParsedOkfMemoryDocument {\n\titem?: MemoryItem;\n\tbody: string;\n\tdiagnostics: OkfMemoryDiagnostic[];\n}\n\nexport interface OkfMemoryDocumentInput {\n\ttype: PiOkfType;\n\ttitle: string;\n\tdescription: string;\n\tscope: MemoryScope;\n\tbody: string;\n\ttags?: string[];\n\ttimestamp?: string;\n\tevidenceRefs?: string[];\n}\n\nexport interface OkfProjectRulePromotionRequest {\n\titem: MemoryItem;\n\tapprovalId?: string;\n\ttrustedConfigPath?: string;\n}\n\nexport type OkfProjectRulePromotionRejection =\n\t| \"not_project_rule_candidate\"\n\t| \"missing_explicit_promotion_authority\"\n\t| \"stale_or_conflicting_memory\";\n\nconst OKF_TYPE_TO_MEMORY_KIND = new Map<PiOkfType, MemoryItemKind>([\n\t[\"Design Decision\", \"design_decision\"],\n\t[\"Architecture Concept\", \"architecture_concept\"],\n\t[\"Project Rule Candidate\", \"project_rule_candidate\"],\n\t[\"Implementation Note\", \"fact\"],\n\t[\"Debugging Finding\", \"debugging_finding\"],\n\t[\"Invalidated Assumption\", \"invalidated_assumption\"],\n\t[\"Tooling Playbook\", \"procedure\"],\n\t[\"External Reference\", \"reference\"],\n\t[\"User Preference\", \"user_preference\"],\n\t[\"Capability Doc\", \"reference\"],\n]);\n\nconst VALID_SCOPES: readonly MemoryScope[] = [\"session\", \"project\", \"user\", \"global\"];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(record: Record<string, unknown>, key: string): string | undefined {\n\tconst value = record[key];\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value : undefined;\n}\n\nfunction stringArrayField(record: Record<string, unknown>, key: string): string[] | undefined {\n\tconst value = record[key];\n\tif (value === undefined) return undefined;\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\") ? value : undefined;\n}\n\nfunction memoryItemKindForOkfType(type: string): MemoryItemKind | undefined {\n\treturn OKF_TYPE_TO_MEMORY_KIND.get(type as PiOkfType);\n}\n\nfunction memoryIdForDocument(\n\tproviderId: string,\n\turi: string | undefined,\n\ttitle: string,\n\ttimestamp: string | undefined,\n): string {\n\treturn createHash(\"sha256\")\n\t\t.update([providerId, uri ?? \"\", title, timestamp ?? \"\"].join(\"\\0\"))\n\t\t.digest(\"hex\")\n\t\t.slice(0, 24);\n}\n\nfunction evidenceRefsFromOkf(providerId: string, refs: string[] | undefined): MemoryEvidenceRef[] {\n\treturn (refs ?? []).map((ref) => ({ type: \"external\", id: ref, providerId, description: \"OKF evidence_ref\" }));\n}\n\nfunction buildMemoryRef(\n\tproviderId: string,\n\tid: string,\n\tscope: MemoryScope,\n\tkind: MemoryItemKind,\n\turi?: string,\n): MemoryRef {\n\treturn { providerId, itemId: id, scope, kind, uri };\n}\n\nfunction validScope(value: string | undefined): MemoryScope | undefined {\n\treturn value !== undefined && VALID_SCOPES.includes(value as MemoryScope) ? (value as MemoryScope) : undefined;\n}\n\nexport function parseOkfMemoryDocument(content: string, options: ParseOkfMemoryOptions = {}): ParsedOkfMemoryDocument {\n\tlet frontmatter: Record<string, unknown>;\n\tlet body: string;\n\ttry {\n\t\tconst parsed = parseFrontmatter(content);\n\t\tfrontmatter = parsed.frontmatter;\n\t\tbody = parsed.body;\n\t} catch (error) {\n\t\treturn {\n\t\t\tbody: content,\n\t\t\tdiagnostics: [{ code: \"invalid_yaml\", message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\n\tconst diagnostics: OkfMemoryDiagnostic[] = [];\n\tif (!isRecord(frontmatter) || Object.keys(frontmatter).length === 0) {\n\t\treturn { body, diagnostics: [{ code: \"missing_frontmatter\", message: \"OKF memory requires YAML frontmatter.\" }] };\n\t}\n\n\tconst type = stringField(frontmatter, \"type\");\n\tif (type === undefined) diagnostics.push({ code: \"missing_type\", message: \"OKF memory requires a type.\" });\n\tconst kind = type === undefined ? undefined : memoryItemKindForOkfType(type);\n\tif (type !== undefined && kind === undefined)\n\t\tdiagnostics.push({ code: \"unknown_type\", message: `Unknown Pi OKF type: ${type}` });\n\n\tconst title = stringField(frontmatter, \"title\");\n\tif (title === undefined) diagnostics.push({ code: \"missing_title\", message: \"OKF memory requires a title.\" });\n\tconst description = stringField(frontmatter, \"description\");\n\tif (description === undefined)\n\t\tdiagnostics.push({ code: \"missing_description\", message: \"OKF memory requires a description.\" });\n\n\tconst pi = frontmatter.pi;\n\tif (!isRecord(pi)) diagnostics.push({ code: \"missing_pi\", message: \"OKF memory requires a pi block.\" });\n\tconst scope = isRecord(pi) ? validScope(stringField(pi, \"scope\")) : undefined;\n\tif (isRecord(pi) && scope === undefined)\n\t\tdiagnostics.push({ code: \"invalid_scope\", message: \"pi.scope must be session, project, user, or global.\" });\n\tconst authority = isRecord(pi) ? stringField(pi, \"authority\") : undefined;\n\tif (isRecord(pi) && authority !== PI_OKF_AUTHORITY) {\n\t\tdiagnostics.push({ code: \"invalid_authority\", message: `pi.authority must be ${PI_OKF_AUTHORITY}.` });\n\t}\n\tconst evidenceRefs = isRecord(pi) ? stringArrayField(pi, \"evidence_refs\") : undefined;\n\tif (isRecord(pi) && pi.evidence_refs !== undefined && evidenceRefs === undefined) {\n\t\tdiagnostics.push({ code: \"invalid_evidence_refs\", message: \"pi.evidence_refs must be a string array.\" });\n\t}\n\n\tif (\n\t\tdiagnostics.length > 0 ||\n\t\tkind === undefined ||\n\t\ttitle === undefined ||\n\t\tdescription === undefined ||\n\t\tscope === undefined\n\t) {\n\t\treturn { body, diagnostics };\n\t}\n\n\tconst providerId = options.providerId ?? PI_OKF_PROVIDER_ID;\n\tconst timestamp = stringField(frontmatter, \"timestamp\");\n\tconst id = options.fallbackId ?? memoryIdForDocument(providerId, options.uri, title, timestamp);\n\tconst ref = buildMemoryRef(providerId, id, scope, kind, options.uri);\n\treturn {\n\t\tbody,\n\t\tdiagnostics,\n\t\titem: {\n\t\t\tid,\n\t\t\tproviderId,\n\t\t\tsource: \"pi_native\",\n\t\t\tkind,\n\t\t\tscope,\n\t\t\tdurability: \"durable\",\n\t\t\ttitle,\n\t\t\tsummary: description,\n\t\t\tcontent: body.length > 0 ? body : undefined,\n\t\t\trefs: [ref],\n\t\t\tevidenceRefs: evidenceRefsFromOkf(providerId, evidenceRefs),\n\t\t\ttimestamp,\n\t\t},\n\t};\n}\n\nexport function formatOkfMemoryDocument(input: OkfMemoryDocumentInput): string {\n\tconst frontmatter = {\n\t\ttype: input.type,\n\t\ttitle: input.title,\n\t\tdescription: input.description,\n\t\ttags: input.tags,\n\t\ttimestamp: input.timestamp,\n\t\tpi: {\n\t\t\tscope: input.scope,\n\t\t\tauthority: PI_OKF_AUTHORITY,\n\t\t\tevidence_refs: input.evidenceRefs ?? [],\n\t\t},\n\t};\n\treturn `---\\n${stringify(frontmatter).trim()}\\n---\\n\\n${input.body.trim()}\\n`;\n}\n\nexport function okfMemoryItemToWriteRequest(item: MemoryItem, reason: string): MemoryWriteRequest {\n\treturn {\n\t\tproviderId: item.providerId,\n\t\tscope: item.scope,\n\t\tkind: item.kind,\n\t\ttitle: item.title,\n\t\tsummary: item.summary,\n\t\tcontent: item.content,\n\t\tevidenceRefs: item.evidenceRefs,\n\t\tsensitivity: \"normal\",\n\t\treason,\n\t};\n}\n\nexport function validateOkfProjectRulePromotion(\n\trequest: OkfProjectRulePromotionRequest,\n): OkfProjectRulePromotionRejection[] {\n\tconst rejections: OkfProjectRulePromotionRejection[] = [];\n\tif (request.item.kind !== \"project_rule_candidate\") rejections.push(\"not_project_rule_candidate\");\n\tif (request.approvalId === undefined && request.trustedConfigPath === undefined) {\n\t\trejections.push(\"missing_explicit_promotion_authority\");\n\t}\n\tif (request.item.stale || request.item.conflict !== undefined) rejections.push(\"stale_or_conflicting_memory\");\n\treturn rejections;\n}\n"]}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Pure policy-engine primitives (Phase 0.6): a hard-constraint evaluator, break-even
3
+ * scoring helpers, and reason-code formatting. No provider calls, no I/O, no wiring into
4
+ * prompt construction, model routing, or validation yet.
5
+ *
6
+ * The one invariant every helper here must uphold: a hard constraint can never be
7
+ * overridden by a positive expected saving. Scoring only runs for candidates that already
8
+ * cleared the hard-constraint layer.
9
+ */
10
+ import type { HardConstraintFlags, PolicyAction, PolicyCandidateScore, PolicyFeatures, PolicyHardConstraintCode } from "./policy-types.ts";
11
+ /**
12
+ * Evaluate hard constraints for a single candidate action. Returns the (possibly empty)
13
+ * list of violated constraint codes; any non-empty result means the action must be
14
+ * rejected outright, never merely down-weighted by scoring.
15
+ */
16
+ export declare function evaluateHardConstraints(action: PolicyAction, features: PolicyFeatures, flags: HardConstraintFlags): PolicyHardConstraintCode[];
17
+ /**
18
+ * Inputs to the context-retention break-even formula from decision-math-and-research.md:
19
+ * saving(i) = N_remaining * (T_raw - T_digest) * C_token - C_pack - P_need*C_retrieve
20
+ * - P_error*C_error - C_cache
21
+ */
22
+ export interface ContextRetentionSavingInputs {
23
+ rawTokens: number;
24
+ compactTokens: number;
25
+ expectedRemainingTurns: number;
26
+ marginalInputTokenCost: number;
27
+ packCostTokens: number;
28
+ probabilityNeededAgain: number;
29
+ retrievalCostTokens: number;
30
+ probabilityErrorIfDropped: number;
31
+ errorCostTokens: number;
32
+ cacheImpactTokens: number;
33
+ }
34
+ export declare function computeContextRetentionSaving(inputs: ContextRetentionSavingInputs): number;
35
+ /**
36
+ * N_break_even(i) from decision-math-and-research.md: the number of remaining turns at
37
+ * which packing/summarizing first becomes worthwhile. Returns +Infinity when the raw vs.
38
+ * compact token gap never pays for itself (per-turn saving is zero or negative).
39
+ */
40
+ export declare function computeBreakEvenRemainingTurns(inputs: Omit<ContextRetentionSavingInputs, "expectedRemainingTurns"> & {
41
+ margin: number;
42
+ }): number;
43
+ /**
44
+ * Hard cap override from policy-engine-spec.md: oversized raw tool output must be packed
45
+ * regardless of break-even math, unless the item is pinned, current, or the latest
46
+ * failure.
47
+ */
48
+ export declare function exceedsHardOutputCap(rawTokens: number, maxRawToolOutputTokens: number, features: Pick<PolicyFeatures, "isPinned" | "isCurrentDiff" | "isLatestFailure">): boolean;
49
+ export interface ContextRetentionCandidateInput {
50
+ action: PolicyAction;
51
+ features: PolicyFeatures;
52
+ flags: HardConstraintFlags;
53
+ saving: ContextRetentionSavingInputs;
54
+ margin: number;
55
+ confidence: "low" | "medium" | "high";
56
+ }
57
+ /**
58
+ * Score one context-retention candidate. Hard constraints are checked first and, if any
59
+ * fire, the candidate is returned as unappliable (infinite cost, zero savings) no matter
60
+ * what the break-even math says — a hard constraint can never be overridden by savings.
61
+ */
62
+ export declare function scoreContextRetentionCandidate(input: ContextRetentionCandidateInput): PolicyCandidateScore;
63
+ export declare function formatHardConstraintReason(code: PolicyHardConstraintCode): string;
64
+ /** Human-readable, deterministic summary of a scored candidate's reason codes. */
65
+ export declare function formatCandidateReason(candidate: Pick<PolicyCandidateScore, "action" | "reasonCodes">): string;
66
+ //# sourceMappingURL=policy-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-engine.d.ts","sourceRoot":"","sources":["../../../src/core/context/policy-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACX,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,wBAAwB,EACxB,MAAM,mBAAmB,CAAC;AAY3B;;;;GAIG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,mBAAmB,GACxB,wBAAwB,EAAE,CA0C5B;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,4BAA4B,GAAG,MAAM,CAS1F;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC7C,MAAM,EAAE,IAAI,CAAC,4BAA4B,EAAE,wBAAwB,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GACvF,MAAM,CAUR;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,MAAM,EACjB,sBAAsB,EAAE,MAAM,EAC9B,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC,GAC9E,OAAO,CAGT;AAED,MAAM,WAAW,8BAA8B;IAC9C,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,4BAA4B,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,8BAA8B,GAAG,oBAAoB,CAkC1G;AAgBD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,wBAAwB,GAAG,MAAM,CAEjF;AAED,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,aAAa,CAAC,GAAG,MAAM,CAQ7G","sourcesContent":["/**\n * Pure policy-engine primitives (Phase 0.6): a hard-constraint evaluator, break-even\n * scoring helpers, and reason-code formatting. No provider calls, no I/O, no wiring into\n * prompt construction, model routing, or validation yet.\n *\n * The one invariant every helper here must uphold: a hard constraint can never be\n * overridden by a positive expected saving. Scoring only runs for candidates that already\n * cleared the hard-constraint layer.\n */\n\nimport type {\n\tHardConstraintFlags,\n\tPolicyAction,\n\tPolicyCandidateScore,\n\tPolicyFeatures,\n\tPolicyHardConstraintCode,\n} from \"./policy-types.ts\";\n\nconst AGGRESSIVE_CONTEXT_ACTIONS: ReadonlySet<PolicyAction> = new Set([\n\t\"summarize\",\n\t\"drop_from_prompt\",\n\t\"pack_to_artifact\",\n]);\n\nfunction pushUnique(codes: PolicyHardConstraintCode[], code: PolicyHardConstraintCode): void {\n\tif (!codes.includes(code)) codes.push(code);\n}\n\n/**\n * Evaluate hard constraints for a single candidate action. Returns the (possibly empty)\n * list of violated constraint codes; any non-empty result means the action must be\n * rejected outright, never merely down-weighted by scoring.\n */\nexport function evaluateHardConstraints(\n\taction: PolicyAction,\n\tfeatures: PolicyFeatures,\n\tflags: HardConstraintFlags,\n): PolicyHardConstraintCode[] {\n\tconst codes: PolicyHardConstraintCode[] = [];\n\n\tif (AGGRESSIVE_CONTEXT_ACTIONS.has(action)) {\n\t\tif (features.isPinned) pushUnique(codes, \"pinned_user_instruction\");\n\t\tif (flags.isApprovalOrDenial) pushUnique(codes, \"approval_or_denial\");\n\t\tif (flags.isSafetyConstraint) pushUnique(codes, \"safety_constraint\");\n\t\tif (features.isOpenRequirement) pushUnique(codes, \"open_requirement\");\n\t\tif (flags.isActiveBlocker) pushUnique(codes, \"active_blocker\");\n\t\tif (features.isLatestFailure) pushUnique(codes, \"latest_unresolved_failure\");\n\t\tif (features.isCurrentDiff) pushUnique(codes, \"current_diff_summary\");\n\t\tif (flags.isCurrentValidationResult) pushUnique(codes, \"current_validation_result\");\n\t\tif (flags.isPathOrToolScope) pushUnique(codes, \"path_or_tool_scope\");\n\t}\n\n\t// drop_from_prompt discards content outright, so it requires a retrieval path that\n\t// already exists. pack_to_artifact is the first-capture operation that *creates* the\n\t// retrieval path (tool-output-artifacts.md: measure -> digest/preview/artifact -> prompt\n\t// item), so it must not be rejected merely for lacking one; it only needs a working\n\t// artifact store to write into.\n\tif (action === \"drop_from_prompt\" && !flags.hasAvailableRetrievalPath) {\n\t\tpushUnique(codes, \"missing_retrieval_path\");\n\t}\n\tif (action === \"pack_to_artifact\" && !flags.artifactStoreAvailable) {\n\t\tpushUnique(codes, \"missing_retrieval_path\");\n\t}\n\n\tif (action === \"summarize\" && features.isDecisionBearing && !flags.hasEvidenceRefForSummary) {\n\t\tpushUnique(codes, \"missing_retrieval_path\");\n\t}\n\n\tif (action === \"route_cheap\") {\n\t\tif (features.taskRisk === \"high\" || features.taskRisk === \"unknown\" || features.taskRisk === undefined) {\n\t\t\tpushUnique(codes, \"unknown_risk\");\n\t\t}\n\t\tif (flags.isHighImpactOrBroadMultiFileEdit) pushUnique(codes, \"unknown_risk\");\n\t\tif (flags.priorAttemptFailedForReasoningOrArchitecture) pushUnique(codes, \"unknown_risk\");\n\t\tif (!flags.validationAvailableAndStrong) pushUnique(codes, \"unknown_risk\");\n\t\tif (!flags.pathOrToolBoundariesEnforced) pushUnique(codes, \"path_or_tool_scope\");\n\t}\n\n\treturn codes;\n}\n\n/**\n * Inputs to the context-retention break-even formula from decision-math-and-research.md:\n * saving(i) = N_remaining * (T_raw - T_digest) * C_token - C_pack - P_need*C_retrieve\n * - P_error*C_error - C_cache\n */\nexport interface ContextRetentionSavingInputs {\n\trawTokens: number;\n\tcompactTokens: number;\n\texpectedRemainingTurns: number;\n\tmarginalInputTokenCost: number;\n\tpackCostTokens: number;\n\tprobabilityNeededAgain: number;\n\tretrievalCostTokens: number;\n\tprobabilityErrorIfDropped: number;\n\terrorCostTokens: number;\n\tcacheImpactTokens: number;\n}\n\nexport function computeContextRetentionSaving(inputs: ContextRetentionSavingInputs): number {\n\tconst rawCost = inputs.expectedRemainingTurns * inputs.rawTokens * inputs.marginalInputTokenCost;\n\tconst compactCost = inputs.expectedRemainingTurns * inputs.compactTokens * inputs.marginalInputTokenCost;\n\tconst oneTimeCost =\n\t\tinputs.packCostTokens +\n\t\tinputs.probabilityNeededAgain * inputs.retrievalCostTokens +\n\t\tinputs.probabilityErrorIfDropped * inputs.errorCostTokens +\n\t\tinputs.cacheImpactTokens;\n\treturn rawCost - compactCost - oneTimeCost;\n}\n\n/**\n * N_break_even(i) from decision-math-and-research.md: the number of remaining turns at\n * which packing/summarizing first becomes worthwhile. Returns +Infinity when the raw vs.\n * compact token gap never pays for itself (per-turn saving is zero or negative).\n */\nexport function computeBreakEvenRemainingTurns(\n\tinputs: Omit<ContextRetentionSavingInputs, \"expectedRemainingTurns\"> & { margin: number },\n): number {\n\tconst perTurnSaving = (inputs.rawTokens - inputs.compactTokens) * inputs.marginalInputTokenCost;\n\tif (perTurnSaving <= 0) return Number.POSITIVE_INFINITY;\n\tconst oneTimeCost =\n\t\tinputs.packCostTokens +\n\t\tinputs.probabilityNeededAgain * inputs.retrievalCostTokens +\n\t\tinputs.probabilityErrorIfDropped * inputs.errorCostTokens +\n\t\tinputs.cacheImpactTokens +\n\t\tinputs.margin;\n\treturn oneTimeCost / perTurnSaving;\n}\n\n/**\n * Hard cap override from policy-engine-spec.md: oversized raw tool output must be packed\n * regardless of break-even math, unless the item is pinned, current, or the latest\n * failure.\n */\nexport function exceedsHardOutputCap(\n\trawTokens: number,\n\tmaxRawToolOutputTokens: number,\n\tfeatures: Pick<PolicyFeatures, \"isPinned\" | \"isCurrentDiff\" | \"isLatestFailure\">,\n): boolean {\n\tif (features.isPinned || features.isCurrentDiff || features.isLatestFailure) return false;\n\treturn rawTokens > maxRawToolOutputTokens;\n}\n\nexport interface ContextRetentionCandidateInput {\n\taction: PolicyAction;\n\tfeatures: PolicyFeatures;\n\tflags: HardConstraintFlags;\n\tsaving: ContextRetentionSavingInputs;\n\tmargin: number;\n\tconfidence: \"low\" | \"medium\" | \"high\";\n}\n\n/**\n * Score one context-retention candidate. Hard constraints are checked first and, if any\n * fire, the candidate is returned as unappliable (infinite cost, zero savings) no matter\n * what the break-even math says — a hard constraint can never be overridden by savings.\n */\nexport function scoreContextRetentionCandidate(input: ContextRetentionCandidateInput): PolicyCandidateScore {\n\tconst hardConstraints = evaluateHardConstraints(input.action, input.features, input.flags);\n\tif (hardConstraints.length > 0) {\n\t\treturn {\n\t\t\taction: input.action,\n\t\t\texpectedCostTokens: Number.POSITIVE_INFINITY,\n\t\t\texpectedSavingsTokens: 0,\n\t\t\texpectedReliabilityRisk: 1,\n\t\t\tcacheImpactTokens: input.saving.cacheImpactTokens,\n\t\t\treworkRiskTokens: input.saving.probabilityErrorIfDropped * input.saving.errorCostTokens,\n\t\t\tconfidence: \"low\",\n\t\t\treasonCodes: hardConstraints,\n\t\t};\n\t}\n\n\tconst saving = computeContextRetentionSaving(input.saving);\n\tconst applied = saving > input.margin;\n\tconst decisionBearingLowConfidence = input.features.isDecisionBearing && input.confidence === \"low\";\n\n\treturn {\n\t\taction: input.action,\n\t\texpectedCostTokens: input.saving.packCostTokens + input.saving.cacheImpactTokens,\n\t\texpectedSavingsTokens: Math.max(0, saving),\n\t\texpectedReliabilityRisk: input.saving.probabilityErrorIfDropped,\n\t\tcacheImpactTokens: input.saving.cacheImpactTokens,\n\t\treworkRiskTokens: input.saving.probabilityErrorIfDropped * input.saving.errorCostTokens,\n\t\tconfidence: input.confidence,\n\t\treasonCodes:\n\t\t\tapplied && !decisionBearingLowConfidence\n\t\t\t\t? [\"saving_above_margin\"]\n\t\t\t\t: decisionBearingLowConfidence\n\t\t\t\t\t? [\"low_confidence_decision_bearing\"]\n\t\t\t\t\t: [\"saving_below_margin\"],\n\t};\n}\n\nconst HARD_CONSTRAINT_REASON_TEXT: Record<PolicyHardConstraintCode, string> = {\n\tpinned_user_instruction: \"item is a pinned user instruction and must remain present verbatim\",\n\tapproval_or_denial: \"item records a user approval or denial and cannot be summarized or dropped\",\n\tsafety_constraint: \"item is a safety/security constraint and must remain present verbatim\",\n\topen_requirement: \"item is an open requirement for the active goal and cannot be dropped while active\",\n\tactive_blocker: \"item is an active blocker and must remain present until resolved\",\n\tlatest_unresolved_failure: \"item is the latest unresolved failure; dropping it risks repeating the mistake\",\n\tcurrent_diff_summary: \"item is the current diff summary during active code changes\",\n\tcurrent_validation_result: \"item is the current validation command/result and cannot be dropped while pending\",\n\tmissing_retrieval_path: \"no retrieval path (artifact/evidence ref) exists to recover this content if evicted\",\n\tpath_or_tool_scope: \"item encodes an active path/tool scope restriction that must stay enforced\",\n\tunknown_risk: \"task risk is high or unknown and this action requires stronger reliability guarantees\",\n};\n\nexport function formatHardConstraintReason(code: PolicyHardConstraintCode): string {\n\treturn HARD_CONSTRAINT_REASON_TEXT[code];\n}\n\n/** Human-readable, deterministic summary of a scored candidate's reason codes. */\nexport function formatCandidateReason(candidate: Pick<PolicyCandidateScore, \"action\" | \"reasonCodes\">): string {\n\tconst hardCodes = candidate.reasonCodes.filter(\n\t\t(code): code is PolicyHardConstraintCode => code in HARD_CONSTRAINT_REASON_TEXT,\n\t);\n\tif (hardCodes.length > 0) {\n\t\treturn `${candidate.action} rejected: ${hardCodes.map(formatHardConstraintReason).join(\"; \")}`;\n\t}\n\treturn `${candidate.action}: ${candidate.reasonCodes.join(\", \")}`;\n}\n"]}