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,200 @@
|
|
|
1
|
+
// The `clone` apply strategy: a git checkout following `origin/<channel>`.
|
|
2
|
+
// (CV22.DS10.US2)
|
|
3
|
+
//
|
|
4
|
+
// This is how every Mirror installed today receives code, and it stays the
|
|
5
|
+
// strategy for a checkout after npm distribution exists: the safety chain is
|
|
6
|
+
// the product's promise, and the transport underneath it is two git commands.
|
|
7
|
+
//
|
|
8
|
+
// Every git invocation goes through an injectable runner so the pipeline's
|
|
9
|
+
// decisions can be driven in tests without a remote, and so this module can be
|
|
10
|
+
// read as "what we ask git for" rather than "how we spawn it".
|
|
11
|
+
|
|
12
|
+
import { runGit } from "#runtime/git.ts";
|
|
13
|
+
import type { ApplyStrategy } from "#runtime/updatePipeline.ts";
|
|
14
|
+
|
|
15
|
+
export type GitRunner = (
|
|
16
|
+
args: readonly string[],
|
|
17
|
+
cwd: string,
|
|
18
|
+
) => { code: number; stdout: string; stderr: string };
|
|
19
|
+
|
|
20
|
+
export const defaultGitRunner: GitRunner = (args, cwd) => runGit([...args], cwd);
|
|
21
|
+
|
|
22
|
+
/** `origin/main` -> `["origin", "main"]`; anything else is refused. */
|
|
23
|
+
export function splitUpstream(upstream: string): [string, string] | null {
|
|
24
|
+
const index = upstream.indexOf("/");
|
|
25
|
+
if (index <= 0 || index === upstream.length - 1) return null;
|
|
26
|
+
const remote = upstream.slice(0, index);
|
|
27
|
+
const branch = upstream.slice(index + 1);
|
|
28
|
+
if (remote.startsWith("-") || branch.startsWith("-")) return null;
|
|
29
|
+
return [remote, branch];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The commit this install is on, read BEFORE anything moves. */
|
|
33
|
+
export function captureCommit(repository: string, git: GitRunner): string | null {
|
|
34
|
+
const result = git(["rev-parse", "--short", "HEAD"], repository);
|
|
35
|
+
const value = result.stdout.trim();
|
|
36
|
+
return result.code === 0 && value ? value : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function fetchUpstream(
|
|
40
|
+
repository: string,
|
|
41
|
+
upstream: string,
|
|
42
|
+
git: GitRunner,
|
|
43
|
+
): { ok: boolean; detail: string } {
|
|
44
|
+
const split = splitUpstream(upstream);
|
|
45
|
+
if (split === null) return { ok: false, detail: "unexpected upstream name" };
|
|
46
|
+
const [remote, branch] = split;
|
|
47
|
+
const result = git(["fetch", remote, branch], repository);
|
|
48
|
+
return result.code === 0
|
|
49
|
+
? { ok: true, detail: `${remote} ${branch}` }
|
|
50
|
+
: { ok: false, detail: result.stderr.trim() || "fetch failed" };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fast-forward only, never a merge. A clone that cannot fast-forward has local
|
|
55
|
+
* work or has diverged, and resolving that is a decision the updater must not
|
|
56
|
+
* take on someone's behalf.
|
|
57
|
+
*/
|
|
58
|
+
export function fastForward(
|
|
59
|
+
repository: string,
|
|
60
|
+
upstream: string,
|
|
61
|
+
git: GitRunner,
|
|
62
|
+
): { ok: boolean; detail: string } {
|
|
63
|
+
const result = git(["merge", "--ff-only", upstream], repository);
|
|
64
|
+
return result.code === 0
|
|
65
|
+
? { ok: true, detail: "" }
|
|
66
|
+
: { ok: false, detail: result.stderr.trim() || "fast-forward refused" };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** One-line subjects installed by this update, for the render. */
|
|
70
|
+
export function installedChanges(
|
|
71
|
+
repository: string,
|
|
72
|
+
previous: string | null,
|
|
73
|
+
next: string | null,
|
|
74
|
+
git: GitRunner,
|
|
75
|
+
): string[] {
|
|
76
|
+
if (!previous || !next || previous === next) return [];
|
|
77
|
+
const result = git(["log", "--oneline", "--no-decorate", `${previous}..${next}`], repository);
|
|
78
|
+
if (result.code !== 0) return [];
|
|
79
|
+
return result.stdout
|
|
80
|
+
.split("\n")
|
|
81
|
+
.map((line) => line.trim())
|
|
82
|
+
.filter(Boolean)
|
|
83
|
+
.slice(0, 20);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The pasteable route back, with the captured value in it. */
|
|
87
|
+
export function cloneRecoveryCommand(previous: string | null): string {
|
|
88
|
+
return previous === null ? "git reset --hard <previous commit>" : `git reset --hard ${previous}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function countCommits(repository: string, range: string, git: GitRunner): number | null {
|
|
92
|
+
const result = git(["rev-list", "--count", range], repository);
|
|
93
|
+
if (result.code !== 0) return null;
|
|
94
|
+
const value = Number.parseInt(result.stdout.trim(), 10);
|
|
95
|
+
return Number.isNaN(value) ? null : value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The clone's answers to the pipeline's questions. A ref is a short commit;
|
|
100
|
+
* the channel is `origin/<channel>`; moving is a fast-forward and nothing
|
|
101
|
+
* else; the way back is a hard reset to the captured commit.
|
|
102
|
+
*/
|
|
103
|
+
export function cloneStrategy(repository: string, upstream: string, git: GitRunner): ApplyStrategy {
|
|
104
|
+
return {
|
|
105
|
+
kind: "clone",
|
|
106
|
+
applyStage: "fast-forward",
|
|
107
|
+
|
|
108
|
+
// The ordinary gate reads the status report; a tree too broken for that
|
|
109
|
+
// still has one thing the repair lane can check without it.
|
|
110
|
+
repairGate: () => {
|
|
111
|
+
const dirty = git(["status", "--porcelain"], repository);
|
|
112
|
+
if (dirty.code !== 0 || dirty.stdout.trim() !== "") {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
detail: "git tree is dirty",
|
|
116
|
+
recovery: ["Commit or stash local changes, then retry runtime update --repair-updater."],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return { ok: true };
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
capture: () => {
|
|
123
|
+
const ref = captureCommit(repository, git);
|
|
124
|
+
return ref === null
|
|
125
|
+
? {
|
|
126
|
+
ok: false,
|
|
127
|
+
detail: "could not read the current commit",
|
|
128
|
+
recovery: ["Mirror must be a readable git checkout to update in place."],
|
|
129
|
+
}
|
|
130
|
+
: { ok: true, ref, detail: ref };
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
fetch: () => {
|
|
134
|
+
const fetched = fetchUpstream(repository, upstream, git);
|
|
135
|
+
return fetched.ok
|
|
136
|
+
? { ok: true, detail: fetched.detail }
|
|
137
|
+
: {
|
|
138
|
+
ok: false,
|
|
139
|
+
detail: fetched.detail,
|
|
140
|
+
recovery: [
|
|
141
|
+
"Check network connectivity and remote access.",
|
|
142
|
+
"Retry runtime update, or use --no-fetch to plan from local refs only.",
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
plan: (previousRef) => {
|
|
148
|
+
const ahead = countCommits(repository, `${upstream}..HEAD`, git);
|
|
149
|
+
const behind = countCommits(repository, `HEAD..${upstream}`, git);
|
|
150
|
+
if (ahead === null || behind === null) {
|
|
151
|
+
return {
|
|
152
|
+
kind: "blocked",
|
|
153
|
+
detail: `cannot compare against ${upstream}`,
|
|
154
|
+
recovery: [`Resolve upstream tracking for ${upstream}, then retry runtime update.`],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (ahead === 0 && behind === 0) return { kind: "current", detail: "already up to date" };
|
|
158
|
+
if (ahead > 0) {
|
|
159
|
+
return {
|
|
160
|
+
kind: "blocked",
|
|
161
|
+
detail: behind > 0 ? "branch diverged" : "local commits present",
|
|
162
|
+
recovery: [
|
|
163
|
+
behind > 0
|
|
164
|
+
? "Branch diverged; reconcile local and upstream commits manually."
|
|
165
|
+
: "Local branch is ahead of upstream; push or reset before updating.",
|
|
166
|
+
"The working tree and the database are unchanged.",
|
|
167
|
+
`Current commit: ${previousRef}`,
|
|
168
|
+
],
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
kind: "ahead",
|
|
173
|
+
target: upstream,
|
|
174
|
+
detail: `pull ${behind} remote commit(s)`,
|
|
175
|
+
dryRun: `would pull ${behind} commit(s) from ${upstream}`,
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
apply: (previousRef, target) => {
|
|
180
|
+
const applied = fastForward(repository, target, git);
|
|
181
|
+
if (!applied.ok) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
detail: applied.detail,
|
|
185
|
+
recovery: ["Working tree is unchanged because fast-forward refused."],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const newRef = captureCommit(repository, git);
|
|
189
|
+
return {
|
|
190
|
+
ok: true,
|
|
191
|
+
newRef,
|
|
192
|
+
detail: `${previousRef} -> ${newRef ?? "unknown"}`,
|
|
193
|
+
changes: installedChanges(repository, previousRef, newRef, git),
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
recoveryCommand: cloneRecoveryCommand,
|
|
198
|
+
installedState: (newRef) => `Code is on ${newRef ?? "the new commit"}`,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// The `package` apply strategy: a global npm install following a dist-tag.
|
|
2
|
+
// (CV22.DS10.US2)
|
|
3
|
+
//
|
|
4
|
+
// This is the mechanism npm distribution makes possible and the git updater
|
|
5
|
+
// never could: the Frame's command registry says so in its own words --
|
|
6
|
+
// `memory runtime update` "atualizaria só o clone, deixando o executável
|
|
7
|
+
// instalado operando contra uma minor futura sem contrato de
|
|
8
|
+
// compatibilidade". A versioned install is what that comment is waiting for.
|
|
9
|
+
//
|
|
10
|
+
// Every npm invocation goes through an injectable runner, like the git one, so
|
|
11
|
+
// the pipeline's decisions are testable without a registry.
|
|
12
|
+
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
|
+
import { type ApplyStrategy, KNOWN_CHANNELS } from "#runtime/updatePipeline.ts";
|
|
15
|
+
import { compareSemver, isPlainSemver } from "#util/semver.ts";
|
|
16
|
+
|
|
17
|
+
/** `cwd` matters to the one npm command that reads a tree, `publish`; the rest ignore it. */
|
|
18
|
+
export type NpmRunner = (
|
|
19
|
+
args: readonly string[],
|
|
20
|
+
cwd?: string,
|
|
21
|
+
) => {
|
|
22
|
+
code: number;
|
|
23
|
+
stdout: string;
|
|
24
|
+
stderr: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const defaultNpmRunner: NpmRunner = (args, cwd) => {
|
|
28
|
+
try {
|
|
29
|
+
const stdout = execFileSync("npm", [...args], {
|
|
30
|
+
encoding: "utf8",
|
|
31
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
32
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
33
|
+
});
|
|
34
|
+
return { code: 0, stdout, stderr: "" };
|
|
35
|
+
} catch (error) {
|
|
36
|
+
const shaped = error as { status?: number; stdout?: string; stderr?: string };
|
|
37
|
+
return {
|
|
38
|
+
code: shaped.status ?? -1,
|
|
39
|
+
stdout: shaped.stdout ?? "",
|
|
40
|
+
stderr: shaped.stderr ?? String(error),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** `npm root -g`, or null when npm is not usable. Resolved once per run. */
|
|
46
|
+
export function npmRootGlobal(npm: NpmRunner = defaultNpmRunner): string | null {
|
|
47
|
+
const result = npm(["root", "-g"]);
|
|
48
|
+
const value = result.stdout.trim();
|
|
49
|
+
return result.code === 0 && value ? value : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The package channel's location and reader live in `#runtime/channel.ts`
|
|
53
|
+
// with the clone's, since CV22.DS10.US3 plateau 4 gave both a writer.
|
|
54
|
+
|
|
55
|
+
export type DistTags = { ok: true; tags: Record<string, string> } | { ok: false; detail: string };
|
|
56
|
+
|
|
57
|
+
/** `npm view <name> dist-tags --json`, read once per run. */
|
|
58
|
+
export function readDistTags(name: string, npm: NpmRunner = defaultNpmRunner): DistTags {
|
|
59
|
+
const result = npm(["view", name, "dist-tags", "--json"]);
|
|
60
|
+
if (result.code !== 0)
|
|
61
|
+
return { ok: false, detail: firstLine(result.stderr) || "npm view failed" };
|
|
62
|
+
let parsed: unknown;
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(result.stdout);
|
|
65
|
+
} catch {
|
|
66
|
+
return { ok: false, detail: "npm view returned unreadable JSON" };
|
|
67
|
+
}
|
|
68
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
69
|
+
return { ok: false, detail: "npm view returned no dist-tags" };
|
|
70
|
+
}
|
|
71
|
+
const tags: Record<string, string> = {};
|
|
72
|
+
for (const [tag, value] of Object.entries(parsed as Record<string, unknown>)) {
|
|
73
|
+
if (typeof value === "string") tags[tag] = value;
|
|
74
|
+
}
|
|
75
|
+
return { ok: true, tags };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Resolve a dist-tag to a CONCRETE version before anything is installed.
|
|
80
|
+
*
|
|
81
|
+
* A bare `npm install -g name@stable` installs whatever the tag pointed at in
|
|
82
|
+
* that instant and reports nothing about it. Resolving first means the version
|
|
83
|
+
* is printed by `--check` and `--dry-run`, recorded in the stage detail and
|
|
84
|
+
* the log, and available as the value the recovery route needs. Following a
|
|
85
|
+
* mutable tag is the normal posture of `npm update -g`; being able to say what
|
|
86
|
+
* you got is the proportional control.
|
|
87
|
+
*
|
|
88
|
+
* The registry is a boundary. Its answer becomes the spec of
|
|
89
|
+
* `npm install -g <name>@<value>`, and npm's spec grammar admits tags, ranges,
|
|
90
|
+
* URLs, and paths beside versions, so a value that is not a plain version is
|
|
91
|
+
* refused here, before it is printed or installed (CV22.DS10.US3 plateau 4).
|
|
92
|
+
*/
|
|
93
|
+
function resolveFrom(
|
|
94
|
+
tags: Record<string, string>,
|
|
95
|
+
name: string,
|
|
96
|
+
channel: string,
|
|
97
|
+
): { ok: true; version: string } | { ok: false; detail: string } {
|
|
98
|
+
const version = tags[channel];
|
|
99
|
+
if (version === undefined || version === "") {
|
|
100
|
+
return { ok: false, detail: `no dist-tag '${channel}' for ${name}` };
|
|
101
|
+
}
|
|
102
|
+
if (!isPlainSemver(version)) {
|
|
103
|
+
return { ok: false, detail: `dist-tag '${channel}' is not a version: ${version}` };
|
|
104
|
+
}
|
|
105
|
+
return { ok: true, version };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Which way the channel lies from the installed version. Migrations run one
|
|
110
|
+
* way, so a channel BEHIND the install is not an update to take: it is a
|
|
111
|
+
* downgrade, refused at plan, and the person is told which channel carries
|
|
112
|
+
* what they have.
|
|
113
|
+
*/
|
|
114
|
+
export type ChannelDirection =
|
|
115
|
+
| { kind: "current"; version: string }
|
|
116
|
+
| { kind: "ahead"; version: string }
|
|
117
|
+
| { kind: "behind"; version: string; detail: string; carriedBy: string | null }
|
|
118
|
+
| { kind: "unresolved"; detail: string };
|
|
119
|
+
|
|
120
|
+
export function channelDirection(
|
|
121
|
+
install: { name: string; version: string },
|
|
122
|
+
channel: string,
|
|
123
|
+
npm: NpmRunner = defaultNpmRunner,
|
|
124
|
+
): ChannelDirection {
|
|
125
|
+
const read = readDistTags(install.name, npm);
|
|
126
|
+
if (!read.ok) return { kind: "unresolved", detail: read.detail };
|
|
127
|
+
const resolved = resolveFrom(read.tags, install.name, channel);
|
|
128
|
+
if (!resolved.ok) return { kind: "unresolved", detail: resolved.detail };
|
|
129
|
+
const order = compareSemver(resolved.version, install.version);
|
|
130
|
+
if (order === 0) return { kind: "current", version: resolved.version };
|
|
131
|
+
if (order > 0) return { kind: "ahead", version: resolved.version };
|
|
132
|
+
const carriedBy =
|
|
133
|
+
Object.entries(read.tags).find(
|
|
134
|
+
([tag, version]) =>
|
|
135
|
+
tag !== channel &&
|
|
136
|
+
KNOWN_CHANNELS.has(tag) &&
|
|
137
|
+
isPlainSemver(version) &&
|
|
138
|
+
compareSemver(version, install.version) >= 0,
|
|
139
|
+
)?.[0] ?? null;
|
|
140
|
+
return {
|
|
141
|
+
kind: "behind",
|
|
142
|
+
version: resolved.version,
|
|
143
|
+
detail: `'${channel}' is behind the installed version (${resolved.version} < ${install.version})`,
|
|
144
|
+
carriedBy,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// --- `runtime update --check` for a package ----------------------------------
|
|
149
|
+
|
|
150
|
+
export type PackageAvailabilityStatus =
|
|
151
|
+
| "up_to_date"
|
|
152
|
+
| "update_available"
|
|
153
|
+
| "channel_behind"
|
|
154
|
+
| "unresolved";
|
|
155
|
+
|
|
156
|
+
export interface PackageUpdateAvailability {
|
|
157
|
+
name: string;
|
|
158
|
+
installed: string;
|
|
159
|
+
channel: { value: string; note: string | null };
|
|
160
|
+
resolved: string | null;
|
|
161
|
+
status: PackageAvailabilityStatus;
|
|
162
|
+
note: string | null;
|
|
163
|
+
/** The known channel at or past the installed version, when this one is behind. */
|
|
164
|
+
carriedBy: string | null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function checkPackageUpdateAvailability(
|
|
168
|
+
install: { name: string; version: string },
|
|
169
|
+
channel: { value: string; note: string | null },
|
|
170
|
+
npm: NpmRunner = defaultNpmRunner,
|
|
171
|
+
): PackageUpdateAvailability {
|
|
172
|
+
const base = { name: install.name, installed: install.version, channel, carriedBy: null };
|
|
173
|
+
const direction = channelDirection(install, channel.value, npm);
|
|
174
|
+
switch (direction.kind) {
|
|
175
|
+
case "current":
|
|
176
|
+
return { ...base, resolved: direction.version, status: "up_to_date", note: null };
|
|
177
|
+
case "ahead":
|
|
178
|
+
return { ...base, resolved: direction.version, status: "update_available", note: null };
|
|
179
|
+
case "behind":
|
|
180
|
+
return {
|
|
181
|
+
...base,
|
|
182
|
+
resolved: direction.version,
|
|
183
|
+
status: "channel_behind",
|
|
184
|
+
note: direction.detail,
|
|
185
|
+
carriedBy: direction.carriedBy,
|
|
186
|
+
};
|
|
187
|
+
case "unresolved":
|
|
188
|
+
return { ...base, resolved: null, status: "unresolved", note: direction.detail };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** The package's counterpart of `renderRuntimeUpdateAvailability`, same shape. */
|
|
193
|
+
export function renderPackageUpdateAvailability(report: PackageUpdateAvailability): string {
|
|
194
|
+
const lines = ["Mirror runtime update check", ""];
|
|
195
|
+
lines.push(`Version: ${report.installed}`);
|
|
196
|
+
lines.push(`Install: package (${report.name}@${report.installed})`);
|
|
197
|
+
lines.push(`Update channel: ${report.channel.value}`);
|
|
198
|
+
if (report.channel.note) lines.push(`Update channel note: ${report.channel.note}`);
|
|
199
|
+
lines.push(`Channel version: ${report.resolved ?? "unresolved"}`);
|
|
200
|
+
lines.push(`Availability: ${report.status}`);
|
|
201
|
+
if (report.note) lines.push(`Reason: ${report.note}`);
|
|
202
|
+
if (report.status === "update_available") {
|
|
203
|
+
lines.push("");
|
|
204
|
+
lines.push("Preview:");
|
|
205
|
+
lines.push("runtime update --dry-run");
|
|
206
|
+
lines.push("");
|
|
207
|
+
lines.push("Update:");
|
|
208
|
+
lines.push("runtime update");
|
|
209
|
+
} else if (report.status === "up_to_date") {
|
|
210
|
+
lines.push("");
|
|
211
|
+
lines.push("Next: no update needed");
|
|
212
|
+
} else if (report.status === "channel_behind") {
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push(
|
|
215
|
+
report.carriedBy
|
|
216
|
+
? `Next: runtime channel ${report.carriedBy}`
|
|
217
|
+
: `Next: stay on ${report.installed} until '${report.channel.value}' reaches it`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return `${lines.join("\n")}\n`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Install one exact version globally. Never a bare tag. */
|
|
224
|
+
export function installGlobal(
|
|
225
|
+
name: string,
|
|
226
|
+
version: string,
|
|
227
|
+
npm: NpmRunner = defaultNpmRunner,
|
|
228
|
+
): { ok: boolean; detail: string } {
|
|
229
|
+
const result = npm(["install", "-g", `${name}@${version}`]);
|
|
230
|
+
return result.code === 0
|
|
231
|
+
? { ok: true, detail: `${name}@${version}` }
|
|
232
|
+
: { ok: false, detail: firstLine(result.stderr) || "npm install failed" };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** The pasteable route back, with the captured version in it. */
|
|
236
|
+
export function packageRecoveryCommand(name: string, previousVersion: string | null): string {
|
|
237
|
+
return previousVersion === null
|
|
238
|
+
? `npm install -g ${name}@<previous version>`
|
|
239
|
+
: `npm install -g ${name}@${previousVersion}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* The package's answers to the pipeline's questions. A ref is an installed
|
|
244
|
+
* version, read from the manifest before anything is installed over it (npm's
|
|
245
|
+
* global install is not atomic, so a pinned reinstall is the only rollback
|
|
246
|
+
* there is); the channel is a dist-tag resolved to a concrete version at plan
|
|
247
|
+
* time; moving is one global install of exactly that version; the way back is
|
|
248
|
+
* the same install of the captured one. Nothing is fetched: the registry is
|
|
249
|
+
* asked once, at plan.
|
|
250
|
+
*/
|
|
251
|
+
export function packageStrategy(
|
|
252
|
+
install: { name: string; version: string },
|
|
253
|
+
channel: string,
|
|
254
|
+
npm: NpmRunner,
|
|
255
|
+
): ApplyStrategy {
|
|
256
|
+
return {
|
|
257
|
+
kind: "package",
|
|
258
|
+
applyStage: "apply",
|
|
259
|
+
|
|
260
|
+
// A package has no tree to be dirty: the status gate is the only gate, and
|
|
261
|
+
// the repair lane simply forgoes it.
|
|
262
|
+
repairGate: () => ({ ok: true }),
|
|
263
|
+
|
|
264
|
+
capture: () => ({
|
|
265
|
+
ok: true,
|
|
266
|
+
ref: install.version,
|
|
267
|
+
detail: `${install.name}@${install.version}`,
|
|
268
|
+
}),
|
|
269
|
+
|
|
270
|
+
plan: (previousRef) => {
|
|
271
|
+
const direction = channelDirection(
|
|
272
|
+
{ name: install.name, version: previousRef },
|
|
273
|
+
channel,
|
|
274
|
+
npm,
|
|
275
|
+
);
|
|
276
|
+
switch (direction.kind) {
|
|
277
|
+
case "unresolved":
|
|
278
|
+
return {
|
|
279
|
+
kind: "blocked",
|
|
280
|
+
detail: direction.detail,
|
|
281
|
+
recovery: [
|
|
282
|
+
`Could not resolve the '${channel}' dist-tag for ${install.name}.`,
|
|
283
|
+
"Check network access to the npm registry, then retry runtime update.",
|
|
284
|
+
],
|
|
285
|
+
};
|
|
286
|
+
case "current":
|
|
287
|
+
return { kind: "current", detail: `already up to date (${direction.version})` };
|
|
288
|
+
case "behind":
|
|
289
|
+
return {
|
|
290
|
+
kind: "blocked",
|
|
291
|
+
detail: direction.detail,
|
|
292
|
+
recovery: [
|
|
293
|
+
"A downgrade is refused: migrations do not run backwards.",
|
|
294
|
+
direction.carriedBy
|
|
295
|
+
? `Follow the channel that carries ${previousRef}: runtime channel ${direction.carriedBy}`
|
|
296
|
+
: `Stay on ${previousRef} until '${channel}' reaches it.`,
|
|
297
|
+
"Nothing was installed and the database is unchanged.",
|
|
298
|
+
],
|
|
299
|
+
};
|
|
300
|
+
case "ahead":
|
|
301
|
+
return {
|
|
302
|
+
kind: "ahead",
|
|
303
|
+
target: direction.version,
|
|
304
|
+
detail: `${previousRef} -> ${direction.version}`,
|
|
305
|
+
dryRun: `would install ${install.name}@${direction.version}`,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
apply: (_previousRef, target) => {
|
|
311
|
+
const applied = installGlobal(install.name, target, npm);
|
|
312
|
+
return applied.ok
|
|
313
|
+
? { ok: true, newRef: target, detail: applied.detail, changes: [] }
|
|
314
|
+
: {
|
|
315
|
+
ok: false,
|
|
316
|
+
detail: applied.detail,
|
|
317
|
+
recovery: ["A global npm install is not atomic; this one did not complete."],
|
|
318
|
+
};
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
recoveryCommand: (previousRef) => packageRecoveryCommand(install.name, previousRef),
|
|
322
|
+
installedState: (newRef) => `${install.name}@${newRef ?? "<unknown>"} is installed`,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function firstLine(text: string): string {
|
|
327
|
+
return text.trim().split("\n")[0] ?? "";
|
|
328
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// The tree that holds the running program. CV22.DS10.US3 plateau 1.
|
|
2
|
+
//
|
|
3
|
+
// Three readers used to locate the tree three ways: `init` walked up from its
|
|
4
|
+
// own file for `templates/identity`; `runtime release-notes` asked
|
|
5
|
+
// `git rev-parse --show-toplevel` and fell back to the cwd; the welcome card
|
|
6
|
+
// read `<cwd>/docs/releases/<version>.md`. Only the first worked for an
|
|
7
|
+
// installed package, and the third answered for whatever directory the person
|
|
8
|
+
// happened to be in. Now there is one answer, from the same walk the version
|
|
9
|
+
// and the checkout guard already use (`packageIdentity.ts`), anchored at this
|
|
10
|
+
// file -- so it is the tree the code came from, in a checkout, through
|
|
11
|
+
// `npm link`, or under `npm root -g` alike. Never the cwd, never git.
|
|
12
|
+
|
|
13
|
+
import { findPackageIdentity } from "./packageIdentity.ts";
|
|
14
|
+
|
|
15
|
+
export class TreeRootNotFoundError extends Error {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The root of the tree this module was loaded from: the directory holding the
|
|
19
|
+
* manifest and the front door. Throws when there is none, which means the
|
|
20
|
+
* program is running from a copy that is not a Mirror Mind tree at all.
|
|
21
|
+
*/
|
|
22
|
+
export function runningTreeRoot(): string {
|
|
23
|
+
const identity = findPackageIdentity(import.meta.dirname);
|
|
24
|
+
if (identity === null) {
|
|
25
|
+
throw new TreeRootNotFoundError(
|
|
26
|
+
`no Mirror Mind tree holds ${import.meta.filename}: package.json and ts/src/frontDoor/cli.ts not found above it`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return identity.root;
|
|
30
|
+
}
|