@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.550
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 +133 -19
- 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-bootstrap-drift.md +54 -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 +3555 -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 +304 -0
- package/dist/heart/config.js +114 -118
- package/dist/heart/core.js +925 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +512 -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 +554 -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 +665 -0
- package/dist/heart/daemon/cli-exec.js +7565 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1590 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +775 -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 -1672
- package/dist/heart/daemon/daemon-entry.js +417 -2
- package/dist/heart/daemon/daemon-health.js +183 -0
- package/dist/heart/daemon/daemon-rollup.js +58 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +758 -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 +844 -0
- package/dist/heart/daemon/drift-detection.js +146 -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 +102 -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 +353 -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 +52 -117
- 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 +200 -51
- 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 +255 -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-state.js +216 -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 +11 -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 +381 -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-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -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 +30 -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 +995 -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 +139 -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 +816 -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 +111 -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 +561 -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 +569 -182
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +248 -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/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/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,15 +33,31 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.downloadBlueBubblesAttachment = exports.VLM_TEXT_WRAPPERS = void 0;
|
|
36
37
|
exports.hydrateBlueBubblesAttachments = hydrateBlueBubblesAttachments;
|
|
37
38
|
const node_child_process_1 = require("node:child_process");
|
|
38
39
|
const fs = __importStar(require("node:fs/promises"));
|
|
39
40
|
const os = __importStar(require("node:os"));
|
|
40
41
|
const path = __importStar(require("node:path"));
|
|
41
|
-
const runtime_1 = require("
|
|
42
|
-
const
|
|
42
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
43
|
+
const identity_1 = require("../../heart/identity");
|
|
44
|
+
const model_capabilities_1 = require("../../heart/model-capabilities");
|
|
45
|
+
const image_normalize_1 = require("../../heart/attachments/image-normalize");
|
|
46
|
+
const store_1 = require("../../heart/attachments/store");
|
|
47
|
+
const bluebubbles_1 = require("../../heart/attachments/sources/bluebubbles");
|
|
48
|
+
const attachment_download_1 = require("./attachment-download");
|
|
49
|
+
// Pin the exact wrapper strings so tests and code read from one source.
|
|
50
|
+
exports.VLM_TEXT_WRAPPERS = {
|
|
51
|
+
description: (desc) => `[image description: ${desc}]`,
|
|
52
|
+
failure: (reason) => `[image description failed: ${reason}]`,
|
|
53
|
+
};
|
|
54
|
+
// D3 prompt template. Included here (not templated out) because the contract
|
|
55
|
+
// is load-bearing — see planning doc section D3 and AX-4.
|
|
56
|
+
function buildVlmPrompt(userText) {
|
|
57
|
+
const body = userText ?? "";
|
|
58
|
+
return `User message: "${body}"\n\nDescribe this image in detail, focusing on anything relevant to what the user said above.\nInclude any text visible in the image verbatim.`;
|
|
59
|
+
}
|
|
43
60
|
const AUDIO_EXTENSIONS = new Set([".mp3", ".wav", ".m4a", ".caf", ".ogg"]);
|
|
44
|
-
const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".heic", ".heif"]);
|
|
45
61
|
const AUDIO_EXTENSION_BY_CONTENT_TYPE = {
|
|
46
62
|
"audio/wav": ".wav",
|
|
47
63
|
"audio/x-wav": ".wav",
|
|
@@ -65,31 +81,19 @@ const AUDIO_INPUT_FORMAT_BY_EXTENSION = {
|
|
|
65
81
|
const WHISPER_CPP_FORMULA = "whisper-cpp";
|
|
66
82
|
const WHISPER_CPP_MODEL_NAME = "ggml-base.en.bin";
|
|
67
83
|
const WHISPER_CPP_MODEL_URL = `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${WHISPER_CPP_MODEL_NAME}`;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
// Lazy — getAgentToolsRoot() requires identity to be resolved, which isn't
|
|
85
|
+
// true at module-load time in most unit test contexts. Tests that only touch
|
|
86
|
+
// the image/VLM path shouldn't break because the audio path asked for a
|
|
87
|
+
// tools root they don't need.
|
|
88
|
+
function whisperCppPaths() {
|
|
89
|
+
const toolsDir = path.join((0, identity_1.getAgentToolsRoot)(), "whisper-cpp");
|
|
90
|
+
const modelsDir = path.join(toolsDir, "models");
|
|
91
|
+
const modelPath = path.join(modelsDir, WHISPER_CPP_MODEL_NAME);
|
|
92
|
+
return { toolsDir, modelsDir, modelPath };
|
|
76
93
|
}
|
|
77
94
|
function describeAttachment(attachment) {
|
|
78
95
|
return attachment.transferName?.trim() || attachment.guid?.trim() || "attachment";
|
|
79
96
|
}
|
|
80
|
-
function inferContentType(attachment, responseType) {
|
|
81
|
-
const normalizedResponseType = responseType?.split(";")[0]?.trim().toLowerCase();
|
|
82
|
-
if (normalizedResponseType) {
|
|
83
|
-
return normalizedResponseType;
|
|
84
|
-
}
|
|
85
|
-
return attachment.mimeType?.trim().toLowerCase() || undefined;
|
|
86
|
-
}
|
|
87
|
-
function isImageAttachment(attachment, contentType) {
|
|
88
|
-
if (contentType?.startsWith("image/"))
|
|
89
|
-
return true;
|
|
90
|
-
const extension = path.extname(attachment.transferName ?? "").toLowerCase();
|
|
91
|
-
return IMAGE_EXTENSIONS.has(extension);
|
|
92
|
-
}
|
|
93
97
|
function isAudioAttachment(attachment, contentType) {
|
|
94
98
|
if (contentType?.startsWith("audio/"))
|
|
95
99
|
return true;
|
|
@@ -169,12 +173,13 @@ async function resolveWhisperCppBinary(timeoutMs) {
|
|
|
169
173
|
return candidate;
|
|
170
174
|
}
|
|
171
175
|
async function ensureWhisperCppModel(timeoutMs, fetchImpl) {
|
|
176
|
+
const { modelsDir, modelPath } = whisperCppPaths();
|
|
172
177
|
try {
|
|
173
|
-
await fs.access(
|
|
174
|
-
return
|
|
178
|
+
await fs.access(modelPath);
|
|
179
|
+
return modelPath;
|
|
175
180
|
}
|
|
176
181
|
catch {
|
|
177
|
-
await fs.mkdir(
|
|
182
|
+
await fs.mkdir(modelsDir, { recursive: true });
|
|
178
183
|
const response = await fetchImpl(WHISPER_CPP_MODEL_URL, {
|
|
179
184
|
method: "GET",
|
|
180
185
|
signal: AbortSignal.timeout(Math.max(timeoutMs, 300_000)),
|
|
@@ -182,8 +187,8 @@ async function ensureWhisperCppModel(timeoutMs, fetchImpl) {
|
|
|
182
187
|
if (!response.ok) {
|
|
183
188
|
throw new Error(`failed to download whisper.cpp model: HTTP ${response.status}`);
|
|
184
189
|
}
|
|
185
|
-
await fs.writeFile(
|
|
186
|
-
return
|
|
190
|
+
await fs.writeFile(modelPath, Buffer.from(await response.arrayBuffer()));
|
|
191
|
+
return modelPath;
|
|
187
192
|
}
|
|
188
193
|
}
|
|
189
194
|
async function convertAudioForWhisperCpp(sourcePath, outputPath, timeoutMs) {
|
|
@@ -235,59 +240,105 @@ async function transcribeAudioWithWhisperCpp(params, modelFetchImpl = fetch) {
|
|
|
235
240
|
await fs.rm(workDir, { recursive: true, force: true }).catch(() => undefined);
|
|
236
241
|
}
|
|
237
242
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (!guid) {
|
|
241
|
-
throw new Error("attachment guid missing");
|
|
242
|
-
}
|
|
243
|
-
if (typeof attachment.totalBytes === "number" && attachment.totalBytes > MAX_ATTACHMENT_BYTES) {
|
|
244
|
-
throw new Error(`attachment exceeds ${MAX_ATTACHMENT_BYTES} byte limit`);
|
|
245
|
-
}
|
|
246
|
-
const url = buildBlueBubblesApiUrl(config.serverUrl, `/api/v1/attachment/${encodeURIComponent(guid)}/download`, config.password);
|
|
247
|
-
const response = await fetchImpl(url, {
|
|
248
|
-
method: "GET",
|
|
249
|
-
signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
|
|
250
|
-
});
|
|
251
|
-
if (!response.ok) {
|
|
252
|
-
throw new Error(`HTTP ${response.status}`);
|
|
253
|
-
}
|
|
254
|
-
const buffer = Buffer.from(await response.arrayBuffer());
|
|
255
|
-
if (buffer.length > MAX_ATTACHMENT_BYTES) {
|
|
256
|
-
throw new Error(`attachment exceeds ${MAX_ATTACHMENT_BYTES} byte limit`);
|
|
257
|
-
}
|
|
258
|
-
return {
|
|
259
|
-
buffer,
|
|
260
|
-
contentType: inferContentType(attachment, response.headers.get("content-type")),
|
|
261
|
-
};
|
|
262
|
-
}
|
|
243
|
+
var attachment_download_2 = require("./attachment-download");
|
|
244
|
+
Object.defineProperty(exports, "downloadBlueBubblesAttachment", { enumerable: true, get: function () { return attachment_download_2.downloadBlueBubblesAttachment; } });
|
|
263
245
|
async function hydrateBlueBubblesAttachments(attachments, config, channelConfig, deps = {}) {
|
|
264
|
-
(0, runtime_1.emitNervesEvent)({
|
|
265
|
-
component: "senses",
|
|
266
|
-
event: "senses.bluebubbles_media_hydrate",
|
|
267
|
-
message: "hydrating bluebubbles attachments",
|
|
268
|
-
meta: {
|
|
269
|
-
attachmentCount: attachments.length,
|
|
270
|
-
preferAudioInput: deps.preferAudioInput ?? false,
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
246
|
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
274
247
|
const modelFetchImpl = deps.modelFetchImpl ?? fetch;
|
|
275
248
|
const transcribeAudio = deps.transcribeAudio ?? ((params) => transcribeAudioWithWhisperCpp(params, modelFetchImpl));
|
|
276
249
|
const preferAudioInput = deps.preferAudioInput ?? false;
|
|
250
|
+
const chatModel = deps.chatModel;
|
|
251
|
+
const visionCapable = chatModel ? (0, model_capabilities_1.getModelCapabilities)(chatModel).vision === true : true;
|
|
252
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
253
|
+
const agentRoot = (0, identity_1.getAgentRoot)(agentName);
|
|
277
254
|
const inputParts = [];
|
|
278
255
|
const transcriptAdditions = [];
|
|
279
256
|
const notices = [];
|
|
280
257
|
for (const attachment of attachments) {
|
|
281
258
|
const name = describeAttachment(attachment);
|
|
259
|
+
const initialRecord = attachment.guid?.trim()
|
|
260
|
+
? (0, store_1.cacheRecentAttachment)(agentName, (0, bluebubbles_1.buildBlueBubblesAttachmentRecord)(attachment), agentRoot)
|
|
261
|
+
: null;
|
|
282
262
|
try {
|
|
283
|
-
const downloaded = await
|
|
263
|
+
const downloaded = await (0, attachment_download_1.downloadBlueBubblesAttachment)(attachment, config, channelConfig, fetchImpl);
|
|
284
264
|
const base64 = downloaded.buffer.toString("base64");
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
265
|
+
const byteCount = downloaded.buffer.length;
|
|
266
|
+
const persistedRecord = initialRecord && initialRecord.source === "bluebubbles"
|
|
267
|
+
? await (0, bluebubbles_1.persistBlueBubblesAttachmentSource)(agentName, initialRecord, {
|
|
268
|
+
buffer: downloaded.buffer,
|
|
269
|
+
mimeType: downloaded.contentType,
|
|
270
|
+
byteCount,
|
|
271
|
+
}, agentRoot)
|
|
272
|
+
: null;
|
|
273
|
+
if ((0, attachment_download_1.isBlueBubblesImageAttachment)(attachment, downloaded.contentType)) {
|
|
274
|
+
const mimeType = downloaded.contentType ?? "application/octet-stream";
|
|
275
|
+
if (visionCapable) {
|
|
276
|
+
inputParts.push({
|
|
277
|
+
type: "image_url",
|
|
278
|
+
image_url: {
|
|
279
|
+
url: `data:${mimeType};base64,${base64}`,
|
|
280
|
+
detail: "auto",
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
(0, runtime_1.emitNervesEvent)({
|
|
284
|
+
level: "warn",
|
|
285
|
+
component: "senses",
|
|
286
|
+
event: "senses.bluebubbles_media_hydrate",
|
|
287
|
+
message: "bluebubbles media hydrate",
|
|
288
|
+
meta: {
|
|
289
|
+
attachmentGuid: attachment.guid,
|
|
290
|
+
mimeType,
|
|
291
|
+
byteCount,
|
|
292
|
+
hydrationPath: "native-passthrough",
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
if (!deps.vlmDescribe) {
|
|
299
|
+
throw new Error("no VLM describer configured — wire a vlmDescribe dep or configure a vision-capable chat model");
|
|
300
|
+
}
|
|
301
|
+
if (!persistedRecord?.sourceData.localPath) {
|
|
302
|
+
throw new Error("image attachment could not be persisted for normalization");
|
|
303
|
+
}
|
|
304
|
+
const normalized = await (0, image_normalize_1.normalizeImageForVision)({
|
|
305
|
+
attachment: persistedRecord,
|
|
306
|
+
sourcePath: persistedRecord.sourceData.localPath,
|
|
307
|
+
agentName,
|
|
308
|
+
agentRoot,
|
|
309
|
+
});
|
|
310
|
+
const normalizedBuffer = await fs.readFile(normalized.path);
|
|
311
|
+
const normalizedMime = normalized.mimeType ?? persistedRecord.mimeType ?? "image/jpeg";
|
|
312
|
+
const dataUrl = `data:${normalizedMime};base64,${normalizedBuffer.toString("base64")}`;
|
|
313
|
+
const description = await deps.vlmDescribe({
|
|
314
|
+
prompt: buildVlmPrompt(deps.userText),
|
|
315
|
+
imageDataUrl: dataUrl,
|
|
316
|
+
attachmentGuid: attachment.guid,
|
|
317
|
+
mimeType: normalizedMime,
|
|
318
|
+
chatModel,
|
|
319
|
+
});
|
|
320
|
+
inputParts.push({
|
|
321
|
+
type: "text",
|
|
322
|
+
text: exports.VLM_TEXT_WRAPPERS.description(description),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
catch (vlmError) {
|
|
326
|
+
const reason = vlmError instanceof Error ? vlmError.message : String(vlmError);
|
|
327
|
+
inputParts.push({
|
|
328
|
+
type: "text",
|
|
329
|
+
text: exports.VLM_TEXT_WRAPPERS.failure(reason),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
(0, runtime_1.emitNervesEvent)({
|
|
333
|
+
level: "warn",
|
|
334
|
+
component: "senses",
|
|
335
|
+
event: "senses.bluebubbles_media_hydrate",
|
|
336
|
+
message: "bluebubbles media hydrate",
|
|
337
|
+
meta: {
|
|
338
|
+
attachmentGuid: attachment.guid,
|
|
339
|
+
mimeType: persistedRecord?.mimeType ?? mimeType,
|
|
340
|
+
byteCount,
|
|
341
|
+
hydrationPath: "vlm-describe",
|
|
291
342
|
},
|
|
292
343
|
});
|
|
293
344
|
continue;
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BlueBubblesIgnoredEventError = void 0;
|
|
3
4
|
exports.normalizeBlueBubblesEvent = normalizeBlueBubblesEvent;
|
|
4
|
-
const runtime_1 = require("
|
|
5
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
6
|
+
const render_1 = require("../../heart/attachments/render");
|
|
7
|
+
const bluebubbles_1 = require("../../heart/attachments/sources/bluebubbles");
|
|
8
|
+
const IGNORABLE_GUIDLESS_EVENT_TYPES = new Set([
|
|
9
|
+
"chat-read-status-changed",
|
|
10
|
+
]);
|
|
11
|
+
class BlueBubblesIgnoredEventError extends Error {
|
|
12
|
+
eventType;
|
|
13
|
+
constructor(eventType, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "BlueBubblesIgnoredEventError";
|
|
16
|
+
this.eventType = eventType;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.BlueBubblesIgnoredEventError = BlueBubblesIgnoredEventError;
|
|
5
20
|
function asRecord(value) {
|
|
6
21
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
7
22
|
? value
|
|
@@ -107,18 +122,14 @@ function extractAttachments(data) {
|
|
|
107
122
|
function formatAttachmentText(attachments) {
|
|
108
123
|
if (attachments.length === 0)
|
|
109
124
|
return "";
|
|
125
|
+
const renderable = attachments
|
|
126
|
+
.filter((attachment) => typeof attachment.guid === "string" && attachment.guid.trim().length > 0)
|
|
127
|
+
.map((attachment) => (0, bluebubbles_1.buildBlueBubblesAttachmentRecord)(attachment));
|
|
128
|
+
if (renderable.length > 0) {
|
|
129
|
+
return (0, render_1.renderAttachmentBlock)(renderable);
|
|
130
|
+
}
|
|
110
131
|
const [first] = attachments;
|
|
111
|
-
|
|
112
|
-
const label = mime.startsWith("image/")
|
|
113
|
-
? "image attachment"
|
|
114
|
-
: mime.startsWith("audio/")
|
|
115
|
-
? "audio attachment"
|
|
116
|
-
: "attachment";
|
|
117
|
-
const name = first.transferName ? `: ${first.transferName}` : "";
|
|
118
|
-
const dimensions = typeof first.width === "number" && typeof first.height === "number" && first.width > 0 && first.height > 0
|
|
119
|
-
? ` (${first.width}x${first.height})`
|
|
120
|
-
: "";
|
|
121
|
-
return `[${label}${name}${dimensions}]`;
|
|
132
|
+
return `[attachment: ${first.transferName?.trim() || "unknown"}]`;
|
|
122
133
|
}
|
|
123
134
|
function formatMessageText(data, attachments) {
|
|
124
135
|
const text = readString(data, "text")?.trim() ?? "";
|
|
@@ -127,6 +138,13 @@ function formatMessageText(data, attachments) {
|
|
|
127
138
|
if (balloonBundleId === "com.apple.messages.URLBalloonProvider") {
|
|
128
139
|
return `${text}\n[link preview attached]`;
|
|
129
140
|
}
|
|
141
|
+
// B2 fix: when text and attachments both exist, append the attachment
|
|
142
|
+
// marker so downstream senses can see the guid/filename. Previously the
|
|
143
|
+
// marker was dropped whenever text was non-empty, which hid images from
|
|
144
|
+
// the agent when the user captioned a screenshot.
|
|
145
|
+
if (attachments.length > 0) {
|
|
146
|
+
return `${text}\n${formatAttachmentText(attachments)}`;
|
|
147
|
+
}
|
|
130
148
|
return text;
|
|
131
149
|
}
|
|
132
150
|
return formatAttachmentText(attachments);
|
|
@@ -198,6 +216,9 @@ function normalizeBlueBubblesEvent(payload) {
|
|
|
198
216
|
message: "ignored bluebubbles payload without guid",
|
|
199
217
|
meta: { eventType },
|
|
200
218
|
});
|
|
219
|
+
if (IGNORABLE_GUIDLESS_EVENT_TYPES.has(eventType)) {
|
|
220
|
+
throw new BlueBubblesIgnoredEventError(eventType, `Ignored BlueBubbles event '${eventType}' without data.guid`);
|
|
221
|
+
}
|
|
201
222
|
throw new Error("BlueBubbles payload is missing data.guid");
|
|
202
223
|
}
|
|
203
224
|
const threadOriginatorGuid = readString(data, "threadOriginatorGuid")?.trim() || undefined;
|
|
@@ -38,9 +38,9 @@ exports.recordBlueBubblesMutation = recordBlueBubblesMutation;
|
|
|
38
38
|
exports.listBlueBubblesRecoveryCandidates = listBlueBubblesRecoveryCandidates;
|
|
39
39
|
const fs = __importStar(require("node:fs"));
|
|
40
40
|
const path = __importStar(require("node:path"));
|
|
41
|
-
const runtime_1 = require("
|
|
42
|
-
const identity_1 = require("
|
|
43
|
-
const config_1 = require("
|
|
41
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
42
|
+
const identity_1 = require("../../heart/identity");
|
|
43
|
+
const config_1 = require("../../heart/config");
|
|
44
44
|
function getBlueBubblesMutationLogPath(agentName, sessionKey) {
|
|
45
45
|
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
|
|
46
46
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getBlueBubblesProcessedLogPath = getBlueBubblesProcessedLogPath;
|
|
37
|
+
exports.hasProcessedBlueBubblesMessage = hasProcessedBlueBubblesMessage;
|
|
38
|
+
exports.hasProcessedBlueBubblesMessageGuid = hasProcessedBlueBubblesMessageGuid;
|
|
39
|
+
exports.recordProcessedBlueBubblesMessage = recordProcessedBlueBubblesMessage;
|
|
40
|
+
const fs = __importStar(require("node:fs"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const config_1 = require("../../heart/config");
|
|
43
|
+
const identity_1 = require("../../heart/identity");
|
|
44
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
45
|
+
function getBlueBubblesProcessedLogPath(agentName, sessionKey) {
|
|
46
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "processed", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
|
|
47
|
+
}
|
|
48
|
+
function readEntries(filePath) {
|
|
49
|
+
try {
|
|
50
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
51
|
+
return raw
|
|
52
|
+
.split("\n")
|
|
53
|
+
.map((line) => line.trim())
|
|
54
|
+
.filter(Boolean)
|
|
55
|
+
.map((line) => JSON.parse(line))
|
|
56
|
+
.filter((entry) => typeof entry.messageGuid === "string" && typeof entry.sessionKey === "string");
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function readAllEntries(agentName) {
|
|
63
|
+
const processedDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "processed");
|
|
64
|
+
try {
|
|
65
|
+
return fs.readdirSync(processedDir)
|
|
66
|
+
.filter((name) => name.endsWith(".ndjson"))
|
|
67
|
+
.sort()
|
|
68
|
+
.flatMap((name) => readEntries(path.join(processedDir, name)));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function isCompletedProcessedEntry(entry) {
|
|
75
|
+
return entry.outcome !== "recovery-timeout";
|
|
76
|
+
}
|
|
77
|
+
function hasProcessedBlueBubblesMessage(agentName, sessionKey, messageGuid) {
|
|
78
|
+
if (!messageGuid.trim())
|
|
79
|
+
return false;
|
|
80
|
+
const filePath = getBlueBubblesProcessedLogPath(agentName, sessionKey);
|
|
81
|
+
return readEntries(filePath).some((entry) => entry.messageGuid === messageGuid && isCompletedProcessedEntry(entry));
|
|
82
|
+
}
|
|
83
|
+
function hasProcessedBlueBubblesMessageGuid(agentName, messageGuid) {
|
|
84
|
+
if (!messageGuid.trim())
|
|
85
|
+
return false;
|
|
86
|
+
return readAllEntries(agentName).some((entry) => entry.messageGuid === messageGuid && isCompletedProcessedEntry(entry));
|
|
87
|
+
}
|
|
88
|
+
function recordProcessedBlueBubblesMessage(agentName, event, source, outcome) {
|
|
89
|
+
const filePath = getBlueBubblesProcessedLogPath(agentName, event.chat.sessionKey);
|
|
90
|
+
try {
|
|
91
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
92
|
+
if (event.messageGuid.trim() && readEntries(filePath).some((entry) => (entry.messageGuid === event.messageGuid
|
|
93
|
+
&& isCompletedProcessedEntry(entry)))) {
|
|
94
|
+
return filePath;
|
|
95
|
+
}
|
|
96
|
+
fs.appendFileSync(filePath, JSON.stringify({
|
|
97
|
+
recordedAt: new Date().toISOString(),
|
|
98
|
+
messageGuid: event.messageGuid,
|
|
99
|
+
sessionKey: event.chat.sessionKey,
|
|
100
|
+
source,
|
|
101
|
+
outcome,
|
|
102
|
+
}) + "\n", "utf-8");
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
(0, runtime_1.emitNervesEvent)({
|
|
106
|
+
level: "warn",
|
|
107
|
+
component: "senses",
|
|
108
|
+
event: "senses.bluebubbles_processed_log_error",
|
|
109
|
+
message: "failed to record bluebubbles processed sidecar log",
|
|
110
|
+
meta: {
|
|
111
|
+
agentName,
|
|
112
|
+
messageGuid: event.messageGuid,
|
|
113
|
+
sessionKey: event.chat.sessionKey,
|
|
114
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
return filePath;
|
|
118
|
+
}
|
|
119
|
+
(0, runtime_1.emitNervesEvent)({
|
|
120
|
+
component: "senses",
|
|
121
|
+
event: "senses.bluebubbles_processed_logged",
|
|
122
|
+
message: "recorded handled bluebubbles message to processed sidecar log",
|
|
123
|
+
meta: {
|
|
124
|
+
agentName,
|
|
125
|
+
messageGuid: event.messageGuid,
|
|
126
|
+
sessionKey: event.chat.sessionKey,
|
|
127
|
+
source,
|
|
128
|
+
outcome,
|
|
129
|
+
path: filePath,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
return filePath;
|
|
133
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.replayBlueBubblesMessage = replayBlueBubblesMessage;
|
|
4
|
+
exports.formatBlueBubblesReplayText = formatBlueBubblesReplayText;
|
|
5
|
+
const render_1 = require("../../heart/attachments/render");
|
|
6
|
+
const bluebubbles_1 = require("../../heart/attachments/sources/bluebubbles");
|
|
7
|
+
const machine_identity_1 = require("../../heart/machine-identity");
|
|
8
|
+
const identity_1 = require("../../heart/identity");
|
|
9
|
+
const runtime_credentials_1 = require("../../heart/runtime-credentials");
|
|
10
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
11
|
+
const client_1 = require("./client");
|
|
12
|
+
const model_1 = require("./model");
|
|
13
|
+
function buildReplayHint(probeEventType, event) {
|
|
14
|
+
if (probeEventType === "updated-message"
|
|
15
|
+
&& event.kind === "mutation"
|
|
16
|
+
&& (event.mutationType === "read" || event.mutationType === "delivery")) {
|
|
17
|
+
return "replay resolved to a state-only mutation; rerun with --event-type new-message to inspect the original message payload.";
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
async function replayBlueBubblesMessage(params, deps = {}) {
|
|
22
|
+
const agentName = params.agentName.trim();
|
|
23
|
+
const messageGuid = params.messageGuid.trim();
|
|
24
|
+
const eventType = params.eventType ?? "new-message";
|
|
25
|
+
if (!agentName) {
|
|
26
|
+
throw new Error("bluebubbles replay requires agentName");
|
|
27
|
+
}
|
|
28
|
+
if (!messageGuid) {
|
|
29
|
+
throw new Error("bluebubbles replay requires messageGuid");
|
|
30
|
+
}
|
|
31
|
+
const setReplayAgentName = deps.setAgentName ?? identity_1.setAgentName;
|
|
32
|
+
const resetReplayIdentity = deps.resetIdentity ?? identity_1.resetIdentity;
|
|
33
|
+
const normalizeEvent = deps.normalizeEvent ?? model_1.normalizeBlueBubblesEvent;
|
|
34
|
+
const loadMachineId = deps.loadMachineId ?? (() => (0, machine_identity_1.loadOrCreateMachineIdentity)().machineId);
|
|
35
|
+
const refreshMachineRuntimeConfig = deps.refreshMachineRuntimeConfig ?? runtime_credentials_1.refreshMachineRuntimeCredentialConfig;
|
|
36
|
+
(0, runtime_1.emitNervesEvent)({
|
|
37
|
+
component: "senses",
|
|
38
|
+
event: "senses.bluebubbles_replay_start",
|
|
39
|
+
message: "starting bluebubbles historical replay",
|
|
40
|
+
meta: {
|
|
41
|
+
agentName,
|
|
42
|
+
messageGuid,
|
|
43
|
+
eventType,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
setReplayAgentName(agentName);
|
|
47
|
+
try {
|
|
48
|
+
if (!deps.createClient) {
|
|
49
|
+
const machineId = loadMachineId();
|
|
50
|
+
await refreshMachineRuntimeConfig(agentName, machineId, { preserveCachedOnFailure: true });
|
|
51
|
+
}
|
|
52
|
+
const client = deps.createClient ? deps.createClient() : (0, client_1.createBlueBubblesClient)();
|
|
53
|
+
const probe = normalizeEvent({
|
|
54
|
+
type: eventType,
|
|
55
|
+
data: {
|
|
56
|
+
guid: messageGuid,
|
|
57
|
+
hasPayloadData: true,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const event = await client.repairEvent(probe);
|
|
61
|
+
const attachmentRecords = event.kind === "message"
|
|
62
|
+
? event.attachments
|
|
63
|
+
.filter((attachment) => typeof attachment.guid === "string" && attachment.guid.trim().length > 0)
|
|
64
|
+
.map((attachment) => (0, bluebubbles_1.buildBlueBubblesAttachmentRecord)(attachment))
|
|
65
|
+
: [];
|
|
66
|
+
const result = {
|
|
67
|
+
probe: {
|
|
68
|
+
agentName,
|
|
69
|
+
messageGuid,
|
|
70
|
+
eventType,
|
|
71
|
+
},
|
|
72
|
+
event,
|
|
73
|
+
attachmentIds: attachmentRecords.map((attachment) => attachment.id),
|
|
74
|
+
attachmentBlock: (0, render_1.renderAttachmentBlock)(attachmentRecords),
|
|
75
|
+
...(buildReplayHint(eventType, event) ? { hint: buildReplayHint(eventType, event) } : {}),
|
|
76
|
+
};
|
|
77
|
+
(0, runtime_1.emitNervesEvent)({
|
|
78
|
+
component: "senses",
|
|
79
|
+
event: "senses.bluebubbles_replay_end",
|
|
80
|
+
message: "completed bluebubbles historical replay",
|
|
81
|
+
meta: {
|
|
82
|
+
agentName,
|
|
83
|
+
messageGuid,
|
|
84
|
+
eventType,
|
|
85
|
+
kind: event.kind,
|
|
86
|
+
attachmentCount: attachmentRecords.length,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
(0, runtime_1.emitNervesEvent)({
|
|
93
|
+
level: "warn",
|
|
94
|
+
component: "senses",
|
|
95
|
+
event: "senses.bluebubbles_replay_error",
|
|
96
|
+
message: "bluebubbles historical replay failed",
|
|
97
|
+
meta: {
|
|
98
|
+
agentName,
|
|
99
|
+
messageGuid,
|
|
100
|
+
eventType,
|
|
101
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
resetReplayIdentity();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function formatBlueBubblesReplayText(result) {
|
|
111
|
+
const lines = [
|
|
112
|
+
`probe: ${result.probe.eventType}`,
|
|
113
|
+
`agent: ${result.probe.agentName}`,
|
|
114
|
+
`message_guid: ${result.probe.messageGuid}`,
|
|
115
|
+
`result_kind: ${result.event.kind}`,
|
|
116
|
+
`session: ${result.event.chat.sessionKey}`,
|
|
117
|
+
];
|
|
118
|
+
if (result.event.kind === "mutation") {
|
|
119
|
+
lines.push(`mutation_type: ${result.event.mutationType}`);
|
|
120
|
+
}
|
|
121
|
+
if (result.event.kind === "message" && result.event.inputPartsForAgent?.length) {
|
|
122
|
+
lines.push(`input_parts_for_agent: ${result.event.inputPartsForAgent.length}`);
|
|
123
|
+
}
|
|
124
|
+
if (result.event.repairNotice?.trim()) {
|
|
125
|
+
lines.push(`repair_notice: ${result.event.repairNotice.trim()}`);
|
|
126
|
+
}
|
|
127
|
+
if (result.attachmentBlock && !result.event.textForAgent.includes(result.attachmentBlock)) {
|
|
128
|
+
lines.push(result.attachmentBlock);
|
|
129
|
+
}
|
|
130
|
+
lines.push("[text_for_agent]");
|
|
131
|
+
lines.push(result.event.textForAgent || "(empty)");
|
|
132
|
+
if (result.hint) {
|
|
133
|
+
lines.push("[hint]");
|
|
134
|
+
lines.push(result.hint);
|
|
135
|
+
}
|
|
136
|
+
return lines.join("\n");
|
|
137
|
+
}
|