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,513 @@
1
+ // argv -> answer for the extension-catalog READS (CV22.DS7.TS4 plateau 1).
2
+ //
3
+ // The composition layer over `catalog.ts`: the hand-rolled argument parsing
4
+ // `cli/extensions.py`, `cli/ext.py`, and `cli/inspect.py` do, and the exact
5
+ // order in which each command prints, refuses, and exits. Nothing here is
6
+ // routed -- `routing.ts` still sends every one of these to Python; the front
7
+ // door is plateau 7.
8
+ //
9
+ // The write verbs (`sync`, `install`, `uninstall`, `expose-claude`,
10
+ // `clean-claude`) are plateau 5 -- the plan's amendment swapped them with the
11
+ // dispatch, because installing a command-skill calls the extension's own
12
+ // `register(api)` and so DEPENDS on the host this plateau lands. Their
13
+ // REFUSALS live here already, because they are produced by this parser before
14
+ // any write is attempted, and a validated write argv raises
15
+ // `UnsupportedCatalogCommandError` rather than pretending: an unimplemented
16
+ // path must fail loudly, not silently print nothing.
17
+
18
+ import { existsSync } from "node:fs";
19
+ import { homedir } from "node:os";
20
+ import { join } from "node:path";
21
+ import type { WritableDatabase } from "#db/database.ts";
22
+ import { PROGRAM } from "#util/program.ts";
23
+ import {
24
+ type BindingDeps,
25
+ parseBindingTail,
26
+ runBind,
27
+ runBindings,
28
+ runMigrate,
29
+ runUnbind,
30
+ } from "./bindings.ts";
31
+ import {
32
+ discoverExtensions,
33
+ extensionsRootForHome,
34
+ filterManifestsForRuntime,
35
+ type RenderedCommand,
36
+ renderCommandSkillList,
37
+ renderExtensionList,
38
+ renderInspectExtension,
39
+ renderInspectRuntimeCatalog,
40
+ runtimeSkillsRootForHome,
41
+ } from "./catalog.ts";
42
+ import {
43
+ cleanupClaudeRuntimeSkills,
44
+ exposeClaudeRuntimeSkills,
45
+ installExtension,
46
+ loadRuntimeCatalog,
47
+ renderInstallReport,
48
+ renderUninstallReport,
49
+ syncExtensionsForRuntime,
50
+ uninstallExtension,
51
+ } from "./catalogWrites.ts";
52
+ import {
53
+ type ExtensionDispatch,
54
+ extensionNotInstalled,
55
+ installedExtensionDir,
56
+ noRuntimeRefusal,
57
+ readDeclaredCommands,
58
+ readSubcommandListing,
59
+ renderSubcommandListing,
60
+ } from "./dispatch.ts";
61
+ import { ExtensionValidationError } from "./errors.ts";
62
+
63
+ export class UnsupportedCatalogCommandError extends Error {}
64
+
65
+ const EXTENSIONS_USAGE =
66
+ `Usage: ${PROGRAM} extensions [list|validate|sync|install|uninstall|` +
67
+ "expose-claude|clean-claude] [--mirror-home PATH] [--extensions-root PATH] " +
68
+ "[--runtime NAME] [--target-root PATH]";
69
+ const LIST_USAGE =
70
+ `Usage: ${PROGRAM} list [personas|journeys|extensions|all] ` +
71
+ "[--mirror-home PATH] [--verbose] [--extensions-root PATH] [--runtime NAME]";
72
+ const INSPECT_USAGE =
73
+ `Usage: ${PROGRAM} inspect persona|extension|runtime-catalog|llm-calls|` +
74
+ "embedding-provenance <id> [--mirror-home PATH] [--extensions-root PATH]";
75
+ const EXT_USAGE = [
76
+ "Usage:",
77
+ ` ${PROGRAM} ext list`,
78
+ ` ${PROGRAM} ext <id> [--help]`,
79
+ ` ${PROGRAM} ext <id> <subcommand> [args...]`,
80
+ ` ${PROGRAM} ext <id> bind <capability> (--persona <id> | --journey <id> | --global)`,
81
+ ` ${PROGRAM} ext <id> unbind <capability> (--persona <id> | --journey <id> | --global)`,
82
+ ` ${PROGRAM} ext <id> bindings`,
83
+ ` ${PROGRAM} ext <id> migrate`,
84
+ "",
85
+ ].join("\n");
86
+
87
+ const EXTENSIONS_VERBS = new Set([
88
+ "list",
89
+ "validate",
90
+ "sync",
91
+ "install",
92
+ "uninstall",
93
+ "expose-claude",
94
+ "clean-claude",
95
+ ]);
96
+
97
+ /** Everything these commands need from the environment, passed, never read. */
98
+ export interface CatalogContext {
99
+ /** The resolved Mirror home; `--mirror-home` has already been applied. */
100
+ readonly mirrorHome: string;
101
+ }
102
+
103
+ /** The writable half, for the four `ext` verbs that touch the database. */
104
+ export interface ExtWriteContext extends CatalogContext {
105
+ readonly db: WritableDatabase;
106
+ readonly deps: BindingDeps;
107
+ }
108
+
109
+ const BUILTIN_VERBS = new Set(["bind", "unbind", "bindings", "migrate"]);
110
+ const HELP_FLAGS = new Set(["--help", "-h", "help"]);
111
+
112
+ const BUILTIN_VERB_HELP: Record<string, readonly [string, string]> = {
113
+ bind: [
114
+ "bind <capability> (--persona <id> | --journey <id> | --global)",
115
+ "Bind a capability to a persona, a journey, or every context.",
116
+ ],
117
+ unbind: [
118
+ "unbind <capability> (--persona <id> | --journey <id> | --global)",
119
+ "Remove a capability binding.",
120
+ ],
121
+ bindings: ["bindings", "List the extension's capability bindings."],
122
+ migrate: ["migrate", "Apply the extension's pending database migrations."],
123
+ };
124
+
125
+ function out(stdout: string, exitCode = 0): RenderedCommand {
126
+ return { stdout, stderr: "", exitCode };
127
+ }
128
+
129
+ function usage(text: string): RenderedCommand {
130
+ return out(`${text}\n`, 1);
131
+ }
132
+
133
+ interface ParsedOptions {
134
+ extensionsRoot: string | null;
135
+ mirrorHome: string | null;
136
+ runtime: string | null;
137
+ targetRoot: string | null;
138
+ positional: string[];
139
+ }
140
+
141
+ /**
142
+ * Port of `extensions._parse_args`.
143
+ *
144
+ * A flag whose value is missing is NOT an error here: the loop's `i + 1 <
145
+ * len(args)` guard fails, so a trailing `--runtime` falls through to the
146
+ * positional list and is read as a subcommand. Reproduced deliberately.
147
+ */
148
+ export function parseCatalogOptions(argv: readonly string[]): ParsedOptions {
149
+ const parsed: ParsedOptions = {
150
+ extensionsRoot: null,
151
+ mirrorHome: null,
152
+ runtime: null,
153
+ targetRoot: null,
154
+ positional: [],
155
+ };
156
+ let index = 0;
157
+ while (index < argv.length) {
158
+ const token = argv[index] as string;
159
+ const value = argv[index + 1];
160
+ if (token === "--extensions-root" && value !== undefined) {
161
+ parsed.extensionsRoot = value;
162
+ index += 2;
163
+ } else if (token === "--mirror-home" && value !== undefined) {
164
+ parsed.mirrorHome = value;
165
+ index += 2;
166
+ } else if (token === "--runtime" && value !== undefined) {
167
+ parsed.runtime = value;
168
+ index += 2;
169
+ } else if (token === "--target-root" && value !== undefined) {
170
+ parsed.targetRoot = value;
171
+ index += 2;
172
+ } else {
173
+ parsed.positional.push(token);
174
+ index += 1;
175
+ }
176
+ }
177
+ return parsed;
178
+ }
179
+
180
+ function resolveRoot(context: CatalogContext, explicit: string | null): string {
181
+ return explicit ?? extensionsRootForHome(context.mirrorHome);
182
+ }
183
+
184
+ /** Python's `Path(p).expanduser()`, which the two `--target-root` verbs apply. */
185
+ function expandHomePath(path: string): string {
186
+ if (path === "~") return homedir();
187
+ if (path.startsWith("~/")) return join(homedir(), path.slice(2));
188
+ return path;
189
+ }
190
+
191
+ function writeContext(context: CatalogContext, command: string): ExtWriteContext {
192
+ if (!isWriteContext(context)) {
193
+ throw new UnsupportedCatalogCommandError(`extensions ${command} needs a write context`);
194
+ }
195
+ return context;
196
+ }
197
+
198
+ /**
199
+ * Python lets `install`'s validation errors escape as a traceback: exit 1,
200
+ * nothing on stdout. TypeScript cannot reproduce those bytes, so it answers
201
+ * the recorded divergence shape -- the same exit code, one line on stderr --
202
+ * and, like Python, writes nothing to stdout.
203
+ */
204
+ function failLoudly(run: () => RenderedCommand): RenderedCommand {
205
+ try {
206
+ return run();
207
+ } catch (error) {
208
+ if (!(error instanceof ExtensionValidationError)) throw error;
209
+ return { stdout: "", stderr: `${error.message}\n`, exitCode: 1 };
210
+ }
211
+ }
212
+
213
+ /** Port of the read half of `cmd_extensions`. */
214
+ export function runExtensionsCommand(
215
+ context: CatalogContext,
216
+ argv: readonly string[],
217
+ ): RenderedCommand {
218
+ const options = parseCatalogOptions(argv);
219
+ const command = options.positional[0] ?? "list";
220
+ if (!EXTENSIONS_VERBS.has(command)) return usage(EXTENSIONS_USAGE);
221
+
222
+ if (command === "install") {
223
+ if (options.positional.length !== 2) {
224
+ return usage(
225
+ `Usage: ${PROGRAM} extensions install <id> [--extensions-root PATH] ` +
226
+ "[--mirror-home PATH] [--runtime NAME]",
227
+ );
228
+ }
229
+ if (options.extensionsRoot === null) return usage("install requires --extensions-root PATH");
230
+ const write = writeContext(context, "install");
231
+ return failLoudly(() =>
232
+ renderInstallReport(
233
+ installExtension({
234
+ extensionId: options.positional[1] as string,
235
+ sourceRoot: options.extensionsRoot as string,
236
+ mirrorHome: write.mirrorHome,
237
+ runtime: options.runtime,
238
+ db: write.db,
239
+ deps: write.deps,
240
+ }),
241
+ ),
242
+ );
243
+ }
244
+ if (command === "uninstall") {
245
+ if (options.positional.length !== 2) {
246
+ return usage(
247
+ `Usage: ${PROGRAM} extensions uninstall <id> [--mirror-home PATH] [--runtime NAME]`,
248
+ );
249
+ }
250
+ const write = writeContext(context, "uninstall");
251
+ // Python CATCHES the validation error here and prints it as a line, where
252
+ // `install` lets the same class escape as a traceback. Same command, two
253
+ // refusal shapes, measured rather than unified.
254
+ try {
255
+ return renderUninstallReport(
256
+ uninstallExtension({
257
+ extensionId: options.positional[1] as string,
258
+ mirrorHome: write.mirrorHome,
259
+ runtime: options.runtime,
260
+ db: write.db,
261
+ deps: write.deps,
262
+ }),
263
+ );
264
+ } catch (error) {
265
+ if (!(error instanceof ExtensionValidationError)) throw error;
266
+ return out(`${error.message}\n`, 1);
267
+ }
268
+ }
269
+ if (command === "expose-claude" || command === "clean-claude") {
270
+ if (options.targetRoot === null) return usage(`${command} requires --target-root PATH`);
271
+ const write = writeContext(context, command);
272
+ const projectRoot = expandHomePath(options.targetRoot);
273
+ if (command === "clean-claude") {
274
+ const report = cleanupClaudeRuntimeSkills(projectRoot);
275
+ const lines = [
276
+ `Removed Claude external skills from ${report.claudeSkillsRoot}`,
277
+ ` overlay catalog: ${report.overlayCatalogPath}`,
278
+ ...report.removed.map((path) => ` removed ${path}`),
279
+ ];
280
+ return out(`${lines.join("\n")}\n`);
281
+ }
282
+ try {
283
+ const catalog = loadRuntimeCatalog("claude", write.mirrorHome);
284
+ const report = exposeClaudeRuntimeSkills(projectRoot, catalog);
285
+ const lines = [
286
+ `Exposed Claude external skills into ${report.claudeSkillsRoot}`,
287
+ ` overlay catalog: ${report.overlayCatalogPath}`,
288
+ ...report.removed.map((path) => ` pruned ${path}`),
289
+ ...report.exposed.map((item) => ` ${item.commandName} -> ${item.targetSkillPath}`),
290
+ ];
291
+ return out(`${lines.join("\n")}\n`);
292
+ } catch (error) {
293
+ if (!(error instanceof ExtensionValidationError)) throw error;
294
+ return out(`${error.message}\n`, 1);
295
+ }
296
+ }
297
+
298
+ const root = resolveRoot(context, options.extensionsRoot);
299
+ const discovery = discoverExtensions(root);
300
+ const manifests = filterManifestsForRuntime(discovery.manifests, options.runtime);
301
+
302
+ if (command === "list") {
303
+ const header = options.runtime === null ? "" : `Runtime filter: ${options.runtime}\n`;
304
+ return out(header + renderExtensionList(manifests, discovery.errors, root));
305
+ }
306
+
307
+ // `validate` and `sync` share this prelude, and its ORDER is the measured
308
+ // surprise: an invalid extension exits 1 here, BEFORE `sync` can complain
309
+ // about a missing `--runtime`. This INVALID block also has no leading blank
310
+ // line, unlike the one inside `print_extension_list`.
311
+ let stdout = `Extensions root: ${root}\n`;
312
+ if (options.runtime !== null) stdout += `Runtime filter: ${options.runtime}\n`;
313
+ if (discovery.errors.length > 0) {
314
+ stdout += "=== INVALID EXTENSIONS ===\n";
315
+ for (const [extensionId, message] of discovery.errors) {
316
+ stdout += ` ${extensionId}: ${message}\n`;
317
+ }
318
+ return out(stdout, 1);
319
+ }
320
+ if (command === "validate") {
321
+ return out(`${stdout}Validated ${manifests.length} extension(s).\n`);
322
+ }
323
+ if (options.runtime === null) return out(`${stdout}sync requires --runtime\n`, 1);
324
+ if (options.targetRoot === null) return out(`${stdout}sync requires --target-root PATH\n`, 1);
325
+
326
+ // `sync` writes files but never the database, so it needs the clock seam and
327
+ // nothing else. Note the target root is used RAW, not expanded: only
328
+ // `expose-claude` and `clean-claude` call `expanduser` on theirs.
329
+ const write = writeContext(context, "sync");
330
+ const synced = syncExtensionsForRuntime(
331
+ manifests,
332
+ options.runtime,
333
+ options.targetRoot,
334
+ write.deps,
335
+ );
336
+ const lines = [
337
+ `${stdout}Synced ${synced.length} extension(s) to ${options.targetRoot}`,
338
+ ...synced.map((item) => ` ${item.command_name} -> ${item.installed_skill_path}`),
339
+ ];
340
+ return out(`${lines.join("\n")}\n`);
341
+ }
342
+
343
+ /**
344
+ * Port of `cmd_ext`: the top-level parse, `_cmd_list`, `_print_top_help`, the
345
+ * built-in verbs, and the DECISION to dispatch into an extension.
346
+ *
347
+ * It answers with bytes for everything it can decide alone, and with an
348
+ * `ExtensionDispatch` for `ext <id>` and `ext <id> <subcommand>` -- the two
349
+ * leaves that must load extension code. Deciding and executing are separate on
350
+ * purpose: this layer stays pure and testable, and only the caller that is
351
+ * allowed to spawn a process runs the decision.
352
+ */
353
+ export function runExtCommand(
354
+ context: CatalogContext,
355
+ argv: readonly string[],
356
+ ): RenderedCommand | ExtensionDispatch {
357
+ const args: string[] = [];
358
+ let mirrorHome: string | null = null;
359
+ for (let index = 0; index < argv.length; index += 1) {
360
+ const token = argv[index] as string;
361
+ const value = argv[index + 1];
362
+ if (token === "--mirror-home" && value !== undefined) {
363
+ mirrorHome = value;
364
+ index += 1;
365
+ continue;
366
+ }
367
+ args.push(token);
368
+ }
369
+ const home = mirrorHome ?? context.mirrorHome;
370
+ const head = args[0];
371
+ // A bare `ext` and `ext --help` print the SAME bytes and differ only in the
372
+ // exit code. Measured, not assumed.
373
+ if (head === undefined) return out(EXT_USAGE, 1);
374
+ if (head === "--help" || head === "-h" || head === "help") return out(EXT_USAGE, 0);
375
+ if (head === "list") {
376
+ const root = extensionsRootForHome(home);
377
+ const discovery = discoverExtensions(root);
378
+ return out(renderCommandSkillList(discovery.manifests, discovery.errors, root));
379
+ }
380
+
381
+ const extensionId = head;
382
+ const rest = args.slice(1);
383
+ const verb = rest[0];
384
+ // `ext <id>` lists the extension's subcommands, and Python models that as a
385
+ // dispatch of `--help` rather than as a command of its own.
386
+ if (verb === undefined) return dispatchOrNotInstalled(home, extensionId, "--help", []);
387
+ const tail = rest.slice(1);
388
+
389
+ // Describe, never execute: this guard is a fix `cli/ext.py` carries, and
390
+ // losing it would make `ext <id> migrate --help` APPLY migrations.
391
+ if (BUILTIN_VERBS.has(verb) && tail.some((token) => HELP_FLAGS.has(token))) {
392
+ const [usage, description] = BUILTIN_VERB_HELP[verb] as readonly [string, string];
393
+ return out(`Usage:\n ${PROGRAM} ext ${extensionId} ${usage}\n\n${description}\n`);
394
+ }
395
+
396
+ if (!BUILTIN_VERBS.has(verb)) return dispatchOrNotInstalled(home, extensionId, verb, tail);
397
+ if (!isWriteContext(context)) {
398
+ throw new UnsupportedCatalogCommandError(`ext ${verb} needs a writable database`);
399
+ }
400
+ if (verb === "bindings") return runBindings(context.db, extensionId);
401
+ if (verb === "migrate") return runMigrate(context.db, home, extensionId, context.deps);
402
+
403
+ const parsed = parseBindingTail(extensionId, verb === "bind" ? "bind" : "unbind", tail);
404
+ if ("stdout" in parsed) return parsed;
405
+ const target = { kind: parsed.kind, id: parsed.id };
406
+ return verb === "bind"
407
+ ? runBind(context.db, extensionId, parsed.capabilityId, target, context.deps)
408
+ : runUnbind(context.db, extensionId, parsed.capabilityId, target);
409
+ }
410
+
411
+ function isWriteContext(context: CatalogContext): context is ExtWriteContext {
412
+ return "db" in context;
413
+ }
414
+
415
+ /**
416
+ * Decide what `ext <id> [subcommand]` does, without running anything.
417
+ *
418
+ * The installed check `_dispatch_subcommand` ran before loading anything, and
419
+ * its refusal prints the path Python BUILT, not the path it would resolve --
420
+ * see `installedExtensionDir` for why that distinction is observable.
421
+ *
422
+ * After CV22.DS10.TS2 there are five outcomes and only the last one is a
423
+ * process:
424
+ *
425
+ * 1. not installed -> Python's byte-identical refusal
426
+ * 2. a help spelling -> the manifest-rendered listing
427
+ * 3. a name the manifest does not document -> unknown + the listing
428
+ * 4. documented, no runtime -> the refusal, on stderr, exit 1
429
+ * 5. documented with a runtime -> an `ExtensionDispatch` for the caller
430
+ * that is allowed to spawn
431
+ *
432
+ * Cases 3 and 4 are deliberately distinct. "I have never heard of that" and
433
+ * "that exists but has not been migrated" are different problems with
434
+ * different fixes, and collapsing them would send a user editing the wrong
435
+ * file.
436
+ */
437
+ function dispatchOrNotInstalled(
438
+ mirrorHome: string,
439
+ extensionId: string,
440
+ subcommand: string,
441
+ argv: readonly string[],
442
+ ): RenderedCommand | ExtensionDispatch {
443
+ const extensionRoot = installedExtensionDir(mirrorHome, extensionId);
444
+ if (!existsSync(extensionRoot)) return extensionNotInstalled(mirrorHome, extensionId);
445
+
446
+ const entries = readSubcommandListing(extensionRoot);
447
+ if (HELP_FLAGS.has(subcommand)) return out(renderSubcommandListing(extensionId, entries));
448
+
449
+ const documented = entries.find((entry) => entry.name === subcommand);
450
+ if (documented === undefined) {
451
+ return out(
452
+ `unknown subcommand '${subcommand}' for extension/${extensionId}\n` +
453
+ renderSubcommandListing(extensionId, entries),
454
+ 1,
455
+ );
456
+ }
457
+ const declared = readDeclaredCommands(extensionRoot).find((entry) => entry.name === subcommand);
458
+ if (declared === undefined) {
459
+ return { stdout: "", stderr: noRuntimeRefusal(extensionId, subcommand), exitCode: 1 };
460
+ }
461
+ return {
462
+ kind: "extension-subcommand",
463
+ extensionId,
464
+ subcommand,
465
+ argv: [...argv],
466
+ mirrorHome,
467
+ extensionRoot,
468
+ command: declared.command,
469
+ };
470
+ }
471
+
472
+ /** Port of `cmd_list`'s extension branch and its usage refusal. */
473
+ export function runListCommand(context: CatalogContext, argv: readonly string[]): RenderedCommand {
474
+ const options = parseCatalogOptions(argv);
475
+ const target = options.positional[0] ?? "all";
476
+ if (!["personas", "journeys", "extensions", "all"].includes(target)) return usage(LIST_USAGE);
477
+ if (target !== "extensions") {
478
+ // `personas`, `journeys`, and the persona/journey halves of `all` are
479
+ // DS7.US1's ported reads; the front-door composition is plateau 7.
480
+ throw new UnsupportedCatalogCommandError(`list ${target} composes the DS7.US1 reads`);
481
+ }
482
+ const root = resolveRoot(context, options.extensionsRoot);
483
+ const discovery = discoverExtensions(root);
484
+ const manifests = filterManifestsForRuntime(discovery.manifests, options.runtime);
485
+ const header = options.runtime === null ? "" : `Runtime filter: ${options.runtime}\n`;
486
+ return out(header + renderExtensionList(manifests, discovery.errors, root));
487
+ }
488
+
489
+ /** Port of `cmd_inspect`'s catalog targets and its usage refusal. */
490
+ export function runInspectCommand(
491
+ context: CatalogContext,
492
+ argv: readonly string[],
493
+ ): RenderedCommand {
494
+ const options = parseCatalogOptions(argv);
495
+ const [target, targetId] = options.positional;
496
+ if (
497
+ options.positional.length !== 2 ||
498
+ target === undefined ||
499
+ !["persona", "extension", "runtime-catalog"].includes(target)
500
+ ) {
501
+ return usage(INSPECT_USAGE);
502
+ }
503
+ if (target === "persona") {
504
+ throw new UnsupportedCatalogCommandError("inspect persona is DS7.US1's ported read");
505
+ }
506
+ if (target === "extension") {
507
+ return renderInspectExtension(resolveRoot(context, options.extensionsRoot), targetId as string);
508
+ }
509
+ const runtime = targetId as string;
510
+ return out(
511
+ renderInspectRuntimeCatalog(runtimeSkillsRootForHome(context.mirrorHome, runtime), runtime),
512
+ );
513
+ }