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,113 @@
1
+ // CR079: no Ariad command replaces content it did not write.
2
+ //
3
+ // Every file the Builder writes goes through here, under one of two policies.
4
+ //
5
+ // A SCAFFOLD (`create-only`) is written once, when absent, and never again: the
6
+ // Plan packages, Expand's story indexes, the method templates. From its first
7
+ // write on, it belongs to the Driver.
8
+ //
9
+ // A RECORD (`sealed-record`) may be rewritten, because a checkpoint recorded as
10
+ // pending and later accepted runs its command again, and the file has to follow.
11
+ // These are the closure artifacts: `validation.md`, `review.md`, `coherence.md`
12
+ // and `done.md`, at story and Delivery Story level. A record is rewritten only
13
+ // while the runtime can prove that it wrote the file and nobody changed it
14
+ // since. The proof is a seal on the record's last line: the SHA-256 of everything
15
+ // above it, with line endings normalized, so that a CRLF checkout does not read
16
+ // as an edit.
17
+ //
18
+ // Anything else is PRESERVED, byte for byte, and the caller reports that: an
19
+ // authored file, an edited record, a record written before the seal existed, a
20
+ // removed seal, or text after the seal. Before this, the closure writers
21
+ // replaced whatever was there, and two stories lost authored validation evidence
22
+ // to them.
23
+ //
24
+ // Both policies refuse a path outside the project before writing anything.
25
+ // `builderWriteGuard.test.ts` fails if any other module under `ts/src/builder`
26
+ // writes a file, so a new artifact cannot arrive without choosing a policy here.
27
+
28
+ import { createHash } from "node:crypto";
29
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
30
+ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
31
+
32
+ export type ArtifactPolicy = "create-only" | "sealed-record";
33
+
34
+ /** What the writer did, which is what a surface must report: never a pre-check. */
35
+ export type ArtifactOutcome = "created" | "updated" | "existing" | "preserved";
36
+
37
+ export class ArtifactOutsideProjectError extends Error {}
38
+
39
+ const SEAL_TEXT =
40
+ "Ariad wrote this file and rewrites it only while this line matches the text above it. " +
41
+ "Edit the file and Ariad will leave it as it is.";
42
+
43
+ /** The hash and a closing marker; the prose between them may change without orphaning old seals. */
44
+ const SEAL_LINE = /^<!-- ariad-seal sha256:([0-9a-f]{64}) .*-->$/u;
45
+
46
+ export function writeBuilderArtifact(options: {
47
+ readonly path: string;
48
+ readonly content: string;
49
+ readonly policy: ArtifactPolicy;
50
+ readonly projectRoot: string;
51
+ }): ArtifactOutcome {
52
+ const target = confinedTo(options.projectRoot, options.path);
53
+ const sealed = options.policy === "sealed-record";
54
+ if (!existsSync(target)) {
55
+ mkdirSync(dirname(target), { recursive: true });
56
+ writeFileSync(target, sealed ? sealArtifact(options.content) : options.content, "utf8");
57
+ return "created";
58
+ }
59
+ if (!sealed) return "existing";
60
+ if (!isSealedByAriad(readFileSync(target, "utf8"))) return "preserved";
61
+ writeFileSync(target, sealArtifact(options.content), "utf8");
62
+ return "updated";
63
+ }
64
+
65
+ /**
66
+ * The project root a write must stay inside. A path that arrives without one is a
67
+ * caller bug: it is refused loudly rather than written unconfined.
68
+ */
69
+ export function requireProjectRoot(projectRoot: string | null | undefined, path: string): string {
70
+ if (!projectRoot) {
71
+ throw new Error(`Error: ${path} was given without its project root; refusing to write it.`);
72
+ }
73
+ return projectRoot;
74
+ }
75
+
76
+ /** The content, then one line carrying the SHA-256 of that content. */
77
+ export function sealArtifact(content: string): string {
78
+ const body = normalized(content.endsWith("\n") ? content : `${content}\n`);
79
+ return `${body}<!-- ariad-seal sha256:${sha256(body)} — ${SEAL_TEXT} -->\n`;
80
+ }
81
+
82
+ /** True only when the last line is a seal whose hash matches everything above it. */
83
+ export function isSealedByAriad(text: string): boolean {
84
+ const lines = normalized(text).replace(/\n+$/u, "").split("\n");
85
+ const match = SEAL_LINE.exec(lines.pop() ?? "");
86
+ if (match === null) return false;
87
+ return match[1] === sha256(lines.length > 0 ? `${lines.join("\n")}\n` : "");
88
+ }
89
+
90
+ function normalized(text: string): string {
91
+ return text.replaceAll("\r\n", "\n");
92
+ }
93
+
94
+ function sha256(text: string): string {
95
+ return createHash("sha256").update(text, "utf8").digest("hex");
96
+ }
97
+
98
+ /**
99
+ * Both resolved against the working directory, as `writeFileSync` would resolve the
100
+ * path: a relative project path (the lifecycle corpus uses one) must not be read as
101
+ * relative to itself.
102
+ */
103
+ function confinedTo(projectRoot: string, path: string): string {
104
+ const root = resolve(projectRoot);
105
+ const target = resolve(path);
106
+ const within = relative(root, target);
107
+ if (within === "" || within === ".." || within.startsWith(`..${sep}`) || isAbsolute(within)) {
108
+ throw new ArtifactOutsideProjectError(
109
+ `Error: refusing to write ${path}: it is outside the project at ${root}.`,
110
+ );
111
+ }
112
+ return target;
113
+ }
@@ -0,0 +1,199 @@
1
+ // CV22.DS7.US8 plateau 4 — the four files story closure writes.
2
+ //
3
+ // Port of `_render_validation_artifact`, `_render_review_artifact`,
4
+ // `_render_coherence_artifact`, and `_render_done_artifact` from
5
+ // `src/memory/builder/lifecycle.py`.
6
+ //
7
+ // These are RECORDS, not scaffolds: a checkpoint recorded pending and later
8
+ // accepted runs its verb again, and the file has to follow. Python wrote them
9
+ // unconditionally, and the port reproduced that until CR079 settled it, because a
10
+ // guard added during the port would have hidden the CR. The overwrite destroyed a
11
+ // 235-line authored `validation.md`, and a 146-line one a story later.
12
+ // `writeClosureArtifact` now writes through the artifact writer as a sealed
13
+ // record: rewritten only while its seal proves Ariad wrote the file and nobody
14
+ // changed it, and preserved byte for byte otherwise. The corpus sequence
15
+ // `closure_preserves_authored_artifacts` records the authored files surviving.
16
+ //
17
+ // Each body's `## ` headings are also the shape a human reassembles by hand after an
18
+ // overwrite, so they are graded as bytes rather than as structure.
19
+
20
+ import {
21
+ type ArtifactOutcome,
22
+ requireProjectRoot,
23
+ writeBuilderArtifact,
24
+ } from "./artifactWriter.ts";
25
+ import { markdownList } from "./planArtifacts.ts";
26
+
27
+ /** Python `_render_validation_artifact`. */
28
+ export function renderValidationArtifact(report: {
29
+ activeItem: string;
30
+ automatedChecks: readonly string[];
31
+ checksStatus: string;
32
+ e2eDecision: string;
33
+ e2eEvidence: string | null;
34
+ navigatorValidationRoute: string;
35
+ navigatorAccepted: boolean;
36
+ expectedObservation: string;
37
+ passCondition: string;
38
+ failCondition: string;
39
+ missingEvidence: readonly string[];
40
+ }): string {
41
+ return `# Validation — ${report.activeItem}
42
+
43
+ ## Status
44
+
45
+ ${report.missingEvidence.length > 0 ? "Blocked" : "Passed"}
46
+
47
+ ## Automated Checks
48
+
49
+ ${markdownList(
50
+ report.automatedChecks.length > 0 ? report.automatedChecks : ["No automated checks declared."],
51
+ )}
52
+
53
+ Checks status: ${report.checksStatus}
54
+
55
+ ## E2E
56
+
57
+ Decision: ${report.e2eDecision}
58
+
59
+ Evidence: ${report.e2eEvidence || "none"}
60
+
61
+ ## Navigator Validation
62
+
63
+ Route: ${report.navigatorValidationRoute}
64
+
65
+ Navigator accepted: ${report.navigatorAccepted ? "yes" : "no"}
66
+
67
+ Expected observation: ${report.expectedObservation}
68
+
69
+ Pass condition: ${report.passCondition}
70
+
71
+ Fail condition: ${report.failCondition}
72
+
73
+ ## Missing Evidence
74
+
75
+ ${markdownList(report.missingEvidence.length > 0 ? report.missingEvidence : ["none"])}
76
+ `;
77
+ }
78
+
79
+ /** Python `_render_review_artifact`. */
80
+ export function renderReviewArtifact(report: {
81
+ activeItem: string;
82
+ debtFindings: readonly string[];
83
+ debtDecision: string;
84
+ deferReason: string | null;
85
+ revisitTrigger: string | null;
86
+ missingDecision: readonly string[];
87
+ }): string {
88
+ return `# Review — ${report.activeItem}
89
+
90
+ ## Status
91
+
92
+ ${report.missingDecision.length > 0 ? "Pending debt decision" : "Reviewed"}
93
+
94
+ ## Debt Findings
95
+
96
+ ${markdownList(
97
+ report.debtFindings.length > 0 ? report.debtFindings : ["No debt findings declared."],
98
+ )}
99
+
100
+ ## Debt Decision
101
+
102
+ ${report.debtDecision}
103
+
104
+ ## Defer Reason
105
+
106
+ ${report.deferReason || "none"}
107
+
108
+ ## Revisit Trigger
109
+
110
+ ${report.revisitTrigger || "none"}
111
+
112
+ ## Missing Decision
113
+
114
+ ${markdownList(report.missingDecision.length > 0 ? report.missingDecision : ["none"])}
115
+ `;
116
+ }
117
+
118
+ /** Python `_render_coherence_artifact`. */
119
+ export function renderCoherenceArtifact(report: {
120
+ activeItem: string;
121
+ processAlignment: string;
122
+ projectAlignment: string;
123
+ productAlignment: string;
124
+ localDifferences: readonly string[];
125
+ missingCoherence: readonly string[];
126
+ }): string {
127
+ return `# Coherence — ${report.activeItem}
128
+
129
+ ## Status
130
+
131
+ ${report.missingCoherence.length > 0 ? "Pending coherence" : "Coherent"}
132
+
133
+ ## Process Alignment
134
+
135
+ ${report.processAlignment}
136
+
137
+ ## Project Alignment
138
+
139
+ ${report.projectAlignment}
140
+
141
+ ## Product Alignment
142
+
143
+ ${report.productAlignment}
144
+
145
+ ## Local Guide Differences
146
+
147
+ ${markdownList(report.localDifferences.length > 0 ? report.localDifferences : ["none"])}
148
+
149
+ ## Missing Coherence
150
+
151
+ ${markdownList(report.missingCoherence.length > 0 ? report.missingCoherence : ["none"])}
152
+ `;
153
+ }
154
+
155
+ /** Python `_render_done_artifact`. */
156
+ export function renderDoneArtifact(report: {
157
+ activeItem: string;
158
+ historyAction: string;
159
+ roadmapUpdate: string;
160
+ nextRecommendation: string;
161
+ missingDone: readonly string[];
162
+ }): string {
163
+ return `# Done — ${report.activeItem}
164
+
165
+ ## Status
166
+
167
+ ${report.missingDone.length > 0 ? "Pending Done" : "Done"}
168
+
169
+ ## History Action
170
+
171
+ ${report.historyAction}
172
+
173
+ ## Roadmap Update
174
+
175
+ ${report.roadmapUpdate}
176
+
177
+ ## Next Recommendation
178
+
179
+ ${report.nextRecommendation}
180
+
181
+ ## Missing Done
182
+
183
+ ${markdownList(report.missingDone.length > 0 ? report.missingDone : ["none"])}
184
+ `;
185
+ }
186
+
187
+ /** A closure record: created sealed, rewritten while its seal holds, otherwise preserved. */
188
+ export function writeClosureArtifact(
189
+ path: string,
190
+ content: string,
191
+ projectRoot: string | null | undefined,
192
+ ): ArtifactOutcome {
193
+ return writeBuilderArtifact({
194
+ path,
195
+ content,
196
+ policy: "sealed-record",
197
+ projectRoot: requireProjectRoot(projectRoot, path),
198
+ });
199
+ }
@@ -0,0 +1,316 @@
1
+ // CV22.DS7.US8 plateau 5 — the Delivery Story package and the closure artifacts.
2
+ //
3
+ // Port of `_write_delivery_story_package` / `_render_*_artifact` in
4
+ // `delivery_story_plan.py` and `_write_artifact` / `_render_artifact` in
5
+ // `delivery_story_closure.py`.
6
+ //
7
+ // Two OPPOSITE file rules live here, and the difference is deliberate in Python:
8
+ //
9
+ // * the Plan package preserves — `index.md`, `plan.md`, and `test-guide.md` are
10
+ // written only when absent, so Expand-generated or hand-authored content
11
+ // survives Plan and approval alike;
12
+ // * the closure artifacts OVERWRITE — `validation.md`, `review.md`,
13
+ // `coherence.md`, and `done.md` are rewritten on every call. That is CR079, the
14
+ // same defect story closure carries, and it is reproduced rather than repaired:
15
+ // adding the "obvious" existence guard here fails the corpus on purpose.
16
+ //
17
+ // The manifest each writer returns reports the REAL disk action, which is what the
18
+ // artifact writer says it did, because the ARTIFACTS_MATERIALIZED surface must match
19
+ // what happened rather than what was intended (CR079). The package is a scaffold,
20
+ // written only where absent; the closure artifact is a sealed record.
21
+
22
+ import { existsSync, readFileSync } from "node:fs";
23
+ import { dirname, join } from "node:path";
24
+ import { pySplitLines, pyStrip } from "#util/pythonText.ts";
25
+ import {
26
+ existingArtifact,
27
+ type MaterializedArtifact,
28
+ materializedArtifact,
29
+ } from "./artifactSurfaces.ts";
30
+ import {
31
+ type ArtifactOutcome,
32
+ requireProjectRoot,
33
+ writeBuilderArtifact,
34
+ } from "./artifactWriter.ts";
35
+
36
+ /** What the renderers need from a Delivery Story Plan report. */
37
+ export interface DeliveryStoryArtifactInput {
38
+ readonly journey: string;
39
+ readonly method: string;
40
+ readonly deliveryStory: string;
41
+ readonly deliveryStoryTitle: string | null;
42
+ readonly childWorkItems: readonly string[];
43
+ readonly objective: string;
44
+ }
45
+
46
+ const FLOW_UNIT_DELIVERY_STORY = "delivery_story";
47
+
48
+ /** Python's `"\n".join(f"- {item}" for item in items) or "- none"`. */
49
+ function childList(items: readonly string[]): string {
50
+ return items.map((item) => `- ${item}`).join("\n") || "- none";
51
+ }
52
+
53
+ /** Python `_PLAN_CONTRACT_SECTIONS`, with the guidance text that becomes the placeholder. */
54
+ const PLAN_CONTRACT_SECTIONS: readonly (readonly [string, string])[] = [
55
+ ["Scope", "name what this Delivery Story delivers across its child work packages."],
56
+ ["Non-Goals", "name what is explicitly out of scope for this Delivery Story."],
57
+ [
58
+ "Acceptance Behavior",
59
+ "describe the aggregate observable outcome, using Given/When/Then when practical.",
60
+ ],
61
+ [
62
+ "Validation Route",
63
+ "describe how the aggregate delivery is validated, including whether E2E is required.",
64
+ ],
65
+ [
66
+ "Implementation Contract",
67
+ "record the constraints for child work: TDD for behavior changes, changes scoped to " +
68
+ "this Delivery Story's children, and no silent scope absorption.",
69
+ ],
70
+ ];
71
+
72
+ /** Python `_placeholder_line`. */
73
+ export function placeholderLine(guidance: string): string {
74
+ return `Pending — ${guidance}`;
75
+ }
76
+
77
+ /**
78
+ * Python `_unfilled_plan_sections_for` in `delivery_story_plan.py`.
79
+ *
80
+ * NOT the story-level rule (`planSectionsToAuthor` in `scaffoldState.ts`), and the
81
+ * difference is an authority boundary rather than a detail. The Delivery Story check carries two
82
+ * conditions the story-level one does not:
83
+ *
84
+ * * the section body CONTAINS this section's exact scaffold line
85
+ * (`Pending — <guidance>`) anywhere, not only at the start of a line;
86
+ * * the casefolded body contains `placeholder` ANYWHERE, where the story-level
87
+ * rule only matches it at the start of a line.
88
+ *
89
+ * So the DS rule is strictly broader, and reusing the story helper would consume a
90
+ * preauthorization receipt against a Plan Python still calls unfilled — authority
91
+ * granted where Python refuses it. Graded by
92
+ * `delivery_story_preauthorization_refuses_prose_placeholder`.
93
+ */
94
+ export function unfilledDeliveryStoryPlanSections(planPath: string | null): string[] {
95
+ const headers = PLAN_CONTRACT_SECTIONS.map(([header]) => header);
96
+ if (planPath === null || !existsSync(planPath)) return headers;
97
+ const sections = levelTwoSections(readFileSync(planPath, "utf8"));
98
+ const throwaway = new Set(["todo", "tbd", "...", "n/a", "none"]);
99
+ const unfilled: string[] = [];
100
+ for (const [header, guidance] of PLAN_CONTRACT_SECTIONS) {
101
+ const body = pyStrip(sections.get(header) ?? "");
102
+ const normalized = body.toLowerCase();
103
+ const lines = pySplitLines(body)
104
+ .map((line) => pyStrip(line).toLowerCase())
105
+ .filter((line) => line !== "");
106
+ if (
107
+ !body ||
108
+ body.includes(placeholderLine(guidance)) ||
109
+ lines.some((line) => line.startsWith("pending")) ||
110
+ lines.some((line) => throwaway.has(line)) ||
111
+ normalized.includes("placeholder")
112
+ ) {
113
+ unfilled.push(header);
114
+ }
115
+ }
116
+ return unfilled;
117
+ }
118
+
119
+ /**
120
+ * Python `_level_two_sections` — the DS copy.
121
+ *
122
+ * `setdefault` semantics: a repeated `## Scope` appends to the first section.
123
+ */
124
+ function levelTwoSections(planText: string): Map<string, string> {
125
+ const sections = new Map<string, string[]>();
126
+ let current: string | null = null;
127
+ for (const line of planText.split("\n")) {
128
+ if (line.startsWith("## ")) {
129
+ current = pyStrip(line.slice(3));
130
+ if (!sections.has(current)) sections.set(current, []);
131
+ } else if (current !== null) {
132
+ sections.get(current)?.push(line);
133
+ }
134
+ }
135
+ return new Map([...sections].map(([header, lines]) => [header, lines.join("\n")]));
136
+ }
137
+
138
+ /** Python `_render_plan_artifact`. */
139
+ export function renderDeliveryStoryPlanArtifact(report: DeliveryStoryArtifactInput): string {
140
+ const contractSections = PLAN_CONTRACT_SECTIONS.map(
141
+ ([header, guidance]) => `## ${header}\n\n${placeholderLine(guidance)}`,
142
+ ).join("\n\n");
143
+ return `# Delivery Story Plan — ${report.deliveryStory}
144
+
145
+ **Journey:** ${report.journey}
146
+ **Method:** ${report.method}
147
+ **Navigator Flow Unit:** ${FLOW_UNIT_DELIVERY_STORY}
148
+
149
+ ## Delivery Story
150
+
151
+ ${report.deliveryStoryTitle || "Untitled Delivery Story"}
152
+
153
+ ## Objective
154
+
155
+ ${report.objective}
156
+
157
+ ## Child Work Packages
158
+
159
+ ${childList(report.childWorkItems)}
160
+
161
+ ${contractSections}
162
+
163
+ ---
164
+
165
+ _Approval and lifecycle state are tracked by the Builder runtime, not duplicated in this plan._
166
+ `;
167
+ }
168
+
169
+ /** Python `_render_index_artifact`. */
170
+ export function renderDeliveryStoryIndexArtifact(report: DeliveryStoryArtifactInput): string {
171
+ const title = report.deliveryStoryTitle || report.deliveryStory;
172
+ return `[< Parent](../index.md)
173
+
174
+ # ${report.deliveryStory} — ${title}
175
+
176
+ **Status:** 🟡 Planned
177
+ **Type:** Delivery Story
178
+
179
+ ---
180
+
181
+ ## Outcome
182
+
183
+ ${report.objective}
184
+
185
+ ## Child Work Packages
186
+
187
+ ${childList(report.childWorkItems)}
188
+
189
+ ## Done Condition
190
+
191
+ The Delivery Story is done when its child work packages produce a coherent delivery outcome.
192
+
193
+ ---
194
+
195
+ ## Artifacts
196
+
197
+ - [Plan](plan.md)
198
+ - [Test Guide](test-guide.md)
199
+ `;
200
+ }
201
+
202
+ /** Python `_render_test_guide_artifact`. */
203
+ export function renderDeliveryStoryTestGuideArtifact(report: DeliveryStoryArtifactInput): string {
204
+ return `[< Story](index.md)
205
+
206
+ # Test Guide — ${report.deliveryStory}
207
+
208
+ ## Aggregate Validation
209
+
210
+ Pending aggregate Delivery Story validation across child work packages.
211
+
212
+ ## Child Work Packages
213
+
214
+ ${childList(report.childWorkItems)}
215
+
216
+ ## Navigator Validation
217
+
218
+ Provide the Navigator-visible route with expected observation, pass condition, and fail condition before the Delivery Story can pass aggregate Validation.
219
+
220
+ ## Validation Evidence
221
+
222
+ Pending implementation and validation.
223
+ `;
224
+ }
225
+
226
+ /**
227
+ * Python `_write_delivery_story_package`.
228
+ *
229
+ * Insert-if-absent for all three files, and the manifest order is
230
+ * `index → plan → test guide` regardless of which one was created.
231
+ */
232
+ export function writeDeliveryStoryPackage(
233
+ planPath: string,
234
+ report: DeliveryStoryArtifactInput,
235
+ projectRoot: string | null | undefined,
236
+ ): readonly MaterializedArtifact[] {
237
+ const parent = dirname(planPath);
238
+ const root = requireProjectRoot(projectRoot, planPath);
239
+ const write = (kind: string, path: string, content: string): MaterializedArtifact =>
240
+ writeBuilderArtifact({ path, content, policy: "create-only", projectRoot: root }) === "existing"
241
+ ? existingArtifact(kind, path)
242
+ : materializedArtifact(kind, path, { existedBefore: false });
243
+ // Written plan first, as before: the plan is the artifact the other two describe.
244
+ const plan = write("plan", planPath, renderDeliveryStoryPlanArtifact(report));
245
+ const index = write(
246
+ "story index",
247
+ join(parent, "index.md"),
248
+ renderDeliveryStoryIndexArtifact(report),
249
+ );
250
+ const testGuide = write(
251
+ "test guide",
252
+ join(parent, "test-guide.md"),
253
+ renderDeliveryStoryTestGuideArtifact(report),
254
+ );
255
+ return [index, plan, testGuide];
256
+ }
257
+
258
+ /** What the closure artifact renderer needs from a DS closure report. */
259
+ export interface DeliveryStoryClosureArtifactInput {
260
+ readonly deliveryStory: string;
261
+ readonly childWorkItems: readonly string[];
262
+ readonly checkpoint: string;
263
+ readonly status: string;
264
+ readonly summary: string;
265
+ readonly boundary: string;
266
+ }
267
+
268
+ /** Python `_render_artifact` in `delivery_story_closure.py`. */
269
+ export function renderDeliveryStoryClosureArtifact(
270
+ report: DeliveryStoryClosureArtifactInput,
271
+ ): string {
272
+ // Python's `str.title()` over a `_`-to-space checkpoint name: `debt_review`
273
+ // becomes `Debt Review`.
274
+ const title = report.checkpoint
275
+ .replaceAll("_", " ")
276
+ .replace(
277
+ /[A-Za-z]+('[A-Za-z]*)?/g,
278
+ (word) => word[0].toUpperCase() + word.slice(1).toLowerCase(),
279
+ );
280
+ return `# ${title} — ${report.deliveryStory}
281
+
282
+ ## Status
283
+
284
+ ${report.status}
285
+
286
+ ## Summary
287
+
288
+ ${report.summary}
289
+
290
+ ## Child Work Packages
291
+
292
+ ${report.childWorkItems.map((item) => `- ${item}`).join("\n") || "- none"}
293
+
294
+ ## Boundary
295
+
296
+ ${report.boundary}
297
+ `;
298
+ }
299
+
300
+ /**
301
+ * A Delivery Story closure record: created sealed, rewritten while its seal holds,
302
+ * and otherwise preserved (CR079). Null when the story has no package to write to.
303
+ */
304
+ export function writeDeliveryStoryClosureArtifact(
305
+ path: string | null,
306
+ report: DeliveryStoryClosureArtifactInput,
307
+ projectRoot: string | null | undefined,
308
+ ): ArtifactOutcome | null {
309
+ if (path === null) return null;
310
+ return writeBuilderArtifact({
311
+ path,
312
+ content: renderDeliveryStoryClosureArtifact(report),
313
+ policy: "sealed-record",
314
+ projectRoot: requireProjectRoot(projectRoot, path),
315
+ });
316
+ }