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,220 @@
1
+ // Where is this Mirror installed, and what can update it? (CV22.DS10.US2)
2
+ //
3
+ // The updater's first question, answered from where the front door ITSELF
4
+ // lives rather than from configuration. A user who has to tell the updater how
5
+ // they installed Mirror can tell it wrong, and the answer decides whether the
6
+ // next step is `git merge --ff-only` or `npm install -g`.
7
+ //
8
+ // Three answers, and `unknown` is a real one: an install we cannot identify is
9
+ // refused with its reason printed, never updated on a guess.
10
+
11
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
12
+ import { basename, dirname, join, resolve, sep } from "node:path";
13
+
14
+ export type InstallKind =
15
+ | { kind: "clone"; repository: string }
16
+ | { kind: "package"; root: string; name: string; version: string }
17
+ | { kind: "unknown"; reason: string };
18
+
19
+ export interface InstallKindProbe {
20
+ /** The front door's own resolved path. */
21
+ frontDoorPath: string;
22
+ /**
23
+ * `npm root -g`, resolved once by the caller, when the caller needs npm's
24
+ * word that `-g` addresses THIS install: the update lane does. Given as a
25
+ * string, a package must sit inside it. Omitted or `null` (npm not probed,
26
+ * or not available), a package is known by its layout alone -- see
27
+ * `packageByLayout` -- which is what the read-only routes ask, since they
28
+ * run where npm may not be on the PATH and must still say what this is.
29
+ */
30
+ npmRootGlobal?: string | null;
31
+ exists?: (path: string) => boolean;
32
+ readFile?: (path: string) => string;
33
+ /**
34
+ * Symlink resolution for the front door's path. `npm link` places a symlink
35
+ * named like the package under the global root, so a developer's checkout
36
+ * can be reached through a path that looks installed; what is updated must
37
+ * be the tree the file really lives in.
38
+ */
39
+ realpath?: (path: string) => string;
40
+ }
41
+
42
+ /** Is `child` inside `parent`, by path components rather than string prefix? */
43
+ function isInside(parent: string, child: string): boolean {
44
+ const base = resolve(parent);
45
+ const target = resolve(child);
46
+ return target === base || target.startsWith(base.endsWith(sep) ? base : base + sep);
47
+ }
48
+
49
+ /**
50
+ * The git work tree holding this front door, identified by the repository
51
+ * marker this project actually has: a root that carries `package.json` and a
52
+ * `.git` entry (the manifest moved to the root in CV22.DS10.US3, D2). Walking up rather than asking git keeps detection free of a
53
+ * subprocess and of git's own notion of "inside a work tree", which is true in
54
+ * places this updater must not touch (a submodule, a nested checkout).
55
+ */
56
+ function cloneRootFor(startDir: string, exists: (path: string) => boolean): string | null {
57
+ let current = resolve(startDir);
58
+ for (;;) {
59
+ if (exists(join(current, ".git")) && exists(join(current, "package.json"))) {
60
+ return current;
61
+ }
62
+ const parent = dirname(current);
63
+ if (parent === current) return null;
64
+ current = parent;
65
+ }
66
+ }
67
+
68
+ interface Manifest {
69
+ root: string;
70
+ name: string;
71
+ version: string;
72
+ bins: string[];
73
+ }
74
+
75
+ /** The nearest manifest above the front door that names and versions a package. */
76
+ function nearestManifest(
77
+ frontDoorPath: string,
78
+ stopAt: string | null,
79
+ exists: (path: string) => boolean,
80
+ readFile: (path: string) => string,
81
+ ): Manifest | null {
82
+ let current = resolve(dirname(frontDoorPath));
83
+ const stop = stopAt === null ? null : resolve(stopAt);
84
+ for (;;) {
85
+ const manifest = join(current, "package.json");
86
+ if (exists(manifest)) {
87
+ try {
88
+ const parsed = JSON.parse(readFile(manifest)) as {
89
+ name?: unknown;
90
+ version?: unknown;
91
+ bin?: unknown;
92
+ };
93
+ if (typeof parsed.name === "string" && typeof parsed.version === "string") {
94
+ const bins =
95
+ typeof parsed.bin === "string"
96
+ ? [parsed.name]
97
+ : typeof parsed.bin === "object" && parsed.bin !== null
98
+ ? Object.keys(parsed.bin)
99
+ : [];
100
+ return { root: current, name: parsed.name, version: parsed.version, bins };
101
+ }
102
+ } catch {
103
+ // A manifest we cannot read is not a package we should reinstall.
104
+ return null;
105
+ }
106
+ }
107
+ if (current === stop) return null;
108
+ const parent = dirname(current);
109
+ if (parent === current) return null;
110
+ current = parent;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * The installed package holding this front door, by npm's own word: the
116
+ * manifest sits inside `npm root -g`.
117
+ *
118
+ * Being under SOME `node_modules/` is not enough, and the difference matters:
119
+ * a project-local dependency would detect as `package`, and `npm install -g`
120
+ * would then update a completely different tree from the one running. The
121
+ * global root is the evidence that `-g` addresses THIS install, which is why
122
+ * the update lane asks this way.
123
+ */
124
+ function packageUnderNpmRoot(
125
+ frontDoorPath: string,
126
+ npmRootGlobal: string,
127
+ exists: (path: string) => boolean,
128
+ readFile: (path: string) => string,
129
+ realpath: (path: string) => string,
130
+ ): InstallKind | null {
131
+ // Both sides resolved: the front door already is, and npm answers with
132
+ // the prefix as configured, symlinks and all (/tmp on macOS is one).
133
+ const root = realpath(resolve(npmRootGlobal));
134
+ if (!isInside(root, frontDoorPath)) return null;
135
+ const manifest = nearestManifest(frontDoorPath, root, exists, readFile);
136
+ if (manifest === null) return null;
137
+ return { kind: "package", root: manifest.root, name: manifest.name, version: manifest.version };
138
+ }
139
+
140
+ /**
141
+ * The installed package holding this front door, by its layout, with no
142
+ * subprocess: the manifest sits at `<prefix>/lib/node_modules/<name>` -- the
143
+ * global layout npm uses on every platform this core supports -- AND one of
144
+ * the manifest's bins exists at `<prefix>/bin/<bin>` and resolves back into
145
+ * the package. The bin is what makes a global install global; a project that
146
+ * happens to live at `<x>/lib` has the first half and not the second.
147
+ * (CV22.DS10.US3 plateau 4: the read-only routes run where npm may be off
148
+ * the PATH and must still say what this is.)
149
+ */
150
+ function packageByLayout(
151
+ frontDoorPath: string,
152
+ exists: (path: string) => boolean,
153
+ readFile: (path: string) => string,
154
+ realpath: (path: string) => string,
155
+ ): InstallKind | null {
156
+ const manifest = nearestManifest(frontDoorPath, null, exists, readFile);
157
+ if (manifest === null) return null;
158
+ const nodeModules = dirname(manifest.root);
159
+ const lib = dirname(nodeModules);
160
+ if (basename(nodeModules) !== "node_modules" || basename(lib) !== "lib") return null;
161
+ const prefix = dirname(lib);
162
+ const linked = manifest.bins.some((bin) => {
163
+ const link = join(prefix, "bin", bin);
164
+ return exists(link) && isInside(manifest.root, realpath(link));
165
+ });
166
+ if (!linked) return null;
167
+ return { kind: "package", root: manifest.root, name: manifest.name, version: manifest.version };
168
+ }
169
+
170
+ /** `realpathSync`, except that a path that does not exist is returned as given. */
171
+ function safeRealpath(path: string): string {
172
+ try {
173
+ return realpathSync(path);
174
+ } catch {
175
+ return path;
176
+ }
177
+ }
178
+
179
+ export function detectInstallKind(probe: InstallKindProbe): InstallKind {
180
+ const exists = probe.exists ?? existsSync;
181
+ const readFile = probe.readFile ?? ((path: string) => readFileSync(path, "utf8"));
182
+ const realpath = probe.realpath ?? safeRealpath;
183
+ const frontDoorPath = realpath(resolve(probe.frontDoorPath));
184
+
185
+ const asPackage = probe.npmRootGlobal
186
+ ? packageUnderNpmRoot(frontDoorPath, probe.npmRootGlobal, exists, readFile, realpath)
187
+ : packageByLayout(frontDoorPath, exists, readFile, realpath);
188
+ if (asPackage !== null) return asPackage;
189
+
190
+ const repository = cloneRootFor(dirname(frontDoorPath), exists);
191
+ if (repository !== null) return { kind: "clone", repository };
192
+
193
+ return {
194
+ kind: "unknown",
195
+ reason:
196
+ probe.npmRootGlobal === null
197
+ ? "not a git checkout, and npm is unavailable to identify a package install"
198
+ : probe.npmRootGlobal === undefined
199
+ ? "not a git checkout, and not laid out as a global npm install"
200
+ : "not a git checkout, and not under the global npm root",
201
+ };
202
+ }
203
+
204
+ /** One line for a render or a log entry. */
205
+ export function describeInstallKind(install: InstallKind): string {
206
+ if (install.kind === "clone") return `clone (${install.repository})`;
207
+ if (install.kind === "package") return `package (${install.name}@${install.version})`;
208
+ return `unknown (${install.reason})`;
209
+ }
210
+
211
+ /**
212
+ * The install, for `runtime status` and `runtime version`: the kind, and for
213
+ * a package the root `npm install -g` replaces, which its one-line form does
214
+ * not carry (US2 D3, deferred to CV22.DS10.US3 plateau 4).
215
+ */
216
+ export function renderInstallLines(install: InstallKind): string[] {
217
+ const lines = [`Install: ${describeInstallKind(install)}`];
218
+ if (install.kind === "package") lines.push(`Install root: ${install.root}`);
219
+ return lines;
220
+ }
@@ -0,0 +1,154 @@
1
+ // `runtime migrate` — apply pending migrations, and say what the ledger did.
2
+ // (CV22.DS10.US2, decision D8)
3
+ //
4
+ // This verb does not exist on the oracle, and adding it corrects the oracle.
5
+ // Python's updater calls `_apply_migrations` IN-PROCESS, which means it
6
+ // migrates the database with the code it just fast-forwarded away from: the
7
+ // interpreter has already imported the old modules, and a migration authored
8
+ // in the new commit is not among them. The TypeScript updater spawns this verb
9
+ // in a FRESH process after `apply`, so the code that migrates is the code that
10
+ // was just installed.
11
+ //
12
+ // It is also useful on its own, which is why it is a named verb rather than a
13
+ // private argv: when an update fails between `apply` and `migrate`, the
14
+ // operator needs a way to finish the job without running the whole pipeline.
15
+ //
16
+ // The ledger is printed before and after because "migrations: pass" is a claim
17
+ // and the `_migrations` rows are the evidence. A stage that infers a migration
18
+ // from "some command opened the database" is what the Plan review rejected.
19
+
20
+ import { existsSync } from "node:fs";
21
+ import { openDatabaseReadOnly } from "#db/database.ts";
22
+ import { ensureMigratedOnOpen, type MigrateVerdict } from "#db/migrateOnOpen.ts";
23
+
24
+ export interface MigrateOutcome {
25
+ dbPath: string;
26
+ before: string[];
27
+ after: string[];
28
+ applied: string[];
29
+ migrated: boolean;
30
+ /**
31
+ * The verdict, and the whole point of CV22.DS10.US2's debt D-025.
32
+ *
33
+ * There used to be two: migrated, or not. "Not" covered both `nothing
34
+ * pending` and a DECLINED migration, and both rendered as
35
+ * `Migrate result: nothing pending` with exit 0 -- so the updater's migrate
36
+ * stage passed on a database with pending work nothing had applied, on the
37
+ * one command whose job is to leave the database correct after an update.
38
+ */
39
+ verdict: MigrateVerdict;
40
+ /** Why the engine declined, when it did. */
41
+ declinedReason: string | null;
42
+ backupPath: string | null;
43
+ error: string | null;
44
+ }
45
+
46
+ /** Exit code for a declined migration: not success, not a crash. */
47
+ export const MIGRATE_DECLINED_EXIT = 1;
48
+
49
+ /** The `_migrations` ledger, sorted. `null` when it cannot be read at all. */
50
+ export function readLedger(dbPath: string): string[] | null {
51
+ if (!existsSync(dbPath)) return null;
52
+ let db: ReturnType<typeof openDatabaseReadOnly>;
53
+ try {
54
+ db = openDatabaseReadOnly(dbPath);
55
+ } catch {
56
+ return null;
57
+ }
58
+ try {
59
+ const rows = db.prepare("SELECT id FROM _migrations").all() as { id: string }[];
60
+ return rows.map((row) => row.id).sort();
61
+ } catch {
62
+ return null;
63
+ } finally {
64
+ db.close();
65
+ }
66
+ }
67
+
68
+ export function runMigrate(dbPath: string): MigrateOutcome {
69
+ const before = readLedger(dbPath);
70
+ if (before === null) {
71
+ return {
72
+ dbPath,
73
+ before: [],
74
+ after: [],
75
+ applied: [],
76
+ migrated: false,
77
+ verdict: "declined",
78
+ declinedReason: null,
79
+ backupPath: null,
80
+ error: existsSync(dbPath)
81
+ ? "database has no readable migration ledger"
82
+ : `database not found: ${dbPath}`,
83
+ };
84
+ }
85
+
86
+ try {
87
+ const result = ensureMigratedOnOpen(dbPath);
88
+ const after = readLedger(dbPath) ?? before;
89
+ return {
90
+ dbPath,
91
+ before,
92
+ after,
93
+ applied: [...result.appliedIds],
94
+ migrated: result.migrated,
95
+ verdict: result.verdict,
96
+ declinedReason: result.declinedReason ?? null,
97
+ backupPath: result.backupPath ?? null,
98
+ error: null,
99
+ };
100
+ } catch (error) {
101
+ return {
102
+ dbPath,
103
+ before,
104
+ after: readLedger(dbPath) ?? before,
105
+ applied: [],
106
+ migrated: false,
107
+ verdict: "declined",
108
+ declinedReason: null,
109
+ backupPath: null,
110
+ error: error instanceof Error ? error.message.split("\n")[0] : String(error),
111
+ };
112
+ }
113
+ }
114
+
115
+ export function renderMigrate(outcome: MigrateOutcome): string {
116
+ const lines: string[] = ["Mirror runtime migrate", ""];
117
+ lines.push(`Database: ${outcome.dbPath}`);
118
+ if (outcome.error !== null) {
119
+ lines.push(`Migration error: ${outcome.error}`);
120
+ lines.push("");
121
+ lines.push("Migrate result: failed");
122
+ return `${lines.join("\n")}\n`;
123
+ }
124
+
125
+ // A standalone `runtime migrate` runs OUTSIDE the updater's backup-and-verify
126
+ // chain: its only pre-state is migrate-on-open's own snapshot, which uses one
127
+ // fixed name and is overwritten on each write. Inside the pipeline a verified
128
+ // archive was taken three stages earlier; run directly, this line is the only
129
+ // warning a user gets (CV22.DS10.US2 handoff review, security-engineer).
130
+ lines.push(`Ledger before: ${outcome.before.length} migration(s)`);
131
+ lines.push(`Ledger after: ${outcome.after.length} migration(s)`);
132
+ if (outcome.applied.length > 0) lines.push(`Applied: ${outcome.applied.join(", ")}`);
133
+ if (outcome.backupPath) lines.push(`Pre-migration snapshot: ${outcome.backupPath}`);
134
+ if (outcome.verdict === "declined" && outcome.declinedReason) {
135
+ lines.push(`Declined: ${outcome.declinedReason}.`);
136
+ }
137
+ if (!outcome.migrated) {
138
+ lines.push("Take a verified archive first if you are running this outside an update:");
139
+ lines.push(" runtime backup");
140
+ }
141
+ lines.push("");
142
+ // Three verdicts, three lines. `declined` is NOT `nothing pending`: the first
143
+ // says the engine refused work it could not safely do, the second that there
144
+ // was none. Conflating them is what let an update report a passing migrate
145
+ // stage on a database that had not been migrated.
146
+ lines.push(
147
+ outcome.verdict === "applied"
148
+ ? `Migrate result: applied ${outcome.applied.length} migration(s)`
149
+ : outcome.verdict === "declined"
150
+ ? "Migrate result: declined"
151
+ : "Migrate result: nothing pending",
152
+ );
153
+ return `${lines.join("\n")}\n`;
154
+ }
@@ -0,0 +1,102 @@
1
+ // What identifies a Mirror Mind tree, and where its version comes from.
2
+ //
3
+ // CV22.DS10.TS5 plateau 1, decision D1. Until this story both answers were
4
+ // read out of `pyproject.toml`:
5
+ //
6
+ // * `packageVersion` walked upward for its `version =` line -- THE version,
7
+ // read by the updater, the release doctor, the welcome card,
8
+ // `runtime version|status`, the MCP server's `initialize`, and the Claude
9
+ // plugin builder (US2 decision D2: one body, so npm changes one place);
10
+ // * `isMirrorMindCheckout` identified a checkout as the first directory
11
+ // holding both `pyproject.toml` and `src/memory/`.
12
+ //
13
+ // The second one is why this module exists rather than a one-line edit.
14
+ // Deleting `src/memory/` would have silently disabled the production
15
+ // clone-role guard -- the check that stops Builder from mutating a production
16
+ // clone -- because the guard would simply stop recognizing the tree. No test
17
+ // would have failed. The inventory found it by reading; `cloneRoleGuard.test.ts`
18
+ // now pins it.
19
+ //
20
+ // So identity moves to the TypeScript package, and both answers come from one
21
+ // walk. CV22.DS10.US3 (decisions D1, D2) renamed the package to `mirror-mind`
22
+ // and moved the manifest to the repository root, so a checkout and an
23
+ // installed package have the same paths and one layout serves both.
24
+
25
+ import { existsSync, readFileSync } from "node:fs";
26
+ import { dirname, join, resolve } from "node:path";
27
+
28
+ /**
29
+ * The npm package name that identifies this codebase, and the name
30
+ * `npm install -g` takes (CV22.DS10.US3, D1).
31
+ *
32
+ * It is checked rather than assumed so a stray `package.json` -- `.pi/`, a
33
+ * user's own project -- is never mistaken for Mirror Mind.
34
+ */
35
+ export const PACKAGE_NAME = "mirror-mind";
36
+
37
+ /**
38
+ * Where the manifest and the front door sit relative to a tree root.
39
+ *
40
+ * One layout, because the repository IS the package (US3, D2): the manifest at
41
+ * the root and the front door at `ts/src/frontDoor/cli.ts`, in a checkout and
42
+ * under `npm root -g` alike. Until US3 a second candidate described a
43
+ * flattened install that was never published.
44
+ */
45
+ const MANIFEST = "package.json";
46
+ const FRONT_DOOR = join("ts", "src", "frontDoor", "cli.ts");
47
+
48
+ export interface PackageIdentity {
49
+ /** The tree root: the directory the manifest was found relative to. */
50
+ readonly root: string;
51
+ /** The manifest's `name`, whatever it is. */
52
+ readonly name: string;
53
+ /** The manifest's `version`, or null when it has none. */
54
+ readonly version: string | null;
55
+ /** True when `name` is this codebase's. */
56
+ readonly isMirrorMind: boolean;
57
+ }
58
+
59
+ function readIdentity(root: string): PackageIdentity | null {
60
+ const manifestPath = join(root, MANIFEST);
61
+ // BOTH markers, as Python required both `pyproject.toml` and `src/memory/`:
62
+ // a manifest alone is a file anyone can have, and the front door is what
63
+ // makes the tree this program.
64
+ if (!existsSync(manifestPath) || !existsSync(join(root, FRONT_DOOR))) return null;
65
+ try {
66
+ const parsed = JSON.parse(readFileSync(manifestPath, "utf8")) as {
67
+ name?: unknown;
68
+ version?: unknown;
69
+ };
70
+ const name = typeof parsed.name === "string" ? parsed.name : "";
71
+ return {
72
+ root,
73
+ name,
74
+ version: typeof parsed.version === "string" ? parsed.version : null,
75
+ isMirrorMind: name === PACKAGE_NAME,
76
+ };
77
+ } catch {
78
+ // An unreadable or malformed manifest answers "not Mirror Mind" rather
79
+ // than continuing upward -- Python's `return False` inside the `except`,
80
+ // not a `continue`. A broken manifest is a broken tree, not an absent one.
81
+ return { root, name: "", version: null, isMirrorMind: false };
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Walk upward for the nearest tree that carries a manifest AND a front door.
87
+ *
88
+ * **The walk STOPS at the first such directory, whatever it answers.** It does
89
+ * not keep climbing toward a tree that would say yes. That is Python's
90
+ * behavior for the pyproject/`src/memory` pair, and it is what makes a nested
91
+ * project decide for itself instead of inheriting its parent's identity.
92
+ */
93
+ export function findPackageIdentity(start: string): PackageIdentity | null {
94
+ let current = resolve(start);
95
+ for (;;) {
96
+ const identity = readIdentity(current);
97
+ if (identity) return identity;
98
+ const parent = dirname(current);
99
+ if (parent === current) return null;
100
+ current = parent;
101
+ }
102
+ }