mirror-mind 0.0.1 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/.claude/hooks/log-session-end.sh +85 -0
  2. package/.claude/hooks/log-user-prompt.sh +85 -0
  3. package/.claude/hooks/mirror-inject.sh +85 -0
  4. package/.claude/hooks/session-start.sh +85 -0
  5. package/.gemini/hooks/log-assistant.sh +85 -0
  6. package/.gemini/hooks/log-user.sh +85 -0
  7. package/.gemini/hooks/session-end.sh +85 -0
  8. package/.gemini/hooks/session-start.sh +85 -0
  9. package/.pi/extensions/mirror-logger.ts +561 -0
  10. package/.pi/skills/mm-backup/SKILL.md +21 -0
  11. package/.pi/skills/mm-build/SKILL.md +1206 -0
  12. package/.pi/skills/mm-consolidate/SKILL.md +112 -0
  13. package/.pi/skills/mm-consult/SKILL.md +70 -0
  14. package/.pi/skills/mm-conversations/SKILL.md +16 -0
  15. package/.pi/skills/mm-discard/SKILL.md +39 -0
  16. package/.pi/skills/mm-explore/SKILL.md +255 -0
  17. package/.pi/skills/mm-help/SKILL.md +74 -0
  18. package/.pi/skills/mm-identity/SKILL.md +96 -0
  19. package/.pi/skills/mm-journal/SKILL.md +16 -0
  20. package/.pi/skills/mm-journey/SKILL.md +23 -0
  21. package/.pi/skills/mm-journeys/SKILL.md +15 -0
  22. package/.pi/skills/mm-memories/SKILL.md +17 -0
  23. package/.pi/skills/mm-mirror/SKILL.md +98 -0
  24. package/.pi/skills/mm-mute/SKILL.md +18 -0
  25. package/.pi/skills/mm-new/SKILL.md +18 -0
  26. package/.pi/skills/mm-recall/SKILL.md +17 -0
  27. package/.pi/skills/mm-release-notes/SKILL.md +52 -0
  28. package/.pi/skills/mm-seed/SKILL.md +19 -0
  29. package/.pi/skills/mm-shadow/SKILL.md +117 -0
  30. package/.pi/skills/mm-soul/SKILL.md +502 -0
  31. package/.pi/skills/mm-tasks/SKILL.md +24 -0
  32. package/.pi/skills/mm-update/SKILL.md +32 -0
  33. package/.pi/skills/mm-week/SKILL.md +28 -0
  34. package/.pi/skills/mm-welcome/SKILL.md +24 -0
  35. package/AGENTS.md +188 -0
  36. package/README.md +126 -9
  37. package/bin/loader.js +67 -0
  38. package/bin/mirror-hook.js +7 -0
  39. package/bin/mirror.js +7 -0
  40. package/docs/releases/index.md +99 -0
  41. package/docs/releases/pending-cutoffs.md +510 -0
  42. package/docs/releases/v0.10.0.md +123 -0
  43. package/docs/releases/v0.10.1.md +66 -0
  44. package/docs/releases/v0.10.10.md +51 -0
  45. package/docs/releases/v0.10.11.md +39 -0
  46. package/docs/releases/v0.10.12.md +57 -0
  47. package/docs/releases/v0.10.13.md +35 -0
  48. package/docs/releases/v0.10.14.md +42 -0
  49. package/docs/releases/v0.10.15.md +53 -0
  50. package/docs/releases/v0.10.16.md +35 -0
  51. package/docs/releases/v0.10.17.md +43 -0
  52. package/docs/releases/v0.10.2.md +64 -0
  53. package/docs/releases/v0.10.3.md +78 -0
  54. package/docs/releases/v0.10.4.md +42 -0
  55. package/docs/releases/v0.10.5.md +57 -0
  56. package/docs/releases/v0.10.6.md +47 -0
  57. package/docs/releases/v0.10.7.md +53 -0
  58. package/docs/releases/v0.10.8.md +49 -0
  59. package/docs/releases/v0.10.9.md +37 -0
  60. package/docs/releases/v0.11.0.md +86 -0
  61. package/docs/releases/v0.12.0.md +67 -0
  62. package/docs/releases/v0.13.0.md +64 -0
  63. package/docs/releases/v0.14.0.md +68 -0
  64. package/docs/releases/v0.15.0.md +48 -0
  65. package/docs/releases/v0.16.0.md +50 -0
  66. package/docs/releases/v0.16.1.md +55 -0
  67. package/docs/releases/v0.16.2.md +36 -0
  68. package/docs/releases/v0.17.0.md +50 -0
  69. package/docs/releases/v0.17.1.md +58 -0
  70. package/docs/releases/v0.17.2.md +42 -0
  71. package/docs/releases/v0.17.3.md +58 -0
  72. package/docs/releases/v0.18.0.md +84 -0
  73. package/docs/releases/v0.18.1.md +51 -0
  74. package/docs/releases/v0.18.2.md +69 -0
  75. package/docs/releases/v0.19.0.md +85 -0
  76. package/docs/releases/v0.19.1.md +46 -0
  77. package/docs/releases/v0.20.0.md +85 -0
  78. package/docs/releases/v0.21.0.md +61 -0
  79. package/docs/releases/v0.21.1.md +47 -0
  80. package/docs/releases/v0.22.0.md +77 -0
  81. package/docs/releases/v0.22.1.md +42 -0
  82. package/docs/releases/v0.23.0.md +105 -0
  83. package/docs/releases/v0.24.0.md +125 -0
  84. package/docs/releases/v0.25.0.md +107 -0
  85. package/docs/releases/v0.26.0.md +139 -0
  86. package/docs/releases/v0.26.1.md +65 -0
  87. package/docs/releases/v0.26.2.md +43 -0
  88. package/docs/releases/v0.27.0.md +63 -0
  89. package/docs/releases/v0.28.0.md +59 -0
  90. package/docs/releases/v0.29.0.md +61 -0
  91. package/docs/releases/v0.29.1.md +59 -0
  92. package/docs/releases/v0.29.2.md +59 -0
  93. package/docs/releases/v0.29.3.md +93 -0
  94. package/docs/releases/v0.30.0.md +75 -0
  95. package/docs/releases/v0.30.1.md +93 -0
  96. package/docs/releases/v0.30.2.md +66 -0
  97. package/docs/releases/v0.31.0.md +122 -0
  98. package/docs/releases/v0.31.1.md +142 -0
  99. package/docs/releases/v0.31.10.md +118 -0
  100. package/docs/releases/v0.31.11.md +88 -0
  101. package/docs/releases/v0.31.12.md +105 -0
  102. package/docs/releases/v0.31.13.md +99 -0
  103. package/docs/releases/v0.31.14.md +97 -0
  104. package/docs/releases/v0.31.2.md +115 -0
  105. package/docs/releases/v0.31.3.md +142 -0
  106. package/docs/releases/v0.31.4.md +117 -0
  107. package/docs/releases/v0.31.5.md +155 -0
  108. package/docs/releases/v0.31.6.md +132 -0
  109. package/docs/releases/v0.31.7.md +132 -0
  110. package/docs/releases/v0.31.8.md +120 -0
  111. package/docs/releases/v0.31.9.md +120 -0
  112. package/docs/releases/v0.32.0.md +261 -0
  113. package/docs/releases/v0.32.1.md +59 -0
  114. package/docs/releases/v0.8.0.md +118 -0
  115. package/docs/releases/v0.9.0.md +98 -0
  116. package/docs/releases/v0.9.1.md +83 -0
  117. package/package.json +102 -6
  118. package/plugins/mirror-mind/.claude-plugin/plugin.json +13 -0
  119. package/plugins/mirror-mind/hooks/hooks.json +50 -0
  120. package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
  121. package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
  122. package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
  123. package/plugins/mirror-mind/hooks/session-start.sh +98 -0
  124. package/plugins/mirror-mind/mcp/launch.sh +52 -0
  125. package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
  126. package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
  127. package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
  128. package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
  129. package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
  130. package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
  131. package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
  132. package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
  133. package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
  134. package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
  135. package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
  136. package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
  137. package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
  138. package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +65 -0
  139. package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
  140. package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
  141. package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
  142. package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
  143. package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
  144. package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
  145. package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
  146. package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
  147. package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
  148. package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
  149. package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
  150. package/scripts/codex-hooks/session-end.sh +85 -0
  151. package/scripts/codex-hooks/session-start.sh +85 -0
  152. package/scripts/codex-mirror.sh +48 -0
  153. package/templates/identity/README.md +119 -0
  154. package/templates/identity/ego/behavior.yaml +52 -0
  155. package/templates/identity/ego/constraints.yaml +15 -0
  156. package/templates/identity/ego/identity.yaml +43 -0
  157. package/templates/identity/journeys/personal-growth.yaml +39 -0
  158. package/templates/identity/organization/identity.yaml +24 -0
  159. package/templates/identity/organization/principles.yaml +17 -0
  160. package/templates/identity/personas/coach.yaml +94 -0
  161. package/templates/identity/personas/designer.yaml +93 -0
  162. package/templates/identity/personas/doctor.yaml +96 -0
  163. package/templates/identity/personas/engineer.yaml +77 -0
  164. package/templates/identity/personas/financial.yaml +97 -0
  165. package/templates/identity/personas/prompt-engineer.yaml +122 -0
  166. package/templates/identity/personas/researcher.yaml +88 -0
  167. package/templates/identity/personas/strategist.yaml +91 -0
  168. package/templates/identity/personas/teacher.yaml +95 -0
  169. package/templates/identity/personas/therapist.yaml +91 -0
  170. package/templates/identity/personas/thinker.yaml +74 -0
  171. package/templates/identity/personas/writer.yaml +76 -0
  172. package/templates/identity/self/config.yaml +16 -0
  173. package/templates/identity/self/soul.yaml +105 -0
  174. package/templates/identity/user/identity.yaml +30 -0
  175. package/ts/src/backup/staging.ts +62 -0
  176. package/ts/src/backup/zipBackup.ts +267 -0
  177. package/ts/src/backup/zipReader.ts +109 -0
  178. package/ts/src/backup/zipWriter.ts +148 -0
  179. package/ts/src/builder/activeCheckpoint.ts +134 -0
  180. package/ts/src/builder/aggregateStatus.ts +34 -0
  181. package/ts/src/builder/approve.ts +149 -0
  182. package/ts/src/builder/argv.ts +292 -0
  183. package/ts/src/builder/ariadMethod.ts +536 -0
  184. package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
  185. package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
  186. package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
  187. package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
  188. package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
  189. package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
  190. package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
  191. package/ts/src/builder/artifacts/storyFiles.ts +61 -0
  192. package/ts/src/builder/artifacts/storyIndex.ts +166 -0
  193. package/ts/src/builder/cadence.ts +59 -0
  194. package/ts/src/builder/card.ts +192 -0
  195. package/ts/src/builder/checkpointRefused.ts +66 -0
  196. package/ts/src/builder/closure.ts +964 -0
  197. package/ts/src/builder/commands.ts +2053 -0
  198. package/ts/src/builder/cursorPosition.ts +176 -0
  199. package/ts/src/builder/cursorTransitions.ts +77 -0
  200. package/ts/src/builder/deliveryCursor.ts +577 -0
  201. package/ts/src/builder/deliveryStoryClosure.ts +521 -0
  202. package/ts/src/builder/deliveryStoryPlan.ts +536 -0
  203. package/ts/src/builder/deliveryStoryReady.ts +160 -0
  204. package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
  205. package/ts/src/builder/expand.ts +336 -0
  206. package/ts/src/builder/flowUnit.ts +339 -0
  207. package/ts/src/builder/homeSurface.ts +122 -0
  208. package/ts/src/builder/implementationGuard.ts +125 -0
  209. package/ts/src/builder/index.ts +11 -0
  210. package/ts/src/builder/lifecycleRefusal.ts +92 -0
  211. package/ts/src/builder/lifecycleRibbon.ts +159 -0
  212. package/ts/src/builder/load.ts +313 -0
  213. package/ts/src/builder/methodAdoption.ts +113 -0
  214. package/ts/src/builder/methodDefinition.ts +429 -0
  215. package/ts/src/builder/methodInspection.ts +371 -0
  216. package/ts/src/builder/plan.ts +408 -0
  217. package/ts/src/builder/planPreauthorization.ts +265 -0
  218. package/ts/src/builder/prepare.ts +225 -0
  219. package/ts/src/builder/projectPaths.ts +64 -0
  220. package/ts/src/builder/pull.ts +356 -0
  221. package/ts/src/builder/pullCandidates.ts +463 -0
  222. package/ts/src/builder/pullCandidatesRender.ts +238 -0
  223. package/ts/src/builder/refinementField.ts +93 -0
  224. package/ts/src/builder/releaseIntent.ts +173 -0
  225. package/ts/src/builder/resumeState.ts +84 -0
  226. package/ts/src/builder/resumeSurface.ts +149 -0
  227. package/ts/src/builder/roadmapGrammar.ts +300 -0
  228. package/ts/src/builder/roadmapScan.ts +97 -0
  229. package/ts/src/builder/roadmapScope.ts +210 -0
  230. package/ts/src/builder/scopePhrases.ts +146 -0
  231. package/ts/src/builder/storyPaths.ts +196 -0
  232. package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
  233. package/ts/src/builder/surfaceProtocol.ts +42 -0
  234. package/ts/src/builder/templateGeneration.ts +148 -0
  235. package/ts/src/builder/transition.ts +178 -0
  236. package/ts/src/consult/args.ts +99 -0
  237. package/ts/src/consult/core.ts +122 -0
  238. package/ts/src/consult/modelCatalog.ts +55 -0
  239. package/ts/src/consult/render.ts +47 -0
  240. package/ts/src/conversation/append.ts +414 -0
  241. package/ts/src/conversation/backfill.ts +387 -0
  242. package/ts/src/conversation/closeTail.ts +467 -0
  243. package/ts/src/conversation/extraction.ts +333 -0
  244. package/ts/src/conversation/extractionDriver.ts +130 -0
  245. package/ts/src/conversation/extractionRun.ts +70 -0
  246. package/ts/src/conversation/journeyInference.ts +165 -0
  247. package/ts/src/conversation/journeyRepair.ts +114 -0
  248. package/ts/src/conversation/lifecycleFaces.ts +197 -0
  249. package/ts/src/conversation/lifecycleWrites.ts +313 -0
  250. package/ts/src/conversation/listing.ts +77 -0
  251. package/ts/src/conversation/logger.ts +576 -0
  252. package/ts/src/conversation/loggerCli.ts +282 -0
  253. package/ts/src/conversation/loggerRuntime.ts +259 -0
  254. package/ts/src/conversation/metadataLifecycle.ts +443 -0
  255. package/ts/src/conversation/recall.ts +66 -0
  256. package/ts/src/conversation/sessionComposites.ts +258 -0
  257. package/ts/src/conversation/sessionImport.ts +90 -0
  258. package/ts/src/conversation/transcriptBackfill.ts +141 -0
  259. package/ts/src/cultivation/applyActions.ts +241 -0
  260. package/ts/src/cultivation/cluster.ts +86 -0
  261. package/ts/src/cultivation/consolidationStore.ts +281 -0
  262. package/ts/src/cultivation/promptContext.ts +62 -0
  263. package/ts/src/cultivation/propose.ts +305 -0
  264. package/ts/src/cultivation/scan.ts +155 -0
  265. package/ts/src/db/backupGate.ts +47 -0
  266. package/ts/src/db/bootstrap.ts +108 -0
  267. package/ts/src/db/bootstrapLock.ts +223 -0
  268. package/ts/src/db/copyGuard.ts +60 -0
  269. package/ts/src/db/database.ts +397 -0
  270. package/ts/src/db/decode.ts +66 -0
  271. package/ts/src/db/ftsIntegrity.ts +41 -0
  272. package/ts/src/db/migrateOnOpen.ts +214 -0
  273. package/ts/src/db/migrations.ts +576 -0
  274. package/ts/src/db/readyOnOpen.ts +35 -0
  275. package/ts/src/db/rowDecode.ts +42 -0
  276. package/ts/src/db/schema.ts +432 -0
  277. package/ts/src/db/schemaInventory.ts +225 -0
  278. package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
  279. package/ts/src/db/schemaState.ts +91 -0
  280. package/ts/src/db/schemaTsDivergence.ts +114 -0
  281. package/ts/src/descriptor/descriptorRead.ts +49 -0
  282. package/ts/src/docs/docsLint.ts +265 -0
  283. package/ts/src/explorer/handoff.ts +522 -0
  284. package/ts/src/explorer/render.ts +335 -0
  285. package/ts/src/explorer/story.ts +769 -0
  286. package/ts/src/explorer/transition.ts +72 -0
  287. package/ts/src/extensions/bindings.ts +170 -0
  288. package/ts/src/extensions/catalog.ts +249 -0
  289. package/ts/src/extensions/catalogCommands.ts +513 -0
  290. package/ts/src/extensions/catalogWrites.ts +652 -0
  291. package/ts/src/extensions/contextRuntime.ts +325 -0
  292. package/ts/src/extensions/dispatch.ts +374 -0
  293. package/ts/src/extensions/errors.ts +24 -0
  294. package/ts/src/extensions/manifest.ts +356 -0
  295. package/ts/src/extensions/migrations.ts +350 -0
  296. package/ts/src/extraction/conversation.ts +304 -0
  297. package/ts/src/extraction/conversationMetadata.ts +206 -0
  298. package/ts/src/extraction/fencing.ts +106 -0
  299. package/ts/src/extraction/json.ts +17 -0
  300. package/ts/src/extraction/prompts.ts +470 -0
  301. package/ts/src/frontDoor/args.ts +30 -0
  302. package/ts/src/frontDoor/argvShape.ts +106 -0
  303. package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
  304. package/ts/src/frontDoor/buildRoute.ts +398 -0
  305. package/ts/src/frontDoor/cli.ts +1865 -0
  306. package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
  307. package/ts/src/frontDoor/consultRoute.ts +50 -0
  308. package/ts/src/frontDoor/contentTailRoute.ts +239 -0
  309. package/ts/src/frontDoor/conversationLoggerRoute.ts +73 -0
  310. package/ts/src/frontDoor/cultivationRoute.ts +210 -0
  311. package/ts/src/frontDoor/dbPath.ts +131 -0
  312. package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
  313. package/ts/src/frontDoor/exploreRoute.ts +572 -0
  314. package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
  315. package/ts/src/frontDoor/frontDoorLog.ts +57 -0
  316. package/ts/src/frontDoor/identityWrite.ts +36 -0
  317. package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
  318. package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
  319. package/ts/src/frontDoor/liveBackup.ts +100 -0
  320. package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
  321. package/ts/src/frontDoor/namedRefusal.ts +35 -0
  322. package/ts/src/frontDoor/nodeSupport.ts +24 -0
  323. package/ts/src/frontDoor/render/consolidate.ts +199 -0
  324. package/ts/src/frontDoor/render/conversations.ts +33 -0
  325. package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
  326. package/ts/src/frontDoor/render/descriptor.ts +20 -0
  327. package/ts/src/frontDoor/render/detectPersona.ts +50 -0
  328. package/ts/src/frontDoor/render/icons.ts +13 -0
  329. package/ts/src/frontDoor/render/identity.ts +59 -0
  330. package/ts/src/frontDoor/render/identityRows.ts +17 -0
  331. package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
  332. package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
  333. package/ts/src/frontDoor/render/journeys.ts +79 -0
  334. package/ts/src/frontDoor/render/list.ts +41 -0
  335. package/ts/src/frontDoor/render/memories.ts +67 -0
  336. package/ts/src/frontDoor/render/recall.ts +49 -0
  337. package/ts/src/frontDoor/render/shadow.ts +155 -0
  338. package/ts/src/frontDoor/render/tasks.ts +99 -0
  339. package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
  340. package/ts/src/frontDoor/render/week.ts +113 -0
  341. package/ts/src/frontDoor/routing.ts +999 -0
  342. package/ts/src/frontDoor/runtimeRoute.ts +623 -0
  343. package/ts/src/frontDoor/searchRoute.ts +166 -0
  344. package/ts/src/frontDoor/seedPaths.ts +98 -0
  345. package/ts/src/frontDoor/soulRoute.ts +433 -0
  346. package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
  347. package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
  348. package/ts/src/frontDoor/usage.ts +176 -0
  349. package/ts/src/guards/claudePlugin.ts +252 -0
  350. package/ts/src/guards/packContents.ts +306 -0
  351. package/ts/src/guards/piSourcedSkills.ts +70 -0
  352. package/ts/src/guards/retiredRouteShadows.ts +57 -0
  353. package/ts/src/guards/retiredSurfaces.ts +564 -0
  354. package/ts/src/hooks/claude.ts +176 -0
  355. package/ts/src/hooks/codex.ts +45 -0
  356. package/ts/src/hooks/gemini.ts +126 -0
  357. package/ts/src/hooks/main.ts +109 -0
  358. package/ts/src/hooks/mirrorState.ts +71 -0
  359. package/ts/src/hooks/payload.ts +68 -0
  360. package/ts/src/hooks/runtime.ts +159 -0
  361. package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
  362. package/ts/src/identity/descriptorGenerate.ts +162 -0
  363. package/ts/src/identity/identityEdit.ts +143 -0
  364. package/ts/src/identity/identityKey.ts +77 -0
  365. package/ts/src/identity/identityRead.ts +69 -0
  366. package/ts/src/identity/identityStore.ts +80 -0
  367. package/ts/src/identity/journeyListing.ts +53 -0
  368. package/ts/src/identity/personaInspect.ts +44 -0
  369. package/ts/src/identity/personaListing.ts +37 -0
  370. package/ts/src/identity/setIdentity.ts +64 -0
  371. package/ts/src/index.ts +231 -0
  372. package/ts/src/init/init.ts +111 -0
  373. package/ts/src/journey/journeyOptions.ts +131 -0
  374. package/ts/src/journey/journeyRemoval.ts +158 -0
  375. package/ts/src/journey/journeyStatus.ts +149 -0
  376. package/ts/src/journey/journeySyncFile.ts +87 -0
  377. package/ts/src/journey/journeyWrite.ts +203 -0
  378. package/ts/src/journey/parentJourney.ts +41 -0
  379. package/ts/src/journey/validateParentJourney.ts +55 -0
  380. package/ts/src/mcp/boundary.ts +151 -0
  381. package/ts/src/mcp/guards.ts +244 -0
  382. package/ts/src/mcp/main.ts +121 -0
  383. package/ts/src/mcp/payload.ts +141 -0
  384. package/ts/src/mcp/protocol.ts +141 -0
  385. package/ts/src/mcp/readModels.ts +241 -0
  386. package/ts/src/mcp/registry.ts +201 -0
  387. package/ts/src/mcp/serve.ts +120 -0
  388. package/ts/src/mcp/tools/deterministic.ts +137 -0
  389. package/ts/src/mcp/tools/providerCrossing.ts +187 -0
  390. package/ts/src/mcp/wire.ts +8 -0
  391. package/ts/src/memory/journal.ts +180 -0
  392. package/ts/src/memory/listing.ts +107 -0
  393. package/ts/src/memory/memoryWrite.ts +88 -0
  394. package/ts/src/memory/reinforcement.ts +35 -0
  395. package/ts/src/mirror/context.ts +161 -0
  396. package/ts/src/mirror/defaultResolution.ts +199 -0
  397. package/ts/src/mirror/orchestration.ts +364 -0
  398. package/ts/src/mirror/reception.ts +194 -0
  399. package/ts/src/mirror/render.ts +75 -0
  400. package/ts/src/mirror/runtimeSession.ts +205 -0
  401. package/ts/src/mode/operatingMode.ts +148 -0
  402. package/ts/src/observability/callOutcome.ts +115 -0
  403. package/ts/src/observability/inspectLedger.ts +329 -0
  404. package/ts/src/observability/ledgerHooks.ts +126 -0
  405. package/ts/src/observability/llmCalls.ts +154 -0
  406. package/ts/src/persona/detectPersona.ts +81 -0
  407. package/ts/src/planning/promptAssembly.ts +111 -0
  408. package/ts/src/planning/weekPending.ts +81 -0
  409. package/ts/src/planning/weekPlan.ts +183 -0
  410. package/ts/src/planning/weekSave.ts +117 -0
  411. package/ts/src/providers/config.ts +189 -0
  412. package/ts/src/providers/cost.ts +64 -0
  413. package/ts/src/providers/credits.ts +204 -0
  414. package/ts/src/providers/embedding.ts +321 -0
  415. package/ts/src/providers/familyProviders.ts +147 -0
  416. package/ts/src/providers/llm.ts +334 -0
  417. package/ts/src/providers/openrouter.ts +244 -0
  418. package/ts/src/providers/redaction.ts +110 -0
  419. package/ts/src/providers/replay.ts +15 -0
  420. package/ts/src/providers/transport.ts +410 -0
  421. package/ts/src/repair/encodingRepair.ts +253 -0
  422. package/ts/src/runtime/backup.ts +151 -0
  423. package/ts/src/runtime/channel.ts +146 -0
  424. package/ts/src/runtime/config.ts +168 -0
  425. package/ts/src/runtime/diagnose.ts +686 -0
  426. package/ts/src/runtime/git.ts +510 -0
  427. package/ts/src/runtime/installKind.ts +220 -0
  428. package/ts/src/runtime/migrate.ts +154 -0
  429. package/ts/src/runtime/packageIdentity.ts +102 -0
  430. package/ts/src/runtime/releaseNotes.ts +244 -0
  431. package/ts/src/runtime/status.ts +557 -0
  432. package/ts/src/runtime/strategies/clone.ts +200 -0
  433. package/ts/src/runtime/strategies/package.ts +328 -0
  434. package/ts/src/runtime/treeRoot.ts +30 -0
  435. package/ts/src/runtime/update.ts +445 -0
  436. package/ts/src/runtime/updateGate.ts +40 -0
  437. package/ts/src/runtime/updatePipeline.ts +159 -0
  438. package/ts/src/runtime/version.ts +36 -0
  439. package/ts/src/runtime/wiring.ts +130 -0
  440. package/ts/src/search/memorySearch.ts +338 -0
  441. package/ts/src/search/ranker.ts +154 -0
  442. package/ts/src/seed/seed.ts +256 -0
  443. package/ts/src/seed/seedYaml.ts +133 -0
  444. package/ts/src/soul/apply.ts +218 -0
  445. package/ts/src/soul/harvest.ts +267 -0
  446. package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
  447. package/ts/src/soul/prompts/soul_self_voice.md +219 -0
  448. package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
  449. package/ts/src/soul/prompts.ts +85 -0
  450. package/ts/src/soul/render.ts +358 -0
  451. package/ts/src/soul/state.ts +212 -0
  452. package/ts/src/soul/transition.ts +37 -0
  453. package/ts/src/tasks/journeyPathParse.ts +113 -0
  454. package/ts/src/tasks/taskImportSync.ts +142 -0
  455. package/ts/src/tasks/taskStore.ts +312 -0
  456. package/ts/src/tasks/weekView.ts +120 -0
  457. package/ts/src/util/clipCodePoints.ts +26 -0
  458. package/ts/src/util/paths.ts +63 -0
  459. package/ts/src/util/program.ts +9 -0
  460. package/ts/src/util/pyGenerators.ts +144 -0
  461. package/ts/src/util/pythonText.ts +317 -0
  462. package/ts/src/util/semver.ts +45 -0
  463. package/ts/src/util/shellWord.ts +25 -0
  464. package/ts/src/util/slug.ts +64 -0
  465. package/ts/src/welcome/card.ts +339 -0
  466. package/ts/src/welcome/statusLine.ts +101 -0
  467. package/ts/src/welcome/updateCache.ts +129 -0
@@ -0,0 +1,445 @@
1
+ // `runtime update` — the pipeline body, run once for either install kind.
2
+ // (CV22.DS10.US2; one body over two strategies since CV22.DS10.US3 plateau 4,
3
+ // debt D-026.)
4
+ //
5
+ // Everything structural lives elsewhere: the stage vocabulary, the render, and
6
+ // the strategy seam in `updatePipeline.ts`, the gate in `updateGate.ts`, the
7
+ // git verbs and the clone strategy in `strategies/clone.ts`, the npm verbs and
8
+ // the package strategy in `strategies/package.ts`, the install answer in
9
+ // `installKind.ts`. This module is the ORDER those are used in, and the two
10
+ // places the redesign departs from the oracle:
11
+ //
12
+ // 1. `capture` is a stage. The oracle reads `previous_commit` as a side
13
+ // effect of the status report; here it is recorded deliberately, before
14
+ // anything can move, because the recovery block is only as useful as that
15
+ // value and `apply` must be unreachable without it.
16
+ //
17
+ // 2. `migrate` and `validate` run in FRESH PROCESSES on the code that was
18
+ // just installed. The oracle migrates in-process, with the modules it
19
+ // imported before the fast-forward -- so a migration authored in the new
20
+ // commit is invisible to the very run that installed it.
21
+ //
22
+ // A LANE is a list of steps. The ordinary lane is the whole promise; the
23
+ // repair lane is the smallest safe act that can make a broken updater usable
24
+ // again -- no status gate (the status is what is broken), no backup, no
25
+ // migrations (the new code owns those on the next ordinary run). The lane is
26
+ // chosen once, below; no step asks which lane it is in.
27
+
28
+ import { spawnSync } from "node:child_process";
29
+ import { verifyBackupArchive } from "#runtime/backup.ts";
30
+ import type { InstallKind } from "#runtime/installKind.ts";
31
+ import { cloneStrategy, defaultGitRunner, type GitRunner } from "#runtime/strategies/clone.ts";
32
+ import { defaultNpmRunner, type NpmRunner, packageStrategy } from "#runtime/strategies/package.ts";
33
+ import type { statusAllowsUpdatePreflight } from "#runtime/updateGate.ts";
34
+ import {
35
+ type ApplyStrategy,
36
+ stage,
37
+ type UpdateResult,
38
+ type UpdateStage,
39
+ } from "#runtime/updatePipeline.ts";
40
+ import { commandOnPath } from "#util/paths.ts";
41
+ import { PROGRAM } from "#util/program.ts";
42
+ import { shellWord } from "#util/shellWord.ts";
43
+
44
+ /** Runs the FRONT DOOR again, on the code now installed. */
45
+ export type UpdateSpawn = (argv: readonly string[]) => {
46
+ code: number;
47
+ stdout: string;
48
+ stderr: string;
49
+ };
50
+
51
+ export interface UpdateDeps {
52
+ install: InstallKind;
53
+ /** `origin/<channel>` for a clone; null for a package, which has no upstream. */
54
+ upstream: string | null;
55
+ channel: string;
56
+ mirrorHome: string | null;
57
+ /** The status report, re-read after apply through a fresh process. */
58
+ statusReady: () => { ready: boolean; detail: string };
59
+ gate: () => ReturnType<typeof statusAllowsUpdatePreflight> & { ready: boolean };
60
+ createBackup: () => string | null;
61
+ /**
62
+ * Injected like every other seam so the pipeline's ORDER can be driven
63
+ * without real archives. The default is the real verifier -- the stage is
64
+ * worthless if it can be satisfied by anything cheaper.
65
+ */
66
+ verifyBackup?: (path: string) => { valid: boolean; note: string | null };
67
+ git?: GitRunner;
68
+ spawnFrontDoor: UpdateSpawn;
69
+ fetch?: boolean;
70
+ migrate?: boolean;
71
+ /** Plan only: report what WOULD happen and touch nothing. */
72
+ dryRun?: boolean;
73
+ /**
74
+ * The self-repair lane. A minimal gate (readable checkout, upstream, clean
75
+ * tree), fast-forward, migrations SKIPPED, and an instruction to rerun
76
+ * `runtime update` with the repaired updater. It exists for the failure the
77
+ * ordinary gate cannot survive: an updater too broken to evaluate its own
78
+ * status, which is why entering it must not depend on that status.
79
+ */
80
+ repair?: boolean;
81
+ /** Why the repair lane was entered, when it was entered automatically. */
82
+ repairReason?: string;
83
+ /** The npm seam, injected for the same reason the git one is. */
84
+ npm?: NpmRunner;
85
+ }
86
+
87
+ /** One update in flight: what the steps have learned so far. */
88
+ interface Run {
89
+ readonly deps: UpdateDeps;
90
+ readonly strategy: ApplyStrategy;
91
+ readonly stages: UpdateStage[];
92
+ previousRef: string | null;
93
+ /** What `plan` found to apply; set only on an `ahead` outcome. */
94
+ target: string | null;
95
+ dryRunDetail: string | null;
96
+ backupPath: string | null;
97
+ newRef: string | null;
98
+ changes: string[];
99
+ }
100
+
101
+ /** A step either ends the run with a result or lets the next step run. */
102
+ type Step = (run: Run) => UpdateResult | null;
103
+
104
+ function failed(run: Run, recovery: string[]): UpdateResult {
105
+ return {
106
+ stages: run.stages,
107
+ previousRef: run.previousRef,
108
+ newRef: run.newRef,
109
+ backupPath: run.backupPath,
110
+ success: false,
111
+ recovery,
112
+ installedChanges: [],
113
+ };
114
+ }
115
+
116
+ function succeeded(run: Run): UpdateResult {
117
+ return {
118
+ stages: run.stages,
119
+ previousRef: run.previousRef,
120
+ newRef: run.newRef,
121
+ backupPath: run.backupPath,
122
+ success: true,
123
+ recovery: [],
124
+ installedChanges: run.changes,
125
+ };
126
+ }
127
+
128
+ /** The ref `capture` recorded. A step that needs it runs after `capture` by construction. */
129
+ function captured(run: Run): string {
130
+ if (run.previousRef === null) throw new Error("capture must run before this stage");
131
+ return run.previousRef;
132
+ }
133
+
134
+ function backupLine(run: Run): string[] {
135
+ return run.backupPath ? [`Backup: ${run.backupPath}`] : [];
136
+ }
137
+
138
+ // --- the steps ---------------------------------------------------------------
139
+
140
+ const statusGate: Step = (run) => {
141
+ const verdict = run.deps.gate();
142
+ if (verdict.ready) {
143
+ run.stages.push(stage("status gate", "pass"));
144
+ return null;
145
+ }
146
+ if (!verdict.allowed) {
147
+ run.stages.push(stage("status gate", "fail", "runtime status is not ready"));
148
+ return failed(run, [
149
+ "Run: runtime diagnose",
150
+ "Resolve the reported drift, then retry runtime update.",
151
+ ]);
152
+ }
153
+ run.stages.push(stage("status gate", "pass", `update-safe preflight drift (${verdict.detail})`));
154
+ return null;
155
+ };
156
+
157
+ const repairPreflight: Step = (run) => {
158
+ run.stages.push(
159
+ stage("repair preflight", "pass", run.deps.repairReason ?? "requested with --repair-updater"),
160
+ );
161
+ const verdict = run.strategy.repairGate();
162
+ if (verdict.ok) return null;
163
+ run.stages.push(stage("repair preflight", "fail", verdict.detail));
164
+ return failed(run, verdict.recovery);
165
+ };
166
+
167
+ const capture: Step = (run) => {
168
+ const outcome = run.strategy.capture();
169
+ if (!outcome.ok) {
170
+ run.stages.push(stage("capture", "fail", outcome.detail));
171
+ return failed(run, outcome.recovery);
172
+ }
173
+ run.previousRef = outcome.ref;
174
+ run.stages.push(stage("capture", "pass", outcome.detail));
175
+ return null;
176
+ };
177
+
178
+ const fetch: Step = (run) => {
179
+ const fetchUpstream = run.strategy.fetch;
180
+ if (fetchUpstream === undefined) return null;
181
+ if (run.deps.fetch === false) {
182
+ run.stages.push(stage("fetch", "skip", "--no-fetch"));
183
+ return null;
184
+ }
185
+ const outcome = fetchUpstream();
186
+ if (!outcome.ok) {
187
+ run.stages.push(stage("fetch", "fail", outcome.detail));
188
+ return failed(run, outcome.recovery);
189
+ }
190
+ run.stages.push(stage("fetch", "pass", outcome.detail));
191
+ return null;
192
+ };
193
+
194
+ const plan: Step = (run) => {
195
+ const outcome = run.strategy.plan(captured(run));
196
+ if (outcome.kind === "blocked") {
197
+ run.stages.push(stage("plan", "fail", outcome.detail));
198
+ return failed(run, outcome.recovery);
199
+ }
200
+ run.stages.push(stage("plan", "pass", outcome.detail));
201
+ if (outcome.kind === "current") {
202
+ // Nothing to do, and nothing was archived to find that out.
203
+ run.newRef = run.previousRef;
204
+ return succeeded(run);
205
+ }
206
+ run.target = outcome.target;
207
+ run.dryRunDetail = outcome.dryRun;
208
+ return null;
209
+ };
210
+
211
+ const dryRunStop: Step = (run) => {
212
+ if (run.deps.dryRun !== true) return null;
213
+ // Everything above this line is read-only. Stopping here is the whole
214
+ // promise of a dry run: the stages a real run would take next are named,
215
+ // not performed.
216
+ run.stages.push(stage("backup", "skip", "dry run"));
217
+ run.stages.push(stage("verify backup", "skip", "dry run"));
218
+ run.stages.push(stage(run.strategy.applyStage, "skip", run.dryRunDetail ?? "dry run"));
219
+ run.stages.push(stage("migrate", "skip", "dry run"));
220
+ run.stages.push(stage("post-update status", "skip", "dry run"));
221
+ return succeeded(run);
222
+ };
223
+
224
+ const backupAndVerify: Step = (run) => {
225
+ const home = run.deps.mirrorHome ?? "<mirror home>";
226
+ let backupPath: string | null;
227
+ try {
228
+ backupPath = run.deps.createBackup();
229
+ } catch (error) {
230
+ run.stages.push(
231
+ stage("backup", "fail", error instanceof Error ? error.message : String(error)),
232
+ );
233
+ return failed(run, [`Backup directory must be writable: ${home}`]);
234
+ }
235
+ if (backupPath === null) {
236
+ run.stages.push(stage("backup", "fail", "database not found"));
237
+ return failed(run, [`Expected a database under: ${home}`]);
238
+ }
239
+ run.backupPath = backupPath;
240
+ run.stages.push(stage("backup", "pass", backupPath));
241
+
242
+ const verification = (run.deps.verifyBackup ?? verifyBackupArchive)(backupPath);
243
+ if (!verification.valid) {
244
+ run.stages.push(stage("verify backup", "fail", verification.note ?? "invalid backup"));
245
+ return failed(run, [
246
+ `Backup created but failed verification: ${backupPath}`,
247
+ "Inspect the archive before retrying runtime update; nothing has moved.",
248
+ ]);
249
+ }
250
+ run.stages.push(stage("verify backup", "pass"));
251
+ return null;
252
+ };
253
+
254
+ const skipBackup: Step = (run) => {
255
+ run.stages.push(stage("backup", "skip", "repair lane"));
256
+ return null;
257
+ };
258
+
259
+ /** The first irreversible step. */
260
+ const apply: Step = (run) => {
261
+ const previousRef = captured(run);
262
+ if (run.target === null) throw new Error("plan must name a target before apply");
263
+ const outcome = run.strategy.apply(previousRef, run.target);
264
+ if (!outcome.ok) {
265
+ run.stages.push(stage(run.strategy.applyStage, "fail", outcome.detail));
266
+ return failed(run, [
267
+ ...outcome.recovery,
268
+ ...backupLine(run),
269
+ `Recover with: ${run.strategy.recoveryCommand(previousRef)}`,
270
+ ]);
271
+ }
272
+ run.newRef = outcome.newRef;
273
+ run.changes = outcome.changes;
274
+ run.stages.push(stage(run.strategy.applyStage, "pass", outcome.detail));
275
+ return null;
276
+ };
277
+
278
+ /** Fresh process, NEW code. */
279
+ const migrate: Step = (run) => {
280
+ if (run.deps.migrate === false) {
281
+ run.stages.push(stage("migrate", "skip", "--skip-migrations"));
282
+ return null;
283
+ }
284
+ const home = run.deps.mirrorHome;
285
+ const result = run.deps.spawnFrontDoor(
286
+ home ? ["runtime", "migrate", "--mirror-home", home] : ["runtime", "migrate"],
287
+ );
288
+ if (result.code !== 0) {
289
+ run.stages.push(stage("migrate", "fail", firstLine(result.stderr || result.stdout)));
290
+ return failed(run, [
291
+ ...backupLine(run),
292
+ `${run.strategy.installedState(run.newRef)}; the database may be partly migrated.`,
293
+ `Restore the database from the backup, then: ${run.strategy.recoveryCommand(captured(run))}`,
294
+ ]);
295
+ }
296
+ run.stages.push(stage("migrate", "pass", migrateSummary(result.stdout)));
297
+ return null;
298
+ };
299
+
300
+ const skipMigrate: Step = (run) => {
301
+ run.stages.push(stage("migrate", "skip", "repair lane: the ordinary update owns migrations"));
302
+ return null;
303
+ };
304
+
305
+ /** Fresh process: the verdict comes from the code that was just installed. */
306
+ const validate: Step = (run) => {
307
+ const post = run.deps.statusReady();
308
+ if (!post.ready) {
309
+ run.stages.push(stage("post-update status", "fail", post.detail));
310
+ return failed(run, [
311
+ `${run.strategy.installedState(run.newRef)} and the database may be migrated.`,
312
+ ...backupLine(run),
313
+ "Run: runtime diagnose",
314
+ ]);
315
+ }
316
+ run.stages.push(stage("post-update status", "pass"));
317
+ return null;
318
+ };
319
+
320
+ // --- the lanes ---------------------------------------------------------------
321
+
322
+ const ORDINARY_LANE: readonly Step[] = [
323
+ statusGate,
324
+ capture,
325
+ fetch,
326
+ plan,
327
+ dryRunStop,
328
+ backupAndVerify,
329
+ apply,
330
+ migrate,
331
+ validate,
332
+ ];
333
+
334
+ const REPAIR_LANE: readonly Step[] = [
335
+ repairPreflight,
336
+ capture,
337
+ fetch,
338
+ plan,
339
+ dryRunStop,
340
+ skipBackup,
341
+ apply,
342
+ skipMigrate,
343
+ ];
344
+
345
+ function strategyFor(deps: UpdateDeps, install: Exclude<InstallKind, { kind: "unknown" }>) {
346
+ if (install.kind === "package") {
347
+ return packageStrategy(install, deps.channel, deps.npm ?? defaultNpmRunner);
348
+ }
349
+ return cloneStrategy(
350
+ install.repository,
351
+ deps.upstream ?? `origin/${deps.channel}`,
352
+ deps.git ?? defaultGitRunner,
353
+ );
354
+ }
355
+
356
+ export function runUpdate(deps: UpdateDeps): UpdateResult {
357
+ const stages: UpdateStage[] = [];
358
+ if (deps.install.kind === "unknown") {
359
+ stages.push(stage("status gate", "fail", `install kind unknown: ${deps.install.reason}`));
360
+ return {
361
+ stages,
362
+ previousRef: null,
363
+ newRef: null,
364
+ backupPath: null,
365
+ success: false,
366
+ recovery: [
367
+ "Mirror could not identify how it is installed, so it will not update itself.",
368
+ "A git checkout updates in place; a global npm install updates through npm.",
369
+ ],
370
+ installedChanges: [],
371
+ };
372
+ }
373
+
374
+ const run: Run = {
375
+ deps,
376
+ strategy: strategyFor(deps, deps.install),
377
+ stages,
378
+ previousRef: null,
379
+ target: null,
380
+ dryRunDetail: null,
381
+ backupPath: null,
382
+ newRef: null,
383
+ changes: [],
384
+ };
385
+ const lane = deps.repair === true ? REPAIR_LANE : ORDINARY_LANE;
386
+ for (const step of lane) {
387
+ const result = step(run);
388
+ if (result !== null) return result;
389
+ }
390
+ return succeeded(run);
391
+ }
392
+
393
+ /**
394
+ * What to say after the stages, when the update itself has nothing more to
395
+ * say. One case today (CV22.DS10.US3 plateau 4): a clone whose PATH does not
396
+ * reach `mirror`. Every skill invokes that name, and a checkout provides it
397
+ * only after `npm link` has run once at its root -- the seam every clone user
398
+ * crosses once, at the update that brought the skills saying it. A package
399
+ * put `mirror` on the PATH by being installed; a failed update's last words
400
+ * are its recovery block.
401
+ */
402
+ export function postUpdateHints(
403
+ install: InstallKind,
404
+ result: UpdateResult,
405
+ env: NodeJS.ProcessEnv,
406
+ canExecute?: (path: string) => boolean,
407
+ ): string[] {
408
+ if (install.kind !== "clone" || !result.success) return [];
409
+ if (commandOnPath(PROGRAM, env, canExecute) !== null) return [];
410
+ // A command the person will paste: the path is one shell word (CR104).
411
+ return [
412
+ `\`${PROGRAM}\` is not on the PATH: run \`npm link\` once in ${shellWord(install.repository)}, so the skills can call it.`,
413
+ ];
414
+ }
415
+
416
+ function firstLine(text: string): string {
417
+ return text.trim().split("\n")[0] ?? "migration failed";
418
+ }
419
+
420
+ /** The one line from `runtime migrate`'s render worth carrying into a stage. */
421
+ function migrateSummary(stdout: string): string {
422
+ const match = /^Migrate result: (.+)$/m.exec(stdout);
423
+ return match?.[1] ?? "completed";
424
+ }
425
+
426
+ /**
427
+ * Spawn the front door again, inheriting the environment explicitly. `entry`
428
+ * is the bin that loads it, not the `.ts` file: see the route's `spawner`.
429
+ */
430
+ export function frontDoorSpawner(entry: string, env: NodeJS.ProcessEnv): UpdateSpawn {
431
+ return (argv) => {
432
+ const result = spawnSync(process.execPath, [entry, ...argv], {
433
+ encoding: "utf8",
434
+ // A spawned front door does NOT inherit `--env-file`; the variables it
435
+ // needs are passed explicitly or it resolves a different home than the
436
+ // process that launched it.
437
+ env: { ...env, NODE_OPTIONS: env.NODE_OPTIONS ?? "--no-warnings" },
438
+ });
439
+ return {
440
+ code: result.status ?? -1,
441
+ stdout: result.stdout ?? "",
442
+ stderr: result.stderr ?? "",
443
+ };
444
+ };
445
+ }
@@ -0,0 +1,40 @@
1
+ // The pre-update status gate (CV22.DS10.US2).
2
+ //
3
+ // Port of `_status_allows_update_preflight`, kept as a pure function of the
4
+ // status report because it is the single most consequential decision the
5
+ // updater makes: whether to touch the tree at all.
6
+ //
7
+ // The relaxed lane is narrow ON PURPOSE, and the oracle's docstring says why:
8
+ // the updater must not let old code block the very update that would teach it
9
+ // about a newer migration. So core-migration ledger drift -- and ONLY that --
10
+ // may pass a non-ready status, because the update still backs up before it
11
+ // migrates and still requires a ready status afterwards. Everything else
12
+ // (dirty tree, missing database, unready extension, unresolvable home) fails.
13
+
14
+ import type { RuntimeStatusReport } from "#runtime/status.ts";
15
+
16
+ export interface GateVerdict {
17
+ allowed: boolean;
18
+ detail: string;
19
+ }
20
+
21
+ export function statusAllowsUpdatePreflight(report: RuntimeStatusReport): GateVerdict {
22
+ if (report.mirror_home_error) return { allowed: false, detail: report.mirror_home_error };
23
+ if (report.git.error) return { allowed: false, detail: report.git.error };
24
+ if (report.git.dirty) return { allowed: false, detail: "git tree is dirty" };
25
+ if (report.db_exists !== true) return { allowed: false, detail: "database missing" };
26
+ if (report.extension_health.some((item) => !item.ready)) {
27
+ return { allowed: false, detail: "extension health is not ready" };
28
+ }
29
+
30
+ const core = report.core_migrations;
31
+ if (core.ready) return { allowed: true, detail: "runtime status is ready" };
32
+ if (core.note) return { allowed: false, detail: core.note };
33
+
34
+ const parts: string[] = [];
35
+ if (core.missing.length > 0) parts.push(`pending core migrations: ${core.missing.join(", ")}`);
36
+ if (core.unknown.length > 0) parts.push(`unknown core migrations: ${core.unknown.join(", ")}`);
37
+ if (parts.length > 0) return { allowed: true, detail: parts.join("; ") };
38
+
39
+ return { allowed: false, detail: "core migration status is not ready" };
40
+ }
@@ -0,0 +1,159 @@
1
+ // The update pipeline: what Mirror promises when it updates itself.
2
+ // (CV22.DS10.US2)
3
+ //
4
+ // gate -> capture -> plan -> fetch -> backup -> verify -> apply
5
+ // -> migrate -> validate
6
+ //
7
+ // The order is the oracle's, and it is load-bearing in both directions: plan
8
+ // and fetch are cheap and read-only, so they come first and a no-op update
9
+ // never archives the database; `apply` is the first irreversible step, so
10
+ // nothing reaches it until `capture` recorded where to go back to and
11
+ // `verify backup` proved the archive opens.
12
+ //
13
+ // Only `apply` differs between a clone and a package. Everything here is the
14
+ // same for both, which is why it lives in its own module rather than inside
15
+ // either strategy -- and why the seam between the body and a strategy is
16
+ // declared here too (CV22.DS10.US3 plateau 4, debt D-026): the body in
17
+ // `update.ts` runs the order above once, and a strategy answers only the
18
+ // questions whose answer depends on how Mirror was installed.
19
+
20
+ /**
21
+ * The channels an update may follow, for either install kind: `stable` is the
22
+ * promoted release, `main` the development branch. A clone follows
23
+ * `origin/<channel>`; a package follows the dist-tag of the same name.
24
+ */
25
+ export const KNOWN_CHANNELS: ReadonlySet<string> = new Set(["stable", "main"]);
26
+ export const DEFAULT_CHANNEL = "stable";
27
+
28
+ export type StageState = "pass" | "fail" | "skip";
29
+
30
+ export interface UpdateStage {
31
+ name: string;
32
+ state: StageState;
33
+ detail?: string;
34
+ }
35
+
36
+ export interface UpdateResult {
37
+ stages: UpdateStage[];
38
+ /**
39
+ * Where to go back to, read BEFORE anything moved: a commit for a clone, an
40
+ * installed version for a package. The recovery block is only as useful as
41
+ * this value, which is why it is captured in its own stage rather than
42
+ * derived afterwards from a tree that has already changed.
43
+ */
44
+ previousRef: string | null;
45
+ newRef: string | null;
46
+ backupPath: string | null;
47
+ success: boolean;
48
+ recovery: string[];
49
+ installedChanges: string[];
50
+ }
51
+
52
+ export function stage(name: string, state: StageState, detail?: string): UpdateStage {
53
+ return detail === undefined ? { name, state } : { name, state, detail };
54
+ }
55
+
56
+ // --- the strategy seam -------------------------------------------------------
57
+
58
+ /** A step that could not be taken, with the stage detail and the route back. */
59
+ export interface Refusal {
60
+ ok: false;
61
+ detail: string;
62
+ recovery: string[];
63
+ }
64
+
65
+ export type CaptureOutcome = { ok: true; ref: string; detail: string } | Refusal;
66
+ export type FetchOutcome = { ok: true; detail: string } | Refusal;
67
+ export type GateOutcome = { ok: true } | Refusal;
68
+
69
+ export type PlanOutcome =
70
+ /** Nothing to do; the update ends here without archiving anything. */
71
+ | { kind: "current"; detail: string }
72
+ /** Something to apply: `target` is what apply moves to, `dryRun` what a dry run says it would do. */
73
+ | { kind: "ahead"; target: string; detail: string; dryRun: string }
74
+ | { kind: "blocked"; detail: string; recovery: string[] };
75
+
76
+ export type ApplyOutcome =
77
+ | { ok: true; newRef: string | null; detail: string; changes: string[] }
78
+ | Refusal;
79
+
80
+ /**
81
+ * What differs between a clone and a package, and nothing else.
82
+ *
83
+ * The body owns the order, the gate, the dry run, the backup and its
84
+ * verification, the fresh-process migrate and validate, and the recovery
85
+ * block's shape. A strategy owns the meaning of a ref (a commit, a version),
86
+ * how to read it, how to learn whether the channel is ahead, how to move, and
87
+ * the words that name its own apply stage and its way back.
88
+ */
89
+ export interface ApplyStrategy {
90
+ readonly kind: "clone" | "package";
91
+ /** What the render calls the irreversible step: `fast-forward` or `apply`. */
92
+ readonly applyStage: string;
93
+ /**
94
+ * The minimal gate the repair lane runs INSTEAD of the status gate: what
95
+ * must be true of the install itself when the status cannot be trusted.
96
+ */
97
+ repairGate(): GateOutcome;
98
+ /** The ref to go back to, read before anything moves. */
99
+ capture(): CaptureOutcome;
100
+ /** Absent when there is nothing to fetch: a registry is asked at plan time. */
101
+ fetch?(): FetchOutcome;
102
+ plan(previousRef: string): PlanOutcome;
103
+ apply(previousRef: string, target: string): ApplyOutcome;
104
+ /** The pasteable route back, with the captured ref in it. */
105
+ recoveryCommand(previousRef: string): string;
106
+ /** Where the code stands after apply, for the recovery block. */
107
+ installedState(newRef: string | null): string;
108
+ }
109
+
110
+ /** Port of `render_runtime_update_result`, in the redesign's vocabulary. */
111
+ export function renderUpdateResult(result: UpdateResult): string {
112
+ const marks: Record<StageState, string> = { pass: "✓", fail: "✗", skip: "-" };
113
+ const lines: string[] = ["Mirror runtime update", ""];
114
+ for (const entry of result.stages) {
115
+ const mark = marks[entry.state] ?? "?";
116
+ lines.push(
117
+ entry.detail ? `[${mark}] ${entry.name}: ${entry.detail}` : `[${mark}] ${entry.name}`,
118
+ );
119
+ }
120
+ lines.push("");
121
+ if (result.previousRef && result.newRef && result.previousRef !== result.newRef) {
122
+ lines.push(`Previous: ${result.previousRef}`);
123
+ lines.push(`New: ${result.newRef}`);
124
+ }
125
+ if (result.backupPath) lines.push(`Backup: ${result.backupPath}`);
126
+ if (result.installedChanges.length > 0) {
127
+ lines.push("");
128
+ lines.push("Installed changes:");
129
+ for (const change of result.installedChanges) lines.push(`- ${change}`);
130
+ }
131
+ lines.push("");
132
+ if (result.success) {
133
+ lines.push("Update result: success");
134
+ } else {
135
+ lines.push("Update result: failed");
136
+ if (result.recovery.length > 0) {
137
+ lines.push("");
138
+ lines.push("Recovery:");
139
+ for (const entry of result.recovery) lines.push(`- ${entry}`);
140
+ }
141
+ }
142
+ return `${lines.join("\n")}\n`;
143
+ }
144
+
145
+ /**
146
+ * One line per update, for `<mirror-home>/front-door.log`.
147
+ *
148
+ * The log already records every routing decision; an update that moved the
149
+ * tree and migrated the database should not be the one event that leaves no
150
+ * trace. Months later this line is the only evidence of what happened.
151
+ */
152
+ export function updateLogDetail(install: string, channel: string, result: UpdateResult): string {
153
+ const stages = result.stages.map((entry) => `${entry.name}=${entry.state}`).join(",");
154
+ const from = result.previousRef ?? "unknown";
155
+ const to = result.newRef ?? "unchanged";
156
+ return `update install=${install} channel=${channel} ${from}->${to} ${stages} result=${
157
+ result.success ? "success" : "failed"
158
+ }`;
159
+ }
@@ -0,0 +1,36 @@
1
+ // The project's version, read from source.
2
+ //
3
+ // Extracted from `runtime/git.ts` (CV22.DS9.TS2): the MCP server reports this
4
+ // string in `initialize`, and importing the git module -- which spawns
5
+ // `git`, carries network timeouts, and owns the read-only-repository boundary --
6
+ // to learn a version is the wrong dependency direction. `git.ts` re-exports it,
7
+ // so the runtime surface's call sites are unchanged.
8
+
9
+ import { findPackageIdentity } from "./packageIdentity.ts";
10
+
11
+ /**
12
+ * THE product version. One function, read by the updater, the release doctor,
13
+ * the welcome card, and the MCP server, so that npm distribution changes one
14
+ * body and nothing else (CV22.DS10.US2, decision D2).
15
+ *
16
+ * Until CV22.DS10.TS5 this walked upward for `pyproject.toml`'s first
17
+ * `version =` line, a port of `_version_from_pyproject`.
18
+ *
19
+ * **TS5 moves the authority to the TypeScript package** (decision D1). The
20
+ * comment that used to live here said US3 would do it, while the Zero Python
21
+ * gate assigned `pyproject.toml`'s deletion to TS5 -- both could not hold, and
22
+ * a version that reads a file this story deletes would answer `null` and
23
+ * render as `unknown` in the updater, the release doctor, the welcome card,
24
+ * and the MCP handshake.
25
+ *
26
+ * `package.json` therefore carries the real version from now on. US3 still
27
+ * changes exactly one place, which was US2's intent: `PACKAGE_NAME` and the
28
+ * `private` flag.
29
+ */
30
+ export function packageVersion(start: string): string | null {
31
+ const identity = findPackageIdentity(start);
32
+ // A tree that is not ours has no version to report -- the same `null` the
33
+ // pyproject walk returned when it reached the filesystem root.
34
+ if (!identity?.isMirrorMind) return null;
35
+ return identity.version;
36
+ }