pi-obsidian-memory 0.0.1 → 0.1.0

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 (572) hide show
  1. package/README.md +173 -7
  2. package/package.json +41 -11
  3. package/skills/obsidian-memory/SKILL.md +101 -0
  4. package/src/domain/capture/constants.ts +5 -0
  5. package/src/domain/capture/index.ts +6 -0
  6. package/src/domain/capture/input-problems.ts +9 -0
  7. package/src/domain/capture/schemas.ts +92 -0
  8. package/src/domain/capture/tally.ts +26 -0
  9. package/src/domain/capture/types.ts +49 -0
  10. package/src/domain/capture/validate.ts +75 -0
  11. package/src/domain/command-flags/constants.ts +141 -0
  12. package/src/domain/command-flags/index.ts +1 -0
  13. package/src/domain/config/change.ts +105 -0
  14. package/src/domain/config/constants.ts +25 -0
  15. package/src/domain/config/diagnostics.ts +35 -0
  16. package/src/domain/config/disclosures.ts +8 -0
  17. package/src/domain/config/fields.ts +7 -0
  18. package/src/domain/config/index.ts +11 -0
  19. package/src/domain/config/inspection.ts +43 -0
  20. package/src/domain/config/invariants.ts +68 -0
  21. package/src/domain/config/legacy-capture.ts +17 -0
  22. package/src/domain/config/observations.ts +109 -0
  23. package/src/domain/config/parse.ts +25 -0
  24. package/src/domain/config/paths.ts +61 -0
  25. package/src/domain/config/registration.ts +34 -0
  26. package/src/domain/config/repair.ts +36 -0
  27. package/src/domain/config/resources.ts +65 -0
  28. package/src/domain/config/rules.ts +49 -0
  29. package/src/domain/config/schemas.ts +155 -0
  30. package/src/domain/config/settings.ts +23 -0
  31. package/src/domain/config/types.ts +239 -0
  32. package/src/domain/decision-model/constants.ts +7 -0
  33. package/src/domain/decision-model/cutoffs.ts +8 -0
  34. package/src/domain/decision-model/endpoint.ts +11 -0
  35. package/src/domain/decision-model/failure-detail.ts +8 -0
  36. package/src/domain/decision-model/index.ts +6 -0
  37. package/src/domain/decision-model/rank.ts +36 -0
  38. package/src/domain/decision-model/types.ts +77 -0
  39. package/src/domain/embeddings/constants.ts +55 -0
  40. package/src/domain/embeddings/identity.ts +30 -0
  41. package/src/domain/embeddings/index.ts +5 -0
  42. package/src/domain/embeddings/schemas.ts +25 -0
  43. package/src/domain/embeddings/types.ts +52 -0
  44. package/src/domain/embeddings/vectors.ts +53 -0
  45. package/src/domain/folder-index/constants.ts +9 -0
  46. package/src/domain/folder-index/display.ts +22 -0
  47. package/src/domain/folder-index/index.ts +5 -0
  48. package/src/domain/folder-index/listing.ts +58 -0
  49. package/src/domain/folder-index/render.ts +114 -0
  50. package/src/domain/folder-index/types.ts +41 -0
  51. package/src/domain/index.ts +22 -0
  52. package/src/domain/lifecycle/index.ts +2 -0
  53. package/src/domain/lifecycle/lifecycle.ts +39 -0
  54. package/src/domain/lifecycle/types.ts +17 -0
  55. package/src/domain/loaded-memory/budget.ts +14 -0
  56. package/src/domain/loaded-memory/constants.ts +9 -0
  57. package/src/domain/loaded-memory/index.ts +4 -0
  58. package/src/domain/loaded-memory/render.ts +30 -0
  59. package/src/domain/loaded-memory/types.ts +19 -0
  60. package/src/domain/memory/draft.ts +12 -0
  61. package/src/domain/memory/index.ts +4 -0
  62. package/src/domain/memory/schemas.ts +15 -0
  63. package/src/domain/memory/target.ts +27 -0
  64. package/src/domain/memory/types.ts +20 -0
  65. package/src/domain/memory-agent/index.ts +5 -0
  66. package/src/domain/memory-agent/input-problems.ts +9 -0
  67. package/src/domain/memory-agent/refusal.ts +6 -0
  68. package/src/domain/memory-agent/schemas.ts +112 -0
  69. package/src/domain/memory-agent/types.ts +25 -0
  70. package/src/domain/memory-agent/validate.ts +67 -0
  71. package/src/domain/names/constants.ts +32 -0
  72. package/src/domain/names/index.ts +2 -0
  73. package/src/domain/names/names.ts +83 -0
  74. package/src/domain/note/check.ts +68 -0
  75. package/src/domain/note/constants.ts +15 -0
  76. package/src/domain/note/frontmatter-fields.ts +175 -0
  77. package/src/domain/note/frontmatter.ts +138 -0
  78. package/src/domain/note/index.ts +9 -0
  79. package/src/domain/note/parse.ts +41 -0
  80. package/src/domain/note/render.ts +27 -0
  81. package/src/domain/note/schema-errors.ts +41 -0
  82. package/src/domain/note/schemas.ts +38 -0
  83. package/src/domain/note/types.ts +53 -0
  84. package/src/domain/note/validate.ts +19 -0
  85. package/src/domain/path-platform/index.ts +2 -0
  86. package/src/domain/path-platform/path-module.ts +11 -0
  87. package/src/domain/path-platform/types.ts +1 -0
  88. package/src/domain/search-catalog/constants.ts +1 -0
  89. package/src/domain/search-catalog/coverage.ts +35 -0
  90. package/src/domain/search-catalog/dont-forget.ts +10 -0
  91. package/src/domain/search-catalog/fingerprint.ts +9 -0
  92. package/src/domain/search-catalog/index.ts +10 -0
  93. package/src/domain/search-catalog/inspection.ts +47 -0
  94. package/src/domain/search-catalog/plan.ts +68 -0
  95. package/src/domain/search-catalog/ranking.ts +27 -0
  96. package/src/domain/search-catalog/schemas.ts +49 -0
  97. package/src/domain/search-catalog/types.ts +103 -0
  98. package/src/domain/search-catalog/vector-refresh.ts +22 -0
  99. package/src/domain/shell-edit/command-segments.ts +28 -0
  100. package/src/domain/shell-edit/command-words.ts +22 -0
  101. package/src/domain/shell-edit/constants.ts +125 -0
  102. package/src/domain/shell-edit/executed-files.ts +154 -0
  103. package/src/domain/shell-edit/index.ts +6 -0
  104. package/src/domain/shell-edit/powershell-files.ts +38 -0
  105. package/src/domain/shell-edit/rules.ts +19 -0
  106. package/src/domain/shell-edit/types.ts +75 -0
  107. package/src/domain/tool-flags/constants.ts +178 -0
  108. package/src/domain/tool-flags/index.ts +2 -0
  109. package/src/domain/tool-flags/types.ts +7 -0
  110. package/src/domain/validation/constants.ts +1 -0
  111. package/src/domain/validation/describe.ts +137 -0
  112. package/src/domain/validation/index.ts +3 -0
  113. package/src/domain/validation/types.ts +3 -0
  114. package/src/domain/vault-access/absolute-candidate.ts +81 -0
  115. package/src/domain/vault-access/argument-tokens.ts +22 -0
  116. package/src/domain/vault-access/command-mentions-vault.ts +115 -0
  117. package/src/domain/vault-access/constants.ts +54 -0
  118. package/src/domain/vault-access/index.ts +7 -0
  119. package/src/domain/vault-access/types.ts +18 -0
  120. package/src/domain/vault-access/vault-access-refusal.ts +36 -0
  121. package/src/domain/vault-access/vault-location.ts +22 -0
  122. package/src/domain/vault-assets/index.ts +2 -0
  123. package/src/domain/vault-assets/render.ts +51 -0
  124. package/src/domain/vault-assets/types.ts +36 -0
  125. package/src/domain/vault-catalog/analyze.ts +37 -0
  126. package/src/domain/vault-catalog/classify.ts +37 -0
  127. package/src/domain/vault-catalog/dont-forget.ts +6 -0
  128. package/src/domain/vault-catalog/export-entries.ts +10 -0
  129. package/src/domain/vault-catalog/index.ts +5 -0
  130. package/src/domain/vault-catalog/types.ts +114 -0
  131. package/src/domain/vault-diagnosis/diagnose.ts +79 -0
  132. package/src/domain/vault-diagnosis/index.ts +2 -0
  133. package/src/domain/vault-diagnosis/types.ts +31 -0
  134. package/src/domain/vault-path/constants.ts +13 -0
  135. package/src/domain/vault-path/index.ts +2 -0
  136. package/src/domain/vault-path/vault-path.ts +65 -0
  137. package/src/pi/capture/cadence.ts +49 -0
  138. package/src/pi/capture/completion.ts +26 -0
  139. package/src/pi/capture/constants.ts +5 -0
  140. package/src/pi/capture/handlers.ts +30 -0
  141. package/src/pi/capture/index.ts +8 -0
  142. package/src/pi/capture/runtime.ts +83 -0
  143. package/src/pi/capture/schemas.ts +8 -0
  144. package/src/pi/capture/tool-calls.ts +6 -0
  145. package/src/pi/capture/transcript.ts +55 -0
  146. package/src/pi/capture/types.ts +46 -0
  147. package/src/pi/change-report/constants.ts +15 -0
  148. package/src/pi/change-report/index.ts +3 -0
  149. package/src/pi/change-report/report.ts +54 -0
  150. package/src/pi/change-report/types.ts +8 -0
  151. package/src/pi/context/constants.ts +5 -0
  152. package/src/pi/context/index.ts +3 -0
  153. package/src/pi/context/status.ts +15 -0
  154. package/src/pi/context/types.ts +98 -0
  155. package/src/pi/extension.ts +100 -0
  156. package/src/pi/index.ts +26 -0
  157. package/src/pi/memory-add/constants.ts +13 -0
  158. package/src/pi/memory-add/index.ts +5 -0
  159. package/src/pi/memory-add/memory-add.ts +31 -0
  160. package/src/pi/memory-add/respond.ts +55 -0
  161. package/src/pi/memory-add/schemas.ts +29 -0
  162. package/src/pi/memory-add/types.ts +15 -0
  163. package/src/pi/memory-archive/constants.ts +8 -0
  164. package/src/pi/memory-archive/index.ts +4 -0
  165. package/src/pi/memory-archive/memory-archive.ts +29 -0
  166. package/src/pi/memory-archive/schemas.ts +15 -0
  167. package/src/pi/memory-archive/types.ts +8 -0
  168. package/src/pi/memory-block/block.ts +75 -0
  169. package/src/pi/memory-block/constants.ts +24 -0
  170. package/src/pi/memory-block/index.ts +4 -0
  171. package/src/pi/memory-block/render.ts +54 -0
  172. package/src/pi/memory-block/types.ts +24 -0
  173. package/src/pi/memory-doctor/constants.ts +43 -0
  174. package/src/pi/memory-doctor/index.ts +4 -0
  175. package/src/pi/memory-doctor/memory-doctor.ts +135 -0
  176. package/src/pi/memory-doctor/report.ts +101 -0
  177. package/src/pi/memory-doctor/types.ts +13 -0
  178. package/src/pi/memory-export/constants.ts +15 -0
  179. package/src/pi/memory-export/index.ts +4 -0
  180. package/src/pi/memory-export/memory-export.ts +57 -0
  181. package/src/pi/memory-export/name.ts +9 -0
  182. package/src/pi/memory-export/types.ts +4 -0
  183. package/src/pi/memory-get/constants.ts +12 -0
  184. package/src/pi/memory-get/index.ts +5 -0
  185. package/src/pi/memory-get/memory-get.ts +23 -0
  186. package/src/pi/memory-get/respond.ts +38 -0
  187. package/src/pi/memory-get/schemas.ts +13 -0
  188. package/src/pi/memory-get/types.ts +10 -0
  189. package/src/pi/memory-init/constants.ts +17 -0
  190. package/src/pi/memory-init/index.ts +2 -0
  191. package/src/pi/memory-init/memory-init.ts +63 -0
  192. package/src/pi/memory-search/constants.ts +16 -0
  193. package/src/pi/memory-search/index.ts +5 -0
  194. package/src/pi/memory-search/memory-search.ts +22 -0
  195. package/src/pi/memory-search/respond.ts +62 -0
  196. package/src/pi/memory-search/schemas.ts +11 -0
  197. package/src/pi/memory-search/types.ts +10 -0
  198. package/src/pi/memory-session/constants.ts +7 -0
  199. package/src/pi/memory-session/index.ts +4 -0
  200. package/src/pi/memory-session/keeper.ts +101 -0
  201. package/src/pi/memory-session/respond.ts +6 -0
  202. package/src/pi/memory-session/types.ts +23 -0
  203. package/src/pi/memory-settings/constants.ts +69 -0
  204. package/src/pi/memory-settings/edits.ts +46 -0
  205. package/src/pi/memory-settings/index.ts +9 -0
  206. package/src/pi/memory-settings/lines.ts +119 -0
  207. package/src/pi/memory-settings/models.ts +81 -0
  208. package/src/pi/memory-settings/projects.ts +46 -0
  209. package/src/pi/memory-settings/providers.ts +77 -0
  210. package/src/pi/memory-settings/save.ts +16 -0
  211. package/src/pi/memory-settings/screen.ts +27 -0
  212. package/src/pi/memory-settings/types.ts +87 -0
  213. package/src/pi/memory-setup/constants.ts +33 -0
  214. package/src/pi/memory-setup/disclosure.ts +22 -0
  215. package/src/pi/memory-setup/index.ts +4 -0
  216. package/src/pi/memory-setup/memory-setup.ts +153 -0
  217. package/src/pi/memory-setup/types.ts +6 -0
  218. package/src/pi/memory-succeed/constants.ts +10 -0
  219. package/src/pi/memory-succeed/index.ts +4 -0
  220. package/src/pi/memory-succeed/memory-succeed.ts +34 -0
  221. package/src/pi/memory-succeed/schemas.ts +30 -0
  222. package/src/pi/memory-succeed/types.ts +8 -0
  223. package/src/pi/memory-update/constants.ts +8 -0
  224. package/src/pi/memory-update/index.ts +4 -0
  225. package/src/pi/memory-update/memory-update.ts +29 -0
  226. package/src/pi/memory-update/schemas.ts +24 -0
  227. package/src/pi/memory-update/types.ts +8 -0
  228. package/src/pi/paths/constants.ts +7 -0
  229. package/src/pi/paths/index.ts +2 -0
  230. package/src/pi/paths/paths.ts +15 -0
  231. package/src/pi/paths/platform.ts +7 -0
  232. package/src/pi/registrar.ts +25 -0
  233. package/src/pi/registration-report/constants.ts +13 -0
  234. package/src/pi/registration-report/index.ts +2 -0
  235. package/src/pi/registration-report/report.ts +26 -0
  236. package/src/pi/relevant-memory/constants.ts +3 -0
  237. package/src/pi/relevant-memory/index.ts +4 -0
  238. package/src/pi/relevant-memory/prompt.ts +23 -0
  239. package/src/pi/relevant-memory/runtime.ts +88 -0
  240. package/src/pi/relevant-memory/types.ts +14 -0
  241. package/src/pi/semantic/constants.ts +3 -0
  242. package/src/pi/semantic/index.ts +2 -0
  243. package/src/pi/semantic/runtime.ts +59 -0
  244. package/src/pi/session-start/constants.ts +7 -0
  245. package/src/pi/session-start/index.ts +3 -0
  246. package/src/pi/session-start/session-start.ts +48 -0
  247. package/src/pi/session-start/types.ts +5 -0
  248. package/src/pi/shell-edit-guard/guard.ts +41 -0
  249. package/src/pi/shell-edit-guard/index.ts +3 -0
  250. package/src/pi/shell-edit-guard/prompt.ts +30 -0
  251. package/src/pi/shell-edit-guard/types.ts +13 -0
  252. package/src/pi/types.ts +44 -0
  253. package/src/pi/vault-guard/constants.ts +1 -0
  254. package/src/pi/vault-guard/index.ts +4 -0
  255. package/src/pi/vault-guard/request.ts +39 -0
  256. package/src/pi/vault-guard/types.ts +5 -0
  257. package/src/pi/vault-guard/vault-guard.ts +21 -0
  258. package/src/services/capture-cadence/domain-rules.ts +8 -0
  259. package/src/services/capture-cadence/index.ts +1 -0
  260. package/src/services/clock/clock.ts +7 -0
  261. package/src/services/clock/index.ts +1 -0
  262. package/src/services/config/canonicalize.ts +163 -0
  263. package/src/services/config/constants.ts +1 -0
  264. package/src/services/config/fully-qualified-path.ts +14 -0
  265. package/src/services/config/index.ts +12 -0
  266. package/src/services/config/path-identity.ts +65 -0
  267. package/src/services/config/publication.ts +75 -0
  268. package/src/services/config/read.ts +47 -0
  269. package/src/services/config/registration.ts +26 -0
  270. package/src/services/config/resolve-input.ts +27 -0
  271. package/src/services/config/snapshot.ts +26 -0
  272. package/src/services/config/target.ts +2 -0
  273. package/src/services/config/types.ts +97 -0
  274. package/src/services/config/vault-access.ts +2 -0
  275. package/src/services/config/volume-namespace.ts +5 -0
  276. package/src/services/config/write.ts +63 -0
  277. package/src/services/decision-model/constants.ts +16 -0
  278. package/src/services/decision-model/decide.ts +42 -0
  279. package/src/services/decision-model/diagnostics.ts +6 -0
  280. package/src/services/decision-model/endpoint.ts +1 -0
  281. package/src/services/decision-model/failure-detail.ts +1 -0
  282. package/src/services/decision-model/index.ts +7 -0
  283. package/src/services/decision-model/interruption.ts +29 -0
  284. package/src/services/decision-model/jev.ts +61 -0
  285. package/src/services/decision-model/laya-batch.ts +64 -0
  286. package/src/services/decision-model/laya-http-failure.ts +41 -0
  287. package/src/services/decision-model/laya-response.ts +95 -0
  288. package/src/services/decision-model/laya.ts +35 -0
  289. package/src/services/decision-model/preflight.ts +24 -0
  290. package/src/services/decision-model/prompts.ts +36 -0
  291. package/src/services/decision-model/schemas.ts +43 -0
  292. package/src/services/decision-model/score-candidates.ts +41 -0
  293. package/src/services/decision-model/types.ts +182 -0
  294. package/src/services/embeddings/asset-download.ts +45 -0
  295. package/src/services/embeddings/asset-fetch.ts +39 -0
  296. package/src/services/embeddings/asset-inspection.ts +36 -0
  297. package/src/services/embeddings/batch.ts +32 -0
  298. package/src/services/embeddings/chunks.ts +80 -0
  299. package/src/services/embeddings/configuration.ts +8 -0
  300. package/src/services/embeddings/constants.ts +24 -0
  301. package/src/services/embeddings/errors.ts +11 -0
  302. package/src/services/embeddings/google.ts +90 -0
  303. package/src/services/embeddings/http.ts +64 -0
  304. package/src/services/embeddings/index.ts +17 -0
  305. package/src/services/embeddings/inference.ts +35 -0
  306. package/src/services/embeddings/local.ts +138 -0
  307. package/src/services/embeddings/model-asset.ts +68 -0
  308. package/src/services/embeddings/model-cache.ts +30 -0
  309. package/src/services/embeddings/openai.ts +64 -0
  310. package/src/services/embeddings/operation.ts +31 -0
  311. package/src/services/embeddings/responses.ts +41 -0
  312. package/src/services/embeddings/runtime.ts +13 -0
  313. package/src/services/embeddings/schemas.ts +53 -0
  314. package/src/services/embeddings/types.ts +116 -0
  315. package/src/services/id/id.ts +5 -0
  316. package/src/services/id/index.ts +1 -0
  317. package/src/services/index.ts +11 -0
  318. package/src/services/llm/capture.ts +19 -0
  319. package/src/services/llm/check-chat-models.ts +38 -0
  320. package/src/services/llm/complete.ts +57 -0
  321. package/src/services/llm/constants.ts +32 -0
  322. package/src/services/llm/domain-rules.ts +2 -0
  323. package/src/services/llm/index.ts +6 -0
  324. package/src/services/llm/lifetime.ts +16 -0
  325. package/src/services/llm/retrieve.ts +19 -0
  326. package/src/services/llm/schemas.ts +9 -0
  327. package/src/services/llm/types.ts +94 -0
  328. package/src/services/search-index/catalog-query.ts +34 -0
  329. package/src/services/search-index/catalog-statements.ts +33 -0
  330. package/src/services/search-index/catalog.ts +19 -0
  331. package/src/services/search-index/cleanup.ts +13 -0
  332. package/src/services/search-index/close.ts +5 -0
  333. package/src/services/search-index/constants.ts +102 -0
  334. package/src/services/search-index/dont-forget.ts +1 -0
  335. package/src/services/search-index/fingerprint.ts +17 -0
  336. package/src/services/search-index/folder-index-statements.ts +17 -0
  337. package/src/services/search-index/folder-index-storage.ts +54 -0
  338. package/src/services/search-index/folder-indexes.ts +13 -0
  339. package/src/services/search-index/index.ts +14 -0
  340. package/src/services/search-index/inspection.ts +1 -0
  341. package/src/services/search-index/inventory.ts +67 -0
  342. package/src/services/search-index/legacy.ts +64 -0
  343. package/src/services/search-index/location.ts +12 -0
  344. package/src/services/search-index/open.ts +46 -0
  345. package/src/services/search-index/query.ts +39 -0
  346. package/src/services/search-index/ranking.ts +12 -0
  347. package/src/services/search-index/reconcile.ts +93 -0
  348. package/src/services/search-index/recovery.ts +56 -0
  349. package/src/services/search-index/refusals.ts +21 -0
  350. package/src/services/search-index/schema.ts +42 -0
  351. package/src/services/search-index/schemas.ts +181 -0
  352. package/src/services/search-index/search.ts +5 -0
  353. package/src/services/search-index/statements.ts +18 -0
  354. package/src/services/search-index/storage.ts +207 -0
  355. package/src/services/search-index/types.ts +113 -0
  356. package/src/services/search-index/vector-statements.ts +18 -0
  357. package/src/services/search-index/vector-storage.ts +169 -0
  358. package/src/services/search-index/vectors.ts +18 -0
  359. package/src/services/search-index/write.ts +9 -0
  360. package/src/services/shell-edit/ask.ts +53 -0
  361. package/src/services/shell-edit/domain-rules.ts +2 -0
  362. package/src/services/shell-edit/index.ts +4 -0
  363. package/src/services/shell-edit/schemas.ts +23 -0
  364. package/src/services/shell-edit/types.ts +61 -0
  365. package/src/services/shell-scripts/constants.ts +1 -0
  366. package/src/services/shell-scripts/files.ts +16 -0
  367. package/src/services/shell-scripts/index.ts +5 -0
  368. package/src/services/shell-scripts/package-scripts.ts +74 -0
  369. package/src/services/shell-scripts/schemas.ts +3 -0
  370. package/src/services/shell-scripts/scripts.ts +27 -0
  371. package/src/services/shell-scripts/types.ts +11 -0
  372. package/src/services/vault/archive.ts +31 -0
  373. package/src/services/vault/bootstrap/ensure.ts +50 -0
  374. package/src/services/vault/bootstrap/index.ts +2 -0
  375. package/src/services/vault/bootstrap/paths.ts +57 -0
  376. package/src/services/vault/bootstrap/types.ts +17 -0
  377. package/src/services/vault/bootstrap/write.ts +47 -0
  378. package/src/services/vault/catalog/bytes.ts +51 -0
  379. package/src/services/vault/catalog/dont-forget.ts +1 -0
  380. package/src/services/vault/catalog/enumerate.ts +69 -0
  381. package/src/services/vault/catalog/export.ts +21 -0
  382. package/src/services/vault/catalog/failures.ts +16 -0
  383. package/src/services/vault/catalog/index.ts +10 -0
  384. package/src/services/vault/catalog/inspect.ts +41 -0
  385. package/src/services/vault/catalog/observe.ts +35 -0
  386. package/src/services/vault/catalog/resolve.ts +94 -0
  387. package/src/services/vault/catalog/stat.ts +23 -0
  388. package/src/services/vault/catalog/types.ts +69 -0
  389. package/src/services/vault/catalog/visit.ts +58 -0
  390. package/src/services/vault/complete-blank.ts +66 -0
  391. package/src/services/vault/constants.ts +3 -0
  392. package/src/services/vault/context/index.ts +1 -0
  393. package/src/services/vault/context/types.ts +10 -0
  394. package/src/services/vault/create.ts +19 -0
  395. package/src/services/vault/display.ts +6 -0
  396. package/src/services/vault/domain-rules.ts +10 -0
  397. package/src/services/vault/draft.ts +2 -0
  398. package/src/services/vault/filesystem/failures.ts +53 -0
  399. package/src/services/vault/filesystem/hash.ts +5 -0
  400. package/src/services/vault/filesystem/index.ts +5 -0
  401. package/src/services/vault/filesystem/read.ts +61 -0
  402. package/src/services/vault/filesystem/types.ts +36 -0
  403. package/src/services/vault/filesystem/write.ts +80 -0
  404. package/src/services/vault/find.ts +27 -0
  405. package/src/services/vault/folder-contents.ts +31 -0
  406. package/src/services/vault/folder-index/index.ts +2 -0
  407. package/src/services/vault/folder-index/read.ts +87 -0
  408. package/src/services/vault/folder-index/types.ts +19 -0
  409. package/src/services/vault/folder-listing.ts +1 -0
  410. package/src/services/vault/index.ts +21 -0
  411. package/src/services/vault/inspect-folder.ts +13 -0
  412. package/src/services/vault/list.ts +121 -0
  413. package/src/services/vault/memory-folder.ts +24 -0
  414. package/src/services/vault/paths.ts +11 -0
  415. package/src/services/vault/publish.ts +52 -0
  416. package/src/services/vault/read.ts +46 -0
  417. package/src/services/vault/refresh-folders.ts +197 -0
  418. package/src/services/vault/refresh-plan.ts +79 -0
  419. package/src/services/vault/refresh.ts +8 -0
  420. package/src/services/vault/refusals.ts +23 -0
  421. package/src/services/vault/relocate.ts +131 -0
  422. package/src/services/vault/relocation-checks.ts +89 -0
  423. package/src/services/vault/resolve-stored-file.ts +43 -0
  424. package/src/services/vault/resolve.ts +109 -0
  425. package/src/services/vault/succeed.ts +45 -0
  426. package/src/services/vault/types.ts +199 -0
  427. package/src/services/vault/update-file.ts +58 -0
  428. package/src/services/vault/update.ts +22 -0
  429. package/src/services/vault/write-new-file.ts +37 -0
  430. package/src/shared/index.ts +1 -0
  431. package/src/shared/result/index.ts +1 -0
  432. package/src/shared/result/types.ts +17 -0
  433. package/src/usecases/add-memory/add-memory.ts +83 -0
  434. package/src/usecases/add-memory/index.ts +4 -0
  435. package/src/usecases/add-memory/maintenance.ts +23 -0
  436. package/src/usecases/add-memory/schemas.ts +12 -0
  437. package/src/usecases/add-memory/types.ts +47 -0
  438. package/src/usecases/archive-memory/archive-memory.ts +27 -0
  439. package/src/usecases/archive-memory/index.ts +3 -0
  440. package/src/usecases/archive-memory/schemas.ts +11 -0
  441. package/src/usecases/archive-memory/types.ts +17 -0
  442. package/src/usecases/capture-memory/apply.ts +73 -0
  443. package/src/usecases/capture-memory/capture-memory.ts +117 -0
  444. package/src/usecases/capture-memory/constants.ts +15 -0
  445. package/src/usecases/capture-memory/index.ts +5 -0
  446. package/src/usecases/capture-memory/observe.ts +122 -0
  447. package/src/usecases/capture-memory/settings.ts +20 -0
  448. package/src/usecases/capture-memory/types.ts +103 -0
  449. package/src/usecases/check-shell-edit/check-shell-edit.ts +28 -0
  450. package/src/usecases/check-shell-edit/index.ts +2 -0
  451. package/src/usecases/check-shell-edit/types.ts +30 -0
  452. package/src/usecases/check-vault-access/check-vault-access.ts +23 -0
  453. package/src/usecases/check-vault-access/constants.ts +7 -0
  454. package/src/usecases/check-vault-access/index.ts +4 -0
  455. package/src/usecases/check-vault-access/raw-device.ts +10 -0
  456. package/src/usecases/check-vault-access/targets.ts +49 -0
  457. package/src/usecases/check-vault-access/types.ts +33 -0
  458. package/src/usecases/complete-blank-memory/complete-blank-memory.ts +48 -0
  459. package/src/usecases/complete-blank-memory/constants.ts +3 -0
  460. package/src/usecases/complete-blank-memory/index.ts +4 -0
  461. package/src/usecases/complete-blank-memory/schemas.ts +14 -0
  462. package/src/usecases/complete-blank-memory/types.ts +28 -0
  463. package/src/usecases/diagnose-memory/constants.ts +3 -0
  464. package/src/usecases/diagnose-memory/decision.ts +36 -0
  465. package/src/usecases/diagnose-memory/diagnose-memory.ts +52 -0
  466. package/src/usecases/diagnose-memory/embeddings.ts +39 -0
  467. package/src/usecases/diagnose-memory/index.ts +5 -0
  468. package/src/usecases/diagnose-memory/types.ts +86 -0
  469. package/src/usecases/diagnose-memory/vault.ts +33 -0
  470. package/src/usecases/export-memory/collect.ts +20 -0
  471. package/src/usecases/export-memory/constants.ts +3 -0
  472. package/src/usecases/export-memory/export-memory.ts +84 -0
  473. package/src/usecases/export-memory/index.ts +3 -0
  474. package/src/usecases/export-memory/types.ts +28 -0
  475. package/src/usecases/get-memory/get-memory.ts +97 -0
  476. package/src/usecases/get-memory/index.ts +2 -0
  477. package/src/usecases/get-memory/types.ts +25 -0
  478. package/src/usecases/index.ts +25 -0
  479. package/src/usecases/list-memory/index.ts +2 -0
  480. package/src/usecases/list-memory/leased/index.ts +2 -0
  481. package/src/usecases/list-memory/leased/read.ts +16 -0
  482. package/src/usecases/list-memory/leased/types.ts +21 -0
  483. package/src/usecases/list-memory/list-memory.ts +33 -0
  484. package/src/usecases/list-memory/types.ts +8 -0
  485. package/src/usecases/load-dont-forget/index.ts +2 -0
  486. package/src/usecases/load-dont-forget/load-dont-forget.ts +111 -0
  487. package/src/usecases/load-dont-forget/types.ts +26 -0
  488. package/src/usecases/memory-change/change.ts +42 -0
  489. package/src/usecases/memory-change/index.ts +5 -0
  490. package/src/usecases/memory-change/maintenance.ts +11 -0
  491. package/src/usecases/memory-change/partial.ts +18 -0
  492. package/src/usecases/memory-change/receipt.ts +40 -0
  493. package/src/usecases/memory-change/types.ts +44 -0
  494. package/src/usecases/operation-context/context.ts +37 -0
  495. package/src/usecases/operation-context/index.ts +2 -0
  496. package/src/usecases/operation-context/types.ts +19 -0
  497. package/src/usecases/registration/check.ts +6 -0
  498. package/src/usecases/registration/entry.ts +33 -0
  499. package/src/usecases/registration/index.ts +8 -0
  500. package/src/usecases/registration/init.ts +94 -0
  501. package/src/usecases/registration/prepare-init.ts +43 -0
  502. package/src/usecases/registration/prepare.ts +35 -0
  503. package/src/usecases/registration/propose.ts +34 -0
  504. package/src/usecases/registration/publication.ts +90 -0
  505. package/src/usecases/registration/setup.ts +41 -0
  506. package/src/usecases/registration/types.ts +107 -0
  507. package/src/usecases/relevant-memory/agent.ts +55 -0
  508. package/src/usecases/relevant-memory/constants.ts +28 -0
  509. package/src/usecases/relevant-memory/cutoffs.ts +29 -0
  510. package/src/usecases/relevant-memory/decision.ts +102 -0
  511. package/src/usecases/relevant-memory/index.ts +11 -0
  512. package/src/usecases/relevant-memory/loaded.ts +31 -0
  513. package/src/usecases/relevant-memory/refresh.ts +30 -0
  514. package/src/usecases/relevant-memory/retrieve-memory.ts +62 -0
  515. package/src/usecases/relevant-memory/schemas.ts +20 -0
  516. package/src/usecases/relevant-memory/session-memory.ts +53 -0
  517. package/src/usecases/relevant-memory/track-dont-forget.ts +13 -0
  518. package/src/usecases/relevant-memory/types.ts +106 -0
  519. package/src/usecases/resolve-memory/index.ts +2 -0
  520. package/src/usecases/resolve-memory/leased/index.ts +2 -0
  521. package/src/usecases/resolve-memory/leased/resolve.ts +109 -0
  522. package/src/usecases/resolve-memory/leased/types.ts +35 -0
  523. package/src/usecases/resolve-memory/resolve-memory.ts +23 -0
  524. package/src/usecases/resolve-memory/types.ts +7 -0
  525. package/src/usecases/search-memory/constants.ts +1 -0
  526. package/src/usecases/search-memory/index.ts +3 -0
  527. package/src/usecases/search-memory/search-memory.ts +132 -0
  528. package/src/usecases/search-memory/types.ts +39 -0
  529. package/src/usecases/semantic/constants.ts +7 -0
  530. package/src/usecases/semantic/index.ts +5 -0
  531. package/src/usecases/semantic/prepare.ts +30 -0
  532. package/src/usecases/semantic/rank.ts +83 -0
  533. package/src/usecases/semantic/refresh-vectors.ts +95 -0
  534. package/src/usecases/semantic/types.ts +17 -0
  535. package/src/usecases/semantic-port/index.ts +1 -0
  536. package/src/usecases/semantic-port/types.ts +20 -0
  537. package/src/usecases/semantic-provider/constants.ts +6 -0
  538. package/src/usecases/semantic-provider/index.ts +5 -0
  539. package/src/usecases/semantic-provider/local.ts +33 -0
  540. package/src/usecases/semantic-provider/remote.ts +10 -0
  541. package/src/usecases/semantic-provider/size.ts +10 -0
  542. package/src/usecases/semantic-provider/types.ts +19 -0
  543. package/src/usecases/session/index.ts +2 -0
  544. package/src/usecases/session/lease.ts +70 -0
  545. package/src/usecases/session/receipts.ts +46 -0
  546. package/src/usecases/session/state.ts +106 -0
  547. package/src/usecases/session/types.ts +45 -0
  548. package/src/usecases/settings/change.ts +142 -0
  549. package/src/usecases/settings/index.ts +3 -0
  550. package/src/usecases/settings/prepare.ts +24 -0
  551. package/src/usecases/settings/types.ts +32 -0
  552. package/src/usecases/succeed-memory/index.ts +3 -0
  553. package/src/usecases/succeed-memory/schemas.ts +13 -0
  554. package/src/usecases/succeed-memory/succeed-memory.ts +34 -0
  555. package/src/usecases/succeed-memory/types.ts +18 -0
  556. package/src/usecases/synchronize-memory/index.ts +2 -0
  557. package/src/usecases/synchronize-memory/leased/aliases.ts +55 -0
  558. package/src/usecases/synchronize-memory/leased/folder-states.ts +58 -0
  559. package/src/usecases/synchronize-memory/leased/index.ts +2 -0
  560. package/src/usecases/synchronize-memory/leased/inspection.ts +32 -0
  561. package/src/usecases/synchronize-memory/leased/maintenance.ts +41 -0
  562. package/src/usecases/synchronize-memory/leased/publication.ts +55 -0
  563. package/src/usecases/synchronize-memory/leased/scan.ts +37 -0
  564. package/src/usecases/synchronize-memory/leased/synchronize.ts +102 -0
  565. package/src/usecases/synchronize-memory/leased/types.ts +60 -0
  566. package/src/usecases/synchronize-memory/synchronize-memory.ts +26 -0
  567. package/src/usecases/synchronize-memory/types.ts +5 -0
  568. package/src/usecases/update-memory/index.ts +3 -0
  569. package/src/usecases/update-memory/schemas.ts +14 -0
  570. package/src/usecases/update-memory/types.ts +16 -0
  571. package/src/usecases/update-memory/update-memory.ts +31 -0
  572. package/CHANGELOG.md +0 -21
@@ -0,0 +1,47 @@
1
+ import { join } from "node:path"
2
+
3
+ import type { VaultCatalogFailure } from "#src/domain"
4
+ import { catalogFailure, catalogIoFailure, resolveCatalogEntry } from "#src/services/vault/catalog"
5
+ import { publishExclusively } from "#src/services/vault/filesystem"
6
+ import type { Done } from "#src/shared"
7
+ import { existingAsset } from "./paths.ts"
8
+ import type { AssetWriteRequest } from "./types.ts"
9
+
10
+ export async function createAssetExclusively(request: AssetWriteRequest): Promise<Done | VaultCatalogFailure> {
11
+ const existing = await existingAsset(request)
12
+ if (!existing.succeeded) return existing
13
+ if (existing.output !== "") return preserveAsset(request, existing.output)
14
+ const parent = await resolveCatalogEntry({ root: request.root, path: request.folder })
15
+ if (!parent.succeeded) return parent
16
+ return publishAsset(request, parent.output.absolutePath)
17
+ }
18
+
19
+ async function publishAsset(request: AssetWriteRequest, parent: string): Promise<Done | VaultCatalogFailure> {
20
+ const path = [request.folder, request.name].filter((part) => part !== "").join("/")
21
+ try {
22
+ const written = await publishExclusively(join(parent, request.name), request.content)
23
+ if (!written.succeeded) {
24
+ if (written.reason !== "exists") {
25
+ return { succeeded: false, path, scope: "file", reason: "not-writable", problems: written.problems }
26
+ }
27
+ request.progress.maintenanceProblems.push(...written.problems)
28
+ return preserveAsset(request, path)
29
+ }
30
+ if (written.maintenanceProblems) request.progress.maintenanceProblems.push(...written.maintenanceProblems)
31
+ request.progress.created.push(path)
32
+ return { succeeded: true }
33
+ } catch (error) {
34
+ if (error instanceof Error) return catalogIoFailure(error, { path, scope: "file" })
35
+ throw error
36
+ }
37
+ }
38
+
39
+ async function preserveAsset(request: AssetWriteRequest, path: string): Promise<Done | VaultCatalogFailure> {
40
+ const resolved = await resolveCatalogEntry({ root: request.root, path })
41
+ if (!resolved.succeeded) return resolved
42
+ if (resolved.output.kind !== "file") {
43
+ return catalogFailure({ path, scope: "file", reason: "not-file", problem: "The asset path is not a regular file" })
44
+ }
45
+ request.progress.preserved.push(path)
46
+ return { succeeded: true }
47
+ }
@@ -0,0 +1,51 @@
1
+ import { open, stat } from "node:fs/promises"
2
+
3
+ import type { VaultCatalogFailure } from "#src/domain"
4
+ import type { VaultContext } from "#src/services/vault/context"
5
+ import { hashOf } from "#src/services/vault/filesystem"
6
+ import { catalogFailure, catalogIoFailure } from "./failures.ts"
7
+ import { resolveCatalogEntry, resolveCatalogRoot } from "./resolve.ts"
8
+ import { catalogStat, sameCatalogStat } from "./stat.ts"
9
+ import type { CatalogBytesResult, CatalogReadRequest, ResolvedCatalogEntry } from "./types.ts"
10
+
11
+ export async function readCatalogBytes(vault: VaultContext, request: CatalogReadRequest): Promise<CatalogBytesResult> {
12
+ const root = await resolveCatalogRoot(vault)
13
+ if (!root.succeeded) return root
14
+ const resolved = await resolveCatalogEntry({ root: root.output, path: request.path })
15
+ if (!resolved.succeeded) return resolved
16
+ if (resolved.output.kind !== "file") {
17
+ return catalogFailure({ path: request.path, scope: "file", reason: "not-file", problem: "Expected a regular file" })
18
+ }
19
+ try {
20
+ return await readStableBytes(resolved.output, request)
21
+ } catch (error) {
22
+ if (error instanceof Error) return catalogIoFailure(error, { path: request.path, scope: "file" })
23
+ throw error
24
+ }
25
+ }
26
+
27
+ async function readStableBytes(entry: ResolvedCatalogEntry, request: CatalogReadRequest): Promise<CatalogBytesResult> {
28
+ const before = entry.stat
29
+ if (request.expectedStat && !sameCatalogStat(before, request.expectedStat)) return changed(request.path)
30
+ const file = await open(entry.absolutePath, "r")
31
+ try {
32
+ const opened = catalogStat(await file.stat())
33
+ if (!sameCatalogStat(before, opened)) return changed(request.path)
34
+ const bytes = await file.readFile()
35
+ const after = catalogStat(await file.stat())
36
+ if (!sameCatalogStat(before, after)) return changed(request.path)
37
+ if (!sameCatalogStat(after, catalogStat(await stat(entry.absolutePath)))) return changed(request.path)
38
+ return { succeeded: true, output: { path: request.path, bytes, rawHash: hashOf(bytes), stat: after } }
39
+ } finally {
40
+ await file.close()
41
+ }
42
+ }
43
+
44
+ function changed(path: string): VaultCatalogFailure {
45
+ return catalogFailure({
46
+ path,
47
+ scope: "file",
48
+ reason: "changed",
49
+ problem: "The file changed while collecting its snapshot",
50
+ })
51
+ }
@@ -0,0 +1 @@
1
+ export { isLoadedDontForget } from "#src/domain"
@@ -0,0 +1,69 @@
1
+ import type { Dirent } from "node:fs"
2
+ import { readdir } from "node:fs/promises"
3
+
4
+ import { catalogFileKind, isCatalogHidden, isCatalogNotePath, type VaultEnumerationResult } from "#src/domain"
5
+ import type { VaultContext } from "#src/services/vault/context"
6
+ import { catalogIoFailure } from "./failures.ts"
7
+ import { resolveCatalogEntry, resolveCatalogRoot, resolveListedEntry } from "./resolve.ts"
8
+ import type { CatalogResolveResult, CatalogWalk, CatalogWalkRequest } from "./types.ts"
9
+ import { visitCatalogEntry } from "./visit.ts"
10
+
11
+ export async function enumerateVault(vault: VaultContext): Promise<VaultEnumerationResult> {
12
+ return walkVault({ vault, mode: "memory" })
13
+ }
14
+
15
+ export async function walkVault(request: CatalogWalkRequest): Promise<VaultEnumerationResult> {
16
+ const root = await resolveCatalogRoot(request.vault)
17
+ if (!root.succeeded) return root
18
+ const walk: CatalogWalk = {
19
+ ...request,
20
+ root: root.output,
21
+ pending: [""],
22
+ inventory: { entries: [], observedPaths: [], completeDirectories: [], failures: [], aliases: [] },
23
+ }
24
+ while (walk.pending.length > 0) {
25
+ const folder = walk.pending.pop()
26
+ if (typeof folder === "string") await enumerateDirectory(walk, folder)
27
+ }
28
+ walk.inventory.entries.sort((a, b) => a.path.localeCompare(b.path))
29
+ return { succeeded: true, output: walk.inventory }
30
+ }
31
+
32
+ async function enumerateDirectory(walk: CatalogWalk, folder: string): Promise<void> {
33
+ const resolved = await resolveCatalogEntry({ root: walk.root, path: folder })
34
+ if (!resolved.succeeded) {
35
+ walk.inventory.failures.push({ ...resolved, scope: "directory" })
36
+ return
37
+ }
38
+ try {
39
+ const canonicalFolder = resolved.output.canonicalPath === folder
40
+ const entries = await readdir(resolved.output.absolutePath, { withFileTypes: true })
41
+ walk.inventory.completeDirectories.push(folder)
42
+ for (const entry of entries) {
43
+ const path = [folder, entry.name].filter((part) => part !== "").join("/")
44
+ if (skipEntry(walk, path, entry.isDirectory())) continue
45
+ walk.inventory.observedPaths.push(path)
46
+ visitCatalogEntry(walk, path, await resolveListing(walk, path, entry, canonicalFolder))
47
+ }
48
+ } catch (error) {
49
+ if (!(error instanceof Error)) throw error
50
+ walk.inventory.failures.push(catalogIoFailure(error, { path: folder, scope: "directory" }))
51
+ }
52
+ }
53
+
54
+ async function resolveListing(
55
+ walk: CatalogWalk,
56
+ path: string,
57
+ entry: Dirent,
58
+ canonicalFolder: boolean,
59
+ ): Promise<CatalogResolveResult> {
60
+ const location = { root: walk.root, path }
61
+ if (canonicalFolder) return resolveListedEntry(location, entry)
62
+ return resolveCatalogEntry(location)
63
+ }
64
+
65
+ function skipEntry(walk: CatalogWalk, path: string, directory: boolean): boolean {
66
+ if (walk.mode === "export") return isCatalogHidden(path) || catalogFileKind(path) === "temporary"
67
+ if (directory) return isCatalogHidden(path)
68
+ return isCatalogHidden(path) && !isCatalogNotePath(path) && catalogFileKind(path) !== "temporary"
69
+ }
@@ -0,0 +1,21 @@
1
+ import type { VaultCatalogFailure, VaultExportFile, VaultExportResult } from "#src/domain"
2
+ import type { VaultContext } from "#src/services/vault/context"
3
+ import { readCatalogBytes } from "./bytes.ts"
4
+ import { walkVault } from "./enumerate.ts"
5
+
6
+ export async function collectExportFiles(vault: VaultContext): Promise<VaultExportResult> {
7
+ const scan = await walkVault({ vault, mode: "export" })
8
+ if (!scan.succeeded) return { succeeded: false, failures: [scan], problems: scan.problems }
9
+ const failures: VaultCatalogFailure[] = [...scan.output.failures]
10
+ const files: VaultExportFile[] = []
11
+ for (const entry of scan.output.entries) {
12
+ if (entry.kind === "folder" || entry.kind === "temporary") continue
13
+ const read = await readCatalogBytes(vault, { path: entry.path, expectedStat: entry.stat })
14
+ if (read.succeeded) files.push(read.output)
15
+ else failures.push(read)
16
+ }
17
+ if (failures.length > 0) {
18
+ return { succeeded: false, failures, problems: failures.flatMap((failure) => failure.problems) }
19
+ }
20
+ return { succeeded: true, output: files }
21
+ }
@@ -0,0 +1,16 @@
1
+ import type { VaultCatalogFailure } from "#src/domain"
2
+ import type { CatalogFailureDetail, CatalogOperation } from "./types.ts"
3
+
4
+ export function catalogFailure(detail: CatalogFailureDetail): VaultCatalogFailure {
5
+ return { succeeded: false, path: detail.path, scope: detail.scope, reason: detail.reason, problems: [detail.problem] }
6
+ }
7
+
8
+ export function catalogIoFailure(error: Error, operation: CatalogOperation): VaultCatalogFailure {
9
+ let reason: VaultCatalogFailure["reason"] = "io-error"
10
+ if ("code" in error) {
11
+ if (error.code === "ENOENT") reason = "not-found"
12
+ if (error.code === "ENOTDIR") reason = "not-directory"
13
+ if (error.code === "EACCES" || error.code === "EPERM" || error.code === "EBUSY") reason = "unreadable"
14
+ }
15
+ return catalogFailure({ ...operation, reason, problem: error.message })
16
+ }
@@ -0,0 +1,10 @@
1
+ export * from "./bytes.ts"
2
+ export * from "./dont-forget.ts"
3
+ export * from "./enumerate.ts"
4
+ export * from "./export.ts"
5
+ export * from "./failures.ts"
6
+ export * from "./inspect.ts"
7
+ export * from "./observe.ts"
8
+ export * from "./resolve.ts"
9
+ export * from "./stat.ts"
10
+ export * from "./types.ts"
@@ -0,0 +1,41 @@
1
+ import {
2
+ analyzeVaultNote,
3
+ type InspectedVaultFile,
4
+ isCatalogNotePath,
5
+ isRootArchive,
6
+ type VaultExportFile,
7
+ type VaultFileRequest,
8
+ type VaultInspectionResult,
9
+ } from "#src/domain"
10
+ import type { VaultContext } from "#src/services/vault/context"
11
+ import { readCatalogBytes } from "./bytes.ts"
12
+ import { catalogFailure } from "./failures.ts"
13
+ import { resolveCatalogEntry, resolveCatalogRoot } from "./resolve.ts"
14
+
15
+ export async function inspectVaultFile(vault: VaultContext, request: VaultFileRequest): Promise<VaultInspectionResult> {
16
+ const root = await resolveCatalogRoot(vault)
17
+ if (!root.succeeded) return root
18
+ const resolved = await resolveCatalogEntry({ root: root.output, path: request.path })
19
+ if (!resolved.succeeded) return resolved
20
+ const canonicalPath = resolved.output.canonicalPath
21
+ if (resolved.output.kind !== "file" || ![request.path, canonicalPath].every(isCatalogNotePath)) {
22
+ return catalogFailure({
23
+ path: request.path,
24
+ scope: "file",
25
+ reason: "excluded",
26
+ problem: "This path is not a memory note",
27
+ })
28
+ }
29
+
30
+ const raw = await readCatalogBytes(vault, { ...request, expectedStat: resolved.output.stat })
31
+ if (!raw.succeeded) return raw
32
+ return { succeeded: true, output: inspectContent(vault, raw.output, canonicalPath) }
33
+ }
34
+
35
+ function inspectContent(vault: VaultContext, raw: VaultExportFile, canonicalPath: string): InspectedVaultFile {
36
+ const text = Buffer.from(raw.bytes).toString("utf8")
37
+ const archived = isRootArchive(raw.path) || isRootArchive(canonicalPath)
38
+ const statement = canonicalPath.slice(canonicalPath.lastIndexOf("/") + 1, -3)
39
+ const analysis = analyzeVaultNote({ statement, text, archived, limits: vault.limits })
40
+ return { path: raw.path, canonicalPath, text, rawHash: raw.rawHash, stat: raw.stat, archived, analysis }
41
+ }
@@ -0,0 +1,35 @@
1
+ import { isCatalogHidden, isRootTemplate, type VaultFileRequest } from "#src/domain"
2
+ import type { VaultContext } from "#src/services/vault/context"
3
+ import { catalogFailure } from "./failures.ts"
4
+ import { resolveCatalogEntry, resolveCatalogRoot } from "./resolve.ts"
5
+ import type { CatalogResolveResult } from "./types.ts"
6
+
7
+ export async function observeVaultPath(vault: VaultContext, request: VaultFileRequest): Promise<CatalogResolveResult> {
8
+ let path = request.path
9
+ if (path.length > 1 && path.endsWith("/")) path = path.slice(0, -1)
10
+ const root = await resolveCatalogRoot(vault)
11
+ if (!root.succeeded) return root
12
+ const entry = await resolveCatalogEntry({ root: root.output, path })
13
+ if (!entry.succeeded) return entry
14
+ if (request.path.endsWith("/") && entry.output.kind !== "directory") {
15
+ return catalogFailure({
16
+ path: request.path,
17
+ scope: "directory",
18
+ reason: "not-directory",
19
+ problem: "Expected a folder",
20
+ })
21
+ }
22
+ if (entry.output.kind === "directory" && ![path, entry.output.canonicalPath].every(isReadableFolder)) {
23
+ return catalogFailure({
24
+ path: request.path,
25
+ scope: "directory",
26
+ reason: "excluded",
27
+ problem: "This folder is not readable memory",
28
+ })
29
+ }
30
+ return entry
31
+ }
32
+
33
+ function isReadableFolder(path: string): boolean {
34
+ return !isCatalogHidden(path) && !isRootTemplate(path)
35
+ }
@@ -0,0 +1,94 @@
1
+ import type { Dirent } from "node:fs"
2
+ import { lstat, realpath, stat } from "node:fs/promises"
3
+ import { isAbsolute, join, relative, sep } from "node:path"
4
+
5
+ import { isSafeCatalogPath } from "#src/domain"
6
+ import type { VaultContext } from "#src/services/vault/context"
7
+ import { catalogFailure, catalogIoFailure } from "./failures.ts"
8
+ import { catalogEntryKind, catalogStat } from "./stat.ts"
9
+ import type { CatalogLocation, CatalogResolveResult, CatalogRootResult } from "./types.ts"
10
+
11
+ export async function resolveCatalogRoot(vault: VaultContext): Promise<CatalogRootResult> {
12
+ try {
13
+ const root = await realpath(vault.path)
14
+ if (!(await stat(root)).isDirectory()) {
15
+ return catalogFailure({
16
+ path: "",
17
+ scope: "directory",
18
+ reason: "not-directory",
19
+ problem: "The vault root is not a directory",
20
+ })
21
+ }
22
+ return { succeeded: true, output: root }
23
+ } catch (error) {
24
+ if (error instanceof Error) return catalogIoFailure(error, { path: "", scope: "directory" })
25
+ throw error
26
+ }
27
+ }
28
+
29
+ export async function resolveCatalogEntry(location: CatalogLocation): Promise<CatalogResolveResult> {
30
+ if (location.path !== "" && !isSafeCatalogPath(location.path)) {
31
+ return catalogFailure({
32
+ path: location.path,
33
+ scope: "entry",
34
+ reason: "invalid-path",
35
+ problem: "Expected a safe vault-relative path with / separators",
36
+ })
37
+ }
38
+ try {
39
+ const resolved = await resolveComponents(location)
40
+ if (!resolved.succeeded) return resolved
41
+ const stats = await stat(resolved.output)
42
+ return {
43
+ succeeded: true,
44
+ output: {
45
+ absolutePath: resolved.output,
46
+ canonicalPath: relative(location.root, resolved.output).split(sep).join("/"),
47
+ kind: catalogEntryKind(stats),
48
+ stat: catalogStat(stats),
49
+ },
50
+ }
51
+ } catch (error) {
52
+ if (error instanceof Error) return catalogIoFailure(error, { path: location.path, scope: "entry" })
53
+ throw error
54
+ }
55
+ }
56
+
57
+ export async function resolveListedEntry(location: CatalogLocation, listed: Dirent): Promise<CatalogResolveResult> {
58
+ if (!(listed.isFile() || listed.isDirectory()) || !isSafeCatalogPath(location.path)) {
59
+ return resolveCatalogEntry(location)
60
+ }
61
+ const absolutePath = join(location.root, ...location.path.split("/"))
62
+ try {
63
+ const stats = await lstat(absolutePath)
64
+ if (stats.isSymbolicLink()) return resolveCatalogEntry(location)
65
+ return {
66
+ succeeded: true,
67
+ output: { absolutePath, canonicalPath: location.path, kind: catalogEntryKind(stats), stat: catalogStat(stats) },
68
+ }
69
+ } catch (error) {
70
+ if (error instanceof Error) return catalogIoFailure(error, { path: location.path, scope: "entry" })
71
+ throw error
72
+ }
73
+ }
74
+
75
+ async function resolveComponents(location: CatalogLocation): Promise<CatalogRootResult> {
76
+ let current = location.root
77
+ for (const part of location.path.split("/").filter((part) => part !== "")) {
78
+ current = await realpath(join(current, part))
79
+ if (!isCatalogInside(location.root, current)) {
80
+ return catalogFailure({
81
+ path: location.path,
82
+ scope: "entry",
83
+ reason: "outside-vault",
84
+ problem: "The path leads outside the real vault root",
85
+ })
86
+ }
87
+ }
88
+ return { succeeded: true, output: current }
89
+ }
90
+
91
+ export function isCatalogInside(root: string, path: string): boolean {
92
+ const rel = relative(root, path)
93
+ return !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`)
94
+ }
@@ -0,0 +1,23 @@
1
+ import type { Stats } from "node:fs"
2
+
3
+ import type { VaultFileStat } from "#src/domain"
4
+ import type { ResolvedCatalogEntry } from "./types.ts"
5
+
6
+ export function catalogStat(stats: Stats): VaultFileStat {
7
+ return { size: stats.size, mtimeMs: stats.mtimeMs, ctimeMs: stats.ctimeMs, device: stats.dev, inode: stats.ino }
8
+ }
9
+
10
+ export function catalogEntryKind(stats: Stats): ResolvedCatalogEntry["kind"] {
11
+ if (stats.isFile()) return "file"
12
+ if (stats.isDirectory()) return "directory"
13
+ return "other"
14
+ }
15
+
16
+ export function sameCatalogStat(left: VaultFileStat, right: VaultFileStat): boolean {
17
+ return (
18
+ left.size === right.size &&
19
+ left.mtimeMs === right.mtimeMs &&
20
+ left.device === right.device &&
21
+ left.inode === right.inode
22
+ )
23
+ }
@@ -0,0 +1,69 @@
1
+ import type { VaultCatalogFailure, VaultEnumeration, VaultExportFile, VaultFileStat } from "#src/domain"
2
+ import type { VaultContext } from "#src/services/vault/context"
3
+ import type { Succeeded } from "#src/shared"
4
+
5
+ export type {
6
+ InspectedVaultFile,
7
+ ParsedVaultNote,
8
+ UnclosedVaultNote,
9
+ VaultAlias,
10
+ VaultCatalogEntry,
11
+ VaultCatalogFailure,
12
+ VaultEntryKind,
13
+ VaultEnumeration,
14
+ VaultEnumerationResult,
15
+ VaultExportFailure,
16
+ VaultExportFile,
17
+ VaultExportResult,
18
+ VaultFileRequest,
19
+ VaultFileStat,
20
+ VaultInspectionResult,
21
+ VaultNoteAnalysis,
22
+ VaultNoteProblems,
23
+ } from "#src/domain"
24
+
25
+ export interface CatalogLocation {
26
+ root: string
27
+ path: string
28
+ }
29
+
30
+ export interface ResolvedCatalogEntry {
31
+ absolutePath: string
32
+ canonicalPath: string
33
+ kind: "file" | "directory" | "other"
34
+ stat: VaultFileStat
35
+ }
36
+
37
+ export interface CatalogFailureDetail {
38
+ path: string
39
+ scope: VaultCatalogFailure["scope"]
40
+ reason: VaultCatalogFailure["reason"]
41
+ problem: string
42
+ }
43
+
44
+ export interface CatalogOperation {
45
+ path: string
46
+ scope: VaultCatalogFailure["scope"]
47
+ }
48
+
49
+ export type CatalogRootResult = Succeeded<string> | VaultCatalogFailure
50
+ export type CatalogResolveResult = Succeeded<ResolvedCatalogEntry> | VaultCatalogFailure
51
+ export type CatalogBytesResult = Succeeded<VaultExportFile> | VaultCatalogFailure
52
+
53
+ export interface CatalogReadRequest {
54
+ path: string
55
+ expectedStat?: VaultFileStat
56
+ }
57
+
58
+ export interface CatalogWalk {
59
+ vault: VaultContext
60
+ root: string
61
+ mode: "memory" | "export"
62
+ pending: string[]
63
+ inventory: VaultEnumeration
64
+ }
65
+
66
+ export interface CatalogWalkRequest {
67
+ vault: VaultContext
68
+ mode: CatalogWalk["mode"]
69
+ }
@@ -0,0 +1,58 @@
1
+ import { catalogFileKind, isCatalogHidden, isCatalogNotePath, isRootArchive, isRootTemplate } from "#src/domain"
2
+ import { catalogFailure } from "./failures.ts"
3
+ import type { CatalogResolveResult, CatalogWalk, ResolvedCatalogEntry } from "./types.ts"
4
+
5
+ export function visitCatalogEntry(walk: CatalogWalk, path: string, result: CatalogResolveResult): void {
6
+ if (!result.succeeded) {
7
+ walk.inventory.failures.push(result)
8
+ return
9
+ }
10
+
11
+ const entry = result.output
12
+ if (entry.kind === "directory" && isCatalogHidden(path)) return
13
+
14
+ if (entry.canonicalPath !== path) {
15
+ recordAlias(walk, path, entry)
16
+ return
17
+ }
18
+ recordPhysicalEntry(walk, entry)
19
+ }
20
+
21
+ function recordPhysicalEntry(walk: CatalogWalk, entry: ResolvedCatalogEntry): void {
22
+ const path = entry.canonicalPath
23
+ if (entry.kind === "directory") {
24
+ walk.inventory.entries.push({ path, kind: "folder", archived: isRootArchive(path), stat: entry.stat })
25
+ if (walk.mode === "export" || !isRootTemplate(path)) walk.pending.push(path)
26
+ return
27
+ }
28
+ if (entry.kind !== "file") {
29
+ walk.inventory.failures.push(
30
+ catalogFailure({ path, scope: "entry", reason: "not-file", problem: "Not a regular file or directory" }),
31
+ )
32
+ return
33
+ }
34
+ walk.inventory.entries.push({
35
+ path,
36
+ kind: catalogFileKind(path),
37
+ archived: isRootArchive(path),
38
+ stat: entry.stat,
39
+ })
40
+ }
41
+
42
+ function recordAlias(walk: CatalogWalk, path: string, entry: ResolvedCatalogEntry): void {
43
+ const target = entry.canonicalPath
44
+ if (entry.kind === "directory" && (target === "" || path.startsWith(`${target}/`))) {
45
+ walk.inventory.failures.push(
46
+ catalogFailure({ path, scope: "directory", reason: "cycle", problem: "Directory alias leads to an ancestor" }),
47
+ )
48
+ return
49
+ }
50
+ const memoryNote = walk.mode === "memory" && entry.kind === "file" && isCatalogNotePath(target)
51
+ if (isCatalogHidden(target) && !memoryNote) {
52
+ walk.inventory.failures.push(
53
+ catalogFailure({ path, scope: "entry", reason: "excluded", problem: "Alias leads to a hidden path" }),
54
+ )
55
+ return
56
+ }
57
+ walk.inventory.aliases.push({ path, target })
58
+ }
@@ -0,0 +1,66 @@
1
+ import { checkMemoryFolder, type Note, parseNote } from "#src/domain"
2
+ import { inspectVaultFile } from "#src/services/vault/catalog"
3
+ import type { VaultContext } from "#src/services/vault/context"
4
+ import type { Succeeded } from "#src/shared"
5
+ import type { BlankCompletionRefusal, CompleteBlankRequest, CompleteBlankResult } from "./types.ts"
6
+ import { updateNoteFile } from "./update-file.ts"
7
+
8
+ export async function completeBlankFile(
9
+ vault: VaultContext,
10
+ request: CompleteBlankRequest,
11
+ ): Promise<CompleteBlankResult> {
12
+ const inspected = await inspectVaultFile(vault, { path: request.path })
13
+ if (!inspected.succeeded) return inspected
14
+ const current = inspected.output
15
+ if (current.rawHash !== request.expectedHash) {
16
+ return { succeeded: false, reason: "conflict", problems: ["The blank file changed since its preview"] }
17
+ }
18
+ const note = noteToComplete(request.note, current.text)
19
+ if (!note.succeeded) return note
20
+
21
+ return completeInspectedBlank(vault, { ...request, note: note.output }, current.canonicalPath)
22
+ }
23
+
24
+ function noteToComplete(note: Note, text: string): Succeeded<Note> | BlankCompletionRefusal {
25
+ if (text.trim() === "") return { succeeded: true, output: note }
26
+ const parsed = parseNote(note.statement, text)
27
+ if (parsed.succeeded) {
28
+ return { succeeded: false, reason: "not-blank", problems: ["The file already has frontmatter"] }
29
+ }
30
+ if (parsed.problems.includes("frontmatter is not closed")) {
31
+ return { succeeded: false, reason: "not-blank", problems: parsed.problems }
32
+ }
33
+ const normalized = text.replaceAll("\r\n", "\n")
34
+ return { succeeded: true, output: { ...note, body: withoutFinalNewline(normalized) } }
35
+ }
36
+
37
+ function withoutFinalNewline(text: string): string {
38
+ if (text.endsWith("\n")) return text.slice(0, -1)
39
+ return text
40
+ }
41
+
42
+ async function completeInspectedBlank(
43
+ vault: VaultContext,
44
+ request: CompleteBlankRequest,
45
+ canonicalPath: string,
46
+ ): Promise<CompleteBlankResult> {
47
+ const folder = canonicalPath.slice(0, Math.max(0, canonicalPath.lastIndexOf("/")))
48
+ const requestedFolder = request.path.slice(0, Math.max(0, request.path.lastIndexOf("/")))
49
+ const problems = [...checkMemoryFolder(folder), ...checkMemoryFolder(requestedFolder)]
50
+ if (problems.length > 0) return { succeeded: false, reason: "invalid", problems }
51
+ const fileName = canonicalPath.slice(canonicalPath.lastIndexOf("/") + 1)
52
+ const requestedName = request.path.slice(request.path.lastIndexOf("/") + 1)
53
+ if (
54
+ fileName.slice(-3).toLowerCase() !== ".md" ||
55
+ fileName.slice(0, -3) !== request.note.statement ||
56
+ requestedName !== fileName
57
+ ) {
58
+ return {
59
+ succeeded: false,
60
+ reason: "path-mismatch",
61
+ problems: ["The candidate statement must match the blank file"],
62
+ }
63
+ }
64
+
65
+ return updateNoteFile(vault, { folder, fileName, note: request.note, expectedHash: request.expectedHash })
66
+ }
@@ -0,0 +1,3 @@
1
+ export const NOTE_EXTENSION = ".md"
2
+
3
+ export const FOLDER_INDEX_FILE_NAME = "index.md"
@@ -0,0 +1 @@
1
+ export * from "./types.ts"
@@ -0,0 +1,10 @@
1
+ import type { NoteLimits } from "#src/domain"
2
+
3
+ export interface VaultContext {
4
+ path: string
5
+ limits: NoteLimits
6
+ }
7
+
8
+ export interface NamedVaultContext extends VaultContext {
9
+ name: string
10
+ }
@@ -0,0 +1,19 @@
1
+ import { checkMemoryFolder, checkNote, type Note } from "#src/domain"
2
+ import type { VaultContext } from "#src/services/vault/context"
3
+ import { resolveMemoryFolder } from "./memory-folder.ts"
4
+ import { writeValidatedNote } from "./publish.ts"
5
+ import type { CreateResult } from "./types.ts"
6
+
7
+ export async function createMemoryNote(vault: VaultContext, folder: string, note: Note): Promise<CreateResult> {
8
+ const problems = [...checkMemoryFolder(folder), ...checkNote(note, vault.limits)]
9
+ if (problems.length > 0) {
10
+ return { succeeded: false, reason: "invalid", problems }
11
+ }
12
+
13
+ const directory = await resolveMemoryFolder(vault.path, folder)
14
+ if (!directory.succeeded) {
15
+ return directory
16
+ }
17
+
18
+ return writeValidatedNote(vault.path, folder, note)
19
+ }
@@ -0,0 +1,6 @@
1
+ import { joinVaultPath } from "#src/domain"
2
+ import { noteFileName } from "./paths.ts"
3
+
4
+ export function displayNotePath(folder: string, statement: string): string {
5
+ return joinVaultPath(folder, noteFileName(statement))
6
+ }