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,220 @@
|
|
|
1
|
+
// Where is this Mirror installed, and what can update it? (CV22.DS10.US2)
|
|
2
|
+
//
|
|
3
|
+
// The updater's first question, answered from where the front door ITSELF
|
|
4
|
+
// lives rather than from configuration. A user who has to tell the updater how
|
|
5
|
+
// they installed Mirror can tell it wrong, and the answer decides whether the
|
|
6
|
+
// next step is `git merge --ff-only` or `npm install -g`.
|
|
7
|
+
//
|
|
8
|
+
// Three answers, and `unknown` is a real one: an install we cannot identify is
|
|
9
|
+
// refused with its reason printed, never updated on a guess.
|
|
10
|
+
|
|
11
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
12
|
+
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
13
|
+
|
|
14
|
+
export type InstallKind =
|
|
15
|
+
| { kind: "clone"; repository: string }
|
|
16
|
+
| { kind: "package"; root: string; name: string; version: string }
|
|
17
|
+
| { kind: "unknown"; reason: string };
|
|
18
|
+
|
|
19
|
+
export interface InstallKindProbe {
|
|
20
|
+
/** The front door's own resolved path. */
|
|
21
|
+
frontDoorPath: string;
|
|
22
|
+
/**
|
|
23
|
+
* `npm root -g`, resolved once by the caller, when the caller needs npm's
|
|
24
|
+
* word that `-g` addresses THIS install: the update lane does. Given as a
|
|
25
|
+
* string, a package must sit inside it. Omitted or `null` (npm not probed,
|
|
26
|
+
* or not available), a package is known by its layout alone -- see
|
|
27
|
+
* `packageByLayout` -- which is what the read-only routes ask, since they
|
|
28
|
+
* run where npm may not be on the PATH and must still say what this is.
|
|
29
|
+
*/
|
|
30
|
+
npmRootGlobal?: string | null;
|
|
31
|
+
exists?: (path: string) => boolean;
|
|
32
|
+
readFile?: (path: string) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Symlink resolution for the front door's path. `npm link` places a symlink
|
|
35
|
+
* named like the package under the global root, so a developer's checkout
|
|
36
|
+
* can be reached through a path that looks installed; what is updated must
|
|
37
|
+
* be the tree the file really lives in.
|
|
38
|
+
*/
|
|
39
|
+
realpath?: (path: string) => string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Is `child` inside `parent`, by path components rather than string prefix? */
|
|
43
|
+
function isInside(parent: string, child: string): boolean {
|
|
44
|
+
const base = resolve(parent);
|
|
45
|
+
const target = resolve(child);
|
|
46
|
+
return target === base || target.startsWith(base.endsWith(sep) ? base : base + sep);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The git work tree holding this front door, identified by the repository
|
|
51
|
+
* marker this project actually has: a root that carries `package.json` and a
|
|
52
|
+
* `.git` entry (the manifest moved to the root in CV22.DS10.US3, D2). Walking up rather than asking git keeps detection free of a
|
|
53
|
+
* subprocess and of git's own notion of "inside a work tree", which is true in
|
|
54
|
+
* places this updater must not touch (a submodule, a nested checkout).
|
|
55
|
+
*/
|
|
56
|
+
function cloneRootFor(startDir: string, exists: (path: string) => boolean): string | null {
|
|
57
|
+
let current = resolve(startDir);
|
|
58
|
+
for (;;) {
|
|
59
|
+
if (exists(join(current, ".git")) && exists(join(current, "package.json"))) {
|
|
60
|
+
return current;
|
|
61
|
+
}
|
|
62
|
+
const parent = dirname(current);
|
|
63
|
+
if (parent === current) return null;
|
|
64
|
+
current = parent;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface Manifest {
|
|
69
|
+
root: string;
|
|
70
|
+
name: string;
|
|
71
|
+
version: string;
|
|
72
|
+
bins: string[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The nearest manifest above the front door that names and versions a package. */
|
|
76
|
+
function nearestManifest(
|
|
77
|
+
frontDoorPath: string,
|
|
78
|
+
stopAt: string | null,
|
|
79
|
+
exists: (path: string) => boolean,
|
|
80
|
+
readFile: (path: string) => string,
|
|
81
|
+
): Manifest | null {
|
|
82
|
+
let current = resolve(dirname(frontDoorPath));
|
|
83
|
+
const stop = stopAt === null ? null : resolve(stopAt);
|
|
84
|
+
for (;;) {
|
|
85
|
+
const manifest = join(current, "package.json");
|
|
86
|
+
if (exists(manifest)) {
|
|
87
|
+
try {
|
|
88
|
+
const parsed = JSON.parse(readFile(manifest)) as {
|
|
89
|
+
name?: unknown;
|
|
90
|
+
version?: unknown;
|
|
91
|
+
bin?: unknown;
|
|
92
|
+
};
|
|
93
|
+
if (typeof parsed.name === "string" && typeof parsed.version === "string") {
|
|
94
|
+
const bins =
|
|
95
|
+
typeof parsed.bin === "string"
|
|
96
|
+
? [parsed.name]
|
|
97
|
+
: typeof parsed.bin === "object" && parsed.bin !== null
|
|
98
|
+
? Object.keys(parsed.bin)
|
|
99
|
+
: [];
|
|
100
|
+
return { root: current, name: parsed.name, version: parsed.version, bins };
|
|
101
|
+
}
|
|
102
|
+
} catch {
|
|
103
|
+
// A manifest we cannot read is not a package we should reinstall.
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (current === stop) return null;
|
|
108
|
+
const parent = dirname(current);
|
|
109
|
+
if (parent === current) return null;
|
|
110
|
+
current = parent;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The installed package holding this front door, by npm's own word: the
|
|
116
|
+
* manifest sits inside `npm root -g`.
|
|
117
|
+
*
|
|
118
|
+
* Being under SOME `node_modules/` is not enough, and the difference matters:
|
|
119
|
+
* a project-local dependency would detect as `package`, and `npm install -g`
|
|
120
|
+
* would then update a completely different tree from the one running. The
|
|
121
|
+
* global root is the evidence that `-g` addresses THIS install, which is why
|
|
122
|
+
* the update lane asks this way.
|
|
123
|
+
*/
|
|
124
|
+
function packageUnderNpmRoot(
|
|
125
|
+
frontDoorPath: string,
|
|
126
|
+
npmRootGlobal: string,
|
|
127
|
+
exists: (path: string) => boolean,
|
|
128
|
+
readFile: (path: string) => string,
|
|
129
|
+
realpath: (path: string) => string,
|
|
130
|
+
): InstallKind | null {
|
|
131
|
+
// Both sides resolved: the front door already is, and npm answers with
|
|
132
|
+
// the prefix as configured, symlinks and all (/tmp on macOS is one).
|
|
133
|
+
const root = realpath(resolve(npmRootGlobal));
|
|
134
|
+
if (!isInside(root, frontDoorPath)) return null;
|
|
135
|
+
const manifest = nearestManifest(frontDoorPath, root, exists, readFile);
|
|
136
|
+
if (manifest === null) return null;
|
|
137
|
+
return { kind: "package", root: manifest.root, name: manifest.name, version: manifest.version };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The installed package holding this front door, by its layout, with no
|
|
142
|
+
* subprocess: the manifest sits at `<prefix>/lib/node_modules/<name>` -- the
|
|
143
|
+
* global layout npm uses on every platform this core supports -- AND one of
|
|
144
|
+
* the manifest's bins exists at `<prefix>/bin/<bin>` and resolves back into
|
|
145
|
+
* the package. The bin is what makes a global install global; a project that
|
|
146
|
+
* happens to live at `<x>/lib` has the first half and not the second.
|
|
147
|
+
* (CV22.DS10.US3 plateau 4: the read-only routes run where npm may be off
|
|
148
|
+
* the PATH and must still say what this is.)
|
|
149
|
+
*/
|
|
150
|
+
function packageByLayout(
|
|
151
|
+
frontDoorPath: string,
|
|
152
|
+
exists: (path: string) => boolean,
|
|
153
|
+
readFile: (path: string) => string,
|
|
154
|
+
realpath: (path: string) => string,
|
|
155
|
+
): InstallKind | null {
|
|
156
|
+
const manifest = nearestManifest(frontDoorPath, null, exists, readFile);
|
|
157
|
+
if (manifest === null) return null;
|
|
158
|
+
const nodeModules = dirname(manifest.root);
|
|
159
|
+
const lib = dirname(nodeModules);
|
|
160
|
+
if (basename(nodeModules) !== "node_modules" || basename(lib) !== "lib") return null;
|
|
161
|
+
const prefix = dirname(lib);
|
|
162
|
+
const linked = manifest.bins.some((bin) => {
|
|
163
|
+
const link = join(prefix, "bin", bin);
|
|
164
|
+
return exists(link) && isInside(manifest.root, realpath(link));
|
|
165
|
+
});
|
|
166
|
+
if (!linked) return null;
|
|
167
|
+
return { kind: "package", root: manifest.root, name: manifest.name, version: manifest.version };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** `realpathSync`, except that a path that does not exist is returned as given. */
|
|
171
|
+
function safeRealpath(path: string): string {
|
|
172
|
+
try {
|
|
173
|
+
return realpathSync(path);
|
|
174
|
+
} catch {
|
|
175
|
+
return path;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function detectInstallKind(probe: InstallKindProbe): InstallKind {
|
|
180
|
+
const exists = probe.exists ?? existsSync;
|
|
181
|
+
const readFile = probe.readFile ?? ((path: string) => readFileSync(path, "utf8"));
|
|
182
|
+
const realpath = probe.realpath ?? safeRealpath;
|
|
183
|
+
const frontDoorPath = realpath(resolve(probe.frontDoorPath));
|
|
184
|
+
|
|
185
|
+
const asPackage = probe.npmRootGlobal
|
|
186
|
+
? packageUnderNpmRoot(frontDoorPath, probe.npmRootGlobal, exists, readFile, realpath)
|
|
187
|
+
: packageByLayout(frontDoorPath, exists, readFile, realpath);
|
|
188
|
+
if (asPackage !== null) return asPackage;
|
|
189
|
+
|
|
190
|
+
const repository = cloneRootFor(dirname(frontDoorPath), exists);
|
|
191
|
+
if (repository !== null) return { kind: "clone", repository };
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
kind: "unknown",
|
|
195
|
+
reason:
|
|
196
|
+
probe.npmRootGlobal === null
|
|
197
|
+
? "not a git checkout, and npm is unavailable to identify a package install"
|
|
198
|
+
: probe.npmRootGlobal === undefined
|
|
199
|
+
? "not a git checkout, and not laid out as a global npm install"
|
|
200
|
+
: "not a git checkout, and not under the global npm root",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** One line for a render or a log entry. */
|
|
205
|
+
export function describeInstallKind(install: InstallKind): string {
|
|
206
|
+
if (install.kind === "clone") return `clone (${install.repository})`;
|
|
207
|
+
if (install.kind === "package") return `package (${install.name}@${install.version})`;
|
|
208
|
+
return `unknown (${install.reason})`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The install, for `runtime status` and `runtime version`: the kind, and for
|
|
213
|
+
* a package the root `npm install -g` replaces, which its one-line form does
|
|
214
|
+
* not carry (US2 D3, deferred to CV22.DS10.US3 plateau 4).
|
|
215
|
+
*/
|
|
216
|
+
export function renderInstallLines(install: InstallKind): string[] {
|
|
217
|
+
const lines = [`Install: ${describeInstallKind(install)}`];
|
|
218
|
+
if (install.kind === "package") lines.push(`Install root: ${install.root}`);
|
|
219
|
+
return lines;
|
|
220
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// `runtime migrate` — apply pending migrations, and say what the ledger did.
|
|
2
|
+
// (CV22.DS10.US2, decision D8)
|
|
3
|
+
//
|
|
4
|
+
// This verb does not exist on the oracle, and adding it corrects the oracle.
|
|
5
|
+
// Python's updater calls `_apply_migrations` IN-PROCESS, which means it
|
|
6
|
+
// migrates the database with the code it just fast-forwarded away from: the
|
|
7
|
+
// interpreter has already imported the old modules, and a migration authored
|
|
8
|
+
// in the new commit is not among them. The TypeScript updater spawns this verb
|
|
9
|
+
// in a FRESH process after `apply`, so the code that migrates is the code that
|
|
10
|
+
// was just installed.
|
|
11
|
+
//
|
|
12
|
+
// It is also useful on its own, which is why it is a named verb rather than a
|
|
13
|
+
// private argv: when an update fails between `apply` and `migrate`, the
|
|
14
|
+
// operator needs a way to finish the job without running the whole pipeline.
|
|
15
|
+
//
|
|
16
|
+
// The ledger is printed before and after because "migrations: pass" is a claim
|
|
17
|
+
// and the `_migrations` rows are the evidence. A stage that infers a migration
|
|
18
|
+
// from "some command opened the database" is what the Plan review rejected.
|
|
19
|
+
|
|
20
|
+
import { existsSync } from "node:fs";
|
|
21
|
+
import { openDatabaseReadOnly } from "#db/database.ts";
|
|
22
|
+
import { ensureMigratedOnOpen, type MigrateVerdict } from "#db/migrateOnOpen.ts";
|
|
23
|
+
|
|
24
|
+
export interface MigrateOutcome {
|
|
25
|
+
dbPath: string;
|
|
26
|
+
before: string[];
|
|
27
|
+
after: string[];
|
|
28
|
+
applied: string[];
|
|
29
|
+
migrated: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The verdict, and the whole point of CV22.DS10.US2's debt D-025.
|
|
32
|
+
*
|
|
33
|
+
* There used to be two: migrated, or not. "Not" covered both `nothing
|
|
34
|
+
* pending` and a DECLINED migration, and both rendered as
|
|
35
|
+
* `Migrate result: nothing pending` with exit 0 -- so the updater's migrate
|
|
36
|
+
* stage passed on a database with pending work nothing had applied, on the
|
|
37
|
+
* one command whose job is to leave the database correct after an update.
|
|
38
|
+
*/
|
|
39
|
+
verdict: MigrateVerdict;
|
|
40
|
+
/** Why the engine declined, when it did. */
|
|
41
|
+
declinedReason: string | null;
|
|
42
|
+
backupPath: string | null;
|
|
43
|
+
error: string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Exit code for a declined migration: not success, not a crash. */
|
|
47
|
+
export const MIGRATE_DECLINED_EXIT = 1;
|
|
48
|
+
|
|
49
|
+
/** The `_migrations` ledger, sorted. `null` when it cannot be read at all. */
|
|
50
|
+
export function readLedger(dbPath: string): string[] | null {
|
|
51
|
+
if (!existsSync(dbPath)) return null;
|
|
52
|
+
let db: ReturnType<typeof openDatabaseReadOnly>;
|
|
53
|
+
try {
|
|
54
|
+
db = openDatabaseReadOnly(dbPath);
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const rows = db.prepare("SELECT id FROM _migrations").all() as { id: string }[];
|
|
60
|
+
return rows.map((row) => row.id).sort();
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
} finally {
|
|
64
|
+
db.close();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function runMigrate(dbPath: string): MigrateOutcome {
|
|
69
|
+
const before = readLedger(dbPath);
|
|
70
|
+
if (before === null) {
|
|
71
|
+
return {
|
|
72
|
+
dbPath,
|
|
73
|
+
before: [],
|
|
74
|
+
after: [],
|
|
75
|
+
applied: [],
|
|
76
|
+
migrated: false,
|
|
77
|
+
verdict: "declined",
|
|
78
|
+
declinedReason: null,
|
|
79
|
+
backupPath: null,
|
|
80
|
+
error: existsSync(dbPath)
|
|
81
|
+
? "database has no readable migration ledger"
|
|
82
|
+
: `database not found: ${dbPath}`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const result = ensureMigratedOnOpen(dbPath);
|
|
88
|
+
const after = readLedger(dbPath) ?? before;
|
|
89
|
+
return {
|
|
90
|
+
dbPath,
|
|
91
|
+
before,
|
|
92
|
+
after,
|
|
93
|
+
applied: [...result.appliedIds],
|
|
94
|
+
migrated: result.migrated,
|
|
95
|
+
verdict: result.verdict,
|
|
96
|
+
declinedReason: result.declinedReason ?? null,
|
|
97
|
+
backupPath: result.backupPath ?? null,
|
|
98
|
+
error: null,
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
dbPath,
|
|
103
|
+
before,
|
|
104
|
+
after: readLedger(dbPath) ?? before,
|
|
105
|
+
applied: [],
|
|
106
|
+
migrated: false,
|
|
107
|
+
verdict: "declined",
|
|
108
|
+
declinedReason: null,
|
|
109
|
+
backupPath: null,
|
|
110
|
+
error: error instanceof Error ? error.message.split("\n")[0] : String(error),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function renderMigrate(outcome: MigrateOutcome): string {
|
|
116
|
+
const lines: string[] = ["Mirror runtime migrate", ""];
|
|
117
|
+
lines.push(`Database: ${outcome.dbPath}`);
|
|
118
|
+
if (outcome.error !== null) {
|
|
119
|
+
lines.push(`Migration error: ${outcome.error}`);
|
|
120
|
+
lines.push("");
|
|
121
|
+
lines.push("Migrate result: failed");
|
|
122
|
+
return `${lines.join("\n")}\n`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// A standalone `runtime migrate` runs OUTSIDE the updater's backup-and-verify
|
|
126
|
+
// chain: its only pre-state is migrate-on-open's own snapshot, which uses one
|
|
127
|
+
// fixed name and is overwritten on each write. Inside the pipeline a verified
|
|
128
|
+
// archive was taken three stages earlier; run directly, this line is the only
|
|
129
|
+
// warning a user gets (CV22.DS10.US2 handoff review, security-engineer).
|
|
130
|
+
lines.push(`Ledger before: ${outcome.before.length} migration(s)`);
|
|
131
|
+
lines.push(`Ledger after: ${outcome.after.length} migration(s)`);
|
|
132
|
+
if (outcome.applied.length > 0) lines.push(`Applied: ${outcome.applied.join(", ")}`);
|
|
133
|
+
if (outcome.backupPath) lines.push(`Pre-migration snapshot: ${outcome.backupPath}`);
|
|
134
|
+
if (outcome.verdict === "declined" && outcome.declinedReason) {
|
|
135
|
+
lines.push(`Declined: ${outcome.declinedReason}.`);
|
|
136
|
+
}
|
|
137
|
+
if (!outcome.migrated) {
|
|
138
|
+
lines.push("Take a verified archive first if you are running this outside an update:");
|
|
139
|
+
lines.push(" runtime backup");
|
|
140
|
+
}
|
|
141
|
+
lines.push("");
|
|
142
|
+
// Three verdicts, three lines. `declined` is NOT `nothing pending`: the first
|
|
143
|
+
// says the engine refused work it could not safely do, the second that there
|
|
144
|
+
// was none. Conflating them is what let an update report a passing migrate
|
|
145
|
+
// stage on a database that had not been migrated.
|
|
146
|
+
lines.push(
|
|
147
|
+
outcome.verdict === "applied"
|
|
148
|
+
? `Migrate result: applied ${outcome.applied.length} migration(s)`
|
|
149
|
+
: outcome.verdict === "declined"
|
|
150
|
+
? "Migrate result: declined"
|
|
151
|
+
: "Migrate result: nothing pending",
|
|
152
|
+
);
|
|
153
|
+
return `${lines.join("\n")}\n`;
|
|
154
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// What identifies a Mirror Mind tree, and where its version comes from.
|
|
2
|
+
//
|
|
3
|
+
// CV22.DS10.TS5 plateau 1, decision D1. Until this story both answers were
|
|
4
|
+
// read out of `pyproject.toml`:
|
|
5
|
+
//
|
|
6
|
+
// * `packageVersion` walked upward for its `version =` line -- THE version,
|
|
7
|
+
// read by the updater, the release doctor, the welcome card,
|
|
8
|
+
// `runtime version|status`, the MCP server's `initialize`, and the Claude
|
|
9
|
+
// plugin builder (US2 decision D2: one body, so npm changes one place);
|
|
10
|
+
// * `isMirrorMindCheckout` identified a checkout as the first directory
|
|
11
|
+
// holding both `pyproject.toml` and `src/memory/`.
|
|
12
|
+
//
|
|
13
|
+
// The second one is why this module exists rather than a one-line edit.
|
|
14
|
+
// Deleting `src/memory/` would have silently disabled the production
|
|
15
|
+
// clone-role guard -- the check that stops Builder from mutating a production
|
|
16
|
+
// clone -- because the guard would simply stop recognizing the tree. No test
|
|
17
|
+
// would have failed. The inventory found it by reading; `cloneRoleGuard.test.ts`
|
|
18
|
+
// now pins it.
|
|
19
|
+
//
|
|
20
|
+
// So identity moves to the TypeScript package, and both answers come from one
|
|
21
|
+
// walk. CV22.DS10.US3 (decisions D1, D2) renamed the package to `mirror-mind`
|
|
22
|
+
// and moved the manifest to the repository root, so a checkout and an
|
|
23
|
+
// installed package have the same paths and one layout serves both.
|
|
24
|
+
|
|
25
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
26
|
+
import { dirname, join, resolve } from "node:path";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The npm package name that identifies this codebase, and the name
|
|
30
|
+
* `npm install -g` takes (CV22.DS10.US3, D1).
|
|
31
|
+
*
|
|
32
|
+
* It is checked rather than assumed so a stray `package.json` -- `.pi/`, a
|
|
33
|
+
* user's own project -- is never mistaken for Mirror Mind.
|
|
34
|
+
*/
|
|
35
|
+
export const PACKAGE_NAME = "mirror-mind";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Where the manifest and the front door sit relative to a tree root.
|
|
39
|
+
*
|
|
40
|
+
* One layout, because the repository IS the package (US3, D2): the manifest at
|
|
41
|
+
* the root and the front door at `ts/src/frontDoor/cli.ts`, in a checkout and
|
|
42
|
+
* under `npm root -g` alike. Until US3 a second candidate described a
|
|
43
|
+
* flattened install that was never published.
|
|
44
|
+
*/
|
|
45
|
+
const MANIFEST = "package.json";
|
|
46
|
+
const FRONT_DOOR = join("ts", "src", "frontDoor", "cli.ts");
|
|
47
|
+
|
|
48
|
+
export interface PackageIdentity {
|
|
49
|
+
/** The tree root: the directory the manifest was found relative to. */
|
|
50
|
+
readonly root: string;
|
|
51
|
+
/** The manifest's `name`, whatever it is. */
|
|
52
|
+
readonly name: string;
|
|
53
|
+
/** The manifest's `version`, or null when it has none. */
|
|
54
|
+
readonly version: string | null;
|
|
55
|
+
/** True when `name` is this codebase's. */
|
|
56
|
+
readonly isMirrorMind: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readIdentity(root: string): PackageIdentity | null {
|
|
60
|
+
const manifestPath = join(root, MANIFEST);
|
|
61
|
+
// BOTH markers, as Python required both `pyproject.toml` and `src/memory/`:
|
|
62
|
+
// a manifest alone is a file anyone can have, and the front door is what
|
|
63
|
+
// makes the tree this program.
|
|
64
|
+
if (!existsSync(manifestPath) || !existsSync(join(root, FRONT_DOOR))) return null;
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(readFileSync(manifestPath, "utf8")) as {
|
|
67
|
+
name?: unknown;
|
|
68
|
+
version?: unknown;
|
|
69
|
+
};
|
|
70
|
+
const name = typeof parsed.name === "string" ? parsed.name : "";
|
|
71
|
+
return {
|
|
72
|
+
root,
|
|
73
|
+
name,
|
|
74
|
+
version: typeof parsed.version === "string" ? parsed.version : null,
|
|
75
|
+
isMirrorMind: name === PACKAGE_NAME,
|
|
76
|
+
};
|
|
77
|
+
} catch {
|
|
78
|
+
// An unreadable or malformed manifest answers "not Mirror Mind" rather
|
|
79
|
+
// than continuing upward -- Python's `return False` inside the `except`,
|
|
80
|
+
// not a `continue`. A broken manifest is a broken tree, not an absent one.
|
|
81
|
+
return { root, name: "", version: null, isMirrorMind: false };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Walk upward for the nearest tree that carries a manifest AND a front door.
|
|
87
|
+
*
|
|
88
|
+
* **The walk STOPS at the first such directory, whatever it answers.** It does
|
|
89
|
+
* not keep climbing toward a tree that would say yes. That is Python's
|
|
90
|
+
* behavior for the pyproject/`src/memory` pair, and it is what makes a nested
|
|
91
|
+
* project decide for itself instead of inheriting its parent's identity.
|
|
92
|
+
*/
|
|
93
|
+
export function findPackageIdentity(start: string): PackageIdentity | null {
|
|
94
|
+
let current = resolve(start);
|
|
95
|
+
for (;;) {
|
|
96
|
+
const identity = readIdentity(current);
|
|
97
|
+
if (identity) return identity;
|
|
98
|
+
const parent = dirname(current);
|
|
99
|
+
if (parent === current) return null;
|
|
100
|
+
current = parent;
|
|
101
|
+
}
|
|
102
|
+
}
|