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.
- package/.claude/hooks/log-session-end.sh +85 -0
- package/.claude/hooks/log-user-prompt.sh +85 -0
- package/.claude/hooks/mirror-inject.sh +85 -0
- package/.claude/hooks/session-start.sh +85 -0
- package/.gemini/hooks/log-assistant.sh +85 -0
- package/.gemini/hooks/log-user.sh +85 -0
- package/.gemini/hooks/session-end.sh +85 -0
- package/.gemini/hooks/session-start.sh +85 -0
- package/.pi/extensions/mirror-logger.ts +561 -0
- package/.pi/skills/mm-backup/SKILL.md +21 -0
- package/.pi/skills/mm-build/SKILL.md +1206 -0
- package/.pi/skills/mm-consolidate/SKILL.md +112 -0
- package/.pi/skills/mm-consult/SKILL.md +70 -0
- package/.pi/skills/mm-conversations/SKILL.md +16 -0
- package/.pi/skills/mm-discard/SKILL.md +39 -0
- package/.pi/skills/mm-explore/SKILL.md +255 -0
- package/.pi/skills/mm-help/SKILL.md +74 -0
- package/.pi/skills/mm-identity/SKILL.md +96 -0
- package/.pi/skills/mm-journal/SKILL.md +16 -0
- package/.pi/skills/mm-journey/SKILL.md +23 -0
- package/.pi/skills/mm-journeys/SKILL.md +15 -0
- package/.pi/skills/mm-memories/SKILL.md +17 -0
- package/.pi/skills/mm-mirror/SKILL.md +98 -0
- package/.pi/skills/mm-mute/SKILL.md +18 -0
- package/.pi/skills/mm-new/SKILL.md +18 -0
- package/.pi/skills/mm-recall/SKILL.md +17 -0
- package/.pi/skills/mm-release-notes/SKILL.md +52 -0
- package/.pi/skills/mm-seed/SKILL.md +19 -0
- package/.pi/skills/mm-shadow/SKILL.md +117 -0
- package/.pi/skills/mm-soul/SKILL.md +502 -0
- package/.pi/skills/mm-tasks/SKILL.md +24 -0
- package/.pi/skills/mm-update/SKILL.md +32 -0
- package/.pi/skills/mm-week/SKILL.md +28 -0
- package/.pi/skills/mm-welcome/SKILL.md +24 -0
- package/AGENTS.md +188 -0
- package/README.md +126 -9
- package/bin/loader.js +67 -0
- package/bin/mirror-hook.js +7 -0
- package/bin/mirror.js +7 -0
- package/docs/releases/index.md +99 -0
- package/docs/releases/pending-cutoffs.md +510 -0
- package/docs/releases/v0.10.0.md +123 -0
- package/docs/releases/v0.10.1.md +66 -0
- package/docs/releases/v0.10.10.md +51 -0
- package/docs/releases/v0.10.11.md +39 -0
- package/docs/releases/v0.10.12.md +57 -0
- package/docs/releases/v0.10.13.md +35 -0
- package/docs/releases/v0.10.14.md +42 -0
- package/docs/releases/v0.10.15.md +53 -0
- package/docs/releases/v0.10.16.md +35 -0
- package/docs/releases/v0.10.17.md +43 -0
- package/docs/releases/v0.10.2.md +64 -0
- package/docs/releases/v0.10.3.md +78 -0
- package/docs/releases/v0.10.4.md +42 -0
- package/docs/releases/v0.10.5.md +57 -0
- package/docs/releases/v0.10.6.md +47 -0
- package/docs/releases/v0.10.7.md +53 -0
- package/docs/releases/v0.10.8.md +49 -0
- package/docs/releases/v0.10.9.md +37 -0
- package/docs/releases/v0.11.0.md +86 -0
- package/docs/releases/v0.12.0.md +67 -0
- package/docs/releases/v0.13.0.md +64 -0
- package/docs/releases/v0.14.0.md +68 -0
- package/docs/releases/v0.15.0.md +48 -0
- package/docs/releases/v0.16.0.md +50 -0
- package/docs/releases/v0.16.1.md +55 -0
- package/docs/releases/v0.16.2.md +36 -0
- package/docs/releases/v0.17.0.md +50 -0
- package/docs/releases/v0.17.1.md +58 -0
- package/docs/releases/v0.17.2.md +42 -0
- package/docs/releases/v0.17.3.md +58 -0
- package/docs/releases/v0.18.0.md +84 -0
- package/docs/releases/v0.18.1.md +51 -0
- package/docs/releases/v0.18.2.md +69 -0
- package/docs/releases/v0.19.0.md +85 -0
- package/docs/releases/v0.19.1.md +46 -0
- package/docs/releases/v0.20.0.md +85 -0
- package/docs/releases/v0.21.0.md +61 -0
- package/docs/releases/v0.21.1.md +47 -0
- package/docs/releases/v0.22.0.md +77 -0
- package/docs/releases/v0.22.1.md +42 -0
- package/docs/releases/v0.23.0.md +105 -0
- package/docs/releases/v0.24.0.md +125 -0
- package/docs/releases/v0.25.0.md +107 -0
- package/docs/releases/v0.26.0.md +139 -0
- package/docs/releases/v0.26.1.md +65 -0
- package/docs/releases/v0.26.2.md +43 -0
- package/docs/releases/v0.27.0.md +63 -0
- package/docs/releases/v0.28.0.md +59 -0
- package/docs/releases/v0.29.0.md +61 -0
- package/docs/releases/v0.29.1.md +59 -0
- package/docs/releases/v0.29.2.md +59 -0
- package/docs/releases/v0.29.3.md +93 -0
- package/docs/releases/v0.30.0.md +75 -0
- package/docs/releases/v0.30.1.md +93 -0
- package/docs/releases/v0.30.2.md +66 -0
- package/docs/releases/v0.31.0.md +122 -0
- package/docs/releases/v0.31.1.md +142 -0
- package/docs/releases/v0.31.10.md +118 -0
- package/docs/releases/v0.31.11.md +88 -0
- package/docs/releases/v0.31.12.md +105 -0
- package/docs/releases/v0.31.13.md +99 -0
- package/docs/releases/v0.31.14.md +97 -0
- package/docs/releases/v0.31.2.md +115 -0
- package/docs/releases/v0.31.3.md +142 -0
- package/docs/releases/v0.31.4.md +117 -0
- package/docs/releases/v0.31.5.md +155 -0
- package/docs/releases/v0.31.6.md +132 -0
- package/docs/releases/v0.31.7.md +132 -0
- package/docs/releases/v0.31.8.md +120 -0
- package/docs/releases/v0.31.9.md +120 -0
- package/docs/releases/v0.32.0.md +261 -0
- package/docs/releases/v0.32.1.md +59 -0
- package/docs/releases/v0.8.0.md +118 -0
- package/docs/releases/v0.9.0.md +98 -0
- package/docs/releases/v0.9.1.md +83 -0
- package/package.json +102 -6
- package/plugins/mirror-mind/.claude-plugin/plugin.json +13 -0
- package/plugins/mirror-mind/hooks/hooks.json +50 -0
- package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
- package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
- package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
- package/plugins/mirror-mind/hooks/session-start.sh +98 -0
- package/plugins/mirror-mind/mcp/launch.sh +52 -0
- package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
- package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
- package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
- package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
- package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
- package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
- package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
- package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
- package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
- package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
- package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
- package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +65 -0
- package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
- package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
- package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
- package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
- package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
- package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
- package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
- package/scripts/codex-hooks/session-end.sh +85 -0
- package/scripts/codex-hooks/session-start.sh +85 -0
- package/scripts/codex-mirror.sh +48 -0
- package/templates/identity/README.md +119 -0
- package/templates/identity/ego/behavior.yaml +52 -0
- package/templates/identity/ego/constraints.yaml +15 -0
- package/templates/identity/ego/identity.yaml +43 -0
- package/templates/identity/journeys/personal-growth.yaml +39 -0
- package/templates/identity/organization/identity.yaml +24 -0
- package/templates/identity/organization/principles.yaml +17 -0
- package/templates/identity/personas/coach.yaml +94 -0
- package/templates/identity/personas/designer.yaml +93 -0
- package/templates/identity/personas/doctor.yaml +96 -0
- package/templates/identity/personas/engineer.yaml +77 -0
- package/templates/identity/personas/financial.yaml +97 -0
- package/templates/identity/personas/prompt-engineer.yaml +122 -0
- package/templates/identity/personas/researcher.yaml +88 -0
- package/templates/identity/personas/strategist.yaml +91 -0
- package/templates/identity/personas/teacher.yaml +95 -0
- package/templates/identity/personas/therapist.yaml +91 -0
- package/templates/identity/personas/thinker.yaml +74 -0
- package/templates/identity/personas/writer.yaml +76 -0
- package/templates/identity/self/config.yaml +16 -0
- package/templates/identity/self/soul.yaml +105 -0
- package/templates/identity/user/identity.yaml +30 -0
- package/ts/src/backup/staging.ts +62 -0
- package/ts/src/backup/zipBackup.ts +267 -0
- package/ts/src/backup/zipReader.ts +109 -0
- package/ts/src/backup/zipWriter.ts +148 -0
- package/ts/src/builder/activeCheckpoint.ts +134 -0
- package/ts/src/builder/aggregateStatus.ts +34 -0
- package/ts/src/builder/approve.ts +149 -0
- package/ts/src/builder/argv.ts +292 -0
- package/ts/src/builder/ariadMethod.ts +536 -0
- package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
- package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
- package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
- package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
- package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
- package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
- package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
- package/ts/src/builder/artifacts/storyFiles.ts +61 -0
- package/ts/src/builder/artifacts/storyIndex.ts +166 -0
- package/ts/src/builder/cadence.ts +59 -0
- package/ts/src/builder/card.ts +192 -0
- package/ts/src/builder/checkpointRefused.ts +66 -0
- package/ts/src/builder/closure.ts +964 -0
- package/ts/src/builder/commands.ts +2053 -0
- package/ts/src/builder/cursorPosition.ts +176 -0
- package/ts/src/builder/cursorTransitions.ts +77 -0
- package/ts/src/builder/deliveryCursor.ts +577 -0
- package/ts/src/builder/deliveryStoryClosure.ts +521 -0
- package/ts/src/builder/deliveryStoryPlan.ts +536 -0
- package/ts/src/builder/deliveryStoryReady.ts +160 -0
- package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
- package/ts/src/builder/expand.ts +336 -0
- package/ts/src/builder/flowUnit.ts +339 -0
- package/ts/src/builder/homeSurface.ts +122 -0
- package/ts/src/builder/implementationGuard.ts +125 -0
- package/ts/src/builder/index.ts +11 -0
- package/ts/src/builder/lifecycleRefusal.ts +92 -0
- package/ts/src/builder/lifecycleRibbon.ts +159 -0
- package/ts/src/builder/load.ts +313 -0
- package/ts/src/builder/methodAdoption.ts +113 -0
- package/ts/src/builder/methodDefinition.ts +429 -0
- package/ts/src/builder/methodInspection.ts +371 -0
- package/ts/src/builder/plan.ts +408 -0
- package/ts/src/builder/planPreauthorization.ts +265 -0
- package/ts/src/builder/prepare.ts +225 -0
- package/ts/src/builder/projectPaths.ts +64 -0
- package/ts/src/builder/pull.ts +356 -0
- package/ts/src/builder/pullCandidates.ts +463 -0
- package/ts/src/builder/pullCandidatesRender.ts +238 -0
- package/ts/src/builder/refinementField.ts +93 -0
- package/ts/src/builder/releaseIntent.ts +173 -0
- package/ts/src/builder/resumeState.ts +84 -0
- package/ts/src/builder/resumeSurface.ts +149 -0
- package/ts/src/builder/roadmapGrammar.ts +300 -0
- package/ts/src/builder/roadmapScan.ts +97 -0
- package/ts/src/builder/roadmapScope.ts +210 -0
- package/ts/src/builder/scopePhrases.ts +146 -0
- package/ts/src/builder/storyPaths.ts +196 -0
- package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
- package/ts/src/builder/surfaceProtocol.ts +42 -0
- package/ts/src/builder/templateGeneration.ts +148 -0
- package/ts/src/builder/transition.ts +178 -0
- package/ts/src/consult/args.ts +99 -0
- package/ts/src/consult/core.ts +122 -0
- package/ts/src/consult/modelCatalog.ts +55 -0
- package/ts/src/consult/render.ts +47 -0
- package/ts/src/conversation/append.ts +414 -0
- package/ts/src/conversation/backfill.ts +387 -0
- package/ts/src/conversation/closeTail.ts +467 -0
- package/ts/src/conversation/extraction.ts +333 -0
- package/ts/src/conversation/extractionDriver.ts +130 -0
- package/ts/src/conversation/extractionRun.ts +70 -0
- package/ts/src/conversation/journeyInference.ts +165 -0
- package/ts/src/conversation/journeyRepair.ts +114 -0
- package/ts/src/conversation/lifecycleFaces.ts +197 -0
- package/ts/src/conversation/lifecycleWrites.ts +313 -0
- package/ts/src/conversation/listing.ts +77 -0
- package/ts/src/conversation/logger.ts +576 -0
- package/ts/src/conversation/loggerCli.ts +282 -0
- package/ts/src/conversation/loggerRuntime.ts +259 -0
- package/ts/src/conversation/metadataLifecycle.ts +443 -0
- package/ts/src/conversation/recall.ts +66 -0
- package/ts/src/conversation/sessionComposites.ts +258 -0
- package/ts/src/conversation/sessionImport.ts +90 -0
- package/ts/src/conversation/transcriptBackfill.ts +141 -0
- package/ts/src/cultivation/applyActions.ts +241 -0
- package/ts/src/cultivation/cluster.ts +86 -0
- package/ts/src/cultivation/consolidationStore.ts +281 -0
- package/ts/src/cultivation/promptContext.ts +62 -0
- package/ts/src/cultivation/propose.ts +305 -0
- package/ts/src/cultivation/scan.ts +155 -0
- package/ts/src/db/backupGate.ts +47 -0
- package/ts/src/db/bootstrap.ts +108 -0
- package/ts/src/db/bootstrapLock.ts +223 -0
- package/ts/src/db/copyGuard.ts +60 -0
- package/ts/src/db/database.ts +397 -0
- package/ts/src/db/decode.ts +66 -0
- package/ts/src/db/ftsIntegrity.ts +41 -0
- package/ts/src/db/migrateOnOpen.ts +214 -0
- package/ts/src/db/migrations.ts +576 -0
- package/ts/src/db/readyOnOpen.ts +35 -0
- package/ts/src/db/rowDecode.ts +42 -0
- package/ts/src/db/schema.ts +432 -0
- package/ts/src/db/schemaInventory.ts +225 -0
- package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
- package/ts/src/db/schemaState.ts +91 -0
- package/ts/src/db/schemaTsDivergence.ts +114 -0
- package/ts/src/descriptor/descriptorRead.ts +49 -0
- package/ts/src/docs/docsLint.ts +265 -0
- package/ts/src/explorer/handoff.ts +522 -0
- package/ts/src/explorer/render.ts +335 -0
- package/ts/src/explorer/story.ts +769 -0
- package/ts/src/explorer/transition.ts +72 -0
- package/ts/src/extensions/bindings.ts +170 -0
- package/ts/src/extensions/catalog.ts +249 -0
- package/ts/src/extensions/catalogCommands.ts +513 -0
- package/ts/src/extensions/catalogWrites.ts +652 -0
- package/ts/src/extensions/contextRuntime.ts +325 -0
- package/ts/src/extensions/dispatch.ts +374 -0
- package/ts/src/extensions/errors.ts +24 -0
- package/ts/src/extensions/manifest.ts +356 -0
- package/ts/src/extensions/migrations.ts +350 -0
- package/ts/src/extraction/conversation.ts +304 -0
- package/ts/src/extraction/conversationMetadata.ts +206 -0
- package/ts/src/extraction/fencing.ts +106 -0
- package/ts/src/extraction/json.ts +17 -0
- package/ts/src/extraction/prompts.ts +470 -0
- package/ts/src/frontDoor/args.ts +30 -0
- package/ts/src/frontDoor/argvShape.ts +106 -0
- package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
- package/ts/src/frontDoor/buildRoute.ts +398 -0
- package/ts/src/frontDoor/cli.ts +1865 -0
- package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
- package/ts/src/frontDoor/consultRoute.ts +50 -0
- package/ts/src/frontDoor/contentTailRoute.ts +239 -0
- package/ts/src/frontDoor/conversationLoggerRoute.ts +73 -0
- package/ts/src/frontDoor/cultivationRoute.ts +210 -0
- package/ts/src/frontDoor/dbPath.ts +131 -0
- package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
- package/ts/src/frontDoor/exploreRoute.ts +572 -0
- package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
- package/ts/src/frontDoor/frontDoorLog.ts +57 -0
- package/ts/src/frontDoor/identityWrite.ts +36 -0
- package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
- package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
- package/ts/src/frontDoor/liveBackup.ts +100 -0
- package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
- package/ts/src/frontDoor/namedRefusal.ts +35 -0
- package/ts/src/frontDoor/nodeSupport.ts +24 -0
- package/ts/src/frontDoor/render/consolidate.ts +199 -0
- package/ts/src/frontDoor/render/conversations.ts +33 -0
- package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
- package/ts/src/frontDoor/render/descriptor.ts +20 -0
- package/ts/src/frontDoor/render/detectPersona.ts +50 -0
- package/ts/src/frontDoor/render/icons.ts +13 -0
- package/ts/src/frontDoor/render/identity.ts +59 -0
- package/ts/src/frontDoor/render/identityRows.ts +17 -0
- package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
- package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
- package/ts/src/frontDoor/render/journeys.ts +79 -0
- package/ts/src/frontDoor/render/list.ts +41 -0
- package/ts/src/frontDoor/render/memories.ts +67 -0
- package/ts/src/frontDoor/render/recall.ts +49 -0
- package/ts/src/frontDoor/render/shadow.ts +155 -0
- package/ts/src/frontDoor/render/tasks.ts +99 -0
- package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
- package/ts/src/frontDoor/render/week.ts +113 -0
- package/ts/src/frontDoor/routing.ts +999 -0
- package/ts/src/frontDoor/runtimeRoute.ts +623 -0
- package/ts/src/frontDoor/searchRoute.ts +166 -0
- package/ts/src/frontDoor/seedPaths.ts +98 -0
- package/ts/src/frontDoor/soulRoute.ts +433 -0
- package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
- package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
- package/ts/src/frontDoor/usage.ts +176 -0
- package/ts/src/guards/claudePlugin.ts +252 -0
- package/ts/src/guards/packContents.ts +306 -0
- package/ts/src/guards/piSourcedSkills.ts +70 -0
- package/ts/src/guards/retiredRouteShadows.ts +57 -0
- package/ts/src/guards/retiredSurfaces.ts +564 -0
- package/ts/src/hooks/claude.ts +176 -0
- package/ts/src/hooks/codex.ts +45 -0
- package/ts/src/hooks/gemini.ts +126 -0
- package/ts/src/hooks/main.ts +109 -0
- package/ts/src/hooks/mirrorState.ts +71 -0
- package/ts/src/hooks/payload.ts +68 -0
- package/ts/src/hooks/runtime.ts +159 -0
- package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
- package/ts/src/identity/descriptorGenerate.ts +162 -0
- package/ts/src/identity/identityEdit.ts +143 -0
- package/ts/src/identity/identityKey.ts +77 -0
- package/ts/src/identity/identityRead.ts +69 -0
- package/ts/src/identity/identityStore.ts +80 -0
- package/ts/src/identity/journeyListing.ts +53 -0
- package/ts/src/identity/personaInspect.ts +44 -0
- package/ts/src/identity/personaListing.ts +37 -0
- package/ts/src/identity/setIdentity.ts +64 -0
- package/ts/src/index.ts +231 -0
- package/ts/src/init/init.ts +111 -0
- package/ts/src/journey/journeyOptions.ts +131 -0
- package/ts/src/journey/journeyRemoval.ts +158 -0
- package/ts/src/journey/journeyStatus.ts +149 -0
- package/ts/src/journey/journeySyncFile.ts +87 -0
- package/ts/src/journey/journeyWrite.ts +203 -0
- package/ts/src/journey/parentJourney.ts +41 -0
- package/ts/src/journey/validateParentJourney.ts +55 -0
- package/ts/src/mcp/boundary.ts +151 -0
- package/ts/src/mcp/guards.ts +244 -0
- package/ts/src/mcp/main.ts +121 -0
- package/ts/src/mcp/payload.ts +141 -0
- package/ts/src/mcp/protocol.ts +141 -0
- package/ts/src/mcp/readModels.ts +241 -0
- package/ts/src/mcp/registry.ts +201 -0
- package/ts/src/mcp/serve.ts +120 -0
- package/ts/src/mcp/tools/deterministic.ts +137 -0
- package/ts/src/mcp/tools/providerCrossing.ts +187 -0
- package/ts/src/mcp/wire.ts +8 -0
- package/ts/src/memory/journal.ts +180 -0
- package/ts/src/memory/listing.ts +107 -0
- package/ts/src/memory/memoryWrite.ts +88 -0
- package/ts/src/memory/reinforcement.ts +35 -0
- package/ts/src/mirror/context.ts +161 -0
- package/ts/src/mirror/defaultResolution.ts +199 -0
- package/ts/src/mirror/orchestration.ts +364 -0
- package/ts/src/mirror/reception.ts +194 -0
- package/ts/src/mirror/render.ts +75 -0
- package/ts/src/mirror/runtimeSession.ts +205 -0
- package/ts/src/mode/operatingMode.ts +148 -0
- package/ts/src/observability/callOutcome.ts +115 -0
- package/ts/src/observability/inspectLedger.ts +329 -0
- package/ts/src/observability/ledgerHooks.ts +126 -0
- package/ts/src/observability/llmCalls.ts +154 -0
- package/ts/src/persona/detectPersona.ts +81 -0
- package/ts/src/planning/promptAssembly.ts +111 -0
- package/ts/src/planning/weekPending.ts +81 -0
- package/ts/src/planning/weekPlan.ts +183 -0
- package/ts/src/planning/weekSave.ts +117 -0
- package/ts/src/providers/config.ts +189 -0
- package/ts/src/providers/cost.ts +64 -0
- package/ts/src/providers/credits.ts +204 -0
- package/ts/src/providers/embedding.ts +321 -0
- package/ts/src/providers/familyProviders.ts +147 -0
- package/ts/src/providers/llm.ts +334 -0
- package/ts/src/providers/openrouter.ts +244 -0
- package/ts/src/providers/redaction.ts +110 -0
- package/ts/src/providers/replay.ts +15 -0
- package/ts/src/providers/transport.ts +410 -0
- package/ts/src/repair/encodingRepair.ts +253 -0
- package/ts/src/runtime/backup.ts +151 -0
- package/ts/src/runtime/channel.ts +146 -0
- package/ts/src/runtime/config.ts +168 -0
- package/ts/src/runtime/diagnose.ts +686 -0
- package/ts/src/runtime/git.ts +510 -0
- package/ts/src/runtime/installKind.ts +220 -0
- package/ts/src/runtime/migrate.ts +154 -0
- package/ts/src/runtime/packageIdentity.ts +102 -0
- package/ts/src/runtime/releaseNotes.ts +244 -0
- package/ts/src/runtime/status.ts +557 -0
- package/ts/src/runtime/strategies/clone.ts +200 -0
- package/ts/src/runtime/strategies/package.ts +328 -0
- package/ts/src/runtime/treeRoot.ts +30 -0
- package/ts/src/runtime/update.ts +445 -0
- package/ts/src/runtime/updateGate.ts +40 -0
- package/ts/src/runtime/updatePipeline.ts +159 -0
- package/ts/src/runtime/version.ts +36 -0
- package/ts/src/runtime/wiring.ts +130 -0
- package/ts/src/search/memorySearch.ts +338 -0
- package/ts/src/search/ranker.ts +154 -0
- package/ts/src/seed/seed.ts +256 -0
- package/ts/src/seed/seedYaml.ts +133 -0
- package/ts/src/soul/apply.ts +218 -0
- package/ts/src/soul/harvest.ts +267 -0
- package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
- package/ts/src/soul/prompts/soul_self_voice.md +219 -0
- package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
- package/ts/src/soul/prompts.ts +85 -0
- package/ts/src/soul/render.ts +358 -0
- package/ts/src/soul/state.ts +212 -0
- package/ts/src/soul/transition.ts +37 -0
- package/ts/src/tasks/journeyPathParse.ts +113 -0
- package/ts/src/tasks/taskImportSync.ts +142 -0
- package/ts/src/tasks/taskStore.ts +312 -0
- package/ts/src/tasks/weekView.ts +120 -0
- package/ts/src/util/clipCodePoints.ts +26 -0
- package/ts/src/util/paths.ts +63 -0
- package/ts/src/util/program.ts +9 -0
- package/ts/src/util/pyGenerators.ts +144 -0
- package/ts/src/util/pythonText.ts +317 -0
- package/ts/src/util/semver.ts +45 -0
- package/ts/src/util/shellWord.ts +25 -0
- package/ts/src/util/slug.ts +64 -0
- package/ts/src/welcome/card.ts +339 -0
- package/ts/src/welcome/statusLine.ts +101 -0
- 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
|
+
}
|