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,321 @@
1
+ // `conversation-logger` CLI dispatch (CV22.DS7.US5 slice A; completed in
2
+ // CV22.DS7.US10 slice F).
3
+ //
4
+ // Ports the argument handling and stdout contract of
5
+ // `conversation_logger.main()`. The strangler's unit is
6
+ // `command + args -> stdout`, so this module returns the output rather than
7
+ // printing it: the front door writes it, and goldens grade it.
8
+ //
9
+ // Every subcommand of the family is dispatched here. The ones that cross the
10
+ // LLM close tail (`switch`, `session-end`, `session-end-pi`, full
11
+ // `session-start`, `session-maintenance`) get their tail from the runtime's
12
+ // close hooks. (Until CV22.DS10.TS5 a reverted tail reported `{ handled:
13
+ // false }` so the caller could fall back to Python; the revert left with the
14
+ // fallback, and every result is now an answer.) `repair-journeys --apply`
15
+ // needs the dated zip backup from the runtime (CV22.DS7.TS1) and refuses, like
16
+ // Python, when it is not available.
17
+
18
+ import { backfillCodexSession } from "#conversation/backfill.ts";
19
+ import { diagnoseJourneyAssociations, renderJourneyFindings } from "#conversation/journeyRepair.ts";
20
+ import {
21
+ discardCurrentConversation,
22
+ endSession,
23
+ handleSessionEndHook,
24
+ handleStopHook,
25
+ handleUserPromptHook,
26
+ isMuted,
27
+ logAssistantMessage,
28
+ logUserMessage,
29
+ setMute,
30
+ switchConversation,
31
+ } from "#conversation/logger.ts";
32
+ import type { LoggerRuntime } from "#conversation/loggerRuntime.ts";
33
+ import {
34
+ sessionMaintenance,
35
+ sessionStart,
36
+ sessionStartFast,
37
+ } from "#conversation/sessionComposites.ts";
38
+ import type { WritableDatabase } from "#db/database.ts";
39
+
40
+ export interface LoggerCliResult {
41
+ stdout: string[];
42
+ stderr: string[];
43
+ exitCode: number;
44
+ }
45
+
46
+ export interface LoggerCliContext {
47
+ stdin?: string;
48
+ }
49
+
50
+ /** Every subcommand `conversation_logger.main()` dispatches. */
51
+ export const CONVERSATION_LOGGER_SUBCOMMANDS = [
52
+ "mute",
53
+ "unmute",
54
+ "status",
55
+ "log-user",
56
+ "log-assistant",
57
+ "user-prompt",
58
+ "stop",
59
+ "discard-current",
60
+ "switch",
61
+ "session-end-pi",
62
+ "session-end",
63
+ "session-start",
64
+ "session-maintenance",
65
+ "diagnose-journeys",
66
+ "repair-journeys",
67
+ "backfill-codex-session",
68
+ ] as const;
69
+
70
+ /** The subcommands whose Python path runs `end_conversation`'s LLM close tail. */
71
+ export const LLM_TAIL_SUBCOMMANDS: ReadonlySet<string> = new Set([
72
+ "switch",
73
+ "session-end-pi",
74
+ "session-end",
75
+ "session-start",
76
+ "session-maintenance",
77
+ ]);
78
+
79
+ /** Subcommands that read their JSON payload from stdin. */
80
+ export const STDIN_SUBCOMMANDS: ReadonlySet<string> = new Set([
81
+ "user-prompt",
82
+ "stop",
83
+ "session-end",
84
+ ]);
85
+
86
+ function extractOption(
87
+ args: string[],
88
+ name: string,
89
+ ): { value: string | null; error: string | null } {
90
+ const index = args.indexOf(name);
91
+ if (index === -1) return { value: null, error: null };
92
+ if (index + 1 >= args.length) {
93
+ const noun = name === "--mirror-home" ? "a path" : name === "--limit" ? "a number" : "a value";
94
+ return { value: null, error: `Error: ${name} requires ${noun}` };
95
+ }
96
+ const value = args[index + 1] as string;
97
+ args.splice(index, 2);
98
+ return { value, error: null };
99
+ }
100
+
101
+ /** Python `"--interface" in args` followed by `args[idx + 1]` when present. */
102
+ function interfaceOption(args: readonly string[], fallback: string): string {
103
+ const index = args.indexOf("--interface");
104
+ return index !== -1 && index + 1 < args.length ? (args[index + 1] as string) : fallback;
105
+ }
106
+
107
+ const ok = (stdout: string[]): LoggerCliResult => ({
108
+ stdout,
109
+ stderr: [],
110
+ exitCode: 0,
111
+ });
112
+
113
+ export async function runConversationLoggerCommand(
114
+ db: WritableDatabase,
115
+ argv: readonly string[],
116
+ runtime: LoggerRuntime,
117
+ context: LoggerCliContext = {},
118
+ ): Promise<LoggerCliResult> {
119
+ const args = [...argv];
120
+
121
+ // Python strips --mirror-home and --session-id before dispatch, failing with
122
+ // exit 1 when either is present without a value.
123
+ const mirrorHome = extractOption(args, "--mirror-home");
124
+ if (mirrorHome.error) {
125
+ return { stdout: [], stderr: [mirrorHome.error], exitCode: 1 };
126
+ }
127
+ const sessionOption = extractOption(args, "--session-id");
128
+ if (sessionOption.error) {
129
+ return { stdout: [], stderr: [sessionOption.error], exitCode: 1 };
130
+ }
131
+ if (args.length === 0) {
132
+ return { stdout: [], stderr: [], exitCode: 1 };
133
+ }
134
+
135
+ const command = args[0] as string;
136
+ if (!(CONVERSATION_LOGGER_SUBCOMMANDS as readonly string[]).includes(command)) {
137
+ // Python's main() silently exits 0 on an unknown subcommand.
138
+ return ok([]);
139
+ }
140
+
141
+ const home = mirrorHome.value ?? runtime.mirrorHome;
142
+ const deps = runtime.deps;
143
+
144
+ switch (command) {
145
+ case "mute":
146
+ setMute(true, home);
147
+ return ok(["Conversation logging MUTED."]);
148
+ case "unmute":
149
+ setMute(false, home);
150
+ return ok(["Conversation logging ACTIVE."]);
151
+ case "status":
152
+ return ok([isMuted(home) ? "MUTED" : "ACTIVE"]);
153
+
154
+ case "user-prompt":
155
+ // `--interface` is the runtime the hook detected (US8); without it the
156
+ // label is Python's hook default.
157
+ handleUserPromptHook(
158
+ db,
159
+ context.stdin ?? "",
160
+ { mirrorHome: home, interface: interfaceOption(args, "claude_code") },
161
+ deps,
162
+ );
163
+ // The hook is silent and always exits 0, whatever the outcome.
164
+ return ok([]);
165
+
166
+ case "stop": {
167
+ // The Stop hook's payload (US8): the turn's final answer, logged beside
168
+ // its prompt when one is waiting. Exit 0 whatever the outcome, and the
169
+ // outcome on stdout in one line: the hook entry runs this route
170
+ // in-process, reads the line, and forwards nothing -- a Stop hook that
171
+ // printed would keep the agent working on some runtimes -- while a
172
+ // person running the command from a shell sees what happened.
173
+ const outcome = handleStopHook(
174
+ db,
175
+ context.stdin ?? "",
176
+ { mirrorHome: home, interface: interfaceOption(args, "claude_code") },
177
+ deps,
178
+ );
179
+ switch (outcome.action) {
180
+ case "logged":
181
+ return ok([`reply logged (${outcome.pairedBy})`]);
182
+ case "skipped":
183
+ return ok([`reply skipped: ${outcome.reason}`]);
184
+ case "muted":
185
+ return ok(["reply not logged: muted"]);
186
+ default:
187
+ // The error text is the fault's, never the payload's.
188
+ return ok([`reply failed: ${outcome.error}`]);
189
+ }
190
+ }
191
+
192
+ case "session-end":
193
+ await handleSessionEndHook(
194
+ db,
195
+ context.stdin ?? "",
196
+ {
197
+ mirrorHome: home,
198
+ claudeProjectDir: runtime.claudeProjectDir,
199
+ homeDir: runtime.homeDir,
200
+ },
201
+ deps,
202
+ await runtime.closeHooks(),
203
+ );
204
+ return ok([]);
205
+
206
+ case "log-user":
207
+ case "log-assistant": {
208
+ const remaining = args.slice(1);
209
+ const interfaceName = extractOption(remaining, "--interface").value ?? "claude_code";
210
+ // Python silently does nothing with fewer than two positional arguments.
211
+ if (remaining.length >= 2) {
212
+ const [targetSession, content] = remaining as [string, string];
213
+ const write = command === "log-user" ? logUserMessage : logAssistantMessage;
214
+ write(db, targetSession, content, { interface: interfaceName }, deps);
215
+ }
216
+ return ok([]);
217
+ }
218
+
219
+ case "switch": {
220
+ const conversationId = await switchConversation(
221
+ db,
222
+ sessionOption.value,
223
+ { envSessionId: runtime.environmentSessionId },
224
+ deps,
225
+ await runtime.closeHooks(),
226
+ );
227
+ return ok([
228
+ conversationId ? `New conversation created: ${conversationId}` : "No active session found.",
229
+ ]);
230
+ }
231
+
232
+ case "session-start":
233
+ if (args.includes("--fast")) return ok([sessionStartFast(db, home, deps.nowIso)]);
234
+ return ok([await sessionStart(db, home, await runtime.maintenanceDeps())]);
235
+
236
+ case "session-maintenance":
237
+ return ok([await sessionMaintenance(db, await runtime.maintenanceDeps())]);
238
+
239
+ case "discard-current": {
240
+ const discarded = discardCurrentConversation(
241
+ db,
242
+ sessionOption.value,
243
+ { interface: interfaceOption(args, "pi") },
244
+ deps,
245
+ );
246
+ return ok([
247
+ discarded
248
+ ? `Discarded current conversation: ${discarded}`
249
+ : "No current conversation to discard.",
250
+ ]);
251
+ }
252
+
253
+ case "session-end-pi":
254
+ if (args.length >= 2) {
255
+ await endSession(
256
+ db,
257
+ args[1] as string,
258
+ { extract: false },
259
+ deps,
260
+ await runtime.closeHooks(),
261
+ );
262
+ }
263
+ return ok([]);
264
+
265
+ case "diagnose-journeys":
266
+ case "repair-journeys": {
267
+ const apply = command === "repair-journeys" && args.includes("--apply");
268
+ const limitOption = extractOption(args, "--limit");
269
+ if (limitOption.error) {
270
+ return { stdout: [], stderr: [limitOption.error], exitCode: 1 };
271
+ }
272
+ let limit: number | null = null;
273
+ if (limitOption.value !== null) {
274
+ // Python `int(value)` raises ValueError on anything but an integer.
275
+ if (!/^\s*[+-]?\d+\s*$/.test(limitOption.value)) {
276
+ return {
277
+ stdout: [],
278
+ stderr: [`ValueError: invalid literal for int() with base 10: '${limitOption.value}'`],
279
+ exitCode: 1,
280
+ };
281
+ }
282
+ limit = Number.parseInt(limitOption.value, 10);
283
+ }
284
+ // Python prints backup()'s progress from inside the repair, BEFORE the
285
+ // findings; the lines are collected here so the order survives.
286
+ const backupLines: string[] = [];
287
+ const backup = runtime.backup;
288
+ const findings = diagnoseJourneyAssociations(db, {
289
+ limit,
290
+ apply,
291
+ ...(apply && backup ? { backup: () => backup((line) => backupLines.push(line)) } : {}),
292
+ });
293
+ const lines = [
294
+ ...backupLines,
295
+ ...renderJourneyFindings(findings, apply).replace(/\n$/, "").split("\n"),
296
+ ];
297
+ if (command === "repair-journeys" && !apply) {
298
+ lines.push("Dry run only. Re-run with --apply to repair after reviewing candidates.");
299
+ }
300
+ return ok(lines);
301
+ }
302
+
303
+ case "backfill-codex-session": {
304
+ if (args.length < 2) return ok([]);
305
+ const path = args[1] as string;
306
+ const count = backfillCodexSession(
307
+ db,
308
+ { jsonlPath: path, interface: interfaceOption(args, "codex") },
309
+ deps,
310
+ );
311
+ return ok([
312
+ count
313
+ ? `Backfilled 1 Codex session from ${path}`
314
+ : `No new Codex session backfilled from ${path}`,
315
+ ]);
316
+ }
317
+
318
+ default:
319
+ return ok([]);
320
+ }
321
+ }
@@ -0,0 +1,259 @@
1
+ // The conversation-logger composition root (CV22.DS7.US10 slice F).
2
+ //
3
+ // Everything the `conversation-logger` subcommands need beyond the database
4
+ // is assembled here, once per invocation, from an EXPLICIT environment: the
5
+ // clock and id generator, the transcript/session resolution inputs, the Pi
6
+ // sessions directory, the pre-write backup, and -- only for the subcommands
7
+ // that cross the LLM close tail -- the replay providers and the maintenance
8
+ // dependencies built on them.
9
+ //
10
+ // The providers are loaded lazily. `diagnose-journeys`, `backfill-codex-session`,
11
+ // or `session-start --fast` must never fail because a replay fixture is not
12
+ // configured, and `switch` or `session-end` must fail loudly (and fall back
13
+ // to Python at the routing layer) when it is not: "unconfigured installs keep
14
+ // Python fallback" is the plan's live-cutover boundary, and this is where it
15
+ // is enforced on the TypeScript side.
16
+ //
17
+ // Nothing here reads `process.env` or `os.homedir()`; the front door passes
18
+ // them in, which is what keeps every test of this module hermetic.
19
+
20
+ import { backfillPiSessions, homeBornAt, resolvePiSessionsDir } from "#conversation/backfill.ts";
21
+ import { createCloseHooks, maybeGenerateTitle } from "#conversation/closeTail.ts";
22
+ import { runConversationExtraction } from "#conversation/extraction.ts";
23
+ import { runExtractionWithAccounting } from "#conversation/extractionRun.ts";
24
+ import { type CloseHooks, endConversation, type LoggerDeps } from "#conversation/logger.ts";
25
+ import type { MaintenanceDeps } from "#conversation/sessionComposites.ts";
26
+ import type { WritableDatabase } from "#db/database.ts";
27
+ import { logLlmCall } from "#observability/llmCalls.ts";
28
+ import {
29
+ resolveExtractionMaxAttempts,
30
+ resolveExtractionModel,
31
+ resolveMaintenanceMaxExtractions,
32
+ resolveSummarizeEnabled,
33
+ resolveTwoPassEnabled,
34
+ } from "#providers/config.ts";
35
+ import { computeCost } from "#providers/cost.ts";
36
+ import type { EmbeddingProvider } from "#providers/embedding.ts";
37
+ import { resolveFamilyProviders } from "#providers/familyProviders.ts";
38
+ import type { LlmProvider, LlmResponse } from "#providers/llm.ts";
39
+ import {
40
+ CONVERSATION_TAIL_TRANSPORT,
41
+ type ProviderTransportMode,
42
+ resolveProviderTransport,
43
+ } from "#providers/transport.ts";
44
+
45
+ /** The environment names the logger runtime reads. */
46
+ export type LoggerRuntimeEnv = {
47
+ MIRROR_SESSION_ID?: string;
48
+ CLAUDE_PROJECT_DIR?: string;
49
+ PI_SESSIONS_DIR?: string;
50
+ MIRROR_TS_CONVERSATION_LLM_REPLAY?: string;
51
+ MIRROR_TS_CONVERSATION_EMBEDDING_REPLAY?: string;
52
+ /** Read by the live providers when the close tail runs against a real model. */
53
+ OPENROUTER_API_KEY?: string;
54
+ MEMORY_LLM_TIMEOUT_EXTRACTION?: string;
55
+ MEMORY_LLM_MAX_RETRIES?: string;
56
+ MEMORY_EMBEDDING_MODEL?: string;
57
+ MEMORY_SUMMARIZE?: string;
58
+ MEMORY_TWO_PASS?: string;
59
+ MEMORY_MAINTENANCE_MAX_EXTRACTIONS?: string;
60
+ MEMORY_EXTRACTION_MAX_ATTEMPTS?: string;
61
+ MEMORY_EXTRACTION_MODEL?: string;
62
+ };
63
+
64
+ export interface LoggerRuntimeOptions {
65
+ db: WritableDatabase;
66
+ mirrorHome: string;
67
+ homeDir: string;
68
+ env: LoggerRuntimeEnv;
69
+ deps: LoggerDeps;
70
+ /**
71
+ * Live provider factory, injectable for tests (CV22.DS8.US2).
72
+ *
73
+ * `loadLlm`/`loadEmbeddings` below are REPLAY-path loaders and are not
74
+ * consulted in live mode, so without this seam no test could exercise the
75
+ * close tail against a failing or instrumented live provider -- which is the
76
+ * behavior this story exists to change.
77
+ */
78
+ liveProviders?: (env: LoggerRuntimeEnv) => {
79
+ llm: LlmProvider;
80
+ embeddings: EmbeddingProvider;
81
+ };
82
+ /** Provider loaders, injectable for tests; default to the replay fixtures. */
83
+ loadLlm?: (path: string) => Promise<LlmProvider>;
84
+ loadEmbeddings?: (path: string) => Promise<EmbeddingProvider>;
85
+ /** Monotonic seconds for the maintenance report; defaults to `performance.now()`. */
86
+ monotonic?: () => number;
87
+ /**
88
+ * The dated zip backup `repair-journeys --apply` gates on (CV22.DS7.TS1).
89
+ * Prints its progress through `stdout` and returns the archive path, or
90
+ * null on failure. Absent (tests, unwired callers) means the repair refuses,
91
+ * exactly as Python refuses when `backup()` returns None.
92
+ */
93
+ backup?: (stdout: (line: string) => void) => string | null;
94
+ }
95
+
96
+ export interface LoggerRuntime {
97
+ readonly deps: LoggerDeps;
98
+ readonly mirrorHome: string;
99
+ readonly homeDir: string;
100
+ readonly claudeProjectDir: string | null;
101
+ readonly environmentSessionId: string | null;
102
+ readonly piSessionsDir: string;
103
+ /** Which transport answers the close tail here: replay, incomplete replay, or live. */
104
+ readonly transportMode: ProviderTransportMode;
105
+ /** The close hooks (extraction + finalization) behind the replay transport. */
106
+ closeHooks(): Promise<CloseHooks>;
107
+ /** The full maintenance wiring, including the real Pi backfill. */
108
+ maintenanceDeps(): Promise<MaintenanceDeps>;
109
+ /** The dated zip backup for the mutating journey repair; see `LoggerRuntimeOptions.backup`. */
110
+ readonly backup: ((stdout: (line: string) => void) => string | null) | null;
111
+ }
112
+
113
+ /**
114
+ * Adapt the close tail's PAIR-shaped live seam to the factory's per-kind
115
+ * overrides, memoized so one invocation builds one pair.
116
+ *
117
+ * The pair shape is load-bearing for tests: an atomicity test that fails the
118
+ * embedding on the second memory needs the same provider objects the close
119
+ * tail will call. Absent, the factory's own live defaults apply -- the default
120
+ * is not duplicated here.
121
+ */
122
+ function liveTailOverrides(
123
+ env: LoggerRuntimeEnv,
124
+ liveProviders: LoggerRuntimeOptions["liveProviders"],
125
+ ): { liveLlm?: () => LlmProvider; liveEmbedding?: () => EmbeddingProvider } {
126
+ if (!liveProviders) return {};
127
+ let pair: { llm: LlmProvider; embeddings: EmbeddingProvider } | null = null;
128
+ const build = () => {
129
+ pair ??= liveProviders(env);
130
+ return pair;
131
+ };
132
+ return { liveLlm: () => build().llm, liveEmbedding: () => build().embeddings };
133
+ }
134
+
135
+ export function createLoggerRuntime(options: LoggerRuntimeOptions): LoggerRuntime {
136
+ const { db, env, deps } = options;
137
+ const piSessionsDir = resolvePiSessionsDir(null, env, options.homeDir);
138
+
139
+ // One precedence, shared with the router so the two cannot disagree about
140
+ // which transport is live: replay -> incomplete -> live. The pair rule that
141
+ // used to live here is now in the spec itself (CR077), so the router and
142
+ // this runtime refuse a half-configured fixture with the same reason.
143
+ const transport = resolveProviderTransport(env, CONVERSATION_TAIL_TRANSPORT);
144
+
145
+ let providers: Promise<{ llm: LlmProvider; embeddings: EmbeddingProvider }> | null = null;
146
+ const loadProviders = () => {
147
+ providers ??= resolveFamilyProviders(env, CONVERSATION_TAIL_TRANSPORT, {
148
+ loadReplayLlm: options.loadLlm,
149
+ loadReplayEmbedding: options.loadEmbeddings,
150
+ ...liveTailOverrides(env, options.liveProviders),
151
+ }).then((family) => {
152
+ // The factory declares both kinds for this family, so both are present
153
+ // by construction.
154
+ const llm = family.llm;
155
+ const embeddings = family.embedding;
156
+ if (!llm || !embeddings) {
157
+ throw new Error("the conversation close tail requires an LLM and an embedding provider");
158
+ }
159
+ return { llm, embeddings };
160
+ });
161
+ return providers;
162
+ };
163
+
164
+ // Python's `_make_logger(role, conversation_id)`: one ledger row per
165
+ // successful close-tail call, priced through the cost authority exactly as
166
+ // `build_llm_logger` prices it (CV22.DS8.US2).
167
+ //
168
+ // This is the sibling of `extraction.ts`'s llmLedger and was missed when
169
+ // that one was fixed: the close-tail METADATA roles (title, tags, summary)
170
+ // log through here, so they carried token counts and a null cost while the
171
+ // extraction roles were priced. Found by the live smoke on real data, not by
172
+ // a test -- under replay no usage comes back, so both look identical.
173
+ const ledger = (role: string, response: LlmResponse, conversationId: string, prompt: string) => {
174
+ const model = response.model ?? resolveExtractionModel({ env });
175
+ logLlmCall(
176
+ db,
177
+ {
178
+ role,
179
+ model,
180
+ prompt,
181
+ response: response.content,
182
+ promptTokens: response.promptTokens ?? null,
183
+ completionTokens: response.completionTokens ?? null,
184
+ latencyMs: response.latencyMs ?? null,
185
+ costUsd: computeCost(
186
+ model,
187
+ response.promptTokens ?? null,
188
+ response.completionTokens ?? null,
189
+ ),
190
+ conversationId,
191
+ },
192
+ { now: deps.nowIso },
193
+ );
194
+ };
195
+
196
+ const maxAttempts = resolveExtractionMaxAttempts({ env });
197
+ const runExtraction = async (database: WritableDatabase, conversationId: string) => {
198
+ const { llm, embeddings } = await loadProviders();
199
+ await runExtractionWithAccounting(
200
+ database,
201
+ conversationId,
202
+ (innerDb, id) =>
203
+ runConversationExtraction(innerDb, id, {
204
+ llm,
205
+ embeddings,
206
+ now: deps.nowIso,
207
+ id: deps.newId,
208
+ summarize: resolveSummarizeEnabled({ env }),
209
+ twoPass: resolveTwoPassEnabled({ env }),
210
+ ledger: true,
211
+ }),
212
+ maxAttempts,
213
+ );
214
+ };
215
+
216
+ const closeHooks = async (): Promise<CloseHooks> => {
217
+ const { llm } = await loadProviders();
218
+ return createCloseHooks({ llm, onLlmCall: ledger, now: deps.nowIso, runExtraction });
219
+ };
220
+
221
+ return {
222
+ deps,
223
+ mirrorHome: options.mirrorHome,
224
+ homeDir: options.homeDir,
225
+ claudeProjectDir: env.CLAUDE_PROJECT_DIR || null,
226
+ environmentSessionId: env.MIRROR_SESSION_ID?.trim() || null,
227
+ piSessionsDir,
228
+ transportMode: transport.mode,
229
+ backup: options.backup ?? null,
230
+ closeHooks,
231
+ async maintenanceDeps(): Promise<MaintenanceDeps> {
232
+ const { llm } = await loadProviders();
233
+ const hooks = createCloseHooks({ llm, onLlmCall: ledger, now: deps.nowIso, runExtraction });
234
+ return {
235
+ closeConversation: (database, conversationId) =>
236
+ endConversation(database, conversationId, { extract: true }, deps, hooks),
237
+ retitleConversation: (database, conversationId) =>
238
+ maybeGenerateTitle(database, conversationId, {
239
+ llm,
240
+ onLlmCall: ledger,
241
+ now: deps.nowIso,
242
+ source: "startup_maintenance",
243
+ }),
244
+ runExtraction,
245
+ // CR121: only the sessions newer than this home; its birth is read from
246
+ // the ledger once per maintenance run, and an unknown birth is an error.
247
+ backfillPiSessions: (database) =>
248
+ backfillPiSessions(
249
+ database,
250
+ { sessionsDir: piSessionsDir, notBefore: homeBornAt(database) },
251
+ deps,
252
+ ),
253
+ extractionLimit: resolveMaintenanceMaxExtractions({ env }),
254
+ monotonic: options.monotonic,
255
+ now: deps.nowIso,
256
+ };
257
+ },
258
+ };
259
+ }