mirror-mind 0.0.1 → 0.33.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 (474) hide show
  1. package/.claude/hooks/log-assistant-reply.sh +85 -0
  2. package/.claude/hooks/log-session-end.sh +85 -0
  3. package/.claude/hooks/log-user-prompt.sh +85 -0
  4. package/.claude/hooks/mirror-inject.sh +85 -0
  5. package/.claude/hooks/session-start.sh +85 -0
  6. package/.gemini/hooks/log-assistant.sh +85 -0
  7. package/.gemini/hooks/log-user.sh +85 -0
  8. package/.gemini/hooks/session-end.sh +85 -0
  9. package/.gemini/hooks/session-start.sh +85 -0
  10. package/.pi/extensions/mirror-logger.ts +646 -0
  11. package/.pi/skills/mm-backup/SKILL.md +21 -0
  12. package/.pi/skills/mm-build/SKILL.md +1206 -0
  13. package/.pi/skills/mm-consolidate/SKILL.md +112 -0
  14. package/.pi/skills/mm-consult/SKILL.md +70 -0
  15. package/.pi/skills/mm-conversations/SKILL.md +16 -0
  16. package/.pi/skills/mm-discard/SKILL.md +39 -0
  17. package/.pi/skills/mm-explore/SKILL.md +255 -0
  18. package/.pi/skills/mm-help/SKILL.md +74 -0
  19. package/.pi/skills/mm-identity/SKILL.md +96 -0
  20. package/.pi/skills/mm-journal/SKILL.md +16 -0
  21. package/.pi/skills/mm-journey/SKILL.md +23 -0
  22. package/.pi/skills/mm-journeys/SKILL.md +15 -0
  23. package/.pi/skills/mm-memories/SKILL.md +17 -0
  24. package/.pi/skills/mm-mirror/SKILL.md +98 -0
  25. package/.pi/skills/mm-mute/SKILL.md +18 -0
  26. package/.pi/skills/mm-new/SKILL.md +18 -0
  27. package/.pi/skills/mm-recall/SKILL.md +17 -0
  28. package/.pi/skills/mm-release-notes/SKILL.md +52 -0
  29. package/.pi/skills/mm-seed/SKILL.md +19 -0
  30. package/.pi/skills/mm-shadow/SKILL.md +117 -0
  31. package/.pi/skills/mm-soul/SKILL.md +502 -0
  32. package/.pi/skills/mm-tasks/SKILL.md +24 -0
  33. package/.pi/skills/mm-update/SKILL.md +32 -0
  34. package/.pi/skills/mm-week/SKILL.md +28 -0
  35. package/.pi/skills/mm-welcome/SKILL.md +24 -0
  36. package/AGENTS.md +188 -0
  37. package/README.md +126 -9
  38. package/bin/loader.js +67 -0
  39. package/bin/mirror-hook.js +7 -0
  40. package/bin/mirror.js +7 -0
  41. package/docs/releases/index.md +100 -0
  42. package/docs/releases/pending-cutoffs.md +510 -0
  43. package/docs/releases/v0.10.0.md +123 -0
  44. package/docs/releases/v0.10.1.md +66 -0
  45. package/docs/releases/v0.10.10.md +51 -0
  46. package/docs/releases/v0.10.11.md +39 -0
  47. package/docs/releases/v0.10.12.md +57 -0
  48. package/docs/releases/v0.10.13.md +35 -0
  49. package/docs/releases/v0.10.14.md +42 -0
  50. package/docs/releases/v0.10.15.md +53 -0
  51. package/docs/releases/v0.10.16.md +35 -0
  52. package/docs/releases/v0.10.17.md +43 -0
  53. package/docs/releases/v0.10.2.md +64 -0
  54. package/docs/releases/v0.10.3.md +78 -0
  55. package/docs/releases/v0.10.4.md +42 -0
  56. package/docs/releases/v0.10.5.md +57 -0
  57. package/docs/releases/v0.10.6.md +47 -0
  58. package/docs/releases/v0.10.7.md +53 -0
  59. package/docs/releases/v0.10.8.md +49 -0
  60. package/docs/releases/v0.10.9.md +37 -0
  61. package/docs/releases/v0.11.0.md +86 -0
  62. package/docs/releases/v0.12.0.md +67 -0
  63. package/docs/releases/v0.13.0.md +64 -0
  64. package/docs/releases/v0.14.0.md +68 -0
  65. package/docs/releases/v0.15.0.md +48 -0
  66. package/docs/releases/v0.16.0.md +50 -0
  67. package/docs/releases/v0.16.1.md +55 -0
  68. package/docs/releases/v0.16.2.md +36 -0
  69. package/docs/releases/v0.17.0.md +50 -0
  70. package/docs/releases/v0.17.1.md +58 -0
  71. package/docs/releases/v0.17.2.md +42 -0
  72. package/docs/releases/v0.17.3.md +58 -0
  73. package/docs/releases/v0.18.0.md +84 -0
  74. package/docs/releases/v0.18.1.md +51 -0
  75. package/docs/releases/v0.18.2.md +69 -0
  76. package/docs/releases/v0.19.0.md +85 -0
  77. package/docs/releases/v0.19.1.md +46 -0
  78. package/docs/releases/v0.20.0.md +85 -0
  79. package/docs/releases/v0.21.0.md +61 -0
  80. package/docs/releases/v0.21.1.md +47 -0
  81. package/docs/releases/v0.22.0.md +77 -0
  82. package/docs/releases/v0.22.1.md +42 -0
  83. package/docs/releases/v0.23.0.md +105 -0
  84. package/docs/releases/v0.24.0.md +125 -0
  85. package/docs/releases/v0.25.0.md +107 -0
  86. package/docs/releases/v0.26.0.md +139 -0
  87. package/docs/releases/v0.26.1.md +65 -0
  88. package/docs/releases/v0.26.2.md +43 -0
  89. package/docs/releases/v0.27.0.md +63 -0
  90. package/docs/releases/v0.28.0.md +59 -0
  91. package/docs/releases/v0.29.0.md +61 -0
  92. package/docs/releases/v0.29.1.md +59 -0
  93. package/docs/releases/v0.29.2.md +59 -0
  94. package/docs/releases/v0.29.3.md +93 -0
  95. package/docs/releases/v0.30.0.md +75 -0
  96. package/docs/releases/v0.30.1.md +93 -0
  97. package/docs/releases/v0.30.2.md +66 -0
  98. package/docs/releases/v0.31.0.md +122 -0
  99. package/docs/releases/v0.31.1.md +142 -0
  100. package/docs/releases/v0.31.10.md +118 -0
  101. package/docs/releases/v0.31.11.md +88 -0
  102. package/docs/releases/v0.31.12.md +105 -0
  103. package/docs/releases/v0.31.13.md +99 -0
  104. package/docs/releases/v0.31.14.md +97 -0
  105. package/docs/releases/v0.31.2.md +115 -0
  106. package/docs/releases/v0.31.3.md +142 -0
  107. package/docs/releases/v0.31.4.md +117 -0
  108. package/docs/releases/v0.31.5.md +155 -0
  109. package/docs/releases/v0.31.6.md +132 -0
  110. package/docs/releases/v0.31.7.md +132 -0
  111. package/docs/releases/v0.31.8.md +120 -0
  112. package/docs/releases/v0.31.9.md +120 -0
  113. package/docs/releases/v0.32.0.md +261 -0
  114. package/docs/releases/v0.32.1.md +59 -0
  115. package/docs/releases/v0.33.0.md +164 -0
  116. package/docs/releases/v0.8.0.md +118 -0
  117. package/docs/releases/v0.9.0.md +98 -0
  118. package/docs/releases/v0.9.1.md +83 -0
  119. package/package.json +102 -6
  120. package/plugins/mirror-mind/.claude-plugin/plugin.json +17 -0
  121. package/plugins/mirror-mind/hooks/hooks.json +62 -0
  122. package/plugins/mirror-mind/hooks/log-assistant-reply.sh +98 -0
  123. package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
  124. package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
  125. package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
  126. package/plugins/mirror-mind/hooks/session-start.sh +98 -0
  127. package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
  128. package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
  129. package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
  130. package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
  131. package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
  132. package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
  133. package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
  134. package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
  135. package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
  136. package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
  137. package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
  138. package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
  139. package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
  140. package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +67 -0
  141. package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
  142. package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
  143. package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
  144. package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
  145. package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
  146. package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
  147. package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
  148. package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
  149. package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
  150. package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
  151. package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
  152. package/scripts/codex-hooks/session-end.sh +85 -0
  153. package/scripts/codex-hooks/session-start.sh +85 -0
  154. package/scripts/codex-mirror.sh +48 -0
  155. package/templates/identity/README.md +119 -0
  156. package/templates/identity/ego/behavior.yaml +52 -0
  157. package/templates/identity/ego/constraints.yaml +15 -0
  158. package/templates/identity/ego/identity.yaml +43 -0
  159. package/templates/identity/journeys/personal-growth.yaml +39 -0
  160. package/templates/identity/organization/identity.yaml +24 -0
  161. package/templates/identity/organization/principles.yaml +17 -0
  162. package/templates/identity/personas/coach.yaml +94 -0
  163. package/templates/identity/personas/designer.yaml +93 -0
  164. package/templates/identity/personas/doctor.yaml +96 -0
  165. package/templates/identity/personas/engineer.yaml +77 -0
  166. package/templates/identity/personas/financial.yaml +97 -0
  167. package/templates/identity/personas/prompt-engineer.yaml +122 -0
  168. package/templates/identity/personas/researcher.yaml +88 -0
  169. package/templates/identity/personas/strategist.yaml +91 -0
  170. package/templates/identity/personas/teacher.yaml +95 -0
  171. package/templates/identity/personas/therapist.yaml +91 -0
  172. package/templates/identity/personas/thinker.yaml +74 -0
  173. package/templates/identity/personas/writer.yaml +76 -0
  174. package/templates/identity/self/config.yaml +16 -0
  175. package/templates/identity/self/soul.yaml +105 -0
  176. package/templates/identity/user/identity.yaml +30 -0
  177. package/ts/src/backup/staging.ts +62 -0
  178. package/ts/src/backup/zipBackup.ts +267 -0
  179. package/ts/src/backup/zipReader.ts +109 -0
  180. package/ts/src/backup/zipWriter.ts +148 -0
  181. package/ts/src/builder/activeCheckpoint.ts +134 -0
  182. package/ts/src/builder/aggregateStatus.ts +34 -0
  183. package/ts/src/builder/approve.ts +149 -0
  184. package/ts/src/builder/argv.ts +292 -0
  185. package/ts/src/builder/ariadMethod.ts +536 -0
  186. package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
  187. package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
  188. package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
  189. package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
  190. package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
  191. package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
  192. package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
  193. package/ts/src/builder/artifacts/storyFiles.ts +61 -0
  194. package/ts/src/builder/artifacts/storyIndex.ts +166 -0
  195. package/ts/src/builder/cadence.ts +59 -0
  196. package/ts/src/builder/card.ts +192 -0
  197. package/ts/src/builder/checkpointRefused.ts +66 -0
  198. package/ts/src/builder/closure.ts +964 -0
  199. package/ts/src/builder/commands.ts +2053 -0
  200. package/ts/src/builder/cursorPosition.ts +176 -0
  201. package/ts/src/builder/cursorTransitions.ts +77 -0
  202. package/ts/src/builder/deliveryCursor.ts +577 -0
  203. package/ts/src/builder/deliveryStoryClosure.ts +521 -0
  204. package/ts/src/builder/deliveryStoryPlan.ts +536 -0
  205. package/ts/src/builder/deliveryStoryReady.ts +160 -0
  206. package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
  207. package/ts/src/builder/expand.ts +336 -0
  208. package/ts/src/builder/flowUnit.ts +339 -0
  209. package/ts/src/builder/homeSurface.ts +122 -0
  210. package/ts/src/builder/implementationGuard.ts +125 -0
  211. package/ts/src/builder/index.ts +11 -0
  212. package/ts/src/builder/lifecycleRefusal.ts +92 -0
  213. package/ts/src/builder/lifecycleRibbon.ts +159 -0
  214. package/ts/src/builder/load.ts +313 -0
  215. package/ts/src/builder/methodAdoption.ts +113 -0
  216. package/ts/src/builder/methodDefinition.ts +429 -0
  217. package/ts/src/builder/methodInspection.ts +371 -0
  218. package/ts/src/builder/plan.ts +408 -0
  219. package/ts/src/builder/planPreauthorization.ts +265 -0
  220. package/ts/src/builder/prepare.ts +225 -0
  221. package/ts/src/builder/projectPaths.ts +64 -0
  222. package/ts/src/builder/pull.ts +356 -0
  223. package/ts/src/builder/pullCandidates.ts +463 -0
  224. package/ts/src/builder/pullCandidatesRender.ts +238 -0
  225. package/ts/src/builder/refinementField.ts +93 -0
  226. package/ts/src/builder/releaseIntent.ts +173 -0
  227. package/ts/src/builder/resumeState.ts +84 -0
  228. package/ts/src/builder/resumeSurface.ts +149 -0
  229. package/ts/src/builder/roadmapGrammar.ts +300 -0
  230. package/ts/src/builder/roadmapScan.ts +97 -0
  231. package/ts/src/builder/roadmapScope.ts +210 -0
  232. package/ts/src/builder/scopePhrases.ts +146 -0
  233. package/ts/src/builder/storyPaths.ts +196 -0
  234. package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
  235. package/ts/src/builder/surfaceProtocol.ts +42 -0
  236. package/ts/src/builder/templateGeneration.ts +148 -0
  237. package/ts/src/builder/transition.ts +178 -0
  238. package/ts/src/consult/args.ts +99 -0
  239. package/ts/src/consult/core.ts +122 -0
  240. package/ts/src/consult/modelCatalog.ts +55 -0
  241. package/ts/src/consult/render.ts +47 -0
  242. package/ts/src/conversation/append.ts +414 -0
  243. package/ts/src/conversation/backfill.ts +387 -0
  244. package/ts/src/conversation/closeTail.ts +467 -0
  245. package/ts/src/conversation/extraction.ts +333 -0
  246. package/ts/src/conversation/extractionDriver.ts +130 -0
  247. package/ts/src/conversation/extractionRun.ts +70 -0
  248. package/ts/src/conversation/hookPayload.ts +51 -0
  249. package/ts/src/conversation/journeyInference.ts +165 -0
  250. package/ts/src/conversation/journeyRepair.ts +114 -0
  251. package/ts/src/conversation/lifecycleFaces.ts +197 -0
  252. package/ts/src/conversation/lifecycleWrites.ts +313 -0
  253. package/ts/src/conversation/listing.ts +77 -0
  254. package/ts/src/conversation/logger.ts +851 -0
  255. package/ts/src/conversation/loggerCli.ts +321 -0
  256. package/ts/src/conversation/loggerRuntime.ts +259 -0
  257. package/ts/src/conversation/metadataLifecycle.ts +443 -0
  258. package/ts/src/conversation/recall.ts +66 -0
  259. package/ts/src/conversation/sessionComposites.ts +258 -0
  260. package/ts/src/conversation/sessionImport.ts +90 -0
  261. package/ts/src/conversation/transcriptBackfill.ts +141 -0
  262. package/ts/src/cultivation/applyActions.ts +241 -0
  263. package/ts/src/cultivation/cluster.ts +86 -0
  264. package/ts/src/cultivation/consolidationStore.ts +281 -0
  265. package/ts/src/cultivation/promptContext.ts +62 -0
  266. package/ts/src/cultivation/propose.ts +305 -0
  267. package/ts/src/cultivation/scan.ts +155 -0
  268. package/ts/src/db/backupGate.ts +47 -0
  269. package/ts/src/db/bootstrap.ts +108 -0
  270. package/ts/src/db/bootstrapLock.ts +223 -0
  271. package/ts/src/db/copyGuard.ts +60 -0
  272. package/ts/src/db/database.ts +397 -0
  273. package/ts/src/db/decode.ts +66 -0
  274. package/ts/src/db/ftsIntegrity.ts +41 -0
  275. package/ts/src/db/migrateOnOpen.ts +214 -0
  276. package/ts/src/db/migrations.ts +576 -0
  277. package/ts/src/db/readyOnOpen.ts +35 -0
  278. package/ts/src/db/rowDecode.ts +42 -0
  279. package/ts/src/db/schema.ts +432 -0
  280. package/ts/src/db/schemaInventory.ts +225 -0
  281. package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
  282. package/ts/src/db/schemaState.ts +91 -0
  283. package/ts/src/db/schemaTsDivergence.ts +114 -0
  284. package/ts/src/descriptor/descriptorRead.ts +49 -0
  285. package/ts/src/docs/docsLint.ts +265 -0
  286. package/ts/src/explorer/handoff.ts +522 -0
  287. package/ts/src/explorer/render.ts +335 -0
  288. package/ts/src/explorer/story.ts +769 -0
  289. package/ts/src/explorer/transition.ts +72 -0
  290. package/ts/src/extensions/bindings.ts +170 -0
  291. package/ts/src/extensions/catalog.ts +249 -0
  292. package/ts/src/extensions/catalogCommands.ts +513 -0
  293. package/ts/src/extensions/catalogWrites.ts +652 -0
  294. package/ts/src/extensions/contextRuntime.ts +325 -0
  295. package/ts/src/extensions/dispatch.ts +374 -0
  296. package/ts/src/extensions/errors.ts +24 -0
  297. package/ts/src/extensions/manifest.ts +356 -0
  298. package/ts/src/extensions/migrations.ts +350 -0
  299. package/ts/src/extraction/conversation.ts +304 -0
  300. package/ts/src/extraction/conversationMetadata.ts +206 -0
  301. package/ts/src/extraction/fencing.ts +106 -0
  302. package/ts/src/extraction/json.ts +17 -0
  303. package/ts/src/extraction/prompts.ts +470 -0
  304. package/ts/src/frontDoor/args.ts +30 -0
  305. package/ts/src/frontDoor/argvShape.ts +106 -0
  306. package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
  307. package/ts/src/frontDoor/buildRoute.ts +398 -0
  308. package/ts/src/frontDoor/cli.ts +1872 -0
  309. package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
  310. package/ts/src/frontDoor/consultRoute.ts +50 -0
  311. package/ts/src/frontDoor/contentTailRoute.ts +239 -0
  312. package/ts/src/frontDoor/conversationLoggerRoute.ts +83 -0
  313. package/ts/src/frontDoor/cultivationRoute.ts +210 -0
  314. package/ts/src/frontDoor/dbPath.ts +131 -0
  315. package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
  316. package/ts/src/frontDoor/exploreRoute.ts +572 -0
  317. package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
  318. package/ts/src/frontDoor/frontDoorLog.ts +57 -0
  319. package/ts/src/frontDoor/identityWrite.ts +36 -0
  320. package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
  321. package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
  322. package/ts/src/frontDoor/liveBackup.ts +100 -0
  323. package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
  324. package/ts/src/frontDoor/namedRefusal.ts +35 -0
  325. package/ts/src/frontDoor/nodeSupport.ts +24 -0
  326. package/ts/src/frontDoor/render/consolidate.ts +199 -0
  327. package/ts/src/frontDoor/render/conversations.ts +33 -0
  328. package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
  329. package/ts/src/frontDoor/render/descriptor.ts +20 -0
  330. package/ts/src/frontDoor/render/detectPersona.ts +50 -0
  331. package/ts/src/frontDoor/render/icons.ts +13 -0
  332. package/ts/src/frontDoor/render/identity.ts +59 -0
  333. package/ts/src/frontDoor/render/identityRows.ts +17 -0
  334. package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
  335. package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
  336. package/ts/src/frontDoor/render/journeys.ts +79 -0
  337. package/ts/src/frontDoor/render/list.ts +41 -0
  338. package/ts/src/frontDoor/render/memories.ts +67 -0
  339. package/ts/src/frontDoor/render/recall.ts +49 -0
  340. package/ts/src/frontDoor/render/shadow.ts +155 -0
  341. package/ts/src/frontDoor/render/tasks.ts +99 -0
  342. package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
  343. package/ts/src/frontDoor/render/week.ts +113 -0
  344. package/ts/src/frontDoor/routing.ts +1001 -0
  345. package/ts/src/frontDoor/runtimeRoute.ts +623 -0
  346. package/ts/src/frontDoor/searchRoute.ts +166 -0
  347. package/ts/src/frontDoor/seedPaths.ts +98 -0
  348. package/ts/src/frontDoor/sessionStartWelcomeRoute.ts +166 -0
  349. package/ts/src/frontDoor/soulRoute.ts +433 -0
  350. package/ts/src/frontDoor/stdinSource.ts +37 -0
  351. package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
  352. package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
  353. package/ts/src/frontDoor/usage.ts +176 -0
  354. package/ts/src/guards/claudePlugin.ts +298 -0
  355. package/ts/src/guards/packContents.ts +306 -0
  356. package/ts/src/guards/piSourcedSkills.ts +70 -0
  357. package/ts/src/guards/retiredRouteShadows.ts +57 -0
  358. package/ts/src/guards/retiredSurfaces.ts +564 -0
  359. package/ts/src/hooks/claude.ts +214 -0
  360. package/ts/src/hooks/codex.ts +45 -0
  361. package/ts/src/hooks/gemini.ts +126 -0
  362. package/ts/src/hooks/main.ts +109 -0
  363. package/ts/src/hooks/mirrorState.ts +71 -0
  364. package/ts/src/hooks/payload.ts +73 -0
  365. package/ts/src/hooks/runtime.ts +179 -0
  366. package/ts/src/hooks/runtimeDetection.ts +34 -0
  367. package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
  368. package/ts/src/identity/descriptorGenerate.ts +162 -0
  369. package/ts/src/identity/identityEdit.ts +143 -0
  370. package/ts/src/identity/identityKey.ts +77 -0
  371. package/ts/src/identity/identityRead.ts +69 -0
  372. package/ts/src/identity/identityStore.ts +80 -0
  373. package/ts/src/identity/journeyListing.ts +53 -0
  374. package/ts/src/identity/personaInspect.ts +44 -0
  375. package/ts/src/identity/personaListing.ts +37 -0
  376. package/ts/src/identity/setIdentity.ts +64 -0
  377. package/ts/src/index.ts +231 -0
  378. package/ts/src/init/init.ts +111 -0
  379. package/ts/src/journey/journeyOptions.ts +131 -0
  380. package/ts/src/journey/journeyRemoval.ts +158 -0
  381. package/ts/src/journey/journeyStatus.ts +149 -0
  382. package/ts/src/journey/journeySyncFile.ts +87 -0
  383. package/ts/src/journey/journeyWrite.ts +203 -0
  384. package/ts/src/journey/parentJourney.ts +41 -0
  385. package/ts/src/journey/validateParentJourney.ts +55 -0
  386. package/ts/src/mcp/boundary.ts +151 -0
  387. package/ts/src/mcp/guards.ts +244 -0
  388. package/ts/src/mcp/main.ts +121 -0
  389. package/ts/src/mcp/payload.ts +141 -0
  390. package/ts/src/mcp/protocol.ts +141 -0
  391. package/ts/src/mcp/readModels.ts +241 -0
  392. package/ts/src/mcp/registry.ts +201 -0
  393. package/ts/src/mcp/serve.ts +120 -0
  394. package/ts/src/mcp/tools/deterministic.ts +137 -0
  395. package/ts/src/mcp/tools/providerCrossing.ts +187 -0
  396. package/ts/src/mcp/wire.ts +8 -0
  397. package/ts/src/memory/journal.ts +180 -0
  398. package/ts/src/memory/listing.ts +107 -0
  399. package/ts/src/memory/memoryWrite.ts +88 -0
  400. package/ts/src/memory/reinforcement.ts +35 -0
  401. package/ts/src/mirror/context.ts +161 -0
  402. package/ts/src/mirror/defaultResolution.ts +199 -0
  403. package/ts/src/mirror/mirrorForm.ts +43 -0
  404. package/ts/src/mirror/orchestration.ts +364 -0
  405. package/ts/src/mirror/reception.ts +194 -0
  406. package/ts/src/mirror/render.ts +75 -0
  407. package/ts/src/mirror/runtimeSession.ts +205 -0
  408. package/ts/src/mode/operatingMode.ts +148 -0
  409. package/ts/src/observability/callOutcome.ts +115 -0
  410. package/ts/src/observability/inspectLedger.ts +329 -0
  411. package/ts/src/observability/ledgerHooks.ts +126 -0
  412. package/ts/src/observability/llmCalls.ts +154 -0
  413. package/ts/src/persona/detectPersona.ts +81 -0
  414. package/ts/src/planning/promptAssembly.ts +111 -0
  415. package/ts/src/planning/weekPending.ts +81 -0
  416. package/ts/src/planning/weekPlan.ts +183 -0
  417. package/ts/src/planning/weekSave.ts +117 -0
  418. package/ts/src/providers/config.ts +189 -0
  419. package/ts/src/providers/cost.ts +64 -0
  420. package/ts/src/providers/credits.ts +204 -0
  421. package/ts/src/providers/embedding.ts +321 -0
  422. package/ts/src/providers/familyProviders.ts +147 -0
  423. package/ts/src/providers/llm.ts +334 -0
  424. package/ts/src/providers/openrouter.ts +244 -0
  425. package/ts/src/providers/redaction.ts +110 -0
  426. package/ts/src/providers/replay.ts +15 -0
  427. package/ts/src/providers/transport.ts +410 -0
  428. package/ts/src/repair/encodingRepair.ts +253 -0
  429. package/ts/src/runtime/backup.ts +151 -0
  430. package/ts/src/runtime/channel.ts +146 -0
  431. package/ts/src/runtime/config.ts +168 -0
  432. package/ts/src/runtime/diagnose.ts +686 -0
  433. package/ts/src/runtime/git.ts +510 -0
  434. package/ts/src/runtime/installKind.ts +220 -0
  435. package/ts/src/runtime/migrate.ts +154 -0
  436. package/ts/src/runtime/packageIdentity.ts +102 -0
  437. package/ts/src/runtime/releaseNotes.ts +244 -0
  438. package/ts/src/runtime/status.ts +557 -0
  439. package/ts/src/runtime/strategies/clone.ts +200 -0
  440. package/ts/src/runtime/strategies/package.ts +328 -0
  441. package/ts/src/runtime/treeRoot.ts +30 -0
  442. package/ts/src/runtime/update.ts +445 -0
  443. package/ts/src/runtime/updateGate.ts +40 -0
  444. package/ts/src/runtime/updatePipeline.ts +159 -0
  445. package/ts/src/runtime/version.ts +36 -0
  446. package/ts/src/runtime/wiring.ts +130 -0
  447. package/ts/src/search/memorySearch.ts +338 -0
  448. package/ts/src/search/ranker.ts +154 -0
  449. package/ts/src/seed/seed.ts +256 -0
  450. package/ts/src/seed/seedYaml.ts +133 -0
  451. package/ts/src/soul/apply.ts +218 -0
  452. package/ts/src/soul/harvest.ts +267 -0
  453. package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
  454. package/ts/src/soul/prompts/soul_self_voice.md +219 -0
  455. package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
  456. package/ts/src/soul/prompts.ts +85 -0
  457. package/ts/src/soul/render.ts +358 -0
  458. package/ts/src/soul/state.ts +212 -0
  459. package/ts/src/soul/transition.ts +37 -0
  460. package/ts/src/tasks/journeyPathParse.ts +113 -0
  461. package/ts/src/tasks/taskImportSync.ts +142 -0
  462. package/ts/src/tasks/taskStore.ts +312 -0
  463. package/ts/src/tasks/weekView.ts +120 -0
  464. package/ts/src/util/clipCodePoints.ts +26 -0
  465. package/ts/src/util/paths.ts +63 -0
  466. package/ts/src/util/program.ts +9 -0
  467. package/ts/src/util/pyGenerators.ts +144 -0
  468. package/ts/src/util/pythonText.ts +317 -0
  469. package/ts/src/util/semver.ts +45 -0
  470. package/ts/src/util/shellWord.ts +25 -0
  471. package/ts/src/util/slug.ts +64 -0
  472. package/ts/src/welcome/card.ts +339 -0
  473. package/ts/src/welcome/statusLine.ts +101 -0
  474. package/ts/src/welcome/updateCache.ts +129 -0
@@ -0,0 +1,241 @@
1
+ // Deterministic + Slice B `consolidate`/`shadow` apply/reject actions
2
+ // (CV22.DS7.US3).
3
+ //
4
+ // Ports `cli/consolidate_cmd.py:cmd_apply`/`cmd_reject` and
5
+ // `cli/shadow_cmd.py:cmd_apply`/`cmd_reject`, including the `merge` action
6
+ // (which needs a fresh embedding -- Slice B, gated on the caller supplying a
7
+ // replay/live `EmbeddingProvider`; see `propose.ts` for the sibling `scan`
8
+ // orchestration). Each action is its own small, individually-tested function
9
+ // behind the front door's dispatch, not one branching mega-handler.
10
+ //
11
+ // Security posture: `identity_update` reaches an identity write ONLY through
12
+ // `applyConsolidationIdentityUpdate` (the self/ego allowlist gate, AI-23) --
13
+ // never the ungated `upsertIdentity`/`setIdentity`. `shadow apply`'s safety is
14
+ // the HARDCODED constant `layer: "shadow"`; only the *key* is model-influenced,
15
+ // and the port must never let the proposal drive the layer.
16
+
17
+ import type { WritableDatabase } from "#db/database.ts";
18
+ import { embeddingToBytes } from "#db/decode.ts";
19
+ import { applyConsolidationIdentityUpdate } from "#identity/applyConsolidationIdentityUpdate.ts";
20
+ import { getIdentityContent } from "#identity/identityRead.ts";
21
+ import { upsertIdentity } from "#identity/identityStore.ts";
22
+ import { createMemoryRow, getMemorySourceForMerge } from "#memory/memoryWrite.ts";
23
+ import {
24
+ addEmbeddingProvenance,
25
+ type EmbeddingAttemptInfo,
26
+ type EmbeddingProvider,
27
+ generateEmbeddingSafely,
28
+ } from "#providers/embedding.ts";
29
+ import {
30
+ type ConsolidationRow,
31
+ updateConsolidationStatus,
32
+ updateMemoryReadinessState,
33
+ } from "./consolidationStore.ts";
34
+
35
+ function sourceMemoryIds(consolidation: ConsolidationRow): string[] {
36
+ return JSON.parse(consolidation.source_memory_ids) as string[];
37
+ }
38
+
39
+ // --- Reject (shared by both families) ----------------------------------------
40
+
41
+ /**
42
+ * Port of `consolidate reject` / `shadow reject`: `status -> 'rejected'`, no
43
+ * source-memory or identity mutation at all. Both CLIs are byte-identical
44
+ * here, so one function serves both front-door commands.
45
+ */
46
+ export function rejectConsolidation(db: WritableDatabase, id: string, nowIso: string): void {
47
+ updateConsolidationStatus(db, id, "rejected", null, nowIso);
48
+ }
49
+
50
+ // --- consolidate apply: identity_update --------------------------------------
51
+
52
+ export type IdentityUpdateOutcome =
53
+ | { kind: "applied"; targetLayer: string; targetKey: string; sourceMemoryIds: string[] }
54
+ | { kind: "missing_target" }
55
+ | { kind: "refused"; message: string };
56
+
57
+ /**
58
+ * `consolidate apply` for `action = 'identity_update'`. Routes the write
59
+ * exclusively through `applyConsolidationIdentityUpdate` (the allowlist gate)
60
+ * -- there is no other reachable path to an identity write from this
61
+ * function. A refused layer writes NOTHING: no identity row, no readiness
62
+ * advance, no consolidation status change (mirrors Python's `sys.exit(1)`
63
+ * before any of those side effects run).
64
+ */
65
+ export function applyIdentityUpdate(
66
+ db: WritableDatabase,
67
+ consolidation: ConsolidationRow,
68
+ resultContent: string,
69
+ ids: { id: string; nowIso: string },
70
+ ): IdentityUpdateOutcome {
71
+ if (!consolidation.target_layer || !consolidation.target_key) {
72
+ return { kind: "missing_target" };
73
+ }
74
+ try {
75
+ applyConsolidationIdentityUpdate(db, {
76
+ targetLayer: consolidation.target_layer,
77
+ targetKey: consolidation.target_key,
78
+ content: resultContent,
79
+ id: ids.id,
80
+ nowIso: ids.nowIso,
81
+ });
82
+ } catch (error) {
83
+ return { kind: "refused", message: error instanceof Error ? error.message : String(error) };
84
+ }
85
+
86
+ const sourceIds = sourceMemoryIds(consolidation);
87
+ for (const memoryId of sourceIds) {
88
+ updateMemoryReadinessState(db, memoryId, "acknowledged");
89
+ }
90
+ updateConsolidationStatus(db, consolidation.id, "accepted", resultContent, ids.nowIso);
91
+ return {
92
+ kind: "applied",
93
+ targetLayer: consolidation.target_layer,
94
+ targetKey: consolidation.target_key,
95
+ sourceMemoryIds: sourceIds,
96
+ };
97
+ }
98
+
99
+ // --- consolidate apply: shadow_candidate --------------------------------------
100
+
101
+ export interface ShadowCandidateOutcome {
102
+ sourceMemoryIds: string[];
103
+ }
104
+
105
+ /**
106
+ * `consolidate apply` for `action = 'shadow_candidate'`: advances every
107
+ * source memory's readiness to `'candidate'` for the next `mm-shadow` pass,
108
+ * then records the consolidation as accepted.
109
+ */
110
+ export function applyShadowCandidate(
111
+ db: WritableDatabase,
112
+ consolidation: ConsolidationRow,
113
+ resultContent: string,
114
+ nowIso: string,
115
+ ): ShadowCandidateOutcome {
116
+ const sourceIds = sourceMemoryIds(consolidation);
117
+ for (const memoryId of sourceIds) {
118
+ updateMemoryReadinessState(db, memoryId, "candidate");
119
+ }
120
+ updateConsolidationStatus(db, consolidation.id, "accepted", resultContent, nowIso);
121
+ return { sourceMemoryIds: sourceIds };
122
+ }
123
+
124
+ // --- shadow apply --------------------------------------------------------------
125
+
126
+ export interface ShadowApplyOutcome {
127
+ targetKey: string;
128
+ sourceMemoryIds: string[];
129
+ }
130
+
131
+ /**
132
+ * `shadow apply`: append (or create) the structural `shadow` identity layer at
133
+ * `target_key` (default `'profile'`), advance source memories to
134
+ * `'acknowledged'`, and record acceptance. SAFETY: `layer` is the HARDCODED
135
+ * constant `"shadow"` -- never read from `consolidation.target_layer` or any
136
+ * other proposal field. Only `target_key` (or the `'profile'` default) is
137
+ * model-influenced; that is the entire allowed surface, matching Python's
138
+ * `mem.store.upsert_identity(Identity(layer="shadow", key=target_key, ...))`.
139
+ */
140
+ export function applyShadowApply(
141
+ db: WritableDatabase,
142
+ consolidation: ConsolidationRow,
143
+ resultContent: string,
144
+ ids: { id: string; nowIso: string },
145
+ ): ShadowApplyOutcome {
146
+ const targetKey = consolidation.target_key ?? "profile";
147
+ const existingContent = getIdentityContent(db, "shadow", targetKey);
148
+ const updatedContent =
149
+ existingContent !== null
150
+ ? `${existingContent.trimEnd()}\n\n---\n\n${resultContent}`
151
+ : resultContent;
152
+
153
+ upsertIdentity(
154
+ db,
155
+ {
156
+ id: ids.id,
157
+ layer: "shadow",
158
+ key: targetKey,
159
+ content: updatedContent,
160
+ version: "1.0.0",
161
+ metadata: null,
162
+ },
163
+ ids.nowIso,
164
+ );
165
+
166
+ const sourceIds = sourceMemoryIds(consolidation);
167
+ for (const memoryId of sourceIds) {
168
+ updateMemoryReadinessState(db, memoryId, "acknowledged");
169
+ }
170
+ updateConsolidationStatus(db, consolidation.id, "accepted", resultContent, ids.nowIso);
171
+ return { targetKey, sourceMemoryIds: sourceIds };
172
+ }
173
+
174
+ // --- consolidate apply: merge (Slice B -- needs a fresh embedding) -----------
175
+
176
+ export type MergeOutcome =
177
+ | { kind: "merged"; mergedMemoryId: string; mergedTitle: string; sourceMemoryIds: string[] }
178
+ | { kind: "source_not_found" };
179
+
180
+ export interface ApplyMergeOptions {
181
+ embeddingProvider: EmbeddingProvider;
182
+ /** The NEW merged memory's id, injected (DS4 determinism idiom) -- unrelated to `consolidation.id`. */
183
+ id: string;
184
+ nowIso: string;
185
+ onEmbeddingAttempt?: (info: EmbeddingAttemptInfo) => void;
186
+ }
187
+
188
+ /**
189
+ * `consolidate apply` for `action = 'merge'`: distill the cluster into one
190
+ * sharper memory. Reads the FIRST source memory only for `memory_type`/
191
+ * `layer`/`journey` (Python's `first = mem.store.get_memory(source_ids[0])`),
192
+ * titles the merge `"[merged] {first.title}"`, sets `context` to the exact
193
+ * `"Merged from: {id, id, ...}"` provenance string (source id order, not
194
+ * sorted), embeds `resultContent` via the injected `EmbeddingProvider`
195
+ * (replay under DS7, live under DS8), stamps embedding provenance, marks
196
+ * every source memory `'integrated'`, and records acceptance. A missing
197
+ * first source memory returns `source_not_found` -- no memory row, no
198
+ * readiness advance, no consolidation status change, mirroring Python's
199
+ * `sys.exit(1)` before any side effect runs.
200
+ */
201
+ export async function applyMerge(
202
+ db: WritableDatabase,
203
+ consolidation: ConsolidationRow,
204
+ resultContent: string,
205
+ options: ApplyMergeOptions,
206
+ ): Promise<MergeOutcome> {
207
+ const sourceIds = sourceMemoryIds(consolidation);
208
+ const first = getMemorySourceForMerge(db, sourceIds[0] as string);
209
+ if (first === null) {
210
+ return { kind: "source_not_found" };
211
+ }
212
+
213
+ const embedding = await generateEmbeddingSafely(options.embeddingProvider, resultContent, {
214
+ onAttempt: options.onEmbeddingAttempt,
215
+ });
216
+
217
+ createMemoryRow(db, {
218
+ id: options.id,
219
+ memoryType: first.memory_type,
220
+ layer: first.layer,
221
+ title: `[merged] ${first.title}`,
222
+ content: resultContent,
223
+ journey: first.journey,
224
+ context: `Merged from: ${sourceIds.join(", ")}`,
225
+ createdAt: options.nowIso,
226
+ relevanceScore: 1.0,
227
+ embedding: embeddingToBytes(embedding),
228
+ metadata: addEmbeddingProvenance(null),
229
+ });
230
+
231
+ for (const memoryId of sourceIds) {
232
+ updateMemoryReadinessState(db, memoryId, "integrated");
233
+ }
234
+ updateConsolidationStatus(db, consolidation.id, "accepted", resultContent, options.nowIso);
235
+ return {
236
+ kind: "merged",
237
+ mergedMemoryId: options.id,
238
+ mergedTitle: `[merged] ${first.title}`,
239
+ sourceMemoryIds: sourceIds,
240
+ };
241
+ }
@@ -0,0 +1,86 @@
1
+ // Port of `cluster_memories` (`src/memory/intelligence/consolidate.py`,
2
+ // CV22.DS7.US3). Pure function, no DB/clock/provider dependency -- graded
3
+ // against the Python oracle by a committed synthetic-embedding golden
4
+ // (`ts/parity/generate_cluster_golden.py`).
5
+ //
6
+ // Greedy single-linkage: a memory joins an existing cluster when its cosine
7
+ // similarity to the cluster SEED (the first member, never re-derived as a
8
+ // centroid) meets the threshold. A memory can only belong to one cluster
9
+ // (first match wins). Memories with no embedding or in a terminal readiness
10
+ // state are skipped up front; singleton groups (clusters of one) are dropped.
11
+
12
+ import { blobToFloat32 } from "#db/decode.ts";
13
+ import { cosineSimilarity } from "#search/ranker.ts";
14
+ import type { CultivationMemory } from "./consolidationStore.ts";
15
+
16
+ /** Mirrors Python's `DEFAULT_CLUSTER_THRESHOLD`. */
17
+ export const DEFAULT_CLUSTER_THRESHOLD = 0.75;
18
+
19
+ /** Mirrors Python's `MAX_CLUSTER_SIZE` -- caps memories per cluster (prevents unwieldy LLM prompts). */
20
+ export const MAX_CLUSTER_SIZE = 5;
21
+
22
+ /** Mirrors Python's `_TERMINAL_STATES` -- readiness states already "done", skipped for clustering. */
23
+ const TERMINAL_READINESS_STATES: ReadonlySet<string> = new Set(["integrated"]);
24
+
25
+ /**
26
+ * The input shape `clusterMemories` needs: a cultivation memory whose
27
+ * embedding MAY be absent (`null`), mirroring Python's `Memory.embedding:
28
+ * bytes | None`. `CultivationMemoryWithEmbedding` (embedding always present,
29
+ * guaranteed by the `embedding IS NOT NULL` SQL filter) is structurally
30
+ * assignable here -- the real `consolidate scan` read path never actually
31
+ * exercises the null branch, but the defensive skip is still a faithful part
32
+ * of the ported function and is proven directly by the golden/unit tests.
33
+ */
34
+ export interface ClusterableMemory extends CultivationMemory {
35
+ embedding_b64: string | null;
36
+ }
37
+
38
+ /**
39
+ * Group semantically similar memories into clusters, byte-for-byte matching
40
+ * Python's `cluster_memories` algorithm and iteration order (both the outer
41
+ * seed scan and the inner candidate scan iterate the SAME `eligible` array in
42
+ * its original order -- not a shrinking remainder -- with `assigned` doing
43
+ * the exclusion).
44
+ */
45
+ export function clusterMemories<T extends ClusterableMemory>(
46
+ memories: readonly T[],
47
+ threshold: number = DEFAULT_CLUSTER_THRESHOLD,
48
+ ): T[][] {
49
+ const eligible = memories.filter(
50
+ (memory) =>
51
+ memory.embedding_b64 !== null && !TERMINAL_READINESS_STATES.has(memory.readiness_state),
52
+ );
53
+ if (eligible.length < 2) return [];
54
+
55
+ const embeddings = new Map<string, Float32Array>();
56
+ for (const memory of eligible) {
57
+ embeddings.set(memory.id, blobToFloat32(Buffer.from(memory.embedding_b64 as string, "base64")));
58
+ }
59
+
60
+ const assigned = new Set<string>();
61
+ const clusters: T[][] = [];
62
+
63
+ for (const seed of eligible) {
64
+ if (assigned.has(seed.id)) continue;
65
+ const cluster: T[] = [seed];
66
+ assigned.add(seed.id);
67
+ const seedEmbedding = embeddings.get(seed.id) as Float32Array;
68
+
69
+ for (const candidate of eligible) {
70
+ if (assigned.has(candidate.id)) continue;
71
+ if (cluster.length >= MAX_CLUSTER_SIZE) break;
72
+ const similarity = cosineSimilarity(
73
+ seedEmbedding,
74
+ embeddings.get(candidate.id) as Float32Array,
75
+ );
76
+ if (similarity >= threshold) {
77
+ cluster.push(candidate);
78
+ assigned.add(candidate.id);
79
+ }
80
+ }
81
+
82
+ if (cluster.length >= 2) clusters.push(cluster);
83
+ }
84
+
85
+ return clusters;
86
+ }
@@ -0,0 +1,281 @@
1
+ // Consolidation persistence + cultivation memory reads (CV22.DS7.US3).
2
+ //
3
+ // A faithful TypeScript port of `ConsolidationStore`
4
+ // (`src/memory/storage/consolidations.py`) plus the two `Store` memory reads
5
+ // `consolidate`/`shadow` depend on: `get_all_memories_with_embeddings` (used by
6
+ // `consolidate scan`, filtered client-side in Python -- pushed down to SQL here,
7
+ // same database-seam philosophy as DS2/US2) and `get_shadow_candidate_memories`
8
+ // (used by `shadow scan`). The `consolidations` table and `memories.readiness_state`
9
+ // column already exist in the TS-authored schema (DS6) -- no new migration here.
10
+
11
+ import type { Database, SqlValue, WritableDatabase } from "#db/database.ts";
12
+ import { optionalString, requireString } from "#db/rowDecode.ts";
13
+
14
+ /** A consolidation row, mirroring the Python `Consolidation` model exactly. */
15
+ export interface ConsolidationRow {
16
+ id: string;
17
+ action: string; // 'merge' | 'identity_update' | 'shadow_candidate' | 'shadow_observation'
18
+ proposal: string;
19
+ result: string | null;
20
+ source_memory_ids: string; // JSON-encoded array of Memory.id values
21
+ target_layer: string | null;
22
+ target_key: string | null;
23
+ rationale: string | null;
24
+ status: string; // 'pending' | 'accepted' | 'rejected'
25
+ created_at: string;
26
+ reviewed_at: string | null;
27
+ }
28
+
29
+ const CONSOLIDATION_COLUMNS =
30
+ "id, action, proposal, result, source_memory_ids, target_layer, target_key, " +
31
+ "rationale, status, created_at, reviewed_at";
32
+
33
+ function toConsolidation(row: Record<string, unknown>): ConsolidationRow {
34
+ return {
35
+ id: requireString(row, "id"),
36
+ action: requireString(row, "action"),
37
+ proposal: requireString(row, "proposal"),
38
+ result: optionalString(row, "result"),
39
+ source_memory_ids: requireString(row, "source_memory_ids"),
40
+ target_layer: optionalString(row, "target_layer"),
41
+ target_key: optionalString(row, "target_key"),
42
+ rationale: optionalString(row, "rationale"),
43
+ status: requireString(row, "status"),
44
+ created_at: requireString(row, "created_at"),
45
+ reviewed_at: optionalString(row, "reviewed_at"),
46
+ };
47
+ }
48
+
49
+ // --- Consolidations ----------------------------------------------------------
50
+
51
+ /** Port of `ConsolidationStore.create_consolidation`. Returns the row as-is. */
52
+ export function createConsolidation(
53
+ db: WritableDatabase,
54
+ consolidation: ConsolidationRow,
55
+ ): ConsolidationRow {
56
+ db.prepare(
57
+ `INSERT INTO consolidations (${CONSOLIDATION_COLUMNS}) ` +
58
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
59
+ ).run(
60
+ consolidation.id,
61
+ consolidation.action,
62
+ consolidation.proposal,
63
+ consolidation.result,
64
+ consolidation.source_memory_ids,
65
+ consolidation.target_layer,
66
+ consolidation.target_key,
67
+ consolidation.rationale,
68
+ consolidation.status,
69
+ consolidation.created_at,
70
+ consolidation.reviewed_at,
71
+ );
72
+ return consolidation;
73
+ }
74
+
75
+ /** Port of `ConsolidationStore.get_consolidation`. */
76
+ export function getConsolidation(db: Database, id: string): ConsolidationRow | null {
77
+ const row = db
78
+ .prepare(`SELECT ${CONSOLIDATION_COLUMNS} FROM consolidations WHERE id = ?`)
79
+ .get(id);
80
+ return row === undefined ? null : toConsolidation(row);
81
+ }
82
+
83
+ /**
84
+ * Port of `ConsolidationStore.update_consolidation_status`: `result` is
85
+ * `COALESCE(?, result)` -- passing `null` preserves the existing `result`
86
+ * (Python's default `result: str | None = None` parameter), matching a
87
+ * `reject` call (no result) leaving `result` untouched.
88
+ */
89
+ export function updateConsolidationStatus(
90
+ db: WritableDatabase,
91
+ id: string,
92
+ status: string,
93
+ result: string | null,
94
+ nowIso: string,
95
+ ): void {
96
+ db.prepare(
97
+ "UPDATE consolidations SET status = ?, result = COALESCE(?, result), reviewed_at = ? WHERE id = ?",
98
+ ).run(status, result, nowIso, id);
99
+ }
100
+
101
+ /** Filters for `listConsolidations`, mirroring the Python signature. */
102
+ export interface ListConsolidationsFilters {
103
+ status?: string | null;
104
+ limit?: number;
105
+ }
106
+
107
+ /**
108
+ * Port of `ConsolidationStore.list_consolidations`: a `1=1` seed, an optional
109
+ * `status = ?` clause, `ORDER BY created_at DESC`, trailing `LIMIT ?`.
110
+ */
111
+ export function listConsolidations(
112
+ db: Database,
113
+ filters: ListConsolidationsFilters = {},
114
+ ): ConsolidationRow[] {
115
+ const { status = null, limit = 20 } = filters;
116
+ const conditions = ["1=1"];
117
+ const params: SqlValue[] = [];
118
+ if (status) {
119
+ conditions.push("status = ?");
120
+ params.push(status);
121
+ }
122
+ params.push(limit);
123
+ return db
124
+ .prepare(
125
+ `SELECT ${CONSOLIDATION_COLUMNS} FROM consolidations WHERE ${conditions.join(" AND ")} ` +
126
+ "ORDER BY created_at DESC LIMIT ?",
127
+ )
128
+ .all(...params)
129
+ .map(toConsolidation);
130
+ }
131
+
132
+ /**
133
+ * Port of the `_resolve_proposal` helper duplicated in both
134
+ * `cli/consolidate_cmd.py` and `cli/shadow_cmd.py`: exact id first, else a
135
+ * first-match-wins scan (by `created_at DESC` order) over the most recent 200
136
+ * consolidations. Deliberately kept SEPARATE from `resolveTaskByIdOrPrefix`
137
+ * (US2): Python itself has no ambiguous-match branch here (unlike tasks) --
138
+ * the first prefix hit in listing order simply wins, so unifying the two
139
+ * resolvers would invent a branch Python does not have.
140
+ */
141
+ export function resolveProposalByIdOrPrefix(
142
+ db: Database,
143
+ idOrPrefix: string,
144
+ ): ConsolidationRow | null {
145
+ const exact = getConsolidation(db, idOrPrefix);
146
+ if (exact) return exact;
147
+ const recent = listConsolidations(db, { limit: 200 });
148
+ return recent.find((item) => item.id.startsWith(idOrPrefix)) ?? null;
149
+ }
150
+
151
+ // --- Memory readiness ---------------------------------------------------------
152
+
153
+ /**
154
+ * Port of `ConsolidationStore.update_memory_readiness_state`. Valid states:
155
+ * observed | candidate | surfaced | acknowledged | integrated. One statement,
156
+ * one implicit commit -- callers must NOT wrap a sequence of these (plus a
157
+ * sibling write) in an explicit transaction; Python commits each call
158
+ * separately and the port preserves that commit boundary exactly.
159
+ */
160
+ export function updateMemoryReadinessState(
161
+ db: WritableDatabase,
162
+ memoryId: string,
163
+ state: string,
164
+ ): void {
165
+ db.prepare("UPDATE memories SET readiness_state = ? WHERE id = ?").run(state, memoryId);
166
+ }
167
+
168
+ // --- Cultivation memory reads --------------------------------------------------
169
+
170
+ /** The memory projection cultivation formatting needs, shared by both scans. */
171
+ export interface CultivationMemory {
172
+ id: string;
173
+ memory_type: string;
174
+ layer: string;
175
+ title: string;
176
+ content: string;
177
+ context: string | null;
178
+ journey: string | null;
179
+ created_at: string;
180
+ readiness_state: string;
181
+ }
182
+
183
+ /** A cultivation memory with its embedding, for clustering (`consolidate scan`). */
184
+ export interface CultivationMemoryWithEmbedding extends CultivationMemory {
185
+ embedding_b64: string;
186
+ }
187
+
188
+ const CULTIVATION_COLUMNS_BASE =
189
+ "id, memory_type, layer, title, content, context, journey, created_at, readiness_state";
190
+
191
+ function toCultivationMemory(row: Record<string, unknown>): CultivationMemory {
192
+ return {
193
+ id: requireString(row, "id"),
194
+ memory_type: requireString(row, "memory_type"),
195
+ layer: requireString(row, "layer"),
196
+ title: requireString(row, "title"),
197
+ content: requireString(row, "content"),
198
+ context: optionalString(row, "context"),
199
+ journey: optionalString(row, "journey"),
200
+ created_at: requireString(row, "created_at"),
201
+ readiness_state: requireString(row, "readiness_state"),
202
+ };
203
+ }
204
+
205
+ /** Optional equality filters for the cultivation memory reads. */
206
+ export interface CultivationMemoryFilters {
207
+ journey?: string | null;
208
+ layer?: string | null;
209
+ }
210
+
211
+ /**
212
+ * Port of `Store.get_all_memories_with_embeddings`, plus the `--journey`/
213
+ * `--layer` filters `consolidate_cmd.cmd_scan` applies client-side in Python
214
+ * -- pushed down into the SQL `WHERE` here (same result set, DS2/US2's
215
+ * query-builder philosophy). `ORDER BY created_at DESC`, matching Python.
216
+ */
217
+ export function getMemoriesWithEmbeddingsForCultivation(
218
+ db: Database,
219
+ filters: CultivationMemoryFilters = {},
220
+ ): CultivationMemoryWithEmbedding[] {
221
+ const conditions = ["embedding IS NOT NULL"];
222
+ const params: SqlValue[] = [];
223
+ if (filters.journey) {
224
+ conditions.push("journey = ?");
225
+ params.push(filters.journey);
226
+ }
227
+ if (filters.layer) {
228
+ conditions.push("layer = ?");
229
+ params.push(filters.layer);
230
+ }
231
+ return db
232
+ .prepare(
233
+ `SELECT ${CULTIVATION_COLUMNS_BASE}, embedding FROM memories ` +
234
+ `WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC`,
235
+ )
236
+ .all(...params)
237
+ .map((row) => {
238
+ const embedding = row.embedding;
239
+ if (!(embedding instanceof Uint8Array)) {
240
+ throw new Error("memory embedding must be a BLOB/Uint8Array");
241
+ }
242
+ return {
243
+ ...toCultivationMemory(row),
244
+ embedding_b64: Buffer.from(embedding).toString("base64"),
245
+ };
246
+ });
247
+ }
248
+
249
+ /** Filters for `getShadowCandidateMemories`, mirroring the Python signature. */
250
+ export interface ShadowCandidateFilters {
251
+ readinessStates?: readonly string[];
252
+ limit?: number;
253
+ }
254
+
255
+ const DEFAULT_SHADOW_READINESS_STATES: readonly string[] = ["observed", "candidate"];
256
+
257
+ /**
258
+ * Port of `Store.get_shadow_candidate_memories`: memories with `layer =
259
+ * 'shadow'` OR `memory_type IN ('tension', 'pattern')`, restricted to the
260
+ * given readiness states (default `observed`/`candidate`), `ORDER BY
261
+ * created_at DESC LIMIT ?`. No embedding requirement -- shadow candidates need
262
+ * not have been embedded.
263
+ */
264
+ export function getShadowCandidateMemories(
265
+ db: Database,
266
+ filters: ShadowCandidateFilters = {},
267
+ ): CultivationMemory[] {
268
+ const readinessStates = filters.readinessStates ?? DEFAULT_SHADOW_READINESS_STATES;
269
+ const limit = filters.limit ?? 100;
270
+ const placeholders = readinessStates.map(() => "?").join(", ");
271
+ const params: SqlValue[] = [...readinessStates, limit];
272
+ return db
273
+ .prepare(
274
+ `SELECT ${CULTIVATION_COLUMNS_BASE} FROM memories ` +
275
+ "WHERE (layer = 'shadow' OR memory_type IN ('tension', 'pattern')) " +
276
+ `AND readiness_state IN (${placeholders}) ` +
277
+ "ORDER BY created_at DESC LIMIT ?",
278
+ )
279
+ .all(...params)
280
+ .map(toCultivationMemory);
281
+ }
@@ -0,0 +1,62 @@
1
+ // The two inputs `cmd_scan` resolves from the database before calling the
2
+ // LLM (CV22.DS8.TS2): the owner's first name and the identity context the
3
+ // consolidation prompt shows the model. Ports `cli/shadow_cmd.py:_user_name`
4
+ // and `cli/consolidate_cmd.py:_identity_context`.
5
+ //
6
+ // On the name: Python has TWO resolvers for these leaves. `shadow_cmd` uses
7
+ // the regex below; `consolidate_cmd` first short-circuits on the literal
8
+ // owner's name being anywhere in the content (a distribution defect, CR014).
9
+ // TS ships one resolver, the regex form. The only input where the two Python
10
+ // forms disagree is content that names the owner without the seed template's
11
+ // "speaking with" line, which no shipped template produces; the golden's
12
+ // `resolvers` section records both columns so the deviation stays visible
13
+ // (plan decision D1, docs/project/decisions.md).
14
+ //
15
+ // This is NOT the close tail's `resolveUserName` (`conversation/extraction.ts`),
16
+ // which ports a third oracle (`You are talking to`). Unifying the three is
17
+ // CR014's job, not this story's.
18
+
19
+ import type { Database } from "#db/database.ts";
20
+ import { getIdentityContent } from "#identity/identityRead.ts";
21
+ import { sliceCodePoints } from "#util/pythonText.ts";
22
+
23
+ /** Python's `\w+` on a `str` pattern: Unicode letters, digits, underscore. A
24
+ * combining mark (Mn) is not a word character in either engine. */
25
+ const SPEAKING_WITH = /speaking with ([\p{L}\p{N}_]+)/u;
26
+
27
+ /** Python's fallback when the row or the marker phrase is absent. */
28
+ export const FALLBACK_USER_NAME = "the user";
29
+
30
+ /** Port of `shadow_cmd._user_name`: the owner's first name from `user/identity`. */
31
+ export function cultivationUserName(db: Database): string {
32
+ const content = getIdentityContent(db, "user", "identity");
33
+ const match = content?.match(SPEAKING_WITH);
34
+ return match?.[1] ?? FALLBACK_USER_NAME;
35
+ }
36
+
37
+ /** `entry.content[:600]` -- code points, not UTF-16 units. */
38
+ export const IDENTITY_CONTEXT_CODE_POINTS = 600;
39
+
40
+ /** The layers `_identity_context` reads, in Python's order. */
41
+ const IDENTITY_CONTEXT_LAYERS: readonly (readonly [string, string])[] = [
42
+ ["ego", "behavior"],
43
+ ["ego", "identity"],
44
+ ["self", "soul"],
45
+ ];
46
+
47
+ /** Python's fallback when none of the three rows exists. */
48
+ export const FALLBACK_IDENTITY_CONTEXT = "(no identity context loaded)";
49
+
50
+ /**
51
+ * Port of `consolidate_cmd._identity_context`: a brief, system-side identity
52
+ * digest for the consolidation prompt's IDENTITY_UPDATE reference.
53
+ */
54
+ export function consolidationIdentityContext(db: Database): string {
55
+ const parts: string[] = [];
56
+ for (const [layer, key] of IDENTITY_CONTEXT_LAYERS) {
57
+ const content = getIdentityContent(db, layer, key);
58
+ if (content === null) continue;
59
+ parts.push(`## ${layer}/${key}\n${sliceCodePoints(content, IDENTITY_CONTEXT_CODE_POINTS)}`);
60
+ }
61
+ return parts.length > 0 ? parts.join("\n\n") : FALLBACK_IDENTITY_CONTEXT;
62
+ }