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,572 @@
|
|
|
1
|
+
// CV22.DS7.US7 plateau 5 — the `explore` front-door route.
|
|
2
|
+
//
|
|
3
|
+
// Dispatch only: every behavior it reaches was ported and graded in plateaus
|
|
4
|
+
// 1-4. What this module owns is the argv shape, the exit codes, the refusals,
|
|
5
|
+
// and the one call into the projection seam.
|
|
6
|
+
//
|
|
7
|
+
// `explore` is the first family with a NESTED subparser, so the allowlist in
|
|
8
|
+
// `routing.ts` is two levels deep: `explore <sub>` and `explore story
|
|
9
|
+
// <action>`. A single-level allowlist would claim `explore story <anything>`
|
|
10
|
+
// and answer an argv shape this route has never implemented — the
|
|
11
|
+
// `conversations append` defect (RS009/CR055), which exited 0 and discarded the
|
|
12
|
+
// caller's data.
|
|
13
|
+
//
|
|
14
|
+
// `story promote` arrived here at US8 plateau 7, having waited on Python by name
|
|
15
|
+
// since US7: `cmd_story_promote` ends by calling Builder `load`, which US8 owns.
|
|
16
|
+
// Its tail is therefore a real session start — providers, close tail, clone-role
|
|
17
|
+
// guard — wired by `buildLoadRuntime.ts`, which plateau 8's `build` route reuses
|
|
18
|
+
// so the two cannot disagree about which transport answered.
|
|
19
|
+
|
|
20
|
+
import { runBuildLoad } from "#builder/load.ts";
|
|
21
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
22
|
+
import {
|
|
23
|
+
type HandoffConversationSource,
|
|
24
|
+
type HandoffSourceMessage,
|
|
25
|
+
writeBuilderHandoffArtifacts,
|
|
26
|
+
} from "#explorer/handoff.ts";
|
|
27
|
+
import {
|
|
28
|
+
renderAttractorsEmerging,
|
|
29
|
+
renderBuilderHandoffProposed,
|
|
30
|
+
renderExperimentProposal,
|
|
31
|
+
renderExploratoryStoryOpened,
|
|
32
|
+
renderExploratoryStoryResumed,
|
|
33
|
+
renderExplorerStoryArchived,
|
|
34
|
+
renderExplorerStoryList,
|
|
35
|
+
renderMissingExploratoryStory,
|
|
36
|
+
renderNarrativeFieldSnapshot,
|
|
37
|
+
renderNoBuilderHandoff,
|
|
38
|
+
renderStoryThickened,
|
|
39
|
+
} from "#explorer/render.ts";
|
|
40
|
+
import {
|
|
41
|
+
archiveExplorerStory,
|
|
42
|
+
clearExplorerStory,
|
|
43
|
+
type ExplorerStory,
|
|
44
|
+
ExplorerStoryError,
|
|
45
|
+
getExplorerStory,
|
|
46
|
+
listExplorerStories,
|
|
47
|
+
markExplorerStoryPromoted,
|
|
48
|
+
renderExplorerStoryContext,
|
|
49
|
+
type Settable,
|
|
50
|
+
type StoryClock,
|
|
51
|
+
type StoryMutation,
|
|
52
|
+
setExplorerAttractors,
|
|
53
|
+
setExplorerBuilderHandoff,
|
|
54
|
+
setExplorerExperimentProposal,
|
|
55
|
+
setExplorerSourceConversations,
|
|
56
|
+
UNSET,
|
|
57
|
+
updateExplorerStory,
|
|
58
|
+
} from "#explorer/story.ts";
|
|
59
|
+
import { renderExplorerModeTransition } from "#explorer/transition.ts";
|
|
60
|
+
import { getIdentityContent } from "#identity/identityRead.ts";
|
|
61
|
+
import { getProjectPath } from "#journey/journeyStatus.ts";
|
|
62
|
+
import { loadMirrorContext } from "#mirror/context.ts";
|
|
63
|
+
import { persistStickyDefaults } from "#mirror/orchestration.ts";
|
|
64
|
+
import { resolveRuntimeSessionId } from "#mirror/runtimeSession.ts";
|
|
65
|
+
import { activateOperatingMode, deactivateOperatingMode } from "#mode/operatingMode.ts";
|
|
66
|
+
import { newId, nowIso } from "#util/pyGenerators.ts";
|
|
67
|
+
import { optionValue, stripOptionWithValue } from "./args.ts";
|
|
68
|
+
import type { BuildLoadRuntime } from "./buildLoadRuntime.ts";
|
|
69
|
+
|
|
70
|
+
/** Python's argparse subcommands for `explore`, by name. */
|
|
71
|
+
export const EXPLORE_SUBCOMMANDS = ["load", "deactivate", "story"] as const;
|
|
72
|
+
|
|
73
|
+
/** Python's argparse actions under `explore story`, by name. */
|
|
74
|
+
export const EXPLORE_STORY_ACTIONS = [
|
|
75
|
+
"show",
|
|
76
|
+
"list",
|
|
77
|
+
"archive",
|
|
78
|
+
"update",
|
|
79
|
+
"clear",
|
|
80
|
+
"open",
|
|
81
|
+
"thicken",
|
|
82
|
+
"snapshot",
|
|
83
|
+
"attractors",
|
|
84
|
+
"experiment",
|
|
85
|
+
"handoff",
|
|
86
|
+
"promote",
|
|
87
|
+
] as const;
|
|
88
|
+
|
|
89
|
+
const OPTIONS_WITH_VALUES = [
|
|
90
|
+
"--mirror-home",
|
|
91
|
+
"--db-path",
|
|
92
|
+
"--session-id",
|
|
93
|
+
"--story",
|
|
94
|
+
"--summary",
|
|
95
|
+
"--last-card",
|
|
96
|
+
"--changed",
|
|
97
|
+
"--attractor",
|
|
98
|
+
"--description",
|
|
99
|
+
"--status",
|
|
100
|
+
"--title",
|
|
101
|
+
"--editorial-synthesis",
|
|
102
|
+
"--source-conversation",
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
const FLAGS = ["--include-full-conversation"];
|
|
106
|
+
|
|
107
|
+
const EXPLORER_GUIDANCE = `=== Explorer Mode guidance ===
|
|
108
|
+
Explorer Mode is active and ready for durable exploration, story thickening, attractors, experiments, and Builder handoff.
|
|
109
|
+
|
|
110
|
+
Explorer preserves uncertainty. Builder executes commitment.
|
|
111
|
+
|
|
112
|
+
While Explorer Mode is active:
|
|
113
|
+
- Treat new substantive material as part of the current Exploratory Story unless the user asks for a clear operational action.
|
|
114
|
+
- Preserve tensions, hypotheses, corrections, and emerging story shape.
|
|
115
|
+
- Update the in-session story when new material changes the accumulated story.
|
|
116
|
+
- Render Story Thickened when new material changes the accumulated story.
|
|
117
|
+
- Do not promote to Builder or Delivery without explicit user confirmation.
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const EXPLORER_DEACTIVATED_SURFACE = `Mirror
|
|
121
|
+
╭────────────────────────────────────────────────────────╮
|
|
122
|
+
│ △ EXPLORER MODE DEACTIVATED │
|
|
123
|
+
│ │
|
|
124
|
+
│ current lens │
|
|
125
|
+
│ ◌ Mirror Mode │
|
|
126
|
+
│ │
|
|
127
|
+
│ context │
|
|
128
|
+
│ Journey context remains available when it is sticky. │
|
|
129
|
+
│ │
|
|
130
|
+
│ boundary │
|
|
131
|
+
│ Explorer lens ended. Uncertainty was not promoted. │
|
|
132
|
+
╰────────────────────────────────────────────────────────╯
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
function positionals(args: readonly string[]): string[] {
|
|
136
|
+
const withoutFlags = args.filter((arg) => !FLAGS.includes(arg));
|
|
137
|
+
return OPTIONS_WITH_VALUES.reduce<string[]>(
|
|
138
|
+
(remaining, option) => stripOptionWithValue(remaining, option),
|
|
139
|
+
withoutFlags,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Python's `_required_surface` marker protocol, byte for byte. */
|
|
144
|
+
function requiredSurface(surfaceId: string, rendered: string): string {
|
|
145
|
+
return `[[MIRROR_REQUIRED_SURFACE_BEGIN:${surfaceId}]]\n${rendered}\n[[MIRROR_REQUIRED_SURFACE_END:${surfaceId}]]`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function write(text: string): number {
|
|
149
|
+
process.stdout.write(`${text}\n`);
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function fail(message: string): number {
|
|
154
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** argparse's own exit for an unknown subcommand or a missing required argument. */
|
|
159
|
+
function usageError(message: string): number {
|
|
160
|
+
process.stderr.write(`${message}\n`);
|
|
161
|
+
return 2;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface ExploreRouteDeps {
|
|
165
|
+
clock: StoryClock;
|
|
166
|
+
readMessages: (db: WritableDatabase, conversationId: string) => HandoffSourceMessage[];
|
|
167
|
+
/**
|
|
168
|
+
* `story promote`'s Builder tail.
|
|
169
|
+
*
|
|
170
|
+
* Injected rather than built here so this route stays free of the provider
|
|
171
|
+
* seam, and so the promote tests can run a session start without one.
|
|
172
|
+
*/
|
|
173
|
+
buildLoadRuntime?: () => Promise<BuildLoadRuntime>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function defaultExploreRouteDeps(): ExploreRouteDeps {
|
|
177
|
+
return {
|
|
178
|
+
clock: { now: nowIso, uuid: newId },
|
|
179
|
+
readMessages: (db, conversationId) =>
|
|
180
|
+
db
|
|
181
|
+
.prepare("SELECT role, content FROM messages WHERE conversation_id = ? ORDER BY rowid")
|
|
182
|
+
.all(conversationId) as unknown as HandoffSourceMessage[],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The story write, unwrapped.
|
|
188
|
+
*
|
|
189
|
+
* Until CV22.DS10.TS1 this asked Python to publish `.mirror/projections` when a
|
|
190
|
+
* mutation changed the projected fields. The subsystem retired with the Python
|
|
191
|
+
* core, so a mutation is now just a mutation.
|
|
192
|
+
*/
|
|
193
|
+
function afterMutation(mutation: StoryMutation): ExplorerStory {
|
|
194
|
+
return mutation.story;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export async function runExploreRoute(
|
|
198
|
+
db: WritableDatabase,
|
|
199
|
+
argv: readonly string[],
|
|
200
|
+
deps: ExploreRouteDeps,
|
|
201
|
+
): Promise<number> {
|
|
202
|
+
const rawArgs = argv.slice(1);
|
|
203
|
+
const args = positionals(rawArgs);
|
|
204
|
+
const sub = args[0];
|
|
205
|
+
const option = (name: string) => optionValue(rawArgs, name);
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
switch (sub) {
|
|
209
|
+
case "load": {
|
|
210
|
+
const slug = args[1];
|
|
211
|
+
if (!slug) return usageError("explore load requires a journey slug");
|
|
212
|
+
// Awaited inside the try: returning the promise would carry a
|
|
213
|
+
// rejection past the catch that turns ExplorerStoryError into exit 1.
|
|
214
|
+
return await runLoad(db, slug, option("--session-id"));
|
|
215
|
+
}
|
|
216
|
+
case "deactivate": {
|
|
217
|
+
deactivateOperatingMode(db, resolveRuntimeSessionId(db, option("--session-id")), nowIso());
|
|
218
|
+
return write(EXPLORER_DEACTIVATED_SURFACE);
|
|
219
|
+
}
|
|
220
|
+
// Awaited for the same reason `load` is: `story promote` runs a Builder
|
|
221
|
+
// session start, and an unawaited rejection would sail past the catch
|
|
222
|
+
// below that turns ExplorerStoryError into exit 1.
|
|
223
|
+
case "story":
|
|
224
|
+
return await runStory(db, args, option, rawArgs, deps);
|
|
225
|
+
default:
|
|
226
|
+
return usageError(`explore: unknown subcommand ${sub ?? ""}`);
|
|
227
|
+
}
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (error instanceof ExplorerStoryError) return fail(error.message);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// No `deps`: `load` activates the mode and renders, but never mutates the
|
|
235
|
+
// story, so it cannot change the projection and never reaches the seam.
|
|
236
|
+
async function runLoad(
|
|
237
|
+
db: WritableDatabase,
|
|
238
|
+
slug: string,
|
|
239
|
+
sessionId: string | null,
|
|
240
|
+
): Promise<number> {
|
|
241
|
+
const journeyContent = getIdentityContent(db, "journey", slug);
|
|
242
|
+
if (!journeyContent) {
|
|
243
|
+
process.stderr.write(`Error: journey '${slug}' not found.\n`);
|
|
244
|
+
return 1;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const resolved = resolveRuntimeSessionId(db, sessionId);
|
|
248
|
+
const now = nowIso();
|
|
249
|
+
activateOperatingMode(db, { mode: "Explorer Mode", journey: slug, sessionId: resolved }, now);
|
|
250
|
+
// Python's `cmd_load` reaches into `memory.skills.mirror`'s PRIVATE sticky
|
|
251
|
+
// writer; the port calls the public one and does not reproduce the violation.
|
|
252
|
+
persistStickyDefaults(db, null, slug, now);
|
|
253
|
+
|
|
254
|
+
// The activation banner goes to stderr, as Python's does: stdout carries the
|
|
255
|
+
// surfaces a runtime must render verbatim.
|
|
256
|
+
process.stderr.write(`\u001b[38;5;183m△ Explorer Mode active — journey: ${slug}\u001b[0m\n`);
|
|
257
|
+
write(renderExplorerModeTransition(slug));
|
|
258
|
+
write(await loadMirrorContext(db, { journey: slug }));
|
|
259
|
+
|
|
260
|
+
const story = getExplorerStory(db, slug);
|
|
261
|
+
if (story) {
|
|
262
|
+
write(
|
|
263
|
+
`\n${requiredSurface("exploratory_story_resumed", renderExploratoryStoryResumed(story))}`,
|
|
264
|
+
);
|
|
265
|
+
write(`\n${renderExplorerStoryContext(story)}`);
|
|
266
|
+
}
|
|
267
|
+
write(`\n${EXPLORER_GUIDANCE}`);
|
|
268
|
+
return 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function runStory(
|
|
272
|
+
db: WritableDatabase,
|
|
273
|
+
args: readonly string[],
|
|
274
|
+
option: (name: string) => string | null,
|
|
275
|
+
rawArgs: readonly string[],
|
|
276
|
+
deps: ExploreRouteDeps,
|
|
277
|
+
): Promise<number> {
|
|
278
|
+
const action = args[1];
|
|
279
|
+
const slug = args[2];
|
|
280
|
+
if (!action) return usageError("explore story requires an action");
|
|
281
|
+
if (!slug) return usageError(`explore story ${action} requires a journey slug`);
|
|
282
|
+
|
|
283
|
+
// A settable scalar is present-or-absent, never nullish: `--story` given with
|
|
284
|
+
// an empty value CLEARS, while omitting it keeps. `optionValue` returns null
|
|
285
|
+
// for both, so presence is read from argv.
|
|
286
|
+
const settable = (name: string): Settable =>
|
|
287
|
+
rawArgs.includes(name) ? (option(name) ?? "") : UNSET;
|
|
288
|
+
|
|
289
|
+
switch (action) {
|
|
290
|
+
case "show": {
|
|
291
|
+
const story = getExplorerStory(db, slug);
|
|
292
|
+
if (!story) return write(`No Exploratory Story for journey: ${slug}`);
|
|
293
|
+
return write(renderExplorerStoryContext(story));
|
|
294
|
+
}
|
|
295
|
+
case "list":
|
|
296
|
+
return write(
|
|
297
|
+
requiredSurface(
|
|
298
|
+
"exploratory_stories",
|
|
299
|
+
renderExplorerStoryList(slug, listExplorerStories(db, slug)),
|
|
300
|
+
),
|
|
301
|
+
);
|
|
302
|
+
case "archive": {
|
|
303
|
+
const { story } = archiveExplorerStory(db, slug, deps.clock);
|
|
304
|
+
return write(
|
|
305
|
+
requiredSurface("exploratory_story_archived", renderExplorerStoryArchived(story, slug)),
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
case "clear":
|
|
309
|
+
clearExplorerStory(db, slug, deps.clock);
|
|
310
|
+
return write(`Exploratory Story cleared for journey: ${slug}`);
|
|
311
|
+
case "update": {
|
|
312
|
+
const story = afterMutation(updateStory(db, slug, settable, deps));
|
|
313
|
+
return write(renderExplorerStoryContext(story));
|
|
314
|
+
}
|
|
315
|
+
case "open": {
|
|
316
|
+
const story = afterMutation(updateStory(db, slug, settable, deps));
|
|
317
|
+
return write(
|
|
318
|
+
requiredSurface("exploratory_story_opened", renderExploratoryStoryOpened(story)),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
case "thicken": {
|
|
322
|
+
const story = afterMutation(updateStory(db, slug, settable, deps));
|
|
323
|
+
return write(
|
|
324
|
+
requiredSurface("story_thickened", renderStoryThickened(story, option("--changed"))),
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
case "snapshot": {
|
|
328
|
+
const story = getExplorerStory(db, slug);
|
|
329
|
+
if (!story) {
|
|
330
|
+
return write(requiredSurface("no_exploratory_story", renderMissingExploratoryStory(slug)));
|
|
331
|
+
}
|
|
332
|
+
return write(
|
|
333
|
+
requiredSurface("narrative_field_snapshot", renderNarrativeFieldSnapshot(story)),
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
case "attractors": {
|
|
337
|
+
const label = option("--attractor");
|
|
338
|
+
if (label === null) {
|
|
339
|
+
return usageError(
|
|
340
|
+
"explore story attractors: the following arguments are required: --attractor",
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
const story = afterMutation(
|
|
344
|
+
setExplorerAttractors(db, slug, deps.clock, [
|
|
345
|
+
{
|
|
346
|
+
label,
|
|
347
|
+
description: option("--description"),
|
|
348
|
+
status: option("--status") ?? "proposed",
|
|
349
|
+
},
|
|
350
|
+
]),
|
|
351
|
+
);
|
|
352
|
+
return write(requiredSurface("attractors_emerging", renderAttractorsEmerging(story)));
|
|
353
|
+
}
|
|
354
|
+
case "experiment": {
|
|
355
|
+
const title = option("--title");
|
|
356
|
+
if (title === null) {
|
|
357
|
+
return usageError(
|
|
358
|
+
"explore story experiment: the following arguments are required: --title",
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
const story = afterMutation(
|
|
362
|
+
setExplorerExperimentProposal(db, slug, deps.clock, {
|
|
363
|
+
title,
|
|
364
|
+
description: option("--description"),
|
|
365
|
+
status: option("--status") ?? "proposed",
|
|
366
|
+
}),
|
|
367
|
+
);
|
|
368
|
+
return write(requiredSurface("experiment_proposal", renderExperimentProposal(story)));
|
|
369
|
+
}
|
|
370
|
+
case "handoff":
|
|
371
|
+
return runHandoff(db, slug, option, rawArgs, deps);
|
|
372
|
+
case "promote":
|
|
373
|
+
return runPromote(db, slug, deps);
|
|
374
|
+
default:
|
|
375
|
+
return usageError(`explore story: unknown action ${action}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Python `cmd_story_promote`: confirm the handoff, mark the story promoted, and
|
|
381
|
+
* enter Builder.
|
|
382
|
+
*
|
|
383
|
+
* The ORDER is the behavior, and one detail decides whether a half-run is
|
|
384
|
+
* recoverable: the Builder tail is resolved BEFORE either write. Python's
|
|
385
|
+
* promote is not idempotent — once the story is promoted it is no longer
|
|
386
|
+
* active, so a second run finds no story and renders `no_builder_handoff` — so
|
|
387
|
+
* a port that mutated first and only then discovered it could not finish would
|
|
388
|
+
* leave the journey in a state neither engine can complete.
|
|
389
|
+
*/
|
|
390
|
+
async function runPromote(
|
|
391
|
+
db: WritableDatabase,
|
|
392
|
+
slug: string,
|
|
393
|
+
deps: ExploreRouteDeps,
|
|
394
|
+
): Promise<number> {
|
|
395
|
+
// The read comes first, and the refusal needs no provider at all: Python's
|
|
396
|
+
// `cmd_story_promote` returns before `cmd_load` when there is no handoff.
|
|
397
|
+
const story = getExplorerStory(db, slug);
|
|
398
|
+
if (!story?.builderHandoff) {
|
|
399
|
+
return write(requiredSurface("no_builder_handoff", renderNoBuilderHandoff(slug)));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const runtime = await deps.buildLoadRuntime?.();
|
|
403
|
+
if (!runtime) {
|
|
404
|
+
// Unreachable through the front door, which always wires the runtime. Loud
|
|
405
|
+
// rather than silent, because a promote with no Builder load behind it
|
|
406
|
+
// would strand a half-promoted story.
|
|
407
|
+
throw new Error("explore story promote reached its route with no Builder load runtime wired");
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Field by field, as Python rebuilds it: only `readiness` changes, and every
|
|
411
|
+
// artifact path the handoff recorded survives the confirmation.
|
|
412
|
+
const handoff = story.builderHandoff;
|
|
413
|
+
afterMutation(
|
|
414
|
+
setExplorerBuilderHandoff(db, slug, deps.clock, {
|
|
415
|
+
title: handoff.title,
|
|
416
|
+
summary: handoff.summary,
|
|
417
|
+
readiness: "confirmed",
|
|
418
|
+
artifactDir: handoff.artifactDir,
|
|
419
|
+
indexPath: handoff.indexPath,
|
|
420
|
+
exploratoryStoryPath: handoff.exploratoryStoryPath,
|
|
421
|
+
handoffInfoPath: handoff.handoffInfoPath,
|
|
422
|
+
productDesignProposalPath: handoff.productDesignProposalPath,
|
|
423
|
+
fullConversationPath: handoff.fullConversationPath,
|
|
424
|
+
}),
|
|
425
|
+
);
|
|
426
|
+
markExplorerStoryPromoted(db, slug, deps.clock);
|
|
427
|
+
|
|
428
|
+
// Python calls `cmd_load(slug)` with no session id, so the session comes from
|
|
429
|
+
// the environment or the active runtime row — never from `explore`'s own
|
|
430
|
+
// `--session-id`, which its promote parser does not even accept.
|
|
431
|
+
const result = await runBuildLoad(
|
|
432
|
+
db,
|
|
433
|
+
{ slug, environmentSessionId: process.env.MIRROR_SESSION_ID ?? null },
|
|
434
|
+
runtime.deps,
|
|
435
|
+
);
|
|
436
|
+
process.stderr.write(result.stderr);
|
|
437
|
+
process.stdout.write(result.stdout);
|
|
438
|
+
return result.exitCode;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function updateStory(
|
|
442
|
+
db: WritableDatabase,
|
|
443
|
+
slug: string,
|
|
444
|
+
settable: (name: string) => Settable,
|
|
445
|
+
deps: ExploreRouteDeps,
|
|
446
|
+
): StoryMutation {
|
|
447
|
+
const fields: {
|
|
448
|
+
currentExploratoryStory?: Settable;
|
|
449
|
+
narrativeFieldSummary?: Settable;
|
|
450
|
+
lastStoryCard?: Settable;
|
|
451
|
+
} = {};
|
|
452
|
+
const story = settable("--story");
|
|
453
|
+
const summary = settable("--summary");
|
|
454
|
+
const lastCard = settable("--last-card");
|
|
455
|
+
if (story !== UNSET) fields.currentExploratoryStory = story;
|
|
456
|
+
if (summary !== UNSET) fields.narrativeFieldSummary = summary;
|
|
457
|
+
if (lastCard !== UNSET) fields.lastStoryCard = lastCard;
|
|
458
|
+
return updateExplorerStory(db, slug, deps.clock, fields);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function runHandoff(
|
|
462
|
+
db: WritableDatabase,
|
|
463
|
+
slug: string,
|
|
464
|
+
option: (name: string) => string | null,
|
|
465
|
+
rawArgs: readonly string[],
|
|
466
|
+
deps: ExploreRouteDeps,
|
|
467
|
+
): number {
|
|
468
|
+
const title = option("--title");
|
|
469
|
+
if (title === null) {
|
|
470
|
+
return usageError("explore story handoff: the following arguments are required: --title");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const story = getExplorerStory(db, slug);
|
|
474
|
+
if (!story) {
|
|
475
|
+
return write(requiredSurface("no_exploratory_story", renderMissingExploratoryStory(slug)));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const includeFullConversation = rawArgs.includes("--include-full-conversation");
|
|
479
|
+
const sources = loadHandoffSources(
|
|
480
|
+
db,
|
|
481
|
+
collectRepeated(rawArgs, "--source-conversation"),
|
|
482
|
+
includeFullConversation,
|
|
483
|
+
deps,
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
let current = story;
|
|
487
|
+
if (sources.length > 0) {
|
|
488
|
+
current = afterMutation(
|
|
489
|
+
setExplorerSourceConversations(
|
|
490
|
+
db,
|
|
491
|
+
slug,
|
|
492
|
+
deps.clock,
|
|
493
|
+
sources.map((source) => ({
|
|
494
|
+
conversationId: source.conversationId,
|
|
495
|
+
title: source.title,
|
|
496
|
+
role: source.role,
|
|
497
|
+
})),
|
|
498
|
+
),
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const projectPath = getProjectPath(db, slug);
|
|
503
|
+
const handoff = projectPath
|
|
504
|
+
? writeBuilderHandoffArtifacts(projectPath, current, {
|
|
505
|
+
title,
|
|
506
|
+
summary: option("--summary"),
|
|
507
|
+
editorialSynthesis: option("--editorial-synthesis"),
|
|
508
|
+
sourceConversations: sources,
|
|
509
|
+
includeFullConversation,
|
|
510
|
+
})
|
|
511
|
+
: {
|
|
512
|
+
title,
|
|
513
|
+
summary: option("--summary"),
|
|
514
|
+
readiness: "proposed" as const,
|
|
515
|
+
artifactDir: null,
|
|
516
|
+
indexPath: null,
|
|
517
|
+
exploratoryStoryPath: null,
|
|
518
|
+
handoffInfoPath: null,
|
|
519
|
+
productDesignProposalPath: null,
|
|
520
|
+
fullConversationPath: null,
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
const updated = afterMutation(setExplorerBuilderHandoff(db, slug, deps.clock, handoff));
|
|
524
|
+
return write(requiredSurface("builder_handoff_proposed", renderBuilderHandoffProposed(updated)));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** `action="append"`: every occurrence, in order. */
|
|
528
|
+
function collectRepeated(args: readonly string[], name: string): string[] {
|
|
529
|
+
const values: string[] = [];
|
|
530
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
531
|
+
if (args[index] === name && index + 1 < args.length) values.push(args[index + 1] as string);
|
|
532
|
+
}
|
|
533
|
+
return values;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/** Python `_parse_source_conversation_arg`: `id` or `id:role`. */
|
|
537
|
+
function parseSourceConversationArg(value: string): { id: string; role: string } {
|
|
538
|
+
const separator = value.indexOf(":");
|
|
539
|
+
if (separator === -1) return { id: value.trim(), role: "source evidence" };
|
|
540
|
+
return {
|
|
541
|
+
id: value.slice(0, separator).trim(),
|
|
542
|
+
role: value.slice(separator + 1).trim() || "source evidence",
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** Python `_load_handoff_sources`: id, then id-prefix; an unknown id is skipped. */
|
|
547
|
+
function loadHandoffSources(
|
|
548
|
+
db: WritableDatabase,
|
|
549
|
+
raw: readonly string[],
|
|
550
|
+
includeMessages: boolean,
|
|
551
|
+
deps: ExploreRouteDeps,
|
|
552
|
+
): HandoffConversationSource[] {
|
|
553
|
+
const sources: HandoffConversationSource[] = [];
|
|
554
|
+
for (const value of raw) {
|
|
555
|
+
const { id, role } = parseSourceConversationArg(value);
|
|
556
|
+
const conversation =
|
|
557
|
+
(db.prepare("SELECT id, title FROM conversations WHERE id = ?").get(id) as
|
|
558
|
+
| { id: string; title: string | null }
|
|
559
|
+
| undefined) ??
|
|
560
|
+
(db
|
|
561
|
+
.prepare("SELECT id, title FROM conversations WHERE id LIKE ? ORDER BY id LIMIT 1")
|
|
562
|
+
.get(`${id}%`) as { id: string; title: string | null } | undefined);
|
|
563
|
+
if (!conversation) continue;
|
|
564
|
+
sources.push({
|
|
565
|
+
conversationId: conversation.id,
|
|
566
|
+
title: conversation.title ?? null,
|
|
567
|
+
role,
|
|
568
|
+
messages: includeMessages ? deps.readMessages(db, conversation.id) : [],
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
return sources;
|
|
572
|
+
}
|