@ouro.bot/cli 0.1.0-alpha.56 → 0.1.0-alpha.561
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/README.md +127 -23
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3604 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +837 -26
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +479 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +322 -0
- package/dist/heart/config.js +114 -118
- package/dist/heart/core.js +913 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +419 -0
- package/dist/heart/daemon/agent-discovery.js +102 -3
- package/dist/heart/daemon/agent-service.js +522 -0
- package/dist/heart/daemon/agentic-repair.js +547 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +776 -0
- package/dist/heart/daemon/cli-exec.js +7457 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1592 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +763 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1698
- package/dist/heart/daemon/daemon-entry.js +387 -2
- package/dist/heart/daemon/daemon-health.js +176 -0
- package/dist/heart/daemon/daemon-rollup.js +57 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +796 -71
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +826 -0
- package/dist/heart/daemon/health-monitor.js +122 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +14 -12
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +375 -33
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +3 -31
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +389 -38
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +158 -11
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +330 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +203 -57
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +31 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +195 -0
- package/dist/heart/mailbox/readers/agent-machine.js +382 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
- package/dist/heart/mailbox/readers/mail.js +362 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
- package/dist/heart/mailbox/readers/sessions.js +232 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +683 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +267 -0
- package/dist/heart/provider-credentials.js +425 -0
- package/dist/heart/provider-failover.js +301 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-readiness-cache.js +40 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +139 -52
- package/dist/heart/providers/azure.js +97 -13
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +367 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +13 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1149 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +243 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +9 -5
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-description.js +139 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +389 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailbox-ui/assets/index-B-461hes.js +61 -0
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/index.html +15 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +674 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +720 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +430 -0
- package/dist/mailroom/mbox-import.js +383 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +233 -0
- package/dist/mailroom/search-cache.js +256 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +165 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +62 -75
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +39 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1011 -123
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +129 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +963 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +178 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +295 -0
- package/dist/repertoire/mcp-manager.js +362 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +47 -1075
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +142 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1857 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-session.js +750 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +604 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +108 -100
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +594 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +77 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +2305 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +520 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +549 -181
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +251 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +178 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +26 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +85 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +80 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +38 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/auth-flow.js +0 -351
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1177
- package/dist/senses/debug-activity.js +0 -148
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -33,53 +33,25 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
38
|
-
exports.
|
|
39
|
-
exports.
|
|
36
|
+
exports.ensureDiaryStorePaths = ensureDiaryStorePaths;
|
|
37
|
+
exports.appendEntriesWithDedup = appendEntriesWithDedup;
|
|
38
|
+
exports.resolveDiaryRoot = resolveDiaryRoot;
|
|
39
|
+
exports.readDiaryEntries = readDiaryEntries;
|
|
40
|
+
exports.saveDiaryEntry = saveDiaryEntry;
|
|
40
41
|
exports.backfillEmbeddings = backfillEmbeddings;
|
|
41
|
-
exports.
|
|
42
|
+
exports.searchDiaryEntries = searchDiaryEntries;
|
|
42
43
|
const fs = __importStar(require("fs"));
|
|
43
44
|
const path = __importStar(require("path"));
|
|
44
45
|
const crypto_1 = require("crypto");
|
|
45
|
-
const config_1 = require("../heart/config");
|
|
46
46
|
const identity_1 = require("../heart/identity");
|
|
47
47
|
const runtime_1 = require("../nerves/runtime");
|
|
48
|
-
const
|
|
48
|
+
const note_search_1 = require("./note-search");
|
|
49
|
+
const diary_integrity_1 = require("./diary-integrity");
|
|
50
|
+
const embedding_provider_1 = require("./embedding-provider");
|
|
49
51
|
const DEDUP_THRESHOLD = 0.6;
|
|
50
52
|
const SEMANTIC_DEDUP_THRESHOLD = 0.95;
|
|
51
53
|
const ENTITY_TOKEN = /[a-z0-9]+/g;
|
|
52
|
-
|
|
53
|
-
class OpenAIEmbeddingProvider {
|
|
54
|
-
apiKey;
|
|
55
|
-
model;
|
|
56
|
-
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
57
|
-
this.apiKey = apiKey;
|
|
58
|
-
this.model = model;
|
|
59
|
-
}
|
|
60
|
-
async embed(texts) {
|
|
61
|
-
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
62
|
-
method: "POST",
|
|
63
|
-
headers: {
|
|
64
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
65
|
-
"Content-Type": "application/json",
|
|
66
|
-
},
|
|
67
|
-
body: JSON.stringify({
|
|
68
|
-
model: this.model,
|
|
69
|
-
input: texts,
|
|
70
|
-
}),
|
|
71
|
-
});
|
|
72
|
-
if (!response.ok) {
|
|
73
|
-
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
74
|
-
}
|
|
75
|
-
const payload = (await response.json());
|
|
76
|
-
if (!payload.data || payload.data.length !== texts.length) {
|
|
77
|
-
throw new Error("embedding response missing expected vectors");
|
|
78
|
-
}
|
|
79
|
-
return payload.data.map((entry) => entry.embedding);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function ensureMemoryStorePaths(rootDir) {
|
|
54
|
+
function ensureDiaryStorePaths(rootDir) {
|
|
83
55
|
const factsPath = path.join(rootDir, "facts.jsonl");
|
|
84
56
|
const entitiesPath = path.join(rootDir, "entities.json");
|
|
85
57
|
const dailyDir = path.join(rootDir, "daily");
|
|
@@ -91,8 +63,8 @@ function ensureMemoryStorePaths(rootDir) {
|
|
|
91
63
|
fs.writeFileSync(entitiesPath, "{}\n", "utf8");
|
|
92
64
|
(0, runtime_1.emitNervesEvent)({
|
|
93
65
|
component: "mind",
|
|
94
|
-
event: "mind.
|
|
95
|
-
message: "
|
|
66
|
+
event: "mind.diary_paths_ready",
|
|
67
|
+
message: "diary store paths ready",
|
|
96
68
|
meta: { rootDir },
|
|
97
69
|
});
|
|
98
70
|
return { rootDir, factsPath, entitiesPath, dailyDir };
|
|
@@ -115,7 +87,7 @@ function overlapScore(left, right) {
|
|
|
115
87
|
}
|
|
116
88
|
return common / Math.min(leftWords.size, rightWords.size);
|
|
117
89
|
}
|
|
118
|
-
function
|
|
90
|
+
function readExistingEntries(factsPath) {
|
|
119
91
|
if (!fs.existsSync(factsPath))
|
|
120
92
|
return [];
|
|
121
93
|
const raw = fs.readFileSync(factsPath, "utf8").trim();
|
|
@@ -178,8 +150,8 @@ function appendDailyFact(dailyDir, fact) {
|
|
|
178
150
|
const dayPath = path.join(dailyDir, `${day}.jsonl`);
|
|
179
151
|
fs.appendFileSync(dayPath, `${JSON.stringify(fact)}\n`, "utf8");
|
|
180
152
|
}
|
|
181
|
-
function
|
|
182
|
-
const existing =
|
|
153
|
+
function appendEntriesWithDedup(stores, incoming, options) {
|
|
154
|
+
const existing = readExistingEntries(stores.factsPath);
|
|
183
155
|
const all = [...existing];
|
|
184
156
|
let added = 0;
|
|
185
157
|
let skipped = 0;
|
|
@@ -192,7 +164,7 @@ function appendFactsWithDedup(stores, incoming, options) {
|
|
|
192
164
|
Array.isArray(fact.embedding) && fact.embedding.length > 0 &&
|
|
193
165
|
Array.isArray(prior.embedding) && prior.embedding.length > 0 &&
|
|
194
166
|
fact.embedding.length === prior.embedding.length) {
|
|
195
|
-
return (0,
|
|
167
|
+
return (0, note_search_1.cosineSimilarity)(fact.embedding, prior.embedding) > semanticThreshold;
|
|
196
168
|
}
|
|
197
169
|
return false;
|
|
198
170
|
});
|
|
@@ -208,26 +180,20 @@ function appendFactsWithDedup(stores, incoming, options) {
|
|
|
208
180
|
}
|
|
209
181
|
(0, runtime_1.emitNervesEvent)({
|
|
210
182
|
component: "mind",
|
|
211
|
-
event: "mind.
|
|
212
|
-
message: "
|
|
183
|
+
event: "mind.diary_write",
|
|
184
|
+
message: "diary write completed",
|
|
213
185
|
meta: { added, skipped },
|
|
214
186
|
});
|
|
215
187
|
return { added, skipped };
|
|
216
188
|
}
|
|
217
|
-
function createDefaultEmbeddingProvider() {
|
|
218
|
-
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
219
|
-
if (!apiKey)
|
|
220
|
-
return null;
|
|
221
|
-
return new OpenAIEmbeddingProvider(apiKey);
|
|
222
|
-
}
|
|
223
189
|
async function buildEmbedding(text, embeddingProvider) {
|
|
224
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
190
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
225
191
|
if (!provider) {
|
|
226
192
|
(0, runtime_1.emitNervesEvent)({
|
|
227
193
|
level: "warn",
|
|
228
194
|
component: "mind",
|
|
229
|
-
event: "mind.
|
|
230
|
-
message: "embedding provider unavailable for
|
|
195
|
+
event: "mind.diary_embedding_unavailable",
|
|
196
|
+
message: "embedding provider unavailable for diary write",
|
|
231
197
|
meta: { reason: "missing_openai_embeddings_key" },
|
|
232
198
|
});
|
|
233
199
|
return [];
|
|
@@ -240,8 +206,8 @@ async function buildEmbedding(text, embeddingProvider) {
|
|
|
240
206
|
(0, runtime_1.emitNervesEvent)({
|
|
241
207
|
level: "warn",
|
|
242
208
|
component: "mind",
|
|
243
|
-
event: "mind.
|
|
244
|
-
message: "embedding provider unavailable for
|
|
209
|
+
event: "mind.diary_embedding_unavailable",
|
|
210
|
+
message: "embedding provider unavailable for diary write",
|
|
245
211
|
meta: {
|
|
246
212
|
reason: error instanceof Error ? error.message : String(error),
|
|
247
213
|
},
|
|
@@ -249,13 +215,19 @@ async function buildEmbedding(text, embeddingProvider) {
|
|
|
249
215
|
return [];
|
|
250
216
|
}
|
|
251
217
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
218
|
+
function resolveDiaryRoot(explicitRoot) {
|
|
219
|
+
if (explicitRoot)
|
|
220
|
+
return explicitRoot;
|
|
221
|
+
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
222
|
+
return path.join(agentRoot, "diary");
|
|
254
223
|
}
|
|
255
|
-
|
|
224
|
+
function readDiaryEntries(diaryRoot) {
|
|
225
|
+
return readExistingEntries(path.join(resolveDiaryRoot(diaryRoot), "facts.jsonl"));
|
|
226
|
+
}
|
|
227
|
+
async function saveDiaryEntry(options) {
|
|
256
228
|
const text = options.text.trim();
|
|
257
|
-
const
|
|
258
|
-
const stores =
|
|
229
|
+
const diaryRoot = resolveDiaryRoot(options.diaryRoot);
|
|
230
|
+
const stores = ensureDiaryStorePaths(diaryRoot);
|
|
259
231
|
const embedding = await buildEmbedding(text, options.embeddingProvider);
|
|
260
232
|
const fact = {
|
|
261
233
|
id: options.idFactory ? options.idFactory() : (0, crypto_1.randomUUID)(),
|
|
@@ -264,24 +236,39 @@ async function saveMemoryFact(options) {
|
|
|
264
236
|
about: options.about?.trim() || undefined,
|
|
265
237
|
createdAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
266
238
|
embedding,
|
|
239
|
+
...(options.provenance ? { provenance: options.provenance } : {}),
|
|
267
240
|
};
|
|
268
|
-
|
|
241
|
+
const integrity = (0, diary_integrity_1.detectSuspiciousContent)(text);
|
|
242
|
+
if (integrity.suspicious) {
|
|
243
|
+
(0, runtime_1.emitNervesEvent)({
|
|
244
|
+
level: "warn",
|
|
245
|
+
component: "mind",
|
|
246
|
+
event: "mind.diary_integrity_warning",
|
|
247
|
+
message: "suspicious content detected in diary entry",
|
|
248
|
+
meta: {
|
|
249
|
+
patterns: integrity.patterns,
|
|
250
|
+
textPreview: text.slice(0, 200),
|
|
251
|
+
entryId: fact.id,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return appendEntriesWithDedup(stores, [fact], { semanticThreshold: SEMANTIC_DEDUP_THRESHOLD });
|
|
269
256
|
}
|
|
270
257
|
async function backfillEmbeddings(options) {
|
|
271
|
-
const
|
|
272
|
-
const factsPath = path.join(
|
|
258
|
+
const diaryRoot = resolveDiaryRoot(options?.diaryRoot);
|
|
259
|
+
const factsPath = path.join(diaryRoot, "facts.jsonl");
|
|
273
260
|
if (!fs.existsSync(factsPath))
|
|
274
261
|
return { total: 0, backfilled: 0, failed: 0 };
|
|
275
|
-
const facts =
|
|
262
|
+
const facts = readExistingEntries(factsPath);
|
|
276
263
|
const needsEmbedding = facts.filter((f) => !Array.isArray(f.embedding) || f.embedding.length === 0);
|
|
277
264
|
if (needsEmbedding.length === 0)
|
|
278
265
|
return { total: facts.length, backfilled: 0, failed: 0 };
|
|
279
|
-
const provider = options?.embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
266
|
+
const provider = options?.embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
280
267
|
if (!provider) {
|
|
281
268
|
(0, runtime_1.emitNervesEvent)({
|
|
282
269
|
level: "warn",
|
|
283
270
|
component: "mind",
|
|
284
|
-
event: "mind.
|
|
271
|
+
event: "mind.diary_backfill_skipped",
|
|
285
272
|
message: "embedding provider unavailable for backfill",
|
|
286
273
|
meta: { needsEmbedding: needsEmbedding.length },
|
|
287
274
|
});
|
|
@@ -307,7 +294,7 @@ async function backfillEmbeddings(options) {
|
|
|
307
294
|
(0, runtime_1.emitNervesEvent)({
|
|
308
295
|
level: "warn",
|
|
309
296
|
component: "mind",
|
|
310
|
-
event: "mind.
|
|
297
|
+
event: "mind.diary_backfill_batch_error",
|
|
311
298
|
message: "embedding backfill batch failed",
|
|
312
299
|
meta: {
|
|
313
300
|
batchStart: i,
|
|
@@ -322,7 +309,7 @@ async function backfillEmbeddings(options) {
|
|
|
322
309
|
fs.writeFileSync(factsPath, lines, "utf8");
|
|
323
310
|
(0, runtime_1.emitNervesEvent)({
|
|
324
311
|
component: "mind",
|
|
325
|
-
event: "mind.
|
|
312
|
+
event: "mind.diary_backfill_complete",
|
|
326
313
|
message: "embedding backfill completed",
|
|
327
314
|
meta: { total: facts.length, backfilled, failed },
|
|
328
315
|
});
|
|
@@ -342,7 +329,7 @@ function uniqueFacts(facts) {
|
|
|
342
329
|
}
|
|
343
330
|
return unique;
|
|
344
331
|
}
|
|
345
|
-
async function
|
|
332
|
+
async function searchDiaryEntries(query, facts, embeddingProvider) {
|
|
346
333
|
const trimmed = query.trim();
|
|
347
334
|
if (!trimmed)
|
|
348
335
|
return [];
|
|
@@ -352,7 +339,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
352
339
|
if (embeddedFacts.length === 0) {
|
|
353
340
|
return substringFallback();
|
|
354
341
|
}
|
|
355
|
-
const provider = embeddingProvider ?? createDefaultEmbeddingProvider();
|
|
342
|
+
const provider = embeddingProvider ?? (0, embedding_provider_1.createDefaultEmbeddingProvider)();
|
|
356
343
|
if (!provider) {
|
|
357
344
|
return substringFallback();
|
|
358
345
|
}
|
|
@@ -366,7 +353,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
366
353
|
.filter((fact) => fact.embedding.length === queryEmbedding.length)
|
|
367
354
|
.map((fact) => ({
|
|
368
355
|
fact,
|
|
369
|
-
score: (0,
|
|
356
|
+
score: (0, note_search_1.cosineSimilarity)(queryEmbedding, fact.embedding),
|
|
370
357
|
}))
|
|
371
358
|
.filter((entry) => entry.score > 0)
|
|
372
359
|
.sort((left, right) => right.score - left.score)
|
|
@@ -378,8 +365,8 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
|
|
|
378
365
|
(0, runtime_1.emitNervesEvent)({
|
|
379
366
|
level: "warn",
|
|
380
367
|
component: "mind",
|
|
381
|
-
event: "mind.
|
|
382
|
-
message: "embedding provider unavailable for
|
|
368
|
+
event: "mind.diary_embedding_unavailable",
|
|
369
|
+
message: "embedding provider unavailable for diary search",
|
|
383
370
|
meta: {
|
|
384
371
|
reason: error instanceof Error ? error.message : String(error),
|
|
385
372
|
},
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared OpenAI embedding provider.
|
|
4
|
+
*
|
|
5
|
+
* Both diary.ts and note-search.ts need to call the OpenAI embeddings
|
|
6
|
+
* API. This module provides the shared implementation so neither duplicates
|
|
7
|
+
* the fetch logic.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.OpenAIEmbeddingProvider = void 0;
|
|
11
|
+
exports.createDefaultEmbeddingProvider = createDefaultEmbeddingProvider;
|
|
12
|
+
const config_1 = require("../heart/config");
|
|
13
|
+
const runtime_1 = require("../nerves/runtime");
|
|
14
|
+
const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
15
|
+
class OpenAIEmbeddingProvider {
|
|
16
|
+
apiKey;
|
|
17
|
+
model;
|
|
18
|
+
constructor(apiKey, model = DEFAULT_EMBEDDING_MODEL) {
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
this.model = model;
|
|
21
|
+
}
|
|
22
|
+
async embed(texts) {
|
|
23
|
+
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
model: this.model,
|
|
31
|
+
input: texts,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`embedding request failed: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const payload = (await response.json());
|
|
38
|
+
if (!payload.data || payload.data.length !== texts.length) {
|
|
39
|
+
throw new Error("embedding response missing expected vectors");
|
|
40
|
+
}
|
|
41
|
+
return payload.data.map((entry) => entry.embedding);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.OpenAIEmbeddingProvider = OpenAIEmbeddingProvider;
|
|
45
|
+
/**
|
|
46
|
+
* Create a default embedding provider from the configured API key.
|
|
47
|
+
* Returns null if no key is configured.
|
|
48
|
+
*/
|
|
49
|
+
function createDefaultEmbeddingProvider() {
|
|
50
|
+
const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
|
|
51
|
+
if (!apiKey)
|
|
52
|
+
return null;
|
|
53
|
+
(0, runtime_1.emitNervesEvent)({
|
|
54
|
+
component: "mind",
|
|
55
|
+
event: "mind.embedding_provider_created",
|
|
56
|
+
message: "default embedding provider created",
|
|
57
|
+
meta: { model: DEFAULT_EMBEDDING_MODEL },
|
|
58
|
+
});
|
|
59
|
+
return new OpenAIEmbeddingProvider(apiKey);
|
|
60
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fileStateCache = exports.FileStateCache = void 0;
|
|
4
|
+
exports.contentHash = contentHash;
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const runtime_1 = require("../nerves/runtime");
|
|
8
|
+
/** Compute sha256 hex hash of content */
|
|
9
|
+
function contentHash(content) {
|
|
10
|
+
return (0, crypto_1.createHash)("sha256").update(content).digest("hex");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Session-scoped LRU cache tracking file reads.
|
|
14
|
+
* Stores content hashes (not full content) to limit stored content.
|
|
15
|
+
* Keyed by absolute file path.
|
|
16
|
+
*
|
|
17
|
+
* Also maintains a separate snapshot list for future rewind support.
|
|
18
|
+
* Snapshots are indexed by content hash and linked to conversation messages.
|
|
19
|
+
*/
|
|
20
|
+
class FileStateCache {
|
|
21
|
+
entries;
|
|
22
|
+
maxSize;
|
|
23
|
+
snapshots = [];
|
|
24
|
+
maxSnapshots = 100;
|
|
25
|
+
constructor(maxSize = 50) {
|
|
26
|
+
this.entries = new Map();
|
|
27
|
+
this.maxSize = maxSize;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Record a file read. Computes content hash and stores metadata.
|
|
31
|
+
*/
|
|
32
|
+
record(filePath, content, mtime, offset, limit, messageId) {
|
|
33
|
+
// If key already exists, delete it so re-insertion moves it to end (most recent)
|
|
34
|
+
if (this.entries.has(filePath)) {
|
|
35
|
+
this.entries.delete(filePath);
|
|
36
|
+
}
|
|
37
|
+
const hash = contentHash(content);
|
|
38
|
+
const fullRead = offset === undefined && limit === undefined;
|
|
39
|
+
this.entries.set(filePath, {
|
|
40
|
+
hash,
|
|
41
|
+
mtime,
|
|
42
|
+
offset: fullRead ? undefined : offset,
|
|
43
|
+
limit: fullRead ? undefined : limit,
|
|
44
|
+
fullRead,
|
|
45
|
+
recordedAt: Date.now(),
|
|
46
|
+
messageId,
|
|
47
|
+
});
|
|
48
|
+
(0, runtime_1.emitNervesEvent)({
|
|
49
|
+
component: "mind",
|
|
50
|
+
event: "mind.file_state.record",
|
|
51
|
+
message: "recorded file state",
|
|
52
|
+
meta: { path: filePath, hash, fullRead },
|
|
53
|
+
});
|
|
54
|
+
// Evict LRU (first entry in Map iteration order) if over capacity
|
|
55
|
+
if (this.entries.size > this.maxSize) {
|
|
56
|
+
const firstKey = this.entries.keys().next().value;
|
|
57
|
+
this.entries.delete(firstKey);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get the cached state for a file path. Also promotes it in LRU order.
|
|
62
|
+
*/
|
|
63
|
+
get(filePath) {
|
|
64
|
+
const entry = this.entries.get(filePath);
|
|
65
|
+
if (entry === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
// Promote to most-recently-used by re-inserting
|
|
68
|
+
this.entries.delete(filePath);
|
|
69
|
+
this.entries.set(filePath, entry);
|
|
70
|
+
(0, runtime_1.emitNervesEvent)({
|
|
71
|
+
component: "mind",
|
|
72
|
+
event: "mind.file_state.get",
|
|
73
|
+
message: "retrieved file state",
|
|
74
|
+
meta: { path: filePath, hash: entry.hash },
|
|
75
|
+
});
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if a file has been modified since the last recorded read.
|
|
80
|
+
* Uses mtime as primary signal, content hash as fallback for cloud sync / touch scenarios.
|
|
81
|
+
* Returns { stale: false } if the path is not in cache or the file cannot be stat'd.
|
|
82
|
+
*/
|
|
83
|
+
isStale(filePath) {
|
|
84
|
+
const entry = this.entries.get(filePath);
|
|
85
|
+
if (entry === undefined)
|
|
86
|
+
return { stale: false };
|
|
87
|
+
let currentMtime;
|
|
88
|
+
try {
|
|
89
|
+
currentMtime = (0, fs_1.statSync)(filePath).mtimeMs;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// File doesn't exist or can't be stat'd -- no basis for staleness
|
|
93
|
+
return { stale: false };
|
|
94
|
+
}
|
|
95
|
+
// Fast path: mtime unchanged means not stale
|
|
96
|
+
if (currentMtime === entry.mtime)
|
|
97
|
+
return { stale: false };
|
|
98
|
+
// mtime differs -- check content hash as fallback (handles touch / cloud sync)
|
|
99
|
+
try {
|
|
100
|
+
const currentContent = (0, fs_1.readFileSync)(filePath, "utf-8");
|
|
101
|
+
const currentHash = contentHash(currentContent);
|
|
102
|
+
if (currentHash === entry.hash)
|
|
103
|
+
return { stale: false };
|
|
104
|
+
(0, runtime_1.emitNervesEvent)({
|
|
105
|
+
component: "mind",
|
|
106
|
+
event: "mind.file_state.stale_detected",
|
|
107
|
+
message: "file staleness detected",
|
|
108
|
+
meta: { path: filePath, previousHash: entry.hash, currentHash },
|
|
109
|
+
});
|
|
110
|
+
return { stale: true, reason: `file modified since last read (mtime and content differ)` };
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Can't read file -- treat as not stale (file may have been deleted)
|
|
114
|
+
return { stale: false };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Create a pre-edit snapshot of the current cache state for a file.
|
|
119
|
+
* Snapshots are stored separately from the LRU cache for future rewind support.
|
|
120
|
+
* Returns undefined if the path is not in cache.
|
|
121
|
+
*/
|
|
122
|
+
snapshot(filePath) {
|
|
123
|
+
const entry = this.entries.get(filePath);
|
|
124
|
+
if (entry === undefined)
|
|
125
|
+
return undefined;
|
|
126
|
+
const snap = {
|
|
127
|
+
filePath,
|
|
128
|
+
hash: entry.hash,
|
|
129
|
+
mtime: entry.mtime,
|
|
130
|
+
messageId: entry.messageId,
|
|
131
|
+
createdAt: Date.now(),
|
|
132
|
+
};
|
|
133
|
+
this.snapshots.push(snap);
|
|
134
|
+
(0, runtime_1.emitNervesEvent)({
|
|
135
|
+
component: "mind",
|
|
136
|
+
event: "mind.file_state.snapshot_created",
|
|
137
|
+
message: "created file state snapshot",
|
|
138
|
+
meta: { path: filePath, hash: snap.hash },
|
|
139
|
+
});
|
|
140
|
+
// Evict oldest snapshots if over capacity
|
|
141
|
+
if (this.snapshots.length > this.maxSnapshots) {
|
|
142
|
+
this.snapshots = this.snapshots.slice(this.snapshots.length - this.maxSnapshots);
|
|
143
|
+
}
|
|
144
|
+
return snap;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all snapshots in creation order.
|
|
148
|
+
*/
|
|
149
|
+
getSnapshots() {
|
|
150
|
+
return this.snapshots;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Look up a snapshot by content hash. Returns the first match.
|
|
154
|
+
*/
|
|
155
|
+
lookupSnapshotByHash(hash) {
|
|
156
|
+
return this.snapshots.find(s => s.hash === hash);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Clear all snapshots.
|
|
160
|
+
*/
|
|
161
|
+
clearSnapshots() {
|
|
162
|
+
this.snapshots = [];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Clear all cached entries (does not clear snapshots).
|
|
166
|
+
*/
|
|
167
|
+
clear() {
|
|
168
|
+
(0, runtime_1.emitNervesEvent)({
|
|
169
|
+
component: "mind",
|
|
170
|
+
event: "mind.file_state.clear",
|
|
171
|
+
message: "cleared file state cache",
|
|
172
|
+
meta: { entryCount: this.entries.size },
|
|
173
|
+
});
|
|
174
|
+
this.entries.clear();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.FileStateCache = FileStateCache;
|
|
178
|
+
/** Session-scoped singleton instance used by tool handlers */
|
|
179
|
+
exports.fileStateCache = new FileStateCache();
|
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
// Channel capabilities -- hardcoded const map keyed by channel identifier.
|
|
3
3
|
// Pure lookup, no I/O, cannot fail. Unknown channel gets minimal defaults.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.channelToFacing = channelToFacing;
|
|
5
6
|
exports.getChannelCapabilities = getChannelCapabilities;
|
|
6
7
|
exports.isRemoteChannel = isRemoteChannel;
|
|
7
8
|
exports.getAlwaysOnSenseNames = getAlwaysOnSenseNames;
|
|
8
9
|
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
+
const AGENT_FACING_CHANNELS = new Set(["inner", "mcp"]);
|
|
11
|
+
function channelToFacing(channel) {
|
|
12
|
+
const facing = channel && AGENT_FACING_CHANNELS.has(channel) ? "agent" : "human";
|
|
13
|
+
(0, runtime_1.emitNervesEvent)({
|
|
14
|
+
component: "channels",
|
|
15
|
+
event: "channel.facing_lookup",
|
|
16
|
+
message: "channel facing lookup",
|
|
17
|
+
meta: { channel: channel ?? "undefined", facing },
|
|
18
|
+
});
|
|
19
|
+
return facing;
|
|
20
|
+
}
|
|
9
21
|
const CHANNEL_CAPABILITIES = {
|
|
10
22
|
cli: {
|
|
11
23
|
channel: "cli",
|
|
@@ -34,6 +46,24 @@ const CHANNEL_CAPABILITIES = {
|
|
|
34
46
|
supportsRichCards: false,
|
|
35
47
|
maxMessageLength: Infinity,
|
|
36
48
|
},
|
|
49
|
+
mail: {
|
|
50
|
+
channel: "mail",
|
|
51
|
+
senseType: "open",
|
|
52
|
+
availableIntegrations: [],
|
|
53
|
+
supportsMarkdown: false,
|
|
54
|
+
supportsStreaming: false,
|
|
55
|
+
supportsRichCards: false,
|
|
56
|
+
maxMessageLength: Infinity,
|
|
57
|
+
},
|
|
58
|
+
voice: {
|
|
59
|
+
channel: "voice",
|
|
60
|
+
senseType: "local",
|
|
61
|
+
availableIntegrations: [],
|
|
62
|
+
supportsMarkdown: false,
|
|
63
|
+
supportsStreaming: true,
|
|
64
|
+
supportsRichCards: false,
|
|
65
|
+
maxMessageLength: Infinity,
|
|
66
|
+
},
|
|
37
67
|
inner: {
|
|
38
68
|
channel: "inner",
|
|
39
69
|
senseType: "internal",
|
|
@@ -43,6 +73,15 @@ const CHANNEL_CAPABILITIES = {
|
|
|
43
73
|
supportsRichCards: false,
|
|
44
74
|
maxMessageLength: Infinity,
|
|
45
75
|
},
|
|
76
|
+
mcp: {
|
|
77
|
+
channel: "mcp",
|
|
78
|
+
senseType: "local",
|
|
79
|
+
availableIntegrations: [],
|
|
80
|
+
supportsMarkdown: true,
|
|
81
|
+
supportsStreaming: false,
|
|
82
|
+
supportsRichCards: false,
|
|
83
|
+
maxMessageLength: Infinity,
|
|
84
|
+
},
|
|
46
85
|
};
|
|
47
86
|
const DEFAULT_CAPABILITIES = {
|
|
48
87
|
channel: "cli",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// FriendResolver -- resolves external identity into a FriendRecord + channel capabilities.
|
|
3
3
|
// Created per-request (per-incoming-message), per-friend.
|
|
4
|
-
// Replaces the old ContextResolver: no authority checker, no separate
|
|
4
|
+
// Replaces the old ContextResolver: no authority checker, no separate note resolution.
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.FriendResolver = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
@@ -31,6 +31,43 @@ class FriendResolver {
|
|
|
31
31
|
}
|
|
32
32
|
if (existing)
|
|
33
33
|
return existing;
|
|
34
|
+
// Migration: local provider previously used "${username}@${hostname}" format.
|
|
35
|
+
// If no exact match, try finding a friend with old-format external ID.
|
|
36
|
+
/* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
|
|
37
|
+
if (this.params.provider === "local" && !this.params.externalId.includes("@")) {
|
|
38
|
+
try {
|
|
39
|
+
const all = typeof this.store.listAll === "function" ? await this.store.listAll() : [];
|
|
40
|
+
/* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
|
|
41
|
+
const migrationMatch = all.find((f) => f.externalIds.some((eid) => eid.provider === "local" && eid.externalId.startsWith(this.params.externalId + "@")));
|
|
42
|
+
if (migrationMatch) {
|
|
43
|
+
const now = new Date().toISOString();
|
|
44
|
+
migrationMatch.externalIds.push({
|
|
45
|
+
provider: this.params.provider,
|
|
46
|
+
externalId: this.params.externalId,
|
|
47
|
+
linkedAt: now,
|
|
48
|
+
});
|
|
49
|
+
migrationMatch.updatedAt = now;
|
|
50
|
+
try {
|
|
51
|
+
await this.store.put(migrationMatch.id, migrationMatch);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// best-effort persist
|
|
55
|
+
}
|
|
56
|
+
(0, runtime_1.emitNervesEvent)({
|
|
57
|
+
component: "friends",
|
|
58
|
+
event: "friends.local_id_migrated",
|
|
59
|
+
message: `migrated local friend identity from hostname format to username-only`,
|
|
60
|
+
meta: { friendId: migrationMatch.id, newExternalId: this.params.externalId },
|
|
61
|
+
});
|
|
62
|
+
return migrationMatch;
|
|
63
|
+
}
|
|
64
|
+
/* v8 ignore stop */
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// fall through to create new
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/* v8 ignore stop */
|
|
34
71
|
// First encounter -- create new FriendRecord
|
|
35
72
|
const now = new Date().toISOString();
|
|
36
73
|
const externalId = {
|
|
@@ -50,6 +87,21 @@ class FriendResolver {
|
|
|
50
87
|
hasAnyFriends = false;
|
|
51
88
|
}
|
|
52
89
|
const isFirstImprint = !hasAnyFriends;
|
|
90
|
+
// BlueBubbles group chats route through here as `imessage-handle` with an
|
|
91
|
+
// externalId of the form `group:any;+;<chatHash>`. When the harness auto-
|
|
92
|
+
// creates the group friend at stranger trust, we mark the record so that
|
|
93
|
+
// the trust gate can surface the relationship for explicit acknowledgment
|
|
94
|
+
// later instead of letting messages accumulate silently.
|
|
95
|
+
const isImessageGroup = this.params.provider === "imessage-handle" &&
|
|
96
|
+
typeof this.params.externalId === "string" &&
|
|
97
|
+
this.params.externalId.startsWith("group:");
|
|
98
|
+
const notes = {};
|
|
99
|
+
if (this.params.displayName !== "Unknown") {
|
|
100
|
+
notes.name = { value: this.params.displayName, savedAt: now };
|
|
101
|
+
}
|
|
102
|
+
if (isImessageGroup && !isFirstImprint) {
|
|
103
|
+
notes.autoCreatedGroup = { value: "true", savedAt: now };
|
|
104
|
+
}
|
|
53
105
|
const friend = {
|
|
54
106
|
id: (0, crypto_1.randomUUID)(),
|
|
55
107
|
name: this.params.displayName,
|
|
@@ -59,7 +111,7 @@ class FriendResolver {
|
|
|
59
111
|
externalIds: [externalId],
|
|
60
112
|
tenantMemberships,
|
|
61
113
|
toolPreferences: {},
|
|
62
|
-
notes
|
|
114
|
+
notes,
|
|
63
115
|
totalTokens: 0,
|
|
64
116
|
createdAt: now,
|
|
65
117
|
updatedAt: now,
|