memkin 0.4.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 (914) hide show
  1. package/LICENSE +191 -0
  2. package/README.en.md +934 -0
  3. package/README.md +934 -0
  4. package/README.zh-CN.md +825 -0
  5. package/bin/memkin.mjs +41 -0
  6. package/dist/adapters/file.d.ts +19 -0
  7. package/dist/adapters/file.d.ts.map +1 -0
  8. package/dist/adapters/file.js +61 -0
  9. package/dist/adapters/file.js.map +1 -0
  10. package/dist/adapters/gbrain.d.ts +29 -0
  11. package/dist/adapters/gbrain.d.ts.map +1 -0
  12. package/dist/adapters/gbrain.js +622 -0
  13. package/dist/adapters/gbrain.js.map +1 -0
  14. package/dist/adapters/index.d.ts +6 -0
  15. package/dist/adapters/index.d.ts.map +1 -0
  16. package/dist/adapters/index.js +5 -0
  17. package/dist/adapters/index.js.map +1 -0
  18. package/dist/adapters/registry.d.ts +18 -0
  19. package/dist/adapters/registry.d.ts.map +1 -0
  20. package/dist/adapters/registry.js +18 -0
  21. package/dist/adapters/registry.js.map +1 -0
  22. package/dist/adapters/stdout.d.ts +12 -0
  23. package/dist/adapters/stdout.d.ts.map +1 -0
  24. package/dist/adapters/stdout.js +29 -0
  25. package/dist/adapters/stdout.js.map +1 -0
  26. package/dist/adapters/store.d.ts +47 -0
  27. package/dist/adapters/store.d.ts.map +1 -0
  28. package/dist/adapters/store.js +642 -0
  29. package/dist/adapters/store.js.map +1 -0
  30. package/dist/cli-helpers.d.ts +12 -0
  31. package/dist/cli-helpers.d.ts.map +1 -0
  32. package/dist/cli-helpers.js +11 -0
  33. package/dist/cli-helpers.js.map +1 -0
  34. package/dist/cli-stores.d.ts +61 -0
  35. package/dist/cli-stores.d.ts.map +1 -0
  36. package/dist/cli-stores.js +130 -0
  37. package/dist/cli-stores.js.map +1 -0
  38. package/dist/cli.d.ts +2 -0
  39. package/dist/cli.d.ts.map +1 -0
  40. package/dist/cli.js +1579 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/collectors/agent/claude-code.d.ts +12 -0
  43. package/dist/collectors/agent/claude-code.d.ts.map +1 -0
  44. package/dist/collectors/agent/claude-code.js +94 -0
  45. package/dist/collectors/agent/claude-code.js.map +1 -0
  46. package/dist/collectors/agent/codex.d.ts +16 -0
  47. package/dist/collectors/agent/codex.d.ts.map +1 -0
  48. package/dist/collectors/agent/codex.js +149 -0
  49. package/dist/collectors/agent/codex.js.map +1 -0
  50. package/dist/collectors/agent/collector.d.ts +20 -0
  51. package/dist/collectors/agent/collector.d.ts.map +1 -0
  52. package/dist/collectors/agent/collector.js +108 -0
  53. package/dist/collectors/agent/collector.js.map +1 -0
  54. package/dist/collectors/agent/hermes.d.ts +13 -0
  55. package/dist/collectors/agent/hermes.d.ts.map +1 -0
  56. package/dist/collectors/agent/hermes.js +90 -0
  57. package/dist/collectors/agent/hermes.js.map +1 -0
  58. package/dist/collectors/agent/index.d.ts +6 -0
  59. package/dist/collectors/agent/index.d.ts.map +1 -0
  60. package/dist/collectors/agent/index.js +5 -0
  61. package/dist/collectors/agent/index.js.map +1 -0
  62. package/dist/collectors/agent/types.d.ts +61 -0
  63. package/dist/collectors/agent/types.d.ts.map +1 -0
  64. package/dist/collectors/agent/types.js +6 -0
  65. package/dist/collectors/agent/types.js.map +1 -0
  66. package/dist/collectors/feishu/auth.d.ts +13 -0
  67. package/dist/collectors/feishu/auth.d.ts.map +1 -0
  68. package/dist/collectors/feishu/auth.js +72 -0
  69. package/dist/collectors/feishu/auth.js.map +1 -0
  70. package/dist/collectors/feishu/chat-name-resolver.d.ts +33 -0
  71. package/dist/collectors/feishu/chat-name-resolver.d.ts.map +1 -0
  72. package/dist/collectors/feishu/chat-name-resolver.js +63 -0
  73. package/dist/collectors/feishu/chat-name-resolver.js.map +1 -0
  74. package/dist/collectors/feishu/collector.d.ts +27 -0
  75. package/dist/collectors/feishu/collector.d.ts.map +1 -0
  76. package/dist/collectors/feishu/collector.js +136 -0
  77. package/dist/collectors/feishu/collector.js.map +1 -0
  78. package/dist/collectors/feishu/cursor-staging.d.ts +11 -0
  79. package/dist/collectors/feishu/cursor-staging.d.ts.map +1 -0
  80. package/dist/collectors/feishu/cursor-staging.js +37 -0
  81. package/dist/collectors/feishu/cursor-staging.js.map +1 -0
  82. package/dist/collectors/feishu/docs/blocks.d.ts +25 -0
  83. package/dist/collectors/feishu/docs/blocks.d.ts.map +1 -0
  84. package/dist/collectors/feishu/docs/blocks.js +34 -0
  85. package/dist/collectors/feishu/docs/blocks.js.map +1 -0
  86. package/dist/collectors/feishu/docs/candidate.d.ts +17 -0
  87. package/dist/collectors/feishu/docs/candidate.d.ts.map +1 -0
  88. package/dist/collectors/feishu/docs/candidate.js +36 -0
  89. package/dist/collectors/feishu/docs/candidate.js.map +1 -0
  90. package/dist/collectors/feishu/docs/config.d.ts +41 -0
  91. package/dist/collectors/feishu/docs/config.d.ts.map +1 -0
  92. package/dist/collectors/feishu/docs/config.js +30 -0
  93. package/dist/collectors/feishu/docs/config.js.map +1 -0
  94. package/dist/collectors/feishu/docs/decision.d.ts +14 -0
  95. package/dist/collectors/feishu/docs/decision.d.ts.map +1 -0
  96. package/dist/collectors/feishu/docs/decision.js +43 -0
  97. package/dist/collectors/feishu/docs/decision.js.map +1 -0
  98. package/dist/collectors/feishu/docs/full-builder.d.ts +17 -0
  99. package/dist/collectors/feishu/docs/full-builder.d.ts.map +1 -0
  100. package/dist/collectors/feishu/docs/full-builder.js +136 -0
  101. package/dist/collectors/feishu/docs/full-builder.js.map +1 -0
  102. package/dist/collectors/feishu/docs/hash.d.ts +8 -0
  103. package/dist/collectors/feishu/docs/hash.d.ts.map +1 -0
  104. package/dist/collectors/feishu/docs/hash.js +15 -0
  105. package/dist/collectors/feishu/docs/hash.js.map +1 -0
  106. package/dist/collectors/feishu/docs/ingest.d.ts +54 -0
  107. package/dist/collectors/feishu/docs/ingest.d.ts.map +1 -0
  108. package/dist/collectors/feishu/docs/ingest.js +120 -0
  109. package/dist/collectors/feishu/docs/ingest.js.map +1 -0
  110. package/dist/collectors/feishu/docs/llm-json.d.ts +13 -0
  111. package/dist/collectors/feishu/docs/llm-json.d.ts.map +1 -0
  112. package/dist/collectors/feishu/docs/llm-json.js +40 -0
  113. package/dist/collectors/feishu/docs/llm-json.js.map +1 -0
  114. package/dist/collectors/feishu/docs/pointer-builder.d.ts +7 -0
  115. package/dist/collectors/feishu/docs/pointer-builder.d.ts.map +1 -0
  116. package/dist/collectors/feishu/docs/pointer-builder.js +11 -0
  117. package/dist/collectors/feishu/docs/pointer-builder.js.map +1 -0
  118. package/dist/collectors/feishu/docs/render.d.ts +8 -0
  119. package/dist/collectors/feishu/docs/render.d.ts.map +1 -0
  120. package/dist/collectors/feishu/docs/render.js +105 -0
  121. package/dist/collectors/feishu/docs/render.js.map +1 -0
  122. package/dist/collectors/feishu/docs/run.d.ts +37 -0
  123. package/dist/collectors/feishu/docs/run.d.ts.map +1 -0
  124. package/dist/collectors/feishu/docs/run.js +143 -0
  125. package/dist/collectors/feishu/docs/run.js.map +1 -0
  126. package/dist/collectors/feishu/docs/status.d.ts +16 -0
  127. package/dist/collectors/feishu/docs/status.d.ts.map +1 -0
  128. package/dist/collectors/feishu/docs/status.js +24 -0
  129. package/dist/collectors/feishu/docs/status.js.map +1 -0
  130. package/dist/collectors/feishu/docs/store-writer.d.ts +32 -0
  131. package/dist/collectors/feishu/docs/store-writer.d.ts.map +1 -0
  132. package/dist/collectors/feishu/docs/store-writer.js +71 -0
  133. package/dist/collectors/feishu/docs/store-writer.js.map +1 -0
  134. package/dist/collectors/feishu/docs/toc.d.ts +3 -0
  135. package/dist/collectors/feishu/docs/toc.d.ts.map +1 -0
  136. package/dist/collectors/feishu/docs/toc.js +19 -0
  137. package/dist/collectors/feishu/docs/toc.js.map +1 -0
  138. package/dist/collectors/feishu/docs/triggers.d.ts +7 -0
  139. package/dist/collectors/feishu/docs/triggers.d.ts.map +1 -0
  140. package/dist/collectors/feishu/docs/triggers.js +31 -0
  141. package/dist/collectors/feishu/docs/triggers.js.map +1 -0
  142. package/dist/collectors/feishu/docs/types.d.ts +109 -0
  143. package/dist/collectors/feishu/docs/types.d.ts.map +1 -0
  144. package/dist/collectors/feishu/docs/types.js +2 -0
  145. package/dist/collectors/feishu/docs/types.js.map +1 -0
  146. package/dist/collectors/feishu/docs/upgrade-queue.d.ts +19 -0
  147. package/dist/collectors/feishu/docs/upgrade-queue.d.ts.map +1 -0
  148. package/dist/collectors/feishu/docs/upgrade-queue.js +36 -0
  149. package/dist/collectors/feishu/docs/upgrade-queue.js.map +1 -0
  150. package/dist/collectors/feishu/docs/url-parser.d.ts +3 -0
  151. package/dist/collectors/feishu/docs/url-parser.d.ts.map +1 -0
  152. package/dist/collectors/feishu/docs/url-parser.js +39 -0
  153. package/dist/collectors/feishu/docs/url-parser.js.map +1 -0
  154. package/dist/collectors/feishu/docs/walkers.d.ts +24 -0
  155. package/dist/collectors/feishu/docs/walkers.d.ts.map +1 -0
  156. package/dist/collectors/feishu/docs/walkers.js +90 -0
  157. package/dist/collectors/feishu/docs/walkers.js.map +1 -0
  158. package/dist/collectors/feishu/docs/wiki-resolver.d.ts +15 -0
  159. package/dist/collectors/feishu/docs/wiki-resolver.d.ts.map +1 -0
  160. package/dist/collectors/feishu/docs/wiki-resolver.js +24 -0
  161. package/dist/collectors/feishu/docs/wiki-resolver.js.map +1 -0
  162. package/dist/collectors/feishu/http-client.d.ts +26 -0
  163. package/dist/collectors/feishu/http-client.d.ts.map +1 -0
  164. package/dist/collectors/feishu/http-client.js +94 -0
  165. package/dist/collectors/feishu/http-client.js.map +1 -0
  166. package/dist/collectors/feishu/index.d.ts +3 -0
  167. package/dist/collectors/feishu/index.d.ts.map +1 -0
  168. package/dist/collectors/feishu/index.js +2 -0
  169. package/dist/collectors/feishu/index.js.map +1 -0
  170. package/dist/collectors/feishu/lark-cli-client.d.ts +28 -0
  171. package/dist/collectors/feishu/lark-cli-client.d.ts.map +1 -0
  172. package/dist/collectors/feishu/lark-cli-client.js +104 -0
  173. package/dist/collectors/feishu/lark-cli-client.js.map +1 -0
  174. package/dist/collectors/feishu/lark-cli-identity-backend.d.ts +28 -0
  175. package/dist/collectors/feishu/lark-cli-identity-backend.d.ts.map +1 -0
  176. package/dist/collectors/feishu/lark-cli-identity-backend.js +110 -0
  177. package/dist/collectors/feishu/lark-cli-identity-backend.js.map +1 -0
  178. package/dist/collectors/feishu/rate-limiter.d.ts +10 -0
  179. package/dist/collectors/feishu/rate-limiter.d.ts.map +1 -0
  180. package/dist/collectors/feishu/rate-limiter.js +33 -0
  181. package/dist/collectors/feishu/rate-limiter.js.map +1 -0
  182. package/dist/collectors/feishu/self-open-id.d.ts +20 -0
  183. package/dist/collectors/feishu/self-open-id.d.ts.map +1 -0
  184. package/dist/collectors/feishu/self-open-id.js +31 -0
  185. package/dist/collectors/feishu/self-open-id.js.map +1 -0
  186. package/dist/collectors/feishu/sources/base.d.ts +9 -0
  187. package/dist/collectors/feishu/sources/base.d.ts.map +1 -0
  188. package/dist/collectors/feishu/sources/base.js +2 -0
  189. package/dist/collectors/feishu/sources/base.js.map +1 -0
  190. package/dist/collectors/feishu/sources/calendar.d.ts +16 -0
  191. package/dist/collectors/feishu/sources/calendar.d.ts.map +1 -0
  192. package/dist/collectors/feishu/sources/calendar.js +98 -0
  193. package/dist/collectors/feishu/sources/calendar.js.map +1 -0
  194. package/dist/collectors/feishu/sources/dm.d.ts +28 -0
  195. package/dist/collectors/feishu/sources/dm.d.ts.map +1 -0
  196. package/dist/collectors/feishu/sources/dm.js +156 -0
  197. package/dist/collectors/feishu/sources/dm.js.map +1 -0
  198. package/dist/collectors/feishu/sources/mail.d.ts +27 -0
  199. package/dist/collectors/feishu/sources/mail.d.ts.map +1 -0
  200. package/dist/collectors/feishu/sources/mail.js +149 -0
  201. package/dist/collectors/feishu/sources/mail.js.map +1 -0
  202. package/dist/collectors/feishu/sources/message-search.d.ts +37 -0
  203. package/dist/collectors/feishu/sources/message-search.d.ts.map +1 -0
  204. package/dist/collectors/feishu/sources/message-search.js +140 -0
  205. package/dist/collectors/feishu/sources/message-search.js.map +1 -0
  206. package/dist/collectors/feishu/sources/messages.d.ts +28 -0
  207. package/dist/collectors/feishu/sources/messages.d.ts.map +1 -0
  208. package/dist/collectors/feishu/sources/messages.js +175 -0
  209. package/dist/collectors/feishu/sources/messages.js.map +1 -0
  210. package/dist/collectors/feishu/sources/tasks.d.ts +15 -0
  211. package/dist/collectors/feishu/sources/tasks.d.ts.map +1 -0
  212. package/dist/collectors/feishu/sources/tasks.js +74 -0
  213. package/dist/collectors/feishu/sources/tasks.js.map +1 -0
  214. package/dist/collectors/feishu/types.d.ts +258 -0
  215. package/dist/collectors/feishu/types.d.ts.map +1 -0
  216. package/dist/collectors/feishu/types.js +17 -0
  217. package/dist/collectors/feishu/types.js.map +1 -0
  218. package/dist/collectors/index.d.ts +10 -0
  219. package/dist/collectors/index.d.ts.map +1 -0
  220. package/dist/collectors/index.js +18 -0
  221. package/dist/collectors/index.js.map +1 -0
  222. package/dist/config-center/connection-checks.d.ts +28 -0
  223. package/dist/config-center/connection-checks.d.ts.map +1 -0
  224. package/dist/config-center/connection-checks.js +114 -0
  225. package/dist/config-center/connection-checks.js.map +1 -0
  226. package/dist/config-center/document.d.ts +21 -0
  227. package/dist/config-center/document.d.ts.map +1 -0
  228. package/dist/config-center/document.js +93 -0
  229. package/dist/config-center/document.js.map +1 -0
  230. package/dist/config-center/index.d.ts +9 -0
  231. package/dist/config-center/index.d.ts.map +1 -0
  232. package/dist/config-center/index.js +29 -0
  233. package/dist/config-center/index.js.map +1 -0
  234. package/dist/config-center/recommendations.d.ts +16 -0
  235. package/dist/config-center/recommendations.d.ts.map +1 -0
  236. package/dist/config-center/recommendations.js +50 -0
  237. package/dist/config-center/recommendations.js.map +1 -0
  238. package/dist/config-center/reducer.d.ts +57 -0
  239. package/dist/config-center/reducer.d.ts.map +1 -0
  240. package/dist/config-center/reducer.js +192 -0
  241. package/dist/config-center/reducer.js.map +1 -0
  242. package/dist/config-center/schema.d.ts +31 -0
  243. package/dist/config-center/schema.d.ts.map +1 -0
  244. package/dist/config-center/schema.js +442 -0
  245. package/dist/config-center/schema.js.map +1 -0
  246. package/dist/config-center/secrets.d.ts +9 -0
  247. package/dist/config-center/secrets.d.ts.map +1 -0
  248. package/dist/config-center/secrets.js +51 -0
  249. package/dist/config-center/secrets.js.map +1 -0
  250. package/dist/config-center/source-dirs.d.ts +16 -0
  251. package/dist/config-center/source-dirs.d.ts.map +1 -0
  252. package/dist/config-center/source-dirs.js +81 -0
  253. package/dist/config-center/source-dirs.js.map +1 -0
  254. package/dist/config-center/tui/app.d.ts +22 -0
  255. package/dist/config-center/tui/app.d.ts.map +1 -0
  256. package/dist/config-center/tui/app.js +142 -0
  257. package/dist/config-center/tui/app.js.map +1 -0
  258. package/dist/config-center/tui/render.d.ts +20 -0
  259. package/dist/config-center/tui/render.d.ts.map +1 -0
  260. package/dist/config-center/tui/render.js +166 -0
  261. package/dist/config-center/tui/render.js.map +1 -0
  262. package/dist/config-center/validation.d.ts +9 -0
  263. package/dist/config-center/validation.d.ts.map +1 -0
  264. package/dist/config-center/validation.js +59 -0
  265. package/dist/config-center/validation.js.map +1 -0
  266. package/dist/consolidator/consolidator.d.ts +43 -0
  267. package/dist/consolidator/consolidator.d.ts.map +1 -0
  268. package/dist/consolidator/consolidator.js +67 -0
  269. package/dist/consolidator/consolidator.js.map +1 -0
  270. package/dist/consolidator/dead-link.d.ts +7 -0
  271. package/dist/consolidator/dead-link.d.ts.map +1 -0
  272. package/dist/consolidator/dead-link.js +57 -0
  273. package/dist/consolidator/dead-link.js.map +1 -0
  274. package/dist/consolidator/hot-warm.d.ts +9 -0
  275. package/dist/consolidator/hot-warm.d.ts.map +1 -0
  276. package/dist/consolidator/hot-warm.js +88 -0
  277. package/dist/consolidator/hot-warm.js.map +1 -0
  278. package/dist/consolidator/infer-preferences.d.ts +14 -0
  279. package/dist/consolidator/infer-preferences.d.ts.map +1 -0
  280. package/dist/consolidator/infer-preferences.js +73 -0
  281. package/dist/consolidator/infer-preferences.js.map +1 -0
  282. package/dist/consolidator/rules.d.ts +5 -0
  283. package/dist/consolidator/rules.d.ts.map +1 -0
  284. package/dist/consolidator/rules.js +53 -0
  285. package/dist/consolidator/rules.js.map +1 -0
  286. package/dist/consolidator/warm-cold.d.ts +13 -0
  287. package/dist/consolidator/warm-cold.d.ts.map +1 -0
  288. package/dist/consolidator/warm-cold.js +91 -0
  289. package/dist/consolidator/warm-cold.js.map +1 -0
  290. package/dist/core/block-builder.d.ts +15 -0
  291. package/dist/core/block-builder.d.ts.map +1 -0
  292. package/dist/core/block-builder.js +185 -0
  293. package/dist/core/block-builder.js.map +1 -0
  294. package/dist/core/canonicalize.d.ts +3 -0
  295. package/dist/core/canonicalize.d.ts.map +1 -0
  296. package/dist/core/canonicalize.js +141 -0
  297. package/dist/core/canonicalize.js.map +1 -0
  298. package/dist/core/concurrency.d.ts +2 -0
  299. package/dist/core/concurrency.d.ts.map +1 -0
  300. package/dist/core/concurrency.js +14 -0
  301. package/dist/core/concurrency.js.map +1 -0
  302. package/dist/core/config.d.ts +257 -0
  303. package/dist/core/config.d.ts.map +1 -0
  304. package/dist/core/config.js +247 -0
  305. package/dist/core/config.js.map +1 -0
  306. package/dist/core/cursors.d.ts +36 -0
  307. package/dist/core/cursors.d.ts.map +1 -0
  308. package/dist/core/cursors.js +90 -0
  309. package/dist/core/cursors.js.map +1 -0
  310. package/dist/core/dedup.d.ts +45 -0
  311. package/dist/core/dedup.d.ts.map +1 -0
  312. package/dist/core/dedup.js +111 -0
  313. package/dist/core/dedup.js.map +1 -0
  314. package/dist/core/entity-extract.d.ts +3 -0
  315. package/dist/core/entity-extract.d.ts.map +1 -0
  316. package/dist/core/entity-extract.js +54 -0
  317. package/dist/core/entity-extract.js.map +1 -0
  318. package/dist/core/env-validation.d.ts +9 -0
  319. package/dist/core/env-validation.d.ts.map +1 -0
  320. package/dist/core/env-validation.js +94 -0
  321. package/dist/core/env-validation.js.map +1 -0
  322. package/dist/core/helpers.d.ts +3 -0
  323. package/dist/core/helpers.d.ts.map +1 -0
  324. package/dist/core/helpers.js +10 -0
  325. package/dist/core/helpers.js.map +1 -0
  326. package/dist/core/identity-resolver.d.ts +42 -0
  327. package/dist/core/identity-resolver.d.ts.map +1 -0
  328. package/dist/core/identity-resolver.js +207 -0
  329. package/dist/core/identity-resolver.js.map +1 -0
  330. package/dist/core/person-identity.d.ts +140 -0
  331. package/dist/core/person-identity.d.ts.map +1 -0
  332. package/dist/core/person-identity.js +428 -0
  333. package/dist/core/person-identity.js.map +1 -0
  334. package/dist/core/person-slug.d.ts +21 -0
  335. package/dist/core/person-slug.d.ts.map +1 -0
  336. package/dist/core/person-slug.js +93 -0
  337. package/dist/core/person-slug.js.map +1 -0
  338. package/dist/core/pipeline-factory.d.ts +13 -0
  339. package/dist/core/pipeline-factory.d.ts.map +1 -0
  340. package/dist/core/pipeline-factory.js +37 -0
  341. package/dist/core/pipeline-factory.js.map +1 -0
  342. package/dist/core/pipeline.d.ts +77 -0
  343. package/dist/core/pipeline.d.ts.map +1 -0
  344. package/dist/core/pipeline.js +332 -0
  345. package/dist/core/pipeline.js.map +1 -0
  346. package/dist/core/resource-loader.d.ts +2 -0
  347. package/dist/core/resource-loader.d.ts.map +1 -0
  348. package/dist/core/resource-loader.js +12 -0
  349. package/dist/core/resource-loader.js.map +1 -0
  350. package/dist/core/schemas.d.ts +5142 -0
  351. package/dist/core/schemas.d.ts.map +1 -0
  352. package/dist/core/schemas.js +256 -0
  353. package/dist/core/schemas.js.map +1 -0
  354. package/dist/core/signal-scoring.d.ts +3 -0
  355. package/dist/core/signal-scoring.d.ts.map +1 -0
  356. package/dist/core/signal-scoring.js +128 -0
  357. package/dist/core/signal-scoring.js.map +1 -0
  358. package/dist/core/source-ref.d.ts +4 -0
  359. package/dist/core/source-ref.d.ts.map +1 -0
  360. package/dist/core/source-ref.js +24 -0
  361. package/dist/core/source-ref.js.map +1 -0
  362. package/dist/core/state.d.ts +22 -0
  363. package/dist/core/state.d.ts.map +1 -0
  364. package/dist/core/state.js +33 -0
  365. package/dist/core/state.js.map +1 -0
  366. package/dist/core/types.d.ts +266 -0
  367. package/dist/core/types.d.ts.map +1 -0
  368. package/dist/core/types.js +6 -0
  369. package/dist/core/types.js.map +1 -0
  370. package/dist/daemon/alerts.d.ts +12 -0
  371. package/dist/daemon/alerts.d.ts.map +1 -0
  372. package/dist/daemon/alerts.js +34 -0
  373. package/dist/daemon/alerts.js.map +1 -0
  374. package/dist/daemon/autostart/argv.d.ts +21 -0
  375. package/dist/daemon/autostart/argv.d.ts.map +1 -0
  376. package/dist/daemon/autostart/argv.js +37 -0
  377. package/dist/daemon/autostart/argv.js.map +1 -0
  378. package/dist/daemon/autostart/daemon-state.d.ts +19 -0
  379. package/dist/daemon/autostart/daemon-state.d.ts.map +1 -0
  380. package/dist/daemon/autostart/daemon-state.js +34 -0
  381. package/dist/daemon/autostart/daemon-state.js.map +1 -0
  382. package/dist/daemon/autostart/index.d.ts +40 -0
  383. package/dist/daemon/autostart/index.d.ts.map +1 -0
  384. package/dist/daemon/autostart/index.js +146 -0
  385. package/dist/daemon/autostart/index.js.map +1 -0
  386. package/dist/daemon/autostart/launchd.d.ts +13 -0
  387. package/dist/daemon/autostart/launchd.d.ts.map +1 -0
  388. package/dist/daemon/autostart/launchd.js +51 -0
  389. package/dist/daemon/autostart/launchd.js.map +1 -0
  390. package/dist/daemon/autostart/runner.d.ts +14 -0
  391. package/dist/daemon/autostart/runner.d.ts.map +1 -0
  392. package/dist/daemon/autostart/runner.js +30 -0
  393. package/dist/daemon/autostart/runner.js.map +1 -0
  394. package/dist/daemon/autostart/systemd.d.ts +11 -0
  395. package/dist/daemon/autostart/systemd.d.ts.map +1 -0
  396. package/dist/daemon/autostart/systemd.js +40 -0
  397. package/dist/daemon/autostart/systemd.js.map +1 -0
  398. package/dist/daemon/index.d.ts +6 -0
  399. package/dist/daemon/index.d.ts.map +1 -0
  400. package/dist/daemon/index.js +6 -0
  401. package/dist/daemon/index.js.map +1 -0
  402. package/dist/daemon/logger.d.ts +8 -0
  403. package/dist/daemon/logger.d.ts.map +1 -0
  404. package/dist/daemon/logger.js +35 -0
  405. package/dist/daemon/logger.js.map +1 -0
  406. package/dist/daemon/reload-manager.d.ts +41 -0
  407. package/dist/daemon/reload-manager.d.ts.map +1 -0
  408. package/dist/daemon/reload-manager.js +89 -0
  409. package/dist/daemon/reload-manager.js.map +1 -0
  410. package/dist/daemon/run-history.d.ts +29 -0
  411. package/dist/daemon/run-history.d.ts.map +1 -0
  412. package/dist/daemon/run-history.js +54 -0
  413. package/dist/daemon/run-history.js.map +1 -0
  414. package/dist/daemon/scheduler.d.ts +45 -0
  415. package/dist/daemon/scheduler.d.ts.map +1 -0
  416. package/dist/daemon/scheduler.js +217 -0
  417. package/dist/daemon/scheduler.js.map +1 -0
  418. package/dist/daemon/serve-runtime.d.ts +31 -0
  419. package/dist/daemon/serve-runtime.d.ts.map +1 -0
  420. package/dist/daemon/serve-runtime.js +230 -0
  421. package/dist/daemon/serve-runtime.js.map +1 -0
  422. package/dist/daemon/source-schedule.d.ts +25 -0
  423. package/dist/daemon/source-schedule.d.ts.map +1 -0
  424. package/dist/daemon/source-schedule.js +87 -0
  425. package/dist/daemon/source-schedule.js.map +1 -0
  426. package/dist/embedded-assets.generated.d.ts +4 -0
  427. package/dist/embedded-assets.generated.d.ts.map +1 -0
  428. package/dist/embedded-assets.generated.js +12 -0
  429. package/dist/embedded-assets.generated.js.map +1 -0
  430. package/dist/extractors/noise-filter.d.ts +30 -0
  431. package/dist/extractors/noise-filter.d.ts.map +1 -0
  432. package/dist/extractors/noise-filter.js +185 -0
  433. package/dist/extractors/noise-filter.js.map +1 -0
  434. package/dist/extractors/playbook-extractor.d.ts +35 -0
  435. package/dist/extractors/playbook-extractor.d.ts.map +1 -0
  436. package/dist/extractors/playbook-extractor.js +98 -0
  437. package/dist/extractors/playbook-extractor.js.map +1 -0
  438. package/dist/extractors/providers/anthropic.d.ts +13 -0
  439. package/dist/extractors/providers/anthropic.d.ts.map +1 -0
  440. package/dist/extractors/providers/anthropic.js +67 -0
  441. package/dist/extractors/providers/anthropic.js.map +1 -0
  442. package/dist/extractors/providers/index.d.ts +12 -0
  443. package/dist/extractors/providers/index.d.ts.map +1 -0
  444. package/dist/extractors/providers/index.js +41 -0
  445. package/dist/extractors/providers/index.js.map +1 -0
  446. package/dist/extractors/providers/mock.d.ts +14 -0
  447. package/dist/extractors/providers/mock.d.ts.map +1 -0
  448. package/dist/extractors/providers/mock.js +37 -0
  449. package/dist/extractors/providers/mock.js.map +1 -0
  450. package/dist/extractors/providers/openai.d.ts +15 -0
  451. package/dist/extractors/providers/openai.d.ts.map +1 -0
  452. package/dist/extractors/providers/openai.js +109 -0
  453. package/dist/extractors/providers/openai.js.map +1 -0
  454. package/dist/extractors/providers/types.d.ts +27 -0
  455. package/dist/extractors/providers/types.d.ts.map +1 -0
  456. package/dist/extractors/providers/types.js +6 -0
  457. package/dist/extractors/providers/types.js.map +1 -0
  458. package/dist/extractors/signal-extractor.d.ts +30 -0
  459. package/dist/extractors/signal-extractor.d.ts.map +1 -0
  460. package/dist/extractors/signal-extractor.js +371 -0
  461. package/dist/extractors/signal-extractor.js.map +1 -0
  462. package/dist/formatters/index.d.ts +3 -0
  463. package/dist/formatters/index.d.ts.map +1 -0
  464. package/dist/formatters/index.js +3 -0
  465. package/dist/formatters/index.js.map +1 -0
  466. package/dist/formatters/json.d.ts +6 -0
  467. package/dist/formatters/json.d.ts.map +1 -0
  468. package/dist/formatters/json.js +16 -0
  469. package/dist/formatters/json.js.map +1 -0
  470. package/dist/formatters/markdown.d.ts +6 -0
  471. package/dist/formatters/markdown.d.ts.map +1 -0
  472. package/dist/formatters/markdown.js +198 -0
  473. package/dist/formatters/markdown.js.map +1 -0
  474. package/dist/hooks/handlers.d.ts +21 -0
  475. package/dist/hooks/handlers.d.ts.map +1 -0
  476. package/dist/hooks/handlers.js +22 -0
  477. package/dist/hooks/handlers.js.map +1 -0
  478. package/dist/hooks/inject.d.ts +7 -0
  479. package/dist/hooks/inject.d.ts.map +1 -0
  480. package/dist/hooks/inject.js +18 -0
  481. package/dist/hooks/inject.js.map +1 -0
  482. package/dist/hooks/install.d.ts +14 -0
  483. package/dist/hooks/install.d.ts.map +1 -0
  484. package/dist/hooks/install.js +34 -0
  485. package/dist/hooks/install.js.map +1 -0
  486. package/dist/hooks/output.d.ts +19 -0
  487. package/dist/hooks/output.d.ts.map +1 -0
  488. package/dist/hooks/output.js +13 -0
  489. package/dist/hooks/output.js.map +1 -0
  490. package/dist/hooks/recall-client.d.ts +25 -0
  491. package/dist/hooks/recall-client.d.ts.map +1 -0
  492. package/dist/hooks/recall-client.js +56 -0
  493. package/dist/hooks/recall-client.js.map +1 -0
  494. package/dist/hooks/run-event.d.ts +13 -0
  495. package/dist/hooks/run-event.d.ts.map +1 -0
  496. package/dist/hooks/run-event.js +20 -0
  497. package/dist/hooks/run-event.js.map +1 -0
  498. package/dist/hooks/settings-edit.d.ts +10 -0
  499. package/dist/hooks/settings-edit.d.ts.map +1 -0
  500. package/dist/hooks/settings-edit.js +44 -0
  501. package/dist/hooks/settings-edit.js.map +1 -0
  502. package/dist/hooks/writeback.d.ts +12 -0
  503. package/dist/hooks/writeback.d.ts.map +1 -0
  504. package/dist/hooks/writeback.js +48 -0
  505. package/dist/hooks/writeback.js.map +1 -0
  506. package/dist/install/clients/claude-code.d.ts +3 -0
  507. package/dist/install/clients/claude-code.d.ts.map +1 -0
  508. package/dist/install/clients/claude-code.js +31 -0
  509. package/dist/install/clients/claude-code.js.map +1 -0
  510. package/dist/install/clients/claude-desktop.d.ts +3 -0
  511. package/dist/install/clients/claude-desktop.d.ts.map +1 -0
  512. package/dist/install/clients/claude-desktop.js +33 -0
  513. package/dist/install/clients/claude-desktop.js.map +1 -0
  514. package/dist/install/clients/codex.d.ts +3 -0
  515. package/dist/install/clients/codex.d.ts.map +1 -0
  516. package/dist/install/clients/codex.js +33 -0
  517. package/dist/install/clients/codex.js.map +1 -0
  518. package/dist/install/clients/cursor.d.ts +3 -0
  519. package/dist/install/clients/cursor.d.ts.map +1 -0
  520. package/dist/install/clients/cursor.js +37 -0
  521. package/dist/install/clients/cursor.js.map +1 -0
  522. package/dist/install/clients/hermes.d.ts +3 -0
  523. package/dist/install/clients/hermes.d.ts.map +1 -0
  524. package/dist/install/clients/hermes.js +37 -0
  525. package/dist/install/clients/hermes.js.map +1 -0
  526. package/dist/install/clients/index.d.ts +4 -0
  527. package/dist/install/clients/index.d.ts.map +1 -0
  528. package/dist/install/clients/index.js +18 -0
  529. package/dist/install/clients/index.js.map +1 -0
  530. package/dist/install/clients/windsurf.d.ts +3 -0
  531. package/dist/install/clients/windsurf.d.ts.map +1 -0
  532. package/dist/install/clients/windsurf.js +34 -0
  533. package/dist/install/clients/windsurf.js.map +1 -0
  534. package/dist/install/command.d.ts +14 -0
  535. package/dist/install/command.d.ts.map +1 -0
  536. package/dist/install/command.js +34 -0
  537. package/dist/install/command.js.map +1 -0
  538. package/dist/install/directive.d.ts +7 -0
  539. package/dist/install/directive.d.ts.map +1 -0
  540. package/dist/install/directive.js +31 -0
  541. package/dist/install/directive.js.map +1 -0
  542. package/dist/install/index.d.ts +28 -0
  543. package/dist/install/index.d.ts.map +1 -0
  544. package/dist/install/index.js +122 -0
  545. package/dist/install/index.js.map +1 -0
  546. package/dist/install/json-config.d.ts +8 -0
  547. package/dist/install/json-config.d.ts.map +1 -0
  548. package/dist/install/json-config.js +44 -0
  549. package/dist/install/json-config.js.map +1 -0
  550. package/dist/install/marked-block.d.ts +11 -0
  551. package/dist/install/marked-block.d.ts.map +1 -0
  552. package/dist/install/marked-block.js +34 -0
  553. package/dist/install/marked-block.js.map +1 -0
  554. package/dist/install/mcp-entry.d.ts +11 -0
  555. package/dist/install/mcp-entry.d.ts.map +1 -0
  556. package/dist/install/mcp-entry.js +7 -0
  557. package/dist/install/mcp-entry.js.map +1 -0
  558. package/dist/install/skill.d.ts +4 -0
  559. package/dist/install/skill.d.ts.map +1 -0
  560. package/dist/install/skill.js +61 -0
  561. package/dist/install/skill.js.map +1 -0
  562. package/dist/install/toml-config.d.ts +4 -0
  563. package/dist/install/toml-config.d.ts.map +1 -0
  564. package/dist/install/toml-config.js +54 -0
  565. package/dist/install/toml-config.js.map +1 -0
  566. package/dist/install/types.d.ts +40 -0
  567. package/dist/install/types.d.ts.map +1 -0
  568. package/dist/install/types.js +10 -0
  569. package/dist/install/types.js.map +1 -0
  570. package/dist/install/yaml-config.d.ts +4 -0
  571. package/dist/install/yaml-config.d.ts.map +1 -0
  572. package/dist/install/yaml-config.js +19 -0
  573. package/dist/install/yaml-config.js.map +1 -0
  574. package/dist/lifecycle/down.d.ts +19 -0
  575. package/dist/lifecycle/down.d.ts.map +1 -0
  576. package/dist/lifecycle/down.js +24 -0
  577. package/dist/lifecycle/down.js.map +1 -0
  578. package/dist/lifecycle/health-poll.d.ts +19 -0
  579. package/dist/lifecycle/health-poll.d.ts.map +1 -0
  580. package/dist/lifecycle/health-poll.js +39 -0
  581. package/dist/lifecycle/health-poll.js.map +1 -0
  582. package/dist/lifecycle/install-state.d.ts +34 -0
  583. package/dist/lifecycle/install-state.d.ts.map +1 -0
  584. package/dist/lifecycle/install-state.js +70 -0
  585. package/dist/lifecycle/install-state.js.map +1 -0
  586. package/dist/lifecycle/legacy-migration.d.ts +58 -0
  587. package/dist/lifecycle/legacy-migration.d.ts.map +1 -0
  588. package/dist/lifecycle/legacy-migration.js +212 -0
  589. package/dist/lifecycle/legacy-migration.js.map +1 -0
  590. package/dist/lifecycle/lifecycle-lock.d.ts +20 -0
  591. package/dist/lifecycle/lifecycle-lock.d.ts.map +1 -0
  592. package/dist/lifecycle/lifecycle-lock.js +98 -0
  593. package/dist/lifecycle/lifecycle-lock.js.map +1 -0
  594. package/dist/lifecycle/run-up.d.ts +38 -0
  595. package/dist/lifecycle/run-up.d.ts.map +1 -0
  596. package/dist/lifecycle/run-up.js +307 -0
  597. package/dist/lifecycle/run-up.js.map +1 -0
  598. package/dist/lifecycle/status.d.ts +38 -0
  599. package/dist/lifecycle/status.d.ts.map +1 -0
  600. package/dist/lifecycle/status.js +41 -0
  601. package/dist/lifecycle/status.js.map +1 -0
  602. package/dist/lifecycle/up.d.ts +35 -0
  603. package/dist/lifecycle/up.d.ts.map +1 -0
  604. package/dist/lifecycle/up.js +45 -0
  605. package/dist/lifecycle/up.js.map +1 -0
  606. package/dist/processors/privacy.d.ts +101 -0
  607. package/dist/processors/privacy.d.ts.map +1 -0
  608. package/dist/processors/privacy.js +273 -0
  609. package/dist/processors/privacy.js.map +1 -0
  610. package/dist/profile/accumulate.d.ts +28 -0
  611. package/dist/profile/accumulate.d.ts.map +1 -0
  612. package/dist/profile/accumulate.js +48 -0
  613. package/dist/profile/accumulate.js.map +1 -0
  614. package/dist/profile/behavior.d.ts +32 -0
  615. package/dist/profile/behavior.d.ts.map +1 -0
  616. package/dist/profile/behavior.js +122 -0
  617. package/dist/profile/behavior.js.map +1 -0
  618. package/dist/profile/four-color.d.ts +12 -0
  619. package/dist/profile/four-color.d.ts.map +1 -0
  620. package/dist/profile/four-color.js +39 -0
  621. package/dist/profile/four-color.js.map +1 -0
  622. package/dist/profile/profile-synth.d.ts +27 -0
  623. package/dist/profile/profile-synth.d.ts.map +1 -0
  624. package/dist/profile/profile-synth.js +174 -0
  625. package/dist/profile/profile-synth.js.map +1 -0
  626. package/dist/profile/types.d.ts +84 -0
  627. package/dist/profile/types.d.ts.map +1 -0
  628. package/dist/profile/types.js +11 -0
  629. package/dist/profile/types.js.map +1 -0
  630. package/dist/server/api.d.ts +49 -0
  631. package/dist/server/api.d.ts.map +1 -0
  632. package/dist/server/api.js +502 -0
  633. package/dist/server/api.js.map +1 -0
  634. package/dist/server/backfill-job.d.ts +36 -0
  635. package/dist/server/backfill-job.d.ts.map +1 -0
  636. package/dist/server/backfill-job.js +88 -0
  637. package/dist/server/backfill-job.js.map +1 -0
  638. package/dist/server/backfill-routes.d.ts +7 -0
  639. package/dist/server/backfill-routes.d.ts.map +1 -0
  640. package/dist/server/backfill-routes.js +146 -0
  641. package/dist/server/backfill-routes.js.map +1 -0
  642. package/dist/server/chat-name-refresh-job.d.ts +33 -0
  643. package/dist/server/chat-name-refresh-job.d.ts.map +1 -0
  644. package/dist/server/chat-name-refresh-job.js +120 -0
  645. package/dist/server/chat-name-refresh-job.js.map +1 -0
  646. package/dist/server/chat-name-routes.d.ts +13 -0
  647. package/dist/server/chat-name-routes.d.ts.map +1 -0
  648. package/dist/server/chat-name-routes.js +81 -0
  649. package/dist/server/chat-name-routes.js.map +1 -0
  650. package/dist/server/config-routes.d.ts +10 -0
  651. package/dist/server/config-routes.d.ts.map +1 -0
  652. package/dist/server/config-routes.js +122 -0
  653. package/dist/server/config-routes.js.map +1 -0
  654. package/dist/server/context.d.ts +13 -0
  655. package/dist/server/context.d.ts.map +1 -0
  656. package/dist/server/context.js +47 -0
  657. package/dist/server/context.js.map +1 -0
  658. package/dist/server/entity.d.ts +25 -0
  659. package/dist/server/entity.d.ts.map +1 -0
  660. package/dist/server/entity.js +34 -0
  661. package/dist/server/entity.js.map +1 -0
  662. package/dist/server/event-bus.d.ts +35 -0
  663. package/dist/server/event-bus.d.ts.map +1 -0
  664. package/dist/server/event-bus.js +4 -0
  665. package/dist/server/event-bus.js.map +1 -0
  666. package/dist/server/mcp-http-runtime.d.ts +28 -0
  667. package/dist/server/mcp-http-runtime.d.ts.map +1 -0
  668. package/dist/server/mcp-http-runtime.js +24 -0
  669. package/dist/server/mcp-http-runtime.js.map +1 -0
  670. package/dist/server/mcp-http.d.ts +41 -0
  671. package/dist/server/mcp-http.d.ts.map +1 -0
  672. package/dist/server/mcp-http.js +139 -0
  673. package/dist/server/mcp-http.js.map +1 -0
  674. package/dist/server/mcp.d.ts +292 -0
  675. package/dist/server/mcp.d.ts.map +1 -0
  676. package/dist/server/mcp.js +1146 -0
  677. package/dist/server/mcp.js.map +1 -0
  678. package/dist/server/open-browser.d.ts +3 -0
  679. package/dist/server/open-browser.d.ts.map +1 -0
  680. package/dist/server/open-browser.js +12 -0
  681. package/dist/server/open-browser.js.map +1 -0
  682. package/dist/server/runtime.d.ts +13 -0
  683. package/dist/server/runtime.d.ts.map +1 -0
  684. package/dist/server/runtime.js +27 -0
  685. package/dist/server/runtime.js.map +1 -0
  686. package/dist/server/server-security.d.ts +51 -0
  687. package/dist/server/server-security.d.ts.map +1 -0
  688. package/dist/server/server-security.js +76 -0
  689. package/dist/server/server-security.js.map +1 -0
  690. package/dist/server/setup-server.d.ts +7 -0
  691. package/dist/server/setup-server.d.ts.map +1 -0
  692. package/dist/server/setup-server.js +49 -0
  693. package/dist/server/setup-server.js.map +1 -0
  694. package/dist/setup/assess-hardware.d.ts +34 -0
  695. package/dist/setup/assess-hardware.d.ts.map +1 -0
  696. package/dist/setup/assess-hardware.js +179 -0
  697. package/dist/setup/assess-hardware.js.map +1 -0
  698. package/dist/setup/connection-tests.d.ts +17 -0
  699. package/dist/setup/connection-tests.d.ts.map +1 -0
  700. package/dist/setup/connection-tests.js +69 -0
  701. package/dist/setup/connection-tests.js.map +1 -0
  702. package/dist/setup/detect-api-keys.d.ts +13 -0
  703. package/dist/setup/detect-api-keys.d.ts.map +1 -0
  704. package/dist/setup/detect-api-keys.js +41 -0
  705. package/dist/setup/detect-api-keys.js.map +1 -0
  706. package/dist/setup/detect-runtime.d.ts +14 -0
  707. package/dist/setup/detect-runtime.d.ts.map +1 -0
  708. package/dist/setup/detect-runtime.js +43 -0
  709. package/dist/setup/detect-runtime.js.map +1 -0
  710. package/dist/setup/detect-sources.d.ts +14 -0
  711. package/dist/setup/detect-sources.d.ts.map +1 -0
  712. package/dist/setup/detect-sources.js +75 -0
  713. package/dist/setup/detect-sources.js.map +1 -0
  714. package/dist/setup/doctor.d.ts +48 -0
  715. package/dist/setup/doctor.d.ts.map +1 -0
  716. package/dist/setup/doctor.js +157 -0
  717. package/dist/setup/doctor.js.map +1 -0
  718. package/dist/setup/generate-config.d.ts +13 -0
  719. package/dist/setup/generate-config.d.ts.map +1 -0
  720. package/dist/setup/generate-config.js +163 -0
  721. package/dist/setup/generate-config.js.map +1 -0
  722. package/dist/setup/index.d.ts +9 -0
  723. package/dist/setup/index.d.ts.map +1 -0
  724. package/dist/setup/index.js +9 -0
  725. package/dist/setup/index.js.map +1 -0
  726. package/dist/setup/init-wizard.d.ts +20 -0
  727. package/dist/setup/init-wizard.d.ts.map +1 -0
  728. package/dist/setup/init-wizard.js +531 -0
  729. package/dist/setup/init-wizard.js.map +1 -0
  730. package/dist/setup/terminal.d.ts +28 -0
  731. package/dist/setup/terminal.d.ts.map +1 -0
  732. package/dist/setup/terminal.js +258 -0
  733. package/dist/setup/terminal.js.map +1 -0
  734. package/dist/setup/validate-config.d.ts +30 -0
  735. package/dist/setup/validate-config.d.ts.map +1 -0
  736. package/dist/setup/validate-config.js +45 -0
  737. package/dist/setup/validate-config.js.map +1 -0
  738. package/dist/store/chunks.d.ts +25 -0
  739. package/dist/store/chunks.d.ts.map +1 -0
  740. package/dist/store/chunks.js +78 -0
  741. package/dist/store/chunks.js.map +1 -0
  742. package/dist/store/data-dir-lock.d.ts +15 -0
  743. package/dist/store/data-dir-lock.d.ts.map +1 -0
  744. package/dist/store/data-dir-lock.js +96 -0
  745. package/dist/store/data-dir-lock.js.map +1 -0
  746. package/dist/store/database.d.ts +31 -0
  747. package/dist/store/database.d.ts.map +1 -0
  748. package/dist/store/database.js +113 -0
  749. package/dist/store/database.js.map +1 -0
  750. package/dist/store/embedding.d.ts +23 -0
  751. package/dist/store/embedding.d.ts.map +1 -0
  752. package/dist/store/embedding.js +62 -0
  753. package/dist/store/embedding.js.map +1 -0
  754. package/dist/store/engine-factory.d.ts +4 -0
  755. package/dist/store/engine-factory.d.ts.map +1 -0
  756. package/dist/store/engine-factory.js +18 -0
  757. package/dist/store/engine-factory.js.map +1 -0
  758. package/dist/store/graph.d.ts +75 -0
  759. package/dist/store/graph.d.ts.map +1 -0
  760. package/dist/store/graph.js +276 -0
  761. package/dist/store/graph.js.map +1 -0
  762. package/dist/store/managed/managed-engine.d.ts +35 -0
  763. package/dist/store/managed/managed-engine.d.ts.map +1 -0
  764. package/dist/store/managed/managed-engine.js +40 -0
  765. package/dist/store/managed/managed-engine.js.map +1 -0
  766. package/dist/store/managed/managed-lock.d.ts +2 -0
  767. package/dist/store/managed/managed-lock.d.ts.map +1 -0
  768. package/dist/store/managed/managed-lock.js +68 -0
  769. package/dist/store/managed/managed-lock.js.map +1 -0
  770. package/dist/store/managed/new-install.d.ts +12 -0
  771. package/dist/store/managed/new-install.d.ts.map +1 -0
  772. package/dist/store/managed/new-install.js +23 -0
  773. package/dist/store/managed/new-install.js.map +1 -0
  774. package/dist/store/managed/pg-paths.d.ts +28 -0
  775. package/dist/store/managed/pg-paths.d.ts.map +1 -0
  776. package/dist/store/managed/pg-paths.js +41 -0
  777. package/dist/store/managed/pg-paths.js.map +1 -0
  778. package/dist/store/managed/pg-runtime-provider.d.ts +47 -0
  779. package/dist/store/managed/pg-runtime-provider.d.ts.map +1 -0
  780. package/dist/store/managed/pg-runtime-provider.js +249 -0
  781. package/dist/store/managed/pg-runtime-provider.js.map +1 -0
  782. package/dist/store/managed/pg-supervisor.d.ts +30 -0
  783. package/dist/store/managed/pg-supervisor.d.ts.map +1 -0
  784. package/dist/store/managed/pg-supervisor.js +308 -0
  785. package/dist/store/managed/pg-supervisor.js.map +1 -0
  786. package/dist/store/managed/recovery-loop.d.ts +41 -0
  787. package/dist/store/managed/recovery-loop.d.ts.map +1 -0
  788. package/dist/store/managed/recovery-loop.js +87 -0
  789. package/dist/store/managed/recovery-loop.js.map +1 -0
  790. package/dist/store/managed/stop-from-state.d.ts +11 -0
  791. package/dist/store/managed/stop-from-state.d.ts.map +1 -0
  792. package/dist/store/managed/stop-from-state.js +26 -0
  793. package/dist/store/managed/stop-from-state.js.map +1 -0
  794. package/dist/store/migrations/index.d.ts +9 -0
  795. package/dist/store/migrations/index.d.ts.map +1 -0
  796. package/dist/store/migrations/index.js +121 -0
  797. package/dist/store/migrations/index.js.map +1 -0
  798. package/dist/store/pages.d.ts +81 -0
  799. package/dist/store/pages.d.ts.map +1 -0
  800. package/dist/store/pages.js +286 -0
  801. package/dist/store/pages.js.map +1 -0
  802. package/dist/store/person-behavior.d.ts +37 -0
  803. package/dist/store/person-behavior.d.ts.map +1 -0
  804. package/dist/store/person-behavior.js +134 -0
  805. package/dist/store/person-behavior.js.map +1 -0
  806. package/dist/store/pglite-assets.d.ts +15 -0
  807. package/dist/store/pglite-assets.d.ts.map +1 -0
  808. package/dist/store/pglite-assets.js +47 -0
  809. package/dist/store/pglite-assets.js.map +1 -0
  810. package/dist/store/pglite-executor.d.ts +21 -0
  811. package/dist/store/pglite-executor.d.ts.map +1 -0
  812. package/dist/store/pglite-executor.js +61 -0
  813. package/dist/store/pglite-executor.js.map +1 -0
  814. package/dist/store/postgres-executor.d.ts +16 -0
  815. package/dist/store/postgres-executor.d.ts.map +1 -0
  816. package/dist/store/postgres-executor.js +77 -0
  817. package/dist/store/postgres-executor.js.map +1 -0
  818. package/dist/store/query-rewrite.d.ts +28 -0
  819. package/dist/store/query-rewrite.d.ts.map +1 -0
  820. package/dist/store/query-rewrite.js +97 -0
  821. package/dist/store/query-rewrite.js.map +1 -0
  822. package/dist/store/search.d.ts +65 -0
  823. package/dist/store/search.d.ts.map +1 -0
  824. package/dist/store/search.js +312 -0
  825. package/dist/store/search.js.map +1 -0
  826. package/dist/store/sequence-sync.d.ts +22 -0
  827. package/dist/store/sequence-sync.d.ts.map +1 -0
  828. package/dist/store/sequence-sync.js +46 -0
  829. package/dist/store/sequence-sync.js.map +1 -0
  830. package/dist/store/sql-executor.d.ts +17 -0
  831. package/dist/store/sql-executor.d.ts.map +1 -0
  832. package/dist/store/sql-executor.js +3 -0
  833. package/dist/store/sql-executor.js.map +1 -0
  834. package/dist/store/store-meta.d.ts +10 -0
  835. package/dist/store/store-meta.d.ts.map +1 -0
  836. package/dist/store/store-meta.js +13 -0
  837. package/dist/store/store-meta.js.map +1 -0
  838. package/dist/store/tags.d.ts +10 -0
  839. package/dist/store/tags.d.ts.map +1 -0
  840. package/dist/store/tags.js +35 -0
  841. package/dist/store/tags.js.map +1 -0
  842. package/dist/store/timeline.d.ts +38 -0
  843. package/dist/store/timeline.d.ts.map +1 -0
  844. package/dist/store/timeline.js +173 -0
  845. package/dist/store/timeline.js.map +1 -0
  846. package/dist/store/trgm-search.d.ts +13 -0
  847. package/dist/store/trgm-search.d.ts.map +1 -0
  848. package/dist/store/trgm-search.js +53 -0
  849. package/dist/store/trgm-search.js.map +1 -0
  850. package/dist/store/wikilink.d.ts +17 -0
  851. package/dist/store/wikilink.d.ts.map +1 -0
  852. package/dist/store/wikilink.js +58 -0
  853. package/dist/store/wikilink.js.map +1 -0
  854. package/dist/sync/obsidian.d.ts +136 -0
  855. package/dist/sync/obsidian.d.ts.map +1 -0
  856. package/dist/sync/obsidian.js +543 -0
  857. package/dist/sync/obsidian.js.map +1 -0
  858. package/dist/synth/cache.d.ts +17 -0
  859. package/dist/synth/cache.d.ts.map +1 -0
  860. package/dist/synth/cache.js +67 -0
  861. package/dist/synth/cache.js.map +1 -0
  862. package/dist/synth/citations.d.ts +12 -0
  863. package/dist/synth/citations.d.ts.map +1 -0
  864. package/dist/synth/citations.js +28 -0
  865. package/dist/synth/citations.js.map +1 -0
  866. package/dist/synth/context.d.ts +10 -0
  867. package/dist/synth/context.d.ts.map +1 -0
  868. package/dist/synth/context.js +67 -0
  869. package/dist/synth/context.js.map +1 -0
  870. package/dist/synth/engine.d.ts +16 -0
  871. package/dist/synth/engine.d.ts.map +1 -0
  872. package/dist/synth/engine.js +111 -0
  873. package/dist/synth/engine.js.map +1 -0
  874. package/dist/synth/gaps.d.ts +17 -0
  875. package/dist/synth/gaps.d.ts.map +1 -0
  876. package/dist/synth/gaps.js +57 -0
  877. package/dist/synth/gaps.js.map +1 -0
  878. package/dist/synth/index.d.ts +6 -0
  879. package/dist/synth/index.d.ts.map +1 -0
  880. package/dist/synth/index.js +6 -0
  881. package/dist/synth/index.js.map +1 -0
  882. package/dist/synth/intent.d.ts +6 -0
  883. package/dist/synth/intent.d.ts.map +1 -0
  884. package/dist/synth/intent.js +13 -0
  885. package/dist/synth/intent.js.map +1 -0
  886. package/dist/synth/intents/daily-report.d.ts +7 -0
  887. package/dist/synth/intents/daily-report.d.ts.map +1 -0
  888. package/dist/synth/intents/daily-report.js +37 -0
  889. package/dist/synth/intents/daily-report.js.map +1 -0
  890. package/dist/synth/intents/index.d.ts +2 -0
  891. package/dist/synth/intents/index.d.ts.map +1 -0
  892. package/dist/synth/intents/index.js +12 -0
  893. package/dist/synth/intents/index.js.map +1 -0
  894. package/dist/synth/intents/person-strategy.d.ts +40 -0
  895. package/dist/synth/intents/person-strategy.d.ts.map +1 -0
  896. package/dist/synth/intents/person-strategy.js +66 -0
  897. package/dist/synth/intents/person-strategy.js.map +1 -0
  898. package/dist/synth/intents/recall.d.ts +8 -0
  899. package/dist/synth/intents/recall.d.ts.map +1 -0
  900. package/dist/synth/intents/recall.js +26 -0
  901. package/dist/synth/intents/recall.js.map +1 -0
  902. package/dist/synth/intents/troubleshoot.d.ts +11 -0
  903. package/dist/synth/intents/troubleshoot.d.ts.map +1 -0
  904. package/dist/synth/intents/troubleshoot.js +66 -0
  905. package/dist/synth/intents/troubleshoot.js.map +1 -0
  906. package/dist/synth/scope.d.ts +13 -0
  907. package/dist/synth/scope.d.ts.map +1 -0
  908. package/dist/synth/scope.js +139 -0
  909. package/dist/synth/scope.js.map +1 -0
  910. package/dist/synth/types.d.ts +117 -0
  911. package/dist/synth/types.d.ts.map +1 -0
  912. package/dist/synth/types.js +2 -0
  913. package/dist/synth/types.js.map +1 -0
  914. package/package.json +98 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1579 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, isAbsolute, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { Command } from "commander";
8
+ import { planStartup, shouldOpenBrowserOnServe } from "./cli-helpers.js";
9
+ import { createStores, openIdentityStore } from "./cli-stores.js";
10
+ import { normalizeDocsConfig } from "./collectors/feishu/docs/config.js";
11
+ import { FullCardBuilder } from "./collectors/feishu/docs/full-builder.js";
12
+ import { runDocSource } from "./collectors/feishu/docs/run.js";
13
+ import { failedCards, summarizeCards } from "./collectors/feishu/docs/status.js";
14
+ import { loadExistingCard, writeCard } from "./collectors/feishu/docs/store-writer.js";
15
+ import { LarkCliHttpClient } from "./collectors/feishu/lark-cli-client.js";
16
+ import { resolveSelfOpenId } from "./collectors/feishu/self-open-id.js";
17
+ import { createClaudeCodeCollector, createCodexCollector, createFeishuCollector, createHermesCollector, getAllCollectors, getCollector, registerCollector, resetRegistry, } from "./collectors/index.js";
18
+ import { Consolidator } from "./consolidator/consolidator.js";
19
+ import { loadConfig, resolveConfigPath, } from "./core/config.js";
20
+ import { CursorStore } from "./core/cursors.js";
21
+ import { getMissingEnvVarsForCommand, validateEnvForCommand } from "./core/env-validation.js";
22
+ import { PersonIdentityStore } from "./core/person-identity.js";
23
+ import { runPipeline } from "./core/pipeline.js";
24
+ import { buildPipelineConfig } from "./core/pipeline-factory.js";
25
+ import { ensureStateDir, statePath } from "./core/state.js";
26
+ import { rawYamlHash, readDaemonState, servingSubsetHash, } from "./daemon/autostart/daemon-state.js";
27
+ import { disableAutostart, statusAutostart } from "./daemon/autostart/index.js";
28
+ import { nodeRunner } from "./daemon/autostart/runner.js";
29
+ import { ReloadManager } from "./daemon/reload-manager.js";
30
+ import { buildServeRuntime, ServeRuntimeHolder } from "./daemon/serve-runtime.js";
31
+ import { VERSION } from "./embedded-assets.generated.js";
32
+ import { createLLMProvider, createMockProvider } from "./extractors/providers/index.js";
33
+ import { hooksInstall, hooksUninstall } from "./hooks/install.js";
34
+ import { runHookEvent } from "./hooks/run-event.js";
35
+ import { runInstall, runUninstall } from "./install/index.js";
36
+ import { scaffoldSkill } from "./install/skill.js";
37
+ import { down } from "./lifecycle/down.js";
38
+ import { migrateLegacyData } from "./lifecycle/legacy-migration.js";
39
+ import { acquireLifecycleLock } from "./lifecycle/lifecycle-lock.js";
40
+ import { runUp } from "./lifecycle/run-up.js";
41
+ import { computeStatus, formatManagedStatus } from "./lifecycle/status.js";
42
+ import { createApiApp } from "./server/api.js";
43
+ import { getSessionContext } from "./server/context.js";
44
+ import { createMcpServer } from "./server/mcp.js";
45
+ import { createMcpHttpApp } from "./server/mcp-http.js";
46
+ import { assertLoopbackOrThrow, resolveMcpHttpRuntime } from "./server/mcp-http-runtime.js";
47
+ import { openBrowser } from "./server/open-browser.js";
48
+ import { startServer } from "./server/runtime.js";
49
+ import { resolveServeSecurity } from "./server/server-security.js";
50
+ import { managedPaths, readManagedState } from "./store/managed/pg-paths.js";
51
+ import { startRecoveryLoop } from "./store/managed/recovery-loop.js";
52
+ import { stopManagedFromState } from "./store/managed/stop-from-state.js";
53
+ import { PersonBehaviorStore } from "./store/person-behavior.js";
54
+ function resolveProjectPath(path, projectRoot) {
55
+ if (!path)
56
+ return undefined;
57
+ if (path.startsWith("~/"))
58
+ return resolve(homedir(), path.slice(2));
59
+ if (path === "~")
60
+ return homedir();
61
+ if (isAbsolute(path))
62
+ return path;
63
+ return resolve(projectRoot, path);
64
+ }
65
+ function bootstrapCollectors(sources, projectRoot) {
66
+ resetRegistry();
67
+ const agentConfigs = {
68
+ "claude-code": { factory: createClaudeCodeCollector, config: sources["claude-code"] },
69
+ codex: { factory: createCodexCollector, config: sources.codex },
70
+ hermes: { factory: createHermesCollector, config: sources.hermes },
71
+ };
72
+ for (const [_id, { factory, config }] of Object.entries(agentConfigs)) {
73
+ if (config?.enabled !== false) {
74
+ registerCollector(factory(resolveProjectPath(config?.base_dir, projectRoot)));
75
+ }
76
+ }
77
+ if (sources.feishu?.enabled !== false && sources.feishu?.app_id) {
78
+ registerCollector(createFeishuCollector(sources.feishu));
79
+ }
80
+ }
81
+ // Try to extract feishu.lark_bin from an existing config so the setup UI's
82
+ // "Feishu — Test Connection" button doesn't fall through to the hardcoded
83
+ // ~/.local/bin/lark path. Silent on missing file or parse errors (the wizard
84
+ // may be running because the YAML doesn't exist yet).
85
+ function readLarkBinFromConfig(configPath) {
86
+ const path = configPath ?? resolve(process.cwd(), "memkin.yaml");
87
+ if (!existsSync(path))
88
+ return undefined;
89
+ try {
90
+ return loadConfig(path).sources?.feishu?.lark_bin;
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ }
96
+ const program = new Command();
97
+ program
98
+ .name("memkin")
99
+ .description("Local-first personal memory extraction and storage")
100
+ .version(VERSION);
101
+ // One-shot legacy auto-migration (memoark → memkin). Runs BEFORE every command's
102
+ // action — i.e. before loadConfig reads memkin.yaml or any store opens — so
103
+ // existing users' data/config/state are moved to the new paths seamlessly.
104
+ // preAction fires for subcommands AND the default program action, covering
105
+ // serve / extract / init / start (and the Tauri sidecar, which shells out to
106
+ // `memkin serve`). All notices go to STDERR: in `serve --mcp` stdout is the
107
+ // JSON-RPC channel and must stay byte-clean, so migration output can never use it.
108
+ program.hook("preAction", () => {
109
+ try {
110
+ migrateLegacyData({ home: homedir(), cwd: process.cwd(), env: process.env });
111
+ }
112
+ catch (err) {
113
+ // Migration is best-effort: a failure must never block the command. Report
114
+ // to stderr and continue (the command will fall through to fresh defaults).
115
+ console.error(`[migration] legacy data migration skipped: ${err instanceof Error ? err.message : String(err)}`);
116
+ }
117
+ });
118
+ program
119
+ .command("init")
120
+ .description("Interactive setup wizard - generates memkin.yaml")
121
+ .option("--auto", "Automatic mode, no prompts")
122
+ .option("--force", "Overwrite existing configuration")
123
+ .option("-c, --config <path>", "Path to output config file (default: memkin.yaml)")
124
+ .option("--no-tui", "Use non-TUI fallback")
125
+ .option("--web", "Launch browser-based setup UI")
126
+ .action(async (options) => {
127
+ if (options.web) {
128
+ const { startSetupServer } = await import("./server/setup-server.js");
129
+ await startSetupServer({
130
+ configPath: options.config,
131
+ larkBin: readLarkBinFromConfig(options.config),
132
+ });
133
+ return;
134
+ }
135
+ try {
136
+ const { runInit } = await import("./setup/index.js");
137
+ await runInit({
138
+ auto: options.auto,
139
+ force: options.force,
140
+ configPath: options.config,
141
+ tui: options.tui,
142
+ });
143
+ }
144
+ catch (error) {
145
+ console.error(error instanceof Error ? error.message : String(error));
146
+ process.exit(1);
147
+ }
148
+ });
149
+ /**
150
+ * Extract command - main pipeline execution
151
+ */
152
+ program
153
+ .command("extract")
154
+ .description("Extract signals from a platform or source")
155
+ .option("-s, --source <name>", "Source/collector name (e.g., claude-code, codex, hermes, feishu, or 'all' for all enabled sources)", "claude-code")
156
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
157
+ .option("-f, --format <type>", "Output format (json|markdown)", "json")
158
+ .option("-a, --adapter <type>", "Output adapter (store|file|gbrain|stdout)", "store")
159
+ .option("-o, --output <dir>", "Output directory for file adapter")
160
+ .option("--since <date>", "Only process messages since date (ISO 8601 or relative: 1d, 2h, 30m)")
161
+ .option("--limit <n>", "Limit number of messages to process", undefined)
162
+ .option("--dry-run", "Do not write outputs, only test pipeline")
163
+ .action(async (options) => {
164
+ try {
165
+ // Load configuration
166
+ const config = loadConfig(options.config);
167
+ const { projectRoot } = config.__context;
168
+ // Ensure state directory exists
169
+ ensureStateDir(projectRoot);
170
+ // Bootstrap collectors from config
171
+ bootstrapCollectors(config.sources, projectRoot);
172
+ // Determine which sources to process
173
+ let sourceIds;
174
+ if (options.source === "all") {
175
+ sourceIds = getAllCollectors().map((c) => c.id);
176
+ }
177
+ else {
178
+ sourceIds = [options.source];
179
+ }
180
+ // Create LLM provider based on config (shared across all sources)
181
+ let provider;
182
+ if (!options.dryRun) {
183
+ validateEnvForCommand(config, "extract");
184
+ const llmConfig = config.llm;
185
+ const envKey = llmConfig.provider === "anthropic"
186
+ ? process.env.ANTHROPIC_API_KEY
187
+ : process.env.OPENAI_API_KEY;
188
+ if (!llmConfig.api_key && !envKey) {
189
+ const envVarName = llmConfig.provider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
190
+ console.error(`Error: No API key configured. Set api_key in memkin.yaml or ${envVarName} env var.`);
191
+ process.exit(1);
192
+ }
193
+ if (!llmConfig.api_key) {
194
+ llmConfig.api_key = envKey;
195
+ }
196
+ provider = createLLMProvider(llmConfig);
197
+ }
198
+ else {
199
+ provider = createMockProvider(new Map());
200
+ }
201
+ // Build pipeline configuration
202
+ const pipelineConfig = buildPipelineConfig(config, options.output || process.cwd(), projectRoot);
203
+ // Parse options
204
+ const format = ["json", "markdown"].includes(options.format) ? options.format : "json";
205
+ const adapter = ["store", "file", "gbrain", "stdout"].includes(options.adapter)
206
+ ? options.adapter
207
+ : "store";
208
+ const limit = options.limit ? parseInt(options.limit, 10) : undefined;
209
+ // Create stores if using store adapter
210
+ let stores;
211
+ if (adapter === "store") {
212
+ stores = await createStores(config);
213
+ }
214
+ // Parse relative since values
215
+ let sinceValue = options.since;
216
+ if (sinceValue) {
217
+ const relMatch = sinceValue.match(/^(\d+)([dhm])$/);
218
+ if (relMatch) {
219
+ const amount = parseInt(relMatch[1], 10);
220
+ const unit = relMatch[2];
221
+ const ms = unit === "d" ? amount * 86400000 : unit === "h" ? amount * 3600000 : amount * 60000;
222
+ sinceValue = new Date(Date.now() - ms).toISOString();
223
+ }
224
+ }
225
+ let anyFailed = false;
226
+ // Process each source
227
+ for (const sourceId of sourceIds) {
228
+ const collector = getCollector(sourceId);
229
+ if (!collector) {
230
+ console.error(`Error: Unknown source '${sourceId}'`);
231
+ anyFailed = true;
232
+ continue;
233
+ }
234
+ // Health check
235
+ const health = await collector.healthCheck();
236
+ if (!health.ok) {
237
+ if (options.source === "all") {
238
+ console.warn(`Warning: ${sourceId} not available — ${health.message}. Skipping.`);
239
+ continue;
240
+ }
241
+ console.error(`Error: ${sourceId} health check failed — ${health.message}`);
242
+ process.exit(1);
243
+ }
244
+ // Run pipeline for this source
245
+ console.log(`\n--- Extracting from: ${sourceId} ---`);
246
+ console.log(`Format: ${format}, Adapter: ${adapter}`);
247
+ if (options.dryRun)
248
+ console.log("DRY-RUN mode enabled");
249
+ if (sinceValue)
250
+ console.log(`Since: ${sinceValue}`);
251
+ if (limit)
252
+ console.log(`Limit: ${limit} messages`);
253
+ console.log("");
254
+ try {
255
+ const result = await runPipeline(pipelineConfig, {
256
+ source: collector,
257
+ provider,
258
+ format: format,
259
+ adapter: adapter,
260
+ stores,
261
+ dryRun: options.dryRun || false,
262
+ since: sinceValue,
263
+ limit,
264
+ });
265
+ // Report results
266
+ console.log("Pipeline execution complete:");
267
+ console.log(` Total messages: ${result.totalMessages}`);
268
+ console.log(` Total blocks: ${result.totalBlocks}`);
269
+ console.log(` OK blocks: ${result.okBlocks}`);
270
+ console.log(` Skipped blocks: ${result.skippedBlocks}`);
271
+ console.log(` Failed blocks: ${result.failedBlocks}`);
272
+ if (result.warnings.length > 0) {
273
+ console.log("\nWarnings:");
274
+ for (const warning of result.warnings) {
275
+ console.log(` - ${warning}`);
276
+ }
277
+ }
278
+ if (result.fatal) {
279
+ console.error(`\nFatal error: ${result.error}`);
280
+ anyFailed = true;
281
+ }
282
+ }
283
+ catch (error) {
284
+ console.error(`\nPipeline failed for ${sourceId}:`, error instanceof Error ? error.message : String(error));
285
+ anyFailed = true;
286
+ }
287
+ }
288
+ // Close stores if they were created
289
+ if (stores) {
290
+ await stores.db.close();
291
+ }
292
+ if (anyFailed) {
293
+ process.exit(1);
294
+ }
295
+ }
296
+ catch (error) {
297
+ console.error("Extract failed:", error instanceof Error ? error.message : String(error));
298
+ process.exit(1);
299
+ }
300
+ });
301
+ /**
302
+ * Doctor command - diagnose configuration and setup
303
+ */
304
+ program
305
+ .command("doctor")
306
+ .description("Diagnose configuration and connectivity")
307
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
308
+ .action(async (options) => {
309
+ const issues = [];
310
+ const warnings = [];
311
+ const ok = [];
312
+ // Check config file
313
+ const configPath = resolveConfigPath(options.config);
314
+ let config = null;
315
+ if (existsSync(configPath)) {
316
+ ok.push(`Configuration file found: ${configPath}`);
317
+ try {
318
+ config = loadConfig(options.config);
319
+ ok.push("Configuration loaded successfully");
320
+ }
321
+ catch (error) {
322
+ issues.push(`Configuration loading failed: ${error instanceof Error ? error.message : String(error)}`);
323
+ }
324
+ }
325
+ else {
326
+ warnings.push(`Configuration file not found: ${configPath}`);
327
+ warnings.push("Create one with: memkin init");
328
+ }
329
+ // Check state directory
330
+ const projectRoot = config?.__context.projectRoot ?? dirname(configPath);
331
+ const stateDir = resolve(projectRoot, ".memkin");
332
+ if (existsSync(stateDir)) {
333
+ ok.push(`State directory exists: ${stateDir}`);
334
+ }
335
+ else {
336
+ warnings.push(`State directory does not exist: ${stateDir}`);
337
+ warnings.push("It will be created automatically on first extract");
338
+ }
339
+ const cwdStateDir = resolve(process.cwd(), ".memkin");
340
+ if (cwdStateDir !== stateDir && existsSync(cwdStateDir)) {
341
+ warnings.push(`Legacy state directory found at current cwd: ${cwdStateDir}`);
342
+ warnings.push(`Current config-root state directory is: ${stateDir}`);
343
+ warnings.push("Move cursor/dedup files manually if you intended to reuse the old state.");
344
+ }
345
+ // Check LLM configuration
346
+ if (config) {
347
+ const missingEnvVars = getMissingEnvVarsForCommand(config, "doctor");
348
+ if (missingEnvVars.length > 0) {
349
+ warnings.push(`Missing environment variables: ${missingEnvVars.join(", ")}`);
350
+ warnings.push(`Referenced by: ${config.__context.configPath}`);
351
+ }
352
+ if (config.llm?.provider && config.llm?.model) {
353
+ ok.push(`LLM provider configured: ${config.llm.provider} / ${config.llm.model}`);
354
+ const envKey = config.llm.provider === "anthropic" ? "ANTHROPIC_API_KEY" : "OPENAI_API_KEY";
355
+ if (!missingEnvVars.includes(envKey)) {
356
+ ok.push(`${config.llm.provider} API key configured`);
357
+ }
358
+ else {
359
+ warnings.push(`${envKey} environment variable not set and no api_key in config`);
360
+ warnings.push(`Set ${envKey} or add api_key to llm config`);
361
+ }
362
+ }
363
+ else {
364
+ issues.push("LLM provider or model not configured");
365
+ }
366
+ // Check sources
367
+ bootstrapCollectors(config.sources, config.__context.projectRoot);
368
+ for (const collector of getAllCollectors()) {
369
+ const health = await collector.healthCheck();
370
+ if (health.ok) {
371
+ ok.push(`Source ${collector.id}: ${health.message}`);
372
+ }
373
+ else {
374
+ warnings.push(`Source ${collector.id}: ${health.message}`);
375
+ }
376
+ }
377
+ // Check Postgres engine
378
+ if ((config.store?.engine ?? "pglite") === "postgres") {
379
+ const dbUrl = config.store?.database_url;
380
+ if (!dbUrl) {
381
+ issues.push("Postgres: store.database_url is not set");
382
+ }
383
+ else {
384
+ const { checkPostgres } = await import("./setup/doctor.js");
385
+ const { maskDatabaseUrl } = await import("./config-center/secrets.js");
386
+ const pg = await checkPostgres(dbUrl);
387
+ if (!pg.connected) {
388
+ issues.push(`Postgres: cannot connect to ${maskDatabaseUrl(dbUrl)}`);
389
+ }
390
+ else {
391
+ ok.push(`Postgres: connected ✓ (${maskDatabaseUrl(dbUrl)})`);
392
+ if (pg.vectorReady) {
393
+ ok.push("Postgres: pgvector ready ✓");
394
+ }
395
+ else {
396
+ issues.push("Postgres: pgvector extension is not available or cannot be created — " +
397
+ "install pgvector and ensure the role has permission to CREATE EXTENSION");
398
+ }
399
+ const { checkPgIdSequences } = await import("./setup/doctor.js");
400
+ const desync = await checkPgIdSequences(dbUrl);
401
+ if (desync === null) {
402
+ warnings.push("Postgres: id sequence check could not run (connection error)");
403
+ }
404
+ else if (desync.length > 0) {
405
+ warnings.push(`Postgres: id sequence desync on ${desync
406
+ .map((d) => `${d.table} (max id ${d.maxId}, sequence would yield ${d.nextValue})`)
407
+ .join(", ")} — usually caused by an id-preserving import/restore. ` +
408
+ "Writes to new slugs fail with duplicate-key errors until repaired; " +
409
+ "memoark repairs this automatically the next time the store is opened " +
410
+ "(any command that touches the store, e.g. `memoark serve`).");
411
+ }
412
+ else {
413
+ ok.push("Postgres: id sequences in sync ✓");
414
+ }
415
+ }
416
+ }
417
+ }
418
+ // Check managed Postgres engine
419
+ if (config.store?.engine === "managed") {
420
+ const { checkManagedPostgres } = await import("./setup/doctor.js");
421
+ const checks = await checkManagedPostgres({
422
+ home: homedir(),
423
+ managedConfig: config.store.managed,
424
+ });
425
+ for (const check of checks) {
426
+ if (check.severity === "ok") {
427
+ ok.push(check.message);
428
+ }
429
+ else if (check.severity === "warn") {
430
+ warnings.push(check.message);
431
+ }
432
+ else {
433
+ issues.push(check.message);
434
+ }
435
+ }
436
+ }
437
+ }
438
+ // Report results
439
+ console.log("=== Memkin Diagnostic Report ===\n");
440
+ if (ok.length > 0) {
441
+ console.log("✓ OK:");
442
+ for (const msg of ok) {
443
+ console.log(` ${msg}`);
444
+ }
445
+ console.log("");
446
+ }
447
+ if (warnings.length > 0) {
448
+ console.log("⚠ Warnings:");
449
+ for (const msg of warnings) {
450
+ console.log(` ${msg}`);
451
+ }
452
+ console.log("");
453
+ }
454
+ if (issues.length > 0) {
455
+ console.log("✗ Issues:");
456
+ for (const msg of issues) {
457
+ console.log(` ${msg}`);
458
+ }
459
+ console.log("");
460
+ process.exit(1);
461
+ }
462
+ console.log("No critical issues found.");
463
+ });
464
+ /**
465
+ * Config subcommand group
466
+ */
467
+ const configCmd = program.command("config").description("Manage configuration");
468
+ configCmd
469
+ .command("init")
470
+ .description("Generate memkin.yaml (alias for 'memkin init')")
471
+ .option("--auto", "Automatic mode, no prompts")
472
+ .option("--force", "Overwrite existing configuration")
473
+ .option("-c, --config <path>", "Path to output config file (default: memkin.yaml)")
474
+ .option("--no-tui", "Use non-TUI fallback")
475
+ .action(async (options) => {
476
+ try {
477
+ const { runInit } = await import("./setup/index.js");
478
+ await runInit({
479
+ auto: options.auto,
480
+ force: options.force,
481
+ configPath: options.config,
482
+ tui: options.tui,
483
+ });
484
+ }
485
+ catch (error) {
486
+ console.error(error instanceof Error ? error.message : String(error));
487
+ process.exit(1);
488
+ }
489
+ });
490
+ configCmd
491
+ .command("edit")
492
+ .description("Edit configuration in browser UI")
493
+ .option("--web", "Launch browser-based settings UI (default behavior)")
494
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
495
+ .action(async (options) => {
496
+ const { startSetupServer } = await import("./server/setup-server.js");
497
+ await startSetupServer({
498
+ configPath: options.config,
499
+ larkBin: readLarkBinFromConfig(options.config),
500
+ });
501
+ });
502
+ /**
503
+ * Sources subcommand group
504
+ */
505
+ const sourcesCmd = program.command("sources").description("Manage data sources");
506
+ sourcesCmd
507
+ .command("list")
508
+ .description("List available sources")
509
+ .option("-c, --config <path>", "Path to config file")
510
+ .action((options) => {
511
+ const config = loadConfig(options.config);
512
+ bootstrapCollectors(config.sources, config.__context.projectRoot);
513
+ const collectors = getAllCollectors();
514
+ console.log("Available sources:\n");
515
+ for (const c of collectors) {
516
+ console.log(` ${c.id} ✓ enabled`);
517
+ console.log(` ${c.description}`);
518
+ console.log("");
519
+ }
520
+ });
521
+ sourcesCmd
522
+ .command("test <name>")
523
+ .description("Test source connectivity and health")
524
+ .option("-c, --config <path>", "Path to config file")
525
+ .action(async (name, options) => {
526
+ try {
527
+ const config = loadConfig(options.config);
528
+ bootstrapCollectors(config.sources, config.__context.projectRoot);
529
+ const collector = getCollector(name);
530
+ if (!collector) {
531
+ console.error(`Error: Unknown source '${name}'`);
532
+ process.exit(1);
533
+ }
534
+ console.log(`Testing source: ${name}\n`);
535
+ const health = await collector.healthCheck();
536
+ if (health.ok) {
537
+ console.log(`✓ ${health.message}`);
538
+ }
539
+ else {
540
+ console.log(`✗ ${health.message}`);
541
+ process.exit(1);
542
+ }
543
+ }
544
+ catch (error) {
545
+ console.error("Test failed:", error instanceof Error ? error.message : String(error));
546
+ process.exit(1);
547
+ }
548
+ });
549
+ async function runServe(options) {
550
+ {
551
+ const serveConfigPath = options.config ?? resolve(process.cwd(), "memkin.yaml");
552
+ if (!existsSync(serveConfigPath)) {
553
+ console.error("No configuration file found.\n" +
554
+ "Run `memkin start` for one-step setup + launch, or `memkin init --web` to configure first.");
555
+ process.exit(1);
556
+ }
557
+ const config = loadConfig(options.config);
558
+ // Anchor the .memkin state dir to the config's project root, not process.cwd().
559
+ // A Finder-launched sidecar has cwd=/, so the default would try to mkdir /.memkin
560
+ // (EROFS on macOS). projectRoot = dirname(configPath), so it lives beside the config.
561
+ const stateDir = ensureStateDir(config.__context.projectRoot);
562
+ const missingEnvVars = getMissingEnvVarsForCommand(config, "serve");
563
+ if (missingEnvVars.length > 0) {
564
+ console.warn(`[warn] Missing env vars: ${missingEnvVars.join(", ")} (referenced by ${config.__context.configPath})`);
565
+ }
566
+ const stores = await createStores(config);
567
+ // P1-1: recovery loop is a PROCESS-LEVEL resource — started from stores.supervisor,
568
+ // never placed inside the ServeRuntimeHolder/runtime (which is disposed on every reload).
569
+ const recovery = stores.supervisor
570
+ ? startRecoveryLoop(stores.supervisor, { intervalMs: 3000 })
571
+ : undefined;
572
+ const initialRuntime = await buildServeRuntime(config, stores, stateDir);
573
+ const holder = new ServeRuntimeHolder(initialRuntime);
574
+ if (config.scheduler?.enabled)
575
+ await holder.current.scheduler?.start();
576
+ const reloadManager = new ReloadManager({
577
+ holder,
578
+ // only read once at construction for the initial signature; ReloadManager tracks lastConfig internally afterward
579
+ currentConfig: () => config,
580
+ buildRuntime: (next) => buildServeRuntime(next, stores, stateDir),
581
+ onRestartRequired: () => console.warn("[reload] store/engine change saved — restart the daemon (`memkin up` or restart serve) to apply; the running process still uses the previous database."),
582
+ });
583
+ const storesWithDaemon = {
584
+ ...stores,
585
+ getDaemonStatus: () => holder.current.getDaemonStatus(),
586
+ // getter: always reads the current runtime, so a Tier-2 swap is seen by routes
587
+ get chatNameRefreshJob() {
588
+ return holder.current.chatNameRefreshJob;
589
+ },
590
+ };
591
+ let shuttingDown = false;
592
+ const shutdown = async () => {
593
+ if (shuttingDown)
594
+ return; // 防重入:连按 Ctrl-C 不会二次 db.close()
595
+ shuttingDown = true;
596
+ // P1-1: stop recovery loop first, then dispose supervisor monitor (NOT the cluster),
597
+ // then dispose the runtime, then close the DB connection.
598
+ recovery?.stop();
599
+ stores.supervisor?.dispose(); // stops monitor only — does NOT stop the cluster
600
+ await holder.current.dispose();
601
+ try {
602
+ await stores.db.close(); // 触发锁 release
603
+ }
604
+ finally {
605
+ process.exit(0); // db.close() 抛错也必须退出
606
+ }
607
+ };
608
+ process.on("SIGTERM", shutdown);
609
+ process.on("SIGINT", shutdown);
610
+ if (options.mcp) {
611
+ const llmConfig = { ...config.llm };
612
+ const envKey = llmConfig.provider === "anthropic"
613
+ ? process.env.ANTHROPIC_API_KEY
614
+ : process.env.OPENAI_API_KEY;
615
+ if (!llmConfig.api_key && envKey)
616
+ llmConfig.api_key = envKey;
617
+ const synthProvider = llmConfig.api_key
618
+ ? createLLMProvider(llmConfig)
619
+ : createMockProvider(new Map());
620
+ let ingestDeps;
621
+ const feishu = config.sources.feishu;
622
+ if (feishu?.enabled && feishu.sources?.docs?.enabled) {
623
+ const client = new LarkCliHttpClient(feishu.lark_bin);
624
+ ingestDeps = {
625
+ client,
626
+ stores: storesWithDaemon,
627
+ provider: synthProvider,
628
+ model: feishu.sources.docs.llm?.model ?? llmConfig.model,
629
+ nowIso: () => new Date().toISOString(),
630
+ };
631
+ }
632
+ const server = createMcpServer(storesWithDaemon, { provider: synthProvider, synthModel: llmConfig.model }, ingestDeps);
633
+ await server.connect(new StdioServerTransport());
634
+ return;
635
+ }
636
+ if (options.mcpHttp ||
637
+ config.mcp.http.enabled ||
638
+ config.server.mcp_transport === "streamable_http") {
639
+ const runtime = resolveMcpHttpRuntime(config.mcp.http, {
640
+ mcpBind: options.mcpBind,
641
+ mcpPort: options.mcpPort,
642
+ mcpReadWrite: options.mcpReadWrite,
643
+ mcpAllowedHost: options.mcpAllowedHost,
644
+ daemonInstanceId: options.daemonInstanceId,
645
+ });
646
+ assertLoopbackOrThrow(runtime);
647
+ // Server-wide auth token (config server.auth_token / MEMKIN_AUTH_TOKEN)
648
+ // also protects the MCP HTTP endpoint. The MCP-specific auth_token_env is
649
+ // kept for backward compat; the server-wide token wins when both are set.
650
+ const serverToken = resolveServeSecurity({
651
+ configHost: config.server.host,
652
+ configToken: config.server.auth_token,
653
+ envToken: process.env.MEMKIN_AUTH_TOKEN,
654
+ }).authToken;
655
+ const tokenEnv = config.mcp.http.auth_token_env;
656
+ const resolvedConfigPath = config.__context.configPath;
657
+ let loadedConfigHash;
658
+ try {
659
+ loadedConfigHash = rawYamlHash(resolvedConfigPath);
660
+ }
661
+ catch {
662
+ // config file may not exist yet; leave hash undefined
663
+ }
664
+ const app = createMcpHttpApp(storesWithDaemon, {
665
+ allowedOrigins: runtime.allowedOrigins,
666
+ allowedHosts: runtime.allowedHosts,
667
+ authToken: serverToken ?? (tokenEnv ? process.env[tokenEnv] : undefined),
668
+ exposeLegacyTools: config.mcp.expose_legacy_tools,
669
+ readOnly: runtime.readOnly,
670
+ health: {
671
+ instanceId: runtime.instanceId,
672
+ pid: process.pid,
673
+ engine: config.store.engine ?? "pglite",
674
+ version: VERSION,
675
+ loadedConfigHash,
676
+ // FIX 5: wire port/bind so isReady() port/bind checks are load-bearing
677
+ port: runtime.port,
678
+ bind: runtime.bind,
679
+ dbProbe: async () => {
680
+ try {
681
+ await stores.db.executor.query("SELECT 1");
682
+ return true;
683
+ }
684
+ catch {
685
+ return false;
686
+ }
687
+ },
688
+ pgProbe: stores.supervisor
689
+ ? async () => (await stores.supervisor.status()) === "running"
690
+ : undefined,
691
+ },
692
+ });
693
+ const server = await startServer(app, {
694
+ hostname: runtime.bind,
695
+ port: runtime.port,
696
+ });
697
+ console.log(`Memkin MCP Streamable HTTP listening on http://${server.hostname}:${server.port}/mcp`);
698
+ return;
699
+ }
700
+ // Resolve bind host + auth token BEFORE creating stores' HTTP surface.
701
+ // Rule: loopback by default; a non-loopback bind REFUSES to start unless an
702
+ // auth token is configured. When a token is set it is enforced everywhere
703
+ // (including loopback). Throws with an actionable message on misconfig.
704
+ const security = resolveServeSecurity({
705
+ flagHost: options.host,
706
+ configHost: config.server.host,
707
+ configToken: config.server.auth_token,
708
+ envToken: process.env.MEMKIN_AUTH_TOKEN,
709
+ });
710
+ const app = createApiApp(storesWithDaemon, {
711
+ authToken: security.authToken,
712
+ onConfigSaved: () => {
713
+ try {
714
+ void reloadManager.run(loadConfig(options.config)).catch((err) => {
715
+ console.error("[reload] Runtime reload failed:", err);
716
+ });
717
+ }
718
+ catch (err) {
719
+ console.error("[reload] Failed to load config after save:", err);
720
+ }
721
+ },
722
+ });
723
+ // In a `bun --compile` sidecar, import.meta.url lives under $bunfs and web/dist is
724
+ // NOT embedded, so the default path can't be served. The Tauri shell ships web/dist
725
+ // as a resource and injects its real path via MEMKIN_WEB_DIST (mirrors pglite-assets).
726
+ const webDist = process.env.MEMKIN_WEB_DIST ?? join(fileURLToPath(import.meta.url), "../../web/dist");
727
+ // `--port 0` (used by the Tauri shell) binds an OS-assigned free port so the desktop
728
+ // app never collides with a CLI `memkin serve`, a stale instance, or anything else
729
+ // on the default port. The actual port is reported below for the webview to read.
730
+ const requestedPort = options.port !== undefined ? Number(options.port) : config.server.http_port;
731
+ const server = Bun.serve({
732
+ port: requestedPort,
733
+ // Loopback by default; `--host` / `server.host` can widen this, but only
734
+ // when an auth token is configured (enforced by resolveServeSecurity above).
735
+ hostname: security.host,
736
+ fetch: async (req) => {
737
+ const url = new URL(req.url);
738
+ // Auth (when a token is configured) is enforced inside the Hono app's
739
+ // /api/* middleware. Web UI static assets below stay unauthenticated —
740
+ // they are the app shell, not data.
741
+ if (url.pathname.startsWith("/api"))
742
+ return app.fetch(req);
743
+ const filePath = url.pathname === "/" ? "index.html" : url.pathname.replace(/^\//, "");
744
+ const candidate = Bun.file(join(webDist, filePath));
745
+ if (await candidate.exists())
746
+ return new Response(candidate);
747
+ return new Response(Bun.file(join(webDist, "index.html")));
748
+ },
749
+ });
750
+ console.log(`Memkin HTTP API listening on http://localhost:${server.port}`);
751
+ // Stdout contract for the Tauri shell: the URL after the marker is where the webview
752
+ // navigates (the port may be OS-assigned, so report the real one — never hardcode).
753
+ console.log(`MEMKIN_READY http://localhost:${server.port}`);
754
+ if (shouldOpenBrowserOnServe({
755
+ open: options.open !== false,
756
+ mcp: !!options.mcp,
757
+ mcpHttp: !!options.mcpHttp,
758
+ })) {
759
+ openBrowser(`http://localhost:${server.port}`);
760
+ }
761
+ const activeScheduler = holder.current.scheduler;
762
+ if (activeScheduler && config.scheduler?.enabled) {
763
+ console.log(`Scheduler running — tick every ${config.scheduler.tick_interval_secs}s, sources: ${activeScheduler.getSourceIds().join(", ")}`);
764
+ }
765
+ }
766
+ }
767
+ program
768
+ .command("serve")
769
+ .description("Start Memkin HTTP API or MCP stdio server")
770
+ .option("-c, --config <path>", "Path to config file")
771
+ .option("--mcp", "Run MCP stdio transport instead of HTTP")
772
+ .option("--mcp-http", "Run MCP Streamable HTTP transport instead of the HTTP API")
773
+ .option("--no-open", "Do not auto-open the browser after starting")
774
+ .option("--pglite-assets <dir>", "Directory holding bundled PGLite assets (compiled-sidecar mode; injected by the Tauri shell)")
775
+ .option("--web-dist <dir>", "Directory holding the built web UI (compiled-sidecar mode; injected by the Tauri shell)")
776
+ .option("--port <n>", "Override the HTTP port; 0 binds an OS-assigned free port (used by the Tauri shell)")
777
+ .option("--host <host>", "Bind host for the HTTP API + Web UI (default 127.0.0.1, loopback only). " +
778
+ "Binding a non-loopback host (e.g. 0.0.0.0) requires an auth token " +
779
+ "(server.auth_token in config or MEMKIN_AUTH_TOKEN env), or the server refuses to start.")
780
+ .option("--mcp-bind <host>", "")
781
+ .option("--mcp-port <port>", "", (v) => {
782
+ const n = Number.parseInt(v, 10);
783
+ if (Number.isNaN(n))
784
+ throw new Error(`--mcp-port: invalid number "${v}"`);
785
+ return n;
786
+ })
787
+ .option("--mcp-read-write", "")
788
+ .option("--mcp-allowed-host <host>", "", (v, acc) => acc.concat(v), [])
789
+ .option("--daemon-instance-id <id>", "")
790
+ .action((options) => {
791
+ if (options.pgliteAssets)
792
+ process.env.MEMKIN_PGLITE_ASSETS = options.pgliteAssets;
793
+ if (options.webDist)
794
+ process.env.MEMKIN_WEB_DIST = options.webDist;
795
+ return runServe(options);
796
+ });
797
+ async function runStart(options) {
798
+ const configPath = options.config ?? resolve(process.cwd(), "memkin.yaml");
799
+ const plan = planStartup(existsSync(configPath));
800
+ if (plan.runSetup) {
801
+ console.log("No configuration found — launching setup wizard...");
802
+ const { startSetupServer } = await import("./server/setup-server.js");
803
+ await startSetupServer({
804
+ configPath: options.config,
805
+ larkBin: readLarkBinFromConfig(options.config),
806
+ });
807
+ }
808
+ await runServe({ config: options.config });
809
+ }
810
+ program
811
+ .command("start")
812
+ .description("One-step launch: setup if needed, then serve + open browser")
813
+ .option("-c, --config <path>", "Path to config file")
814
+ .action((options) => runStart(options));
815
+ program.action(() => runStart({}));
816
+ function reportPlan(planned, verb, dryRun) {
817
+ if (planned.length === 0) {
818
+ console.log("No AI agents detected. Specify one with --agent <id> (claude-code, claude-desktop, cursor, codex, windsurf).");
819
+ return;
820
+ }
821
+ for (const client of planned) {
822
+ console.log(`\n${verb} → ${client.displayName}:`);
823
+ for (const op of client.ops) {
824
+ const where = "path" in op ? op.path : `cli: ${op.args.join(" ")}`;
825
+ console.log(` - ${op.kind} ${op.action} ${where}`);
826
+ }
827
+ }
828
+ if (!dryRun)
829
+ console.log("\nRestart / reopen your agent for changes to take effect.");
830
+ }
831
+ program
832
+ .command("install")
833
+ .description("Register Memkin (MCP config + memory directive) into your AI agents")
834
+ .option("--agent <ids...>", "Target client(s): claude-code, claude-desktop, cursor, codex, windsurf (default: all detected)")
835
+ .option("--project", "Install into the current project instead of globally")
836
+ .option("--http", "Register the Streamable HTTP transport instead of stdio")
837
+ .option("--url <url>", "Explicit MCP server URL for HTTP transport (default: http://127.0.0.1:<port>/mcp)")
838
+ .option("--port <port>", "MCP server port for HTTP transport URL (default: 3928)", (v) => {
839
+ const n = Number.parseInt(v, 10);
840
+ if (Number.isNaN(n))
841
+ throw new Error(`--port: invalid number "${v}"`);
842
+ return n;
843
+ })
844
+ .option("--dry-run", "Preview changes without writing")
845
+ .action((options) => {
846
+ const scope = options.project ? "project" : "global";
847
+ const planned = runInstall({
848
+ agent: options.agent,
849
+ scope,
850
+ http: !!options.http,
851
+ url: options.url,
852
+ port: options.port,
853
+ dryRun: !!options.dryRun,
854
+ });
855
+ reportPlan(planned, options.dryRun ? "Would install" : "Installed", !!options.dryRun);
856
+ });
857
+ program
858
+ .command("uninstall")
859
+ .description("Remove Memkin MCP config + memory directive from your AI agents")
860
+ .option("--agent <ids...>", "Target client(s) (default: all detected)")
861
+ .option("--project", "Operate on the current project instead of globally")
862
+ .option("--dry-run", "Preview changes without writing")
863
+ .action((options) => {
864
+ const scope = options.project ? "project" : "global";
865
+ const planned = runUninstall({ agent: options.agent, scope, dryRun: !!options.dryRun });
866
+ reportPlan(planned, options.dryRun ? "Would remove" : "Removed", !!options.dryRun);
867
+ });
868
+ const hooksCmd = program
869
+ .command("hooks")
870
+ .description("Manage Claude Code hooks for automatic recall / write-back");
871
+ hooksCmd
872
+ .command("install")
873
+ .description("Install SessionStart + UserPromptSubmit (read) hooks; write-back is opt-in")
874
+ .option("--write-back", "Also install the SessionEnd auto write-back hook (opt-in)")
875
+ .option("--project", "Write to ./.claude/settings.json instead of the global one")
876
+ .option("--dry-run", "Preview without writing")
877
+ .action((options) => {
878
+ const res = hooksInstall({
879
+ writeBack: !!options.writeBack,
880
+ project: !!options.project,
881
+ dryRun: !!options.dryRun,
882
+ });
883
+ console.log(`${options.dryRun ? "Would install" : "Installed"} hooks [${res.events.join(", ")}] → ${res.path}`);
884
+ if (!options.writeBack) {
885
+ console.log("Tip: add --write-back to also auto-capture memory at session end (opt-in).");
886
+ }
887
+ if (!options.dryRun)
888
+ console.log("Reopen Claude Code for the hooks to take effect.");
889
+ });
890
+ hooksCmd
891
+ .command("uninstall")
892
+ .description("Remove all Memkin hooks from settings.json")
893
+ .option("--project", "Operate on ./.claude/settings.json instead of the global one")
894
+ .option("--dry-run", "Preview without writing")
895
+ .action((options) => {
896
+ const res = hooksUninstall({ project: !!options.project, dryRun: !!options.dryRun });
897
+ console.log(`${options.dryRun ? "Would remove" : "Removed"} Memkin hooks → ${res.path}`);
898
+ });
899
+ const skillCmd = program.command("skill").description("Manage the Memkin agent skill");
900
+ skillCmd
901
+ .command("scaffold")
902
+ .description("Write the memkin skill (SKILL.md) into a skills directory")
903
+ .option("--dir <path>", "Target skills directory (default: ./.claude/skills)")
904
+ .action((options) => {
905
+ const dir = options.dir ?? join(process.cwd(), ".claude", "skills");
906
+ const path = scaffoldSkill(dir);
907
+ console.log(`Wrote ${path}`);
908
+ });
909
+ async function readStdinJson() {
910
+ const chunks = [];
911
+ for await (const chunk of process.stdin)
912
+ chunks.push(chunk);
913
+ const raw = Buffer.concat(chunks).toString("utf8").trim();
914
+ if (!raw)
915
+ return {};
916
+ try {
917
+ return JSON.parse(raw);
918
+ }
919
+ catch {
920
+ return {};
921
+ }
922
+ }
923
+ program
924
+ .command("hook <event>")
925
+ .description("Internal: Claude Code hook entrypoint (session-start|user-prompt|session-end)")
926
+ .action(async (event) => {
927
+ try {
928
+ const input = await readStdinJson();
929
+ const config = loadConfig(undefined);
930
+ const port = config.server.http_port;
931
+ const out = await runHookEvent(event, input, {
932
+ port,
933
+ sessionContext: async () => {
934
+ const stores = await createStores(config);
935
+ try {
936
+ return await getSessionContext(stores);
937
+ }
938
+ finally {
939
+ await stores.db.close();
940
+ }
941
+ },
942
+ ftsSearch: async (q, opts) => {
943
+ const stores = await createStores(config);
944
+ try {
945
+ return await stores.search.search(q, opts);
946
+ }
947
+ finally {
948
+ await stores.db.close();
949
+ }
950
+ },
951
+ });
952
+ if (out && Object.keys(out).length > 0)
953
+ process.stdout.write(JSON.stringify(out));
954
+ }
955
+ catch {
956
+ // Never break the host session: emit nothing on any failure.
957
+ }
958
+ process.exit(0);
959
+ });
960
+ program
961
+ .command("search <query>")
962
+ .description("Search Memkin memory")
963
+ .option("-c, --config <path>", "Path to config file")
964
+ .option("--mode <mode>", "Search mode (hybrid|fts)", "hybrid")
965
+ .option("--limit <n>", "Limit results", "20")
966
+ .action(async (query, options) => {
967
+ const config = loadConfig(options.config);
968
+ validateEnvForCommand(config, "search", { searchMode: options.mode });
969
+ const stores = await createStores(config);
970
+ const limit = Number(options.limit);
971
+ const results = options.mode === "fts"
972
+ ? await stores.search.search(query, { limit })
973
+ : await stores.search.query(query, { limit });
974
+ for (const result of results) {
975
+ console.log(`${result.slug}\t${result.score.toFixed(4)}\t${result.snippet.slice(0, 200)}`);
976
+ }
977
+ await stores.db.close();
978
+ });
979
+ program
980
+ .command("embed")
981
+ .description("Embed stale Memkin chunks")
982
+ .option("-c, --config <path>", "Path to config file")
983
+ .option("--limit <n>", "Limit chunks")
984
+ .action(async (options) => {
985
+ const config = loadConfig(options.config);
986
+ validateEnvForCommand(config, "embed");
987
+ const stores = await createStores(config);
988
+ const result = await stores.embedding.embedStale({
989
+ limit: options.limit ? Number(options.limit) : undefined,
990
+ });
991
+ console.log(`Embedded ${result.embedded} chunks, errors ${result.errors}`);
992
+ await stores.db.close();
993
+ });
994
+ /**
995
+ * Obsidian sync — bidirectional export/import between PGLite and a vault.
996
+ * See docs/specs/memkin-2026-06-04-obsidian-sync.md
997
+ */
998
+ program
999
+ .command("export")
1000
+ .description("Export Memkin pages to an Obsidian vault (Markdown)")
1001
+ .requiredOption("--vault <path>", "Obsidian vault directory")
1002
+ .option("--force", "Ignore hash comparison, overwrite all files")
1003
+ .option("--dry-run", "Print intended actions without writing")
1004
+ .option("-c, --config <path>", "Path to config file")
1005
+ .action(async (options) => {
1006
+ const { exportToVault } = await import("./sync/obsidian.js");
1007
+ const stores = await createStores(loadConfig(options.config));
1008
+ try {
1009
+ const result = await exportToVault(stores, options.vault, {
1010
+ force: options.force,
1011
+ dryRun: options.dryRun,
1012
+ });
1013
+ console.log(`Exported: ${result.written} written, ${result.skipped} skipped, ${result.errors.length} errors`);
1014
+ for (const err of result.errors) {
1015
+ console.error(` error: ${err.slug}: ${err.reason}`);
1016
+ }
1017
+ if (options.dryRun)
1018
+ console.log("(dry-run: no files written)");
1019
+ }
1020
+ finally {
1021
+ await stores.db.close();
1022
+ }
1023
+ });
1024
+ program
1025
+ .command("import")
1026
+ .description("Import an Obsidian vault back into Memkin")
1027
+ .requiredOption("--vault <path>", "Obsidian vault directory")
1028
+ .option("--force", "Ignore hash comparison, import all files")
1029
+ .option("--dry-run", "Print intended actions without writing")
1030
+ .option("--strict-conflict", "Skip files where DB has changed since last sync instead of overwriting")
1031
+ .option("-c, --config <path>", "Path to config file")
1032
+ .action(async (options) => {
1033
+ const { importFromVault } = await import("./sync/obsidian.js");
1034
+ const stores = await createStores(loadConfig(options.config));
1035
+ try {
1036
+ const result = await importFromVault(stores, options.vault, {
1037
+ force: options.force,
1038
+ dryRun: options.dryRun,
1039
+ strictConflict: options.strictConflict,
1040
+ });
1041
+ console.log(`Imported: ${result.imported} imported, ${result.skipped} skipped, ${result.errors.length} errors`);
1042
+ for (const w of result.warnings) {
1043
+ console.warn(` warn: ${w.slug}: ${w.reason}`);
1044
+ }
1045
+ for (const err of result.errors) {
1046
+ console.error(` error: ${err.file}: ${err.reason}`);
1047
+ }
1048
+ if (!options.dryRun && result.imported > 0) {
1049
+ console.log("Tip: Run 'memkin embed' to update embeddings for changed pages.");
1050
+ }
1051
+ }
1052
+ finally {
1053
+ await stores.db.close();
1054
+ }
1055
+ });
1056
+ program
1057
+ .command("consolidate")
1058
+ .description("Run memory lifecycle tier rotation (hot→warm and/or warm→cold)")
1059
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
1060
+ .option("--hot", "Run hot→warm rotation only")
1061
+ .option("--warm", "Run warm→cold rotation only (requires LLM API key)")
1062
+ .option("--dry-run", "Report what would be consolidated without writing")
1063
+ .action(async (options) => {
1064
+ try {
1065
+ const config = loadConfig(options.config);
1066
+ const stores = await createStores(config);
1067
+ let llmProvider;
1068
+ if (options.warm || (!options.hot && !options.warm)) {
1069
+ const llmConfig = config.llm;
1070
+ const envKey = llmConfig.provider === "anthropic"
1071
+ ? process.env.ANTHROPIC_API_KEY
1072
+ : process.env.OPENAI_API_KEY;
1073
+ const apiKey = llmConfig.api_key ?? envKey;
1074
+ if (apiKey) {
1075
+ if (!llmConfig.api_key)
1076
+ llmConfig.api_key = apiKey;
1077
+ llmProvider = createLLMProvider(llmConfig);
1078
+ }
1079
+ else if (options.warm) {
1080
+ // Explicit --warm with no LLM key: fail fast
1081
+ console.error("Error: --warm requires an LLM API key. Set ANTHROPIC_API_KEY or configure api_key in memkin.yaml.");
1082
+ process.exit(1);
1083
+ }
1084
+ else {
1085
+ // Full run with no LLM: skip warm→cold, run hot only
1086
+ console.warn("Warning: no LLM API key found. Running hot→warm only. " +
1087
+ "Set ANTHROPIC_API_KEY to enable warm→cold consolidation.");
1088
+ }
1089
+ }
1090
+ const consolidator = new Consolidator({
1091
+ pages: stores.pages,
1092
+ graph: stores.graph,
1093
+ tags: stores.tags,
1094
+ timeline: stores.timeline,
1095
+ }, llmProvider, {
1096
+ profile: config.profile,
1097
+ profileStores: {
1098
+ pages: stores.pages,
1099
+ graph: stores.graph,
1100
+ timeline: stores.timeline,
1101
+ behavior: new PersonBehaviorStore(stores.db.executor),
1102
+ },
1103
+ });
1104
+ const mode = options.hot
1105
+ ? "hot"
1106
+ : options.warm
1107
+ ? "warm"
1108
+ : llmProvider
1109
+ ? "all"
1110
+ : "hot"; // fall back to hot-only when full run has no LLM
1111
+ const dryRun = options.dryRun ?? false;
1112
+ if (dryRun)
1113
+ console.log("DRY-RUN mode — no writes will occur\n");
1114
+ const result = await consolidator.runOnce(mode, dryRun);
1115
+ console.log("Consolidation complete:");
1116
+ console.log(` hot→warm pages moved: ${result.hotToWarm}`);
1117
+ console.log(` warm→cold pages archived: ${result.warmToCold}`);
1118
+ console.log(` dead links checked: ${result.deadLinksChecked}`);
1119
+ console.log(` preferences inferred: ${result.preferencesInferred}`);
1120
+ console.log(` profiles synthesized: ${result.profilesSynthesized}`);
1121
+ await stores.db.close();
1122
+ }
1123
+ catch (error) {
1124
+ console.error("Consolidate failed:", error instanceof Error ? error.message : String(error));
1125
+ process.exit(1);
1126
+ }
1127
+ });
1128
+ // ── Person identity (Layer 1: aliases / merge / rename) ────────────────────
1129
+ const HANDLE_KINDS = ["feishu_open_id", "email", "name", "nickname", "slug"];
1130
+ const identityCmd = program
1131
+ .command("identity")
1132
+ .description("Manage person identity: aliases, merge, and rename");
1133
+ identityCmd
1134
+ .command("alias <canonical_slug> <kind> <value>")
1135
+ .description(`Attach an alias/handle to a person. kind: ${HANDLE_KINDS.join(" | ")}`)
1136
+ .option("-c, --config <path>", "Path to config file")
1137
+ .option("--strong", "Force strong strength (auto-resolvable)")
1138
+ .option("--weak", "Force weak strength (explicit-only)")
1139
+ .action(async (canonicalSlug, kind, value, options) => {
1140
+ if (!HANDLE_KINDS.includes(kind)) {
1141
+ console.error(`Error: invalid kind '${kind}'. Expected one of: ${HANDLE_KINDS.join(", ")}`);
1142
+ process.exit(1);
1143
+ }
1144
+ const { db, identity } = await openIdentityStore(loadConfig(options.config));
1145
+ try {
1146
+ const strength = options.strong ? "strong" : options.weak ? "weak" : undefined;
1147
+ await identity.addAlias(canonicalSlug, kind, value, strength);
1148
+ console.log(`Linked ${kind}:${value} → ${canonicalSlug}`);
1149
+ for (const h of await identity.listHandles(canonicalSlug)) {
1150
+ console.log(` ${h.kind}\t${h.value}\t(${h.strength})`);
1151
+ }
1152
+ }
1153
+ catch (error) {
1154
+ console.error("alias failed:", error instanceof Error ? error.message : String(error));
1155
+ process.exit(1);
1156
+ }
1157
+ finally {
1158
+ await db.close();
1159
+ }
1160
+ });
1161
+ identityCmd
1162
+ .command("handles <canonical_slug>")
1163
+ .description("List all handles/aliases attached to a person")
1164
+ .option("-c, --config <path>", "Path to config file")
1165
+ .action(async (canonicalSlug, options) => {
1166
+ const { db, identity } = await openIdentityStore(loadConfig(options.config));
1167
+ try {
1168
+ const handles = await identity.listHandles(canonicalSlug);
1169
+ if (handles.length === 0) {
1170
+ console.log(`No handles for ${canonicalSlug}`);
1171
+ }
1172
+ else {
1173
+ for (const h of handles)
1174
+ console.log(`${h.kind}\t${h.value}\t(${h.strength})`);
1175
+ }
1176
+ }
1177
+ finally {
1178
+ await db.close();
1179
+ }
1180
+ });
1181
+ identityCmd
1182
+ .command("merge <from> <into>")
1183
+ .description("Merge person page <from> into <into> (re-points links/timeline/tags + aliases)")
1184
+ .option("-c, --config <path>", "Path to config file")
1185
+ .action(async (from, into, options) => {
1186
+ const { db, identity } = await openIdentityStore(loadConfig(options.config));
1187
+ try {
1188
+ await identity.merge(from, into);
1189
+ console.log(`Merged ${from} → ${into}`);
1190
+ console.log("Note: run `memkin embed` to re-embed the folded content.");
1191
+ }
1192
+ catch (error) {
1193
+ console.error("merge failed:", error instanceof Error ? error.message : String(error));
1194
+ process.exit(1);
1195
+ }
1196
+ finally {
1197
+ await db.close();
1198
+ }
1199
+ });
1200
+ identityCmd
1201
+ .command("rename <from> <to>")
1202
+ .description("Rename a person's canonical slug (correct a wrong canonicalization)")
1203
+ .option("-c, --config <path>", "Path to config file")
1204
+ .action(async (from, to, options) => {
1205
+ const { db, identity } = await openIdentityStore(loadConfig(options.config));
1206
+ try {
1207
+ await identity.recanonicalize(from, to);
1208
+ console.log(`Renamed ${from} → ${to}`);
1209
+ }
1210
+ catch (error) {
1211
+ console.error("rename failed:", error instanceof Error ? error.message : String(error));
1212
+ process.exit(1);
1213
+ }
1214
+ finally {
1215
+ await db.close();
1216
+ }
1217
+ });
1218
+ const docsCmd = program.command("docs").description("Feishu doc summary cards (DocSource v2)");
1219
+ docsCmd
1220
+ .command("sync")
1221
+ .description("Scan Feishu docs, build pointer cards, upgrade triggered docs to full cards")
1222
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
1223
+ .action(async (options) => {
1224
+ try {
1225
+ const config = loadConfig(options.config);
1226
+ ensureStateDir();
1227
+ const feishu = config.sources.feishu;
1228
+ if (!feishu?.enabled || !feishu.sources?.docs?.enabled) {
1229
+ console.error("Feishu docs source is not enabled in config (sources.feishu.sources.docs.enabled).");
1230
+ process.exit(1);
1231
+ }
1232
+ const stores = await createStores(config);
1233
+ const client = new LarkCliHttpClient(feishu.lark_bin);
1234
+ const docsConfig = normalizeDocsConfig(feishu.sources.docs);
1235
+ // self_open_id: config override else resolve via lark-cli whoami helper used elsewhere
1236
+ const selfOpenId = docsConfig.self_open_id ??
1237
+ (await resolveSelfOpenId(client, feishu.sources?.dm?.self_open_id)) ??
1238
+ "";
1239
+ const llmConfig = { ...config.llm };
1240
+ if (docsConfig.llm.model)
1241
+ llmConfig.model = docsConfig.llm.model;
1242
+ const envKey = llmConfig.provider === "anthropic"
1243
+ ? process.env.ANTHROPIC_API_KEY
1244
+ : process.env.OPENAI_API_KEY;
1245
+ if (!llmConfig.api_key && envKey)
1246
+ llmConfig.api_key = envKey;
1247
+ const provider = llmConfig.api_key
1248
+ ? createLLMProvider(llmConfig)
1249
+ : createMockProvider(new Map());
1250
+ const cursor = new CursorStore(statePath("cursors.yaml"));
1251
+ cursor.load();
1252
+ // Identity layer for canonicalizing action_item owners → person slugs and
1253
+ // detecting self-ownership, so doc/meeting action_items become task signals
1254
+ // the daily report can surface (Spec 9 §3.3).
1255
+ const identity = new PersonIdentityStore(stores.db.executor, { pages: stores.pages }, { behavior: new PersonBehaviorStore(stores.db.executor) });
1256
+ const stats = await runDocSource({
1257
+ client,
1258
+ stores,
1259
+ provider,
1260
+ config: docsConfig,
1261
+ cursor,
1262
+ selfOpenId,
1263
+ nowMs: Date.now(),
1264
+ nowIso: () => new Date().toISOString(),
1265
+ actionItemDeps: {
1266
+ graph: stores.graph,
1267
+ resolveOwner: async (ownerRaw) => {
1268
+ if (!ownerRaw)
1269
+ return null;
1270
+ // best-effort: map a name/@mention to a canonical person slug
1271
+ return ((await identity.resolveHandle("name", ownerRaw)) ??
1272
+ (await identity.resolveHandle("nickname", ownerRaw)) ??
1273
+ null);
1274
+ },
1275
+ isMe: (slug) => identity.isMe(slug),
1276
+ },
1277
+ });
1278
+ console.log(`[docs] scanned=${stats.candidates_scanned} pointer=${stats.pointer_saved} full=${stats.full_card_generated} skipped=${stats.skipped} queue=${stats.upgrade_queue_size} llm_failed=${stats.llm_failed}`);
1279
+ await stores.db.close();
1280
+ }
1281
+ catch (error) {
1282
+ console.error("docs sync failed:", error instanceof Error ? error.message : String(error));
1283
+ process.exit(1);
1284
+ }
1285
+ });
1286
+ docsCmd
1287
+ .command("status")
1288
+ .description("Show Feishu doc card counts")
1289
+ .option("-c, --config <path>", "Path to config file")
1290
+ .option("--failed", "List cards whose last extraction failed")
1291
+ .action(async (options) => {
1292
+ try {
1293
+ const config = loadConfig(options.config);
1294
+ const stores = await createStores(config);
1295
+ const pages = await stores.pages.listPages({ type: "feishu_doc_card", limit: 100000 });
1296
+ if (options.failed) {
1297
+ for (const f of failedCards(pages))
1298
+ console.log(`${f.doc_token}\t${f.error}`);
1299
+ }
1300
+ else {
1301
+ const s = summarizeCards(pages);
1302
+ console.log(`total=${s.total} full=${s.full} pointer=${s.pointer} failed=${s.failed}`);
1303
+ }
1304
+ await stores.db.close();
1305
+ }
1306
+ catch (error) {
1307
+ console.error("docs status failed:", error instanceof Error ? error.message : String(error));
1308
+ process.exit(1);
1309
+ }
1310
+ });
1311
+ docsCmd
1312
+ .command("retry [doc_token]")
1313
+ .description("Retry full-card extraction for a failed doc (or --all-failed)")
1314
+ .option("-c, --config <path>", "Path to config file")
1315
+ .option("--all-failed", "Retry every card with an extract_error")
1316
+ .action(async (docToken, options) => {
1317
+ try {
1318
+ const config = loadConfig(options.config);
1319
+ const feishu = config.sources.feishu;
1320
+ if (!feishu?.sources?.docs?.enabled) {
1321
+ console.error("Feishu docs source not enabled.");
1322
+ process.exit(1);
1323
+ }
1324
+ const stores = await createStores(config);
1325
+ const client = new LarkCliHttpClient(feishu.lark_bin);
1326
+ const docsConfig = normalizeDocsConfig(feishu.sources.docs);
1327
+ const llmConfig = { ...config.llm };
1328
+ if (docsConfig.llm.model)
1329
+ llmConfig.model = docsConfig.llm.model;
1330
+ const envKey = llmConfig.provider === "anthropic"
1331
+ ? process.env.ANTHROPIC_API_KEY
1332
+ : process.env.OPENAI_API_KEY;
1333
+ if (!llmConfig.api_key && envKey)
1334
+ llmConfig.api_key = envKey;
1335
+ const provider = llmConfig.api_key
1336
+ ? createLLMProvider(llmConfig)
1337
+ : createMockProvider(new Map());
1338
+ const builder = new FullCardBuilder(client, provider, docsConfig.llm.model ?? "unknown", () => new Date().toISOString());
1339
+ const tokens = [];
1340
+ if (options.allFailed) {
1341
+ const pages = await stores.pages.listPages({ type: "feishu_doc_card", limit: 100000 });
1342
+ for (const f of failedCards(pages))
1343
+ tokens.push(f.doc_token);
1344
+ }
1345
+ else if (docToken) {
1346
+ tokens.push(docToken);
1347
+ }
1348
+ else {
1349
+ console.error("Provide a doc_token or --all-failed.");
1350
+ process.exit(1);
1351
+ }
1352
+ for (const token of tokens) {
1353
+ const existing = await loadExistingCard(stores, token);
1354
+ if (!existing) {
1355
+ console.warn(`skip ${token}: no existing card`);
1356
+ continue;
1357
+ }
1358
+ // retry intentionally re-evaluates the gate (no force); short/empty docs
1359
+ // stay pointers by design — unlike MCP ingest which forces.
1360
+ const card = await builder.build(existing);
1361
+ await writeCard(stores, card);
1362
+ if (card.extract_level === "pointer") {
1363
+ const reason = card.extract_error ?? card.extract_skipped ?? "unknown";
1364
+ console.log(`${token}: pointer (not upgraded — ${reason})`);
1365
+ }
1366
+ else {
1367
+ console.log(`${token}: full`);
1368
+ }
1369
+ }
1370
+ await stores.db.close();
1371
+ }
1372
+ catch (error) {
1373
+ console.error("docs retry failed:", error instanceof Error ? error.message : String(error));
1374
+ process.exit(1);
1375
+ }
1376
+ });
1377
+ // ---------------------------------------------------------------------------
1378
+ // SP4 — always-on daemon commands
1379
+ // ---------------------------------------------------------------------------
1380
+ program
1381
+ .command("up")
1382
+ .description("Start the always-on Memkin daemon and wire detected AI agents")
1383
+ .option("-c, --config <path>", "Path to config file (default: memkin.yaml)")
1384
+ .option("--port <n>", "Override MCP HTTP port", (v) => {
1385
+ const n = Number.parseInt(v, 10);
1386
+ if (Number.isNaN(n))
1387
+ throw new Error(`--port: invalid number "${v}"`);
1388
+ return n;
1389
+ })
1390
+ .option("--linger", "Enable systemd --linger so the service survives logout (Linux only)")
1391
+ .action(async (options) => {
1392
+ try {
1393
+ const result = await runUp({
1394
+ config: options.config,
1395
+ port: options.port,
1396
+ linger: !!options.linger,
1397
+ });
1398
+ console.log(`✓ Memkin daemon running`);
1399
+ console.log(` URL: ${result.url}`);
1400
+ console.log(` Port: ${result.port}`);
1401
+ console.log(` Engine: ${result.engine}`);
1402
+ if (result.wiredAgents.length > 0) {
1403
+ console.log(` Wired: ${result.wiredAgents.join(", ")}`);
1404
+ }
1405
+ if (result.skippedAgents.length > 0) {
1406
+ for (const s of result.skippedAgents) {
1407
+ console.log(` Skipped: ${s.id} — ${s.reason}`);
1408
+ }
1409
+ }
1410
+ for (const w of result.warnings) {
1411
+ console.log(` ⚠ ${w}`);
1412
+ }
1413
+ }
1414
+ catch (err) {
1415
+ console.error("memkin up failed:", err instanceof Error ? err.message : String(err));
1416
+ process.exit(1);
1417
+ }
1418
+ });
1419
+ program
1420
+ .command("down")
1421
+ .description("Stop the always-on daemon and remove its autostart entry")
1422
+ .action(async () => {
1423
+ const h = homedir();
1424
+ const plat = process.platform;
1425
+ try {
1426
+ // Best-effort config load to detect engine; safe to fail (down works without a config)
1427
+ let engine;
1428
+ try {
1429
+ const cfg = loadConfig();
1430
+ engine = cfg.store.engine;
1431
+ }
1432
+ catch {
1433
+ // no config or parse error — treat engine as unknown (non-managed)
1434
+ }
1435
+ const result = await down({
1436
+ home: h,
1437
+ platform: plat,
1438
+ acquireLock: acquireLifecycleLock,
1439
+ disable: () => disableAutostart({
1440
+ platform: plat,
1441
+ home: h,
1442
+ runner: nodeRunner,
1443
+ keepStateOnBootoutFailure: true,
1444
+ }),
1445
+ engine,
1446
+ stopManagedPg: () => stopManagedFromState(h, nodeRunner).then(() => undefined),
1447
+ });
1448
+ console.log(result.stopped ? `✓ ${result.note}` : `✗ ${result.note}`);
1449
+ }
1450
+ catch (err) {
1451
+ console.error("memkin down failed:", err instanceof Error ? err.message : String(err));
1452
+ process.exit(1);
1453
+ }
1454
+ });
1455
+ program
1456
+ .command("autostart <action>")
1457
+ .description("Manage daemon autostart entry (action: enable | disable | status)")
1458
+ .option("-c, --config <path>", "Path to config file (required for enable)")
1459
+ .option("--port <n>", "Override MCP HTTP port (for enable)", (v) => {
1460
+ const n = Number.parseInt(v, 10);
1461
+ if (Number.isNaN(n))
1462
+ throw new Error(`--port: invalid number "${v}"`);
1463
+ return n;
1464
+ })
1465
+ .action(async (action, options) => {
1466
+ const h = homedir();
1467
+ const plat = process.platform;
1468
+ try {
1469
+ if (action === "enable") {
1470
+ // Delegate fully to runUp which handles all the state-building
1471
+ await runUp({
1472
+ config: options.config,
1473
+ port: options.port,
1474
+ });
1475
+ console.log("✓ Autostart enabled.");
1476
+ }
1477
+ else if (action === "disable") {
1478
+ const res = await disableAutostart({ platform: plat, home: h, runner: nodeRunner });
1479
+ if (res.launcherCode && res.launcherCode !== 0) {
1480
+ console.warn(`Launcher returned non-zero (${res.launcherCode}): ${res.launcherStderr ?? ""}`);
1481
+ }
1482
+ console.log("✓ Autostart disabled.");
1483
+ }
1484
+ else if (action === "status") {
1485
+ const st = await statusAutostart({ platform: plat, home: h, runner: nodeRunner });
1486
+ console.log("Desired state:", st.desired ? JSON.stringify(st.desired, null, 2) : "(none)");
1487
+ console.log(`Launcher output:\n${st.raw}`);
1488
+ }
1489
+ else {
1490
+ console.error(`Unknown autostart action "${action}". Use: enable | disable | status`);
1491
+ process.exit(1);
1492
+ }
1493
+ }
1494
+ catch (err) {
1495
+ console.error(`memkin autostart ${action} failed:`, err instanceof Error ? err.message : String(err));
1496
+ process.exit(1);
1497
+ }
1498
+ });
1499
+ program
1500
+ .command("status")
1501
+ .description("Show the current state of the always-on daemon")
1502
+ .action(async () => {
1503
+ const h = homedir();
1504
+ const stateDir = join(h, ".memkin");
1505
+ const stored = readDaemonState(stateDir);
1506
+ let health = null;
1507
+ if (stored?.url) {
1508
+ try {
1509
+ const healthUrl = stored.url.replace(/\/mcp$/, "/health");
1510
+ const r = await fetch(healthUrl);
1511
+ health = {
1512
+ status: r.status,
1513
+ body: (await r.json().catch(() => ({}))),
1514
+ };
1515
+ }
1516
+ catch {
1517
+ health = null;
1518
+ }
1519
+ }
1520
+ let currentRawHash = null;
1521
+ let currentServingHash = null;
1522
+ if (stored?.config_path) {
1523
+ try {
1524
+ currentRawHash = rawYamlHash(stored.config_path);
1525
+ const cfg = loadConfig(stored.config_path);
1526
+ const rt = resolveMcpHttpRuntime(cfg.mcp.http, {});
1527
+ currentServingHash = servingSubsetHash({
1528
+ bind: rt.bind,
1529
+ port: rt.port,
1530
+ readOnly: rt.readOnly,
1531
+ hosts: rt.allowedHosts,
1532
+ });
1533
+ }
1534
+ catch {
1535
+ // config unreadable
1536
+ }
1537
+ }
1538
+ const report = computeStatus({ stored, currentRawHash, currentServingHash, health });
1539
+ console.log(`Status: ${report.running ? "running ✓" : "stopped ✗"}`);
1540
+ if (report.url)
1541
+ console.log(`URL: ${report.url}`);
1542
+ if (report.pid)
1543
+ console.log(`PID: ${report.pid}`);
1544
+ if (report.engine)
1545
+ console.log(`Engine: ${report.engine}`);
1546
+ if (report.configPath)
1547
+ console.log(`Config: ${report.configPath}`);
1548
+ if (report.drift.configChanged)
1549
+ console.log("⚠ Config changed since last up — run `memkin up` to apply.");
1550
+ if (report.drift.needsReup)
1551
+ console.log("⚠ Serving subset changed — run `memkin up` to re-register agents.");
1552
+ if (report.drift.restartedOntoEditedConfig)
1553
+ console.log("⚠ Daemon restarted onto edited config.");
1554
+ // Show managed Postgres state when engine is managed
1555
+ const managedState = readManagedState(managedPaths(h, "17"));
1556
+ if (managedState) {
1557
+ // Lightweight pg_ctl status probe — run if pg_ctl is available
1558
+ let clusterRunning = null;
1559
+ try {
1560
+ const { spawnSync } = await import("node:child_process");
1561
+ const result = spawnSync(managedState.pgCtlPath, ["status", "-D", managedState.pgdata], {
1562
+ encoding: "utf8",
1563
+ timeout: 3000,
1564
+ });
1565
+ // pg_ctl status exits 0 if running, non-zero if stopped/no data dir
1566
+ clusterRunning = result.status === 0;
1567
+ }
1568
+ catch {
1569
+ clusterRunning = null;
1570
+ }
1571
+ const managedLines = formatManagedStatus(managedState, clusterRunning);
1572
+ console.log("");
1573
+ for (const line of managedLines) {
1574
+ console.log(`${line.label}: ${line.value}`);
1575
+ }
1576
+ }
1577
+ });
1578
+ program.parse(process.argv);
1579
+ //# sourceMappingURL=cli.js.map