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,522 @@
|
|
|
1
|
+
// CV22.DS7.US7 plateau 3 — the Explorer → Builder handoff artifacts, ported
|
|
2
|
+
// from `src/memory/services/explorer_handoff.py`.
|
|
3
|
+
//
|
|
4
|
+
// This module writes five Markdown documents into the USER'S OWN PROJECT, under
|
|
5
|
+
// `<project>/docs/project/explorations/<slug>/`. That makes it the security
|
|
6
|
+
// boundary of the story: `obfuscateSensitiveText` is the last thing standing
|
|
7
|
+
// between a conversation transcript and a file the user commits, and an
|
|
8
|
+
// under-matching port does not fail loudly — it writes a real key into git.
|
|
9
|
+
//
|
|
10
|
+
// So none of the five patterns uses a JavaScript character class shorthand.
|
|
11
|
+
// Every one of them diverges from Python in a way the corpus proves:
|
|
12
|
+
//
|
|
13
|
+
// * `\s` — Python includes U+001C-U+001F and excludes U+FEFF; JavaScript is
|
|
14
|
+
// the exact opposite. The path pattern terminates on it.
|
|
15
|
+
// * `\d` — Python matches EVERY Unicode decimal digit; JavaScript's `\d` is
|
|
16
|
+
// ASCII-only. A phone number in Devanagari digits is redacted by the oracle
|
|
17
|
+
// and, with `\d`, silently is not. Under-redaction is the dangerous
|
|
18
|
+
// direction, and this is the one place the port could reach it.
|
|
19
|
+
// * `\b` — Python's word boundary follows its Unicode-aware `\w`;
|
|
20
|
+
// JavaScript's is ASCII. Reproduced with explicit lookarounds.
|
|
21
|
+
// * `(?i)` — an inline flag JavaScript has no equivalent for; the whole
|
|
22
|
+
// pattern takes `i` instead, which is equivalent only because no other part
|
|
23
|
+
// of it is case-sensitive.
|
|
24
|
+
//
|
|
25
|
+
// Replacements are literal. `String.prototype.replace` interprets `$&`, `` $` ``,
|
|
26
|
+
// `$'`, `$1`, and `$$` in the REPLACEMENT string, so a redaction marker that
|
|
27
|
+
// happened to contain one would rewrite itself from the matched secret. The
|
|
28
|
+
// markers here are bracketed literals, and the one backreference is written
|
|
29
|
+
// deliberately as `$1`.
|
|
30
|
+
|
|
31
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
32
|
+
import { join } from "node:path";
|
|
33
|
+
|
|
34
|
+
import type { ExplorerBuilderHandoff, ExplorerStory } from "#explorer/story.ts";
|
|
35
|
+
import { PYTHON_WHITESPACE_CLASS } from "#util/pythonText.ts";
|
|
36
|
+
import { kebabSlug } from "#util/slug.ts";
|
|
37
|
+
|
|
38
|
+
export interface HandoffSourceMessage {
|
|
39
|
+
readonly role: string;
|
|
40
|
+
readonly content: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface HandoffConversationSource {
|
|
44
|
+
readonly conversationId: string;
|
|
45
|
+
readonly title: string | null;
|
|
46
|
+
readonly role: string;
|
|
47
|
+
readonly messages: readonly HandoffSourceMessage[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --- redaction -------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
/** Python's `\w`: `str.isalnum()` or underscore, so Unicode-aware. */
|
|
53
|
+
const PY_WORD = "\\p{L}\\p{N}_";
|
|
54
|
+
/** Python's `\d`: every Unicode decimal digit (category Nd), not `[0-9]`. */
|
|
55
|
+
const PY_DIGIT = "\\p{Nd}";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Python's `\b` over the Unicode `\w` above.
|
|
59
|
+
*
|
|
60
|
+
* A negative lookbehind is NOT a word boundary, and the difference is visible:
|
|
61
|
+
* `\b` asserts a TRANSITION — word-then-nonword or nonword-then-word — while
|
|
62
|
+
* `(?<![\w])` only asserts "no word character behind". On `call +55 21 ...`
|
|
63
|
+
* the position before `+` satisfies the lookbehind but is not a boundary, so
|
|
64
|
+
* the oracle starts its match at the first digit and leaves the `+` in place.
|
|
65
|
+
* A lookbehind-only port swallows the `+`, over-redacting by one character.
|
|
66
|
+
*/
|
|
67
|
+
const PY_BOUNDARY = `(?:(?<=[${PY_WORD}])(?![${PY_WORD}])|(?<![${PY_WORD}])(?=[${PY_WORD}]))`;
|
|
68
|
+
|
|
69
|
+
const REDACTIONS: readonly { pattern: RegExp; replacement: string }[] = [
|
|
70
|
+
// `/Users/[^\s)\]]+`
|
|
71
|
+
{
|
|
72
|
+
pattern: new RegExp(`/Users/[^${PYTHON_WHITESPACE_CLASS})\\]]+`, "gu"),
|
|
73
|
+
replacement: "[LOCAL_PATH]",
|
|
74
|
+
},
|
|
75
|
+
// `(?i)(api[_-]?key|token|secret|password)\s*=\s*[^\s]+`
|
|
76
|
+
{
|
|
77
|
+
pattern: new RegExp(
|
|
78
|
+
`(api[_-]?key|token|secret|password)[${PYTHON_WHITESPACE_CLASS}]*=` +
|
|
79
|
+
`[${PYTHON_WHITESPACE_CLASS}]*[^${PYTHON_WHITESPACE_CLASS}]+`,
|
|
80
|
+
"giu",
|
|
81
|
+
),
|
|
82
|
+
replacement: "$1=[SECRET]",
|
|
83
|
+
},
|
|
84
|
+
// `sk-[A-Za-z0-9_-]{12,}`
|
|
85
|
+
{ pattern: /sk-[A-Za-z0-9_-]{12,}/gu, replacement: "[SECRET]" },
|
|
86
|
+
// `[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}`
|
|
87
|
+
{
|
|
88
|
+
pattern: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/gu,
|
|
89
|
+
replacement: "[PRIVATE_EMAIL]",
|
|
90
|
+
},
|
|
91
|
+
// `\b(?:\+?\d[\d .()-]{8,}\d)\b`
|
|
92
|
+
{
|
|
93
|
+
pattern: new RegExp(
|
|
94
|
+
`${PY_BOUNDARY}(?:\\+?${PY_DIGIT}[${PY_DIGIT} .()-]{8,}${PY_DIGIT})${PY_BOUNDARY}`,
|
|
95
|
+
"gu",
|
|
96
|
+
),
|
|
97
|
+
replacement: "[PRIVATE_PHONE]",
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Port of `_obfuscate_sensitive_text`. Applied to transcript text before it
|
|
103
|
+
* reaches `full-conversation.md`.
|
|
104
|
+
*
|
|
105
|
+
* Ported at its current strength, gaps included — `/home/...` survives, and so
|
|
106
|
+
* does a bearer token without an `=`. Strengthening the patterns would break
|
|
107
|
+
* parity and is a product decision, not a port decision (US7 plan, Non-Goals).
|
|
108
|
+
*/
|
|
109
|
+
export function obfuscateSensitiveText(text: string): string {
|
|
110
|
+
let redacted = text;
|
|
111
|
+
for (const { pattern, replacement } of REDACTIONS) {
|
|
112
|
+
redacted = redacted.replace(pattern, replacement);
|
|
113
|
+
}
|
|
114
|
+
return redacted;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// --- shared document fragments ---------------------------------------------
|
|
118
|
+
|
|
119
|
+
function renderAttractors(story: ExplorerStory): string {
|
|
120
|
+
if (story.attractors.length === 0) return "_No attractors recorded._";
|
|
121
|
+
const lines: string[] = [];
|
|
122
|
+
for (const attractor of story.attractors) {
|
|
123
|
+
lines.push(`- **${attractor.label}** (\`${attractor.status}\`)`);
|
|
124
|
+
if (attractor.description) lines.push(` - ${attractor.description}`);
|
|
125
|
+
}
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renderExperiment(story: ExplorerStory): string {
|
|
130
|
+
const proposal = story.experimentProposal;
|
|
131
|
+
if (!proposal) return "_No experiment proposal recorded._";
|
|
132
|
+
const lines = [`**${proposal.title}** (\`${proposal.status}\`)`];
|
|
133
|
+
if (proposal.description) lines.push("", proposal.description);
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function renderSourceEvidence(sources: readonly HandoffConversationSource[]): string {
|
|
138
|
+
if (sources.length === 0) return "_No source conversations were attached to this handoff._";
|
|
139
|
+
return sources
|
|
140
|
+
.map(
|
|
141
|
+
(source) =>
|
|
142
|
+
`- \`${source.conversationId}\` — ${source.title || "Untitled conversation"} (${source.role})`,
|
|
143
|
+
)
|
|
144
|
+
.join("\n");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderDecidedProductDirection(story: ExplorerStory): string {
|
|
148
|
+
const parts: string[] = [];
|
|
149
|
+
if (story.currentExploratoryStory) parts.push(story.currentExploratoryStory);
|
|
150
|
+
if (story.narrativeFieldSummary) parts.push(story.narrativeFieldSummary);
|
|
151
|
+
return parts.join("\n\n") || "_No decided product direction recorded._";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function renderCompletenessChecklist(
|
|
155
|
+
story: ExplorerStory,
|
|
156
|
+
sources: readonly HandoffConversationSource[],
|
|
157
|
+
includesFullConversation: boolean,
|
|
158
|
+
): string {
|
|
159
|
+
const checks: readonly [string, boolean][] = [
|
|
160
|
+
[
|
|
161
|
+
"continuous exploratory thickening",
|
|
162
|
+
Boolean(story.narrativeFieldSummary || story.lastStoryCard),
|
|
163
|
+
],
|
|
164
|
+
["source evidence list", sources.length > 0],
|
|
165
|
+
["surfaces and story state", Boolean(story.currentExploratoryStory)],
|
|
166
|
+
["phases or evolution narrative", Boolean(story.narrativeFieldSummary)],
|
|
167
|
+
["examples or simulations", includesFullConversation],
|
|
168
|
+
["product decisions", Boolean(story.currentExploratoryStory)],
|
|
169
|
+
["user conversation flows", includesFullConversation],
|
|
170
|
+
["transition rules", true],
|
|
171
|
+
["risks", true],
|
|
172
|
+
["boundaries", true],
|
|
173
|
+
["open questions", true],
|
|
174
|
+
["what Builder should preserve", true],
|
|
175
|
+
["what Builder should not assume", true],
|
|
176
|
+
];
|
|
177
|
+
const lines = checks.map(([label, present]) => `- [${present ? "x" : " "}] ${label}`);
|
|
178
|
+
const missing = checks.filter(([, present]) => !present).map(([label]) => label);
|
|
179
|
+
if (missing.length > 0) {
|
|
180
|
+
lines.push("", "Missing or weak evidence before Builder should treat this as complete:");
|
|
181
|
+
lines.push(...missing.map((label) => `- ${label}`));
|
|
182
|
+
}
|
|
183
|
+
return lines.join("\n");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// --- documents -------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
function renderIndexDoc(
|
|
189
|
+
story: ExplorerStory,
|
|
190
|
+
options: {
|
|
191
|
+
title: string;
|
|
192
|
+
summary: string | null;
|
|
193
|
+
editorialSynthesis: string | null;
|
|
194
|
+
sourceConversations: readonly HandoffConversationSource[];
|
|
195
|
+
includesFullConversation: boolean;
|
|
196
|
+
},
|
|
197
|
+
): string {
|
|
198
|
+
const fullConversationLine = options.includesFullConversation
|
|
199
|
+
? "- [Full Conversation Evidence](full-conversation.md): privacy-reviewed raw source material."
|
|
200
|
+
: "- Full conversation evidence was not included in this handoff.";
|
|
201
|
+
|
|
202
|
+
return `# Exploration Handoff: ${options.title}
|
|
203
|
+
|
|
204
|
+
## Editorial Synthesis
|
|
205
|
+
|
|
206
|
+
${options.editorialSynthesis || options.summary || story.narrativeFieldSummary || "_No editorial synthesis recorded._"}
|
|
207
|
+
|
|
208
|
+
## Durable Story
|
|
209
|
+
|
|
210
|
+
- Story id: \`${story.id || "not recorded"}\`
|
|
211
|
+
- Journey: \`${story.journey}\`
|
|
212
|
+
- Status: \`${story.status}\`
|
|
213
|
+
|
|
214
|
+
## Source Evidence
|
|
215
|
+
|
|
216
|
+
${renderSourceEvidence(options.sourceConversations)}
|
|
217
|
+
|
|
218
|
+
## What Was Decided
|
|
219
|
+
|
|
220
|
+
${renderDecidedProductDirection(story)}
|
|
221
|
+
|
|
222
|
+
## Transfer Documents
|
|
223
|
+
|
|
224
|
+
- [Exploratory Story](exploratory-story.md): discovery narrative and continuous thickening.
|
|
225
|
+
- [Handoff Info](handoff-info.md): risks, open questions, boundaries, and non-assumptions for Builder.
|
|
226
|
+
- [Product Design Proposal](product-design-proposal.md): user-facing product behavior, without implementation detail.
|
|
227
|
+
${fullConversationLine}
|
|
228
|
+
|
|
229
|
+
## Current Attractors
|
|
230
|
+
|
|
231
|
+
${renderAttractors(story)}
|
|
232
|
+
|
|
233
|
+
## Current Experiment Proposal
|
|
234
|
+
|
|
235
|
+
${renderExperiment(story)}
|
|
236
|
+
|
|
237
|
+
## Builder Reading Order
|
|
238
|
+
|
|
239
|
+
Read this \`index.md\` first, then \`exploratory-story.md\`, then \`handoff-info.md\`, then \`product-design-proposal.md\`. If \`full-conversation.md\` exists, read it as source evidence, not as a delivery plan. Treat the set as exploration output, not as a completed delivery plan.
|
|
240
|
+
`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function renderExploratoryStoryDoc(
|
|
244
|
+
story: ExplorerStory,
|
|
245
|
+
options: { title: string; editorialSynthesis: string | null },
|
|
246
|
+
): string {
|
|
247
|
+
return `# Exploratory Story: ${options.title}
|
|
248
|
+
|
|
249
|
+
## Source
|
|
250
|
+
|
|
251
|
+
- Journey: \`${story.journey}\`
|
|
252
|
+
- Story id: \`${story.id || "not recorded"}\`
|
|
253
|
+
- Mode: Explorer Mode
|
|
254
|
+
|
|
255
|
+
## Continuous Thickening Narrative
|
|
256
|
+
|
|
257
|
+
${options.editorialSynthesis || story.narrativeFieldSummary || "_No continuous thickening narrative recorded._"}
|
|
258
|
+
|
|
259
|
+
## Current Exploratory Story
|
|
260
|
+
|
|
261
|
+
${story.currentExploratoryStory || "_No story text recorded._"}
|
|
262
|
+
|
|
263
|
+
## Narrative Summary
|
|
264
|
+
|
|
265
|
+
${story.narrativeFieldSummary || "_No narrative summary recorded._"}
|
|
266
|
+
|
|
267
|
+
## Last Story Card
|
|
268
|
+
|
|
269
|
+
${story.lastStoryCard || "_No last story card recorded._"}
|
|
270
|
+
|
|
271
|
+
## Attractors
|
|
272
|
+
|
|
273
|
+
${renderAttractors(story)}
|
|
274
|
+
|
|
275
|
+
## Experiment Proposal
|
|
276
|
+
|
|
277
|
+
${renderExperiment(story)}
|
|
278
|
+
|
|
279
|
+
## What Changed Through Exploration
|
|
280
|
+
|
|
281
|
+
This section should preserve the evolution of the exploration: the original question, the meaningful pivots, the corrections that changed the story, and the current point of promotion. If this document was generated from a short runtime summary, Builder should ask the Navigator whether more conversation evidence must be folded in before roadmap work starts.
|
|
282
|
+
`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function renderHandoffInfoDoc(
|
|
286
|
+
story: ExplorerStory,
|
|
287
|
+
options: {
|
|
288
|
+
title: string;
|
|
289
|
+
summary: string | null;
|
|
290
|
+
sourceConversations: readonly HandoffConversationSource[];
|
|
291
|
+
includesFullConversation: boolean;
|
|
292
|
+
},
|
|
293
|
+
): string {
|
|
294
|
+
return `# Handoff Info: ${options.title}
|
|
295
|
+
|
|
296
|
+
## Handoff Summary
|
|
297
|
+
|
|
298
|
+
${options.summary || story.narrativeFieldSummary || "_No handoff summary recorded._"}
|
|
299
|
+
|
|
300
|
+
## Handoff Completeness Checklist
|
|
301
|
+
|
|
302
|
+
${renderCompletenessChecklist(story, options.sourceConversations, options.includesFullConversation)}
|
|
303
|
+
|
|
304
|
+
## What Builder Should Preserve
|
|
305
|
+
|
|
306
|
+
- The exploration is not only a feature request. It carries discovery context and product judgment.
|
|
307
|
+
- The attractor and experiment proposal should guide Builder's first roadmap framing.
|
|
308
|
+
- The product design proposal should be translated into roadmap/story docs only after Builder reads the project.
|
|
309
|
+
|
|
310
|
+
## Risks
|
|
311
|
+
|
|
312
|
+
- Builder may over-treat exploratory material as settled delivery scope.
|
|
313
|
+
- Builder may flatten open questions into implementation assumptions.
|
|
314
|
+
- Builder may focus on mechanism before preserving the user-facing product shape.
|
|
315
|
+
|
|
316
|
+
## Open Questions
|
|
317
|
+
|
|
318
|
+
- Which parts of this exploration should become roadmap stories?
|
|
319
|
+
- What validation route proves the product behavior externally?
|
|
320
|
+
- What should remain outside the first delivery slice?
|
|
321
|
+
|
|
322
|
+
## Boundaries
|
|
323
|
+
|
|
324
|
+
- This handoff is not a delivery plan.
|
|
325
|
+
- Builder must still read the project, create or update roadmap/story docs, and validate with the Navigator.
|
|
326
|
+
- Explorer preserved uncertainty; Builder should not erase it prematurely.
|
|
327
|
+
|
|
328
|
+
## Non-Assumptions
|
|
329
|
+
|
|
330
|
+
- Do not assume implementation architecture from this handoff.
|
|
331
|
+
- Do not assume all open questions are in scope.
|
|
332
|
+
- Do not assume the experiment proposal has already been validated.
|
|
333
|
+
|
|
334
|
+
## Attractors
|
|
335
|
+
|
|
336
|
+
${renderAttractors(story)}
|
|
337
|
+
|
|
338
|
+
## Experiment Status
|
|
339
|
+
|
|
340
|
+
${renderExperiment(story)}
|
|
341
|
+
|
|
342
|
+
## Promotion Boundary
|
|
343
|
+
|
|
344
|
+
Builder executes only after explicit confirmation from the Navigator.
|
|
345
|
+
`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function renderProductDesignDoc(
|
|
349
|
+
story: ExplorerStory,
|
|
350
|
+
options: { title: string; summary: string | null },
|
|
351
|
+
): string {
|
|
352
|
+
return `# Product Design Proposal: ${options.title}
|
|
353
|
+
|
|
354
|
+
## Product Intent
|
|
355
|
+
|
|
356
|
+
${options.summary || story.narrativeFieldSummary || "_No product intent summary recorded._"}
|
|
357
|
+
|
|
358
|
+
## User-Facing Behavior
|
|
359
|
+
|
|
360
|
+
${story.currentExploratoryStory || "_No current story recorded._"}
|
|
361
|
+
|
|
362
|
+
## What The Product Should Feel Like
|
|
363
|
+
|
|
364
|
+
The product should preserve the exploratory shape discovered by Explorer Mode. It should show the user what is happening at the product level, not expose implementation mechanics first.
|
|
365
|
+
|
|
366
|
+
## Interaction Flow
|
|
367
|
+
|
|
368
|
+
- User works in Explorer Mode while uncertainty is still alive.
|
|
369
|
+
- Explorer surfaces story changes visibly.
|
|
370
|
+
- Explorer names attractors and proposes small experiments.
|
|
371
|
+
- Explorer proposes Builder handoff only when the user asks or confirms readiness.
|
|
372
|
+
- Builder begins only after explicit confirmation.
|
|
373
|
+
|
|
374
|
+
## Product-Level States
|
|
375
|
+
|
|
376
|
+
- Exploratory Story active.
|
|
377
|
+
- Attractor proposed or accepted.
|
|
378
|
+
- Experiment proposal proposed or accepted.
|
|
379
|
+
- Builder handoff proposed.
|
|
380
|
+
|
|
381
|
+
## Acceptance Behavior
|
|
382
|
+
|
|
383
|
+
- The user can understand what is being proposed without reading implementation details.
|
|
384
|
+
- The proposal preserves uncertainty and open questions.
|
|
385
|
+
- The proposal gives Builder enough product shape to create roadmap or story plans.
|
|
386
|
+
|
|
387
|
+
## Explicit Non-Goals
|
|
388
|
+
|
|
389
|
+
- This document does not define implementation architecture.
|
|
390
|
+
- This document does not create delivery tasks by itself.
|
|
391
|
+
- This document does not replace Builder planning.
|
|
392
|
+
|
|
393
|
+
## Open Product Questions
|
|
394
|
+
|
|
395
|
+
- Which behavior is necessary for the first delivery slice?
|
|
396
|
+
- What should remain exploratory after Builder starts?
|
|
397
|
+
- What user validation will prove the product behavior works?
|
|
398
|
+
`;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function renderFullConversationDoc(sources: readonly HandoffConversationSource[]): string {
|
|
402
|
+
const sections: string[] = [
|
|
403
|
+
"# Full Conversation Evidence",
|
|
404
|
+
"",
|
|
405
|
+
"This document is source evidence for a Builder handoff. Sensitive personal or local details may have been obfuscated before writing.",
|
|
406
|
+
];
|
|
407
|
+
for (const source of sources) {
|
|
408
|
+
sections.push(
|
|
409
|
+
"",
|
|
410
|
+
`## Conversation ${source.conversationId}`,
|
|
411
|
+
"",
|
|
412
|
+
`- Title: ${source.title || "Untitled conversation"}`,
|
|
413
|
+
`- Evidence role: ${source.role}`,
|
|
414
|
+
);
|
|
415
|
+
for (const message of source.messages) {
|
|
416
|
+
sections.push("", `### ${message.role}`, "", obfuscateSensitiveText(message.content));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return `${sections.join("\n")}\n`;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// --- artifact write --------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
export interface WriteHandoffOptions {
|
|
425
|
+
readonly title: string;
|
|
426
|
+
readonly summary?: string | null;
|
|
427
|
+
readonly editorialSynthesis?: string | null;
|
|
428
|
+
readonly sourceConversations?: readonly HandoffConversationSource[];
|
|
429
|
+
readonly includeFullConversation?: boolean;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Port of `write_builder_handoff_artifacts`.
|
|
434
|
+
*
|
|
435
|
+
* The directory name is `kebab_slug` of the caller-supplied title, falling back
|
|
436
|
+
* to the story text, then the journey, then the literal `"exploration"`. The
|
|
437
|
+
* collision loop appends `-2`, `-3`, ... and is a pre-existing TOCTOU race
|
|
438
|
+
* (check-then-create); it is reproduced rather than fixed, because changing it
|
|
439
|
+
* would be a behavior change hiding inside a port.
|
|
440
|
+
*
|
|
441
|
+
* `kebabSlug` collapses every non-alphanumeric run to a hyphen, so a
|
|
442
|
+
* traversal-looking title cannot escape: `../../etc/passwd` slugs to
|
|
443
|
+
* `etc-passwd`. The corpus proves that rather than the comment asserting it.
|
|
444
|
+
*/
|
|
445
|
+
export function writeBuilderHandoffArtifacts(
|
|
446
|
+
projectPath: string,
|
|
447
|
+
story: ExplorerStory,
|
|
448
|
+
options: WriteHandoffOptions,
|
|
449
|
+
): ExplorerBuilderHandoff {
|
|
450
|
+
const summary = options.summary ?? null;
|
|
451
|
+
const sourceConversations = options.sourceConversations ?? [];
|
|
452
|
+
const includeFullConversation = options.includeFullConversation ?? false;
|
|
453
|
+
const fullConversationWritten = includeFullConversation && sourceConversations.length > 0;
|
|
454
|
+
|
|
455
|
+
const explorationsRoot = join(projectPath, "docs", "project", "explorations");
|
|
456
|
+
const slug =
|
|
457
|
+
kebabSlug(options.title || story.currentExploratoryStory || story.journey) || "exploration";
|
|
458
|
+
|
|
459
|
+
let base = join(explorationsRoot, slug);
|
|
460
|
+
let suffix = 2;
|
|
461
|
+
while (existsSync(base)) {
|
|
462
|
+
base = join(explorationsRoot, `${slug}-${suffix}`);
|
|
463
|
+
suffix += 1;
|
|
464
|
+
}
|
|
465
|
+
mkdirSync(base, { recursive: true });
|
|
466
|
+
|
|
467
|
+
const indexPath = join(base, "index.md");
|
|
468
|
+
const exploratoryStoryPath = join(base, "exploratory-story.md");
|
|
469
|
+
const handoffInfoPath = join(base, "handoff-info.md");
|
|
470
|
+
const productDesignPath = join(base, "product-design-proposal.md");
|
|
471
|
+
const fullConversationPath = join(base, "full-conversation.md");
|
|
472
|
+
|
|
473
|
+
writeFileSync(
|
|
474
|
+
indexPath,
|
|
475
|
+
renderIndexDoc(story, {
|
|
476
|
+
title: options.title,
|
|
477
|
+
summary,
|
|
478
|
+
editorialSynthesis: options.editorialSynthesis ?? null,
|
|
479
|
+
sourceConversations,
|
|
480
|
+
includesFullConversation: fullConversationWritten,
|
|
481
|
+
}),
|
|
482
|
+
"utf-8",
|
|
483
|
+
);
|
|
484
|
+
writeFileSync(
|
|
485
|
+
exploratoryStoryPath,
|
|
486
|
+
renderExploratoryStoryDoc(story, {
|
|
487
|
+
title: options.title,
|
|
488
|
+
editorialSynthesis: options.editorialSynthesis ?? null,
|
|
489
|
+
}),
|
|
490
|
+
"utf-8",
|
|
491
|
+
);
|
|
492
|
+
writeFileSync(
|
|
493
|
+
handoffInfoPath,
|
|
494
|
+
renderHandoffInfoDoc(story, {
|
|
495
|
+
title: options.title,
|
|
496
|
+
summary,
|
|
497
|
+
sourceConversations,
|
|
498
|
+
includesFullConversation: fullConversationWritten,
|
|
499
|
+
}),
|
|
500
|
+
"utf-8",
|
|
501
|
+
);
|
|
502
|
+
writeFileSync(
|
|
503
|
+
productDesignPath,
|
|
504
|
+
renderProductDesignDoc(story, { title: options.title, summary }),
|
|
505
|
+
"utf-8",
|
|
506
|
+
);
|
|
507
|
+
if (fullConversationWritten) {
|
|
508
|
+
writeFileSync(fullConversationPath, renderFullConversationDoc(sourceConversations), "utf-8");
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return {
|
|
512
|
+
title: options.title,
|
|
513
|
+
summary,
|
|
514
|
+
readiness: "proposed",
|
|
515
|
+
artifactDir: base,
|
|
516
|
+
indexPath,
|
|
517
|
+
exploratoryStoryPath,
|
|
518
|
+
handoffInfoPath,
|
|
519
|
+
productDesignProposalPath: productDesignPath,
|
|
520
|
+
fullConversationPath: fullConversationWritten ? fullConversationPath : null,
|
|
521
|
+
};
|
|
522
|
+
}
|