pi-obsidian-memory 0.0.1 → 0.1.1

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 +237 -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,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
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ diagnoseVault,
3
+ exportEntries,
4
+ type Note,
5
+ type NoteChange,
6
+ type PlacedNote,
7
+ updatedNote,
8
+ type VaultDiagnosis,
9
+ type VaultExportEntry,
10
+ } from "#src/domain"
@@ -0,0 +1,2 @@
1
+ export type { MemoryDraft } from "#src/domain"
2
+ export { MemoryDraftSchema, newNote } from "#src/domain"
@@ -0,0 +1,53 @@
1
+ import type { ReadFailure, WriteFailure } from "./types.ts"
2
+
3
+ export function readFailure(error: Error, path: string): ReadFailure {
4
+ const code = errorCode(error)
5
+ const problems = [`${path} cannot be read (${code})`]
6
+ switch (code) {
7
+ case "ENOENT":
8
+ return { succeeded: false, reason: "not-found", code, problems }
9
+ case "ENOTDIR":
10
+ case "EISDIR":
11
+ return { succeeded: false, reason: "not-directory", code, problems }
12
+ case "EACCES":
13
+ case "EPERM":
14
+ case "EBUSY":
15
+ case "ELOOP":
16
+ return { succeeded: false, reason: "not-readable", code, problems }
17
+ default:
18
+ throw error
19
+ }
20
+ }
21
+
22
+ export function writeFailure(error: Error, path: string): WriteFailure {
23
+ const code = errorCode(error)
24
+ const problems = [`${path} cannot be written (${code})`]
25
+ switch (code) {
26
+ case "ENOENT":
27
+ return { succeeded: false, reason: "not-found", code, problems }
28
+ case "ENOTDIR":
29
+ case "EISDIR":
30
+ return { succeeded: false, reason: "not-directory", code, problems }
31
+ case "EEXIST":
32
+ return { succeeded: false, reason: "exists", code, problems }
33
+ case "EACCES":
34
+ case "EPERM":
35
+ case "EBUSY":
36
+ case "ENOSPC":
37
+ case "EDQUOT":
38
+ case "EROFS":
39
+ case "ENOTSUP":
40
+ case "EXDEV":
41
+ case "EMLINK":
42
+ return { succeeded: false, reason: "not-writable", code, problems }
43
+ default:
44
+ throw error
45
+ }
46
+ }
47
+
48
+ export function errorCode(error: Error): string {
49
+ if ("code" in error && typeof error.code === "string") {
50
+ return error.code
51
+ }
52
+ return error.name
53
+ }
@@ -0,0 +1,5 @@
1
+ import { createHash } from "node:crypto"
2
+
3
+ export function hashOf(content: Buffer | string): string {
4
+ return createHash("sha256").update(content).digest("hex")
5
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./failures.ts"
2
+ export * from "./hash.ts"
3
+ export * from "./read.ts"
4
+ export * from "./types.ts"
5
+ export * from "./write.ts"
@@ -0,0 +1,61 @@
1
+ import { lstat, readdir, readFile, realpath } from "node:fs/promises"
2
+
3
+ import { readFailure } from "./failures.ts"
4
+ import type { EntriesResult, ExistingFileResult, RawFileResult, RealPathResult, StatResult } from "./types.ts"
5
+
6
+ export async function readRawFile(path: string): Promise<RawFileResult> {
7
+ try {
8
+ return { succeeded: true, output: await readFile(path) }
9
+ } catch (error) {
10
+ if (error instanceof Error) {
11
+ return readFailure(error, path)
12
+ }
13
+ throw error
14
+ }
15
+ }
16
+
17
+ export async function linkStatOf(path: string): Promise<StatResult> {
18
+ try {
19
+ return { succeeded: true, output: await lstat(path) }
20
+ } catch (error) {
21
+ if (error instanceof Error) {
22
+ return readFailure(error, path)
23
+ }
24
+ throw error
25
+ }
26
+ }
27
+
28
+ export async function realPathOf(path: string): Promise<RealPathResult> {
29
+ try {
30
+ return { succeeded: true, output: await realpath(path) }
31
+ } catch (error) {
32
+ if (error instanceof Error) {
33
+ return readFailure(error, path)
34
+ }
35
+ throw error
36
+ }
37
+ }
38
+
39
+ export async function directoryEntriesOf(path: string): Promise<EntriesResult> {
40
+ try {
41
+ return { succeeded: true, output: await readdir(path, { withFileTypes: true }) }
42
+ } catch (error) {
43
+ if (error instanceof Error) {
44
+ return readFailure(error, path)
45
+ }
46
+ throw error
47
+ }
48
+ }
49
+
50
+ export async function findFileIgnoringCase(directory: string, fileName: string): Promise<ExistingFileResult> {
51
+ const entries = await directoryEntriesOf(directory)
52
+ if (!entries.succeeded) {
53
+ return entries
54
+ }
55
+
56
+ const found = entries.output.find((entry) => entry.name.toLowerCase() === fileName.toLowerCase())
57
+ if (found) {
58
+ return { succeeded: true, output: found.name }
59
+ }
60
+ return { succeeded: false, reason: "not-found", code: "ENOENT", problems: [`${fileName} does not exist`] }
61
+ }
@@ -0,0 +1,36 @@
1
+ import type { Dirent, Stats } from "node:fs"
2
+
3
+ import type { Done, Failed, Succeeded } from "#src/shared"
4
+
5
+ interface MissingFile extends Failed {
6
+ reason: "not-found"
7
+ code: string
8
+ }
9
+
10
+ interface NotDirectory extends Failed {
11
+ reason: "not-directory"
12
+ code: string
13
+ }
14
+
15
+ interface NotReadable extends Failed {
16
+ reason: "not-readable"
17
+ code: string
18
+ }
19
+
20
+ export type ReadFailure = MissingFile | NotDirectory | NotReadable
21
+
22
+ export interface WriteFailure extends Failed {
23
+ reason: "not-found" | "not-directory" | "not-writable" | "exists"
24
+ code: string
25
+ }
26
+
27
+ export interface FileWarnings {
28
+ maintenanceProblems?: string[]
29
+ }
30
+
31
+ export type RawFileResult = Succeeded<Buffer> | ReadFailure
32
+ export type StatResult = Succeeded<Stats> | ReadFailure
33
+ export type RealPathResult = Succeeded<string> | ReadFailure
34
+ export type EntriesResult = Succeeded<Dirent[]> | ReadFailure
35
+ export type ExistingFileResult = Succeeded<string> | ReadFailure
36
+ export type WriteResult = (Done & FileWarnings) | WriteFailure
@@ -0,0 +1,80 @@
1
+ import { randomUUID } from "node:crypto"
2
+ import { link, mkdir, rename, rm, writeFile } from "node:fs/promises"
3
+ import { basename, dirname, join } from "node:path"
4
+
5
+ import { writeFailure } from "./failures.ts"
6
+ import type { WriteResult } from "./types.ts"
7
+
8
+ export async function publishExclusively(path: string, text: string): Promise<WriteResult> {
9
+ return publish(path, text, "create")
10
+ }
11
+
12
+ export async function writeAtomically(path: string, text: string): Promise<WriteResult> {
13
+ return publish(path, text, "replace")
14
+ }
15
+
16
+ async function publish(path: string, text: string, mode: "create" | "replace"): Promise<WriteResult> {
17
+ const temporary = join(dirname(path), `.${basename(path)}.tmp-${randomUUID()}`)
18
+ let result: WriteResult
19
+ let cleanupProblems: string[] = []
20
+ try {
21
+ await writeFile(temporary, text, { flag: "wx" })
22
+ if (mode === "create") {
23
+ await link(temporary, path)
24
+ } else {
25
+ await rename(temporary, path)
26
+ }
27
+ result = { succeeded: true }
28
+ } catch (error) {
29
+ if (!(error instanceof Error)) {
30
+ throw error
31
+ }
32
+ result = writeFailure(error, path)
33
+ } finally {
34
+ cleanupProblems = await cleanupTemporary(temporary)
35
+ }
36
+
37
+ if (cleanupProblems.length === 0) {
38
+ return result
39
+ }
40
+ if (result.succeeded) {
41
+ return { ...result, maintenanceProblems: cleanupProblems }
42
+ }
43
+ return { ...result, problems: [...result.problems, ...cleanupProblems] }
44
+ }
45
+
46
+ async function cleanupTemporary(path: string): Promise<string[]> {
47
+ try {
48
+ await rm(path, { force: true })
49
+ return []
50
+ } catch (error) {
51
+ if (error instanceof Error) {
52
+ return [`Temporary file ${path} could not be removed: ${error.message}`]
53
+ }
54
+ return [`Temporary file ${path} could not be removed`]
55
+ }
56
+ }
57
+
58
+ export async function createDirectory(path: string): Promise<WriteResult> {
59
+ try {
60
+ await mkdir(path, { recursive: true })
61
+ return { succeeded: true }
62
+ } catch (error) {
63
+ if (error instanceof Error) {
64
+ return writeFailure(error, path)
65
+ }
66
+ throw error
67
+ }
68
+ }
69
+
70
+ export async function removeFile(path: string): Promise<WriteResult> {
71
+ try {
72
+ await rm(path)
73
+ return { succeeded: true }
74
+ } catch (error) {
75
+ if (error instanceof Error) {
76
+ return writeFailure(error, path)
77
+ }
78
+ throw error
79
+ }
80
+ }
@@ -0,0 +1,27 @@
1
+ import type { VaultContext } from "#src/services/vault/context"
2
+ import { findFileIgnoringCase } from "#src/services/vault/filesystem"
3
+ import { NOTE_EXTENSION } from "./constants.ts"
4
+ import { displayNotePath } from "./display.ts"
5
+ import { noteFileName } from "./paths.ts"
6
+ import { readNote } from "./read.ts"
7
+ import { resolveFolder } from "./resolve.ts"
8
+ import type { ReadNoteResult } from "./types.ts"
9
+
10
+ export async function findNote(vault: VaultContext, folder: string, statement: string): Promise<ReadNoteResult> {
11
+ const directory = await resolveFolder(vault.path, folder)
12
+ if (!directory.succeeded) {
13
+ return directory
14
+ }
15
+
16
+ const existing = await findFileIgnoringCase(directory.output, noteFileName(statement))
17
+ if (!existing.succeeded) {
18
+ if (existing.reason !== "not-found") {
19
+ return existing
20
+ }
21
+
22
+ return { succeeded: false, reason: "not-found", problems: [`${displayNotePath(folder, statement)} does not exist`] }
23
+ }
24
+
25
+ const realStatement = existing.output.slice(0, -NOTE_EXTENSION.length)
26
+ return readNote(vault, folder, realStatement)
27
+ }