mirror-mind 0.0.1 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/log-session-end.sh +85 -0
- package/.claude/hooks/log-user-prompt.sh +85 -0
- package/.claude/hooks/mirror-inject.sh +85 -0
- package/.claude/hooks/session-start.sh +85 -0
- package/.gemini/hooks/log-assistant.sh +85 -0
- package/.gemini/hooks/log-user.sh +85 -0
- package/.gemini/hooks/session-end.sh +85 -0
- package/.gemini/hooks/session-start.sh +85 -0
- package/.pi/extensions/mirror-logger.ts +561 -0
- package/.pi/skills/mm-backup/SKILL.md +21 -0
- package/.pi/skills/mm-build/SKILL.md +1206 -0
- package/.pi/skills/mm-consolidate/SKILL.md +112 -0
- package/.pi/skills/mm-consult/SKILL.md +70 -0
- package/.pi/skills/mm-conversations/SKILL.md +16 -0
- package/.pi/skills/mm-discard/SKILL.md +39 -0
- package/.pi/skills/mm-explore/SKILL.md +255 -0
- package/.pi/skills/mm-help/SKILL.md +74 -0
- package/.pi/skills/mm-identity/SKILL.md +96 -0
- package/.pi/skills/mm-journal/SKILL.md +16 -0
- package/.pi/skills/mm-journey/SKILL.md +23 -0
- package/.pi/skills/mm-journeys/SKILL.md +15 -0
- package/.pi/skills/mm-memories/SKILL.md +17 -0
- package/.pi/skills/mm-mirror/SKILL.md +98 -0
- package/.pi/skills/mm-mute/SKILL.md +18 -0
- package/.pi/skills/mm-new/SKILL.md +18 -0
- package/.pi/skills/mm-recall/SKILL.md +17 -0
- package/.pi/skills/mm-release-notes/SKILL.md +52 -0
- package/.pi/skills/mm-seed/SKILL.md +19 -0
- package/.pi/skills/mm-shadow/SKILL.md +117 -0
- package/.pi/skills/mm-soul/SKILL.md +502 -0
- package/.pi/skills/mm-tasks/SKILL.md +24 -0
- package/.pi/skills/mm-update/SKILL.md +32 -0
- package/.pi/skills/mm-week/SKILL.md +28 -0
- package/.pi/skills/mm-welcome/SKILL.md +24 -0
- package/AGENTS.md +188 -0
- package/README.md +126 -9
- package/bin/loader.js +67 -0
- package/bin/mirror-hook.js +7 -0
- package/bin/mirror.js +7 -0
- package/docs/releases/index.md +99 -0
- package/docs/releases/pending-cutoffs.md +510 -0
- package/docs/releases/v0.10.0.md +123 -0
- package/docs/releases/v0.10.1.md +66 -0
- package/docs/releases/v0.10.10.md +51 -0
- package/docs/releases/v0.10.11.md +39 -0
- package/docs/releases/v0.10.12.md +57 -0
- package/docs/releases/v0.10.13.md +35 -0
- package/docs/releases/v0.10.14.md +42 -0
- package/docs/releases/v0.10.15.md +53 -0
- package/docs/releases/v0.10.16.md +35 -0
- package/docs/releases/v0.10.17.md +43 -0
- package/docs/releases/v0.10.2.md +64 -0
- package/docs/releases/v0.10.3.md +78 -0
- package/docs/releases/v0.10.4.md +42 -0
- package/docs/releases/v0.10.5.md +57 -0
- package/docs/releases/v0.10.6.md +47 -0
- package/docs/releases/v0.10.7.md +53 -0
- package/docs/releases/v0.10.8.md +49 -0
- package/docs/releases/v0.10.9.md +37 -0
- package/docs/releases/v0.11.0.md +86 -0
- package/docs/releases/v0.12.0.md +67 -0
- package/docs/releases/v0.13.0.md +64 -0
- package/docs/releases/v0.14.0.md +68 -0
- package/docs/releases/v0.15.0.md +48 -0
- package/docs/releases/v0.16.0.md +50 -0
- package/docs/releases/v0.16.1.md +55 -0
- package/docs/releases/v0.16.2.md +36 -0
- package/docs/releases/v0.17.0.md +50 -0
- package/docs/releases/v0.17.1.md +58 -0
- package/docs/releases/v0.17.2.md +42 -0
- package/docs/releases/v0.17.3.md +58 -0
- package/docs/releases/v0.18.0.md +84 -0
- package/docs/releases/v0.18.1.md +51 -0
- package/docs/releases/v0.18.2.md +69 -0
- package/docs/releases/v0.19.0.md +85 -0
- package/docs/releases/v0.19.1.md +46 -0
- package/docs/releases/v0.20.0.md +85 -0
- package/docs/releases/v0.21.0.md +61 -0
- package/docs/releases/v0.21.1.md +47 -0
- package/docs/releases/v0.22.0.md +77 -0
- package/docs/releases/v0.22.1.md +42 -0
- package/docs/releases/v0.23.0.md +105 -0
- package/docs/releases/v0.24.0.md +125 -0
- package/docs/releases/v0.25.0.md +107 -0
- package/docs/releases/v0.26.0.md +139 -0
- package/docs/releases/v0.26.1.md +65 -0
- package/docs/releases/v0.26.2.md +43 -0
- package/docs/releases/v0.27.0.md +63 -0
- package/docs/releases/v0.28.0.md +59 -0
- package/docs/releases/v0.29.0.md +61 -0
- package/docs/releases/v0.29.1.md +59 -0
- package/docs/releases/v0.29.2.md +59 -0
- package/docs/releases/v0.29.3.md +93 -0
- package/docs/releases/v0.30.0.md +75 -0
- package/docs/releases/v0.30.1.md +93 -0
- package/docs/releases/v0.30.2.md +66 -0
- package/docs/releases/v0.31.0.md +122 -0
- package/docs/releases/v0.31.1.md +142 -0
- package/docs/releases/v0.31.10.md +118 -0
- package/docs/releases/v0.31.11.md +88 -0
- package/docs/releases/v0.31.12.md +105 -0
- package/docs/releases/v0.31.13.md +99 -0
- package/docs/releases/v0.31.14.md +97 -0
- package/docs/releases/v0.31.2.md +115 -0
- package/docs/releases/v0.31.3.md +142 -0
- package/docs/releases/v0.31.4.md +117 -0
- package/docs/releases/v0.31.5.md +155 -0
- package/docs/releases/v0.31.6.md +132 -0
- package/docs/releases/v0.31.7.md +132 -0
- package/docs/releases/v0.31.8.md +120 -0
- package/docs/releases/v0.31.9.md +120 -0
- package/docs/releases/v0.32.0.md +261 -0
- package/docs/releases/v0.32.1.md +59 -0
- package/docs/releases/v0.8.0.md +118 -0
- package/docs/releases/v0.9.0.md +98 -0
- package/docs/releases/v0.9.1.md +83 -0
- package/package.json +102 -6
- package/plugins/mirror-mind/.claude-plugin/plugin.json +13 -0
- package/plugins/mirror-mind/hooks/hooks.json +50 -0
- package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
- package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
- package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
- package/plugins/mirror-mind/hooks/session-start.sh +98 -0
- package/plugins/mirror-mind/mcp/launch.sh +52 -0
- package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
- package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
- package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
- package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
- package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
- package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
- package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
- package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
- package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
- package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
- package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
- package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +65 -0
- package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
- package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
- package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
- package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
- package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
- package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
- package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
- package/scripts/codex-hooks/session-end.sh +85 -0
- package/scripts/codex-hooks/session-start.sh +85 -0
- package/scripts/codex-mirror.sh +48 -0
- package/templates/identity/README.md +119 -0
- package/templates/identity/ego/behavior.yaml +52 -0
- package/templates/identity/ego/constraints.yaml +15 -0
- package/templates/identity/ego/identity.yaml +43 -0
- package/templates/identity/journeys/personal-growth.yaml +39 -0
- package/templates/identity/organization/identity.yaml +24 -0
- package/templates/identity/organization/principles.yaml +17 -0
- package/templates/identity/personas/coach.yaml +94 -0
- package/templates/identity/personas/designer.yaml +93 -0
- package/templates/identity/personas/doctor.yaml +96 -0
- package/templates/identity/personas/engineer.yaml +77 -0
- package/templates/identity/personas/financial.yaml +97 -0
- package/templates/identity/personas/prompt-engineer.yaml +122 -0
- package/templates/identity/personas/researcher.yaml +88 -0
- package/templates/identity/personas/strategist.yaml +91 -0
- package/templates/identity/personas/teacher.yaml +95 -0
- package/templates/identity/personas/therapist.yaml +91 -0
- package/templates/identity/personas/thinker.yaml +74 -0
- package/templates/identity/personas/writer.yaml +76 -0
- package/templates/identity/self/config.yaml +16 -0
- package/templates/identity/self/soul.yaml +105 -0
- package/templates/identity/user/identity.yaml +30 -0
- package/ts/src/backup/staging.ts +62 -0
- package/ts/src/backup/zipBackup.ts +267 -0
- package/ts/src/backup/zipReader.ts +109 -0
- package/ts/src/backup/zipWriter.ts +148 -0
- package/ts/src/builder/activeCheckpoint.ts +134 -0
- package/ts/src/builder/aggregateStatus.ts +34 -0
- package/ts/src/builder/approve.ts +149 -0
- package/ts/src/builder/argv.ts +292 -0
- package/ts/src/builder/ariadMethod.ts +536 -0
- package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
- package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
- package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
- package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
- package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
- package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
- package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
- package/ts/src/builder/artifacts/storyFiles.ts +61 -0
- package/ts/src/builder/artifacts/storyIndex.ts +166 -0
- package/ts/src/builder/cadence.ts +59 -0
- package/ts/src/builder/card.ts +192 -0
- package/ts/src/builder/checkpointRefused.ts +66 -0
- package/ts/src/builder/closure.ts +964 -0
- package/ts/src/builder/commands.ts +2053 -0
- package/ts/src/builder/cursorPosition.ts +176 -0
- package/ts/src/builder/cursorTransitions.ts +77 -0
- package/ts/src/builder/deliveryCursor.ts +577 -0
- package/ts/src/builder/deliveryStoryClosure.ts +521 -0
- package/ts/src/builder/deliveryStoryPlan.ts +536 -0
- package/ts/src/builder/deliveryStoryReady.ts +160 -0
- package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
- package/ts/src/builder/expand.ts +336 -0
- package/ts/src/builder/flowUnit.ts +339 -0
- package/ts/src/builder/homeSurface.ts +122 -0
- package/ts/src/builder/implementationGuard.ts +125 -0
- package/ts/src/builder/index.ts +11 -0
- package/ts/src/builder/lifecycleRefusal.ts +92 -0
- package/ts/src/builder/lifecycleRibbon.ts +159 -0
- package/ts/src/builder/load.ts +313 -0
- package/ts/src/builder/methodAdoption.ts +113 -0
- package/ts/src/builder/methodDefinition.ts +429 -0
- package/ts/src/builder/methodInspection.ts +371 -0
- package/ts/src/builder/plan.ts +408 -0
- package/ts/src/builder/planPreauthorization.ts +265 -0
- package/ts/src/builder/prepare.ts +225 -0
- package/ts/src/builder/projectPaths.ts +64 -0
- package/ts/src/builder/pull.ts +356 -0
- package/ts/src/builder/pullCandidates.ts +463 -0
- package/ts/src/builder/pullCandidatesRender.ts +238 -0
- package/ts/src/builder/refinementField.ts +93 -0
- package/ts/src/builder/releaseIntent.ts +173 -0
- package/ts/src/builder/resumeState.ts +84 -0
- package/ts/src/builder/resumeSurface.ts +149 -0
- package/ts/src/builder/roadmapGrammar.ts +300 -0
- package/ts/src/builder/roadmapScan.ts +97 -0
- package/ts/src/builder/roadmapScope.ts +210 -0
- package/ts/src/builder/scopePhrases.ts +146 -0
- package/ts/src/builder/storyPaths.ts +196 -0
- package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
- package/ts/src/builder/surfaceProtocol.ts +42 -0
- package/ts/src/builder/templateGeneration.ts +148 -0
- package/ts/src/builder/transition.ts +178 -0
- package/ts/src/consult/args.ts +99 -0
- package/ts/src/consult/core.ts +122 -0
- package/ts/src/consult/modelCatalog.ts +55 -0
- package/ts/src/consult/render.ts +47 -0
- package/ts/src/conversation/append.ts +414 -0
- package/ts/src/conversation/backfill.ts +387 -0
- package/ts/src/conversation/closeTail.ts +467 -0
- package/ts/src/conversation/extraction.ts +333 -0
- package/ts/src/conversation/extractionDriver.ts +130 -0
- package/ts/src/conversation/extractionRun.ts +70 -0
- package/ts/src/conversation/journeyInference.ts +165 -0
- package/ts/src/conversation/journeyRepair.ts +114 -0
- package/ts/src/conversation/lifecycleFaces.ts +197 -0
- package/ts/src/conversation/lifecycleWrites.ts +313 -0
- package/ts/src/conversation/listing.ts +77 -0
- package/ts/src/conversation/logger.ts +576 -0
- package/ts/src/conversation/loggerCli.ts +282 -0
- package/ts/src/conversation/loggerRuntime.ts +259 -0
- package/ts/src/conversation/metadataLifecycle.ts +443 -0
- package/ts/src/conversation/recall.ts +66 -0
- package/ts/src/conversation/sessionComposites.ts +258 -0
- package/ts/src/conversation/sessionImport.ts +90 -0
- package/ts/src/conversation/transcriptBackfill.ts +141 -0
- package/ts/src/cultivation/applyActions.ts +241 -0
- package/ts/src/cultivation/cluster.ts +86 -0
- package/ts/src/cultivation/consolidationStore.ts +281 -0
- package/ts/src/cultivation/promptContext.ts +62 -0
- package/ts/src/cultivation/propose.ts +305 -0
- package/ts/src/cultivation/scan.ts +155 -0
- package/ts/src/db/backupGate.ts +47 -0
- package/ts/src/db/bootstrap.ts +108 -0
- package/ts/src/db/bootstrapLock.ts +223 -0
- package/ts/src/db/copyGuard.ts +60 -0
- package/ts/src/db/database.ts +397 -0
- package/ts/src/db/decode.ts +66 -0
- package/ts/src/db/ftsIntegrity.ts +41 -0
- package/ts/src/db/migrateOnOpen.ts +214 -0
- package/ts/src/db/migrations.ts +576 -0
- package/ts/src/db/readyOnOpen.ts +35 -0
- package/ts/src/db/rowDecode.ts +42 -0
- package/ts/src/db/schema.ts +432 -0
- package/ts/src/db/schemaInventory.ts +225 -0
- package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
- package/ts/src/db/schemaState.ts +91 -0
- package/ts/src/db/schemaTsDivergence.ts +114 -0
- package/ts/src/descriptor/descriptorRead.ts +49 -0
- package/ts/src/docs/docsLint.ts +265 -0
- package/ts/src/explorer/handoff.ts +522 -0
- package/ts/src/explorer/render.ts +335 -0
- package/ts/src/explorer/story.ts +769 -0
- package/ts/src/explorer/transition.ts +72 -0
- package/ts/src/extensions/bindings.ts +170 -0
- package/ts/src/extensions/catalog.ts +249 -0
- package/ts/src/extensions/catalogCommands.ts +513 -0
- package/ts/src/extensions/catalogWrites.ts +652 -0
- package/ts/src/extensions/contextRuntime.ts +325 -0
- package/ts/src/extensions/dispatch.ts +374 -0
- package/ts/src/extensions/errors.ts +24 -0
- package/ts/src/extensions/manifest.ts +356 -0
- package/ts/src/extensions/migrations.ts +350 -0
- package/ts/src/extraction/conversation.ts +304 -0
- package/ts/src/extraction/conversationMetadata.ts +206 -0
- package/ts/src/extraction/fencing.ts +106 -0
- package/ts/src/extraction/json.ts +17 -0
- package/ts/src/extraction/prompts.ts +470 -0
- package/ts/src/frontDoor/args.ts +30 -0
- package/ts/src/frontDoor/argvShape.ts +106 -0
- package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
- package/ts/src/frontDoor/buildRoute.ts +398 -0
- package/ts/src/frontDoor/cli.ts +1865 -0
- package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
- package/ts/src/frontDoor/consultRoute.ts +50 -0
- package/ts/src/frontDoor/contentTailRoute.ts +239 -0
- package/ts/src/frontDoor/conversationLoggerRoute.ts +73 -0
- package/ts/src/frontDoor/cultivationRoute.ts +210 -0
- package/ts/src/frontDoor/dbPath.ts +131 -0
- package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
- package/ts/src/frontDoor/exploreRoute.ts +572 -0
- package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
- package/ts/src/frontDoor/frontDoorLog.ts +57 -0
- package/ts/src/frontDoor/identityWrite.ts +36 -0
- package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
- package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
- package/ts/src/frontDoor/liveBackup.ts +100 -0
- package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
- package/ts/src/frontDoor/namedRefusal.ts +35 -0
- package/ts/src/frontDoor/nodeSupport.ts +24 -0
- package/ts/src/frontDoor/render/consolidate.ts +199 -0
- package/ts/src/frontDoor/render/conversations.ts +33 -0
- package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
- package/ts/src/frontDoor/render/descriptor.ts +20 -0
- package/ts/src/frontDoor/render/detectPersona.ts +50 -0
- package/ts/src/frontDoor/render/icons.ts +13 -0
- package/ts/src/frontDoor/render/identity.ts +59 -0
- package/ts/src/frontDoor/render/identityRows.ts +17 -0
- package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
- package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
- package/ts/src/frontDoor/render/journeys.ts +79 -0
- package/ts/src/frontDoor/render/list.ts +41 -0
- package/ts/src/frontDoor/render/memories.ts +67 -0
- package/ts/src/frontDoor/render/recall.ts +49 -0
- package/ts/src/frontDoor/render/shadow.ts +155 -0
- package/ts/src/frontDoor/render/tasks.ts +99 -0
- package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
- package/ts/src/frontDoor/render/week.ts +113 -0
- package/ts/src/frontDoor/routing.ts +999 -0
- package/ts/src/frontDoor/runtimeRoute.ts +623 -0
- package/ts/src/frontDoor/searchRoute.ts +166 -0
- package/ts/src/frontDoor/seedPaths.ts +98 -0
- package/ts/src/frontDoor/soulRoute.ts +433 -0
- package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
- package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
- package/ts/src/frontDoor/usage.ts +176 -0
- package/ts/src/guards/claudePlugin.ts +252 -0
- package/ts/src/guards/packContents.ts +306 -0
- package/ts/src/guards/piSourcedSkills.ts +70 -0
- package/ts/src/guards/retiredRouteShadows.ts +57 -0
- package/ts/src/guards/retiredSurfaces.ts +564 -0
- package/ts/src/hooks/claude.ts +176 -0
- package/ts/src/hooks/codex.ts +45 -0
- package/ts/src/hooks/gemini.ts +126 -0
- package/ts/src/hooks/main.ts +109 -0
- package/ts/src/hooks/mirrorState.ts +71 -0
- package/ts/src/hooks/payload.ts +68 -0
- package/ts/src/hooks/runtime.ts +159 -0
- package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
- package/ts/src/identity/descriptorGenerate.ts +162 -0
- package/ts/src/identity/identityEdit.ts +143 -0
- package/ts/src/identity/identityKey.ts +77 -0
- package/ts/src/identity/identityRead.ts +69 -0
- package/ts/src/identity/identityStore.ts +80 -0
- package/ts/src/identity/journeyListing.ts +53 -0
- package/ts/src/identity/personaInspect.ts +44 -0
- package/ts/src/identity/personaListing.ts +37 -0
- package/ts/src/identity/setIdentity.ts +64 -0
- package/ts/src/index.ts +231 -0
- package/ts/src/init/init.ts +111 -0
- package/ts/src/journey/journeyOptions.ts +131 -0
- package/ts/src/journey/journeyRemoval.ts +158 -0
- package/ts/src/journey/journeyStatus.ts +149 -0
- package/ts/src/journey/journeySyncFile.ts +87 -0
- package/ts/src/journey/journeyWrite.ts +203 -0
- package/ts/src/journey/parentJourney.ts +41 -0
- package/ts/src/journey/validateParentJourney.ts +55 -0
- package/ts/src/mcp/boundary.ts +151 -0
- package/ts/src/mcp/guards.ts +244 -0
- package/ts/src/mcp/main.ts +121 -0
- package/ts/src/mcp/payload.ts +141 -0
- package/ts/src/mcp/protocol.ts +141 -0
- package/ts/src/mcp/readModels.ts +241 -0
- package/ts/src/mcp/registry.ts +201 -0
- package/ts/src/mcp/serve.ts +120 -0
- package/ts/src/mcp/tools/deterministic.ts +137 -0
- package/ts/src/mcp/tools/providerCrossing.ts +187 -0
- package/ts/src/mcp/wire.ts +8 -0
- package/ts/src/memory/journal.ts +180 -0
- package/ts/src/memory/listing.ts +107 -0
- package/ts/src/memory/memoryWrite.ts +88 -0
- package/ts/src/memory/reinforcement.ts +35 -0
- package/ts/src/mirror/context.ts +161 -0
- package/ts/src/mirror/defaultResolution.ts +199 -0
- package/ts/src/mirror/orchestration.ts +364 -0
- package/ts/src/mirror/reception.ts +194 -0
- package/ts/src/mirror/render.ts +75 -0
- package/ts/src/mirror/runtimeSession.ts +205 -0
- package/ts/src/mode/operatingMode.ts +148 -0
- package/ts/src/observability/callOutcome.ts +115 -0
- package/ts/src/observability/inspectLedger.ts +329 -0
- package/ts/src/observability/ledgerHooks.ts +126 -0
- package/ts/src/observability/llmCalls.ts +154 -0
- package/ts/src/persona/detectPersona.ts +81 -0
- package/ts/src/planning/promptAssembly.ts +111 -0
- package/ts/src/planning/weekPending.ts +81 -0
- package/ts/src/planning/weekPlan.ts +183 -0
- package/ts/src/planning/weekSave.ts +117 -0
- package/ts/src/providers/config.ts +189 -0
- package/ts/src/providers/cost.ts +64 -0
- package/ts/src/providers/credits.ts +204 -0
- package/ts/src/providers/embedding.ts +321 -0
- package/ts/src/providers/familyProviders.ts +147 -0
- package/ts/src/providers/llm.ts +334 -0
- package/ts/src/providers/openrouter.ts +244 -0
- package/ts/src/providers/redaction.ts +110 -0
- package/ts/src/providers/replay.ts +15 -0
- package/ts/src/providers/transport.ts +410 -0
- package/ts/src/repair/encodingRepair.ts +253 -0
- package/ts/src/runtime/backup.ts +151 -0
- package/ts/src/runtime/channel.ts +146 -0
- package/ts/src/runtime/config.ts +168 -0
- package/ts/src/runtime/diagnose.ts +686 -0
- package/ts/src/runtime/git.ts +510 -0
- package/ts/src/runtime/installKind.ts +220 -0
- package/ts/src/runtime/migrate.ts +154 -0
- package/ts/src/runtime/packageIdentity.ts +102 -0
- package/ts/src/runtime/releaseNotes.ts +244 -0
- package/ts/src/runtime/status.ts +557 -0
- package/ts/src/runtime/strategies/clone.ts +200 -0
- package/ts/src/runtime/strategies/package.ts +328 -0
- package/ts/src/runtime/treeRoot.ts +30 -0
- package/ts/src/runtime/update.ts +445 -0
- package/ts/src/runtime/updateGate.ts +40 -0
- package/ts/src/runtime/updatePipeline.ts +159 -0
- package/ts/src/runtime/version.ts +36 -0
- package/ts/src/runtime/wiring.ts +130 -0
- package/ts/src/search/memorySearch.ts +338 -0
- package/ts/src/search/ranker.ts +154 -0
- package/ts/src/seed/seed.ts +256 -0
- package/ts/src/seed/seedYaml.ts +133 -0
- package/ts/src/soul/apply.ts +218 -0
- package/ts/src/soul/harvest.ts +267 -0
- package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
- package/ts/src/soul/prompts/soul_self_voice.md +219 -0
- package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
- package/ts/src/soul/prompts.ts +85 -0
- package/ts/src/soul/render.ts +358 -0
- package/ts/src/soul/state.ts +212 -0
- package/ts/src/soul/transition.ts +37 -0
- package/ts/src/tasks/journeyPathParse.ts +113 -0
- package/ts/src/tasks/taskImportSync.ts +142 -0
- package/ts/src/tasks/taskStore.ts +312 -0
- package/ts/src/tasks/weekView.ts +120 -0
- package/ts/src/util/clipCodePoints.ts +26 -0
- package/ts/src/util/paths.ts +63 -0
- package/ts/src/util/program.ts +9 -0
- package/ts/src/util/pyGenerators.ts +144 -0
- package/ts/src/util/pythonText.ts +317 -0
- package/ts/src/util/semver.ts +45 -0
- package/ts/src/util/shellWord.ts +25 -0
- package/ts/src/util/slug.ts +64 -0
- package/ts/src/welcome/card.ts +339 -0
- package/ts/src/welcome/statusLine.ts +101 -0
- package/ts/src/welcome/updateCache.ts +129 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one transport-selection precedence for provider-backed command families
|
|
3
|
+
* (CV22.DS8.US1, generalized by CV22.DS8.US3 / CR077).
|
|
4
|
+
*
|
|
5
|
+
* Sixteen leaves reach a provider. Each one needs the same decision: a
|
|
6
|
+
* deterministic replay fixture for CI and the smokes, or the live provider.
|
|
7
|
+
* Deriving that per leaf is how the US11 defect happened -- `LLM_ROLES` had a
|
|
8
|
+
* type and a hand-maintained guard that drifted apart, and the unit tests
|
|
9
|
+
* still passed. One list, no drift.
|
|
10
|
+
*
|
|
11
|
+
* Until CV22.DS10.TS5 there was a third answer, an operational revert to
|
|
12
|
+
* Python (`<revertVar>=0`), and it outranked everything else. It left with the
|
|
13
|
+
* engine it reverted to (decision D3). A leftover variable is inert, and
|
|
14
|
+
* `runtime diagnose` says so.
|
|
15
|
+
*
|
|
16
|
+
* CR077: a family may need MORE THAN ONE replay fixture (the close tail needs
|
|
17
|
+
* an LLM fixture and an embedding fixture; `mirror load --query` and the
|
|
18
|
+
* cultivation family are the same shape). The spec used to name one variable,
|
|
19
|
+
* so the "both or neither" rule lived privately in `loggerRuntime` -- and the
|
|
20
|
+
* router could report `replay` for an invocation the runtime then refused.
|
|
21
|
+
* The spec now carries the whole rule and `incomplete_replay` is a mode, so
|
|
22
|
+
* routing and the runtime agree by construction.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export type ProviderTransportMode = "replay" | "incomplete_replay" | "live";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Read-only env view. Indexed access is deliberate: families name their
|
|
29
|
+
* variables as data, so a typed per-variable interface would have to be
|
|
30
|
+
* extended for every family US3 flips.
|
|
31
|
+
*/
|
|
32
|
+
export type ProviderTransportEnv = Readonly<Record<string, string | undefined>>;
|
|
33
|
+
|
|
34
|
+
/** The provider kinds a replay fixture can answer for. */
|
|
35
|
+
export type ProviderKind = "llm" | "embedding" | "credits";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Which fixture variable answers for which provider kind.
|
|
39
|
+
*
|
|
40
|
+
* Keyed rather than a bare list because the family provider factory has to
|
|
41
|
+
* know what each fixture IS, not only that it is required. The "all or none"
|
|
42
|
+
* rule derives from the declared set either way.
|
|
43
|
+
*/
|
|
44
|
+
export type ProviderReplaySpec = Partial<Record<ProviderKind, string>>;
|
|
45
|
+
|
|
46
|
+
export interface ProviderTransportSpec {
|
|
47
|
+
/** Replay fixture variables this family needs. All of them, or none. */
|
|
48
|
+
replay?: ProviderReplaySpec;
|
|
49
|
+
/** Reason recorded when the live provider is selected. */
|
|
50
|
+
liveReason?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ProviderTransportDecision {
|
|
54
|
+
mode: ProviderTransportMode;
|
|
55
|
+
/** Route-decision reason, surfaced in the front-door log. Never a payload. */
|
|
56
|
+
reason: string;
|
|
57
|
+
/** Set only in `replay` mode: the fixture path for each declared kind. */
|
|
58
|
+
replayPaths?: Readonly<ProviderReplaySpec>;
|
|
59
|
+
/** Set only in `incomplete_replay`: the fixtures that must also be set. */
|
|
60
|
+
missingReplayVars?: readonly string[];
|
|
61
|
+
/** Set only in `incomplete_replay`: the fixtures that already are. */
|
|
62
|
+
presentReplayVars?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve which transport answers a provider-backed command.
|
|
67
|
+
*
|
|
68
|
+
* Precedence, highest first:
|
|
69
|
+
*
|
|
70
|
+
* 1. **replay** -- every declared fixture variable is set. Deterministic, no
|
|
71
|
+
* network, no spend. This is what CI and the smokes use. It deliberately
|
|
72
|
+
* does not require `MIRROR_TS_EXTERNAL_ROUTES`: that gate was DS5's safety
|
|
73
|
+
* catch while replay was the PRODUCTION route, and after the live cutover
|
|
74
|
+
* replay is a test transport.
|
|
75
|
+
* 2. **incomplete_replay** -- some declared fixtures are set and some are not.
|
|
76
|
+
* Never live: someone who set one variable meant to replay, and running
|
|
77
|
+
* half a fixture would spend real money. The only honest answer names the
|
|
78
|
+
* missing half.
|
|
79
|
+
* 3. **live** -- the DS8 default. An unconfigured install reaches the provider
|
|
80
|
+
* through TypeScript.
|
|
81
|
+
*
|
|
82
|
+
* An exported-but-empty fixture variable is treated as absent, because that
|
|
83
|
+
* shell accident should not become a file-not-found later.
|
|
84
|
+
*/
|
|
85
|
+
export function resolveProviderTransport(
|
|
86
|
+
env: ProviderTransportEnv,
|
|
87
|
+
spec: ProviderTransportSpec,
|
|
88
|
+
): ProviderTransportDecision {
|
|
89
|
+
const declared = declaredReplayVars(spec);
|
|
90
|
+
const present = declared.filter(([, variable]) => Boolean(env[variable]));
|
|
91
|
+
|
|
92
|
+
if (declared.length > 0 && present.length === declared.length) {
|
|
93
|
+
const replayPaths: ProviderReplaySpec = {};
|
|
94
|
+
for (const [kind, variable] of declared) replayPaths[kind] = env[variable];
|
|
95
|
+
return {
|
|
96
|
+
mode: "replay",
|
|
97
|
+
reason: `${declared.map(([, variable]) => variable).join(" + ")} replay transport`,
|
|
98
|
+
replayPaths,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (present.length > 0) {
|
|
103
|
+
const missingReplayVars = declared
|
|
104
|
+
.filter(([, variable]) => !env[variable])
|
|
105
|
+
.map(([, variable]) => variable);
|
|
106
|
+
const presentReplayVars = present.map(([, variable]) => variable);
|
|
107
|
+
return {
|
|
108
|
+
mode: "incomplete_replay",
|
|
109
|
+
reason:
|
|
110
|
+
`incomplete replay fixture: ${presentReplayVars.join(", ")} set, ` +
|
|
111
|
+
`${missingReplayVars.join(", ")} missing`,
|
|
112
|
+
missingReplayVars,
|
|
113
|
+
presentReplayVars,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { mode: "live", reason: spec.liveReason ?? "live provider" };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The declared fixture variables, in a stable kind order for stable reasons. */
|
|
121
|
+
function declaredReplayVars(spec: ProviderTransportSpec): [ProviderKind, string][] {
|
|
122
|
+
const order: ProviderKind[] = ["llm", "embedding", "credits"];
|
|
123
|
+
return order
|
|
124
|
+
.filter((kind) => Boolean(spec.replay?.[kind]))
|
|
125
|
+
.map((kind) => [kind, spec.replay?.[kind] as string]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A command whose provider work belongs to families it does not own
|
|
130
|
+
* (CV22.DS7.US8 item 18b).
|
|
131
|
+
*
|
|
132
|
+
* `build load` is the case that forced this. It owns no provider seam: its two
|
|
133
|
+
* embeddings ARE the search family, and the previous conversation's close tail
|
|
134
|
+
* IS the conversation-tail family -- both already live in production since DS8.
|
|
135
|
+
* Its fixtures are the owner's; the composed families only say whether replay
|
|
136
|
+
* was intended somewhere, so a half-configured harness refuses instead of
|
|
137
|
+
* reaching the live provider through fixtures nobody set.
|
|
138
|
+
*/
|
|
139
|
+
export interface ComposedProviderTransportSpec {
|
|
140
|
+
/** Named in every composed reason, so the log says which command composed. */
|
|
141
|
+
readonly label: string;
|
|
142
|
+
/** The family whose fixtures the command's providers are actually built from. */
|
|
143
|
+
readonly owner: ProviderTransportSpec;
|
|
144
|
+
/**
|
|
145
|
+
* Families whose work this command performs. Consulted for replay intent --
|
|
146
|
+
* never for fixtures, because a composing command runs every seam off the
|
|
147
|
+
* owner's.
|
|
148
|
+
*/
|
|
149
|
+
readonly composes: readonly ProviderTransportSpec[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Resolve one transport decision for a command that composes several families.
|
|
154
|
+
*
|
|
155
|
+
* Precedence, extending `resolveProviderTransport` rather than replacing it:
|
|
156
|
+
*
|
|
157
|
+
* 1. **any incomplete fixture refuses** -- including a composed family's. Its
|
|
158
|
+
* own pair rule cannot be honoured by a runtime that never sees it.
|
|
159
|
+
* 2. **replay intent anywhere requires the OWNER's complete fixture set.** A
|
|
160
|
+
* harness that configured the search family for replay and then ran `build
|
|
161
|
+
* load` would reach the live provider through fixtures nobody set -- a
|
|
162
|
+
* silent charge -- so the only honest answer names the fixtures missing
|
|
163
|
+
* here.
|
|
164
|
+
* 3. otherwise the owner's decision stands, unchanged.
|
|
165
|
+
*
|
|
166
|
+
* (A fourth rule, "any revert wins", sat on top until CV22.DS10.TS5 deleted
|
|
167
|
+
* the reverts with the engine they reverted to.)
|
|
168
|
+
*
|
|
169
|
+
* With an empty `composes` the result is byte-identical to the single-family
|
|
170
|
+
* decision: the composition is data, not a second precedence to drift from.
|
|
171
|
+
*/
|
|
172
|
+
export function resolveComposedProviderTransport(
|
|
173
|
+
env: ProviderTransportEnv,
|
|
174
|
+
spec: ComposedProviderTransportSpec,
|
|
175
|
+
): ProviderTransportDecision {
|
|
176
|
+
const owner = resolveProviderTransport(env, spec.owner);
|
|
177
|
+
const composed = spec.composes.map((family) => resolveProviderTransport(env, family));
|
|
178
|
+
|
|
179
|
+
if (owner.mode === "incomplete_replay") return owner;
|
|
180
|
+
const incomplete = composed.find((decision) => decision.mode === "incomplete_replay");
|
|
181
|
+
if (incomplete) return composedReason(incomplete, spec.label);
|
|
182
|
+
|
|
183
|
+
const replaying = spec.composes.filter((_, index) => composed[index]?.mode === "replay");
|
|
184
|
+
if (owner.mode === "live" && replaying.length > 0) {
|
|
185
|
+
const missingReplayVars = declaredReplayVars(spec.owner).map(([, variable]) => variable);
|
|
186
|
+
// A composition whose owner declares no fixture has nothing to name, and
|
|
187
|
+
// nothing of its own to replay either: the owner's decision stands.
|
|
188
|
+
if (missingReplayVars.length > 0) {
|
|
189
|
+
const presentReplayVars = replaying.flatMap((family) =>
|
|
190
|
+
declaredReplayVars(family)
|
|
191
|
+
.map(([, variable]) => variable)
|
|
192
|
+
.filter((variable) => Boolean(env[variable])),
|
|
193
|
+
);
|
|
194
|
+
return composedReason(
|
|
195
|
+
{
|
|
196
|
+
mode: "incomplete_replay",
|
|
197
|
+
reason:
|
|
198
|
+
`incomplete replay fixture: ${presentReplayVars.join(", ")} set, ` +
|
|
199
|
+
`${missingReplayVars.join(", ")} missing`,
|
|
200
|
+
missingReplayVars,
|
|
201
|
+
presentReplayVars,
|
|
202
|
+
},
|
|
203
|
+
spec.label,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return owner;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Same decision, with the composing command named for the front-door log. */
|
|
212
|
+
function composedReason(
|
|
213
|
+
decision: ProviderTransportDecision,
|
|
214
|
+
label: string,
|
|
215
|
+
): ProviderTransportDecision {
|
|
216
|
+
return { ...decision, reason: `${decision.reason} (composed by ${label})` };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Exactly one half of a multi-fixture family's replay configuration is set.
|
|
221
|
+
*
|
|
222
|
+
* Someone who set one variable meant to replay, so the only honest answer is
|
|
223
|
+
* to stop and name the missing half. (Until CV22.DS10.TS5 a PLAIN family sent
|
|
224
|
+
* this case to the Python fallback, which has no replay transport and would
|
|
225
|
+
* have called the live provider; only compositions refused. With the fallback
|
|
226
|
+
* gone every family refuses.)
|
|
227
|
+
*
|
|
228
|
+
* Lived in `loggerRuntime` until CR077; it is the whole family rule's error,
|
|
229
|
+
* so it belongs beside the rule.
|
|
230
|
+
*/
|
|
231
|
+
export class ReplayFixtureIncompleteError extends Error {
|
|
232
|
+
constructor(decision: ProviderTransportDecision) {
|
|
233
|
+
const missing = (decision.missingReplayVars ?? []).join(", ");
|
|
234
|
+
const present = (decision.presentReplayVars ?? []).join(", ");
|
|
235
|
+
super(
|
|
236
|
+
`${present} is set but ${missing} is not. This command needs EVERY replay ` +
|
|
237
|
+
"fixture its family declares; running with part of one would reach the live " +
|
|
238
|
+
`provider and spend real money. Set ${missing}, or unset ${present} to run live ` +
|
|
239
|
+
"deliberately.",
|
|
240
|
+
);
|
|
241
|
+
this.name = "ReplayFixtureIncompleteError";
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// --- Family transport specs ------------------------------------------------
|
|
246
|
+
//
|
|
247
|
+
// Each provider-backed family names its variables here, in one place, rather
|
|
248
|
+
// than in the route that happens to consume them: `routing.ts` decides the
|
|
249
|
+
// route and the provider factory builds the providers, and both must read the
|
|
250
|
+
// same spec or they can disagree about which transport is live.
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Fresh semantic search (CV22.DS8.US1).
|
|
254
|
+
*
|
|
255
|
+
* `MIRROR_TS_EXTERNAL_ROUTES` is deliberately absent: it was DS5's safety gate
|
|
256
|
+
* while replay was the PRODUCTION route for this leaf, and after the live
|
|
257
|
+
* cutover replay is a test transport.
|
|
258
|
+
*/
|
|
259
|
+
export const SEARCH_TRANSPORT: ProviderTransportSpec = {
|
|
260
|
+
replay: { embedding: "MIRROR_TS_SEARCH_EMBEDDING_REPLAY" },
|
|
261
|
+
liveReason: "DS8.US1 fresh semantic search live",
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* The conversation close tail (CV22.DS8.US2): title, tags, summary, memory and
|
|
266
|
+
* task extraction, and their embeddings.
|
|
267
|
+
*
|
|
268
|
+
* Two fixtures back this family, not one -- the pair rule that motivated
|
|
269
|
+
* CR077. It now lives in the spec, so the router cannot report `replay` for an
|
|
270
|
+
* invocation the runtime refuses.
|
|
271
|
+
*/
|
|
272
|
+
export const CONVERSATION_TAIL_TRANSPORT: ProviderTransportSpec = {
|
|
273
|
+
replay: {
|
|
274
|
+
llm: "MIRROR_TS_CONVERSATION_LLM_REPLAY",
|
|
275
|
+
embedding: "MIRROR_TS_CONVERSATION_EMBEDDING_REPLAY",
|
|
276
|
+
},
|
|
277
|
+
liveReason: "DS8.US2 conversation close tail live",
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* `soul harvest save` (CV22.DS8.US3) -- the one leaf of the Soul command that
|
|
282
|
+
* crosses the provider seam, and only through the embedding: the save supplies
|
|
283
|
+
* title, layer, and tags, so the journal classifier is unreachable.
|
|
284
|
+
*/
|
|
285
|
+
export const SOUL_HARVEST_TRANSPORT: ProviderTransportSpec = {
|
|
286
|
+
replay: { embedding: "MIRROR_TS_SOUL_EMBEDDING_REPLAY" },
|
|
287
|
+
liveReason: "DS8.US3 soul harvest save live",
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* `consult credits` and `consult ask` (CV22.DS8.US3).
|
|
292
|
+
*
|
|
293
|
+
* TWO specs for one family, because the fixtures are genuinely per leaf:
|
|
294
|
+
* `credits` needs only the credits fixture, while `ask` needs the chat fixture
|
|
295
|
+
* AND the credits one (it fetches the call's real cost, then prints the
|
|
296
|
+
* balance). With the credits fixture alone, `credits` replays and `ask`
|
|
297
|
+
* refuses -- it must not go live for the half nobody configured.
|
|
298
|
+
*/
|
|
299
|
+
export const CONSULT_CREDITS_TRANSPORT: ProviderTransportSpec = {
|
|
300
|
+
replay: { credits: "MIRROR_TS_CREDITS_REPLAY" },
|
|
301
|
+
liveReason: "DS8.US3 consult credits live",
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export const CONSULT_ASK_TRANSPORT: ProviderTransportSpec = {
|
|
305
|
+
replay: { llm: "MIRROR_TS_CONSULT_LLM_REPLAY", credits: "MIRROR_TS_CREDITS_REPLAY" },
|
|
306
|
+
liveReason: "DS8.US3 consult ask live",
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* `mirror load --query` (CV22.DS8.US3): the reception classifier plus the
|
|
311
|
+
* query's own embedding for attachment and journey search.
|
|
312
|
+
*
|
|
313
|
+
* `MEMORY_RECEPTION=0` skips the classifier; the embedding half stays, which is
|
|
314
|
+
* why both fixtures are declared.
|
|
315
|
+
*/
|
|
316
|
+
export const MIRROR_QUERY_TRANSPORT: ProviderTransportSpec = {
|
|
317
|
+
replay: {
|
|
318
|
+
llm: "MIRROR_TS_MIRROR_LLM_REPLAY",
|
|
319
|
+
embedding: "MIRROR_TS_MIRROR_EMBEDDING_REPLAY",
|
|
320
|
+
},
|
|
321
|
+
liveReason: "DS8.US3 mirror load --query live",
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* `consolidate scan` and `shadow scan` -- the two cultivation leaves that send
|
|
326
|
+
* a PROMPT. Everything around the call landed in CV22.DS8.US3; the flip
|
|
327
|
+
* itself waited for CV22.DS8.TS2, because until then TypeScript sent a fenced
|
|
328
|
+
* Markdown dump of the memories with no task statement and no JSON output
|
|
329
|
+
* contract -- invisible under replay, which answers by role and never reads
|
|
330
|
+
* the prompt. The real templates now travel with the call and their assembled
|
|
331
|
+
* bytes are digest-pinned against the Python oracle (`cultivation/propose.ts`).
|
|
332
|
+
*/
|
|
333
|
+
export const CULTIVATION_SCAN_TRANSPORT: ProviderTransportSpec = {
|
|
334
|
+
replay: { llm: "MIRROR_TS_CULTIVATION_LLM_REPLAY" },
|
|
335
|
+
liveReason: "DS8.TS2 cultivation scan live",
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* `consolidate apply` (CV22.DS8.US3).
|
|
340
|
+
*
|
|
341
|
+
* A SEPARATE spec, and not blocked by TS2: apply sends no prompt at all. A
|
|
342
|
+
* `merge` embeds the merged content and an `identity_update` makes no provider
|
|
343
|
+
* call whatsoever, so the only fixture it can need is the embedding one. The
|
|
344
|
+
* plan and the burn-down ledger both said "the three cultivation leaves wait
|
|
345
|
+
* for TS2"; measured, it is two.
|
|
346
|
+
*/
|
|
347
|
+
export const CULTIVATION_APPLY_TRANSPORT: ProviderTransportSpec = {
|
|
348
|
+
replay: { embedding: "MIRROR_TS_CULTIVATION_EMBEDDING_REPLAY" },
|
|
349
|
+
liveReason: "DS8.US3 consolidate apply live",
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/** `journal` (CV22.DS8.US3): classify the entry, then embed the memory. */
|
|
353
|
+
export const JOURNAL_TRANSPORT: ProviderTransportSpec = {
|
|
354
|
+
replay: {
|
|
355
|
+
llm: "MIRROR_TS_JOURNAL_LLM_REPLAY",
|
|
356
|
+
embedding: "MIRROR_TS_JOURNAL_EMBEDDING_REPLAY",
|
|
357
|
+
},
|
|
358
|
+
liveReason: "DS8.US3 journal live",
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
/** `week plan` (CV22.DS8.US3). `week save` and `week view` make no provider call. */
|
|
362
|
+
export const WEEK_PLAN_TRANSPORT: ProviderTransportSpec = {
|
|
363
|
+
replay: { llm: "MIRROR_TS_WEEK_LLM_REPLAY" },
|
|
364
|
+
liveReason: "DS8.US3 week plan live",
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* `descriptor generate` (CV22.DS8.US3). One call per persona AND per journey
|
|
369
|
+
* when no `--layer/--key` narrows it, so the front-door log records `calls=N`.
|
|
370
|
+
*/
|
|
371
|
+
export const DESCRIPTOR_TRANSPORT: ProviderTransportSpec = {
|
|
372
|
+
replay: { llm: "MIRROR_TS_DESCRIPTOR_LLM_REPLAY" },
|
|
373
|
+
liveReason: "DS8.US3 descriptor generate live",
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* `build load` (CV22.DS7.US8) -- the one leaf of the 27 that crosses the
|
|
378
|
+
* provider seam, and the only family here that owns no seam of its own.
|
|
379
|
+
*
|
|
380
|
+
* Two fixtures, because `load` reaches the model twice over: the embedding for
|
|
381
|
+
* its two searches (scoped and global, the same query), and the LLM plus
|
|
382
|
+
* embedding of the previous conversation's close tail, which `switchConversation`
|
|
383
|
+
* runs on the way in. Every seam inside the command is built from THESE
|
|
384
|
+
* variables, which is why an incomplete set here refuses even when another
|
|
385
|
+
* family's fixtures are present.
|
|
386
|
+
*/
|
|
387
|
+
export const BUILD_LOAD_TRANSPORT: ProviderTransportSpec = {
|
|
388
|
+
replay: {
|
|
389
|
+
llm: "MIRROR_TS_BUILD_LLM_REPLAY",
|
|
390
|
+
embedding: "MIRROR_TS_BUILD_EMBEDDING_REPLAY",
|
|
391
|
+
},
|
|
392
|
+
liveReason: "DS7.US8 build load live",
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* The three specs `build load` resolves BEFORE it prints a byte (item 18b).
|
|
397
|
+
*
|
|
398
|
+
* Four surfaces -- transition card, entry surface, identity context, and the
|
|
399
|
+
* banner on stderr -- print ahead of the first provider call, so a refusal
|
|
400
|
+
* decided later would come after all of them in the Navigator's terminal.
|
|
401
|
+
*
|
|
402
|
+
* The composed pair is what makes a half-configured harness refuse: replay
|
|
403
|
+
* intent on the search or conversation-tail family requires this command's
|
|
404
|
+
* own fixtures, rather than reaching the live provider through ones nobody set.
|
|
405
|
+
*/
|
|
406
|
+
export const BUILD_LOAD_COMPOSITION: ComposedProviderTransportSpec = {
|
|
407
|
+
label: "build load",
|
|
408
|
+
owner: BUILD_LOAD_TRANSPORT,
|
|
409
|
+
composes: [SEARCH_TRANSPORT, CONVERSATION_TAIL_TRANSPORT],
|
|
410
|
+
};
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// Reversible UTF-8/Windows mojibake repair for Mirror user text.
|
|
2
|
+
//
|
|
3
|
+
// Port of `src/memory/cli/repair_encoding.py` (CV22.DS7.TS1). Older
|
|
4
|
+
// Windows/local-runtime combinations stored UTF-8 text after decoding it as a
|
|
5
|
+
// legacy code page, producing "é" where "é" was meant. The repair only touches
|
|
6
|
+
// two-code-point sequences that round-trip cleanly: re-encode through Latin-1
|
|
7
|
+
// (first pass) or Windows-1252 (second pass), then decode strictly as UTF-8;
|
|
8
|
+
// anything that fails either step is left exactly as it was. Legitimate text
|
|
9
|
+
// such as "Âncora" therefore survives, which is the whole safety argument.
|
|
10
|
+
//
|
|
11
|
+
// Parity notes, each pinned by the golden:
|
|
12
|
+
// - `.` matches one CODE POINT (`u` + `s` flags), never a UTF-16 unit.
|
|
13
|
+
// - Python's `bytes.decode("utf-8")` is strict; so is a fatal TextDecoder.
|
|
14
|
+
// - Windows-1252 has five undefined bytes and a repertoire outside Latin-1;
|
|
15
|
+
// a code point it cannot encode makes the pass leave the chunk unchanged,
|
|
16
|
+
// exactly like Python's UnicodeEncodeError branch.
|
|
17
|
+
// - The preview collapses whitespace with Python's `str.split()` set, which
|
|
18
|
+
// is not JavaScript's `\s`, and caps by code point, not `.length`.
|
|
19
|
+
|
|
20
|
+
import { type Database, type WritableDatabase, withTransaction } from "#db/database.ts";
|
|
21
|
+
import { pythonWhitespaceRegex } from "#util/pythonText.ts";
|
|
22
|
+
|
|
23
|
+
/** One repairable cell: where it is, what it holds, what it becomes. */
|
|
24
|
+
export interface RepairHit {
|
|
25
|
+
table: string;
|
|
26
|
+
column: string;
|
|
27
|
+
row_id: number;
|
|
28
|
+
before: string;
|
|
29
|
+
after: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// UTF-8 bytes decoded as Latin-1: "é", "ç", "ã", "º", ...
|
|
33
|
+
const LATIN1_UTF8_PAIR = /[\u00c2-\u00c3][\u0080-\u00bf]/gu;
|
|
34
|
+
// UTF-8 bytes decoded as Windows-1252: "Ó", "É", ... (any following code point).
|
|
35
|
+
const CP1252_UTF8_PAIR = /[\u00c2-\u00c3]./gsu;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* User-text columns that can be scanned without touching arbitrary extension
|
|
39
|
+
* tables. Missing tables/columns are ignored for older database versions.
|
|
40
|
+
* Order matters: it is the oracle's scan order, hence the hit order.
|
|
41
|
+
*/
|
|
42
|
+
const TEXT_TARGETS: readonly (readonly [string, readonly string[]])[] = [
|
|
43
|
+
["identity", ["content"]],
|
|
44
|
+
["attachments", ["content"]],
|
|
45
|
+
["memories", ["content", "summary", "source", "journey", "layer"]],
|
|
46
|
+
["messages", ["content"]],
|
|
47
|
+
["conversations", ["title", "summary", "journey", "persona"]],
|
|
48
|
+
["memory_access_log", ["access_context"]],
|
|
49
|
+
["tasks", ["title", "description", "journey", "status", "notes"]],
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Windows-1252 code points for bytes 0x80–0x9F. `undefined` marks the five
|
|
54
|
+
* bytes (0x81, 0x8D, 0x8F, 0x90, 0x9D) the code page leaves unassigned;
|
|
55
|
+
* every other byte maps to itself (0x00–0x7F, 0xA0–0xFF), as in Latin-1.
|
|
56
|
+
*/
|
|
57
|
+
const CP1252_HIGH_BLOCK: readonly (number | undefined)[] = [
|
|
58
|
+
0x20ac,
|
|
59
|
+
undefined,
|
|
60
|
+
0x201a,
|
|
61
|
+
0x0192,
|
|
62
|
+
0x201e,
|
|
63
|
+
0x2026,
|
|
64
|
+
0x2020,
|
|
65
|
+
0x2021,
|
|
66
|
+
0x02c6,
|
|
67
|
+
0x2030,
|
|
68
|
+
0x0160,
|
|
69
|
+
0x2039,
|
|
70
|
+
0x0152,
|
|
71
|
+
undefined,
|
|
72
|
+
0x017d,
|
|
73
|
+
undefined,
|
|
74
|
+
undefined,
|
|
75
|
+
0x2018,
|
|
76
|
+
0x2019,
|
|
77
|
+
0x201c,
|
|
78
|
+
0x201d,
|
|
79
|
+
0x2022,
|
|
80
|
+
0x2013,
|
|
81
|
+
0x2014,
|
|
82
|
+
0x02dc,
|
|
83
|
+
0x2122,
|
|
84
|
+
0x0161,
|
|
85
|
+
0x203a,
|
|
86
|
+
0x0153,
|
|
87
|
+
undefined,
|
|
88
|
+
0x017e,
|
|
89
|
+
0x0178,
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const CP1252_BYTE_FOR_CODE_POINT: ReadonlyMap<number, number> = new Map(
|
|
93
|
+
CP1252_HIGH_BLOCK.flatMap((codePoint, offset) =>
|
|
94
|
+
codePoint === undefined ? [] : [[codePoint, 0x80 + offset] as const],
|
|
95
|
+
),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const STRICT_UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
99
|
+
|
|
100
|
+
/** Encode one code point as Latin-1, or `null` when it does not fit. */
|
|
101
|
+
function latin1Byte(codePoint: number): number | null {
|
|
102
|
+
return codePoint <= 0xff ? codePoint : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Encode one code point as Windows-1252, or `null` when the code page lacks it. */
|
|
106
|
+
function cp1252Byte(codePoint: number): number | null {
|
|
107
|
+
if (codePoint < 0x80 || (codePoint >= 0xa0 && codePoint <= 0xff)) return codePoint;
|
|
108
|
+
return CP1252_BYTE_FOR_CODE_POINT.get(codePoint) ?? null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Re-encode `chunk` byte-per-code-point through `encodeByte` and decode the
|
|
113
|
+
* result strictly as UTF-8. Returns the chunk unchanged when either step
|
|
114
|
+
* fails — the same "leave it alone" contract as Python's `_decode_pair`.
|
|
115
|
+
*/
|
|
116
|
+
function decodePair(chunk: string, encodeByte: (codePoint: number) => number | null): string {
|
|
117
|
+
const bytes: number[] = [];
|
|
118
|
+
for (const char of chunk) {
|
|
119
|
+
const byte = encodeByte(char.codePointAt(0) as number);
|
|
120
|
+
if (byte === null) return chunk;
|
|
121
|
+
bytes.push(byte);
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
return STRICT_UTF8.decode(Uint8Array.from(bytes));
|
|
125
|
+
} catch {
|
|
126
|
+
return chunk;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Return `text` with reversible mojibake repaired. Only two-code-point
|
|
132
|
+
* sequences that decode as UTF-8 after re-encoding through Latin-1 or
|
|
133
|
+
* Windows-1252 change; everything else — including legitimate Portuguese like
|
|
134
|
+
* "Âncora" — stays as it is.
|
|
135
|
+
*/
|
|
136
|
+
export function repairText(text: string): string {
|
|
137
|
+
const latin1Pass = text.replace(LATIN1_UTF8_PAIR, (chunk) => decodePair(chunk, latin1Byte));
|
|
138
|
+
return latin1Pass.replace(CP1252_UTF8_PAIR, (chunk) => decodePair(chunk, cp1252Byte));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function hasRepairableMojibake(text: string): boolean {
|
|
142
|
+
return repairText(text) !== text;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Python's `str.isspace()` set — what `str.split()` with no separator splits
|
|
147
|
+
* on. Differs from JavaScript `\s`: it includes U+001C–U+001F and excludes
|
|
148
|
+
* U+FEFF. Shared with the extension migration checksum, which depends on the
|
|
149
|
+
* same distinction (CV22.DS7.TS3).
|
|
150
|
+
*/
|
|
151
|
+
const PYTHON_WHITESPACE = pythonWhitespaceRegex();
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Port of `_preview`: collapse whitespace runs to single spaces, trim, and cap
|
|
155
|
+
* at `limit` code points with a trailing ellipsis.
|
|
156
|
+
*/
|
|
157
|
+
export function previewText(text: string, limit = 80): string {
|
|
158
|
+
const compact = text
|
|
159
|
+
.split(PYTHON_WHITESPACE)
|
|
160
|
+
.filter((part) => part !== "")
|
|
161
|
+
.join(" ");
|
|
162
|
+
const codePoints = Array.from(compact);
|
|
163
|
+
if (codePoints.length > limit) {
|
|
164
|
+
return `${codePoints.slice(0, limit - 1).join("")}…`;
|
|
165
|
+
}
|
|
166
|
+
return compact;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function existingColumns(db: Database, table: string): Set<string> {
|
|
170
|
+
try {
|
|
171
|
+
return new Set(
|
|
172
|
+
db
|
|
173
|
+
.prepare(`PRAGMA table_info("${table}")`)
|
|
174
|
+
.all()
|
|
175
|
+
.map((row) => String(row.name)),
|
|
176
|
+
);
|
|
177
|
+
} catch {
|
|
178
|
+
return new Set();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function scanTable(db: Database, table: string, columns: readonly string[]): RepairHit[] {
|
|
183
|
+
const existing = existingColumns(db, table);
|
|
184
|
+
const selected = columns.filter((column) => existing.has(column));
|
|
185
|
+
if (selected.length === 0) return [];
|
|
186
|
+
|
|
187
|
+
const quoted = selected.map((column) => `"${column}"`).join(", ");
|
|
188
|
+
let rows: Record<string, unknown>[];
|
|
189
|
+
try {
|
|
190
|
+
// Same statement as the oracle, deliberately without ORDER BY: same
|
|
191
|
+
// engine, same plan, same rowid order. The golden pins it.
|
|
192
|
+
rows = db.prepare(`SELECT _rowid_ AS __rowid__, ${quoted} FROM "${table}"`).all();
|
|
193
|
+
} catch {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const hits: RepairHit[] = [];
|
|
198
|
+
for (const row of rows) {
|
|
199
|
+
const rowId = Number(row.__rowid__);
|
|
200
|
+
for (const column of selected) {
|
|
201
|
+
const value = row[column];
|
|
202
|
+
if (typeof value !== "string") continue;
|
|
203
|
+
const fixed = repairText(value);
|
|
204
|
+
if (fixed !== value) {
|
|
205
|
+
hits.push({ table, column, row_id: rowId, before: value, after: fixed });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return hits;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Scan every target table/column and return the ordered list of repairable cells. */
|
|
213
|
+
export function scanDatabase(db: Database): RepairHit[] {
|
|
214
|
+
return TEXT_TARGETS.flatMap(([table, columns]) => scanTable(db, table, columns));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Apply every hit by `_rowid_` in one transaction; returns the count applied. */
|
|
218
|
+
export function applyRepairs(db: WritableDatabase, hits: readonly RepairHit[]): number {
|
|
219
|
+
return withTransaction(db, () => {
|
|
220
|
+
for (const hit of hits) {
|
|
221
|
+
db.prepare(`UPDATE "${hit.table}" SET "${hit.column}" = ? WHERE _rowid_ = ?`).run(
|
|
222
|
+
hit.after,
|
|
223
|
+
hit.row_id,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return hits.length;
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface ScanReportOptions {
|
|
231
|
+
dbPath: string;
|
|
232
|
+
hits: readonly RepairHit[];
|
|
233
|
+
/** Maximum preview rows; negative values behave as zero, like `max(limit, 0)`. */
|
|
234
|
+
limit: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Render the scan section of the report exactly as the oracle prints it. */
|
|
238
|
+
export function renderScanReport({ dbPath, hits, limit }: ScanReportOptions): string {
|
|
239
|
+
const shown = Math.max(limit, 0);
|
|
240
|
+
const lines = [`Database: ${dbPath}`, `Repairable mojibake hits: ${hits.length}`];
|
|
241
|
+
for (const hit of hits.slice(0, shown)) {
|
|
242
|
+
lines.push(
|
|
243
|
+
`- ${hit.table}.${hit.column} row=${hit.row_id}: ${previewText(hit.before)} -> ${previewText(hit.after)}`,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
if (hits.length > shown) lines.push(`… ${hits.length - shown} more`);
|
|
247
|
+
return `${lines.join("\n")}\n`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Render the trailing line of a successful `--apply`. */
|
|
251
|
+
export function renderApplyReport(applied: number): string {
|
|
252
|
+
return `Applied repairs: ${applied}\n`;
|
|
253
|
+
}
|