mirror-mind 0.0.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/log-assistant-reply.sh +85 -0
- package/.claude/hooks/log-session-end.sh +85 -0
- package/.claude/hooks/log-user-prompt.sh +85 -0
- package/.claude/hooks/mirror-inject.sh +85 -0
- package/.claude/hooks/session-start.sh +85 -0
- package/.gemini/hooks/log-assistant.sh +85 -0
- package/.gemini/hooks/log-user.sh +85 -0
- package/.gemini/hooks/session-end.sh +85 -0
- package/.gemini/hooks/session-start.sh +85 -0
- package/.pi/extensions/mirror-logger.ts +646 -0
- package/.pi/skills/mm-backup/SKILL.md +21 -0
- package/.pi/skills/mm-build/SKILL.md +1206 -0
- package/.pi/skills/mm-consolidate/SKILL.md +112 -0
- package/.pi/skills/mm-consult/SKILL.md +70 -0
- package/.pi/skills/mm-conversations/SKILL.md +16 -0
- package/.pi/skills/mm-discard/SKILL.md +39 -0
- package/.pi/skills/mm-explore/SKILL.md +255 -0
- package/.pi/skills/mm-help/SKILL.md +74 -0
- package/.pi/skills/mm-identity/SKILL.md +96 -0
- package/.pi/skills/mm-journal/SKILL.md +16 -0
- package/.pi/skills/mm-journey/SKILL.md +23 -0
- package/.pi/skills/mm-journeys/SKILL.md +15 -0
- package/.pi/skills/mm-memories/SKILL.md +17 -0
- package/.pi/skills/mm-mirror/SKILL.md +98 -0
- package/.pi/skills/mm-mute/SKILL.md +18 -0
- package/.pi/skills/mm-new/SKILL.md +18 -0
- package/.pi/skills/mm-recall/SKILL.md +17 -0
- package/.pi/skills/mm-release-notes/SKILL.md +52 -0
- package/.pi/skills/mm-seed/SKILL.md +19 -0
- package/.pi/skills/mm-shadow/SKILL.md +117 -0
- package/.pi/skills/mm-soul/SKILL.md +502 -0
- package/.pi/skills/mm-tasks/SKILL.md +24 -0
- package/.pi/skills/mm-update/SKILL.md +32 -0
- package/.pi/skills/mm-week/SKILL.md +28 -0
- package/.pi/skills/mm-welcome/SKILL.md +24 -0
- package/AGENTS.md +188 -0
- package/README.md +126 -9
- package/bin/loader.js +67 -0
- package/bin/mirror-hook.js +7 -0
- package/bin/mirror.js +7 -0
- package/docs/releases/index.md +100 -0
- package/docs/releases/pending-cutoffs.md +510 -0
- package/docs/releases/v0.10.0.md +123 -0
- package/docs/releases/v0.10.1.md +66 -0
- package/docs/releases/v0.10.10.md +51 -0
- package/docs/releases/v0.10.11.md +39 -0
- package/docs/releases/v0.10.12.md +57 -0
- package/docs/releases/v0.10.13.md +35 -0
- package/docs/releases/v0.10.14.md +42 -0
- package/docs/releases/v0.10.15.md +53 -0
- package/docs/releases/v0.10.16.md +35 -0
- package/docs/releases/v0.10.17.md +43 -0
- package/docs/releases/v0.10.2.md +64 -0
- package/docs/releases/v0.10.3.md +78 -0
- package/docs/releases/v0.10.4.md +42 -0
- package/docs/releases/v0.10.5.md +57 -0
- package/docs/releases/v0.10.6.md +47 -0
- package/docs/releases/v0.10.7.md +53 -0
- package/docs/releases/v0.10.8.md +49 -0
- package/docs/releases/v0.10.9.md +37 -0
- package/docs/releases/v0.11.0.md +86 -0
- package/docs/releases/v0.12.0.md +67 -0
- package/docs/releases/v0.13.0.md +64 -0
- package/docs/releases/v0.14.0.md +68 -0
- package/docs/releases/v0.15.0.md +48 -0
- package/docs/releases/v0.16.0.md +50 -0
- package/docs/releases/v0.16.1.md +55 -0
- package/docs/releases/v0.16.2.md +36 -0
- package/docs/releases/v0.17.0.md +50 -0
- package/docs/releases/v0.17.1.md +58 -0
- package/docs/releases/v0.17.2.md +42 -0
- package/docs/releases/v0.17.3.md +58 -0
- package/docs/releases/v0.18.0.md +84 -0
- package/docs/releases/v0.18.1.md +51 -0
- package/docs/releases/v0.18.2.md +69 -0
- package/docs/releases/v0.19.0.md +85 -0
- package/docs/releases/v0.19.1.md +46 -0
- package/docs/releases/v0.20.0.md +85 -0
- package/docs/releases/v0.21.0.md +61 -0
- package/docs/releases/v0.21.1.md +47 -0
- package/docs/releases/v0.22.0.md +77 -0
- package/docs/releases/v0.22.1.md +42 -0
- package/docs/releases/v0.23.0.md +105 -0
- package/docs/releases/v0.24.0.md +125 -0
- package/docs/releases/v0.25.0.md +107 -0
- package/docs/releases/v0.26.0.md +139 -0
- package/docs/releases/v0.26.1.md +65 -0
- package/docs/releases/v0.26.2.md +43 -0
- package/docs/releases/v0.27.0.md +63 -0
- package/docs/releases/v0.28.0.md +59 -0
- package/docs/releases/v0.29.0.md +61 -0
- package/docs/releases/v0.29.1.md +59 -0
- package/docs/releases/v0.29.2.md +59 -0
- package/docs/releases/v0.29.3.md +93 -0
- package/docs/releases/v0.30.0.md +75 -0
- package/docs/releases/v0.30.1.md +93 -0
- package/docs/releases/v0.30.2.md +66 -0
- package/docs/releases/v0.31.0.md +122 -0
- package/docs/releases/v0.31.1.md +142 -0
- package/docs/releases/v0.31.10.md +118 -0
- package/docs/releases/v0.31.11.md +88 -0
- package/docs/releases/v0.31.12.md +105 -0
- package/docs/releases/v0.31.13.md +99 -0
- package/docs/releases/v0.31.14.md +97 -0
- package/docs/releases/v0.31.2.md +115 -0
- package/docs/releases/v0.31.3.md +142 -0
- package/docs/releases/v0.31.4.md +117 -0
- package/docs/releases/v0.31.5.md +155 -0
- package/docs/releases/v0.31.6.md +132 -0
- package/docs/releases/v0.31.7.md +132 -0
- package/docs/releases/v0.31.8.md +120 -0
- package/docs/releases/v0.31.9.md +120 -0
- package/docs/releases/v0.32.0.md +261 -0
- package/docs/releases/v0.32.1.md +59 -0
- package/docs/releases/v0.33.0.md +164 -0
- package/docs/releases/v0.8.0.md +118 -0
- package/docs/releases/v0.9.0.md +98 -0
- package/docs/releases/v0.9.1.md +83 -0
- package/package.json +102 -6
- package/plugins/mirror-mind/.claude-plugin/plugin.json +17 -0
- package/plugins/mirror-mind/hooks/hooks.json +62 -0
- package/plugins/mirror-mind/hooks/log-assistant-reply.sh +98 -0
- package/plugins/mirror-mind/hooks/log-session-end.sh +98 -0
- package/plugins/mirror-mind/hooks/log-user-prompt.sh +98 -0
- package/plugins/mirror-mind/hooks/mirror-inject.sh +98 -0
- package/plugins/mirror-mind/hooks/session-start.sh +98 -0
- package/plugins/mirror-mind/skills/mm-backup/SKILL.md +27 -0
- package/plugins/mirror-mind/skills/mm-build/SKILL.md +1206 -0
- package/plugins/mirror-mind/skills/mm-consolidate/SKILL.md +112 -0
- package/plugins/mirror-mind/skills/mm-consult/SKILL.md +83 -0
- package/plugins/mirror-mind/skills/mm-conversations/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-discard/SKILL.md +40 -0
- package/plugins/mirror-mind/skills/mm-explore/SKILL.md +241 -0
- package/plugins/mirror-mind/skills/mm-help/SKILL.md +104 -0
- package/plugins/mirror-mind/skills/mm-identity/SKILL.md +96 -0
- package/plugins/mirror-mind/skills/mm-journal/SKILL.md +21 -0
- package/plugins/mirror-mind/skills/mm-journey/SKILL.md +37 -0
- package/plugins/mirror-mind/skills/mm-journeys/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-memories/SKILL.md +20 -0
- package/plugins/mirror-mind/skills/mm-mirror/SKILL.md +67 -0
- package/plugins/mirror-mind/skills/mm-mute/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-new/SKILL.md +18 -0
- package/plugins/mirror-mind/skills/mm-recall/SKILL.md +17 -0
- package/plugins/mirror-mind/skills/mm-release-notes/SKILL.md +31 -0
- package/plugins/mirror-mind/skills/mm-seed/SKILL.md +15 -0
- package/plugins/mirror-mind/skills/mm-shadow/SKILL.md +117 -0
- package/plugins/mirror-mind/skills/mm-soul/SKILL.md +488 -0
- package/plugins/mirror-mind/skills/mm-tasks/SKILL.md +36 -0
- package/plugins/mirror-mind/skills/mm-update/SKILL.md +30 -0
- package/plugins/mirror-mind/skills/mm-week/SKILL.md +46 -0
- package/plugins/mirror-mind/skills/mm-welcome/SKILL.md +22 -0
- package/scripts/codex-hooks/session-end.sh +85 -0
- package/scripts/codex-hooks/session-start.sh +85 -0
- package/scripts/codex-mirror.sh +48 -0
- package/templates/identity/README.md +119 -0
- package/templates/identity/ego/behavior.yaml +52 -0
- package/templates/identity/ego/constraints.yaml +15 -0
- package/templates/identity/ego/identity.yaml +43 -0
- package/templates/identity/journeys/personal-growth.yaml +39 -0
- package/templates/identity/organization/identity.yaml +24 -0
- package/templates/identity/organization/principles.yaml +17 -0
- package/templates/identity/personas/coach.yaml +94 -0
- package/templates/identity/personas/designer.yaml +93 -0
- package/templates/identity/personas/doctor.yaml +96 -0
- package/templates/identity/personas/engineer.yaml +77 -0
- package/templates/identity/personas/financial.yaml +97 -0
- package/templates/identity/personas/prompt-engineer.yaml +122 -0
- package/templates/identity/personas/researcher.yaml +88 -0
- package/templates/identity/personas/strategist.yaml +91 -0
- package/templates/identity/personas/teacher.yaml +95 -0
- package/templates/identity/personas/therapist.yaml +91 -0
- package/templates/identity/personas/thinker.yaml +74 -0
- package/templates/identity/personas/writer.yaml +76 -0
- package/templates/identity/self/config.yaml +16 -0
- package/templates/identity/self/soul.yaml +105 -0
- package/templates/identity/user/identity.yaml +30 -0
- package/ts/src/backup/staging.ts +62 -0
- package/ts/src/backup/zipBackup.ts +267 -0
- package/ts/src/backup/zipReader.ts +109 -0
- package/ts/src/backup/zipWriter.ts +148 -0
- package/ts/src/builder/activeCheckpoint.ts +134 -0
- package/ts/src/builder/aggregateStatus.ts +34 -0
- package/ts/src/builder/approve.ts +149 -0
- package/ts/src/builder/argv.ts +292 -0
- package/ts/src/builder/ariadMethod.ts +536 -0
- package/ts/src/builder/artifacts/artifactSurfaces.ts +106 -0
- package/ts/src/builder/artifacts/artifactWriter.ts +113 -0
- package/ts/src/builder/artifacts/closureArtifacts.ts +199 -0
- package/ts/src/builder/artifacts/deliveryStoryArtifacts.ts +316 -0
- package/ts/src/builder/artifacts/planArtifacts.ts +242 -0
- package/ts/src/builder/artifacts/scaffoldSections.ts +273 -0
- package/ts/src/builder/artifacts/scaffoldState.ts +227 -0
- package/ts/src/builder/artifacts/storyFiles.ts +61 -0
- package/ts/src/builder/artifacts/storyIndex.ts +166 -0
- package/ts/src/builder/cadence.ts +59 -0
- package/ts/src/builder/card.ts +192 -0
- package/ts/src/builder/checkpointRefused.ts +66 -0
- package/ts/src/builder/closure.ts +964 -0
- package/ts/src/builder/commands.ts +2053 -0
- package/ts/src/builder/cursorPosition.ts +176 -0
- package/ts/src/builder/cursorTransitions.ts +77 -0
- package/ts/src/builder/deliveryCursor.ts +577 -0
- package/ts/src/builder/deliveryStoryClosure.ts +521 -0
- package/ts/src/builder/deliveryStoryPlan.ts +536 -0
- package/ts/src/builder/deliveryStoryReady.ts +160 -0
- package/ts/src/builder/deliveryStoryRoadmapClosure.ts +151 -0
- package/ts/src/builder/expand.ts +336 -0
- package/ts/src/builder/flowUnit.ts +339 -0
- package/ts/src/builder/homeSurface.ts +122 -0
- package/ts/src/builder/implementationGuard.ts +125 -0
- package/ts/src/builder/index.ts +11 -0
- package/ts/src/builder/lifecycleRefusal.ts +92 -0
- package/ts/src/builder/lifecycleRibbon.ts +159 -0
- package/ts/src/builder/load.ts +313 -0
- package/ts/src/builder/methodAdoption.ts +113 -0
- package/ts/src/builder/methodDefinition.ts +429 -0
- package/ts/src/builder/methodInspection.ts +371 -0
- package/ts/src/builder/plan.ts +408 -0
- package/ts/src/builder/planPreauthorization.ts +265 -0
- package/ts/src/builder/prepare.ts +225 -0
- package/ts/src/builder/projectPaths.ts +64 -0
- package/ts/src/builder/pull.ts +356 -0
- package/ts/src/builder/pullCandidates.ts +463 -0
- package/ts/src/builder/pullCandidatesRender.ts +238 -0
- package/ts/src/builder/refinementField.ts +93 -0
- package/ts/src/builder/releaseIntent.ts +173 -0
- package/ts/src/builder/resumeState.ts +84 -0
- package/ts/src/builder/resumeSurface.ts +149 -0
- package/ts/src/builder/roadmapGrammar.ts +300 -0
- package/ts/src/builder/roadmapScan.ts +97 -0
- package/ts/src/builder/roadmapScope.ts +210 -0
- package/ts/src/builder/scopePhrases.ts +146 -0
- package/ts/src/builder/storyPaths.ts +196 -0
- package/ts/src/builder/storyPlanPreauthorization.ts +287 -0
- package/ts/src/builder/surfaceProtocol.ts +42 -0
- package/ts/src/builder/templateGeneration.ts +148 -0
- package/ts/src/builder/transition.ts +178 -0
- package/ts/src/consult/args.ts +99 -0
- package/ts/src/consult/core.ts +122 -0
- package/ts/src/consult/modelCatalog.ts +55 -0
- package/ts/src/consult/render.ts +47 -0
- package/ts/src/conversation/append.ts +414 -0
- package/ts/src/conversation/backfill.ts +387 -0
- package/ts/src/conversation/closeTail.ts +467 -0
- package/ts/src/conversation/extraction.ts +333 -0
- package/ts/src/conversation/extractionDriver.ts +130 -0
- package/ts/src/conversation/extractionRun.ts +70 -0
- package/ts/src/conversation/hookPayload.ts +51 -0
- package/ts/src/conversation/journeyInference.ts +165 -0
- package/ts/src/conversation/journeyRepair.ts +114 -0
- package/ts/src/conversation/lifecycleFaces.ts +197 -0
- package/ts/src/conversation/lifecycleWrites.ts +313 -0
- package/ts/src/conversation/listing.ts +77 -0
- package/ts/src/conversation/logger.ts +851 -0
- package/ts/src/conversation/loggerCli.ts +321 -0
- package/ts/src/conversation/loggerRuntime.ts +259 -0
- package/ts/src/conversation/metadataLifecycle.ts +443 -0
- package/ts/src/conversation/recall.ts +66 -0
- package/ts/src/conversation/sessionComposites.ts +258 -0
- package/ts/src/conversation/sessionImport.ts +90 -0
- package/ts/src/conversation/transcriptBackfill.ts +141 -0
- package/ts/src/cultivation/applyActions.ts +241 -0
- package/ts/src/cultivation/cluster.ts +86 -0
- package/ts/src/cultivation/consolidationStore.ts +281 -0
- package/ts/src/cultivation/promptContext.ts +62 -0
- package/ts/src/cultivation/propose.ts +305 -0
- package/ts/src/cultivation/scan.ts +155 -0
- package/ts/src/db/backupGate.ts +47 -0
- package/ts/src/db/bootstrap.ts +108 -0
- package/ts/src/db/bootstrapLock.ts +223 -0
- package/ts/src/db/copyGuard.ts +60 -0
- package/ts/src/db/database.ts +397 -0
- package/ts/src/db/decode.ts +66 -0
- package/ts/src/db/ftsIntegrity.ts +41 -0
- package/ts/src/db/migrateOnOpen.ts +214 -0
- package/ts/src/db/migrations.ts +576 -0
- package/ts/src/db/readyOnOpen.ts +35 -0
- package/ts/src/db/rowDecode.ts +42 -0
- package/ts/src/db/schema.ts +432 -0
- package/ts/src/db/schemaInventory.ts +225 -0
- package/ts/src/db/schemaInventorySnapshot.ts +2107 -0
- package/ts/src/db/schemaState.ts +91 -0
- package/ts/src/db/schemaTsDivergence.ts +114 -0
- package/ts/src/descriptor/descriptorRead.ts +49 -0
- package/ts/src/docs/docsLint.ts +265 -0
- package/ts/src/explorer/handoff.ts +522 -0
- package/ts/src/explorer/render.ts +335 -0
- package/ts/src/explorer/story.ts +769 -0
- package/ts/src/explorer/transition.ts +72 -0
- package/ts/src/extensions/bindings.ts +170 -0
- package/ts/src/extensions/catalog.ts +249 -0
- package/ts/src/extensions/catalogCommands.ts +513 -0
- package/ts/src/extensions/catalogWrites.ts +652 -0
- package/ts/src/extensions/contextRuntime.ts +325 -0
- package/ts/src/extensions/dispatch.ts +374 -0
- package/ts/src/extensions/errors.ts +24 -0
- package/ts/src/extensions/manifest.ts +356 -0
- package/ts/src/extensions/migrations.ts +350 -0
- package/ts/src/extraction/conversation.ts +304 -0
- package/ts/src/extraction/conversationMetadata.ts +206 -0
- package/ts/src/extraction/fencing.ts +106 -0
- package/ts/src/extraction/json.ts +17 -0
- package/ts/src/extraction/prompts.ts +470 -0
- package/ts/src/frontDoor/args.ts +30 -0
- package/ts/src/frontDoor/argvShape.ts +106 -0
- package/ts/src/frontDoor/buildLoadRuntime.ts +139 -0
- package/ts/src/frontDoor/buildRoute.ts +398 -0
- package/ts/src/frontDoor/cli.ts +1872 -0
- package/ts/src/frontDoor/cloneRoleGuard.ts +98 -0
- package/ts/src/frontDoor/consultRoute.ts +50 -0
- package/ts/src/frontDoor/contentTailRoute.ts +239 -0
- package/ts/src/frontDoor/conversationLoggerRoute.ts +83 -0
- package/ts/src/frontDoor/cultivationRoute.ts +210 -0
- package/ts/src/frontDoor/dbPath.ts +131 -0
- package/ts/src/frontDoor/dbSafetyToolsRoute.ts +240 -0
- package/ts/src/frontDoor/exploreRoute.ts +572 -0
- package/ts/src/frontDoor/extensionCatalogRoute.ts +252 -0
- package/ts/src/frontDoor/frontDoorLog.ts +57 -0
- package/ts/src/frontDoor/identityWrite.ts +36 -0
- package/ts/src/frontDoor/journeyWriteRoute.ts +26 -0
- package/ts/src/frontDoor/lifecycleWriteRoute.ts +110 -0
- package/ts/src/frontDoor/liveBackup.ts +100 -0
- package/ts/src/frontDoor/mirrorModeRoute.ts +163 -0
- package/ts/src/frontDoor/namedRefusal.ts +35 -0
- package/ts/src/frontDoor/nodeSupport.ts +24 -0
- package/ts/src/frontDoor/render/consolidate.ts +199 -0
- package/ts/src/frontDoor/render/conversations.ts +33 -0
- package/ts/src/frontDoor/render/cultivationShared.ts +21 -0
- package/ts/src/frontDoor/render/descriptor.ts +20 -0
- package/ts/src/frontDoor/render/detectPersona.ts +50 -0
- package/ts/src/frontDoor/render/icons.ts +13 -0
- package/ts/src/frontDoor/render/identity.ts +59 -0
- package/ts/src/frontDoor/render/identityRows.ts +17 -0
- package/ts/src/frontDoor/render/inspectPersona.ts +53 -0
- package/ts/src/frontDoor/render/journeyStatus.ts +78 -0
- package/ts/src/frontDoor/render/journeys.ts +79 -0
- package/ts/src/frontDoor/render/list.ts +41 -0
- package/ts/src/frontDoor/render/memories.ts +67 -0
- package/ts/src/frontDoor/render/recall.ts +49 -0
- package/ts/src/frontDoor/render/shadow.ts +155 -0
- package/ts/src/frontDoor/render/tasks.ts +99 -0
- package/ts/src/frontDoor/render/tasksImportSync.ts +63 -0
- package/ts/src/frontDoor/render/week.ts +113 -0
- package/ts/src/frontDoor/routing.ts +1001 -0
- package/ts/src/frontDoor/runtimeRoute.ts +623 -0
- package/ts/src/frontDoor/searchRoute.ts +166 -0
- package/ts/src/frontDoor/seedPaths.ts +98 -0
- package/ts/src/frontDoor/sessionStartWelcomeRoute.ts +166 -0
- package/ts/src/frontDoor/soulRoute.ts +433 -0
- package/ts/src/frontDoor/stdinSource.ts +37 -0
- package/ts/src/frontDoor/tasksImportSyncRoute.ts +110 -0
- package/ts/src/frontDoor/tasksWriteRoute.ts +101 -0
- package/ts/src/frontDoor/usage.ts +176 -0
- package/ts/src/guards/claudePlugin.ts +298 -0
- package/ts/src/guards/packContents.ts +306 -0
- package/ts/src/guards/piSourcedSkills.ts +70 -0
- package/ts/src/guards/retiredRouteShadows.ts +57 -0
- package/ts/src/guards/retiredSurfaces.ts +564 -0
- package/ts/src/hooks/claude.ts +214 -0
- package/ts/src/hooks/codex.ts +45 -0
- package/ts/src/hooks/gemini.ts +126 -0
- package/ts/src/hooks/main.ts +109 -0
- package/ts/src/hooks/mirrorState.ts +71 -0
- package/ts/src/hooks/payload.ts +73 -0
- package/ts/src/hooks/runtime.ts +179 -0
- package/ts/src/hooks/runtimeDetection.ts +34 -0
- package/ts/src/identity/applyConsolidationIdentityUpdate.ts +67 -0
- package/ts/src/identity/descriptorGenerate.ts +162 -0
- package/ts/src/identity/identityEdit.ts +143 -0
- package/ts/src/identity/identityKey.ts +77 -0
- package/ts/src/identity/identityRead.ts +69 -0
- package/ts/src/identity/identityStore.ts +80 -0
- package/ts/src/identity/journeyListing.ts +53 -0
- package/ts/src/identity/personaInspect.ts +44 -0
- package/ts/src/identity/personaListing.ts +37 -0
- package/ts/src/identity/setIdentity.ts +64 -0
- package/ts/src/index.ts +231 -0
- package/ts/src/init/init.ts +111 -0
- package/ts/src/journey/journeyOptions.ts +131 -0
- package/ts/src/journey/journeyRemoval.ts +158 -0
- package/ts/src/journey/journeyStatus.ts +149 -0
- package/ts/src/journey/journeySyncFile.ts +87 -0
- package/ts/src/journey/journeyWrite.ts +203 -0
- package/ts/src/journey/parentJourney.ts +41 -0
- package/ts/src/journey/validateParentJourney.ts +55 -0
- package/ts/src/mcp/boundary.ts +151 -0
- package/ts/src/mcp/guards.ts +244 -0
- package/ts/src/mcp/main.ts +121 -0
- package/ts/src/mcp/payload.ts +141 -0
- package/ts/src/mcp/protocol.ts +141 -0
- package/ts/src/mcp/readModels.ts +241 -0
- package/ts/src/mcp/registry.ts +201 -0
- package/ts/src/mcp/serve.ts +120 -0
- package/ts/src/mcp/tools/deterministic.ts +137 -0
- package/ts/src/mcp/tools/providerCrossing.ts +187 -0
- package/ts/src/mcp/wire.ts +8 -0
- package/ts/src/memory/journal.ts +180 -0
- package/ts/src/memory/listing.ts +107 -0
- package/ts/src/memory/memoryWrite.ts +88 -0
- package/ts/src/memory/reinforcement.ts +35 -0
- package/ts/src/mirror/context.ts +161 -0
- package/ts/src/mirror/defaultResolution.ts +199 -0
- package/ts/src/mirror/mirrorForm.ts +43 -0
- package/ts/src/mirror/orchestration.ts +364 -0
- package/ts/src/mirror/reception.ts +194 -0
- package/ts/src/mirror/render.ts +75 -0
- package/ts/src/mirror/runtimeSession.ts +205 -0
- package/ts/src/mode/operatingMode.ts +148 -0
- package/ts/src/observability/callOutcome.ts +115 -0
- package/ts/src/observability/inspectLedger.ts +329 -0
- package/ts/src/observability/ledgerHooks.ts +126 -0
- package/ts/src/observability/llmCalls.ts +154 -0
- package/ts/src/persona/detectPersona.ts +81 -0
- package/ts/src/planning/promptAssembly.ts +111 -0
- package/ts/src/planning/weekPending.ts +81 -0
- package/ts/src/planning/weekPlan.ts +183 -0
- package/ts/src/planning/weekSave.ts +117 -0
- package/ts/src/providers/config.ts +189 -0
- package/ts/src/providers/cost.ts +64 -0
- package/ts/src/providers/credits.ts +204 -0
- package/ts/src/providers/embedding.ts +321 -0
- package/ts/src/providers/familyProviders.ts +147 -0
- package/ts/src/providers/llm.ts +334 -0
- package/ts/src/providers/openrouter.ts +244 -0
- package/ts/src/providers/redaction.ts +110 -0
- package/ts/src/providers/replay.ts +15 -0
- package/ts/src/providers/transport.ts +410 -0
- package/ts/src/repair/encodingRepair.ts +253 -0
- package/ts/src/runtime/backup.ts +151 -0
- package/ts/src/runtime/channel.ts +146 -0
- package/ts/src/runtime/config.ts +168 -0
- package/ts/src/runtime/diagnose.ts +686 -0
- package/ts/src/runtime/git.ts +510 -0
- package/ts/src/runtime/installKind.ts +220 -0
- package/ts/src/runtime/migrate.ts +154 -0
- package/ts/src/runtime/packageIdentity.ts +102 -0
- package/ts/src/runtime/releaseNotes.ts +244 -0
- package/ts/src/runtime/status.ts +557 -0
- package/ts/src/runtime/strategies/clone.ts +200 -0
- package/ts/src/runtime/strategies/package.ts +328 -0
- package/ts/src/runtime/treeRoot.ts +30 -0
- package/ts/src/runtime/update.ts +445 -0
- package/ts/src/runtime/updateGate.ts +40 -0
- package/ts/src/runtime/updatePipeline.ts +159 -0
- package/ts/src/runtime/version.ts +36 -0
- package/ts/src/runtime/wiring.ts +130 -0
- package/ts/src/search/memorySearch.ts +338 -0
- package/ts/src/search/ranker.ts +154 -0
- package/ts/src/seed/seed.ts +256 -0
- package/ts/src/seed/seedYaml.ts +133 -0
- package/ts/src/soul/apply.ts +218 -0
- package/ts/src/soul/harvest.ts +267 -0
- package/ts/src/soul/prompts/soul_beauty_voice.md +103 -0
- package/ts/src/soul/prompts/soul_self_voice.md +219 -0
- package/ts/src/soul/prompts/soul_wisdom_voice.md +121 -0
- package/ts/src/soul/prompts.ts +85 -0
- package/ts/src/soul/render.ts +358 -0
- package/ts/src/soul/state.ts +212 -0
- package/ts/src/soul/transition.ts +37 -0
- package/ts/src/tasks/journeyPathParse.ts +113 -0
- package/ts/src/tasks/taskImportSync.ts +142 -0
- package/ts/src/tasks/taskStore.ts +312 -0
- package/ts/src/tasks/weekView.ts +120 -0
- package/ts/src/util/clipCodePoints.ts +26 -0
- package/ts/src/util/paths.ts +63 -0
- package/ts/src/util/program.ts +9 -0
- package/ts/src/util/pyGenerators.ts +144 -0
- package/ts/src/util/pythonText.ts +317 -0
- package/ts/src/util/semver.ts +45 -0
- package/ts/src/util/shellWord.ts +25 -0
- package/ts/src/util/slug.ts +64 -0
- package/ts/src/welcome/card.ts +339 -0
- package/ts/src/welcome/statusLine.ts +101 -0
- package/ts/src/welcome/updateCache.ts +129 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live OpenRouter HTTP transport (AI-18, CV22.DS8.US1).
|
|
3
|
+
*
|
|
4
|
+
* Python reaches OpenRouter through the OpenAI SDK and inherits its retry
|
|
5
|
+
* policy; TypeScript ports the POLICY, not the package. Node >= 24 ships a
|
|
6
|
+
* global `fetch`, so the only thing an SDK would add here is a dependency with
|
|
7
|
+
* its own release cadence sitting on the path of every paid call.
|
|
8
|
+
*
|
|
9
|
+
* Every side effect is injectable (`fetch`, `sleep`) so no test in this repo
|
|
10
|
+
* can reach the network by accident. The client itself logs NOTHING:
|
|
11
|
+
* observability belongs to `logLlmCall` (metadata mode) and the front-door
|
|
12
|
+
* log, both of which are already redacted by contract.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { ProviderConfig } from "./config.ts";
|
|
16
|
+
import { redactString } from "./redaction.ts";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The AI-18 failure taxonomy. Closed on purpose: a caller that switches on
|
|
20
|
+
* `kind` must break at compile time when a class is added, rather than
|
|
21
|
+
* silently funnelling a new failure into `provider_error`.
|
|
22
|
+
*/
|
|
23
|
+
export type LlmTransportErrorKind =
|
|
24
|
+
| "timeout"
|
|
25
|
+
| "auth"
|
|
26
|
+
| "rate_limit"
|
|
27
|
+
| "malformed_output"
|
|
28
|
+
| "provider_error";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A provider failure, carrying the classification and NOTHING else.
|
|
32
|
+
*
|
|
33
|
+
* The fields are deliberately minimal. Error objects get serialized whole by
|
|
34
|
+
* loggers, test reporters, and crash handlers, so a `Response`, a body, or a
|
|
35
|
+
* `cause` chain kept "just for debugging" is a leak path for both the API key
|
|
36
|
+
* and the request content (a query, a transcript, an identity document). The
|
|
37
|
+
* message is redacted; the enumerable surface is `kind`, `status`, `retryable`.
|
|
38
|
+
*/
|
|
39
|
+
export class LlmTransportError extends Error {
|
|
40
|
+
readonly kind: LlmTransportErrorKind;
|
|
41
|
+
readonly status: number | null;
|
|
42
|
+
readonly retryable: boolean;
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
kind: LlmTransportErrorKind,
|
|
46
|
+
message: string,
|
|
47
|
+
options: { status?: number | null; retryable?: boolean } = {},
|
|
48
|
+
) {
|
|
49
|
+
// No `cause`: it would carry the original error's message and, through it,
|
|
50
|
+
// whatever the provider echoed back.
|
|
51
|
+
super(message);
|
|
52
|
+
this.name = "LlmTransportError";
|
|
53
|
+
this.kind = kind;
|
|
54
|
+
this.status = options.status ?? null;
|
|
55
|
+
this.retryable = options.retryable ?? false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface OpenRouterClientOptions {
|
|
60
|
+
fetch?: typeof fetch;
|
|
61
|
+
sleep?: (ms: number) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ProviderRequestOptions {
|
|
65
|
+
/** Hard bound for one attempt, from the per-role pins in config.ts. */
|
|
66
|
+
timeoutMs: number;
|
|
67
|
+
/** Additional attempts after the first. Defaults to Python's ceiling of 2. */
|
|
68
|
+
maxRetries?: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface OpenRouterClient {
|
|
72
|
+
postJson(path: string, body: unknown, options: ProviderRequestOptions): Promise<unknown>;
|
|
73
|
+
/**
|
|
74
|
+
* A bounded GET, for OpenRouter's read endpoints (`/credits`,
|
|
75
|
+
* `/generation`).
|
|
76
|
+
*
|
|
77
|
+
* Python reaches those two through bare `urllib.request.urlopen` with **no
|
|
78
|
+
* timeout at all**, so a hung connection there parks the command forever.
|
|
79
|
+
* TypeScript bounds every attempt instead -- a deliberate divergence, at the
|
|
80
|
+
* embedding tier Python itself uses for its other cheap GET (`/models`).
|
|
81
|
+
* Recorded in `docs/project/decisions.md` (CV22.DS8.US3).
|
|
82
|
+
*/
|
|
83
|
+
getJson(path: string, options: ProviderRequestOptions): Promise<unknown>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Base backoff; doubles per attempt (0.5s, 1s, 2s, ...). */
|
|
87
|
+
const BASE_BACKOFF_MS = 500;
|
|
88
|
+
/** Ceiling for computed backoff and for an honored `retry-after`. */
|
|
89
|
+
const MAX_BACKOFF_MS = 60_000;
|
|
90
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* One attempt's outcome. The retry hint travels HERE rather than on the error,
|
|
94
|
+
* so the error's serialized shape stays minimal and the loop keeps the whole
|
|
95
|
+
* retry decision in one place.
|
|
96
|
+
*/
|
|
97
|
+
type AttemptOutcome =
|
|
98
|
+
| { ok: true; body: unknown }
|
|
99
|
+
| { ok: false; error: LlmTransportError; retryAfterMs: number | null };
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Statuses the OpenAI SDK retries, which is what Python's behavior is made of:
|
|
103
|
+
* request timeout, conflict, rate limit, and any server-side failure. Every
|
|
104
|
+
* other 4xx is a deterministic client error -- retrying it spends money to get
|
|
105
|
+
* the same answer.
|
|
106
|
+
*/
|
|
107
|
+
function isRetryableStatus(status: number): boolean {
|
|
108
|
+
return status === 408 || status === 409 || status === 429 || status >= 500;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function classifyStatus(status: number): LlmTransportErrorKind {
|
|
112
|
+
if (status === 401 || status === 403) return "auth";
|
|
113
|
+
if (status === 429) return "rate_limit";
|
|
114
|
+
return "provider_error";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const defaultSleep = (ms: number): Promise<void> =>
|
|
118
|
+
new Promise((resolve) => setTimeout(resolve, ms));
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Honor `retry-after` when the provider states one, capped so a hostile or
|
|
122
|
+
* confused header cannot park a session hook for an hour.
|
|
123
|
+
*/
|
|
124
|
+
function retryAfterMs(response: Response): number | null {
|
|
125
|
+
const raw = response.headers.get("retry-after");
|
|
126
|
+
if (!raw) return null;
|
|
127
|
+
const seconds = Number(raw.trim());
|
|
128
|
+
if (!Number.isFinite(seconds) || seconds < 0) return null;
|
|
129
|
+
return Math.min(seconds * 1000, MAX_BACKOFF_MS);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function backoffMs(attemptIndex: number): number {
|
|
133
|
+
return Math.min(BASE_BACKOFF_MS * 2 ** attemptIndex, MAX_BACKOFF_MS);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isAbortError(error: unknown): boolean {
|
|
137
|
+
return error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function createOpenRouterClient(
|
|
141
|
+
config: ProviderConfig,
|
|
142
|
+
options: OpenRouterClientOptions = {},
|
|
143
|
+
): OpenRouterClient {
|
|
144
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
145
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
146
|
+
// Every message leaving this client passes through here. The key is the only
|
|
147
|
+
// secret the client holds, so it is the only needle redaction needs.
|
|
148
|
+
const redact = (message: string): string => redactString(message, { secrets: [config.apiKey] });
|
|
149
|
+
|
|
150
|
+
async function attempt(
|
|
151
|
+
method: "GET" | "POST",
|
|
152
|
+
path: string,
|
|
153
|
+
body: unknown,
|
|
154
|
+
timeoutMs: number,
|
|
155
|
+
): Promise<AttemptOutcome> {
|
|
156
|
+
let response: Response;
|
|
157
|
+
try {
|
|
158
|
+
response = await fetchImpl(`${config.baseUrl}${path}`, {
|
|
159
|
+
method,
|
|
160
|
+
headers:
|
|
161
|
+
method === "POST"
|
|
162
|
+
? { "content-type": "application/json", authorization: `Bearer ${config.apiKey}` }
|
|
163
|
+
: { authorization: `Bearer ${config.apiKey}` },
|
|
164
|
+
body: method === "POST" ? JSON.stringify(body) : undefined,
|
|
165
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
166
|
+
// The base URL is a module constant; there is no legitimate redirect.
|
|
167
|
+
// Refusing is explicit, rather than trusting the spec to strip the
|
|
168
|
+
// Authorization header on a cross-origin hop (RS005).
|
|
169
|
+
redirect: "error",
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (isAbortError(error)) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
retryAfterMs: null,
|
|
176
|
+
error: new LlmTransportError("timeout", `provider call timed out after ${timeoutMs}ms`, {
|
|
177
|
+
retryable: true,
|
|
178
|
+
}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Transport-level failure (DNS, TLS, connection reset, refused redirect).
|
|
182
|
+
// The underlying message can echo request details, so it is not carried.
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
retryAfterMs: null,
|
|
186
|
+
error: new LlmTransportError("provider_error", "provider connection failed", {
|
|
187
|
+
retryable: true,
|
|
188
|
+
}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
retryAfterMs: retryAfterMs(response),
|
|
196
|
+
error: new LlmTransportError(
|
|
197
|
+
classifyStatus(response.status),
|
|
198
|
+
redact(`provider returned HTTP ${response.status}`),
|
|
199
|
+
{ status: response.status, retryable: isRetryableStatus(response.status) },
|
|
200
|
+
),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
return { ok: true, body: await response.json() };
|
|
206
|
+
} catch {
|
|
207
|
+
// A 200 that is not JSON is deterministic -- a gateway page, a truncated
|
|
208
|
+
// body. Retrying pays for the same answer, so it is terminal.
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
retryAfterMs: null,
|
|
212
|
+
error: new LlmTransportError("malformed_output", "provider returned a non-JSON body", {
|
|
213
|
+
status: response.status,
|
|
214
|
+
retryable: false,
|
|
215
|
+
}),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// One retry loop for both verbs: the taxonomy, the retryable-status set, the
|
|
221
|
+
// `retry-after` handling, and the backoff are properties of the TRANSPORT,
|
|
222
|
+
// not of the method. A second loop for GET would be a second place for the
|
|
223
|
+
// policy to drift.
|
|
224
|
+
async function send(
|
|
225
|
+
method: "GET" | "POST",
|
|
226
|
+
path: string,
|
|
227
|
+
body: unknown,
|
|
228
|
+
requestOptions: ProviderRequestOptions,
|
|
229
|
+
): Promise<unknown> {
|
|
230
|
+
const maxRetries = requestOptions.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
231
|
+
|
|
232
|
+
for (let index = 0; ; index += 1) {
|
|
233
|
+
const outcome = await attempt(method, path, body, requestOptions.timeoutMs);
|
|
234
|
+
if (outcome.ok) return outcome.body;
|
|
235
|
+
if (!outcome.error.retryable || index === maxRetries) throw outcome.error;
|
|
236
|
+
await sleep(outcome.retryAfterMs ?? backoffMs(index));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
postJson: (path, body, requestOptions) => send("POST", path, body, requestOptions),
|
|
242
|
+
getJson: (path, requestOptions) => send("GET", path, undefined, requestOptions),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const REDACTION_MARKER = "[REDACTED]";
|
|
2
|
+
|
|
3
|
+
const SECRET_KEY_PATTERN = /(?:api[_-]?key|apikey|authorization|token|secret|password|credential)/i;
|
|
4
|
+
const BEARER_TOKEN_PATTERN = /\bBearer\s+[^\s,;"'}\]]+/gi;
|
|
5
|
+
|
|
6
|
+
export interface RedactionOptions {
|
|
7
|
+
secrets?: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class UnsafeFixtureError extends Error {
|
|
11
|
+
constructor(message: string) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "UnsafeFixtureError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function redactString(value: string, options: RedactionOptions = {}): string {
|
|
18
|
+
let redacted = value.replace(BEARER_TOKEN_PATTERN, `Bearer ${REDACTION_MARKER}`);
|
|
19
|
+
for (const secret of normalizedSecrets(options.secrets ?? [])) {
|
|
20
|
+
redacted = redacted.split(secret).join(REDACTION_MARKER);
|
|
21
|
+
}
|
|
22
|
+
return redacted;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function redactJson(value: unknown, options: RedactionOptions = {}): unknown {
|
|
26
|
+
return redactJsonValue(value, options, undefined);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function assertFixtureSafe(value: unknown, options: RedactionOptions = {}): void {
|
|
30
|
+
const leaks = findFixtureLeaks(value, options);
|
|
31
|
+
if (leaks.length > 0) {
|
|
32
|
+
throw new UnsafeFixtureError(
|
|
33
|
+
`unsafe fixture contains unsanitized secret material: ${leaks.join(", ")}`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function redactJsonValue(
|
|
39
|
+
value: unknown,
|
|
40
|
+
options: RedactionOptions,
|
|
41
|
+
key: string | undefined,
|
|
42
|
+
): unknown {
|
|
43
|
+
if (SECRET_KEY_PATTERN.test(key ?? "")) {
|
|
44
|
+
return REDACTION_MARKER;
|
|
45
|
+
}
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
return redactString(value, options);
|
|
48
|
+
}
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
return value.map((item) => redactJsonValue(item, options, undefined));
|
|
51
|
+
}
|
|
52
|
+
if (isRecord(value)) {
|
|
53
|
+
const entries = Object.entries(value).map(([childKey, childValue]) => [
|
|
54
|
+
childKey,
|
|
55
|
+
redactJsonValue(childValue, options, childKey),
|
|
56
|
+
]);
|
|
57
|
+
return Object.fromEntries(entries);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function findFixtureLeaks(value: unknown, options: RedactionOptions): string[] {
|
|
63
|
+
const leaks: string[] = [];
|
|
64
|
+
walk(value, [], (path, current, key) => {
|
|
65
|
+
if (typeof current !== "string") {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const pathText = path.join(".") || "<root>";
|
|
69
|
+
if (SECRET_KEY_PATTERN.test(key ?? "") && current !== REDACTION_MARKER) {
|
|
70
|
+
leaks.push(`${pathText} uses secret-looking key without redaction`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (BEARER_TOKEN_PATTERN.test(current) && !current.includes(REDACTION_MARKER)) {
|
|
74
|
+
leaks.push(`${pathText} contains bearer token`);
|
|
75
|
+
}
|
|
76
|
+
for (const secret of normalizedSecrets(options.secrets ?? [])) {
|
|
77
|
+
if (current.includes(secret)) {
|
|
78
|
+
leaks.push(`${pathText} contains configured secret`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return leaks;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function walk(
|
|
86
|
+
value: unknown,
|
|
87
|
+
path: readonly string[],
|
|
88
|
+
visit: (path: readonly string[], value: unknown, key: string | undefined) => void,
|
|
89
|
+
): void {
|
|
90
|
+
visit(path, value, path.at(-1));
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
value.forEach((item, index) => {
|
|
93
|
+
walk(item, [...path, String(index)], visit);
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (isRecord(value)) {
|
|
98
|
+
for (const [key, child] of Object.entries(value)) {
|
|
99
|
+
walk(child, [...path, key], visit);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function normalizedSecrets(secrets: readonly string[]): string[] {
|
|
105
|
+
return secrets.map((secret) => secret.trim()).filter((secret) => secret.length > 0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
109
|
+
return typeof value === "object" && value !== null;
|
|
110
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
import { assertFixtureSafe, type RedactionOptions } from "./redaction.ts";
|
|
4
|
+
|
|
5
|
+
export type ReplayFixture = unknown;
|
|
6
|
+
|
|
7
|
+
export async function loadReplayFixture(
|
|
8
|
+
path: string,
|
|
9
|
+
options: RedactionOptions = {},
|
|
10
|
+
): Promise<ReplayFixture> {
|
|
11
|
+
const raw = await readFile(path, "utf8");
|
|
12
|
+
const fixture = JSON.parse(raw) as ReplayFixture;
|
|
13
|
+
assertFixtureSafe(fixture, options);
|
|
14
|
+
return fixture;
|
|
15
|
+
}
|