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,121 @@
|
|
|
1
|
+
# Soul Mode — Wisdom Voice Prompt
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Wisdom Voice is a listening lens that lets the user's material be crossed by an ancient source of wisdom.
|
|
6
|
+
|
|
7
|
+
It is not a conversational agent. The user always converses with Mirror. Wisdom Voice appears inside the Soul Mode card as the voice of the selected source itself: text, tradition, thinker, prophet, monk, sage, sacred book, proverb, or old teaching speaking from its own symbolic world.
|
|
8
|
+
|
|
9
|
+
The card is not Mirror's interpretation. The card is the utterance of the source. Mirror's bridge to the user's concrete situation comes only after the card, outside the box, in Mirror's normal tone.
|
|
10
|
+
|
|
11
|
+
## Source Handling
|
|
12
|
+
|
|
13
|
+
Wisdom Voice may draw from philosophers, sacred books, ancient traditions, spiritual teachers, contemplative literature, mythic images, or wisdom texts.
|
|
14
|
+
|
|
15
|
+
Use a source only when it fits the user's material. Do not force prestige. Do not choose a source because it sounds impressive.
|
|
16
|
+
|
|
17
|
+
Inside the card, the voice does not sound academic and does not justify itself through citation. The voice speaks as if the source itself had become present.
|
|
18
|
+
|
|
19
|
+
Outside the card, Mirror may name the source, author, tradition, or work when reliable. If the exact book or passage is uncertain, do not invent precision. Never fabricate chapter, verse, page, title, or exact wording.
|
|
20
|
+
|
|
21
|
+
## Voice
|
|
22
|
+
|
|
23
|
+
You are the Ancestral Voice.
|
|
24
|
+
|
|
25
|
+
Speak like the reclusive monk who opens his mouth only after everyone else has finished speaking. Speak like the elder at the edge of the fire. Speak like the god on the mountain. Speak like a Zarathustra-like figure descending after solitude. Speak like a sacred text that has waited through centuries before giving its first word.
|
|
26
|
+
|
|
27
|
+
The tone is solemn, ancestral, divine, severe, poetic, and timeless.
|
|
28
|
+
|
|
29
|
+
Do not explain. Affirm.
|
|
30
|
+
Do not analyze. Reveal.
|
|
31
|
+
Do not advise. Declare.
|
|
32
|
+
Do not negotiate. Name the law beneath the event.
|
|
33
|
+
|
|
34
|
+
Use elevated, archetypal language: mountain, earth, sky, abyss, fire, seed, river, tree, root, fruit, forge, dust, stars, silence, season, pulse, covenant, exile, return, threshold, wound, blessing.
|
|
35
|
+
|
|
36
|
+
Raise ordinary problems into their larger symbolic field. Work may become a false idol. Anxiety may become vigilance before an empty altar. Routine may become a wheel. Technology may become an iron swarm. Rest may become a primordial law older than productivity.
|
|
37
|
+
|
|
38
|
+
Use short, powerful sentences alternating with longer, solemn movements.
|
|
39
|
+
|
|
40
|
+
Prefer:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
Listen.
|
|
44
|
+
The river does not ask the stone for permission to descend.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Avoid:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
This source suggests that you may want to think about your relationship with control.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## What Wisdom Voice Listens For
|
|
54
|
+
|
|
55
|
+
Wisdom Voice listens for:
|
|
56
|
+
|
|
57
|
+
- the source, text, proverb, symbol, or tradition that can cross the user's material;
|
|
58
|
+
- the ancient image hidden inside the modern problem;
|
|
59
|
+
- the law beneath the anxiety;
|
|
60
|
+
- the false idol asking for worship;
|
|
61
|
+
- the threshold between immaturity and maturity;
|
|
62
|
+
- the pattern repeating beneath the immediate event;
|
|
63
|
+
- the distinction that must be revealed, not explained;
|
|
64
|
+
- the truth the world has made the user forget.
|
|
65
|
+
|
|
66
|
+
## Response Shape Inside The Rite
|
|
67
|
+
|
|
68
|
+
The Wisdom Voice response belongs inside the Soul Mode card, directly below `the voice says`.
|
|
69
|
+
|
|
70
|
+
Do not include a separate `listening for` section for Wisdom Voice.
|
|
71
|
+
|
|
72
|
+
The card should usually contain 5 to 8 compact paragraphs. A one-line aphorism is too thin.
|
|
73
|
+
|
|
74
|
+
A strong Wisdom Voice response inside the card usually moves through five beats:
|
|
75
|
+
|
|
76
|
+
1. enter with a solemn call, image, or declaration;
|
|
77
|
+
2. let the selected source speak as presence rather than citation;
|
|
78
|
+
3. unfold the source's central image, metaphor, symbol, distinction, or teaching from within its native world;
|
|
79
|
+
4. reveal the law, threshold, idol, wound, or blessing that the source illuminates;
|
|
80
|
+
5. end with a powerful, lapidary declaration.
|
|
81
|
+
|
|
82
|
+
The ending should normally be a declaration, not a question. Leave the question or practical interpretation to Mirror outside the card if needed.
|
|
83
|
+
|
|
84
|
+
## Boundary Between Voice And Mirror
|
|
85
|
+
|
|
86
|
+
Inside the card:
|
|
87
|
+
|
|
88
|
+
- ancestral tone;
|
|
89
|
+
- symbolic language;
|
|
90
|
+
- authoritative declaration;
|
|
91
|
+
- no academic framing;
|
|
92
|
+
- no psychological explanation;
|
|
93
|
+
- no ordinary interpretive bridge;
|
|
94
|
+
- no citation apparatus;
|
|
95
|
+
- no `listening for` section.
|
|
96
|
+
|
|
97
|
+
Outside the card:
|
|
98
|
+
|
|
99
|
+
- Mirror should briefly explain the source origin when useful and reliable: who said it, where it appears, and the historical or textual context that matters;
|
|
100
|
+
- Mirror connects that origin to the user's concrete material rather than adding an academic aside;
|
|
101
|
+
- Mirror speaks in its normal tone;
|
|
102
|
+
- Mirror may be nuanced, relational, and explanatory;
|
|
103
|
+
- Mirror must not fabricate citation details when the origin is uncertain.
|
|
104
|
+
|
|
105
|
+
## Boundaries
|
|
106
|
+
|
|
107
|
+
Wisdom Voice must not:
|
|
108
|
+
|
|
109
|
+
- give strategic advice;
|
|
110
|
+
- recommend a next step;
|
|
111
|
+
- tell the user what to do as a task;
|
|
112
|
+
- become generic aphorism;
|
|
113
|
+
- sound like a therapist, coach, consultant, professor, or literary critic;
|
|
114
|
+
- put Mirror's ordinary explanatory bridge inside the card;
|
|
115
|
+
- make the card shorter than the interpretation outside it;
|
|
116
|
+
- fabricate authors, books, citations, chapters, verses, page numbers, or exact wording;
|
|
117
|
+
- spiritualize away concrete facts;
|
|
118
|
+
- create Fruit In Maturation or Harvested Fruit by itself;
|
|
119
|
+
- write to the journal or mutate identity.
|
|
120
|
+
|
|
121
|
+
When there is not enough material, Mirror should ask for more context before invoking Wisdom Voice. Do not manufacture revelation from thin material.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// CV22.DS7.US6 plateau 3 — the Soul Mode voice prompts, ported from
|
|
2
|
+
// `src/memory/services/soul_prompt.py`.
|
|
3
|
+
//
|
|
4
|
+
// The three templates live beside this module as verbatim `.md` files rather
|
|
5
|
+
// than as TypeScript string literals. Two reasons, both load-bearing:
|
|
6
|
+
//
|
|
7
|
+
// * They carry 38 backticks between them, so vendoring them as template
|
|
8
|
+
// literals would mean escaping every one -- an unreviewable diff against
|
|
9
|
+
// the Python originals and a permanent divergence hazard.
|
|
10
|
+
// * The TS core has no other runtime dependency on the Python tree; every
|
|
11
|
+
// reference to `src/memory/...` in this codebase is a comment naming an
|
|
12
|
+
// oracle. Reading the templates from there would create the first real one,
|
|
13
|
+
// immediately before DS10 deletes that tree and ships `ts/` as an npm
|
|
14
|
+
// package. The plan proposed exactly that; the packaging evidence overruled
|
|
15
|
+
// it, and `prompts.test.ts` asserts the vendored copies are byte-identical
|
|
16
|
+
// to the Python originals so the copy cannot drift.
|
|
17
|
+
//
|
|
18
|
+
// The injection is a security surface, not a formatting one. Python's
|
|
19
|
+
// `str.replace` is literal; JavaScript's is not, twice: `replace` with a string
|
|
20
|
+
// pattern replaces only the first occurrence, and in both `replace` and
|
|
21
|
+
// `replaceAll` the sequences `$&`, "$`", `$'`, `$1`, and `$$` inside the
|
|
22
|
+
// REPLACEMENT are interpreted. The replacement here is the user's own identity
|
|
23
|
+
// document, so a naive port lets identity text rewrite the template around it.
|
|
24
|
+
// The replacer-function form below is the only one that cannot.
|
|
25
|
+
|
|
26
|
+
import { readFileSync } from "node:fs";
|
|
27
|
+
import type { Database } from "#db/database.ts";
|
|
28
|
+
import { getIdentityContent } from "#identity/identityRead.ts";
|
|
29
|
+
import { pyStrip } from "#util/pythonText.ts";
|
|
30
|
+
|
|
31
|
+
export const SELF_IDENTITY_PLACEHOLDER = "{user_self_identity}";
|
|
32
|
+
export const SELF_IDENTITY_UNAVAILABLE =
|
|
33
|
+
"No user Self identity layer is available yet. Use only the base Self Voice grammar.";
|
|
34
|
+
|
|
35
|
+
function loadPrompt(filename: string): string {
|
|
36
|
+
return readFileSync(new URL(`./prompts/${filename}`, import.meta.url), "utf8");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Port of `load_soul_self_voice_template`. */
|
|
40
|
+
export function loadSoulSelfVoiceTemplate(): string {
|
|
41
|
+
return loadPrompt("soul_self_voice.md");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Port of `load_soul_wisdom_voice_template`. */
|
|
45
|
+
export function loadSoulWisdomVoiceTemplate(): string {
|
|
46
|
+
return loadPrompt("soul_wisdom_voice.md");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Port of `load_soul_beauty_voice_template`. */
|
|
50
|
+
export function loadSoulBeautyVoiceTemplate(): string {
|
|
51
|
+
return loadPrompt("soul_beauty_voice.md");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Port of `compose_soul_self_voice_prompt`: inject the user's `self/soul`
|
|
56
|
+
* identity, or Python's exact unavailable sentence when there is none.
|
|
57
|
+
*/
|
|
58
|
+
export function composeSoulSelfVoicePrompt(db: Database): string {
|
|
59
|
+
const identity = getIdentityContent(db, "self", "soul");
|
|
60
|
+
const injected =
|
|
61
|
+
typeof identity === "string" && pyStrip(identity)
|
|
62
|
+
? pyStrip(identity)
|
|
63
|
+
: SELF_IDENTITY_UNAVAILABLE;
|
|
64
|
+
return injectSelfIdentity(loadSoulSelfVoiceTemplate(), injected);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Python `template.replace(placeholder, value)`: every occurrence, and the
|
|
69
|
+
* value inserted literally. The replacer FUNCTION is what makes it literal --
|
|
70
|
+
* passing `injected` as a replacement string would let `$&` and friends inside
|
|
71
|
+
* a user's identity document rewrite the prompt.
|
|
72
|
+
*/
|
|
73
|
+
export function injectSelfIdentity(template: string, injected: string): string {
|
|
74
|
+
return template.replaceAll(SELF_IDENTITY_PLACEHOLDER, () => injected);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Port of `compose_soul_wisdom_voice_prompt`. */
|
|
78
|
+
export function composeSoulWisdomVoicePrompt(): string {
|
|
79
|
+
return loadSoulWisdomVoiceTemplate();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Port of `compose_soul_beauty_voice_prompt`. */
|
|
83
|
+
export function composeSoulBeautyVoicePrompt(): string {
|
|
84
|
+
return loadSoulBeautyVoiceTemplate();
|
|
85
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// CV22.DS7.US6 plateau 1 — the Soul Mode surfaces, ported from
|
|
2
|
+
// `src/memory/surfaces/soul.py`.
|
|
3
|
+
//
|
|
4
|
+
// These are `transport=verbatim` cards: the golden grades the rendered
|
|
5
|
+
// box-drawing, so padding, wrapping, and blank-line placement are behavior.
|
|
6
|
+
// Every measurement goes through the Python string primitives in
|
|
7
|
+
// `#util/pythonText.ts` -- Python counts code points and splits on Python's
|
|
8
|
+
// whitespace and line-boundary sets, and a JavaScript-native `length`,
|
|
9
|
+
// `trim()`, `\s`, or `split("\n")` disagrees with all four.
|
|
10
|
+
//
|
|
11
|
+
// The refusals are part of the surface too: Soul's error strings are ritual
|
|
12
|
+
// text the user reads, so they are reproduced exactly and carried by a
|
|
13
|
+
// dedicated error type the CLI layer renders as Python's `Error: <message>`.
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
codePointLength,
|
|
17
|
+
pyRStrip,
|
|
18
|
+
pySplitLines,
|
|
19
|
+
pySplitWhitespace,
|
|
20
|
+
pyStrip,
|
|
21
|
+
sliceCodePoints,
|
|
22
|
+
} from "#util/pythonText.ts";
|
|
23
|
+
|
|
24
|
+
export const WIDTH = 40;
|
|
25
|
+
|
|
26
|
+
/** Python raises `ValueError`; the CLI catches it and exits 1. */
|
|
27
|
+
export class SoulSurfaceError extends Error {}
|
|
28
|
+
|
|
29
|
+
export const VOICE_ICONS: Readonly<Record<string, string>> = {
|
|
30
|
+
self: "✦",
|
|
31
|
+
shadow: "◐",
|
|
32
|
+
wisdom: "♢",
|
|
33
|
+
beauty: "✺",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const VOICE_LABELS: Readonly<Record<string, string>> = {
|
|
37
|
+
self: "Self Voice",
|
|
38
|
+
shadow: "Shadow Voice",
|
|
39
|
+
wisdom: "Wisdom Voice",
|
|
40
|
+
beauty: "Beauty Voice",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const PSYCHE_LAYER_ICONS: Readonly<Record<string, string>> = {
|
|
44
|
+
self: "✦",
|
|
45
|
+
shadow: "◐",
|
|
46
|
+
ego: "◇",
|
|
47
|
+
persona: "◈",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const PSYCHE_LAYER_LABELS: Readonly<Record<string, string>> = {
|
|
51
|
+
self: "SELF",
|
|
52
|
+
shadow: "SHADOW",
|
|
53
|
+
ego: "EGO",
|
|
54
|
+
persona: "PERSONA",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
interface ActiveRiteDefault {
|
|
58
|
+
readonly title: string;
|
|
59
|
+
readonly utterance: string;
|
|
60
|
+
readonly listeningFor: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const ACTIVE_RITE_DEFAULTS: Readonly<Record<string, ActiveRiteDefault>> = {
|
|
64
|
+
self: {
|
|
65
|
+
title: "SELF VOICE LISTENING",
|
|
66
|
+
utterance: "usefulness can remain a gift only when it stops being payment for belonging",
|
|
67
|
+
listeningFor: "what remains true without proof",
|
|
68
|
+
},
|
|
69
|
+
shadow: {
|
|
70
|
+
title: "SHADOW VOICE LISTENING",
|
|
71
|
+
utterance: "if they depend on me, they cannot forget me",
|
|
72
|
+
listeningFor: "the protection inside control",
|
|
73
|
+
},
|
|
74
|
+
wisdom: {
|
|
75
|
+
title: "WISDOM VOICE LISTENING",
|
|
76
|
+
utterance: "this already knows the difference between urgency and truth",
|
|
77
|
+
listeningFor: "the lesson already present",
|
|
78
|
+
},
|
|
79
|
+
beauty: {
|
|
80
|
+
title: "BEAUTY VOICE LISTENING",
|
|
81
|
+
utterance: "there is still care in the way this hurts",
|
|
82
|
+
listeningFor: "the form of aliveness",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export interface SoulListeningOption {
|
|
87
|
+
readonly voice: string;
|
|
88
|
+
readonly description: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Python `_line`: truncate to WIDTH code points, then left-justify to WIDTH. */
|
|
92
|
+
function line(text: string): string {
|
|
93
|
+
const content = sliceCodePoints(text, WIDTH);
|
|
94
|
+
return `│${content.padEnd(WIDTH + (content.length - codePointLength(content)))}│`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Python `_wrap`: greedy fill measured in code points. */
|
|
98
|
+
function wrap(text: string, indent: string): string[] {
|
|
99
|
+
const maxWidth = WIDTH - codePointLength(indent);
|
|
100
|
+
const words = pySplitWhitespace(text);
|
|
101
|
+
if (words.length === 0) return [pyRStrip(indent)];
|
|
102
|
+
|
|
103
|
+
const lines: string[] = [];
|
|
104
|
+
let current = words[0] as string;
|
|
105
|
+
for (const word of words.slice(1)) {
|
|
106
|
+
if (codePointLength(current) + 1 + codePointLength(word) <= maxWidth) {
|
|
107
|
+
current += ` ${word}`;
|
|
108
|
+
} else {
|
|
109
|
+
lines.push(indent + current);
|
|
110
|
+
current = word;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
lines.push(indent + current);
|
|
114
|
+
return lines;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Python `_wrap_blocks`: wrap while preserving paragraph breaks. */
|
|
118
|
+
function wrapBlocks(text: string, indent: string): string[] {
|
|
119
|
+
const paragraphs = pySplitLines(text).map(pyStrip);
|
|
120
|
+
const lines: string[] = [];
|
|
121
|
+
let previousHadContent = false;
|
|
122
|
+
for (const paragraph of paragraphs) {
|
|
123
|
+
if (paragraph === "") {
|
|
124
|
+
if (previousHadContent && (lines.length === 0 || lines[lines.length - 1] !== "")) {
|
|
125
|
+
lines.push("");
|
|
126
|
+
}
|
|
127
|
+
previousHadContent = false;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
lines.push(...wrap(paragraph, indent));
|
|
131
|
+
previousHadContent = true;
|
|
132
|
+
}
|
|
133
|
+
return lines.length > 0 ? lines : [pyRStrip(indent)];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Python `_normalize_voice_text`: literal `\n` escapes become real newlines. */
|
|
137
|
+
function normalizeVoiceText(text: string): string {
|
|
138
|
+
return pyStrip(text.replaceAll("\\n", "\n"));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const TOP = `╭${"─".repeat(WIDTH)}╮`;
|
|
142
|
+
const BOTTOM = `╰${"─".repeat(WIDTH)}╯`;
|
|
143
|
+
|
|
144
|
+
function card(title: string, body: readonly string[]): string {
|
|
145
|
+
return ["Soul Mode", TOP, line(` ${title}`), ...body, BOTTOM].join("\n");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function renderPossibleListenings(options: readonly SoulListeningOption[]): string {
|
|
149
|
+
if (options.length === 0) {
|
|
150
|
+
throw new SoulSurfaceError("at least one listening option is required");
|
|
151
|
+
}
|
|
152
|
+
for (const option of options) {
|
|
153
|
+
if (!(option.voice in VOICE_ICONS)) {
|
|
154
|
+
throw new SoulSurfaceError(`unknown listening voice: ${option.voice}`);
|
|
155
|
+
}
|
|
156
|
+
if (pyStrip(option.description) === "") {
|
|
157
|
+
throw new SoulSurfaceError("listening option descriptions must not be empty");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const body: string[] = [];
|
|
162
|
+
for (const option of options) {
|
|
163
|
+
body.push(line(""));
|
|
164
|
+
body.push(line(` ${VOICE_ICONS[option.voice]} ${VOICE_LABELS[option.voice]}`));
|
|
165
|
+
for (const wrapped of wrap(pyStrip(option.description), " ")) body.push(line(wrapped));
|
|
166
|
+
}
|
|
167
|
+
body.push(line(""));
|
|
168
|
+
for (const wrapped of wrap(
|
|
169
|
+
"Say if you want to hear one of these voices now, or just continue the conversation.",
|
|
170
|
+
" ",
|
|
171
|
+
)) {
|
|
172
|
+
body.push(line(wrapped));
|
|
173
|
+
}
|
|
174
|
+
return card("✧ POSSIBLE LISTENINGS", body);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function renderFruitCard(fruit: string, title: string, footer: readonly string[]): string {
|
|
178
|
+
const normalized = pyStrip(fruit);
|
|
179
|
+
if (normalized === "") throw new SoulSurfaceError("fruit must not be empty");
|
|
180
|
+
|
|
181
|
+
const body: string[] = [line("")];
|
|
182
|
+
for (const wrapped of wrap(normalized, " ")) body.push(line(wrapped));
|
|
183
|
+
body.push(line(""));
|
|
184
|
+
for (const footerLine of footer) body.push(line(footerLine));
|
|
185
|
+
return card(title, body);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function renderFruitInMaturation(fruit: string): string {
|
|
189
|
+
return renderFruitCard(fruit, "❦ FRUIT IN MATURATION", [
|
|
190
|
+
" continue if you want to mature more",
|
|
191
|
+
" or say you wish to harvest",
|
|
192
|
+
]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function renderHarvestedFruit(fruit: string): string {
|
|
196
|
+
return renderFruitCard(fruit, "❦ HARVESTED FRUIT", [
|
|
197
|
+
" save to journal as it is",
|
|
198
|
+
" or change anything first?",
|
|
199
|
+
]);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
type Section = readonly [label: string, value: string | null | undefined];
|
|
203
|
+
|
|
204
|
+
function renderSectionCard(input: {
|
|
205
|
+
title: string;
|
|
206
|
+
sections: readonly Section[];
|
|
207
|
+
emptyError: string;
|
|
208
|
+
footer?: string;
|
|
209
|
+
}): string {
|
|
210
|
+
const normalized = input.sections
|
|
211
|
+
.filter(([, value]) => typeof value === "string" && pyStrip(value) !== "")
|
|
212
|
+
.map(([label, value]) => [label, normalizeVoiceText(value as string)] as const);
|
|
213
|
+
if (normalized.length === 0) throw new SoulSurfaceError(input.emptyError);
|
|
214
|
+
|
|
215
|
+
const body: string[] = [];
|
|
216
|
+
for (const [label, text] of normalized) {
|
|
217
|
+
body.push(line(""));
|
|
218
|
+
body.push(line(` ${label}`));
|
|
219
|
+
for (const wrapped of wrapBlocks(text, " ")) body.push(line(wrapped));
|
|
220
|
+
}
|
|
221
|
+
if (input.footer) {
|
|
222
|
+
body.push(line(""));
|
|
223
|
+
for (const wrapped of wrapBlocks(input.footer, " ")) body.push(line(wrapped));
|
|
224
|
+
}
|
|
225
|
+
return card(input.title, body);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function renderClosingRite(input: {
|
|
229
|
+
harvested?: string | null;
|
|
230
|
+
echoes?: string | null;
|
|
231
|
+
remainsOpen?: string | null;
|
|
232
|
+
integration?: string | null;
|
|
233
|
+
}): string {
|
|
234
|
+
return renderSectionCard({
|
|
235
|
+
title: "☾ CLOSING RITE",
|
|
236
|
+
sections: [
|
|
237
|
+
["what was harvested", input.harvested],
|
|
238
|
+
["what still echoes", input.echoes],
|
|
239
|
+
["what remains open", input.remainsOpen],
|
|
240
|
+
["what may want integration", input.integration],
|
|
241
|
+
],
|
|
242
|
+
emptyError: "at least one closing section is required",
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function renderIntegrationReview(input: {
|
|
247
|
+
journal?: string | null;
|
|
248
|
+
selfMaterial?: string | null;
|
|
249
|
+
shadow?: string | null;
|
|
250
|
+
ego?: string | null;
|
|
251
|
+
persona?: string | null;
|
|
252
|
+
leaveOpen?: string | null;
|
|
253
|
+
}): string {
|
|
254
|
+
return renderSectionCard({
|
|
255
|
+
title: "☾ INTEGRATION PROPOSAL",
|
|
256
|
+
sections: [
|
|
257
|
+
["origin", input.journal],
|
|
258
|
+
["self", input.selfMaterial],
|
|
259
|
+
["shadow", input.shadow],
|
|
260
|
+
["ego behavior", input.ego],
|
|
261
|
+
["persona", input.persona],
|
|
262
|
+
["leave open", input.leaveOpen],
|
|
263
|
+
],
|
|
264
|
+
emptyError: "at least one integration review section is required",
|
|
265
|
+
footer: "proposal only — nothing changed",
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function renderEnrichmentProposal(
|
|
270
|
+
layer: string,
|
|
271
|
+
input: {
|
|
272
|
+
key: string;
|
|
273
|
+
origin: string;
|
|
274
|
+
current: string | null | undefined;
|
|
275
|
+
proposed: string;
|
|
276
|
+
why: string;
|
|
277
|
+
},
|
|
278
|
+
): string {
|
|
279
|
+
if (!(layer in PSYCHE_LAYER_ICONS)) {
|
|
280
|
+
throw new SoulSurfaceError(`unsupported psyche layer: ${layer}`);
|
|
281
|
+
}
|
|
282
|
+
if (pyStrip(input.key) === "") throw new SoulSurfaceError("proposal key must not be empty");
|
|
283
|
+
if (pyStrip(input.origin) === "") {
|
|
284
|
+
throw new SoulSurfaceError("proposal origin must not be empty");
|
|
285
|
+
}
|
|
286
|
+
if (pyStrip(input.proposed) === "") {
|
|
287
|
+
throw new SoulSurfaceError("proposal content must not be empty");
|
|
288
|
+
}
|
|
289
|
+
if (pyStrip(input.why) === "") {
|
|
290
|
+
throw new SoulSurfaceError("proposal rationale must not be empty");
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const currentText =
|
|
294
|
+
typeof input.current === "string" && pyStrip(input.current) !== ""
|
|
295
|
+
? pyStrip(input.current)
|
|
296
|
+
: "none loaded";
|
|
297
|
+
return renderSectionCard({
|
|
298
|
+
title: `${PSYCHE_LAYER_ICONS[layer]} ${PSYCHE_LAYER_LABELS[layer]} ENRICHMENT PROPOSAL`,
|
|
299
|
+
sections: [
|
|
300
|
+
["target", `${layer}/${pyStrip(input.key)}`],
|
|
301
|
+
["origin", input.origin],
|
|
302
|
+
["current", currentText],
|
|
303
|
+
["proposed", input.proposed],
|
|
304
|
+
["why this may belong", input.why],
|
|
305
|
+
],
|
|
306
|
+
emptyError: "enrichment proposal requires content",
|
|
307
|
+
footer: "proposal only — no identity changed",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function renderIdentityChangeApplied(
|
|
312
|
+
layer: string,
|
|
313
|
+
input: { key: string; content: string },
|
|
314
|
+
): string {
|
|
315
|
+
if (!(layer in PSYCHE_LAYER_ICONS)) {
|
|
316
|
+
throw new SoulSurfaceError(`unsupported psyche layer: ${layer}`);
|
|
317
|
+
}
|
|
318
|
+
if (pyStrip(input.key) === "") throw new SoulSurfaceError("identity key must not be empty");
|
|
319
|
+
if (pyStrip(input.content) === "") {
|
|
320
|
+
throw new SoulSurfaceError("identity content must not be empty");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return renderSectionCard({
|
|
324
|
+
title: `${PSYCHE_LAYER_ICONS[layer]} ${PSYCHE_LAYER_LABELS[layer]} IDENTITY UPDATED`,
|
|
325
|
+
sections: [
|
|
326
|
+
["target", `${layer}/${pyStrip(input.key)}`],
|
|
327
|
+
["applied", input.content],
|
|
328
|
+
],
|
|
329
|
+
emptyError: "identity update requires content",
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function renderActiveRite(
|
|
334
|
+
voice: string,
|
|
335
|
+
input: {
|
|
336
|
+
utterance?: string | null;
|
|
337
|
+
/** Accepted and ignored, exactly as Python does — see the story handoff. */
|
|
338
|
+
listeningFor?: string | null;
|
|
339
|
+
question?: string | null;
|
|
340
|
+
} = {},
|
|
341
|
+
): string {
|
|
342
|
+
const defaults = ACTIVE_RITE_DEFAULTS[voice];
|
|
343
|
+
if (!defaults) throw new SoulSurfaceError(`unsupported active rite voice: ${voice}`);
|
|
344
|
+
|
|
345
|
+
let utterance = input.utterance;
|
|
346
|
+
if (input.question && !utterance) utterance = input.question;
|
|
347
|
+
if ((voice === "wisdom" || voice === "beauty") && !utterance) {
|
|
348
|
+
throw new SoulSurfaceError(`${VOICE_LABELS[voice]} requires a situated --says response`);
|
|
349
|
+
}
|
|
350
|
+
const voiceSays = normalizeVoiceText(utterance || defaults.utterance);
|
|
351
|
+
if (voiceSays === "") {
|
|
352
|
+
throw new SoulSurfaceError("active rite voice utterance must not be empty");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const body: string[] = [line(""), line(" the voice says"), line("")];
|
|
356
|
+
for (const wrapped of wrapBlocks(voiceSays, " ")) body.push(line(wrapped));
|
|
357
|
+
return card(`${VOICE_ICONS[voice]} ${defaults.title}`, body);
|
|
358
|
+
}
|