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,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ES-001 metadata-lifecycle WRITE faces — CV22.DS7.TS4 plateau 6.
|
|
3
|
+
*
|
|
4
|
+
* `conversations --metadata-lifecycle-apply <id> [--title/--summary/--tag]` and
|
|
5
|
+
* `--metadata-lifecycle-demo`, the two faces US11 refused by name and handed
|
|
6
|
+
* here (Navigator decision 2026-09-09, option B).
|
|
7
|
+
*
|
|
8
|
+
* This is the WRITE half of an engine already ported: every decision comes from
|
|
9
|
+
* `dryRunMetadataLifecycle`, and what lands here is the bounded application of
|
|
10
|
+
* those decisions. Three rules the corpus pinned and a reading of the code
|
|
11
|
+
* would not give:
|
|
12
|
+
*
|
|
13
|
+
* 1. **A decision is not a permission.** `create` and `repair` apply a title;
|
|
14
|
+
* `preserve` and `refine_candidate` each skip with their OWN reason, and
|
|
15
|
+
* any other decision skips as `decision_<name>_not_applied` — but only
|
|
16
|
+
* when a value was actually offered. With no value the reason is
|
|
17
|
+
* `no_value_provided`, which is a different fact and is reported as one.
|
|
18
|
+
* 2. **Tags ride the summary.** A `defer` tags decision still applies when a
|
|
19
|
+
* summary changed in the SAME call, because the deferral was waiting for
|
|
20
|
+
* exactly that substance. Alone, the same call skips.
|
|
21
|
+
* 3. **The flag is `--tag`, singular and repeatable.** There is no `--tags`;
|
|
22
|
+
* the parser appends into `dest="tags"`. A port written from the parameter
|
|
23
|
+
* name would expose an option Python refuses.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { ConversationLike, MetadataLifecycleReport } from "#conversation/metadataLifecycle.ts";
|
|
27
|
+
import type { WritableDatabase } from "#db/database.ts";
|
|
28
|
+
import { pythonJsonDumps } from "#util/pyGenerators.ts";
|
|
29
|
+
import { sliceCodePoints } from "#util/pythonText.ts";
|
|
30
|
+
import {
|
|
31
|
+
LifecycleFaceError,
|
|
32
|
+
metadataDict,
|
|
33
|
+
resolveConversation,
|
|
34
|
+
runLifecycleDryRun,
|
|
35
|
+
} from "./lifecycleFaces.ts";
|
|
36
|
+
|
|
37
|
+
export interface ApplyMetadataLifecycleInput {
|
|
38
|
+
title?: string | null;
|
|
39
|
+
summary?: string | null;
|
|
40
|
+
/** The repeated `--tag` values, or a pre-encoded string. */
|
|
41
|
+
tags?: readonly string[] | string | null;
|
|
42
|
+
source?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ApplyMetadataLifecycleReport {
|
|
46
|
+
conversation_id: string;
|
|
47
|
+
mode: "apply";
|
|
48
|
+
mutated: boolean;
|
|
49
|
+
changed: Record<string, unknown>;
|
|
50
|
+
skipped: Record<string, string>;
|
|
51
|
+
dry_run: MetadataLifecycleReport;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Port of `ConversationService._clean_title`. */
|
|
55
|
+
export function cleanTitle(title: string): string {
|
|
56
|
+
const clean = title.trim().split(/\s+/u).filter(Boolean).join(" ");
|
|
57
|
+
if (!clean) throw new LifecycleFaceError("title is required");
|
|
58
|
+
if (clean.length > 160) throw new LifecycleFaceError("title must be at most 160 characters");
|
|
59
|
+
return clean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Port of `ConversationService._title_metadata`.
|
|
64
|
+
*
|
|
65
|
+
* `previous_title` is recorded only when it differs from the one already
|
|
66
|
+
* stored, so repeated applies do not overwrite the ORIGINAL title with the one
|
|
67
|
+
* the previous apply wrote.
|
|
68
|
+
*/
|
|
69
|
+
export function titleMetadata(
|
|
70
|
+
metadata: Record<string, unknown>,
|
|
71
|
+
options: { source: string; status: string; previousTitle: string | null },
|
|
72
|
+
): Record<string, unknown> {
|
|
73
|
+
const next = { ...metadata };
|
|
74
|
+
if (options.previousTitle && options.previousTitle !== next.previous_title) {
|
|
75
|
+
next.previous_title = options.previousTitle;
|
|
76
|
+
}
|
|
77
|
+
next.title_source = options.source;
|
|
78
|
+
next.title_status = options.status;
|
|
79
|
+
return next;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Port of `ConversationService.apply_metadata_lifecycle`. */
|
|
83
|
+
export function applyMetadataLifecycle(
|
|
84
|
+
db: WritableDatabase,
|
|
85
|
+
conversationId: string,
|
|
86
|
+
input: ApplyMetadataLifecycleInput = {},
|
|
87
|
+
): ApplyMetadataLifecycleReport {
|
|
88
|
+
const source = input.source ?? "metadata_lifecycle_apply";
|
|
89
|
+
const conversation = resolveConversation(db, conversationId);
|
|
90
|
+
const dryRun = runLifecycleDryRun(db, conversation.id);
|
|
91
|
+
let metadata = metadataDict(conversation);
|
|
92
|
+
const updates: Record<string, string> = {};
|
|
93
|
+
const changed: Record<string, unknown> = {};
|
|
94
|
+
const skipped: Record<string, string> = {};
|
|
95
|
+
|
|
96
|
+
const title = input.title ?? null;
|
|
97
|
+
const titleDecision = String(dryRun.fields.title.decision);
|
|
98
|
+
if (titleDecision === "preserve") {
|
|
99
|
+
skipped.title = "manual_lock_preserved";
|
|
100
|
+
} else if (titleDecision === "refine_candidate") {
|
|
101
|
+
skipped.title = "candidate_decision_requires_explicit_review";
|
|
102
|
+
} else if ((titleDecision === "create" || titleDecision === "repair") && title !== null) {
|
|
103
|
+
const clean = cleanTitle(title);
|
|
104
|
+
updates.title = clean;
|
|
105
|
+
metadata = titleMetadata(metadata, {
|
|
106
|
+
source,
|
|
107
|
+
status: "generated",
|
|
108
|
+
previousTitle: conversation.title,
|
|
109
|
+
});
|
|
110
|
+
changed.title = clean;
|
|
111
|
+
} else if (title !== null) {
|
|
112
|
+
skipped.title = `decision_${titleDecision}_not_applied`;
|
|
113
|
+
} else {
|
|
114
|
+
skipped.title = "no_value_provided";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const summary = input.summary ?? null;
|
|
118
|
+
const summaryDecision = String(dryRun.fields.summary.decision);
|
|
119
|
+
if (summaryDecision === "create" && summary !== null) {
|
|
120
|
+
const clean = summary.trim();
|
|
121
|
+
if (clean) {
|
|
122
|
+
// Python truncates with a slice, which counts CODE POINTS. A UTF-16
|
|
123
|
+
// slice would cut an astral character in half at the boundary.
|
|
124
|
+
updates.summary = sliceCodePoints(clean, 1000);
|
|
125
|
+
metadata.summary_status = "generated";
|
|
126
|
+
changed.summary = updates.summary;
|
|
127
|
+
} else {
|
|
128
|
+
skipped.summary = "blank_value";
|
|
129
|
+
}
|
|
130
|
+
} else if (summary !== null) {
|
|
131
|
+
skipped.summary = `decision_${summaryDecision}_not_applied`;
|
|
132
|
+
} else {
|
|
133
|
+
skipped.summary = "no_value_provided";
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const tags = input.tags ?? null;
|
|
137
|
+
const tagsDecision = String(dryRun.fields.tags.decision);
|
|
138
|
+
// Rule 2: a deferral waits for substance, and a summary landing in this same
|
|
139
|
+
// call IS that substance.
|
|
140
|
+
const tagsReadyAfterSummary = tagsDecision === "defer" && "summary" in changed;
|
|
141
|
+
if ((tagsDecision === "create" || tagsReadyAfterSummary) && tags !== null) {
|
|
142
|
+
updates.tags = typeof tags === "string" ? tags : pythonJsonDumps([...tags]);
|
|
143
|
+
metadata.tags_status = "generated";
|
|
144
|
+
changed.tags = tags;
|
|
145
|
+
} else if (tags !== null) {
|
|
146
|
+
skipped.tags = `decision_${tagsDecision}_not_applied`;
|
|
147
|
+
} else {
|
|
148
|
+
skipped.tags = "no_value_provided";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (Object.keys(changed).length > 0) {
|
|
152
|
+
metadata.metadata_lifecycle_version = 1;
|
|
153
|
+
metadata.last_metadata_update_source = source;
|
|
154
|
+
updates.metadata = pythonJsonDumps(metadata);
|
|
155
|
+
updateConversation(db, conversation.id, updates);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
conversation_id: conversation.id,
|
|
160
|
+
mode: "apply",
|
|
161
|
+
mutated: Object.keys(changed).length > 0,
|
|
162
|
+
changed,
|
|
163
|
+
skipped,
|
|
164
|
+
dry_run: dryRun,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Port of `ConversationStore.update_conversation`: the given columns, nothing else. */
|
|
169
|
+
export function updateConversation(
|
|
170
|
+
db: WritableDatabase,
|
|
171
|
+
conversationId: string,
|
|
172
|
+
updates: Record<string, string>,
|
|
173
|
+
): void {
|
|
174
|
+
const columns = Object.keys(updates);
|
|
175
|
+
if (columns.length === 0) return;
|
|
176
|
+
const assignments = columns.map((column) => `${column} = ?`).join(", ");
|
|
177
|
+
db.prepare(`UPDATE conversations SET ${assignments} WHERE id = ?`).run(
|
|
178
|
+
...columns.map((column) => updates[column] as string),
|
|
179
|
+
conversationId,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The conversation columns the demo reports after applying. */
|
|
184
|
+
export interface ConversationAfter {
|
|
185
|
+
title: string | null;
|
|
186
|
+
summary: string | null;
|
|
187
|
+
tags: string | null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface MetadataLifecycleDemoReport {
|
|
191
|
+
mode: "metadata_lifecycle_demo";
|
|
192
|
+
uses_production_data: false;
|
|
193
|
+
passed: boolean;
|
|
194
|
+
checks: Record<string, boolean>;
|
|
195
|
+
scenarios: Record<string, unknown>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Port of `_metadata_lifecycle_demo_report`.
|
|
200
|
+
*
|
|
201
|
+
* A controlled scenario over a throwaway database: it proves the three
|
|
202
|
+
* decisions a reader most needs to trust — a provisional title is repaired, a
|
|
203
|
+
* manual lock is preserved, and a refine candidate is refused — and it touches
|
|
204
|
+
* no production data, which is the claim `uses_production_data: false` makes.
|
|
205
|
+
*
|
|
206
|
+
* The caller supplies the empty database, so the demo never decides where to
|
|
207
|
+
* write. Python's is `sqlite3.connect(":memory:")`.
|
|
208
|
+
*/
|
|
209
|
+
export function metadataLifecycleDemoReport(
|
|
210
|
+
db: WritableDatabase,
|
|
211
|
+
seed: DemoSeed,
|
|
212
|
+
): MetadataLifecycleDemoReport {
|
|
213
|
+
const repair = seed.startConversation("cli");
|
|
214
|
+
seed.setProvisionalTitle(repair, "vamos trabalhar no maestro");
|
|
215
|
+
seed.addMessage(repair, "user", "Vamos validar checkpoint visibility");
|
|
216
|
+
seed.addMessage(repair, "assistant", "Vamos revisar o handoff");
|
|
217
|
+
const preview = runLifecycleDryRun(db, repair);
|
|
218
|
+
const apply = applyMetadataLifecycle(db, repair, {
|
|
219
|
+
title: "Maestro checkpoint visibility validation",
|
|
220
|
+
summary: "Conversation metadata lifecycle validation.",
|
|
221
|
+
tags: ["metadata", "conversation"],
|
|
222
|
+
});
|
|
223
|
+
const afterApply = readConversation(db, repair);
|
|
224
|
+
|
|
225
|
+
const manual = seed.startConversation("cli", "Initial title");
|
|
226
|
+
seed.addMessage(manual, "user", "Quero corrigir títulos");
|
|
227
|
+
seed.addMessage(manual, "assistant", "Vamos desenhar a correção");
|
|
228
|
+
seed.updateTitle(manual, "Manual conversation title");
|
|
229
|
+
const manualApply = applyMetadataLifecycle(db, manual, {
|
|
230
|
+
title: "Generated replacement title",
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const refine = seed.startConversation("cli", "Initial editorial session");
|
|
234
|
+
seed.addMessage(refine, "user", "Let's begin");
|
|
235
|
+
seed.addMessage(refine, "assistant", "Ready");
|
|
236
|
+
updateConversation(db, refine, {
|
|
237
|
+
summary:
|
|
238
|
+
"Editorial workflow for Raphael Albino manuscript. Scrivener import, " +
|
|
239
|
+
"cover briefing, Kindle export, EPUB validation, chapter cleanup, raw text hygiene.",
|
|
240
|
+
});
|
|
241
|
+
const refineApply = applyMetadataLifecycle(db, refine, {
|
|
242
|
+
title: "Better editorial workflow title",
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const checks = {
|
|
246
|
+
preview_non_mutating: preview.mutated === false,
|
|
247
|
+
apply_changed_title: apply.changed.title === "Maestro checkpoint visibility validation",
|
|
248
|
+
manual_lock_preserved: manualApply.skipped.title === "manual_lock_preserved",
|
|
249
|
+
refine_candidate_skipped:
|
|
250
|
+
refineApply.skipped.title === "candidate_decision_requires_explicit_review",
|
|
251
|
+
};
|
|
252
|
+
return {
|
|
253
|
+
mode: "metadata_lifecycle_demo",
|
|
254
|
+
uses_production_data: false,
|
|
255
|
+
passed: Object.values(checks).every(Boolean),
|
|
256
|
+
checks,
|
|
257
|
+
scenarios: {
|
|
258
|
+
preview,
|
|
259
|
+
apply: {
|
|
260
|
+
report: apply,
|
|
261
|
+
after: {
|
|
262
|
+
title: afterApply?.title ?? null,
|
|
263
|
+
summary: afterApply?.summary ?? null,
|
|
264
|
+
tags: afterApply?.tags ?? null,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
manual_lock: manualApply,
|
|
268
|
+
refine_candidate: refineApply,
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** What the demo needs from the conversation writer, injected rather than reached for. */
|
|
274
|
+
export interface DemoSeed {
|
|
275
|
+
startConversation: (interfaceName: string, title?: string) => string;
|
|
276
|
+
addMessage: (conversationId: string, role: string, content: string) => void;
|
|
277
|
+
setProvisionalTitle: (conversationId: string, title: string) => void;
|
|
278
|
+
updateTitle: (conversationId: string, title: string) => void;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function readConversation(db: WritableDatabase, conversationId: string): ConversationAfter | null {
|
|
282
|
+
const row = db
|
|
283
|
+
.prepare("SELECT title, summary, tags FROM conversations WHERE id = ?")
|
|
284
|
+
.get(conversationId) as unknown as ConversationAfter | undefined;
|
|
285
|
+
return row ?? null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The two title writes the demo scripts, ported from `set_provisional_title`
|
|
290
|
+
* and `update_title`. Both go through `_title_metadata`, which is why a
|
|
291
|
+
* provisional title is later REPAIRABLE and a manual one is locked: the only
|
|
292
|
+
* difference on disk is `title_status`.
|
|
293
|
+
*/
|
|
294
|
+
export function writeTitle(
|
|
295
|
+
db: WritableDatabase,
|
|
296
|
+
conversationId: string,
|
|
297
|
+
title: string,
|
|
298
|
+
kind: "provisional" | "manual",
|
|
299
|
+
): void {
|
|
300
|
+
const conversation = resolveConversation(db, conversationId);
|
|
301
|
+
const clean = cleanTitle(title);
|
|
302
|
+
const metadata = titleMetadata(metadataDict(conversation), {
|
|
303
|
+
source: kind === "manual" ? "manual" : "first_user",
|
|
304
|
+
status: kind === "manual" ? "manual" : "provisional",
|
|
305
|
+
previousTitle: conversation.title,
|
|
306
|
+
});
|
|
307
|
+
updateConversation(db, conversation.id, {
|
|
308
|
+
title: clean,
|
|
309
|
+
metadata: pythonJsonDumps(metadata),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type { ConversationLike };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// `conversations` listing read — the port of Store.list_recent_conversation_summaries
|
|
2
|
+
// (memory.cli.conversations, the plain-listing path only). The metadata-lifecycle
|
|
3
|
+
// and backfill preview/apply flags on the same Python CLI are stateful writes
|
|
4
|
+
// (ES-001); routing.ts falls back to Python whenever any of those flags are
|
|
5
|
+
// present, so this module only ever serves the plain listing.
|
|
6
|
+
//
|
|
7
|
+
// Query-builder + row-mapper, ordering pushed down to SQLite, per the same
|
|
8
|
+
// database-seam philosophy as memory/listing.ts.
|
|
9
|
+
|
|
10
|
+
import type { Database, SqlValue } from "#db/database.ts";
|
|
11
|
+
import { optionalString, requireString } from "#db/rowDecode.ts";
|
|
12
|
+
|
|
13
|
+
export interface ConversationSummary {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string | null;
|
|
16
|
+
started_at: string | null;
|
|
17
|
+
persona: string | null;
|
|
18
|
+
journey: string | null;
|
|
19
|
+
message_count: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ListRecentConversationsFilters {
|
|
23
|
+
limit?: number;
|
|
24
|
+
journey?: string | null;
|
|
25
|
+
persona?: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build the parameterized recent-conversations query, mirroring the Python
|
|
30
|
+
* builder exactly: a `1=1` seed, `journey = ?` then `persona = ?` when
|
|
31
|
+
* provided (in that order), `ORDER BY started_at DESC`, trailing `LIMIT ?`.
|
|
32
|
+
*/
|
|
33
|
+
export function buildListRecentConversationsQuery(filters: ListRecentConversationsFilters = {}): {
|
|
34
|
+
sql: string;
|
|
35
|
+
params: SqlValue[];
|
|
36
|
+
} {
|
|
37
|
+
const { limit = 20, journey = null, persona = null } = filters;
|
|
38
|
+
const conditions = ["1=1"];
|
|
39
|
+
const params: SqlValue[] = [];
|
|
40
|
+
if (journey) {
|
|
41
|
+
conditions.push("journey = ?");
|
|
42
|
+
params.push(journey);
|
|
43
|
+
}
|
|
44
|
+
if (persona) {
|
|
45
|
+
conditions.push("persona = ?");
|
|
46
|
+
params.push(persona);
|
|
47
|
+
}
|
|
48
|
+
params.push(limit);
|
|
49
|
+
const sql =
|
|
50
|
+
"SELECT id, title, started_at, persona, journey, " +
|
|
51
|
+
"(SELECT COUNT(*) FROM messages WHERE conversation_id = c.id) as message_count " +
|
|
52
|
+
`FROM conversations c WHERE ${conditions.join(" AND ")} ORDER BY started_at DESC LIMIT ?`;
|
|
53
|
+
return { sql, params };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function toSummary(row: Record<string, unknown>): ConversationSummary {
|
|
57
|
+
return {
|
|
58
|
+
id: requireString(row, "id"),
|
|
59
|
+
title: optionalString(row, "title"),
|
|
60
|
+
started_at: optionalString(row, "started_at"),
|
|
61
|
+
persona: optionalString(row, "persona"),
|
|
62
|
+
journey: optionalString(row, "journey"),
|
|
63
|
+
message_count: Number(row.message_count),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Return recent conversation summaries with optional equality filters, newest first. */
|
|
68
|
+
export function listRecentConversationSummaries(
|
|
69
|
+
db: Database,
|
|
70
|
+
filters: ListRecentConversationsFilters = {},
|
|
71
|
+
): ConversationSummary[] {
|
|
72
|
+
const { sql, params } = buildListRecentConversationsQuery(filters);
|
|
73
|
+
return db
|
|
74
|
+
.prepare(sql)
|
|
75
|
+
.all(...params)
|
|
76
|
+
.map(toSummary);
|
|
77
|
+
}
|