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,88 @@
|
|
|
1
|
+
// Shared `memories` row writer + minimal read, extracted so extraction
|
|
2
|
+
// (CV22.DS5) and cultivation's `merge` action (CV22.DS7.US3) do not each grow
|
|
3
|
+
// their own copy of the same INSERT (DRY: the original write path lived only
|
|
4
|
+
// in `conversation/extraction.ts`; cultivation needed the identical shape for
|
|
5
|
+
// a merged memory, so the primitive moved here, one level below both callers,
|
|
6
|
+
// and extraction now calls through it unchanged).
|
|
7
|
+
|
|
8
|
+
import type { Database, SqlValue, WritableDatabase } from "#db/database.ts";
|
|
9
|
+
import { optionalString, requireString } from "#db/rowDecode.ts";
|
|
10
|
+
|
|
11
|
+
/** Every writable column of a `memories` row except `last_accessed_at`
|
|
12
|
+
* (never set on insert -- it starts NULL, same as Python's `Memory` default). */
|
|
13
|
+
export interface MemoryRowInput {
|
|
14
|
+
id: string;
|
|
15
|
+
conversationId?: string | null;
|
|
16
|
+
memoryType: string;
|
|
17
|
+
layer: string;
|
|
18
|
+
title: string;
|
|
19
|
+
content: string;
|
|
20
|
+
context?: string | null;
|
|
21
|
+
journey?: string | null;
|
|
22
|
+
persona?: string | null;
|
|
23
|
+
tags?: string | null;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
relevanceScore?: number;
|
|
26
|
+
embedding: Uint8Array;
|
|
27
|
+
metadata?: string | null;
|
|
28
|
+
useCount?: number;
|
|
29
|
+
readinessState?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const MEMORY_COLUMNS =
|
|
33
|
+
"id, conversation_id, memory_type, layer, title, content, context, journey, persona, tags, " +
|
|
34
|
+
"created_at, relevance_score, embedding, metadata, use_count, readiness_state";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Insert one `memories` row. Mirrors both `insert_memory`-shaped writers in
|
|
38
|
+
* the Python core: `ConversationExtraction`'s per-memory insert and
|
|
39
|
+
* `consolidate_cmd.cmd_apply`'s `merge` action -- same 16 columns, same
|
|
40
|
+
* defaults (`relevance_score` 1.0, `use_count` 0, `readiness_state`
|
|
41
|
+
* `'observed'`), `last_accessed_at` always starts NULL (omitted, not a
|
|
42
|
+
* writable column here).
|
|
43
|
+
*/
|
|
44
|
+
export function createMemoryRow(db: WritableDatabase, input: MemoryRowInput): void {
|
|
45
|
+
const params: SqlValue[] = [
|
|
46
|
+
input.id,
|
|
47
|
+
input.conversationId ?? null,
|
|
48
|
+
input.memoryType,
|
|
49
|
+
input.layer,
|
|
50
|
+
input.title,
|
|
51
|
+
input.content,
|
|
52
|
+
input.context ?? null,
|
|
53
|
+
input.journey ?? null,
|
|
54
|
+
input.persona ?? null,
|
|
55
|
+
input.tags ?? null,
|
|
56
|
+
input.createdAt,
|
|
57
|
+
input.relevanceScore ?? 1.0,
|
|
58
|
+
input.embedding,
|
|
59
|
+
input.metadata ?? null,
|
|
60
|
+
input.useCount ?? 0,
|
|
61
|
+
input.readinessState ?? "observed",
|
|
62
|
+
];
|
|
63
|
+
db.prepare(
|
|
64
|
+
`INSERT INTO memories (${MEMORY_COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
65
|
+
).run(...params);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The projection `consolidate apply`'s `merge` action needs from the first source memory. */
|
|
69
|
+
export interface MergeSourceMemory {
|
|
70
|
+
memory_type: string;
|
|
71
|
+
layer: string;
|
|
72
|
+
title: string;
|
|
73
|
+
journey: string | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Port of the fields `cmd_apply`'s merge branch reads via `Store.get_memory`. */
|
|
77
|
+
export function getMemorySourceForMerge(db: Database, id: string): MergeSourceMemory | null {
|
|
78
|
+
const row = db
|
|
79
|
+
.prepare("SELECT memory_type, layer, title, journey FROM memories WHERE id = ?")
|
|
80
|
+
.get(id);
|
|
81
|
+
if (row === undefined) return null;
|
|
82
|
+
return {
|
|
83
|
+
memory_type: requireString(row, "memory_type"),
|
|
84
|
+
layer: requireString(row, "layer"),
|
|
85
|
+
title: requireString(row, "title"),
|
|
86
|
+
journey: optionalString(row, "journey"),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// TS reinforcement writes — the port of the Python core's log_access / log_use.
|
|
2
|
+
//
|
|
3
|
+
// log_access records a retrieval: it appends a memory_access_log row and caches
|
|
4
|
+
// last_accessed_at on the memory. log_use records the stronger "actually drawn on
|
|
5
|
+
// in a response" signal by incrementing use_count. Both mirror
|
|
6
|
+
// src/memory/storage/memories.py exactly. The timestamp is injected (`nowIso`) so
|
|
7
|
+
// a parity run can freeze the clock and match the Python oracle byte-for-byte;
|
|
8
|
+
// the two statements in log_access share the one `nowIso`, as in Python.
|
|
9
|
+
|
|
10
|
+
import { type WritableDatabase, withTransaction } from "#db/database.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Record a retrieval: append to memory_access_log and cache last_accessed_at.
|
|
14
|
+
* The two statements commit as one transaction, matching Python's single
|
|
15
|
+
* `conn.commit()` — a failure between them must never leave the access row
|
|
16
|
+
* without the cached timestamp (or vice versa).
|
|
17
|
+
*/
|
|
18
|
+
export function logAccess(
|
|
19
|
+
db: WritableDatabase,
|
|
20
|
+
memoryId: string,
|
|
21
|
+
nowIso: string,
|
|
22
|
+
context: string | null,
|
|
23
|
+
): void {
|
|
24
|
+
withTransaction(db, () => {
|
|
25
|
+
db.prepare(
|
|
26
|
+
"INSERT INTO memory_access_log (memory_id, accessed_at, access_context) VALUES (?, ?, ?)",
|
|
27
|
+
).run(memoryId, nowIso, context);
|
|
28
|
+
db.prepare("UPDATE memories SET last_accessed_at = ? WHERE id = ?").run(nowIso, memoryId);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Record a use: increment use_count (the stronger reinforcement signal). */
|
|
33
|
+
export function logUse(db: WritableDatabase, memoryId: string): void {
|
|
34
|
+
db.prepare("UPDATE memories SET use_count = use_count + 1 WHERE id = ?").run(memoryId);
|
|
35
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { Database } from "#db/database.ts";
|
|
2
|
+
import { blobToFloat32 } from "#db/decode.ts";
|
|
3
|
+
import { getIdentityContent, listIdentityByLayer } from "#identity/identityRead.ts";
|
|
4
|
+
import {
|
|
5
|
+
type EmbeddingAttemptInfo,
|
|
6
|
+
type EmbeddingProvider,
|
|
7
|
+
generateEmbeddingSafely,
|
|
8
|
+
} from "#providers/embedding.ts";
|
|
9
|
+
import { cosineSimilarity } from "#search/ranker.ts";
|
|
10
|
+
import { stripAccents } from "#util/slug.ts";
|
|
11
|
+
|
|
12
|
+
export interface MirrorContextOptions {
|
|
13
|
+
persona?: string | null;
|
|
14
|
+
journey?: string | null;
|
|
15
|
+
org?: boolean;
|
|
16
|
+
query?: string | null;
|
|
17
|
+
touchesIdentity?: boolean;
|
|
18
|
+
touchesShadow?: boolean;
|
|
19
|
+
embeddingProvider?: EmbeddingProvider;
|
|
20
|
+
/**
|
|
21
|
+
* Where the attachment-search embedding is recorded as spend (CV22.DS9.TS1).
|
|
22
|
+
*
|
|
23
|
+
* Attachment search is a paid call that neither engine logged: Python's
|
|
24
|
+
* `attachment.py` calls `generate_embedding(query)` with no `on_llm_call`, against its
|
|
25
|
+
* own AI-09 rule that every model-in-the-loop call site logs. The MCP server passes a
|
|
26
|
+
* sink so its `mirror_context(query)` spend is countable; every other caller omits it
|
|
27
|
+
* and keeps the oracle's behaviour.
|
|
28
|
+
*/
|
|
29
|
+
embeddingLedger?: (info: EmbeddingAttemptInfo) => void;
|
|
30
|
+
extensionContext?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface AttachmentRow {
|
|
34
|
+
journeyId: string;
|
|
35
|
+
name: string;
|
|
36
|
+
description: string | null;
|
|
37
|
+
content: string;
|
|
38
|
+
embedding: Uint8Array;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function loadMirrorContext(
|
|
42
|
+
db: Database,
|
|
43
|
+
options: MirrorContextOptions = {},
|
|
44
|
+
): Promise<string> {
|
|
45
|
+
const sections: [string, string | null][] = [];
|
|
46
|
+
if (options.touchesIdentity ?? true)
|
|
47
|
+
sections.push(["self/soul", getIdentityContent(db, "self", "soul")]);
|
|
48
|
+
sections.push(["ego/behavior", getIdentityContent(db, "ego", "behavior")]);
|
|
49
|
+
sections.push(["user/identity", getIdentityContent(db, "user", "identity")]);
|
|
50
|
+
if (options.touchesIdentity ?? true)
|
|
51
|
+
sections.push(["ego/identity", getIdentityContent(db, "ego", "identity")]);
|
|
52
|
+
if (options.org) {
|
|
53
|
+
sections.push(["organization/identity", getIdentityContent(db, "organization", "identity")]);
|
|
54
|
+
sections.push([
|
|
55
|
+
"organization/principles",
|
|
56
|
+
getIdentityContent(db, "organization", "principles"),
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
if (options.persona) {
|
|
60
|
+
const content = getIdentityContent(db, "persona", options.persona);
|
|
61
|
+
if (content) sections.push([`persona/${options.persona}`, content]);
|
|
62
|
+
}
|
|
63
|
+
for (const row of listIdentityByLayer(db, "knowledge")) {
|
|
64
|
+
sections.push([`knowledge/${row.key}`, row.content]);
|
|
65
|
+
}
|
|
66
|
+
if (options.journey) {
|
|
67
|
+
const content = getIdentityContent(db, "journey", options.journey);
|
|
68
|
+
if (content) sections.push([`journey/${options.journey}`, content]);
|
|
69
|
+
}
|
|
70
|
+
if (options.touchesShadow) {
|
|
71
|
+
const shadow = listIdentityByLayer(db, "shadow");
|
|
72
|
+
if (shadow.length > 0) {
|
|
73
|
+
sections.push([
|
|
74
|
+
"shadow/profile",
|
|
75
|
+
[
|
|
76
|
+
"[Confirmed shadow patterns — grounded in evidence across multiple conversations]",
|
|
77
|
+
...shadow.map((row) => row.content),
|
|
78
|
+
].join("\n\n"),
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const parts: string[] = [];
|
|
84
|
+
const constraints = getIdentityContent(db, "ego", "constraints");
|
|
85
|
+
if (constraints) parts.push(`=== ⛔ HARD CONSTRAINTS ===\n${constraints}`);
|
|
86
|
+
for (const [label, content] of sections) {
|
|
87
|
+
if (content) parts.push(`=== ${label} ===\n${content}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (options.query) {
|
|
91
|
+
const attachments = await relevantAttachments(
|
|
92
|
+
db,
|
|
93
|
+
options.query,
|
|
94
|
+
options.journey ?? null,
|
|
95
|
+
options.embeddingProvider,
|
|
96
|
+
options.embeddingLedger,
|
|
97
|
+
);
|
|
98
|
+
if (attachments.length > 0) {
|
|
99
|
+
const attachmentParts = ["=== relevant attachments ==="];
|
|
100
|
+
for (const { row, score } of attachments) {
|
|
101
|
+
const source = options.journey ? "" : ` [${row.journeyId}]`;
|
|
102
|
+
attachmentParts.push(`--- ${row.name}${source} (score: ${score.toFixed(3)}) ---`);
|
|
103
|
+
if (row.description) attachmentParts.push(`Description: ${row.description}`);
|
|
104
|
+
attachmentParts.push(row.content);
|
|
105
|
+
}
|
|
106
|
+
parts.push(attachmentParts.join("\n"));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (options.extensionContext) parts.push(options.extensionContext);
|
|
110
|
+
return parts.join("\n\n");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function relevantAttachments(
|
|
114
|
+
db: Database,
|
|
115
|
+
query: string,
|
|
116
|
+
journey: string | null,
|
|
117
|
+
provider?: EmbeddingProvider,
|
|
118
|
+
embeddingLedger?: (info: EmbeddingAttemptInfo) => void,
|
|
119
|
+
): Promise<{ row: AttachmentRow; score: number }[]> {
|
|
120
|
+
const rows = attachmentRows(db, journey);
|
|
121
|
+
// No attachments, no embedding: the early return is why a query against a database
|
|
122
|
+
// without attachments records no spend -- there is none.
|
|
123
|
+
if (rows.length === 0) return [];
|
|
124
|
+
if (!provider) throw new Error("attachment embedding replay provider is required");
|
|
125
|
+
const queryEmbedding = await generateEmbeddingSafely(provider, query, {
|
|
126
|
+
...(embeddingLedger ? { onAttempt: embeddingLedger } : {}),
|
|
127
|
+
});
|
|
128
|
+
const queryTokens = (query.match(/[\p{L}\p{N}_]+/gu) ?? [])
|
|
129
|
+
.filter((token) => [...token].length >= 2 || /^\p{N}+$/u.test(token))
|
|
130
|
+
.map((token) => stripAccents(token.toLowerCase()));
|
|
131
|
+
const scored = rows.map((row) => {
|
|
132
|
+
let score = cosineSimilarity(queryEmbedding, blobToFloat32(row.embedding));
|
|
133
|
+
if (!journey && queryTokens.length > 0) {
|
|
134
|
+
let searchable = stripAccents(
|
|
135
|
+
`${row.journeyId} ${row.name} ${row.description ?? ""}`.toLowerCase(),
|
|
136
|
+
);
|
|
137
|
+
searchable = searchable
|
|
138
|
+
.replace(/(\P{N})(\p{N})/gu, "$1 $2")
|
|
139
|
+
.replace(/(\p{N})(\P{N})/gu, "$1 $2");
|
|
140
|
+
const matches = queryTokens.filter((token) => searchable.includes(token)).length;
|
|
141
|
+
if (matches > 0) score += (matches / queryTokens.length) * 0.15;
|
|
142
|
+
}
|
|
143
|
+
return { row, score };
|
|
144
|
+
});
|
|
145
|
+
scored.sort((a, b) => b.score - a.score);
|
|
146
|
+
return scored.slice(0, journey ? 5 : 8).filter((item) => item.score > 0.4);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function attachmentRows(db: Database, journey: string | null): AttachmentRow[] {
|
|
150
|
+
const sql = journey
|
|
151
|
+
? "SELECT journey_id, name, description, content, embedding FROM attachments WHERE journey_id = ? AND embedding IS NOT NULL ORDER BY created_at"
|
|
152
|
+
: "SELECT journey_id, name, description, content, embedding FROM attachments WHERE embedding IS NOT NULL ORDER BY created_at";
|
|
153
|
+
const rows = journey ? db.prepare(sql).all(journey) : db.prepare(sql).all();
|
|
154
|
+
return rows.map((row) => ({
|
|
155
|
+
journeyId: String(row.journey_id),
|
|
156
|
+
name: String(row.name),
|
|
157
|
+
description: typeof row.description === "string" ? row.description : null,
|
|
158
|
+
content: String(row.content),
|
|
159
|
+
embedding: row.embedding as Uint8Array,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { Database } from "#db/database.ts";
|
|
2
|
+
import { descriptorsByLayer } from "#descriptor/descriptorRead.ts";
|
|
3
|
+
import type { OnProviderCallOutcome } from "#observability/callOutcome.ts";
|
|
4
|
+
import { detectPersona, type PersonaRoutingRow } from "#persona/detectPersona.ts";
|
|
5
|
+
import { type EmbeddingProvider, generateEmbeddingSafely } from "#providers/embedding.ts";
|
|
6
|
+
import type { LlmProvider, LlmResponse } from "#providers/llm.ts";
|
|
7
|
+
import { cosineSimilarity } from "#search/ranker.ts";
|
|
8
|
+
import { stripAccents } from "#util/slug.ts";
|
|
9
|
+
import { runReception, sliceCodePoints } from "./reception.ts";
|
|
10
|
+
import { GLOBAL_STICKY_DEFAULTS_SESSION_ID, getRuntimeSession } from "./runtimeSession.ts";
|
|
11
|
+
|
|
12
|
+
export interface ResolvedMirrorDefaults {
|
|
13
|
+
persona: string | null;
|
|
14
|
+
journey: string | null;
|
|
15
|
+
detectedJourney: [string, number, string][] | null;
|
|
16
|
+
touchesIdentity: boolean;
|
|
17
|
+
touchesShadow: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ResolveMirrorDefaultsInput {
|
|
21
|
+
persona?: string | null;
|
|
22
|
+
journey?: string | null;
|
|
23
|
+
query?: string | null;
|
|
24
|
+
sessionId?: string | null;
|
|
25
|
+
receptionEnabled: boolean;
|
|
26
|
+
llmProvider?: LlmProvider;
|
|
27
|
+
embeddingProvider?: EmbeddingProvider;
|
|
28
|
+
onReceptionLlmCall?: (response: LlmResponse, prompt: string) => void;
|
|
29
|
+
/** Reception's outcome, category only; see `observability/callOutcome.ts`. */
|
|
30
|
+
onReceptionOutcome?: OnProviderCallOutcome;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface IdentityRoutingRow {
|
|
34
|
+
key: string;
|
|
35
|
+
content: string;
|
|
36
|
+
metadata: string | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function resolveMirrorDefaults(
|
|
40
|
+
db: Database,
|
|
41
|
+
input: ResolveMirrorDefaultsInput,
|
|
42
|
+
): Promise<ResolvedMirrorDefaults> {
|
|
43
|
+
let persona = input.persona ?? null;
|
|
44
|
+
let journey = input.journey ?? null;
|
|
45
|
+
let detectedJourney: [string, number, string][] | null = null;
|
|
46
|
+
let touchesIdentity = true;
|
|
47
|
+
let touchesShadow = false;
|
|
48
|
+
|
|
49
|
+
const session = input.sessionId ? getRuntimeSession(db, input.sessionId) : null;
|
|
50
|
+
const global = getRuntimeSession(db, GLOBAL_STICKY_DEFAULTS_SESSION_ID);
|
|
51
|
+
const stickyPersona = session?.persona || global?.persona || null;
|
|
52
|
+
const stickyJourney = session?.journey || global?.journey || null;
|
|
53
|
+
const query = input.query ?? null;
|
|
54
|
+
|
|
55
|
+
if (input.receptionEnabled && query) {
|
|
56
|
+
if (!input.llmProvider) throw new Error("reception replay provider is required");
|
|
57
|
+
const personaRows = identityRoutingRows(db, "persona");
|
|
58
|
+
const journeyRows = identityRoutingRows(db, "journey");
|
|
59
|
+
const personaDescriptors = descriptorMap(db, "persona");
|
|
60
|
+
const journeyDescriptors = descriptorMap(db, "journey");
|
|
61
|
+
const reception = await runReception(
|
|
62
|
+
query,
|
|
63
|
+
personaRows.map((row) => ({
|
|
64
|
+
slug: row.key,
|
|
65
|
+
description: personaDescriptors.get(row.key) ?? sliceCodePoints(row.content, 200),
|
|
66
|
+
routingKeywords: routingKeywords(row.metadata),
|
|
67
|
+
})),
|
|
68
|
+
journeyRows.map((row) => ({
|
|
69
|
+
slug: row.key,
|
|
70
|
+
description: journeyDescriptors.get(row.key) ?? sliceCodePoints(row.content, 200),
|
|
71
|
+
})),
|
|
72
|
+
input.llmProvider,
|
|
73
|
+
input.onReceptionLlmCall,
|
|
74
|
+
input.onReceptionOutcome,
|
|
75
|
+
);
|
|
76
|
+
if (reception.personas.length > 0 && persona === null) persona = reception.personas[0] ?? null;
|
|
77
|
+
if (reception.journey && journey === null) journey = reception.journey;
|
|
78
|
+
touchesIdentity = reception.touchesIdentity;
|
|
79
|
+
touchesShadow = reception.touchesShadow;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
persona ??= stickyPersona;
|
|
83
|
+
journey ??= stickyJourney;
|
|
84
|
+
|
|
85
|
+
if (persona === null && query) {
|
|
86
|
+
const matches = detectPersona(query, personaRoutingRows(db));
|
|
87
|
+
persona = matches[0]?.key ?? null;
|
|
88
|
+
}
|
|
89
|
+
if (journey === null && query) {
|
|
90
|
+
detectedJourney = await detectJourney(db, query, input.embeddingProvider);
|
|
91
|
+
journey = detectedJourney[0]?.[0] ?? null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { persona, journey, detectedJourney, touchesIdentity, touchesShadow };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function detectJourney(
|
|
98
|
+
db: Database,
|
|
99
|
+
query: string,
|
|
100
|
+
embeddingProvider?: EmbeddingProvider,
|
|
101
|
+
threshold = 0.35,
|
|
102
|
+
): Promise<[string, number, string][]> {
|
|
103
|
+
const journeys = identityRoutingRows(db, "journey");
|
|
104
|
+
if (journeys.length === 0) return [];
|
|
105
|
+
const queryTokens = new Set(stripAccents(query.toLowerCase()).match(/[\p{L}\p{N}_]+/gu) ?? []);
|
|
106
|
+
const stopwords = new Set([
|
|
107
|
+
"o",
|
|
108
|
+
"a",
|
|
109
|
+
"os",
|
|
110
|
+
"as",
|
|
111
|
+
"de",
|
|
112
|
+
"do",
|
|
113
|
+
"da",
|
|
114
|
+
"dos",
|
|
115
|
+
"das",
|
|
116
|
+
"e",
|
|
117
|
+
"em",
|
|
118
|
+
"no",
|
|
119
|
+
"na",
|
|
120
|
+
]);
|
|
121
|
+
const textMatches: [string, number, string][] = [];
|
|
122
|
+
for (const row of journeys) {
|
|
123
|
+
const idTokens = new Set(stripAccents(row.key.replaceAll("-", " ").toLowerCase()).split(/\s+/));
|
|
124
|
+
const firstLine =
|
|
125
|
+
row.content
|
|
126
|
+
.split("\n")[0]
|
|
127
|
+
?.trim()
|
|
128
|
+
.replace(/^[# ]+/, "") ?? "";
|
|
129
|
+
const nameTokens = new Set(
|
|
130
|
+
stripAccents(firstLine.toLowerCase()).match(/[\p{L}\p{N}_]+/gu) ?? [],
|
|
131
|
+
);
|
|
132
|
+
const overlap = new Set<string>();
|
|
133
|
+
for (const token of [...idTokens, ...nameTokens]) {
|
|
134
|
+
if (!stopwords.has(token) && queryTokens.has(token)) overlap.add(token);
|
|
135
|
+
}
|
|
136
|
+
if (overlap.size > 0) {
|
|
137
|
+
const all = new Set([...idTokens, ...nameTokens].filter((token) => !stopwords.has(token)));
|
|
138
|
+
textMatches.push([row.key, Math.min(1, overlap.size / Math.max(all.size, 1) + 0.5), "text"]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (textMatches.length > 0) return textMatches.sort((a, b) => b[1] - a[1]);
|
|
142
|
+
if (!embeddingProvider) return [];
|
|
143
|
+
let queryEmbedding: readonly number[];
|
|
144
|
+
try {
|
|
145
|
+
queryEmbedding = await generateEmbeddingSafely(embeddingProvider, query);
|
|
146
|
+
} catch {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
const semantic: [string, number, string][] = [];
|
|
150
|
+
for (const row of journeys) {
|
|
151
|
+
try {
|
|
152
|
+
const vector = await generateEmbeddingSafely(
|
|
153
|
+
embeddingProvider,
|
|
154
|
+
sliceCodePoints(row.content, 1000) || row.key,
|
|
155
|
+
);
|
|
156
|
+
const score = cosineSimilarity(queryEmbedding, vector);
|
|
157
|
+
if (score >= threshold) semantic.push([row.key, score, "semantic"]);
|
|
158
|
+
} catch {
|
|
159
|
+
// Python isolates each journey embedding failure.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return semantic.sort((a, b) => b[1] - a[1]);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function identityRoutingRows(db: Database, layer: string): IdentityRoutingRow[] {
|
|
166
|
+
return db
|
|
167
|
+
.prepare("SELECT key, content, metadata FROM identity WHERE layer = ? ORDER BY key")
|
|
168
|
+
.all(layer)
|
|
169
|
+
.map((row) => ({
|
|
170
|
+
key: String(row.key),
|
|
171
|
+
content: String(row.content),
|
|
172
|
+
metadata: typeof row.metadata === "string" ? row.metadata : null,
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function descriptorMap(db: Database, layer: string): Map<string, string> {
|
|
177
|
+
return new Map(descriptorsByLayer(db, layer).map((row) => [row.key, row.descriptor]));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function personaRoutingRows(db: Database): PersonaRoutingRow[] {
|
|
181
|
+
return identityRoutingRows(db, "persona").map((row) => ({
|
|
182
|
+
key: row.key,
|
|
183
|
+
routing_keywords: routingKeywords(row.metadata),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function routingKeywords(metadata: string | null): string[] {
|
|
188
|
+
if (!metadata) return [];
|
|
189
|
+
try {
|
|
190
|
+
const parsed: unknown = JSON.parse(metadata);
|
|
191
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return [];
|
|
192
|
+
const value = (parsed as Record<string, unknown>).routing_keywords;
|
|
193
|
+
return Array.isArray(value)
|
|
194
|
+
? value.filter((item): item is string => typeof item === "string")
|
|
195
|
+
: [];
|
|
196
|
+
} catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
}
|