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,92 @@
1
+ // CR067 with CR020 — refusals that say where a story's delivery cursor stands.
2
+ //
3
+ // The story lifecycle's guards in `plan.ts` and `closure.ts` each test the cursor's
4
+ // last event by hand. This module states which event completes each step, so a refusal
5
+ // can tell "not reached yet" from "already done". The order those events come in is
6
+ // the table of positions in `cursorPosition.ts` (CR114), which also places the cursor
7
+ // on the ribbon and names what it accepts next. The guards stay as written; a
8
+ // table-driven test runs every step against every event, so the two expressions cannot
9
+ // drift apart.
10
+ //
11
+ // Delivery Story events are outside the order: a cursor holding one gets no
12
+ // already-complete refusal, never a guessed one.
13
+
14
+ import { STORY_LIFECYCLE_EVENTS } from "./cursorPosition.ts";
15
+ import type { BuilderDeliveryCursor } from "./deliveryCursor.ts";
16
+
17
+ /** The story steps a lifecycle command can be refused at. */
18
+ export type LifecycleStep =
19
+ | "prepare"
20
+ | "plan"
21
+ | "plan_approval"
22
+ | "validate"
23
+ | "debt_review"
24
+ | "coherence"
25
+ | "done";
26
+
27
+ /** Why a step was refused. Only `already_complete` is decided by this module. */
28
+ export type RefusalKind =
29
+ | "already_complete"
30
+ | "pending_confirmation"
31
+ | "not_reached"
32
+ | "missing_evidence";
33
+
34
+ const COMPLETING_EVENT: Readonly<Record<LifecycleStep, string>> = {
35
+ // CR114 (D3): Prepare is complete once the cursor reaches Plan; Prepare at Prepare
36
+ // runs again, which rewrites only what Prepare wrote.
37
+ prepare: "plan",
38
+ plan: "plan",
39
+ plan_approval: "plan_approved",
40
+ validate: "validation_passed",
41
+ debt_review: "review_complete",
42
+ coherence: "coherence_complete",
43
+ done: "done_complete",
44
+ };
45
+
46
+ const STEP_NAME: Readonly<Record<LifecycleStep, string>> = {
47
+ prepare: "Prepare",
48
+ plan: "Plan",
49
+ plan_approval: "Plan approval",
50
+ validate: "Validation",
51
+ debt_review: "Debt Review",
52
+ coherence: "Coherence",
53
+ done: "Done",
54
+ };
55
+
56
+ /** True once the cursor has reached or passed the event that completes `step`. */
57
+ export function isAlreadyComplete(step: LifecycleStep, event: string | null): boolean {
58
+ const order = STORY_LIFECYCLE_EVENTS;
59
+ const at = event === null ? -1 : order.indexOf(event);
60
+ return at !== -1 && at >= order.indexOf(COMPLETING_EVENT[step]);
61
+ }
62
+
63
+ /** A lifecycle step refused before any change, with its reason's identity. */
64
+ export class LifecycleRefusal extends Error {
65
+ readonly step: LifecycleStep;
66
+ readonly kind: RefusalKind;
67
+
68
+ constructor(step: LifecycleStep, kind: RefusalKind, message: string) {
69
+ super(message);
70
+ this.name = "LifecycleRefusal";
71
+ this.step = step;
72
+ this.kind = kind;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Throw when `step` is already complete for the cursor's item. Every guard calls this
78
+ * first, so a finished step is never refused with a precondition that holds.
79
+ */
80
+ export function refuseIfAlreadyComplete(
81
+ step: LifecycleStep,
82
+ cursor: Pick<BuilderDeliveryCursor, "activeItem" | "lastDeliveryEvent" | "pendingConfirmation">,
83
+ ): void {
84
+ if (!isAlreadyComplete(step, cursor.lastDeliveryEvent)) return;
85
+ const pending = cursor.pendingConfirmation ? `, pending ${cursor.pendingConfirmation}` : "";
86
+ throw new LifecycleRefusal(
87
+ step,
88
+ "already_complete",
89
+ `${STEP_NAME[step]} is already complete for ${cursor.activeItem}: ` +
90
+ `the cursor is at ${cursor.lastDeliveryEvent}${pending}.`,
91
+ );
92
+ }
@@ -0,0 +1,159 @@
1
+ // CV22.DS7.US8 plateau 2 — the lifecycle progress ribbons.
2
+ //
3
+ // Port of `src/memory/builder/lifecycle_ribbon.py`. Every checkpoint surface
4
+ // prints one of these under its `Delivery` header, so a wrong glyph or a wrong
5
+ // separator is a byte divergence on most of the story's 33 surfaces.
6
+ //
7
+ // Three vocabularies, not one: the Delivery lifecycle, the Refinement Story flow,
8
+ // and the Change Request cycle. Only the first is in this story's scope for
9
+ // rendering, but all three are ported because they share `_render_progress_ribbon`
10
+ // and porting one of three copies of a shared renderer is how the `_wrap_plain_text`
11
+ // divergence happened in Python.
12
+ //
13
+ // An unknown stage RAISES rather than rendering a partial ribbon, and the message
14
+ // names the vocabulary — `unknown Ariad lifecycle stage: x` versus `unknown Ariad
15
+ // Refinement Story stage: x`. That is a Class B refusal with byte-exact text.
16
+ //
17
+ // CR113: a stage the item's level never reaches is drawn `–`, not applicable. A User
18
+ // or Technical Story never expands, and the Delivery ribbon drew its Expand as done
19
+ // once the cursor passed Prepare, and as still to come before. The level is a
20
+ // required argument, so every caller decides; which levels never expand is the
21
+ // runtime's one predicate, `isImplementableByDefault`. A Delivery Story, and a
22
+ // ribbon drawn with no level, look as they always did.
23
+
24
+ import { isImplementableByDefault } from "./cursorTransitions.ts";
25
+
26
+ /** Python `DELIVERY_LIFECYCLE_STAGES`. */
27
+ export const DELIVERY_LIFECYCLE_STAGES = [
28
+ "pull",
29
+ "prepare",
30
+ "expand",
31
+ "plan",
32
+ "implement",
33
+ "validate",
34
+ "debt_review",
35
+ "done",
36
+ ] as const;
37
+
38
+ const DELIVERY_STAGE_LABELS: Record<string, string> = {
39
+ pull: "Pull",
40
+ prepare: "Prepare",
41
+ expand: "Expand",
42
+ plan: "Plan",
43
+ implement: "Implement",
44
+ validate: "Validate",
45
+ debt_review: "Debt Review",
46
+ done: "Done",
47
+ };
48
+
49
+ /** Python `REFINEMENT_STORY_STAGES`. */
50
+ export const REFINEMENT_STORY_STAGES = [
51
+ "pull",
52
+ "select_cr",
53
+ "cr_cycle",
54
+ "review",
55
+ "coherence",
56
+ "close",
57
+ ] as const;
58
+
59
+ const REFINEMENT_STORY_STAGE_LABELS: Record<string, string> = {
60
+ pull: "Pull",
61
+ select_cr: "Select CR",
62
+ cr_cycle: "CR Cycle",
63
+ review: "Review",
64
+ coherence: "Coherence",
65
+ close: "Close",
66
+ };
67
+
68
+ /** Python `CHANGE_REQUEST_STAGES`. */
69
+ export const CHANGE_REQUEST_STAGES = [
70
+ "confirm",
71
+ "plan",
72
+ "implement",
73
+ "validate",
74
+ "done_note",
75
+ ] as const;
76
+
77
+ const CHANGE_REQUEST_STAGE_LABELS: Record<string, string> = {
78
+ confirm: "Confirm",
79
+ plan: "Plan",
80
+ implement: "Implement",
81
+ validate: "Validate",
82
+ done_note: "Done Note",
83
+ };
84
+
85
+ /** The mark for a stage the item's level never reaches (CR113). */
86
+ const NOT_APPLICABLE = "–";
87
+
88
+ /** Python `_render_progress_ribbon`, with the stages an item's level never reaches. */
89
+ function renderProgressRibbon(options: {
90
+ current: string;
91
+ stages: readonly string[];
92
+ labels: Record<string, string>;
93
+ label: string;
94
+ separator: string;
95
+ unknownKind: string;
96
+ notApplicable?: ReadonlySet<string>;
97
+ }): string {
98
+ const { current, stages, labels, label, separator, unknownKind } = options;
99
+ const notApplicable = options.notApplicable ?? new Set<string>();
100
+ const currentIndex = stages.indexOf(current);
101
+ if (currentIndex === -1) {
102
+ throw new Error(`unknown ${unknownKind}: ${current}`);
103
+ }
104
+ const parts = stages.map((stage, index) => {
105
+ const marker = notApplicable.has(stage)
106
+ ? NOT_APPLICABLE
107
+ : index < currentIndex
108
+ ? "✓"
109
+ : index === currentIndex
110
+ ? "◉"
111
+ : "○";
112
+ return `${marker} ${labels[stage]}`;
113
+ });
114
+ return `${label}: ${parts.join(` ${separator} `)}`;
115
+ }
116
+
117
+ /** The Delivery stages an item's level never reaches: Expand, for a story. */
118
+ const STORY_NEVER_REACHES: ReadonlySet<string> = new Set(["expand"]);
119
+
120
+ /**
121
+ * Python `render_lifecycle_ribbon`, told the item's level (CR113). `null` is a
122
+ * ribbon with no item to speak of, drawn as it always was.
123
+ */
124
+ export function renderLifecycleRibbon(current: string, level: string | null): string {
125
+ return renderProgressRibbon({
126
+ current,
127
+ stages: DELIVERY_LIFECYCLE_STAGES,
128
+ labels: DELIVERY_STAGE_LABELS,
129
+ label: "Delivery Flow",
130
+ separator: "→",
131
+ unknownKind: "Ariad lifecycle stage",
132
+ notApplicable:
133
+ level !== null && isImplementableByDefault(level) ? STORY_NEVER_REACHES : undefined,
134
+ });
135
+ }
136
+
137
+ /** Python `render_refinement_lifecycle_ribbon`. */
138
+ export function renderRefinementLifecycleRibbon(current = "pull"): string {
139
+ return renderProgressRibbon({
140
+ current,
141
+ stages: REFINEMENT_STORY_STAGES,
142
+ labels: REFINEMENT_STORY_STAGE_LABELS,
143
+ label: "RS Flow",
144
+ separator: "→",
145
+ unknownKind: "Ariad Refinement Story stage",
146
+ });
147
+ }
148
+
149
+ /** Python `render_change_request_lifecycle_ribbon`. */
150
+ export function renderChangeRequestLifecycleRibbon(current = "confirm"): string {
151
+ return renderProgressRibbon({
152
+ current,
153
+ stages: CHANGE_REQUEST_STAGES,
154
+ labels: CHANGE_REQUEST_STAGE_LABELS,
155
+ label: "CR Cycle",
156
+ separator: "→",
157
+ unknownKind: "Ariad Change Request stage",
158
+ });
159
+ }
@@ -0,0 +1,313 @@
1
+ // CV22.DS7.US8 plateau 7 — `build load`, the last leaf.
2
+ //
3
+ // Port of `cmd_load` in `src/memory/cli/build.py`.
4
+ //
5
+ // This is the command `/mm-build <journey>` runs, in all three runtimes, and the
6
+ // only one in the `build` family that crosses the provider seam: two embeddings
7
+ // for its own searches, plus the previous conversation's close tail through
8
+ // `switchConversation`.
9
+ //
10
+ // ## The ORDER of effects is behavior
11
+ //
12
+ // identity read → clone-role guard → banner (stderr) → transition card → entry
13
+ // surface → identity context → two searches → memories block → sticky defaults →
14
+ // operating-mode row → conversation switch → trailer.
15
+ //
16
+ // A port that writes the mode row before the searches passes every surface golden
17
+ // and changes what a CRASHED `load` leaves behind — which is the state a Navigator
18
+ // meets when a provider is down. Four surfaces print before the first provider
19
+ // call, so the transport decision has to be taken before any of them (the route
20
+ // does that; see `frontDoor/buildRoute.ts` at plateau 8).
21
+ //
22
+ // ## What it does NOT do
23
+ //
24
+ // It never falls back mid-command. If the embedding provider fails, the search
25
+ // degrades to FTS-only and the lifecycle continues: the mode row is still written
26
+ // and the conversation still switches, because in Python those statements simply
27
+ // follow the searches. The degraded card is indistinguishable from a healthy one —
28
+ // reproduced, and carried to Debt Review as a CR rather than marked here.
29
+
30
+ import type { Database, WritableDatabase } from "#db/database.ts";
31
+ import { memoriesById } from "#frontDoor/searchRoute.ts";
32
+ import { getIdentityContent } from "#identity/identityRead.ts";
33
+ import { getProjectPath } from "#journey/journeyStatus.ts";
34
+ import { loadMirrorContext } from "#mirror/context.ts";
35
+ import { persistStickyDefaults } from "#mirror/orchestration.ts";
36
+ import { resolveRuntimeSessionId } from "#mirror/runtimeSession.ts";
37
+ import { activateOperatingMode } from "#mode/operatingMode.ts";
38
+ import { ProviderConfigError } from "#providers/config.ts";
39
+ import type { EmbeddingProvider } from "#providers/embedding.ts";
40
+ import { searchMemoriesWithStatus } from "#search/memorySearch.ts";
41
+ import { PROGRAM } from "#util/program.ts";
42
+ import { shellWord } from "#util/shellWord.ts";
43
+ import { renderBuilderOrientationSurface } from "./homeSurface.ts";
44
+ import { getAdoptedMethod } from "./methodAdoption.ts";
45
+ import { inspectPullCandidates, inspectRoadmapSnapshot } from "./pullCandidates.ts";
46
+ import { renderProjectPositionReport } from "./pullCandidatesRender.ts";
47
+ import { findCanonicalRefinementIndex, inspectRefinementField } from "./refinementField.ts";
48
+ import { readBuilderResumeState } from "./resumeState.ts";
49
+ import { renderBuilderResumeSurface } from "./resumeSurface.ts";
50
+ import { resolveRoadmapScope, scopePullCandidates } from "./roadmapScope.ts";
51
+ import { extractQuery, renderBuilderModeTransition } from "./transition.ts";
52
+
53
+ export interface BuildLoadResult {
54
+ readonly stdout: string;
55
+ readonly stderr: string;
56
+ readonly exitCode: number;
57
+ /** Metadata only, for the front-door log: never the query, never a message. */
58
+ readonly degradedKind?: string;
59
+ /** How many provider calls the command made, for the log's `calls=` field. */
60
+ readonly providerCalls: number;
61
+ }
62
+
63
+ /**
64
+ * What an unconfigured install has instead of a provider.
65
+ *
66
+ * Python has no "absent provider" state: `generate_embedding` raises
67
+ * `RuntimeError` when the key is missing, the search catches it, and the block
68
+ * still renders FTS-only. Returning no results here instead -- which this did
69
+ * until the degraded scenario measured it -- renders an EMPTY memories block on
70
+ * a machine with a working corpus and no key, and does it silently, in the
71
+ * surface a Navigator reads to choose the day's work.
72
+ *
73
+ * `ProviderConfigError` is the right class, not a convenience: it is the one
74
+ * failure that fires no ledger hook, which is how Python prices a missing key
75
+ * too (no call was made, so no row).
76
+ */
77
+ const MISSING_EMBEDDING_PROVIDER: EmbeddingProvider = {
78
+ embed: async () => {
79
+ throw new ProviderConfigError(
80
+ "No embedding provider was supplied to `build load`; the memories block " +
81
+ "degrades to the local FTS index.",
82
+ );
83
+ },
84
+ };
85
+
86
+ export interface BuildLoadDeps {
87
+ readonly nowIso: () => string;
88
+ readonly newId: () => string;
89
+ /** Absent means no provider: the searches degrade to FTS-only, as Python's do. */
90
+ readonly embeddingProvider?: EmbeddingProvider;
91
+ /** Python's `switch_conversation`, injected because it carries the close tail. */
92
+ readonly switchConversation?: (journey: string, sessionId: string | null) => Promise<void>;
93
+ /**
94
+ * `_check_clone_role_guard`'s outcome, injected because its inputs are the
95
+ * MACHINE's -- a git root and a marker file -- and this module is graded as a
96
+ * pure port over a database. `frontDoor/cloneRoleGuard.ts` supplies the real
97
+ * one; the corpus stages a neutral checkout so the guard stays silent.
98
+ *
99
+ * `exitCode: null` is the `--ignore-production-role` case: the warning prints
100
+ * and the session start CONTINUES.
101
+ */
102
+ readonly cloneRoleGuard?: (
103
+ projectPath: string | null,
104
+ ) => { readonly stderr: string; readonly exitCode: number | null } | null;
105
+ }
106
+
107
+ /**
108
+ * Python `_print_builder_entry_surface`.
109
+ *
110
+ * Which surface appears is decided by the CURSOR, not by adoption: an adopted
111
+ * journey whose cursor has neither an active item nor a pending confirmation gets
112
+ * the position report plus `■ BUILDER ORIENTATION`; anything else gets
113
+ * `■ BUILDER RESUME`. Both read the Refinement field from project files only,
114
+ * since CV22.DS10.TS4 retired the Workbench.
115
+ *
116
+ * Exported for the CR114 walk, which compares the list this prints with `build show`'s
117
+ * at every position of a lifecycle.
118
+ */
119
+ export function renderBuilderEntrySurface(
120
+ db: Database,
121
+ slug: string,
122
+ projectPath: string | null,
123
+ ): string {
124
+ const canonicalRefinementIndex = findCanonicalRefinementIndex(projectPath);
125
+ const resumeState = readBuilderResumeState(db, slug);
126
+ const cursor = resumeState.cursor;
127
+ // Every "where are we" and "what next" below is the journey's own (CR002):
128
+ // derived from the cursor these surfaces already render, never from a scan of
129
+ // the whole roadmap.
130
+ const scope = resolveRoadmapScope(projectPath || null, cursor);
131
+ if (cursor && !cursor.activeItem && !cursor.pendingConfirmation) {
132
+ const candidates = inspectPullCandidates(projectPath, { journey: slug, method: "ariad" });
133
+ const view = scopePullCandidates(candidates, scope);
134
+ const roadmap = inspectRoadmapSnapshot(projectPath, { journey: slug, method: "ariad" });
135
+ return `${printed(renderProjectPositionReport(roadmap, { view }))}${renderBuilderOrientationSurface(
136
+ {
137
+ candidates,
138
+ refinement: inspectRefinementField(projectPath),
139
+ cadence: cursor,
140
+ },
141
+ )}`;
142
+ }
143
+ return renderBuilderResumeSurface(resumeState, { scope, canonicalRefinementIndex });
144
+ }
145
+
146
+ /**
147
+ * Python's merge of the two searches: dedupe by id, sort by score, take six.
148
+ *
149
+ * Exported and pure because the FIRST-occurrence rule is not observable through
150
+ * the command in any case the corpus could hold. The same memory is ranked in both
151
+ * searches, but its two scores differ only when MMR's diversity penalty differs
152
+ * between the candidate sets, AND the difference has to invert the relative order
153
+ * of two duplicated ids before the rendered block changes. Mutation testing
154
+ * reported the rule ungraded, two corpus shapes failed to expose it, and inventing
155
+ * a third would have been engineering a case to satisfy a mutant rather than to
156
+ * describe behavior.
157
+ *
158
+ * So it is graded here instead, with hand-built inputs, and the limitation is
159
+ * declared rather than implied — the same treatment plateau 5 gave the CAS
160
+ * conflict branch.
161
+ *
162
+ * Keeping the FIRST occurrence means a duplicated memory carries its SCOPED score,
163
+ * which is the one computed among the journey's own memories.
164
+ */
165
+ export function mergeRankedResults(
166
+ scoped: readonly { id: string; score: number }[],
167
+ global: readonly { id: string; score: number }[],
168
+ limit = 6,
169
+ ): { id: string; score: number }[] {
170
+ const seen = new Set<string>();
171
+ const merged: { id: string; score: number }[] = [];
172
+ for (const result of [...scoped, ...global]) {
173
+ if (seen.has(result.id)) continue;
174
+ seen.add(result.id);
175
+ merged.push({ id: result.id, score: result.score });
176
+ }
177
+ // Python sorts by score DESCENDING with a stable sort, so equal scores keep the
178
+ // scoped-before-global order the merge produced. JavaScript's sort is stable by
179
+ // specification since ES2019, so the comparator alone reproduces it.
180
+ merged.sort((left, right) => right.score - left.score);
181
+ return merged.slice(0, limit);
182
+ }
183
+
184
+ /** Python's `print(...)`: the value plus the newline `print` adds. */
185
+ function printed(text: string): string {
186
+ return `${text}\n`;
187
+ }
188
+
189
+ const BANNER_COLOR = "\u001b[38;5;117m";
190
+ const BANNER_RESET = "\u001b[0m";
191
+
192
+ /** Python `_print_builder_banner`: stderr, ANSI bytes included. */
193
+ function banner(slug: string, projectPath: string | null): string {
194
+ const lines = [`${BANNER_COLOR}⚙ Builder Mode active — journey: ${slug}${BANNER_RESET}`];
195
+ if (projectPath) lines.push(`${BANNER_COLOR} 📁 ${projectPath}${BANNER_RESET}`);
196
+ return lines.map(printed).join("");
197
+ }
198
+
199
+ export interface BuildLoadOptions {
200
+ readonly slug: string;
201
+ readonly sessionId?: string | null;
202
+ readonly environmentSessionId?: string | null;
203
+ }
204
+
205
+ /** Python `cmd_load`. */
206
+ export async function runBuildLoad(
207
+ db: WritableDatabase,
208
+ options: BuildLoadOptions,
209
+ deps: BuildLoadDeps,
210
+ ): Promise<BuildLoadResult> {
211
+ const slug = options.slug;
212
+ const journeyContent = getIdentityContent(db, "journey", slug);
213
+ if (!journeyContent) {
214
+ return {
215
+ stdout: "",
216
+ stderr: printed(`Error: journey '${slug}' not found.`),
217
+ exitCode: 1,
218
+ providerCalls: 0,
219
+ };
220
+ }
221
+ const projectPath = getProjectPath(db, slug);
222
+
223
+ // The clone-role guard runs BEFORE the banner: refusing after it would print a
224
+ // session start the command then abandons.
225
+ //
226
+ // It exits **2**, not 1 -- a usage-level refusal, the class argparse uses --
227
+ // while the unknown-journey refusal above exits 1. The two are one `if` apart
228
+ // and were the same code until the guard was ported and graded.
229
+ const guard = deps.cloneRoleGuard?.(projectPath) ?? null;
230
+ if (guard !== null && guard.exitCode !== null) {
231
+ return { stdout: "", stderr: guard.stderr, exitCode: guard.exitCode, providerCalls: 0 };
232
+ }
233
+
234
+ let stdout = printed(renderBuilderModeTransition({ journey: slug, journeyContent, projectPath }));
235
+ // The override warning precedes the banner, as Python's two `print`s do.
236
+ const stderr = `${guard?.stderr ?? ""}${banner(slug, projectPath)}`;
237
+
238
+ if (getAdoptedMethod(db, slug) === "ariad") {
239
+ stdout += printed(renderBuilderEntrySurface(db, slug, projectPath));
240
+ }
241
+
242
+ stdout += printed(await loadMirrorContext(db, { persona: "engineer", journey: slug }));
243
+
244
+ // The two searches. Python runs them unconditionally and passes `log_access`
245
+ // by default, so this read MUTATES `access_count` on what it returns — which is
246
+ // why a second `load` against the same database legitimately reorders the block.
247
+ const query = extractQuery(journeyContent, slug);
248
+ let providerCalls = 0;
249
+ // `calls=` counts round-trips that REACHED a provider. A missing provider is a
250
+ // configuration failure rather than a call -- Python raises before its attempt
251
+ // loop and writes no ledger row -- so counting it would put a call in the
252
+ // front-door log that no ledger row backs.
253
+ const configured = deps.embeddingProvider !== undefined;
254
+ const provider = deps.embeddingProvider ?? MISSING_EMBEDDING_PROVIDER;
255
+ const runSearch = async (journey?: string) => {
256
+ if (configured) providerCalls += 1;
257
+ return searchMemoriesWithStatus(db, {
258
+ query,
259
+ limit: 5,
260
+ provider,
261
+ ...(journey === undefined ? {} : { journey }),
262
+ });
263
+ };
264
+ const scoped = await runSearch(slug);
265
+ const global = await runSearch();
266
+ const degradedKind = scoped.degradedKind ?? global.degradedKind;
267
+
268
+ // Merge, dedupe by id keeping the FIRST occurrence, then sort by score
269
+ // descending and take six. Python's `sort` is STABLE, so equal scores keep the
270
+ // scoped-before-global order the merge produced.
271
+ const relevant = mergeRankedResults(scoped.results, global.results);
272
+ if (relevant.length > 0) {
273
+ // The ranker returns ids and scores; the rendered block needs the rows, read
274
+ // through the same helper `memories --search` uses.
275
+ const rows = memoriesById(
276
+ db,
277
+ relevant.map((entry) => entry.id),
278
+ );
279
+ stdout += "\n=== recent memories ===\n";
280
+ for (const entry of relevant) {
281
+ const memory = rows.get(entry.id);
282
+ if (memory === undefined) continue;
283
+ stdout += `\n[${memory.layer}] ${memory.title}\n`;
284
+ stdout += printed(memory.content);
285
+ }
286
+ }
287
+
288
+ persistStickyDefaults(db, "engineer", slug, deps.nowIso());
289
+ const resolvedSessionId = resolveRuntimeSessionId(
290
+ db,
291
+ options.sessionId ?? null,
292
+ options.environmentSessionId ?? null,
293
+ );
294
+ activateOperatingMode(
295
+ db,
296
+ { mode: "Builder Mode", journey: slug, sessionId: resolvedSessionId },
297
+ deps.nowIso(),
298
+ );
299
+ await deps.switchConversation?.(slug, resolvedSessionId);
300
+
301
+ stdout += projectPath
302
+ ? `\nproject_path=${projectPath}\n`
303
+ : `\n[Journey '${slug}' has no project_path configured. ` +
304
+ `Run: ${PROGRAM} journey set-path ${shellWord(slug)} /path/to/project]\n`;
305
+
306
+ return {
307
+ stdout,
308
+ stderr,
309
+ exitCode: 0,
310
+ ...(degradedKind === undefined ? {} : { degradedKind }),
311
+ providerCalls,
312
+ };
313
+ }
@@ -0,0 +1,113 @@
1
+ // CV22.DS7.US8 plateau 1 — which Builder method a journey has adopted.
2
+ //
3
+ // Port of `src/memory/builder/method_adoption.py`. All of Builder's state lives
4
+ // in `runtime_sessions` rows keyed by a prefix, and this is the simplest one: a
5
+ // single-field JSON payload under `__builder_method_adoption__:<journey>`.
6
+ //
7
+ // Reader, writer, and clear land TOGETHER even though plateau 1 only needs the
8
+ // read. The rule that keeps D2's revert honest is that a TS write must produce
9
+ // the bytes Python would write for the same state, and splitting a serializer
10
+ // from its parser across plateaus is how that stops being checkable. The
11
+ // delivery cursor stays in plateau 2 because it carries compare-and-swap,
12
+ // generations, and the preauthorization receipt; this row carries one key.
13
+ //
14
+ // Python writes `json.dumps({"method": ...}, ensure_ascii=False)`, which for a
15
+ // single ASCII key is `{"method": "ariad"}` — note the space after the colon,
16
+ // Python's default separator and NOT `JSON.stringify`'s output.
17
+
18
+ import type { Database, WritableDatabase } from "#db/database.ts";
19
+ import { getRuntimeSession, upsertRuntimeSession } from "#mirror/runtimeSession.ts";
20
+ import { pythonJsonDumps } from "#util/pyGenerators.ts";
21
+
22
+ const ADOPTION_SESSION_PREFIX = "__builder_method_adoption__:";
23
+
24
+ /** Python `_session_id`. */
25
+ export function adoptionSessionId(journey: string): string {
26
+ return `${ADOPTION_SESSION_PREFIX}${journey}`;
27
+ }
28
+
29
+ /** Python `_normalize_journey`: strip, and refuse empty. */
30
+ function normalizeJourney(journey: string): string {
31
+ const normalized = typeof journey === "string" ? journey.trim() : "";
32
+ if (!normalized) throw new Error("journey must not be empty");
33
+ return normalized;
34
+ }
35
+
36
+ /** Python `_normalize_method`: strip, and refuse empty. */
37
+ function normalizeMethod(method: string): string {
38
+ const normalized = typeof method === "string" ? method.trim() : "";
39
+ if (!normalized) throw new Error("method must not be empty");
40
+ return normalized;
41
+ }
42
+
43
+ export interface BuilderMethodAdoption {
44
+ readonly journey: string;
45
+ readonly method: string;
46
+ }
47
+
48
+ /**
49
+ * Python `get_adopted_method`: `None` unless the row exists, is active, has
50
+ * metadata, parses as a JSON object, and carries a non-empty string `method`.
51
+ *
52
+ * Every one of those is a silent `None` rather than an error, so a corrupted row
53
+ * reads as "not adopted" instead of failing Builder activation.
54
+ */
55
+ export function getAdoptedMethod(db: Database, journey: string): string | null {
56
+ const normalizedJourney = normalizeJourney(journey);
57
+ const session = getRuntimeSession(db, adoptionSessionId(normalizedJourney));
58
+ if (!session?.active || !session.metadata) return null;
59
+ let data: unknown;
60
+ try {
61
+ data = JSON.parse(session.metadata);
62
+ } catch {
63
+ return null;
64
+ }
65
+ if (typeof data !== "object" || data === null || Array.isArray(data)) return null;
66
+ const method = (data as Record<string, unknown>).method;
67
+ if (typeof method !== "string") return null;
68
+ const normalized = method.trim();
69
+ return normalized || null;
70
+ }
71
+
72
+ /** Python `set_adopted_method`. */
73
+ export function setAdoptedMethod(
74
+ db: WritableDatabase,
75
+ journey: string,
76
+ method: string,
77
+ nowIso: () => string,
78
+ ): BuilderMethodAdoption {
79
+ const normalizedJourney = normalizeJourney(journey);
80
+ const normalizedMethod = normalizeMethod(method);
81
+ upsertRuntimeSession(
82
+ db,
83
+ adoptionSessionId(normalizedJourney),
84
+ {
85
+ interface: "builder_method_adoption",
86
+ journey: normalizedJourney,
87
+ active: true,
88
+ metadata: pythonJsonDumps({ method: normalizedMethod }),
89
+ },
90
+ nowIso(),
91
+ );
92
+ return { journey: normalizedJourney, method: normalizedMethod };
93
+ }
94
+
95
+ /** Python `clear_adopted_method`: deactivate the row and null its metadata. */
96
+ export function clearAdoptedMethod(
97
+ db: WritableDatabase,
98
+ journey: string,
99
+ nowIso: () => string,
100
+ ): void {
101
+ const normalizedJourney = normalizeJourney(journey);
102
+ upsertRuntimeSession(
103
+ db,
104
+ adoptionSessionId(normalizedJourney),
105
+ {
106
+ interface: "builder_method_adoption",
107
+ journey: normalizedJourney,
108
+ active: false,
109
+ metadata: null,
110
+ },
111
+ nowIso(),
112
+ );
113
+ }