mirror-mind 0.0.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/log-assistant-reply.sh +85 -0
- package/.claude/hooks/log-session-end.sh +85 -0
- package/.claude/hooks/log-user-prompt.sh +85 -0
- package/.claude/hooks/mirror-inject.sh +85 -0
- package/.claude/hooks/session-start.sh +85 -0
- package/.gemini/hooks/log-assistant.sh +85 -0
- package/.gemini/hooks/log-user.sh +85 -0
- package/.gemini/hooks/session-end.sh +85 -0
- package/.gemini/hooks/session-start.sh +85 -0
- package/.pi/extensions/mirror-logger.ts +646 -0
- package/.pi/skills/mm-backup/SKILL.md +21 -0
- package/.pi/skills/mm-build/SKILL.md +1206 -0
- package/.pi/skills/mm-consolidate/SKILL.md +112 -0
- package/.pi/skills/mm-consult/SKILL.md +70 -0
- package/.pi/skills/mm-conversations/SKILL.md +16 -0
- package/.pi/skills/mm-discard/SKILL.md +39 -0
- package/.pi/skills/mm-explore/SKILL.md +255 -0
- package/.pi/skills/mm-help/SKILL.md +74 -0
- package/.pi/skills/mm-identity/SKILL.md +96 -0
- package/.pi/skills/mm-journal/SKILL.md +16 -0
- package/.pi/skills/mm-journey/SKILL.md +23 -0
- package/.pi/skills/mm-journeys/SKILL.md +15 -0
- package/.pi/skills/mm-memories/SKILL.md +17 -0
- package/.pi/skills/mm-mirror/SKILL.md +98 -0
- package/.pi/skills/mm-mute/SKILL.md +18 -0
- package/.pi/skills/mm-new/SKILL.md +18 -0
- package/.pi/skills/mm-recall/SKILL.md +17 -0
- package/.pi/skills/mm-release-notes/SKILL.md +52 -0
- package/.pi/skills/mm-seed/SKILL.md +19 -0
- package/.pi/skills/mm-shadow/SKILL.md +117 -0
- package/.pi/skills/mm-soul/SKILL.md +502 -0
- package/.pi/skills/mm-tasks/SKILL.md +24 -0
- package/.pi/skills/mm-update/SKILL.md +32 -0
- package/.pi/skills/mm-week/SKILL.md +28 -0
- package/.pi/skills/mm-welcome/SKILL.md +24 -0
- package/AGENTS.md +188 -0
- package/README.md +126 -9
- package/bin/loader.js +67 -0
- package/bin/mirror-hook.js +7 -0
- package/bin/mirror.js +7 -0
- package/docs/releases/index.md +100 -0
- package/docs/releases/pending-cutoffs.md +510 -0
- package/docs/releases/v0.10.0.md +123 -0
- package/docs/releases/v0.10.1.md +66 -0
- package/docs/releases/v0.10.10.md +51 -0
- package/docs/releases/v0.10.11.md +39 -0
- package/docs/releases/v0.10.12.md +57 -0
- package/docs/releases/v0.10.13.md +35 -0
- package/docs/releases/v0.10.14.md +42 -0
- package/docs/releases/v0.10.15.md +53 -0
- package/docs/releases/v0.10.16.md +35 -0
- package/docs/releases/v0.10.17.md +43 -0
- package/docs/releases/v0.10.2.md +64 -0
- package/docs/releases/v0.10.3.md +78 -0
- package/docs/releases/v0.10.4.md +42 -0
- package/docs/releases/v0.10.5.md +57 -0
- package/docs/releases/v0.10.6.md +47 -0
- package/docs/releases/v0.10.7.md +53 -0
- package/docs/releases/v0.10.8.md +49 -0
- package/docs/releases/v0.10.9.md +37 -0
- package/docs/releases/v0.11.0.md +86 -0
- package/docs/releases/v0.12.0.md +67 -0
- package/docs/releases/v0.13.0.md +64 -0
- package/docs/releases/v0.14.0.md +68 -0
- package/docs/releases/v0.15.0.md +48 -0
- package/docs/releases/v0.16.0.md +50 -0
- package/docs/releases/v0.16.1.md +55 -0
- package/docs/releases/v0.16.2.md +36 -0
- package/docs/releases/v0.17.0.md +50 -0
- package/docs/releases/v0.17.1.md +58 -0
- package/docs/releases/v0.17.2.md +42 -0
- package/docs/releases/v0.17.3.md +58 -0
- package/docs/releases/v0.18.0.md +84 -0
- package/docs/releases/v0.18.1.md +51 -0
- package/docs/releases/v0.18.2.md +69 -0
- package/docs/releases/v0.19.0.md +85 -0
- package/docs/releases/v0.19.1.md +46 -0
- package/docs/releases/v0.20.0.md +85 -0
- package/docs/releases/v0.21.0.md +61 -0
- package/docs/releases/v0.21.1.md +47 -0
- package/docs/releases/v0.22.0.md +77 -0
- package/docs/releases/v0.22.1.md +42 -0
- package/docs/releases/v0.23.0.md +105 -0
- package/docs/releases/v0.24.0.md +125 -0
- package/docs/releases/v0.25.0.md +107 -0
- package/docs/releases/v0.26.0.md +139 -0
- package/docs/releases/v0.26.1.md +65 -0
- package/docs/releases/v0.26.2.md +43 -0
- package/docs/releases/v0.27.0.md +63 -0
- package/docs/releases/v0.28.0.md +59 -0
- package/docs/releases/v0.29.0.md +61 -0
- package/docs/releases/v0.29.1.md +59 -0
- package/docs/releases/v0.29.2.md +59 -0
- package/docs/releases/v0.29.3.md +93 -0
- package/docs/releases/v0.30.0.md +75 -0
- package/docs/releases/v0.30.1.md +93 -0
- package/docs/releases/v0.30.2.md +66 -0
- package/docs/releases/v0.31.0.md +122 -0
- package/docs/releases/v0.31.1.md +142 -0
- package/docs/releases/v0.31.10.md +118 -0
- package/docs/releases/v0.31.11.md +88 -0
- package/docs/releases/v0.31.12.md +105 -0
- package/docs/releases/v0.31.13.md +99 -0
- package/docs/releases/v0.31.14.md +97 -0
- package/docs/releases/v0.31.2.md +115 -0
- package/docs/releases/v0.31.3.md +142 -0
- package/docs/releases/v0.31.4.md +117 -0
- package/docs/releases/v0.31.5.md +155 -0
- package/docs/releases/v0.31.6.md +132 -0
- package/docs/releases/v0.31.7.md +132 -0
- package/docs/releases/v0.31.8.md +120 -0
- package/docs/releases/v0.31.9.md +120 -0
- package/docs/releases/v0.32.0.md +261 -0
- package/docs/releases/v0.32.1.md +59 -0
- package/docs/releases/v0.33.0.md +164 -0
- package/docs/releases/v0.8.0.md +118 -0
- package/docs/releases/v0.9.0.md +98 -0
- package/docs/releases/v0.9.1.md +83 -0
- package/package.json +102 -6
- package/plugins/mirror-mind/.claude-plugin/plugin.json +17 -0
- package/plugins/mirror-mind/hooks/hooks.json +62 -0
- package/plugins/mirror-mind/hooks/log-assistant-reply.sh +98 -0
- package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
- package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
- package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
- package/plugins/mirror-mind/hooks/session-start.sh +98 -0
- package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
- package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
- package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
- package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
- package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
- package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
- package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
- package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
- package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
- package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
- package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
- package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +67 -0
- package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
- package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
- package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
- package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
- package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
- package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
- package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
- package/scripts/codex-hooks/session-end.sh +85 -0
- package/scripts/codex-hooks/session-start.sh +85 -0
- package/scripts/codex-mirror.sh +48 -0
- package/templates/identity/README.md +119 -0
- package/templates/identity/ego/behavior.yaml +52 -0
- package/templates/identity/ego/constraints.yaml +15 -0
- package/templates/identity/ego/identity.yaml +43 -0
- package/templates/identity/journeys/personal-growth.yaml +39 -0
- package/templates/identity/organization/identity.yaml +24 -0
- package/templates/identity/organization/principles.yaml +17 -0
- package/templates/identity/personas/coach.yaml +94 -0
- package/templates/identity/personas/designer.yaml +93 -0
- package/templates/identity/personas/doctor.yaml +96 -0
- package/templates/identity/personas/engineer.yaml +77 -0
- package/templates/identity/personas/financial.yaml +97 -0
- package/templates/identity/personas/prompt-engineer.yaml +122 -0
- package/templates/identity/personas/researcher.yaml +88 -0
- package/templates/identity/personas/strategist.yaml +91 -0
- package/templates/identity/personas/teacher.yaml +95 -0
- package/templates/identity/personas/therapist.yaml +91 -0
- package/templates/identity/personas/thinker.yaml +74 -0
- package/templates/identity/personas/writer.yaml +76 -0
- package/templates/identity/self/config.yaml +16 -0
- package/templates/identity/self/soul.yaml +105 -0
- package/templates/identity/user/identity.yaml +30 -0
- package/ts/src/backup/staging.ts +62 -0
- package/ts/src/backup/zipBackup.ts +267 -0
- package/ts/src/backup/zipReader.ts +109 -0
- package/ts/src/backup/zipWriter.ts +148 -0
- package/ts/src/builder/activeCheckpoint.ts +134 -0
- package/ts/src/builder/aggregateStatus.ts +34 -0
- package/ts/src/builder/approve.ts +149 -0
- package/ts/src/builder/argv.ts +292 -0
- package/ts/src/builder/ariadMethod.ts +536 -0
- package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
- package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
- package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
- package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
- package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
- package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
- package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
- package/ts/src/builder/artifacts/storyFiles.ts +61 -0
- package/ts/src/builder/artifacts/storyIndex.ts +166 -0
- package/ts/src/builder/cadence.ts +59 -0
- package/ts/src/builder/card.ts +192 -0
- package/ts/src/builder/checkpointRefused.ts +66 -0
- package/ts/src/builder/closure.ts +964 -0
- package/ts/src/builder/commands.ts +2053 -0
- package/ts/src/builder/cursorPosition.ts +176 -0
- package/ts/src/builder/cursorTransitions.ts +77 -0
- package/ts/src/builder/deliveryCursor.ts +577 -0
- package/ts/src/builder/deliveryStoryClosure.ts +521 -0
- package/ts/src/builder/deliveryStoryPlan.ts +536 -0
- package/ts/src/builder/deliveryStoryReady.ts +160 -0
- package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
- package/ts/src/builder/expand.ts +336 -0
- package/ts/src/builder/flowUnit.ts +339 -0
- package/ts/src/builder/homeSurface.ts +122 -0
- package/ts/src/builder/implementationGuard.ts +125 -0
- package/ts/src/builder/index.ts +11 -0
- package/ts/src/builder/lifecycleRefusal.ts +92 -0
- package/ts/src/builder/lifecycleRibbon.ts +159 -0
- package/ts/src/builder/load.ts +313 -0
- package/ts/src/builder/methodAdoption.ts +113 -0
- package/ts/src/builder/methodDefinition.ts +429 -0
- package/ts/src/builder/methodInspection.ts +371 -0
- package/ts/src/builder/plan.ts +408 -0
- package/ts/src/builder/planPreauthorization.ts +265 -0
- package/ts/src/builder/prepare.ts +225 -0
- package/ts/src/builder/projectPaths.ts +64 -0
- package/ts/src/builder/pull.ts +356 -0
- package/ts/src/builder/pullCandidates.ts +463 -0
- package/ts/src/builder/pullCandidatesRender.ts +238 -0
- package/ts/src/builder/refinementField.ts +93 -0
- package/ts/src/builder/releaseIntent.ts +173 -0
- package/ts/src/builder/resumeState.ts +84 -0
- package/ts/src/builder/resumeSurface.ts +149 -0
- package/ts/src/builder/roadmapGrammar.ts +300 -0
- package/ts/src/builder/roadmapScan.ts +97 -0
- package/ts/src/builder/roadmapScope.ts +210 -0
- package/ts/src/builder/scopePhrases.ts +146 -0
- package/ts/src/builder/storyPaths.ts +196 -0
- package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
- package/ts/src/builder/surfaceProtocol.ts +42 -0
- package/ts/src/builder/templateGeneration.ts +148 -0
- package/ts/src/builder/transition.ts +178 -0
- package/ts/src/consult/args.ts +99 -0
- package/ts/src/consult/core.ts +122 -0
- package/ts/src/consult/modelCatalog.ts +55 -0
- package/ts/src/consult/render.ts +47 -0
- package/ts/src/conversation/append.ts +414 -0
- package/ts/src/conversation/backfill.ts +387 -0
- package/ts/src/conversation/closeTail.ts +467 -0
- package/ts/src/conversation/extraction.ts +333 -0
- package/ts/src/conversation/extractionDriver.ts +130 -0
- package/ts/src/conversation/extractionRun.ts +70 -0
- package/ts/src/conversation/hookPayload.ts +51 -0
- package/ts/src/conversation/journeyInference.ts +165 -0
- package/ts/src/conversation/journeyRepair.ts +114 -0
- package/ts/src/conversation/lifecycleFaces.ts +197 -0
- package/ts/src/conversation/lifecycleWrites.ts +313 -0
- package/ts/src/conversation/listing.ts +77 -0
- package/ts/src/conversation/logger.ts +851 -0
- package/ts/src/conversation/loggerCli.ts +321 -0
- package/ts/src/conversation/loggerRuntime.ts +259 -0
- package/ts/src/conversation/metadataLifecycle.ts +443 -0
- package/ts/src/conversation/recall.ts +66 -0
- package/ts/src/conversation/sessionComposites.ts +258 -0
- package/ts/src/conversation/sessionImport.ts +90 -0
- package/ts/src/conversation/transcriptBackfill.ts +141 -0
- package/ts/src/cultivation/applyActions.ts +241 -0
- package/ts/src/cultivation/cluster.ts +86 -0
- package/ts/src/cultivation/consolidationStore.ts +281 -0
- package/ts/src/cultivation/promptContext.ts +62 -0
- package/ts/src/cultivation/propose.ts +305 -0
- package/ts/src/cultivation/scan.ts +155 -0
- package/ts/src/db/backupGate.ts +47 -0
- package/ts/src/db/bootstrap.ts +108 -0
- package/ts/src/db/bootstrapLock.ts +223 -0
- package/ts/src/db/copyGuard.ts +60 -0
- package/ts/src/db/database.ts +397 -0
- package/ts/src/db/decode.ts +66 -0
- package/ts/src/db/ftsIntegrity.ts +41 -0
- package/ts/src/db/migrateOnOpen.ts +214 -0
- package/ts/src/db/migrations.ts +576 -0
- package/ts/src/db/readyOnOpen.ts +35 -0
- package/ts/src/db/rowDecode.ts +42 -0
- package/ts/src/db/schema.ts +432 -0
- package/ts/src/db/schemaInventory.ts +225 -0
- package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
- package/ts/src/db/schemaState.ts +91 -0
- package/ts/src/db/schemaTsDivergence.ts +114 -0
- package/ts/src/descriptor/descriptorRead.ts +49 -0
- package/ts/src/docs/docsLint.ts +265 -0
- package/ts/src/explorer/handoff.ts +522 -0
- package/ts/src/explorer/render.ts +335 -0
- package/ts/src/explorer/story.ts +769 -0
- package/ts/src/explorer/transition.ts +72 -0
- package/ts/src/extensions/bindings.ts +170 -0
- package/ts/src/extensions/catalog.ts +249 -0
- package/ts/src/extensions/catalogCommands.ts +513 -0
- package/ts/src/extensions/catalogWrites.ts +652 -0
- package/ts/src/extensions/contextRuntime.ts +325 -0
- package/ts/src/extensions/dispatch.ts +374 -0
- package/ts/src/extensions/errors.ts +24 -0
- package/ts/src/extensions/manifest.ts +356 -0
- package/ts/src/extensions/migrations.ts +350 -0
- package/ts/src/extraction/conversation.ts +304 -0
- package/ts/src/extraction/conversationMetadata.ts +206 -0
- package/ts/src/extraction/fencing.ts +106 -0
- package/ts/src/extraction/json.ts +17 -0
- package/ts/src/extraction/prompts.ts +470 -0
- package/ts/src/frontDoor/args.ts +30 -0
- package/ts/src/frontDoor/argvShape.ts +106 -0
- package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
- package/ts/src/frontDoor/buildRoute.ts +398 -0
- package/ts/src/frontDoor/cli.ts +1872 -0
- package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
- package/ts/src/frontDoor/consultRoute.ts +50 -0
- package/ts/src/frontDoor/contentTailRoute.ts +239 -0
- package/ts/src/frontDoor/conversationLoggerRoute.ts +83 -0
- package/ts/src/frontDoor/cultivationRoute.ts +210 -0
- package/ts/src/frontDoor/dbPath.ts +131 -0
- package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
- package/ts/src/frontDoor/exploreRoute.ts +572 -0
- package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
- package/ts/src/frontDoor/frontDoorLog.ts +57 -0
- package/ts/src/frontDoor/identityWrite.ts +36 -0
- package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
- package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
- package/ts/src/frontDoor/liveBackup.ts +100 -0
- package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
- package/ts/src/frontDoor/namedRefusal.ts +35 -0
- package/ts/src/frontDoor/nodeSupport.ts +24 -0
- package/ts/src/frontDoor/render/consolidate.ts +199 -0
- package/ts/src/frontDoor/render/conversations.ts +33 -0
- package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
- package/ts/src/frontDoor/render/descriptor.ts +20 -0
- package/ts/src/frontDoor/render/detectPersona.ts +50 -0
- package/ts/src/frontDoor/render/icons.ts +13 -0
- package/ts/src/frontDoor/render/identity.ts +59 -0
- package/ts/src/frontDoor/render/identityRows.ts +17 -0
- package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
- package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
- package/ts/src/frontDoor/render/journeys.ts +79 -0
- package/ts/src/frontDoor/render/list.ts +41 -0
- package/ts/src/frontDoor/render/memories.ts +67 -0
- package/ts/src/frontDoor/render/recall.ts +49 -0
- package/ts/src/frontDoor/render/shadow.ts +155 -0
- package/ts/src/frontDoor/render/tasks.ts +99 -0
- package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
- package/ts/src/frontDoor/render/week.ts +113 -0
- package/ts/src/frontDoor/routing.ts +1001 -0
- package/ts/src/frontDoor/runtimeRoute.ts +623 -0
- package/ts/src/frontDoor/searchRoute.ts +166 -0
- package/ts/src/frontDoor/seedPaths.ts +98 -0
- package/ts/src/frontDoor/sessionStartWelcomeRoute.ts +166 -0
- package/ts/src/frontDoor/soulRoute.ts +433 -0
- package/ts/src/frontDoor/stdinSource.ts +37 -0
- package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
- package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
- package/ts/src/frontDoor/usage.ts +176 -0
- package/ts/src/guards/claudePlugin.ts +298 -0
- package/ts/src/guards/packContents.ts +306 -0
- package/ts/src/guards/piSourcedSkills.ts +70 -0
- package/ts/src/guards/retiredRouteShadows.ts +57 -0
- package/ts/src/guards/retiredSurfaces.ts +564 -0
- package/ts/src/hooks/claude.ts +214 -0
- package/ts/src/hooks/codex.ts +45 -0
- package/ts/src/hooks/gemini.ts +126 -0
- package/ts/src/hooks/main.ts +109 -0
- package/ts/src/hooks/mirrorState.ts +71 -0
- package/ts/src/hooks/payload.ts +73 -0
- package/ts/src/hooks/runtime.ts +179 -0
- package/ts/src/hooks/runtimeDetection.ts +34 -0
- package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
- package/ts/src/identity/descriptorGenerate.ts +162 -0
- package/ts/src/identity/identityEdit.ts +143 -0
- package/ts/src/identity/identityKey.ts +77 -0
- package/ts/src/identity/identityRead.ts +69 -0
- package/ts/src/identity/identityStore.ts +80 -0
- package/ts/src/identity/journeyListing.ts +53 -0
- package/ts/src/identity/personaInspect.ts +44 -0
- package/ts/src/identity/personaListing.ts +37 -0
- package/ts/src/identity/setIdentity.ts +64 -0
- package/ts/src/index.ts +231 -0
- package/ts/src/init/init.ts +111 -0
- package/ts/src/journey/journeyOptions.ts +131 -0
- package/ts/src/journey/journeyRemoval.ts +158 -0
- package/ts/src/journey/journeyStatus.ts +149 -0
- package/ts/src/journey/journeySyncFile.ts +87 -0
- package/ts/src/journey/journeyWrite.ts +203 -0
- package/ts/src/journey/parentJourney.ts +41 -0
- package/ts/src/journey/validateParentJourney.ts +55 -0
- package/ts/src/mcp/boundary.ts +151 -0
- package/ts/src/mcp/guards.ts +244 -0
- package/ts/src/mcp/main.ts +121 -0
- package/ts/src/mcp/payload.ts +141 -0
- package/ts/src/mcp/protocol.ts +141 -0
- package/ts/src/mcp/readModels.ts +241 -0
- package/ts/src/mcp/registry.ts +201 -0
- package/ts/src/mcp/serve.ts +120 -0
- package/ts/src/mcp/tools/deterministic.ts +137 -0
- package/ts/src/mcp/tools/providerCrossing.ts +187 -0
- package/ts/src/mcp/wire.ts +8 -0
- package/ts/src/memory/journal.ts +180 -0
- package/ts/src/memory/listing.ts +107 -0
- package/ts/src/memory/memoryWrite.ts +88 -0
- package/ts/src/memory/reinforcement.ts +35 -0
- package/ts/src/mirror/context.ts +161 -0
- package/ts/src/mirror/defaultResolution.ts +199 -0
- package/ts/src/mirror/mirrorForm.ts +43 -0
- package/ts/src/mirror/orchestration.ts +364 -0
- package/ts/src/mirror/reception.ts +194 -0
- package/ts/src/mirror/render.ts +75 -0
- package/ts/src/mirror/runtimeSession.ts +205 -0
- package/ts/src/mode/operatingMode.ts +148 -0
- package/ts/src/observability/callOutcome.ts +115 -0
- package/ts/src/observability/inspectLedger.ts +329 -0
- package/ts/src/observability/ledgerHooks.ts +126 -0
- package/ts/src/observability/llmCalls.ts +154 -0
- package/ts/src/persona/detectPersona.ts +81 -0
- package/ts/src/planning/promptAssembly.ts +111 -0
- package/ts/src/planning/weekPending.ts +81 -0
- package/ts/src/planning/weekPlan.ts +183 -0
- package/ts/src/planning/weekSave.ts +117 -0
- package/ts/src/providers/config.ts +189 -0
- package/ts/src/providers/cost.ts +64 -0
- package/ts/src/providers/credits.ts +204 -0
- package/ts/src/providers/embedding.ts +321 -0
- package/ts/src/providers/familyProviders.ts +147 -0
- package/ts/src/providers/llm.ts +334 -0
- package/ts/src/providers/openrouter.ts +244 -0
- package/ts/src/providers/redaction.ts +110 -0
- package/ts/src/providers/replay.ts +15 -0
- package/ts/src/providers/transport.ts +410 -0
- package/ts/src/repair/encodingRepair.ts +253 -0
- package/ts/src/runtime/backup.ts +151 -0
- package/ts/src/runtime/channel.ts +146 -0
- package/ts/src/runtime/config.ts +168 -0
- package/ts/src/runtime/diagnose.ts +686 -0
- package/ts/src/runtime/git.ts +510 -0
- package/ts/src/runtime/installKind.ts +220 -0
- package/ts/src/runtime/migrate.ts +154 -0
- package/ts/src/runtime/packageIdentity.ts +102 -0
- package/ts/src/runtime/releaseNotes.ts +244 -0
- package/ts/src/runtime/status.ts +557 -0
- package/ts/src/runtime/strategies/clone.ts +200 -0
- package/ts/src/runtime/strategies/package.ts +328 -0
- package/ts/src/runtime/treeRoot.ts +30 -0
- package/ts/src/runtime/update.ts +445 -0
- package/ts/src/runtime/updateGate.ts +40 -0
- package/ts/src/runtime/updatePipeline.ts +159 -0
- package/ts/src/runtime/version.ts +36 -0
- package/ts/src/runtime/wiring.ts +130 -0
- package/ts/src/search/memorySearch.ts +338 -0
- package/ts/src/search/ranker.ts +154 -0
- package/ts/src/seed/seed.ts +256 -0
- package/ts/src/seed/seedYaml.ts +133 -0
- package/ts/src/soul/apply.ts +218 -0
- package/ts/src/soul/harvest.ts +267 -0
- package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
- package/ts/src/soul/prompts/soul_self_voice.md +219 -0
- package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
- package/ts/src/soul/prompts.ts +85 -0
- package/ts/src/soul/render.ts +358 -0
- package/ts/src/soul/state.ts +212 -0
- package/ts/src/soul/transition.ts +37 -0
- package/ts/src/tasks/journeyPathParse.ts +113 -0
- package/ts/src/tasks/taskImportSync.ts +142 -0
- package/ts/src/tasks/taskStore.ts +312 -0
- package/ts/src/tasks/weekView.ts +120 -0
- package/ts/src/util/clipCodePoints.ts +26 -0
- package/ts/src/util/paths.ts +63 -0
- package/ts/src/util/program.ts +9 -0
- package/ts/src/util/pyGenerators.ts +144 -0
- package/ts/src/util/pythonText.ts +317 -0
- package/ts/src/util/semver.ts +45 -0
- package/ts/src/util/shellWord.ts +25 -0
- package/ts/src/util/slug.ts +64 -0
- package/ts/src/welcome/card.ts +339 -0
- package/ts/src/welcome/statusLine.ts +101 -0
- package/ts/src/welcome/updateCache.ts +129 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// `conversation-logger` CLI dispatch (CV22.DS7.US5 slice A; completed in
|
|
2
|
+
// CV22.DS7.US10 slice F).
|
|
3
|
+
//
|
|
4
|
+
// Ports the argument handling and stdout contract of
|
|
5
|
+
// `conversation_logger.main()`. The strangler's unit is
|
|
6
|
+
// `command + args -> stdout`, so this module returns the output rather than
|
|
7
|
+
// printing it: the front door writes it, and goldens grade it.
|
|
8
|
+
//
|
|
9
|
+
// Every subcommand of the family is dispatched here. The ones that cross the
|
|
10
|
+
// LLM close tail (`switch`, `session-end`, `session-end-pi`, full
|
|
11
|
+
// `session-start`, `session-maintenance`) get their tail from the runtime's
|
|
12
|
+
// close hooks. (Until CV22.DS10.TS5 a reverted tail reported `{ handled:
|
|
13
|
+
// false }` so the caller could fall back to Python; the revert left with the
|
|
14
|
+
// fallback, and every result is now an answer.) `repair-journeys --apply`
|
|
15
|
+
// needs the dated zip backup from the runtime (CV22.DS7.TS1) and refuses, like
|
|
16
|
+
// Python, when it is not available.
|
|
17
|
+
|
|
18
|
+
import { backfillCodexSession } from "#conversation/backfill.ts";
|
|
19
|
+
import { diagnoseJourneyAssociations, renderJourneyFindings } from "#conversation/journeyRepair.ts";
|
|
20
|
+
import {
|
|
21
|
+
discardCurrentConversation,
|
|
22
|
+
endSession,
|
|
23
|
+
handleSessionEndHook,
|
|
24
|
+
handleStopHook,
|
|
25
|
+
handleUserPromptHook,
|
|
26
|
+
isMuted,
|
|
27
|
+
logAssistantMessage,
|
|
28
|
+
logUserMessage,
|
|
29
|
+
setMute,
|
|
30
|
+
switchConversation,
|
|
31
|
+
} from "#conversation/logger.ts";
|
|
32
|
+
import type { LoggerRuntime } from "#conversation/loggerRuntime.ts";
|
|
33
|
+
import {
|
|
34
|
+
sessionMaintenance,
|
|
35
|
+
sessionStart,
|
|
36
|
+
sessionStartFast,
|
|
37
|
+
} from "#conversation/sessionComposites.ts";
|
|
38
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
39
|
+
|
|
40
|
+
export interface LoggerCliResult {
|
|
41
|
+
stdout: string[];
|
|
42
|
+
stderr: string[];
|
|
43
|
+
exitCode: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface LoggerCliContext {
|
|
47
|
+
stdin?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Every subcommand `conversation_logger.main()` dispatches. */
|
|
51
|
+
export const CONVERSATION_LOGGER_SUBCOMMANDS = [
|
|
52
|
+
"mute",
|
|
53
|
+
"unmute",
|
|
54
|
+
"status",
|
|
55
|
+
"log-user",
|
|
56
|
+
"log-assistant",
|
|
57
|
+
"user-prompt",
|
|
58
|
+
"stop",
|
|
59
|
+
"discard-current",
|
|
60
|
+
"switch",
|
|
61
|
+
"session-end-pi",
|
|
62
|
+
"session-end",
|
|
63
|
+
"session-start",
|
|
64
|
+
"session-maintenance",
|
|
65
|
+
"diagnose-journeys",
|
|
66
|
+
"repair-journeys",
|
|
67
|
+
"backfill-codex-session",
|
|
68
|
+
] as const;
|
|
69
|
+
|
|
70
|
+
/** The subcommands whose Python path runs `end_conversation`'s LLM close tail. */
|
|
71
|
+
export const LLM_TAIL_SUBCOMMANDS: ReadonlySet<string> = new Set([
|
|
72
|
+
"switch",
|
|
73
|
+
"session-end-pi",
|
|
74
|
+
"session-end",
|
|
75
|
+
"session-start",
|
|
76
|
+
"session-maintenance",
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
/** Subcommands that read their JSON payload from stdin. */
|
|
80
|
+
export const STDIN_SUBCOMMANDS: ReadonlySet<string> = new Set([
|
|
81
|
+
"user-prompt",
|
|
82
|
+
"stop",
|
|
83
|
+
"session-end",
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
function extractOption(
|
|
87
|
+
args: string[],
|
|
88
|
+
name: string,
|
|
89
|
+
): { value: string | null; error: string | null } {
|
|
90
|
+
const index = args.indexOf(name);
|
|
91
|
+
if (index === -1) return { value: null, error: null };
|
|
92
|
+
if (index + 1 >= args.length) {
|
|
93
|
+
const noun = name === "--mirror-home" ? "a path" : name === "--limit" ? "a number" : "a value";
|
|
94
|
+
return { value: null, error: `Error: ${name} requires ${noun}` };
|
|
95
|
+
}
|
|
96
|
+
const value = args[index + 1] as string;
|
|
97
|
+
args.splice(index, 2);
|
|
98
|
+
return { value, error: null };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Python `"--interface" in args` followed by `args[idx + 1]` when present. */
|
|
102
|
+
function interfaceOption(args: readonly string[], fallback: string): string {
|
|
103
|
+
const index = args.indexOf("--interface");
|
|
104
|
+
return index !== -1 && index + 1 < args.length ? (args[index + 1] as string) : fallback;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const ok = (stdout: string[]): LoggerCliResult => ({
|
|
108
|
+
stdout,
|
|
109
|
+
stderr: [],
|
|
110
|
+
exitCode: 0,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
export async function runConversationLoggerCommand(
|
|
114
|
+
db: WritableDatabase,
|
|
115
|
+
argv: readonly string[],
|
|
116
|
+
runtime: LoggerRuntime,
|
|
117
|
+
context: LoggerCliContext = {},
|
|
118
|
+
): Promise<LoggerCliResult> {
|
|
119
|
+
const args = [...argv];
|
|
120
|
+
|
|
121
|
+
// Python strips --mirror-home and --session-id before dispatch, failing with
|
|
122
|
+
// exit 1 when either is present without a value.
|
|
123
|
+
const mirrorHome = extractOption(args, "--mirror-home");
|
|
124
|
+
if (mirrorHome.error) {
|
|
125
|
+
return { stdout: [], stderr: [mirrorHome.error], exitCode: 1 };
|
|
126
|
+
}
|
|
127
|
+
const sessionOption = extractOption(args, "--session-id");
|
|
128
|
+
if (sessionOption.error) {
|
|
129
|
+
return { stdout: [], stderr: [sessionOption.error], exitCode: 1 };
|
|
130
|
+
}
|
|
131
|
+
if (args.length === 0) {
|
|
132
|
+
return { stdout: [], stderr: [], exitCode: 1 };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const command = args[0] as string;
|
|
136
|
+
if (!(CONVERSATION_LOGGER_SUBCOMMANDS as readonly string[]).includes(command)) {
|
|
137
|
+
// Python's main() silently exits 0 on an unknown subcommand.
|
|
138
|
+
return ok([]);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const home = mirrorHome.value ?? runtime.mirrorHome;
|
|
142
|
+
const deps = runtime.deps;
|
|
143
|
+
|
|
144
|
+
switch (command) {
|
|
145
|
+
case "mute":
|
|
146
|
+
setMute(true, home);
|
|
147
|
+
return ok(["Conversation logging MUTED."]);
|
|
148
|
+
case "unmute":
|
|
149
|
+
setMute(false, home);
|
|
150
|
+
return ok(["Conversation logging ACTIVE."]);
|
|
151
|
+
case "status":
|
|
152
|
+
return ok([isMuted(home) ? "MUTED" : "ACTIVE"]);
|
|
153
|
+
|
|
154
|
+
case "user-prompt":
|
|
155
|
+
// `--interface` is the runtime the hook detected (US8); without it the
|
|
156
|
+
// label is Python's hook default.
|
|
157
|
+
handleUserPromptHook(
|
|
158
|
+
db,
|
|
159
|
+
context.stdin ?? "",
|
|
160
|
+
{ mirrorHome: home, interface: interfaceOption(args, "claude_code") },
|
|
161
|
+
deps,
|
|
162
|
+
);
|
|
163
|
+
// The hook is silent and always exits 0, whatever the outcome.
|
|
164
|
+
return ok([]);
|
|
165
|
+
|
|
166
|
+
case "stop": {
|
|
167
|
+
// The Stop hook's payload (US8): the turn's final answer, logged beside
|
|
168
|
+
// its prompt when one is waiting. Exit 0 whatever the outcome, and the
|
|
169
|
+
// outcome on stdout in one line: the hook entry runs this route
|
|
170
|
+
// in-process, reads the line, and forwards nothing -- a Stop hook that
|
|
171
|
+
// printed would keep the agent working on some runtimes -- while a
|
|
172
|
+
// person running the command from a shell sees what happened.
|
|
173
|
+
const outcome = handleStopHook(
|
|
174
|
+
db,
|
|
175
|
+
context.stdin ?? "",
|
|
176
|
+
{ mirrorHome: home, interface: interfaceOption(args, "claude_code") },
|
|
177
|
+
deps,
|
|
178
|
+
);
|
|
179
|
+
switch (outcome.action) {
|
|
180
|
+
case "logged":
|
|
181
|
+
return ok([`reply logged (${outcome.pairedBy})`]);
|
|
182
|
+
case "skipped":
|
|
183
|
+
return ok([`reply skipped: ${outcome.reason}`]);
|
|
184
|
+
case "muted":
|
|
185
|
+
return ok(["reply not logged: muted"]);
|
|
186
|
+
default:
|
|
187
|
+
// The error text is the fault's, never the payload's.
|
|
188
|
+
return ok([`reply failed: ${outcome.error}`]);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
case "session-end":
|
|
193
|
+
await handleSessionEndHook(
|
|
194
|
+
db,
|
|
195
|
+
context.stdin ?? "",
|
|
196
|
+
{
|
|
197
|
+
mirrorHome: home,
|
|
198
|
+
claudeProjectDir: runtime.claudeProjectDir,
|
|
199
|
+
homeDir: runtime.homeDir,
|
|
200
|
+
},
|
|
201
|
+
deps,
|
|
202
|
+
await runtime.closeHooks(),
|
|
203
|
+
);
|
|
204
|
+
return ok([]);
|
|
205
|
+
|
|
206
|
+
case "log-user":
|
|
207
|
+
case "log-assistant": {
|
|
208
|
+
const remaining = args.slice(1);
|
|
209
|
+
const interfaceName = extractOption(remaining, "--interface").value ?? "claude_code";
|
|
210
|
+
// Python silently does nothing with fewer than two positional arguments.
|
|
211
|
+
if (remaining.length >= 2) {
|
|
212
|
+
const [targetSession, content] = remaining as [string, string];
|
|
213
|
+
const write = command === "log-user" ? logUserMessage : logAssistantMessage;
|
|
214
|
+
write(db, targetSession, content, { interface: interfaceName }, deps);
|
|
215
|
+
}
|
|
216
|
+
return ok([]);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
case "switch": {
|
|
220
|
+
const conversationId = await switchConversation(
|
|
221
|
+
db,
|
|
222
|
+
sessionOption.value,
|
|
223
|
+
{ envSessionId: runtime.environmentSessionId },
|
|
224
|
+
deps,
|
|
225
|
+
await runtime.closeHooks(),
|
|
226
|
+
);
|
|
227
|
+
return ok([
|
|
228
|
+
conversationId ? `New conversation created: ${conversationId}` : "No active session found.",
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
case "session-start":
|
|
233
|
+
if (args.includes("--fast")) return ok([sessionStartFast(db, home, deps.nowIso)]);
|
|
234
|
+
return ok([await sessionStart(db, home, await runtime.maintenanceDeps())]);
|
|
235
|
+
|
|
236
|
+
case "session-maintenance":
|
|
237
|
+
return ok([await sessionMaintenance(db, await runtime.maintenanceDeps())]);
|
|
238
|
+
|
|
239
|
+
case "discard-current": {
|
|
240
|
+
const discarded = discardCurrentConversation(
|
|
241
|
+
db,
|
|
242
|
+
sessionOption.value,
|
|
243
|
+
{ interface: interfaceOption(args, "pi") },
|
|
244
|
+
deps,
|
|
245
|
+
);
|
|
246
|
+
return ok([
|
|
247
|
+
discarded
|
|
248
|
+
? `Discarded current conversation: ${discarded}`
|
|
249
|
+
: "No current conversation to discard.",
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
case "session-end-pi":
|
|
254
|
+
if (args.length >= 2) {
|
|
255
|
+
await endSession(
|
|
256
|
+
db,
|
|
257
|
+
args[1] as string,
|
|
258
|
+
{ extract: false },
|
|
259
|
+
deps,
|
|
260
|
+
await runtime.closeHooks(),
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return ok([]);
|
|
264
|
+
|
|
265
|
+
case "diagnose-journeys":
|
|
266
|
+
case "repair-journeys": {
|
|
267
|
+
const apply = command === "repair-journeys" && args.includes("--apply");
|
|
268
|
+
const limitOption = extractOption(args, "--limit");
|
|
269
|
+
if (limitOption.error) {
|
|
270
|
+
return { stdout: [], stderr: [limitOption.error], exitCode: 1 };
|
|
271
|
+
}
|
|
272
|
+
let limit: number | null = null;
|
|
273
|
+
if (limitOption.value !== null) {
|
|
274
|
+
// Python `int(value)` raises ValueError on anything but an integer.
|
|
275
|
+
if (!/^\s*[+-]?\d+\s*$/.test(limitOption.value)) {
|
|
276
|
+
return {
|
|
277
|
+
stdout: [],
|
|
278
|
+
stderr: [`ValueError: invalid literal for int() with base 10: '${limitOption.value}'`],
|
|
279
|
+
exitCode: 1,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
limit = Number.parseInt(limitOption.value, 10);
|
|
283
|
+
}
|
|
284
|
+
// Python prints backup()'s progress from inside the repair, BEFORE the
|
|
285
|
+
// findings; the lines are collected here so the order survives.
|
|
286
|
+
const backupLines: string[] = [];
|
|
287
|
+
const backup = runtime.backup;
|
|
288
|
+
const findings = diagnoseJourneyAssociations(db, {
|
|
289
|
+
limit,
|
|
290
|
+
apply,
|
|
291
|
+
...(apply && backup ? { backup: () => backup((line) => backupLines.push(line)) } : {}),
|
|
292
|
+
});
|
|
293
|
+
const lines = [
|
|
294
|
+
...backupLines,
|
|
295
|
+
...renderJourneyFindings(findings, apply).replace(/\n$/, "").split("\n"),
|
|
296
|
+
];
|
|
297
|
+
if (command === "repair-journeys" && !apply) {
|
|
298
|
+
lines.push("Dry run only. Re-run with --apply to repair after reviewing candidates.");
|
|
299
|
+
}
|
|
300
|
+
return ok(lines);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
case "backfill-codex-session": {
|
|
304
|
+
if (args.length < 2) return ok([]);
|
|
305
|
+
const path = args[1] as string;
|
|
306
|
+
const count = backfillCodexSession(
|
|
307
|
+
db,
|
|
308
|
+
{ jsonlPath: path, interface: interfaceOption(args, "codex") },
|
|
309
|
+
deps,
|
|
310
|
+
);
|
|
311
|
+
return ok([
|
|
312
|
+
count
|
|
313
|
+
? `Backfilled 1 Codex session from ${path}`
|
|
314
|
+
: `No new Codex session backfilled from ${path}`,
|
|
315
|
+
]);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
default:
|
|
319
|
+
return ok([]);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// The conversation-logger composition root (CV22.DS7.US10 slice F).
|
|
2
|
+
//
|
|
3
|
+
// Everything the `conversation-logger` subcommands need beyond the database
|
|
4
|
+
// is assembled here, once per invocation, from an EXPLICIT environment: the
|
|
5
|
+
// clock and id generator, the transcript/session resolution inputs, the Pi
|
|
6
|
+
// sessions directory, the pre-write backup, and -- only for the subcommands
|
|
7
|
+
// that cross the LLM close tail -- the replay providers and the maintenance
|
|
8
|
+
// dependencies built on them.
|
|
9
|
+
//
|
|
10
|
+
// The providers are loaded lazily. `diagnose-journeys`, `backfill-codex-session`,
|
|
11
|
+
// or `session-start --fast` must never fail because a replay fixture is not
|
|
12
|
+
// configured, and `switch` or `session-end` must fail loudly (and fall back
|
|
13
|
+
// to Python at the routing layer) when it is not: "unconfigured installs keep
|
|
14
|
+
// Python fallback" is the plan's live-cutover boundary, and this is where it
|
|
15
|
+
// is enforced on the TypeScript side.
|
|
16
|
+
//
|
|
17
|
+
// Nothing here reads `process.env` or `os.homedir()`; the front door passes
|
|
18
|
+
// them in, which is what keeps every test of this module hermetic.
|
|
19
|
+
|
|
20
|
+
import { backfillPiSessions, homeBornAt, resolvePiSessionsDir } from "#conversation/backfill.ts";
|
|
21
|
+
import { createCloseHooks, maybeGenerateTitle } from "#conversation/closeTail.ts";
|
|
22
|
+
import { runConversationExtraction } from "#conversation/extraction.ts";
|
|
23
|
+
import { runExtractionWithAccounting } from "#conversation/extractionRun.ts";
|
|
24
|
+
import { type CloseHooks, endConversation, type LoggerDeps } from "#conversation/logger.ts";
|
|
25
|
+
import type { MaintenanceDeps } from "#conversation/sessionComposites.ts";
|
|
26
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
27
|
+
import { logLlmCall } from "#observability/llmCalls.ts";
|
|
28
|
+
import {
|
|
29
|
+
resolveExtractionMaxAttempts,
|
|
30
|
+
resolveExtractionModel,
|
|
31
|
+
resolveMaintenanceMaxExtractions,
|
|
32
|
+
resolveSummarizeEnabled,
|
|
33
|
+
resolveTwoPassEnabled,
|
|
34
|
+
} from "#providers/config.ts";
|
|
35
|
+
import { computeCost } from "#providers/cost.ts";
|
|
36
|
+
import type { EmbeddingProvider } from "#providers/embedding.ts";
|
|
37
|
+
import { resolveFamilyProviders } from "#providers/familyProviders.ts";
|
|
38
|
+
import type { LlmProvider, LlmResponse } from "#providers/llm.ts";
|
|
39
|
+
import {
|
|
40
|
+
CONVERSATION_TAIL_TRANSPORT,
|
|
41
|
+
type ProviderTransportMode,
|
|
42
|
+
resolveProviderTransport,
|
|
43
|
+
} from "#providers/transport.ts";
|
|
44
|
+
|
|
45
|
+
/** The environment names the logger runtime reads. */
|
|
46
|
+
export type LoggerRuntimeEnv = {
|
|
47
|
+
MIRROR_SESSION_ID?: string;
|
|
48
|
+
CLAUDE_PROJECT_DIR?: string;
|
|
49
|
+
PI_SESSIONS_DIR?: string;
|
|
50
|
+
MIRROR_TS_CONVERSATION_LLM_REPLAY?: string;
|
|
51
|
+
MIRROR_TS_CONVERSATION_EMBEDDING_REPLAY?: string;
|
|
52
|
+
/** Read by the live providers when the close tail runs against a real model. */
|
|
53
|
+
OPENROUTER_API_KEY?: string;
|
|
54
|
+
MEMORY_LLM_TIMEOUT_EXTRACTION?: string;
|
|
55
|
+
MEMORY_LLM_MAX_RETRIES?: string;
|
|
56
|
+
MEMORY_EMBEDDING_MODEL?: string;
|
|
57
|
+
MEMORY_SUMMARIZE?: string;
|
|
58
|
+
MEMORY_TWO_PASS?: string;
|
|
59
|
+
MEMORY_MAINTENANCE_MAX_EXTRACTIONS?: string;
|
|
60
|
+
MEMORY_EXTRACTION_MAX_ATTEMPTS?: string;
|
|
61
|
+
MEMORY_EXTRACTION_MODEL?: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export interface LoggerRuntimeOptions {
|
|
65
|
+
db: WritableDatabase;
|
|
66
|
+
mirrorHome: string;
|
|
67
|
+
homeDir: string;
|
|
68
|
+
env: LoggerRuntimeEnv;
|
|
69
|
+
deps: LoggerDeps;
|
|
70
|
+
/**
|
|
71
|
+
* Live provider factory, injectable for tests (CV22.DS8.US2).
|
|
72
|
+
*
|
|
73
|
+
* `loadLlm`/`loadEmbeddings` below are REPLAY-path loaders and are not
|
|
74
|
+
* consulted in live mode, so without this seam no test could exercise the
|
|
75
|
+
* close tail against a failing or instrumented live provider -- which is the
|
|
76
|
+
* behavior this story exists to change.
|
|
77
|
+
*/
|
|
78
|
+
liveProviders?: (env: LoggerRuntimeEnv) => {
|
|
79
|
+
llm: LlmProvider;
|
|
80
|
+
embeddings: EmbeddingProvider;
|
|
81
|
+
};
|
|
82
|
+
/** Provider loaders, injectable for tests; default to the replay fixtures. */
|
|
83
|
+
loadLlm?: (path: string) => Promise<LlmProvider>;
|
|
84
|
+
loadEmbeddings?: (path: string) => Promise<EmbeddingProvider>;
|
|
85
|
+
/** Monotonic seconds for the maintenance report; defaults to `performance.now()`. */
|
|
86
|
+
monotonic?: () => number;
|
|
87
|
+
/**
|
|
88
|
+
* The dated zip backup `repair-journeys --apply` gates on (CV22.DS7.TS1).
|
|
89
|
+
* Prints its progress through `stdout` and returns the archive path, or
|
|
90
|
+
* null on failure. Absent (tests, unwired callers) means the repair refuses,
|
|
91
|
+
* exactly as Python refuses when `backup()` returns None.
|
|
92
|
+
*/
|
|
93
|
+
backup?: (stdout: (line: string) => void) => string | null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface LoggerRuntime {
|
|
97
|
+
readonly deps: LoggerDeps;
|
|
98
|
+
readonly mirrorHome: string;
|
|
99
|
+
readonly homeDir: string;
|
|
100
|
+
readonly claudeProjectDir: string | null;
|
|
101
|
+
readonly environmentSessionId: string | null;
|
|
102
|
+
readonly piSessionsDir: string;
|
|
103
|
+
/** Which transport answers the close tail here: replay, incomplete replay, or live. */
|
|
104
|
+
readonly transportMode: ProviderTransportMode;
|
|
105
|
+
/** The close hooks (extraction + finalization) behind the replay transport. */
|
|
106
|
+
closeHooks(): Promise<CloseHooks>;
|
|
107
|
+
/** The full maintenance wiring, including the real Pi backfill. */
|
|
108
|
+
maintenanceDeps(): Promise<MaintenanceDeps>;
|
|
109
|
+
/** The dated zip backup for the mutating journey repair; see `LoggerRuntimeOptions.backup`. */
|
|
110
|
+
readonly backup: ((stdout: (line: string) => void) => string | null) | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Adapt the close tail's PAIR-shaped live seam to the factory's per-kind
|
|
115
|
+
* overrides, memoized so one invocation builds one pair.
|
|
116
|
+
*
|
|
117
|
+
* The pair shape is load-bearing for tests: an atomicity test that fails the
|
|
118
|
+
* embedding on the second memory needs the same provider objects the close
|
|
119
|
+
* tail will call. Absent, the factory's own live defaults apply -- the default
|
|
120
|
+
* is not duplicated here.
|
|
121
|
+
*/
|
|
122
|
+
function liveTailOverrides(
|
|
123
|
+
env: LoggerRuntimeEnv,
|
|
124
|
+
liveProviders: LoggerRuntimeOptions["liveProviders"],
|
|
125
|
+
): { liveLlm?: () => LlmProvider; liveEmbedding?: () => EmbeddingProvider } {
|
|
126
|
+
if (!liveProviders) return {};
|
|
127
|
+
let pair: { llm: LlmProvider; embeddings: EmbeddingProvider } | null = null;
|
|
128
|
+
const build = () => {
|
|
129
|
+
pair ??= liveProviders(env);
|
|
130
|
+
return pair;
|
|
131
|
+
};
|
|
132
|
+
return { liveLlm: () => build().llm, liveEmbedding: () => build().embeddings };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function createLoggerRuntime(options: LoggerRuntimeOptions): LoggerRuntime {
|
|
136
|
+
const { db, env, deps } = options;
|
|
137
|
+
const piSessionsDir = resolvePiSessionsDir(null, env, options.homeDir);
|
|
138
|
+
|
|
139
|
+
// One precedence, shared with the router so the two cannot disagree about
|
|
140
|
+
// which transport is live: replay -> incomplete -> live. The pair rule that
|
|
141
|
+
// used to live here is now in the spec itself (CR077), so the router and
|
|
142
|
+
// this runtime refuse a half-configured fixture with the same reason.
|
|
143
|
+
const transport = resolveProviderTransport(env, CONVERSATION_TAIL_TRANSPORT);
|
|
144
|
+
|
|
145
|
+
let providers: Promise<{ llm: LlmProvider; embeddings: EmbeddingProvider }> | null = null;
|
|
146
|
+
const loadProviders = () => {
|
|
147
|
+
providers ??= resolveFamilyProviders(env, CONVERSATION_TAIL_TRANSPORT, {
|
|
148
|
+
loadReplayLlm: options.loadLlm,
|
|
149
|
+
loadReplayEmbedding: options.loadEmbeddings,
|
|
150
|
+
...liveTailOverrides(env, options.liveProviders),
|
|
151
|
+
}).then((family) => {
|
|
152
|
+
// The factory declares both kinds for this family, so both are present
|
|
153
|
+
// by construction.
|
|
154
|
+
const llm = family.llm;
|
|
155
|
+
const embeddings = family.embedding;
|
|
156
|
+
if (!llm || !embeddings) {
|
|
157
|
+
throw new Error("the conversation close tail requires an LLM and an embedding provider");
|
|
158
|
+
}
|
|
159
|
+
return { llm, embeddings };
|
|
160
|
+
});
|
|
161
|
+
return providers;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Python's `_make_logger(role, conversation_id)`: one ledger row per
|
|
165
|
+
// successful close-tail call, priced through the cost authority exactly as
|
|
166
|
+
// `build_llm_logger` prices it (CV22.DS8.US2).
|
|
167
|
+
//
|
|
168
|
+
// This is the sibling of `extraction.ts`'s llmLedger and was missed when
|
|
169
|
+
// that one was fixed: the close-tail METADATA roles (title, tags, summary)
|
|
170
|
+
// log through here, so they carried token counts and a null cost while the
|
|
171
|
+
// extraction roles were priced. Found by the live smoke on real data, not by
|
|
172
|
+
// a test -- under replay no usage comes back, so both look identical.
|
|
173
|
+
const ledger = (role: string, response: LlmResponse, conversationId: string, prompt: string) => {
|
|
174
|
+
const model = response.model ?? resolveExtractionModel({ env });
|
|
175
|
+
logLlmCall(
|
|
176
|
+
db,
|
|
177
|
+
{
|
|
178
|
+
role,
|
|
179
|
+
model,
|
|
180
|
+
prompt,
|
|
181
|
+
response: response.content,
|
|
182
|
+
promptTokens: response.promptTokens ?? null,
|
|
183
|
+
completionTokens: response.completionTokens ?? null,
|
|
184
|
+
latencyMs: response.latencyMs ?? null,
|
|
185
|
+
costUsd: computeCost(
|
|
186
|
+
model,
|
|
187
|
+
response.promptTokens ?? null,
|
|
188
|
+
response.completionTokens ?? null,
|
|
189
|
+
),
|
|
190
|
+
conversationId,
|
|
191
|
+
},
|
|
192
|
+
{ now: deps.nowIso },
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const maxAttempts = resolveExtractionMaxAttempts({ env });
|
|
197
|
+
const runExtraction = async (database: WritableDatabase, conversationId: string) => {
|
|
198
|
+
const { llm, embeddings } = await loadProviders();
|
|
199
|
+
await runExtractionWithAccounting(
|
|
200
|
+
database,
|
|
201
|
+
conversationId,
|
|
202
|
+
(innerDb, id) =>
|
|
203
|
+
runConversationExtraction(innerDb, id, {
|
|
204
|
+
llm,
|
|
205
|
+
embeddings,
|
|
206
|
+
now: deps.nowIso,
|
|
207
|
+
id: deps.newId,
|
|
208
|
+
summarize: resolveSummarizeEnabled({ env }),
|
|
209
|
+
twoPass: resolveTwoPassEnabled({ env }),
|
|
210
|
+
ledger: true,
|
|
211
|
+
}),
|
|
212
|
+
maxAttempts,
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const closeHooks = async (): Promise<CloseHooks> => {
|
|
217
|
+
const { llm } = await loadProviders();
|
|
218
|
+
return createCloseHooks({ llm, onLlmCall: ledger, now: deps.nowIso, runExtraction });
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
deps,
|
|
223
|
+
mirrorHome: options.mirrorHome,
|
|
224
|
+
homeDir: options.homeDir,
|
|
225
|
+
claudeProjectDir: env.CLAUDE_PROJECT_DIR || null,
|
|
226
|
+
environmentSessionId: env.MIRROR_SESSION_ID?.trim() || null,
|
|
227
|
+
piSessionsDir,
|
|
228
|
+
transportMode: transport.mode,
|
|
229
|
+
backup: options.backup ?? null,
|
|
230
|
+
closeHooks,
|
|
231
|
+
async maintenanceDeps(): Promise<MaintenanceDeps> {
|
|
232
|
+
const { llm } = await loadProviders();
|
|
233
|
+
const hooks = createCloseHooks({ llm, onLlmCall: ledger, now: deps.nowIso, runExtraction });
|
|
234
|
+
return {
|
|
235
|
+
closeConversation: (database, conversationId) =>
|
|
236
|
+
endConversation(database, conversationId, { extract: true }, deps, hooks),
|
|
237
|
+
retitleConversation: (database, conversationId) =>
|
|
238
|
+
maybeGenerateTitle(database, conversationId, {
|
|
239
|
+
llm,
|
|
240
|
+
onLlmCall: ledger,
|
|
241
|
+
now: deps.nowIso,
|
|
242
|
+
source: "startup_maintenance",
|
|
243
|
+
}),
|
|
244
|
+
runExtraction,
|
|
245
|
+
// CR121: only the sessions newer than this home; its birth is read from
|
|
246
|
+
// the ledger once per maintenance run, and an unknown birth is an error.
|
|
247
|
+
backfillPiSessions: (database) =>
|
|
248
|
+
backfillPiSessions(
|
|
249
|
+
database,
|
|
250
|
+
{ sessionsDir: piSessionsDir, notBefore: homeBornAt(database) },
|
|
251
|
+
deps,
|
|
252
|
+
),
|
|
253
|
+
extractionLimit: resolveMaintenanceMaxExtractions({ env }),
|
|
254
|
+
monotonic: options.monotonic,
|
|
255
|
+
now: deps.nowIso,
|
|
256
|
+
};
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|