mirror-mind 0.0.1 → 0.33.0
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-assistant-reply.sh +85 -0
- 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 +646 -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 +100 -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.33.0.md +164 -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 +17 -0
- package/plugins/mirror-mind/hooks/hooks.json +62 -0
- package/plugins/mirror-mind/hooks/log-assistant-reply.sh +98 -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/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 +67 -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/hookPayload.ts +51 -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 +851 -0
- package/ts/src/conversation/loggerCli.ts +321 -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 +1872 -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 +83 -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 +1001 -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/sessionStartWelcomeRoute.ts +166 -0
- package/ts/src/frontDoor/soulRoute.ts +433 -0
- package/ts/src/frontDoor/stdinSource.ts +37 -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 +298 -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 +214 -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 +73 -0
- package/ts/src/hooks/runtime.ts +179 -0
- package/ts/src/hooks/runtimeDetection.ts +34 -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/mirrorForm.ts +43 -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,225 @@
|
|
|
1
|
+
// CV22.DS7.US8 plateau 3 — Prepare: read the terrain, decide nothing.
|
|
2
|
+
//
|
|
3
|
+
// Port of `prepare_lifecycle_item` and `render_prepare_report` from
|
|
4
|
+
// `src/memory/builder/lifecycle.py`.
|
|
5
|
+
//
|
|
6
|
+
// Prepare is the cheapest event in the lifecycle and the easiest to get subtly
|
|
7
|
+
// wrong, because almost all of its output is derived from ONE field: the active
|
|
8
|
+
// item's level. That field decides whether the story is implementable, whether a
|
|
9
|
+
// granularity decision is required, which rule text appears, and whether the next
|
|
10
|
+
// event renders as `Plan` or `Expand or Plan`. An unknown level is a third case,
|
|
11
|
+
// not an error.
|
|
12
|
+
//
|
|
13
|
+
// It also writes: the cursor moves to `last_delivery_event=prepare` and clears any
|
|
14
|
+
// pending confirmation, which is what lets Plan's `Prepare must be completed`
|
|
15
|
+
// guard mean something.
|
|
16
|
+
//
|
|
17
|
+
// CR114 (D3): which is also why it must not run from anywhere. It ran on any cursor,
|
|
18
|
+
// so a Done story prepared again went back before Plan, where Plan accepted it. It now
|
|
19
|
+
// runs only at Pull, at Prepare again, or on an item with no event, and refuses
|
|
20
|
+
// anywhere else before writing: as already complete from Plan on, by CR067's rule,
|
|
21
|
+
// and as not its place at a Delivery Story's own events or an event it does not know.
|
|
22
|
+
|
|
23
|
+
import { existsSync } from "node:fs";
|
|
24
|
+
import { join, resolve } from "node:path";
|
|
25
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
26
|
+
import { pyTitle } from "#util/pythonText.ts";
|
|
27
|
+
import { cardContextItems, cardPrefixed, cardText, cardWrapped } from "./card.ts";
|
|
28
|
+
import { isImplementableByDefault, normalizeRequired } from "./cursorTransitions.ts";
|
|
29
|
+
import {
|
|
30
|
+
type BuilderDeliveryCursor,
|
|
31
|
+
type CursorWriteDeps,
|
|
32
|
+
getDeliveryCursor,
|
|
33
|
+
setDeliveryCursor,
|
|
34
|
+
} from "./deliveryCursor.ts";
|
|
35
|
+
import { LifecycleRefusal, refuseIfAlreadyComplete } from "./lifecycleRefusal.ts";
|
|
36
|
+
import { renderLifecycleRibbon } from "./lifecycleRibbon.ts";
|
|
37
|
+
import { wrapAriadSurface } from "./surfaceProtocol.ts";
|
|
38
|
+
|
|
39
|
+
/** Python `BuilderPrepareReport`. */
|
|
40
|
+
export interface BuilderPrepareReport {
|
|
41
|
+
readonly journey: string;
|
|
42
|
+
readonly method: string;
|
|
43
|
+
readonly activeItem: string;
|
|
44
|
+
readonly activeItemTitle: string | null;
|
|
45
|
+
readonly activeItemLevel: string | null;
|
|
46
|
+
readonly implementableByDefault: boolean;
|
|
47
|
+
readonly granularityDecisionRequired: boolean;
|
|
48
|
+
readonly contextSummary: readonly string[];
|
|
49
|
+
readonly storyShapeAssessment: string;
|
|
50
|
+
readonly risks: readonly string[];
|
|
51
|
+
readonly applicableRules: readonly string[];
|
|
52
|
+
readonly cursor: BuilderDeliveryCursor;
|
|
53
|
+
readonly nextEvent: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Python `_story_shape_assessment`: three cases, the third being an unknown level. */
|
|
57
|
+
function storyShapeAssessment(level: string | null): string {
|
|
58
|
+
if (isImplementableByDefault(level)) {
|
|
59
|
+
return "Pulled item is implementable by default. Plan may define the execution contract.";
|
|
60
|
+
}
|
|
61
|
+
if (level === "delivery_story") {
|
|
62
|
+
return (
|
|
63
|
+
"Pulled item is a Delivery Story. Ariad requires a granularity decision before " +
|
|
64
|
+
"implementation: expand into User/Technical Stories or approve this Delivery Story " +
|
|
65
|
+
"as one coherent implementable story."
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return "Pulled item level is unknown. Treat granularity as requiring Navigator decision.";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Python `_next_event_rule`. */
|
|
72
|
+
function nextEventRule(level: string | null): string {
|
|
73
|
+
return isImplementableByDefault(level)
|
|
74
|
+
? "Plan is the next event and requires Navigator approval before implementation."
|
|
75
|
+
: "Expand or explicit single-story approval is required before implementation.";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The development guide Prepare reports on, and the one a Plan points to (CR019). */
|
|
79
|
+
export const DEVELOPMENT_GUIDE_PATH = "docs/process/development-guide.md";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* A project's own rules for a Plan's Implementation Contract: one pointer to its
|
|
83
|
+
* development guide when the guide exists, otherwise nothing. The guide is never
|
|
84
|
+
* parsed, and a missing guide says nothing about the project, whose rules may live
|
|
85
|
+
* where its agents already read them (CR019).
|
|
86
|
+
*/
|
|
87
|
+
export function projectContractRules(projectPath: string | null): string[] {
|
|
88
|
+
if (projectPath === null || !existsSync(join(resolve(projectPath), DEVELOPMENT_GUIDE_PATH))) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
return [`Follow the project's development guide: ${DEVELOPMENT_GUIDE_PATH}.`];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Python `_context_summary`.
|
|
96
|
+
*
|
|
97
|
+
* Three fixed paths, in Python's order, each reported present or missing. With no
|
|
98
|
+
* project path the whole block collapses to one line — the shape a journey with no
|
|
99
|
+
* configured project renders.
|
|
100
|
+
*/
|
|
101
|
+
function contextSummary(projectPath: string | null): string[] {
|
|
102
|
+
if (projectPath === null) {
|
|
103
|
+
return ["No project path is configured; Prepare used runtime journey state only."];
|
|
104
|
+
}
|
|
105
|
+
const root = resolve(projectPath);
|
|
106
|
+
return ["README.md", "docs/project/roadmap/index.md", DEVELOPMENT_GUIDE_PATH].map(
|
|
107
|
+
(relativePath) =>
|
|
108
|
+
`${relativePath}: ${existsSync(join(root, relativePath)) ? "present" : "missing"}`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface PrepareOptions {
|
|
113
|
+
readonly journey: string;
|
|
114
|
+
readonly method: string;
|
|
115
|
+
readonly projectPath?: string | null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Python `prepare_lifecycle_item`. */
|
|
119
|
+
export function prepareLifecycleItem(
|
|
120
|
+
db: WritableDatabase,
|
|
121
|
+
options: PrepareOptions,
|
|
122
|
+
deps: CursorWriteDeps,
|
|
123
|
+
): BuilderPrepareReport {
|
|
124
|
+
const journey = normalizeRequired(options.journey, "journey");
|
|
125
|
+
const method = normalizeRequired(options.method, "method");
|
|
126
|
+
|
|
127
|
+
const existing = getDeliveryCursor(db, journey);
|
|
128
|
+
if (existing === null) throw new Error("delivery cursor is required before prepare");
|
|
129
|
+
if (!existing.activeItem) throw new Error("active item is required before prepare");
|
|
130
|
+
refuseIfAlreadyComplete("prepare", existing);
|
|
131
|
+
const event = existing.lastDeliveryEvent;
|
|
132
|
+
if (event !== null && event !== "pull" && event !== "prepare") {
|
|
133
|
+
const pending = existing.pendingConfirmation ? `, pending ${existing.pendingConfirmation}` : "";
|
|
134
|
+
throw new LifecycleRefusal(
|
|
135
|
+
"prepare",
|
|
136
|
+
"not_reached",
|
|
137
|
+
`Prepare follows Pull: ${existing.activeItem} is at ${event}${pending}.`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const cursor = setDeliveryCursor(
|
|
142
|
+
db,
|
|
143
|
+
{
|
|
144
|
+
journey,
|
|
145
|
+
method,
|
|
146
|
+
activeItem: existing.activeItem,
|
|
147
|
+
activeItemTitle: existing.activeItemTitle,
|
|
148
|
+
activeItemLevel: existing.activeItemLevel,
|
|
149
|
+
activeCheckpoint: null,
|
|
150
|
+
pendingConfirmation: null,
|
|
151
|
+
lastDeliveryEvent: "prepare",
|
|
152
|
+
cadenceProfile: existing.cadenceProfile,
|
|
153
|
+
cadenceLimits: existing.cadenceLimits,
|
|
154
|
+
navigatorFlowUnit: existing.navigatorFlowUnit,
|
|
155
|
+
childWorkItems: existing.childWorkItems,
|
|
156
|
+
aggregateCheckpointStatus: existing.aggregateCheckpointStatus,
|
|
157
|
+
},
|
|
158
|
+
deps,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const implementable = isImplementableByDefault(existing.activeItemLevel);
|
|
162
|
+
return {
|
|
163
|
+
journey,
|
|
164
|
+
method,
|
|
165
|
+
activeItem: existing.activeItem,
|
|
166
|
+
activeItemTitle: existing.activeItemTitle,
|
|
167
|
+
activeItemLevel: existing.activeItemLevel,
|
|
168
|
+
implementableByDefault: implementable,
|
|
169
|
+
granularityDecisionRequired: !implementable,
|
|
170
|
+
contextSummary: contextSummary(options.projectPath ?? null),
|
|
171
|
+
storyShapeAssessment: storyShapeAssessment(existing.activeItemLevel),
|
|
172
|
+
risks: [
|
|
173
|
+
"Scope may expand during Plan if the item mixes product and technical work.",
|
|
174
|
+
"Implementation remains blocked until the Plan checkpoint is approved.",
|
|
175
|
+
],
|
|
176
|
+
applicableRules: [
|
|
177
|
+
"Pull selects active work; Prepare reads terrain.",
|
|
178
|
+
nextEventRule(existing.activeItemLevel),
|
|
179
|
+
"No Plan, Implement, Validation, Review, Coherence, or Done work is executed here.",
|
|
180
|
+
],
|
|
181
|
+
cursor,
|
|
182
|
+
nextEvent: "plan",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Python `render_prepare_report`. */
|
|
187
|
+
export function renderPrepareReport(report: BuilderPrepareReport): string {
|
|
188
|
+
const body = `${[
|
|
189
|
+
"Delivery",
|
|
190
|
+
renderLifecycleRibbon("prepare", report.activeItemLevel),
|
|
191
|
+
"",
|
|
192
|
+
"╭────────────────────────────────────────────────────────╮",
|
|
193
|
+
"│ 🧭 PREPARE FIELD READING │",
|
|
194
|
+
"│ │",
|
|
195
|
+
cardText("active item"),
|
|
196
|
+
cardText(`🟦[${report.activeItem}]`),
|
|
197
|
+
cardText(`level: ${report.activeItemLevel ?? "unknown"}`),
|
|
198
|
+
cardText(
|
|
199
|
+
report.implementableByDefault
|
|
200
|
+
? "implementable: yes"
|
|
201
|
+
: "implementable: requires granularity decision",
|
|
202
|
+
),
|
|
203
|
+
"│ │",
|
|
204
|
+
cardText("terrain read"),
|
|
205
|
+
...cardContextItems(report.contextSummary),
|
|
206
|
+
"│ │",
|
|
207
|
+
cardText("story shape"),
|
|
208
|
+
...cardWrapped(report.storyShapeAssessment),
|
|
209
|
+
"│ │",
|
|
210
|
+
cardText("risks"),
|
|
211
|
+
...cardPrefixed(report.risks, "✕"),
|
|
212
|
+
"│ │",
|
|
213
|
+
cardText("applicable rules"),
|
|
214
|
+
...cardPrefixed(report.applicableRules, "✓"),
|
|
215
|
+
"│ │",
|
|
216
|
+
cardText("next event"),
|
|
217
|
+
cardText(report.granularityDecisionRequired ? "Expand or Plan" : pyTitle(report.nextEvent)),
|
|
218
|
+
"│ │",
|
|
219
|
+
cardText("boundary"),
|
|
220
|
+
cardText("Plan was not created."),
|
|
221
|
+
cardText("Implementation remains blocked."),
|
|
222
|
+
"╰────────────────────────────────────────────────────────╯",
|
|
223
|
+
].join("\n")}\n`;
|
|
224
|
+
return wrapAriadSurface("prepare_field_reading", body);
|
|
225
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// CR082 with CR009 — how a Builder surface names a place in the journey's project.
|
|
2
|
+
//
|
|
3
|
+
// Paths are resolved absolute inside the runtime, deliberately: `storyPaths`'
|
|
4
|
+
// confinement guard is only sound on absolutes. What a surface PRINTS is another
|
|
5
|
+
// matter. Surfaces are transported verbatim into replies, handoffs, and committed
|
|
6
|
+
// documents, so a path printed as resolved carries the owner's home directory, and a
|
|
7
|
+
// card cuts it into 54-column chunks where the root's length decides, so the same row
|
|
8
|
+
// reads differently on every machine. Every path a card prints therefore goes through
|
|
9
|
+
// `displayPath`, relative to the project, and every message that names a package is
|
|
10
|
+
// built with it where it is raised.
|
|
11
|
+
//
|
|
12
|
+
// One core answers "where is this path in the project", and each caller keeps its own
|
|
13
|
+
// reading of the two answers that are not a plain relative path: the project root
|
|
14
|
+
// itself, and a path outside the project.
|
|
15
|
+
//
|
|
16
|
+
// A relative path names a file only together with its project, so every report of a
|
|
17
|
+
// write also names the project, by its folder, and the journey it was made for, on one
|
|
18
|
+
// row (CR009): a wrong journey, or a journey whose project path names the wrong folder,
|
|
19
|
+
// shows as a wrong name on the card itself.
|
|
20
|
+
|
|
21
|
+
import { basename, isAbsolute, relative, resolve, sep } from "node:path";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The path's relation to the project, in the platform's separators: `""` for the
|
|
25
|
+
* project root itself, and `null` for a path outside the project.
|
|
26
|
+
*
|
|
27
|
+
* Both arguments are resolved first, so an absolute path and a relative one name the
|
|
28
|
+
* same place when they resolve to it. Outside means `..` itself or `..` followed by a
|
|
29
|
+
* separator: a project folder may be named `..cache`.
|
|
30
|
+
*/
|
|
31
|
+
export function projectRelative(path: string, projectRoot: string): string | null {
|
|
32
|
+
const relation = relative(resolve(projectRoot), resolve(path));
|
|
33
|
+
const outside = relation === ".." || relation.startsWith(`..${sep}`) || isAbsolute(relation);
|
|
34
|
+
return outside ? null : relation;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A path as a surface prints it: relative to the project, `.` for the project root,
|
|
39
|
+
* and the path exactly as given when it lies outside the project or there is none.
|
|
40
|
+
*
|
|
41
|
+
* Printing the ORIGINAL path in the fallback, not the resolved one, is Python's
|
|
42
|
+
* `_display_path`, kept: a path outside the project prints as its caller wrote it.
|
|
43
|
+
*/
|
|
44
|
+
export function displayPath(path: string, projectPath: string | null): string {
|
|
45
|
+
if (projectPath === null) return path;
|
|
46
|
+
const relation = projectRelative(path, projectPath);
|
|
47
|
+
if (relation === null) return path;
|
|
48
|
+
return relation === "" ? "." : relation;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The project's folder: the last segment of its path, or the path itself at the root. */
|
|
52
|
+
export function projectFolder(projectRoot: string): string {
|
|
53
|
+
const resolved = resolve(projectRoot);
|
|
54
|
+
return basename(resolved) || resolved;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The row a report of a write prints (CR009): where the files went, by the project's
|
|
59
|
+
* folder, and for which journey. Two checkouts of one repository share a folder name;
|
|
60
|
+
* the slug on the row tells their journeys apart, and `build load` prints the root.
|
|
61
|
+
*/
|
|
62
|
+
export function targetLine(projectRoot: string, journey: string): string {
|
|
63
|
+
return `project: ${projectFolder(projectRoot)} · journey: ${journey}`;
|
|
64
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// CV22.DS7.US8 plateau 3 — Pull: the Navigator's commitment to an item.
|
|
2
|
+
//
|
|
3
|
+
// Port of `pull_lifecycle_item` and `render_pull_report` from
|
|
4
|
+
// `src/memory/builder/lifecycle.py`.
|
|
5
|
+
//
|
|
6
|
+
// Pull looks like a simple write and is not. Three carry-forward rules decide what
|
|
7
|
+
// survives it, and each one is invisible until it is wrong:
|
|
8
|
+
//
|
|
9
|
+
// 1. **Child work items and aggregate status reset only when the ITEM CHANGED.**
|
|
10
|
+
// A first Pull (no prior active item) and a re-pull of the same code keep
|
|
11
|
+
// them; pulling a different code drops them. A port that always resets loses
|
|
12
|
+
// an expanded Delivery Story's children on a re-pull; one that never resets
|
|
13
|
+
// carries the previous story's children into the new one, which is how a
|
|
14
|
+
// Delivery Story ends up reporting siblings that belong to its predecessor.
|
|
15
|
+
// 2. **The generation always advances**, even for a re-pull of the same item.
|
|
16
|
+
// It is what invalidates a pending authority receipt bound to the old
|
|
17
|
+
// generation, so "pull the same thing again" is a real state change.
|
|
18
|
+
// 3. **Release intent survives only inside the same Delivery Story.** It is
|
|
19
|
+
// keyed to the DS ancestor, so pulling a child of the same DS keeps it and
|
|
20
|
+
// pulling into a different DS clears both fields explicitly.
|
|
21
|
+
//
|
|
22
|
+
// CR113: the card says what happened, at the level that happened, and where the item
|
|
23
|
+
// lives. It was headed DELIVERY STORY ACTIVATED for every level, under a marker
|
|
24
|
+
// naming a Delivery Story; it said Prepare had not run while the same command ran it;
|
|
25
|
+
// it drew a story straight under its CV; and it called any pulled code a roadmap
|
|
26
|
+
// candidate. It now names the level under a marker that names none, claims nothing
|
|
27
|
+
// about Prepare, draws the item's lineage, and says whether the roadmap names the item.
|
|
28
|
+
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
31
|
+
import { codePointLength, pyStrip, pyTitle } from "#util/pythonText.ts";
|
|
32
|
+
import { cardClipped, cardText, cardWrapped } from "./card.ts";
|
|
33
|
+
import {
|
|
34
|
+
ALLOWED_PULL_LEVELS,
|
|
35
|
+
carriedForward,
|
|
36
|
+
deliveryStoryCodeForItem,
|
|
37
|
+
normalizeRequired,
|
|
38
|
+
} from "./cursorTransitions.ts";
|
|
39
|
+
import {
|
|
40
|
+
type BuilderDeliveryCursor,
|
|
41
|
+
type CursorWriteDeps,
|
|
42
|
+
getDeliveryCursor,
|
|
43
|
+
setDeliveryCursor,
|
|
44
|
+
setTo,
|
|
45
|
+
} from "./deliveryCursor.ts";
|
|
46
|
+
import { renderLifecycleRibbon } from "./lifecycleRibbon.ts";
|
|
47
|
+
import {
|
|
48
|
+
inspectPullCandidates,
|
|
49
|
+
inspectRoadmapSnapshot,
|
|
50
|
+
type PullCandidate,
|
|
51
|
+
roadmapPaths,
|
|
52
|
+
} from "./pullCandidates.ts";
|
|
53
|
+
import { linkFreeTitle, matchHeading, parseCandidateStories } from "./roadmapGrammar.ts";
|
|
54
|
+
import { readRoadmapFile } from "./roadmapScan.ts";
|
|
55
|
+
import { resolveRoadmapScope, type ScopeCursor } from "./roadmapScope.ts";
|
|
56
|
+
import { claimedBy, NO_AUTHORED_PACKAGE, NO_PROJECT_PATH, scopeFocus } from "./scopePhrases.ts";
|
|
57
|
+
import { roadmapHeadingDirectories } from "./storyPaths.ts";
|
|
58
|
+
import { wrapAriadSurface } from "./surfaceProtocol.ts";
|
|
59
|
+
|
|
60
|
+
/** Python `BuilderLifecycleItem`. */
|
|
61
|
+
export interface BuilderLifecycleItem {
|
|
62
|
+
readonly code: string;
|
|
63
|
+
readonly title: string;
|
|
64
|
+
readonly level: string;
|
|
65
|
+
readonly whyNow: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Python `BuilderPullReport`. */
|
|
69
|
+
export interface BuilderPullReport {
|
|
70
|
+
readonly journey: string;
|
|
71
|
+
readonly method: string;
|
|
72
|
+
readonly item: BuilderLifecycleItem;
|
|
73
|
+
readonly cursor: BuilderDeliveryCursor;
|
|
74
|
+
readonly nextEvent: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Python `_normalize_item`.
|
|
79
|
+
*
|
|
80
|
+
* Field order is behavior: an empty code is reported before an empty title, and
|
|
81
|
+
* the level VOCABULARY check runs after all four fields are non-empty, so a blank
|
|
82
|
+
* level says "must not be empty" rather than listing the allowed values.
|
|
83
|
+
*/
|
|
84
|
+
function normalizeItem(item: BuilderLifecycleItem): BuilderLifecycleItem {
|
|
85
|
+
const code = normalizeRequired(item.code, "item code");
|
|
86
|
+
// Link-free from here on, as every roadmap reader delivers a title (CR018).
|
|
87
|
+
const title = linkFreeTitle(normalizeRequired(item.title, "item title"));
|
|
88
|
+
const level = normalizeRequired(item.level, "item level");
|
|
89
|
+
const whyNow = normalizeRequired(item.whyNow, "why now");
|
|
90
|
+
if (!(ALLOWED_PULL_LEVELS as readonly string[]).includes(level)) {
|
|
91
|
+
throw new Error(`item level must be one of ${ALLOWED_PULL_LEVELS.join(", ")}`);
|
|
92
|
+
}
|
|
93
|
+
return { code, title, level, whyNow };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface PullOptions {
|
|
97
|
+
readonly journey: string;
|
|
98
|
+
readonly method: string;
|
|
99
|
+
readonly item: BuilderLifecycleItem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Python `pull_lifecycle_item`. */
|
|
103
|
+
export function pullLifecycleItem(
|
|
104
|
+
db: WritableDatabase,
|
|
105
|
+
options: PullOptions,
|
|
106
|
+
deps: CursorWriteDeps,
|
|
107
|
+
): BuilderPullReport {
|
|
108
|
+
const journey = normalizeRequired(options.journey, "journey");
|
|
109
|
+
const method = normalizeRequired(options.method, "method");
|
|
110
|
+
const item = normalizeItem(options.item);
|
|
111
|
+
|
|
112
|
+
const existing = getDeliveryCursor(db, journey);
|
|
113
|
+
if (existing === null) {
|
|
114
|
+
throw new Error("delivery cursor is required before pull");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const itemChanged = existing.activeItem !== null && existing.activeItem !== item.code;
|
|
118
|
+
// A flow unit belongs to the Delivery Story it was chosen for (CR117): it survives Pull
|
|
119
|
+
// only when that Delivery Story is pulled again as the item the cursor already holds.
|
|
120
|
+
// Any other item starts at the default. Not `itemChanged`, which is false for a cursor
|
|
121
|
+
// with no item and would let a stale unit through a Delivery Story's first Pull.
|
|
122
|
+
const keepsFlowUnit = existing.activeItem === item.code && item.level === "delivery_story";
|
|
123
|
+
const preserveReleaseIntent =
|
|
124
|
+
existing.releaseIntentDeliveryStory === deliveryStoryCodeForItem(item.code);
|
|
125
|
+
|
|
126
|
+
const cursor = setDeliveryCursor(
|
|
127
|
+
db,
|
|
128
|
+
{
|
|
129
|
+
journey,
|
|
130
|
+
method,
|
|
131
|
+
activeItem: item.code,
|
|
132
|
+
activeItemTitle: item.title,
|
|
133
|
+
activeItemLevel: item.level,
|
|
134
|
+
activeCheckpoint: null,
|
|
135
|
+
pendingConfirmation: null,
|
|
136
|
+
lastDeliveryEvent: "pull",
|
|
137
|
+
...carriedForward(existing),
|
|
138
|
+
navigatorFlowUnit: keepsFlowUnit ? existing.navigatorFlowUnit : null,
|
|
139
|
+
childWorkItems: itemChanged ? [] : existing.childWorkItems,
|
|
140
|
+
aggregateCheckpointStatus: itemChanged ? [] : existing.aggregateCheckpointStatus,
|
|
141
|
+
cursorGeneration: existing.cursorGeneration + 1,
|
|
142
|
+
// Explicit, not KEEP: Pull is one of the few writes that may CLEAR release
|
|
143
|
+
// intent, and the sentinel would preserve exactly what must be dropped.
|
|
144
|
+
releaseIntentDeliveryStory: setTo(
|
|
145
|
+
preserveReleaseIntent ? existing.releaseIntentDeliveryStory : null,
|
|
146
|
+
),
|
|
147
|
+
releaseIntent: setTo(preserveReleaseIntent ? existing.releaseIntent : null),
|
|
148
|
+
},
|
|
149
|
+
deps,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return { journey, method, item, cursor, nextEvent: "prepare" };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The title of the CV a pulled item sits under, as the roadmap names it (CR018): the
|
|
157
|
+
* focus Project Position shows for the same cursor, so the two surfaces cannot
|
|
158
|
+
* disagree. Python borrowed the head of the item's own title instead. Pull and Ready
|
|
159
|
+
* both render it, and neither computes it: the caller passes this in.
|
|
160
|
+
*/
|
|
161
|
+
export function placementCvTitle(projectRoot: string | null, cursor: ScopeCursor): string {
|
|
162
|
+
const items = inspectRoadmapSnapshot(projectRoot, { journey: "", method: "ariad" }).items;
|
|
163
|
+
return scopeFocus(items, resolveRoadmapScope(projectRoot, cursor))?.title ?? "";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** A Delivery Story a pulled story sits under, titled by the roadmap. */
|
|
167
|
+
export interface PlacementParent {
|
|
168
|
+
readonly code: string;
|
|
169
|
+
readonly title: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Where a pulled item sits: its CV's title, and its Delivery Story when it is a story. */
|
|
173
|
+
export interface Lineage {
|
|
174
|
+
readonly cvTitle: string;
|
|
175
|
+
readonly deliveryStory: PlacementParent | null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** The Pull card's placement, and whether the roadmap names the pulled item (CR113). */
|
|
179
|
+
export interface PullPlacement extends Lineage {
|
|
180
|
+
readonly listed: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The title an authored package's heading gives a code, or why there is none. */
|
|
184
|
+
function packageTitle(
|
|
185
|
+
projectRoot: string,
|
|
186
|
+
claims: ReadonlyMap<string, readonly string[]>,
|
|
187
|
+
code: string,
|
|
188
|
+
): string | null {
|
|
189
|
+
const directories = claims.get(code) ?? [];
|
|
190
|
+
if (directories.length > 1) return claimedBy(directories.length);
|
|
191
|
+
const directory = directories[0];
|
|
192
|
+
if (directory === undefined) return null;
|
|
193
|
+
const { roadmapRoot } = roadmapPaths(projectRoot);
|
|
194
|
+
const content = readRoadmapFile(join(roadmapRoot, directory, "index.md"));
|
|
195
|
+
const heading = content === null ? null : matchHeading(content);
|
|
196
|
+
return heading === null ? null : linkFreeTitle(pyStrip(heading.title));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The item's lineage and whether the roadmap names it, from the roadmap as it stands.
|
|
201
|
+
*
|
|
202
|
+
* Three readers, each the authority for its fact. The CV's title is the focus Project
|
|
203
|
+
* Position shows (`placementCvTitle`). A Delivery Story's title is its package's
|
|
204
|
+
* heading, found by the status-blind heading rule Expand and `resolveStoryDirectory`
|
|
205
|
+
* share, else the roadmap index's listing of it. The item is named when a package
|
|
206
|
+
* heading claims it, when its Delivery Story's candidate table lists it, or when it is
|
|
207
|
+
* a pull candidate. `inspectPullCandidates` alone would not do: it keeps only the
|
|
208
|
+
* statuses that can be pulled, so a story marked Done, or a row with no package yet,
|
|
209
|
+
* would read as not in the roadmap.
|
|
210
|
+
*/
|
|
211
|
+
export function pullPlacement(projectRoot: string | null, cursor: ScopeCursor): PullPlacement {
|
|
212
|
+
const cvTitle = placementCvTitle(projectRoot, cursor);
|
|
213
|
+
const code = cursor.activeItem ?? "";
|
|
214
|
+
const cvCode = code.split(".")[0] ?? code;
|
|
215
|
+
const dsCode = deliveryStoryCodeForItem(code);
|
|
216
|
+
// A story under a Delivery Story that is not itself the CV row's code.
|
|
217
|
+
const parentCode = dsCode !== null && dsCode !== code && dsCode !== cvCode ? dsCode : null;
|
|
218
|
+
if (projectRoot === null) {
|
|
219
|
+
return {
|
|
220
|
+
cvTitle,
|
|
221
|
+
deliveryStory: parentCode === null ? null : { code: parentCode, title: NO_PROJECT_PATH },
|
|
222
|
+
listed: false,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const claims = roadmapHeadingDirectories(projectRoot);
|
|
226
|
+
const candidates = inspectPullCandidates(projectRoot, {
|
|
227
|
+
journey: "",
|
|
228
|
+
method: "ariad",
|
|
229
|
+
}).candidates;
|
|
230
|
+
const deliveryStory =
|
|
231
|
+
parentCode === null
|
|
232
|
+
? null
|
|
233
|
+
: {
|
|
234
|
+
code: parentCode,
|
|
235
|
+
title:
|
|
236
|
+
packageTitle(projectRoot, claims, parentCode) ??
|
|
237
|
+
candidates.find((candidate) => candidate.code === parentCode)?.title ??
|
|
238
|
+
NO_AUTHORED_PACKAGE,
|
|
239
|
+
};
|
|
240
|
+
return {
|
|
241
|
+
cvTitle,
|
|
242
|
+
deliveryStory,
|
|
243
|
+
listed: namedByRoadmap(projectRoot, claims, candidates, code, dsCode),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Whether the roadmap names `code`, by any of three routes: a package heading claims
|
|
249
|
+
* it, its Delivery Story's candidate table lists it, or it is a pull candidate. The
|
|
250
|
+
* candidates are the ones `pullPlacement` already read, so one Pull scans them once
|
|
251
|
+
* (the handoff review, finding 1).
|
|
252
|
+
*/
|
|
253
|
+
function namedByRoadmap(
|
|
254
|
+
projectRoot: string,
|
|
255
|
+
claims: ReadonlyMap<string, readonly string[]>,
|
|
256
|
+
candidates: readonly PullCandidate[],
|
|
257
|
+
code: string,
|
|
258
|
+
dsCode: string | null,
|
|
259
|
+
): boolean {
|
|
260
|
+
if ((claims.get(code) ?? []).length > 0) return true;
|
|
261
|
+
const parentDirectories = dsCode === null || dsCode === code ? [] : (claims.get(dsCode) ?? []);
|
|
262
|
+
if (parentDirectories.length === 1) {
|
|
263
|
+
const { roadmapRoot } = roadmapPaths(projectRoot);
|
|
264
|
+
const content = readRoadmapFile(join(roadmapRoot, parentDirectories[0] as string, "index.md"));
|
|
265
|
+
if (content !== null && parseCandidateStories(content).some((child) => child.code === code)) {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return candidates.some((candidate) => candidate.code === code);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** The last segment of a code: the label a tree row carries. */
|
|
273
|
+
function leafOf(code: string): string {
|
|
274
|
+
const parts = code.split(".");
|
|
275
|
+
return parts.length > 1 ? (parts.at(-1) ?? "") : code;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* The item's lineage as card rows (CR113): the CV, then its Delivery Story when the
|
|
280
|
+
* item is a story under one, then the item. The colors are the three the Ready card
|
|
281
|
+
* draws for the three levels. Pull and Ready both draw their tree here, so they
|
|
282
|
+
* cannot disagree; Ready's is a Delivery Story, one level shorter.
|
|
283
|
+
*/
|
|
284
|
+
export function placementRows(
|
|
285
|
+
item: { readonly code: string; readonly title: string; readonly level: string },
|
|
286
|
+
lineage: Lineage,
|
|
287
|
+
): string[] {
|
|
288
|
+
const cvCode = item.code.split(".")[0] ?? item.code;
|
|
289
|
+
const glyph = item.level === "delivery_story" ? "🟦" : "🟩";
|
|
290
|
+
// Whole where the title is read; the tree rows restate it on one line (CR018).
|
|
291
|
+
const rows = [...cardWrapped(`🟪[${cvCode}] ${lineage.cvTitle}`)];
|
|
292
|
+
if (lineage.deliveryStory === null) {
|
|
293
|
+
rows.push(cardClipped(` └─ ${glyph}[${leafOf(item.code)}] ${item.title}`));
|
|
294
|
+
return rows;
|
|
295
|
+
}
|
|
296
|
+
const parent = lineage.deliveryStory;
|
|
297
|
+
rows.push(cardClipped(` └─ 🟦[${leafOf(parent.code)}] ${parent.title}`));
|
|
298
|
+
rows.push(cardClipped(` └─ ${glyph}[${leafOf(item.code)}] ${item.title}`));
|
|
299
|
+
return rows;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** What the card calls each level it can pull. */
|
|
303
|
+
const ACTIVATED: Readonly<Record<string, string>> = {
|
|
304
|
+
delivery_story: "DELIVERY STORY",
|
|
305
|
+
user_story: "USER STORY",
|
|
306
|
+
technical_story: "TECHNICAL STORY",
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* The title row, padded to terminal columns like every Builder title literal: 🟪 is
|
|
311
|
+
* one code point and two columns, so the row is one code point short of the frame
|
|
312
|
+
* and aligned on screen (see `pullCandidatesRender.ts`). The Delivery Story row keeps
|
|
313
|
+
* the bytes it always had.
|
|
314
|
+
*/
|
|
315
|
+
function activatedTitleRow(level: string): string {
|
|
316
|
+
const inner = ` 🟪■ ${ACTIVATED[level] ?? "ITEM"} ACTIVATED`;
|
|
317
|
+
const columns = codePointLength(inner) + 1;
|
|
318
|
+
return `│${inner}${" ".repeat(Math.max(0, 56 - columns))}│`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Python `render_pull_report`, with the level, the lineage, and a true source (CR113). */
|
|
322
|
+
export function renderPullReport(report: BuilderPullReport, placement: PullPlacement): string {
|
|
323
|
+
const title = report.item.title;
|
|
324
|
+
const body = `${[
|
|
325
|
+
"Delivery",
|
|
326
|
+
renderLifecycleRibbon("pull", report.item.level),
|
|
327
|
+
"",
|
|
328
|
+
"╭────────────────────────────────────────────────────────╮",
|
|
329
|
+
activatedTitleRow(report.item.level),
|
|
330
|
+
"│ │",
|
|
331
|
+
// Whole where the title is read; the tree row below restates it on one line (CR018).
|
|
332
|
+
...cardWrapped(title),
|
|
333
|
+
"│ │",
|
|
334
|
+
cardText("source"),
|
|
335
|
+
cardText(placement.listed ? "roadmap candidate" : "not in the roadmap: pulled by its code"),
|
|
336
|
+
"│ │",
|
|
337
|
+
cardText("roadmap placement"),
|
|
338
|
+
...placementRows(report.item, placement),
|
|
339
|
+
"│ │",
|
|
340
|
+
cardText("intent"),
|
|
341
|
+
...cardWrapped(report.item.whyNow),
|
|
342
|
+
"│ │",
|
|
343
|
+
cardText("commitment"),
|
|
344
|
+
cardText("pulled into active Delivery Work"),
|
|
345
|
+
cardText(`active item: ${report.cursor.activeItem ?? "none"}`),
|
|
346
|
+
"│ │",
|
|
347
|
+
cardText("next event"),
|
|
348
|
+
cardText(pyTitle(report.nextEvent)),
|
|
349
|
+
"│ │",
|
|
350
|
+
cardText("boundary"),
|
|
351
|
+
// Prepare's record is its own card, which the command prints next (CR113, D1).
|
|
352
|
+
cardText("Plan and later lifecycle work were not executed."),
|
|
353
|
+
"╰────────────────────────────────────────────────────────╯",
|
|
354
|
+
].join("\n")}\n`;
|
|
355
|
+
return wrapAriadSurface("item_activated", body);
|
|
356
|
+
}
|