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,306 @@
|
|
|
1
|
+
// What the npm tarball may hold, checked rather than trusted. CV22.DS10.US3
|
|
2
|
+
// plateau 1, the artifact half of DS10's Zero Python gate.
|
|
3
|
+
//
|
|
4
|
+
// `files` in the manifest is a whitelist, and npm adds a few things on its
|
|
5
|
+
// own (README, LICENSE, the manifest). Nothing here repeats that list: this
|
|
6
|
+
// guard asks whether the packed inventory is the RUNTIME SUBSET and nothing
|
|
7
|
+
// else -- every runtime's integration files present, every entry point
|
|
8
|
+
// present, no test, golden, smoke, eval, scratch, environment file, database,
|
|
9
|
+
// Python, Windows product, or spike; and no install lifecycle script, so that
|
|
10
|
+
// installing Mirror is a file copy. The retired-surface guard proves the
|
|
11
|
+
// tree's code spawns no interpreter; this one proves the shipped files carry
|
|
12
|
+
// none.
|
|
13
|
+
//
|
|
14
|
+
// Pure over an inventory, so it can be graded on synthetic lists; the script
|
|
15
|
+
// feeds it `npm pack --dry-run --json`.
|
|
16
|
+
|
|
17
|
+
import { INTERPRETER_INVOCATIONS } from "#guards/retiredSurfaces.ts";
|
|
18
|
+
import { PACKAGE_NAME } from "#runtime/packageIdentity.ts";
|
|
19
|
+
|
|
20
|
+
/** Directory prefixes (with trailing slash) and exact files the tarball may contain. */
|
|
21
|
+
export const ALLOWED_PREFIXES: readonly string[] = [
|
|
22
|
+
"bin/",
|
|
23
|
+
"ts/src/",
|
|
24
|
+
"templates/",
|
|
25
|
+
"docs/releases/",
|
|
26
|
+
".pi/extensions/",
|
|
27
|
+
".pi/skills/",
|
|
28
|
+
".claude/hooks/",
|
|
29
|
+
".gemini/hooks/",
|
|
30
|
+
"plugins/mirror-mind/",
|
|
31
|
+
"scripts/codex-hooks/",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export const ALLOWED_FILES: readonly string[] = [
|
|
35
|
+
"package.json",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"AGENTS.md",
|
|
39
|
+
"ts/README.md",
|
|
40
|
+
"scripts/codex-mirror.sh",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/** Files that must be in every tarball: the entries and one of each runtime's wiring. */
|
|
44
|
+
export const REQUIRED_FILES: readonly string[] = [
|
|
45
|
+
"package.json",
|
|
46
|
+
"README.md",
|
|
47
|
+
"LICENSE",
|
|
48
|
+
"AGENTS.md",
|
|
49
|
+
"bin/loader.js",
|
|
50
|
+
"bin/mirror.js",
|
|
51
|
+
"bin/mirror-hook.js",
|
|
52
|
+
"ts/src/frontDoor/cli.ts",
|
|
53
|
+
"ts/src/hooks/main.ts",
|
|
54
|
+
"ts/src/mcp/main.ts",
|
|
55
|
+
".pi/extensions/mirror-logger.ts",
|
|
56
|
+
".pi/skills/mm-mirror/SKILL.md",
|
|
57
|
+
".claude/hooks/session-start.sh",
|
|
58
|
+
".gemini/hooks/session-start.sh",
|
|
59
|
+
"plugins/mirror-mind/mcp/launch.sh",
|
|
60
|
+
"scripts/codex-hooks/session-start.sh",
|
|
61
|
+
"scripts/codex-mirror.sh",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/** Prefixes that must have at least one file: content the program reads at runtime. */
|
|
65
|
+
export const REQUIRED_PREFIXES: readonly string[] = ["templates/identity/", "docs/releases/"];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* What must never ship, by path. Each is a class the first panel named or a
|
|
69
|
+
* file the Zero Python gate forbids. A path matching any of these fails even
|
|
70
|
+
* when it sits under an allowed prefix (a `.test.ts` inside `ts/src/`, say).
|
|
71
|
+
*/
|
|
72
|
+
export const FORBIDDEN_PATTERNS: readonly { pattern: RegExp; why: string }[] = [
|
|
73
|
+
{
|
|
74
|
+
pattern: /(^|\/)ts\/(test|smoke|evals|parity)\//,
|
|
75
|
+
why: "tests, smokes, evals, and parity tooling",
|
|
76
|
+
},
|
|
77
|
+
{ pattern: /\.test\.ts$/, why: "a test file" },
|
|
78
|
+
{ pattern: /(^|\/)goldens?\//, why: "a golden" },
|
|
79
|
+
{ pattern: /^tmp\//, why: "scratch" },
|
|
80
|
+
{ pattern: /(^|\/)\.env(\.|$)/, why: "an environment file" },
|
|
81
|
+
{ pattern: /\.(db|sqlite|sqlite3)$/, why: "a database" },
|
|
82
|
+
{ pattern: /\.(py|pyc)$/, why: "Python" },
|
|
83
|
+
{ pattern: /(^|\/)(pyproject\.toml|uv\.lock|requirements[^/]*\.txt)$/, why: "Python packaging" },
|
|
84
|
+
{ pattern: /^(frame|installer)\//, why: "the Windows product" },
|
|
85
|
+
{ pattern: /^(spikes|examples)\//, why: "spikes and examples" },
|
|
86
|
+
{ pattern: /(^|\/)node_modules\//, why: "dependencies belong to npm, not the tarball" },
|
|
87
|
+
{ pattern: /(^|\/)\.git(\/|$)/, why: "git metadata" },
|
|
88
|
+
{ pattern: /\.(tgz|zip|exe|dmg)$/, why: "a binary artifact" },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
/** Lifecycle scripts npm would run on install. Installing Mirror is a file copy. */
|
|
92
|
+
export const FORBIDDEN_SCRIPTS: readonly string[] = [
|
|
93
|
+
"preinstall",
|
|
94
|
+
"install",
|
|
95
|
+
"postinstall",
|
|
96
|
+
"prepare",
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
export interface PackManifest {
|
|
100
|
+
name?: unknown;
|
|
101
|
+
version?: unknown;
|
|
102
|
+
private?: unknown;
|
|
103
|
+
bin?: unknown;
|
|
104
|
+
files?: unknown;
|
|
105
|
+
scripts?: unknown;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface PackInventory {
|
|
109
|
+
/** Paths as `npm pack --dry-run --json` lists them, relative to the package root. */
|
|
110
|
+
readonly files: readonly string[];
|
|
111
|
+
readonly manifest: PackManifest;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The file list in `npm pack --dry-run --json`'s output, whichever shape npm
|
|
116
|
+
* printed it in: npm 11 prints an array of packed packages, npm 12 an object
|
|
117
|
+
* keyed by package name. The release workflow's first run (2026-10-10) met
|
|
118
|
+
* the second with a reader written for the first and graded an EMPTY
|
|
119
|
+
* inventory -- every required file "missing" -- which is at least loud; an
|
|
120
|
+
* inventory with no files is never a valid answer, so it throws rather than
|
|
121
|
+
* letting a future reader grade nothing as clean.
|
|
122
|
+
*/
|
|
123
|
+
export function parsePackDryRun(raw: string): string[] {
|
|
124
|
+
const parsed: unknown = JSON.parse(raw);
|
|
125
|
+
const entries: unknown[] = Array.isArray(parsed)
|
|
126
|
+
? parsed
|
|
127
|
+
: parsed !== null && typeof parsed === "object"
|
|
128
|
+
? Object.values(parsed)
|
|
129
|
+
: [];
|
|
130
|
+
const first = entries[0];
|
|
131
|
+
const files =
|
|
132
|
+
first !== null &&
|
|
133
|
+
typeof first === "object" &&
|
|
134
|
+
Array.isArray((first as { files?: unknown }).files)
|
|
135
|
+
? ((first as { files: { path?: unknown }[] }).files ?? [])
|
|
136
|
+
: [];
|
|
137
|
+
const paths = files
|
|
138
|
+
.map((entry) => entry.path)
|
|
139
|
+
.filter((path): path is string => typeof path === "string");
|
|
140
|
+
if (paths.length === 0) {
|
|
141
|
+
throw new Error("npm pack --dry-run --json listed no files; the inventory cannot be graded");
|
|
142
|
+
}
|
|
143
|
+
return paths;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* What no shipped file may say, wherever it sits. Paths are graded above; this
|
|
148
|
+
* grades content, because a file can be in the runtime subset and still carry
|
|
149
|
+
* something that must not reach another person's machine.
|
|
150
|
+
*
|
|
151
|
+
* The runtime subset is read by whoever installed Mirror -- their agent loads
|
|
152
|
+
* the skills and AGENTS.md -- so it addresses them, never the mirror's first
|
|
153
|
+
* owner. US3 F4 found two skills telling every user's agent to present its
|
|
154
|
+
* proposals to the author by first name. The author is credited where that is
|
|
155
|
+
* the point, the license and the README.
|
|
156
|
+
*
|
|
157
|
+
* The second rule is the artifact half of DS10's Zero Python gate (US3
|
|
158
|
+
* plateau 5). The retired-surface guard proves the TREE spawns no interpreter,
|
|
159
|
+
* and the path rules above prove the tarball carries no Python file; this
|
|
160
|
+
* proves no shipped file tells an agent or a person to run the deleted core.
|
|
161
|
+
* The forms are the retired-surface guard's own list, imported, so the two
|
|
162
|
+
* halves cannot drift. Two places may still carry them: `docs/releases/`, each
|
|
163
|
+
* version's record of what it said and what was removed, which `runtime
|
|
164
|
+
* release-notes` shows as written; and the guard whose patterns ARE the data.
|
|
165
|
+
*
|
|
166
|
+
* Each pattern is written so that this file, which ships too, never matches
|
|
167
|
+
* it. An `allowedIn` entry ending in `/` is a prefix.
|
|
168
|
+
*/
|
|
169
|
+
export const FORBIDDEN_CONTENT: readonly {
|
|
170
|
+
pattern: RegExp;
|
|
171
|
+
why: string;
|
|
172
|
+
allowedIn: readonly string[];
|
|
173
|
+
}[] = [
|
|
174
|
+
{
|
|
175
|
+
pattern: /Vin[ií]cius/i,
|
|
176
|
+
why: "names the author; shipped instructions address whoever installed Mirror",
|
|
177
|
+
allowedIn: ["LICENSE", "README.md"],
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
pattern: new RegExp(INTERPRETER_INVOCATIONS.join("|")),
|
|
181
|
+
why: "tells someone to run the Python core, deleted by CV22.DS10.TS5; the artifact carries none",
|
|
182
|
+
allowedIn: ["docs/releases/", "ts/src/guards/retiredSurfaces.ts"],
|
|
183
|
+
},
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
function allowedToSay(rule: { allowedIn: readonly string[] }, path: string): boolean {
|
|
187
|
+
return rule.allowedIn.some((entry) =>
|
|
188
|
+
entry.endsWith("/") ? path.startsWith(entry) : path === entry,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** One shipped file, as the content check reads it. */
|
|
193
|
+
export interface PackedFile {
|
|
194
|
+
readonly path: string;
|
|
195
|
+
readonly content: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface PackProblem {
|
|
199
|
+
readonly code:
|
|
200
|
+
| "forbidden_path"
|
|
201
|
+
| "forbidden_content"
|
|
202
|
+
| "unlisted_path"
|
|
203
|
+
| "missing_file"
|
|
204
|
+
| "missing_prefix"
|
|
205
|
+
| "lifecycle_script"
|
|
206
|
+
| "manifest";
|
|
207
|
+
readonly message: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function allowed(path: string): boolean {
|
|
211
|
+
return ALLOWED_FILES.includes(path) || ALLOWED_PREFIXES.some((prefix) => path.startsWith(prefix));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Every way the inventory departs from the runtime subset, in a stable order. */
|
|
215
|
+
export function checkPackContents(inventory: PackInventory): PackProblem[] {
|
|
216
|
+
const problems: PackProblem[] = [];
|
|
217
|
+
const files = [...inventory.files].sort();
|
|
218
|
+
const present = new Set(files);
|
|
219
|
+
|
|
220
|
+
for (const path of files) {
|
|
221
|
+
const forbidden = FORBIDDEN_PATTERNS.find(({ pattern }) => pattern.test(path));
|
|
222
|
+
if (forbidden) {
|
|
223
|
+
problems.push({ code: "forbidden_path", message: `${path}: ${forbidden.why}` });
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (!allowed(path)) {
|
|
227
|
+
problems.push({ code: "unlisted_path", message: `${path}: not in the runtime subset` });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
for (const path of REQUIRED_FILES) {
|
|
232
|
+
if (!present.has(path)) problems.push({ code: "missing_file", message: `${path}: required` });
|
|
233
|
+
}
|
|
234
|
+
for (const prefix of REQUIRED_PREFIXES) {
|
|
235
|
+
if (!files.some((path) => path.startsWith(prefix))) {
|
|
236
|
+
problems.push({ code: "missing_prefix", message: `${prefix}: nothing under it` });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const { manifest } = inventory;
|
|
241
|
+
if (manifest.name !== PACKAGE_NAME) {
|
|
242
|
+
problems.push({
|
|
243
|
+
code: "manifest",
|
|
244
|
+
message: `name: ${JSON.stringify(manifest.name)} is not ${PACKAGE_NAME}`,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (manifest.private === true) {
|
|
248
|
+
problems.push({ code: "manifest", message: "private: true; the package cannot be published" });
|
|
249
|
+
}
|
|
250
|
+
if (!Array.isArray(manifest.files) || manifest.files.length === 0) {
|
|
251
|
+
problems.push({ code: "manifest", message: "files: missing; the tarball is not whitelisted" });
|
|
252
|
+
}
|
|
253
|
+
const bin = manifest.bin;
|
|
254
|
+
if (
|
|
255
|
+
typeof bin !== "object" ||
|
|
256
|
+
bin === null ||
|
|
257
|
+
typeof (bin as { mirror?: unknown }).mirror !== "string"
|
|
258
|
+
) {
|
|
259
|
+
problems.push({ code: "manifest", message: "bin.mirror: missing" });
|
|
260
|
+
} else {
|
|
261
|
+
const entry = (bin as { mirror: string }).mirror.replace(/^\.\//, "");
|
|
262
|
+
if (!present.has(entry)) {
|
|
263
|
+
problems.push({ code: "manifest", message: `bin.mirror: ${entry} is not in the tarball` });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const scripts = manifest.scripts;
|
|
267
|
+
if (typeof scripts === "object" && scripts !== null) {
|
|
268
|
+
for (const name of FORBIDDEN_SCRIPTS) {
|
|
269
|
+
if (name in scripts) {
|
|
270
|
+
problems.push({
|
|
271
|
+
code: "lifecycle_script",
|
|
272
|
+
message: `scripts.${name}: npm would run it on install; installing Mirror is a file copy`,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return problems;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Every forbidden line in the shipped files, as `path:line: why`, in a stable order. */
|
|
282
|
+
export function checkPackedContent(files: readonly PackedFile[]): PackProblem[] {
|
|
283
|
+
const problems: PackProblem[] = [];
|
|
284
|
+
for (const file of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
285
|
+
for (const rule of FORBIDDEN_CONTENT) {
|
|
286
|
+
if (allowedToSay(rule, file.path)) continue;
|
|
287
|
+
file.content.split("\n").forEach((line, index) => {
|
|
288
|
+
if (rule.pattern.test(line)) {
|
|
289
|
+
problems.push({
|
|
290
|
+
code: "forbidden_content",
|
|
291
|
+
message: `${file.path}:${index + 1}: ${rule.why}`,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return problems;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export function renderPackVerdict(problems: readonly PackProblem[], fileCount: number): string {
|
|
301
|
+
if (problems.length === 0) {
|
|
302
|
+
return `pack contents: clean -- ${fileCount} files, the runtime subset and nothing else; no install script; no forbidden content.\n`;
|
|
303
|
+
}
|
|
304
|
+
const lines = problems.map((problem) => ` ${problem.code}: ${problem.message}`);
|
|
305
|
+
return `pack contents: ${problems.length} problem(s)\n${lines.join("\n")}\n`;
|
|
306
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Skills with one body in every runtime (CR102).
|
|
2
|
+
//
|
|
3
|
+
// Most Mirror skills have two authored bodies. `.pi/skills/` serves Pi, and
|
|
4
|
+
// through the `.agents/skills/` links Codex and Gemini CLI too. `.claude/skills/`
|
|
5
|
+
// serves Claude Code, and `claudePlugin.ts` copies it into the plugin. CR071
|
|
6
|
+
// kept the two apart on purpose: Usage sections, example language, and in
|
|
7
|
+
// `mm-soul` and `mm-mirror` whole lines that are true for one runtime only.
|
|
8
|
+
//
|
|
9
|
+
// `mm-build` had no such line, and its two bodies drifted anyway. By 2026-09-27
|
|
10
|
+
// the Claude Code copy was 108 lines against Pi's 1093, with no activation
|
|
11
|
+
// boundary, no journey binding, and no Ariad. So a skill in this list has one
|
|
12
|
+
// body: its Pi copy is the only one anyone edits, and `claudePlugin.ts`
|
|
13
|
+
// generates both Claude Code copies from it with this module's transform.
|
|
14
|
+
//
|
|
15
|
+
// A skill joins the list only when its Pi body is true in every runtime, which
|
|
16
|
+
// is a decision to record in `docs/project/decisions.md`, not a refactoring.
|
|
17
|
+
|
|
18
|
+
export const PI_SKILLS_DIR = ".pi/skills";
|
|
19
|
+
|
|
20
|
+
/** Skills whose Claude Code copies are generated from the Pi copy. */
|
|
21
|
+
export const PI_SOURCED_SKILLS: readonly string[] = ["mm-build"];
|
|
22
|
+
|
|
23
|
+
const MIRROR_PREFIX = "mm-";
|
|
24
|
+
|
|
25
|
+
/** The Claude Code name of a Mirror skill: `mm-build` is `mm:build` (CR071). */
|
|
26
|
+
export function claudeSkillName(skill: string): string {
|
|
27
|
+
if (!skill.startsWith(MIRROR_PREFIX)) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`${skill} is not a Mirror skill: its name does not start with ${MIRROR_PREFIX}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return `mm:${skill.slice(MIRROR_PREFIX.length)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The Claude Code copy of a Pi-sourced skill: the Pi text with its frontmatter
|
|
37
|
+
* `name` line rewritten, and every other byte unchanged.
|
|
38
|
+
*
|
|
39
|
+
* Refuses, naming `sourcePath`, unless the frontmatter holds exactly one `name`
|
|
40
|
+
* line and it names this skill as every Mirror skill does. A transform that
|
|
41
|
+
* guessed would write a wrong name into a file nobody edits by hand.
|
|
42
|
+
*/
|
|
43
|
+
export function claudeVariant(skill: string, piText: string, sourcePath: string): string {
|
|
44
|
+
const lines = piText.split("\n");
|
|
45
|
+
const close = lines.indexOf("---", 1);
|
|
46
|
+
if (lines[0] !== "---" || close === -1) {
|
|
47
|
+
throw new Error(`${sourcePath}: has no frontmatter`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const expected = `name: "${skill}"`;
|
|
51
|
+
const nameLines = lines
|
|
52
|
+
.slice(1, close)
|
|
53
|
+
.map((line, offset) => ({ line, index: offset + 1 }))
|
|
54
|
+
.filter(({ line }) => line.startsWith("name:"));
|
|
55
|
+
if (nameLines.length !== 1 || nameLines[0].line !== expected) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`${sourcePath}: expected exactly one frontmatter line \`${expected}\`, ` +
|
|
58
|
+
`found ${describeFound(nameLines.map(({ line }) => line))}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
lines[nameLines[0].index] = `name: "${claudeSkillName(skill)}"`;
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function describeFound(nameLines: readonly string[]): string {
|
|
67
|
+
if (nameLines.length === 0) return "none";
|
|
68
|
+
if (nameLines.length > 1) return String(nameLines.length);
|
|
69
|
+
return `\`${nameLines[0]}\``;
|
|
70
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// A retired shape must route, underneath its retired entry, like any name
|
|
2
|
+
// nobody claims (CV22.DS10.TS5, inventory F2).
|
|
3
|
+
//
|
|
4
|
+
// TS4 added the `retired` route and matched it BEFORE dispatch, so the family
|
|
5
|
+
// branches that used to answer the same shapes became unreachable -- and stayed
|
|
6
|
+
// in the file, because a branch the front door can never reach is invisible to
|
|
7
|
+
// every test that goes through the front door. Two of them survived into TS5:
|
|
8
|
+
// the backfill flags and the twenty Workbench verbs, each still routed to
|
|
9
|
+
// Python by name.
|
|
10
|
+
//
|
|
11
|
+
// The file-scanning guard cannot see this. Its `sqlite-refinement-workbench`
|
|
12
|
+
// row exempts `routing.ts` whole, because the retired entries legitimately
|
|
13
|
+
// name the verbs they refuse -- and a file-level exemption is blind to
|
|
14
|
+
// everything else in that file (TS2's lesson). So this check asks the router
|
|
15
|
+
// instead: route each retired shape with the retired match removed, route an
|
|
16
|
+
// unclaimed sibling that differs only in its final token, and require the two
|
|
17
|
+
// decisions to be the same. A family branch keyed on the retired token is the
|
|
18
|
+
// only thing that can make them differ.
|
|
19
|
+
|
|
20
|
+
import { RETIRED_SURFACES, type RetiredSurface, type RouteDecision } from "#frontDoor/routing.ts";
|
|
21
|
+
|
|
22
|
+
/** A final token no family names, so the sibling reaches whatever answers the unclaimed. */
|
|
23
|
+
const UNCLAIMED_TOKEN = "__retired_route_sibling__";
|
|
24
|
+
|
|
25
|
+
export interface ShadowedRetiredRoute {
|
|
26
|
+
/** The retired shape, as its entry names it. */
|
|
27
|
+
readonly surface: string;
|
|
28
|
+
/** What the family branch underneath answers for it -- a route decision reason, never argv. */
|
|
29
|
+
readonly reason: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Every retired shape that some family branch still claims by name.
|
|
34
|
+
*
|
|
35
|
+
* `route` is the family router without the retired match -- `routeByFamily` in
|
|
36
|
+
* production, a fake in the guard's own test, so the check can be seen to fire.
|
|
37
|
+
* Reasons are compared with the sibling's placeholder restored to the retired
|
|
38
|
+
* token, because a generic answer such as `unknown runtime subcommand: <name>`
|
|
39
|
+
* legitimately echoes whichever name it was given.
|
|
40
|
+
*/
|
|
41
|
+
export function shadowedRetiredRoutes(
|
|
42
|
+
route: (argv: readonly string[]) => RouteDecision,
|
|
43
|
+
surfaces: readonly RetiredSurface[] = RETIRED_SURFACES,
|
|
44
|
+
): ShadowedRetiredRoute[] {
|
|
45
|
+
const shadowed: ShadowedRetiredRoute[] = [];
|
|
46
|
+
for (const entry of surfaces) {
|
|
47
|
+
const argv = entry.surface.split(" ");
|
|
48
|
+
const token = argv[argv.length - 1] ?? "";
|
|
49
|
+
const underneath = route(argv);
|
|
50
|
+
const unclaimed = route([...argv.slice(0, -1), UNCLAIMED_TOKEN]);
|
|
51
|
+
const unclaimedReason = unclaimed.reason.split(UNCLAIMED_TOKEN).join(token);
|
|
52
|
+
if (underneath.engine !== unclaimed.engine || underneath.reason !== unclaimedReason) {
|
|
53
|
+
shadowed.push({ surface: entry.surface, reason: underneath.reason });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return shadowed;
|
|
57
|
+
}
|