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,72 @@
1
+ // CV22.DS7.US7 plateau 1 — the △ EXPLORER MODE ACTIVE card, ported from
2
+ // `render_explorer_mode_transition` (`src/memory/surfaces/mode_transition.py`).
3
+ //
4
+ // Same WIDTH as the story cards in `render.ts`, and the `_box`/`_line` bodies
5
+ // are character-identical -- but `_wrap` is NOT. This module's oracle has no
6
+ // `_chunk_word`: a word longer than the line overflows, and `_line` truncates
7
+ // it to WIDTH. The story-card oracle chunks it across several lines instead.
8
+ //
9
+ // So the two helpers must stay separate. Factoring them into one shared
10
+ // implementation silently changes whichever card did not win the merge, and
11
+ // the only input that reveals it is a journey slug longer than 54 characters
12
+ // -- which is exactly why the golden carries one.
13
+
14
+ import { codePointLength, pySplitWhitespace, sliceCodePoints } from "#util/pythonText.ts";
15
+
16
+ const WIDTH = 56;
17
+
18
+ type Row = readonly [label: string, value: string];
19
+
20
+ function line(text: string): string {
21
+ const content = sliceCodePoints(text, WIDTH);
22
+ return `│${content.padEnd(WIDTH + (content.length - codePointLength(content)))}│`;
23
+ }
24
+
25
+ /** `mode_transition._wrap`: greedy fill, long words NOT chunked. */
26
+ function wrap(text: string): string[] {
27
+ const maxWidth = WIDTH - 2;
28
+ const words = pySplitWhitespace(text);
29
+ if (words.length === 0) return [""];
30
+
31
+ const lines: string[] = [];
32
+ let current = words[0] as string;
33
+ for (const word of words.slice(1)) {
34
+ if (codePointLength(current) + 1 + codePointLength(word) <= maxWidth) {
35
+ current += ` ${word}`;
36
+ } else {
37
+ lines.push(current);
38
+ current = word;
39
+ }
40
+ }
41
+ lines.push(current);
42
+ return lines;
43
+ }
44
+
45
+ function box(title: string, rows: readonly Row[]): string {
46
+ const lines = ["Mirror", `╭${"─".repeat(WIDTH)}╮`, line(` ${title}`)];
47
+ for (const [label, value] of rows) {
48
+ lines.push(line(""));
49
+ lines.push(line(` ${label}`));
50
+ for (const wrapped of wrap(value)) {
51
+ lines.push(line(` ${wrapped}`));
52
+ }
53
+ }
54
+ lines.push(`╰${"─".repeat(WIDTH)}╯`);
55
+ return lines.join("\n");
56
+ }
57
+
58
+ /** Port of `render_explorer_mode_transition`. */
59
+ export function renderExplorerModeTransition(journey: string): string {
60
+ return box("△ EXPLORER MODE ACTIVE", [
61
+ ["active journey", journey],
62
+ [
63
+ "availability",
64
+ "Explorer Mode is active and ready for durable exploration, story thickening, attractors, experiments, and Builder handoff.",
65
+ ],
66
+ [
67
+ "what this mode is",
68
+ "Exploration lens. Mirror preserves uncertainty, keeps signals, and thickens exploratory stories before construction.",
69
+ ],
70
+ ["boundary", "Explorer preserves uncertainty."],
71
+ ]);
72
+ }
@@ -0,0 +1,170 @@
1
+ // Extension capability bindings and `ext <id> migrate` (CV22.DS7.TS4 plateau 3).
2
+ //
3
+ // Port of `_cmd_bind`, `_cmd_unbind`, `_cmd_bindings`, `_cmd_migrate`, and
4
+ // `_handle_binding` from `src/memory/cli/ext.py`. These are the family's first
5
+ // WRITES, and two measured facts shape them:
6
+ //
7
+ // * **A `--global` bind is not idempotent, and a persona bind is.**
8
+ // `_ext_bindings`'s primary key includes `target_id`, which is NULL for a
9
+ // global binding, and SQLite does not consider two NULLs equal in a
10
+ // (non-STRICT, rowid) primary key. So `INSERT OR IGNORE` ignores nothing:
11
+ // binding the same capability globally three times leaves THREE rows,
12
+ // where binding it to a persona three times leaves one. Measured on the
13
+ // real schema, reproduced here, and recorded as debt -- the docstring
14
+ // that says "No-op if already present (PK conflict)" is true only for the
15
+ // targeted kinds.
16
+ // * **`created_at` is Python's `isoformat()`**, with `+00:00` and
17
+ // microseconds -- NOT the `Z` form `_now()` uses elsewhere in Mirror. The
18
+ // write probe grades these bytes, so the clock seam yields that spelling.
19
+
20
+ import { existsSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import type { Database, WritableDatabase } from "#db/database.ts";
23
+ import { PROGRAM } from "#util/program.ts";
24
+ import type { RenderedCommand } from "./catalog.ts";
25
+ import { extensionNotInstalled, installedExtensionDir } from "./dispatch.ts";
26
+ import { ExtensionError } from "./errors.ts";
27
+ import { runMigrations } from "./migrations.ts";
28
+
29
+ /** Python `datetime.now(timezone.utc).isoformat()`: `+00:00`, microseconds. */
30
+ export function pythonUtcIsoformat(date: Date = new Date()): string {
31
+ return date.toISOString().replace(/\.(\d{3})Z$/, ".$1000+00:00");
32
+ }
33
+
34
+ export interface BindingDeps {
35
+ /** Injected so the corpus and the probe can freeze it. */
36
+ readonly nowIso: () => string;
37
+ }
38
+
39
+ export interface BindingTarget {
40
+ kind: "persona" | "journey" | "global";
41
+ id: string | null;
42
+ }
43
+
44
+ function out(stdout: string, exitCode = 0): RenderedCommand {
45
+ return { stdout, stderr: "", exitCode };
46
+ }
47
+
48
+ function label(target: BindingTarget): string {
49
+ return target.id ? `${target.kind}/${target.id}` : target.kind;
50
+ }
51
+
52
+ /** Port of `_cmd_bind`. */
53
+ export function runBind(
54
+ db: WritableDatabase,
55
+ extensionId: string,
56
+ capabilityId: string,
57
+ target: BindingTarget,
58
+ deps: BindingDeps,
59
+ ): RenderedCommand {
60
+ db.prepare(
61
+ "INSERT OR IGNORE INTO _ext_bindings " +
62
+ "(extension_id, capability_id, target_kind, target_id, created_at) " +
63
+ "VALUES (?, ?, ?, ?, ?)",
64
+ ).run(extensionId, capabilityId, target.kind, target.id, deps.nowIso());
65
+ return out(`bound ${extensionId}/${capabilityId} -> ${label(target)}\n`);
66
+ }
67
+
68
+ /** Port of `_cmd_unbind`. `target_id IS ?` is what makes a global unbind work. */
69
+ export function runUnbind(
70
+ db: WritableDatabase,
71
+ extensionId: string,
72
+ capabilityId: string,
73
+ target: BindingTarget,
74
+ ): RenderedCommand {
75
+ const result = db
76
+ .prepare(
77
+ "DELETE FROM _ext_bindings WHERE " +
78
+ "extension_id = ? AND capability_id = ? AND " +
79
+ "target_kind = ? AND (target_id IS ? OR target_id = ?)",
80
+ )
81
+ .run(extensionId, capabilityId, target.kind, target.id, target.id);
82
+ if (Number(result.changes) === 0) return out("no matching binding\n");
83
+ return out(`unbound ${extensionId}/${capabilityId} -> ${label(target)}\n`);
84
+ }
85
+
86
+ /** Port of `_cmd_bindings`. */
87
+ export function runBindings(db: Database, extensionId: string): RenderedCommand {
88
+ const rows = db
89
+ .prepare(
90
+ "SELECT capability_id, target_kind, target_id, created_at " +
91
+ "FROM _ext_bindings WHERE extension_id = ? " +
92
+ "ORDER BY capability_id, target_kind, target_id",
93
+ )
94
+ .all(extensionId);
95
+ if (rows.length === 0) return out(`no bindings for extension/${extensionId}\n`);
96
+ const lines = [`=== bindings for extension/${extensionId} ===`];
97
+ for (const row of rows) {
98
+ const target = row.target_id ? String(row.target_id) : "(global)";
99
+ lines.push(` ${String(row.capability_id)} -> ${String(row.target_kind)}/${target}`);
100
+ }
101
+ return out(`${lines.join("\n")}\n`);
102
+ }
103
+
104
+ /** Port of `_cmd_migrate`. An extension error is a printed line and exit 1. */
105
+ export function runMigrate(
106
+ db: WritableDatabase,
107
+ mirrorHome: string,
108
+ extensionId: string,
109
+ deps: BindingDeps,
110
+ ): RenderedCommand {
111
+ // `installedExtensionDir`, not `join`: Python builds this path without
112
+ // normalizing it and then PRINTS it, so `ext ../../etc migrate` must answer
113
+ // with the traversal intact. Plateau 3 shipped `join` here and plateau 4's
114
+ // measurement caught it -- the bindings golden only ever passed a plain id.
115
+ const extensionDir = installedExtensionDir(mirrorHome, extensionId);
116
+ if (!existsSync(extensionDir)) return extensionNotInstalled(mirrorHome, extensionId);
117
+ try {
118
+ const applied = runMigrations(db, extensionId, join(extensionDir, "migrations"), deps);
119
+ return out(`applied ${applied} migration(s) for extension/${extensionId}\n`);
120
+ } catch (error) {
121
+ if (!(error instanceof ExtensionError)) throw error;
122
+ return out(`${error.message}\n`, 1);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Port of `_handle_binding`'s parser.
128
+ *
129
+ * The LAST target flag wins, because Python overwrites `target_kind`/
130
+ * `target_id` on every match rather than refusing a second one; an
131
+ * unrecognised token refuses immediately with the token quoted.
132
+ */
133
+ export function parseBindingTail(
134
+ extensionId: string,
135
+ action: "bind" | "unbind",
136
+ tail: readonly string[],
137
+ ): (BindingTarget & { capabilityId: string }) | RenderedCommand {
138
+ if (tail.length === 0) {
139
+ return out(
140
+ `usage: ${PROGRAM} ext ${extensionId} ${action} <capability> ` +
141
+ "(--persona <id> | --journey <id> | --global)\n",
142
+ 1,
143
+ );
144
+ }
145
+ const capabilityId = tail[0] as string;
146
+ let kind: BindingTarget["kind"] | null = null;
147
+ let id: string | null = null;
148
+ for (let index = 1; index < tail.length; index += 1) {
149
+ const token = tail[index] as string;
150
+ const value = tail[index + 1];
151
+ if (token === "--persona" && value !== undefined) {
152
+ kind = "persona";
153
+ id = value;
154
+ index += 1;
155
+ } else if (token === "--journey" && value !== undefined) {
156
+ kind = "journey";
157
+ id = value;
158
+ index += 1;
159
+ } else if (token === "--global") {
160
+ kind = "global";
161
+ id = null;
162
+ } else {
163
+ return out(`unrecognised argument '${token}'\n`, 1);
164
+ }
165
+ }
166
+ if (kind === null) {
167
+ return out("missing target: pass --persona <id>, --journey <id>, or --global\n", 1);
168
+ }
169
+ return { capabilityId, kind, id };
170
+ }
@@ -0,0 +1,249 @@
1
+ // Extension catalog READS (CV22.DS7.TS4 plateau 1).
2
+ //
3
+ // Port of the read half of `src/memory/cli/extensions.py` plus the catalog
4
+ // branches of `cli/inspect.py` and `cli/ext.py`: discovery, the runtime
5
+ // filter, the runtime catalog file, and the five renderers behind
6
+ // `extensions list|validate`, `ext list`, `list extensions`, `inspect
7
+ // extension`, and `inspect runtime-catalog`.
8
+ //
9
+ // MEASURED AT PLATEAU 1, and the reason the golden grades exit codes:
10
+ // `extensions` and `ext` are hand-rolled parsers. Every refusal in this family
11
+ // prints to **stdout** and exits **1** -- stderr is empty even for a bare
12
+ // `inspect` or an unknown `list` target. Three measured facts a reading of the
13
+ // code would not have given:
14
+ //
15
+ // * `extensions validate` and `extensions sync` print the INVALID block and
16
+ // exit 1 BEFORE reaching their own "sync requires --runtime" message, so an
17
+ // invalid extension masks a usage error;
18
+ // * `ext --help` and a bare `ext` print the same bytes and differ only in
19
+ // exit code (0 against 1);
20
+ // * a MISSING or CORRUPT runtime catalog is rendered as an empty catalog at
21
+ // exit **0**, not as an error -- `_load_catalog` swallows both.
22
+ //
23
+ // The write half (`sync`, `install`, `uninstall`, `expose-claude`,
24
+ // `clean-claude`) is plateau 4 and deliberately absent.
25
+
26
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
27
+ import { join } from "node:path";
28
+ import { sortByCodePoint } from "#util/pythonText.ts";
29
+ import { ExtensionValidationError } from "./errors.ts";
30
+ import { type ExtensionManifest, loadExtensionManifest } from "./manifest.ts";
31
+
32
+ /** Port of `default_extensions_dir_for_home`. */
33
+ export function extensionsRootForHome(mirrorHome: string): string {
34
+ return join(mirrorHome, "extensions");
35
+ }
36
+
37
+ /** Port of `default_runtime_skills_dir_for_home`. */
38
+ export function runtimeSkillsRootForHome(mirrorHome: string, runtime: string): string {
39
+ return join(mirrorHome, "runtime", "skills", runtime);
40
+ }
41
+
42
+ export interface DiscoveryResult {
43
+ manifests: ExtensionManifest[];
44
+ /** `(extension_id, message)` pairs, in discovery order. */
45
+ errors: Array<readonly [string, string]>;
46
+ }
47
+
48
+ /**
49
+ * Port of `discover_extensions`.
50
+ *
51
+ * A missing root is empty, not an error. A child that is not a directory or
52
+ * carries no `skill.yaml` is skipped SILENTLY -- only a present-but-invalid
53
+ * manifest becomes an error row. Python iterates `sorted(root.iterdir())`;
54
+ * every child shares one parent, so that is name order by code point.
55
+ */
56
+ export function discoverExtensions(extensionsRoot: string): DiscoveryResult {
57
+ if (!existsSync(extensionsRoot)) return { manifests: [], errors: [] };
58
+
59
+ const manifests: ExtensionManifest[] = [];
60
+ const errors: Array<readonly [string, string]> = [];
61
+ for (const name of sortByCodePoint(readdirSync(extensionsRoot))) {
62
+ const child = join(extensionsRoot, name);
63
+ if (!isDirectory(child)) continue;
64
+ if (!existsSync(join(child, "skill.yaml"))) continue;
65
+ try {
66
+ manifests.push(loadExtensionManifest(child));
67
+ } catch (error) {
68
+ if (!(error instanceof ExtensionValidationError)) throw error;
69
+ errors.push([name, error.message] as const);
70
+ }
71
+ }
72
+ return { manifests, errors };
73
+ }
74
+
75
+ function isDirectory(path: string): boolean {
76
+ try {
77
+ return statSync(path).isDirectory();
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ /** Port of `filter_manifests_for_runtime`. */
84
+ export function filterManifestsForRuntime(
85
+ manifests: readonly ExtensionManifest[],
86
+ runtime: string | null,
87
+ ): ExtensionManifest[] {
88
+ if (runtime === null) return [...manifests];
89
+ return manifests.filter((manifest) => runtime in manifest.runtimes);
90
+ }
91
+
92
+ function invalidBlock(errors: ReadonlyArray<readonly [string, string]>): string {
93
+ if (errors.length === 0) return "";
94
+ const lines = ["", "=== INVALID EXTENSIONS ==="];
95
+ for (const [extensionId, message] of errors) lines.push(` ${extensionId}: ${message}`);
96
+ return `${lines.join("\n")}\n`;
97
+ }
98
+
99
+ /** Port of `print_extension_list`. */
100
+ export function renderExtensionList(
101
+ manifests: readonly ExtensionManifest[],
102
+ errors: ReadonlyArray<readonly [string, string]>,
103
+ root: string,
104
+ ): string {
105
+ const lines = [`Extensions root: ${root}`, "=== EXTENSIONS ==="];
106
+ if (manifests.length === 0) lines.push(" (none)");
107
+ for (const manifest of manifests) {
108
+ lines.push(` ${manifest.id} [${manifest.kind}]`);
109
+ lines.push(` name: ${manifest.name}`);
110
+ const parts = sortByCodePoint(Object.keys(manifest.runtimes)).map(
111
+ (runtimeName) => `${runtimeName}=${manifest.runtimes[runtimeName]?.commandName ?? ""}`,
112
+ );
113
+ lines.push(` runtimes: ${parts.join(", ")}`);
114
+ }
115
+ return `${lines.join("\n")}\n${invalidBlock(errors)}`;
116
+ }
117
+
118
+ /** Port of `ext._cmd_list`: command-skills only, id and summary. */
119
+ export function renderCommandSkillList(
120
+ manifests: readonly ExtensionManifest[],
121
+ errors: ReadonlyArray<readonly [string, string]>,
122
+ root: string,
123
+ ): string {
124
+ const commandSkills = manifests.filter((manifest) => manifest.kind === "command-skill");
125
+ const lines = [`Extensions root: ${root}`, "=== COMMAND-SKILL EXTENSIONS ==="];
126
+ if (commandSkills.length === 0) lines.push(" (none)");
127
+ for (const manifest of commandSkills) lines.push(` ${manifest.id}: ${manifest.summary}`);
128
+ return `${lines.join("\n")}\n${invalidBlock(errors)}`;
129
+ }
130
+
131
+ export interface RenderedCommand {
132
+ stdout: string;
133
+ stderr: string;
134
+ exitCode: number;
135
+ }
136
+
137
+ /**
138
+ * Port of `_inspect_extension`. The refusal is TWO stdout lines and exit 1,
139
+ * with the validator's own message as the reason -- so a broken manifest and
140
+ * an absent directory are reported the same way, differing only in the reason.
141
+ */
142
+ export function renderInspectExtension(root: string, extensionId: string): RenderedCommand {
143
+ let manifest: ExtensionManifest;
144
+ try {
145
+ manifest = loadExtensionManifest(join(root, extensionId));
146
+ } catch (error) {
147
+ if (!(error instanceof ExtensionValidationError)) throw error;
148
+ return {
149
+ stdout: `extension/${extensionId} not found or invalid\nreason: ${error.message}\n`,
150
+ stderr: "",
151
+ exitCode: 1,
152
+ };
153
+ }
154
+
155
+ const lines = [
156
+ `=== extension/${extensionId} ===`,
157
+ `name: ${manifest.name}`,
158
+ `category: ${manifest.category}`,
159
+ `kind: ${manifest.kind}`,
160
+ `summary: ${manifest.summary}`,
161
+ `root: ${manifest.root}`,
162
+ `manifest_path: ${manifest.manifestPath}`,
163
+ ];
164
+ if (manifest.entrypoint.length > 0) {
165
+ lines.push("entrypoint:");
166
+ for (const [key, value] of manifest.entrypoint) lines.push(` ${key}: ${value}`);
167
+ }
168
+ lines.push("runtimes:");
169
+ for (const runtimeName of sortByCodePoint(Object.keys(manifest.runtimes))) {
170
+ const runtime = manifest.runtimes[runtimeName];
171
+ if (runtime === undefined) continue;
172
+ lines.push(` ${runtimeName}:`);
173
+ lines.push(` command_name: ${runtime.commandName}`);
174
+ if (runtime.skillFile) lines.push(` skill_file: ${runtime.skillFile}`);
175
+ if (runtime.skillPath) lines.push(` skill_path: ${runtime.skillPath}`);
176
+ }
177
+ return { stdout: `${lines.join("\n")}\n`, stderr: "", exitCode: 0 };
178
+ }
179
+
180
+ export interface RuntimeCatalog {
181
+ schemaVersion: unknown;
182
+ runtime: unknown;
183
+ generatedAt: unknown;
184
+ extensions: unknown[];
185
+ }
186
+
187
+ /**
188
+ * Port of `_load_catalog`. Absent, unreadable, and malformed all answer with
189
+ * the same empty catalog -- the reason `inspect runtime-catalog` on a corrupt
190
+ * file exits 0. A bare LIST is the schema-0 legacy shape.
191
+ */
192
+ export function loadCatalog(catalogPath: string): RuntimeCatalog {
193
+ const empty: RuntimeCatalog = {
194
+ schemaVersion: "1",
195
+ runtime: undefined,
196
+ generatedAt: undefined,
197
+ extensions: [],
198
+ };
199
+ if (!existsSync(catalogPath)) return empty;
200
+ let data: unknown;
201
+ try {
202
+ data = JSON.parse(readFileSync(catalogPath, "utf8"));
203
+ } catch {
204
+ return empty;
205
+ }
206
+ if (Array.isArray(data)) {
207
+ return { schemaVersion: "0", runtime: undefined, generatedAt: undefined, extensions: data };
208
+ }
209
+ if (typeof data !== "object" || data === null) return empty;
210
+ const record = data as Record<string, unknown>;
211
+ return {
212
+ schemaVersion: record.schema_version,
213
+ runtime: record.runtime,
214
+ generatedAt: record.generated_at,
215
+ extensions: Array.isArray(record.extensions) ? record.extensions : [],
216
+ };
217
+ }
218
+
219
+ function catalogField(value: unknown): string {
220
+ return value === undefined || value === null ? "(unknown)" : String(value);
221
+ }
222
+
223
+ /** Port of `_inspect_runtime_catalog`. Always exit 0, even with no catalog. */
224
+ export function renderInspectRuntimeCatalog(runtimeRoot: string, runtime: string): string {
225
+ const catalogPath = join(runtimeRoot, "extensions.json");
226
+ const catalog = loadCatalog(catalogPath);
227
+ const lines = [
228
+ `=== runtime-catalog/${runtime} ===`,
229
+ `runtime_root: ${runtimeRoot}`,
230
+ `catalog_path: ${catalogPath}`,
231
+ `schema_version: ${catalogField(catalog.schemaVersion)}`,
232
+ `generated_at: ${catalogField(catalog.generatedAt)}`,
233
+ "extensions:",
234
+ ];
235
+ if (catalog.extensions.length === 0) {
236
+ lines.push(" (none)");
237
+ return `${lines.join("\n")}\n`;
238
+ }
239
+ for (const item of catalog.extensions) {
240
+ const entry = (typeof item === "object" && item !== null ? item : {}) as Record<
241
+ string,
242
+ unknown
243
+ >;
244
+ lines.push(` ${catalogField(entry.id)} -> ${catalogField(entry.command_name)}`);
245
+ lines.push(` kind: ${catalogField(entry.kind)}`);
246
+ lines.push(` installed_skill_path: ${catalogField(entry.installed_skill_path)}`);
247
+ }
248
+ return `${lines.join("\n")}\n`;
249
+ }