@ouro.bot/cli 0.1.0-alpha.6 → 0.1.0-alpha.600
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 +229 -183
- 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/SerpentGuide.ouro/agent.json +83 -0
- package/SerpentGuide.ouro/psyche/SOUL.md +25 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/assets/ouroboros.png +0 -0
- package/changelog.json +4182 -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 +254 -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 +989 -0
- package/dist/heart/agent-entry.js +69 -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/awaiting/await-alert.js +146 -0
- package/dist/heart/awaiting/await-expiry.js +108 -0
- package/dist/heart/awaiting/await-loader.js +91 -0
- package/dist/heart/awaiting/await-parser.js +141 -0
- package/dist/heart/awaiting/await-runtime-state.js +97 -0
- package/dist/heart/awaiting/await-scheduler.js +377 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +142 -0
- package/dist/heart/config-registry.js +322 -0
- package/dist/heart/config.js +164 -135
- package/dist/heart/core.js +1069 -260
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +419 -0
- package/dist/heart/daemon/agent-discovery.js +180 -0
- 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 +7571 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1599 -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 +30 -758
- package/dist/heart/daemon/daemon-entry.js +540 -8
- 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 +287 -0
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +972 -20
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +873 -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 +206 -0
- 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 +188 -0
- 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 +17 -8
- 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 +381 -26
- 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 +39 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +191 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +731 -0
- 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 +349 -0
- 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 +524 -0
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +62 -0
- 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-animation.js +10 -3
- package/dist/heart/{daemon → hatch}/hatch-flow.js +34 -136
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/hatch/specialist-orchestrator.js +129 -0
- package/dist/heart/hatch/specialist-prompt.js +102 -0
- package/dist/heart/hatch/specialist-tools.js +306 -0
- package/dist/heart/identity.js +281 -67
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +2 -20
- 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 +367 -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 +656 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/progress-story.js +42 -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 +202 -50
- package/dist/heart/providers/azure.js +104 -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 +29 -7
- package/dist/heart/providers/openai-codex.js +63 -39
- 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 +70 -0
- package/dist/heart/session-activity.js +190 -0
- 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 +129 -34
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +127 -0
- 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 +143 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +421 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/versioning/ouro-bot-global-installer.js +129 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -0
- package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/versioning/staged-restart.js +146 -0
- package/dist/heart/versioning/update-checker.js +116 -0
- package/dist/heart/versioning/update-hooks.js +142 -0
- package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
- 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 +700 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +788 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +457 -0
- package/dist/mailroom/mbox-import.js +393 -0
- package/dist/mailroom/migration.js +164 -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 +268 -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 +77 -1
- package/dist/mind/context.js +174 -94
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +74 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +58 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +10 -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 +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1267 -130
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +22 -3
- 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 +17 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +997 -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 +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +220 -13
- package/dist/repertoire/coding/spawner.js +58 -12
- package/dist/repertoire/coding/tools.js +209 -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/data/ado-endpoints.json +188 -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 +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +39 -13
- 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 -79
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-awaiting.js +360 -0
- package/dist/repertoire/tools-base.js +56 -707
- package/dist/repertoire/tools-bluebubbles.js +94 -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 +1916 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-obligations.js +142 -0
- package/dist/repertoire/tools-runtime.js +61 -0
- package/dist/repertoire/tools-session.js +809 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +345 -0
- package/dist/repertoire/tools-teams.js +64 -61
- 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-voice.js +144 -0
- package/dist/repertoire/tools.js +154 -98
- 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/await-turn-message.js +58 -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 +685 -0
- package/dist/senses/bluebubbles/entry.js +77 -0
- package/dist/senses/bluebubbles/inbound-log.js +126 -0
- package/dist/senses/bluebubbles/index.js +2548 -0
- package/dist/senses/bluebubbles/media.js +389 -0
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +45 -16
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/bluebubbles/runtime-state.js +137 -0
- package/dist/senses/bluebubbles/session-cleanup.js +72 -0
- package/dist/senses/bluebubbles-meta-guard.js +40 -0
- 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 +777 -264
- package/dist/senses/commands.js +66 -3
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +209 -16
- package/dist/senses/inner-dialog.js +682 -91
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +751 -0
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +392 -0
- package/dist/senses/surface-tool.js +70 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +925 -195
- package/dist/senses/trust-gate.js +207 -2
- package/dist/senses/voice/audio-playback.js +237 -0
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +202 -0
- package/dist/senses/voice/floor-control.js +431 -0
- package/dist/senses/voice/floor-controller.js +115 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +29 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/outbound.js +190 -0
- package/dist/senses/voice/phone.js +33 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/realtime-eval.js +496 -0
- package/dist/senses/voice/realtime-trace.js +531 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +191 -0
- package/dist/senses/voice/twilio-phone-runtime.js +807 -0
- package/dist/senses/voice/twilio-phone.js +5077 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +81 -0
- package/dist/senses/voice-realtime-eval-command.js +99 -0
- package/dist/senses/voice-realtime-eval-entry.js +21 -0
- package/dist/senses/voice-twilio-entry.js +87 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +265 -0
- package/package.json +52 -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 +99 -0
- package/skills/travel-planning.md +138 -0
- package/AdoptionSpecialist.ouro/agent.json +0 -20
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +0 -22
- package/dist/heart/daemon/specialist-orchestrator.js +0 -160
- package/dist/heart/daemon/specialist-prompt.js +0 -40
- package/dist/heart/daemon/specialist-session.js +0 -142
- package/dist/heart/daemon/specialist-tools.js +0 -128
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/dist/mind/associative-recall.js +0 -197
- package/dist/senses/bluebubbles-client.js +0 -279
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -332
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
- /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/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
|
@@ -0,0 +1,389 @@
|
|
|
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.downloadBlueBubblesAttachment = exports.VLM_TEXT_WRAPPERS = void 0;
|
|
37
|
+
exports.hydrateBlueBubblesAttachments = hydrateBlueBubblesAttachments;
|
|
38
|
+
const node_child_process_1 = require("node:child_process");
|
|
39
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
40
|
+
const os = __importStar(require("node:os"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
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
|
+
}
|
|
60
|
+
const AUDIO_EXTENSIONS = new Set([".mp3", ".wav", ".m4a", ".caf", ".ogg"]);
|
|
61
|
+
const AUDIO_EXTENSION_BY_CONTENT_TYPE = {
|
|
62
|
+
"audio/wav": ".wav",
|
|
63
|
+
"audio/x-wav": ".wav",
|
|
64
|
+
"audio/mp3": ".mp3",
|
|
65
|
+
"audio/mpeg": ".mp3",
|
|
66
|
+
"audio/x-caf": ".caf",
|
|
67
|
+
"audio/caf": ".caf",
|
|
68
|
+
"audio/mp4": ".m4a",
|
|
69
|
+
"audio/x-m4a": ".m4a",
|
|
70
|
+
};
|
|
71
|
+
const AUDIO_INPUT_FORMAT_BY_CONTENT_TYPE = {
|
|
72
|
+
"audio/wav": "wav",
|
|
73
|
+
"audio/x-wav": "wav",
|
|
74
|
+
"audio/mp3": "mp3",
|
|
75
|
+
"audio/mpeg": "mp3",
|
|
76
|
+
};
|
|
77
|
+
const AUDIO_INPUT_FORMAT_BY_EXTENSION = {
|
|
78
|
+
".wav": "wav",
|
|
79
|
+
".mp3": "mp3",
|
|
80
|
+
};
|
|
81
|
+
const WHISPER_CPP_FORMULA = "whisper-cpp";
|
|
82
|
+
const WHISPER_CPP_MODEL_NAME = "ggml-base.en.bin";
|
|
83
|
+
const WHISPER_CPP_MODEL_URL = `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${WHISPER_CPP_MODEL_NAME}`;
|
|
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 };
|
|
93
|
+
}
|
|
94
|
+
function describeAttachment(attachment) {
|
|
95
|
+
return attachment.transferName?.trim() || attachment.guid?.trim() || "attachment";
|
|
96
|
+
}
|
|
97
|
+
function isAudioAttachment(attachment, contentType) {
|
|
98
|
+
if (contentType?.startsWith("audio/"))
|
|
99
|
+
return true;
|
|
100
|
+
const extension = path.extname(attachment.transferName ?? "").toLowerCase();
|
|
101
|
+
return AUDIO_EXTENSIONS.has(extension);
|
|
102
|
+
}
|
|
103
|
+
function sanitizeFilename(name) {
|
|
104
|
+
return path.basename(name).replace(/[\r\n"\\]/g, "_");
|
|
105
|
+
}
|
|
106
|
+
function fileExtensionForAudio(attachment, contentType) {
|
|
107
|
+
const transferExt = path.extname(attachment.transferName ?? "").toLowerCase();
|
|
108
|
+
if (transferExt) {
|
|
109
|
+
return transferExt;
|
|
110
|
+
}
|
|
111
|
+
if (contentType && AUDIO_EXTENSION_BY_CONTENT_TYPE[contentType]) {
|
|
112
|
+
return AUDIO_EXTENSION_BY_CONTENT_TYPE[contentType];
|
|
113
|
+
}
|
|
114
|
+
return ".audio";
|
|
115
|
+
}
|
|
116
|
+
function audioFormatForInput(contentType, attachment) {
|
|
117
|
+
const extension = path.extname(attachment?.transferName ?? "").toLowerCase();
|
|
118
|
+
return AUDIO_INPUT_FORMAT_BY_CONTENT_TYPE[contentType ?? ""] ?? AUDIO_INPUT_FORMAT_BY_EXTENSION[extension];
|
|
119
|
+
}
|
|
120
|
+
async function execFileText(file, args, timeout) {
|
|
121
|
+
return await new Promise((resolve, reject) => {
|
|
122
|
+
(0, node_child_process_1.execFile)(file, args, { timeout }, (error, stdout = "", stderr = "") => {
|
|
123
|
+
if (error) {
|
|
124
|
+
const detail = stderr.trim() || stdout.trim() || error.message;
|
|
125
|
+
reject(new Error(detail));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
resolve(stdout);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async function pathExists(targetPath) {
|
|
133
|
+
try {
|
|
134
|
+
await fs.access(targetPath);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function resolveWhisperCppBinary(timeoutMs) {
|
|
142
|
+
try {
|
|
143
|
+
const existing = (await execFileText("which", ["whisper-cli"], timeoutMs)).trim();
|
|
144
|
+
if (existing) {
|
|
145
|
+
return existing;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// fall through to managed install
|
|
150
|
+
}
|
|
151
|
+
let prefix = "";
|
|
152
|
+
try {
|
|
153
|
+
prefix = (await execFileText("brew", ["--prefix", WHISPER_CPP_FORMULA], timeoutMs)).trim();
|
|
154
|
+
if (prefix) {
|
|
155
|
+
const candidate = path.join(prefix, "bin", "whisper-cli");
|
|
156
|
+
if (await pathExists(candidate)) {
|
|
157
|
+
return candidate;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// fall through to managed install
|
|
163
|
+
}
|
|
164
|
+
await execFileText("brew", ["install", WHISPER_CPP_FORMULA], Math.max(timeoutMs, 300_000));
|
|
165
|
+
prefix = (await execFileText("brew", ["--prefix", WHISPER_CPP_FORMULA], timeoutMs)).trim();
|
|
166
|
+
if (!prefix) {
|
|
167
|
+
throw new Error("whisper.cpp installed but brew did not return a usable prefix");
|
|
168
|
+
}
|
|
169
|
+
const candidate = path.join(prefix, "bin", "whisper-cli");
|
|
170
|
+
if (!await pathExists(candidate)) {
|
|
171
|
+
throw new Error("whisper.cpp installed but whisper-cli binary is missing");
|
|
172
|
+
}
|
|
173
|
+
return candidate;
|
|
174
|
+
}
|
|
175
|
+
async function ensureWhisperCppModel(timeoutMs, fetchImpl) {
|
|
176
|
+
const { modelsDir, modelPath } = whisperCppPaths();
|
|
177
|
+
try {
|
|
178
|
+
await fs.access(modelPath);
|
|
179
|
+
return modelPath;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
await fs.mkdir(modelsDir, { recursive: true });
|
|
183
|
+
const response = await fetchImpl(WHISPER_CPP_MODEL_URL, {
|
|
184
|
+
method: "GET",
|
|
185
|
+
signal: AbortSignal.timeout(Math.max(timeoutMs, 300_000)),
|
|
186
|
+
});
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
throw new Error(`failed to download whisper.cpp model: HTTP ${response.status}`);
|
|
189
|
+
}
|
|
190
|
+
await fs.writeFile(modelPath, Buffer.from(await response.arrayBuffer()));
|
|
191
|
+
return modelPath;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function convertAudioForWhisperCpp(sourcePath, outputPath, timeoutMs) {
|
|
195
|
+
try {
|
|
196
|
+
await execFileText("ffmpeg", ["-y", "-i", sourcePath, "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le", outputPath], Math.max(timeoutMs, 120_000));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
catch (ffmpegError) {
|
|
200
|
+
try {
|
|
201
|
+
await execFileText("afconvert", ["-f", "WAVE", "-d", "LEI16@16000", "-c", "1", sourcePath, outputPath], Math.max(timeoutMs, 120_000));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
catch (afconvertError) {
|
|
205
|
+
const ffmpegReason = ffmpegError.message;
|
|
206
|
+
const afconvertReason = afconvertError.message;
|
|
207
|
+
throw new Error(`failed to prepare audio for whisper.cpp (ffmpeg: ${ffmpegReason}; afconvert: ${afconvertReason})`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function transcribeAudioWithWhisperCpp(params, modelFetchImpl = fetch) {
|
|
212
|
+
const workDir = await fs.mkdtemp(path.join(os.tmpdir(), "ouro-bb-audio-"));
|
|
213
|
+
const filename = sanitizeFilename(describeAttachment(params.attachment));
|
|
214
|
+
const extension = fileExtensionForAudio(params.attachment, params.contentType);
|
|
215
|
+
const audioPath = path.join(workDir, `${path.parse(filename).name}${extension}`);
|
|
216
|
+
const wavPath = path.join(workDir, `${path.parse(audioPath).name}.wav`);
|
|
217
|
+
const outputBase = path.join(workDir, path.parse(audioPath).name);
|
|
218
|
+
try {
|
|
219
|
+
await fs.writeFile(audioPath, params.buffer);
|
|
220
|
+
const whisperCliPath = await resolveWhisperCppBinary(params.timeoutMs);
|
|
221
|
+
const modelPath = await ensureWhisperCppModel(params.timeoutMs, modelFetchImpl);
|
|
222
|
+
await convertAudioForWhisperCpp(audioPath, wavPath, params.timeoutMs);
|
|
223
|
+
await execFileText(whisperCliPath, ["-m", modelPath, "-f", wavPath, "-oj", "-of", outputBase], Math.max(params.timeoutMs, 120_000));
|
|
224
|
+
const transcriptPath = `${outputBase}.json`;
|
|
225
|
+
const raw = await fs.readFile(transcriptPath, "utf8");
|
|
226
|
+
const parsed = JSON.parse(raw);
|
|
227
|
+
if (typeof parsed.text === "string") {
|
|
228
|
+
return parsed.text.trim();
|
|
229
|
+
}
|
|
230
|
+
if (Array.isArray(parsed.transcription)) {
|
|
231
|
+
return parsed.transcription
|
|
232
|
+
.map((entry) => (typeof entry?.text === "string" ? entry.text.trim() : ""))
|
|
233
|
+
.filter(Boolean)
|
|
234
|
+
.join(" ")
|
|
235
|
+
.trim();
|
|
236
|
+
}
|
|
237
|
+
return "";
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
await fs.rm(workDir, { recursive: true, force: true }).catch(() => undefined);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
var attachment_download_2 = require("./attachment-download");
|
|
244
|
+
Object.defineProperty(exports, "downloadBlueBubblesAttachment", { enumerable: true, get: function () { return attachment_download_2.downloadBlueBubblesAttachment; } });
|
|
245
|
+
async function hydrateBlueBubblesAttachments(attachments, config, channelConfig, deps = {}) {
|
|
246
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
247
|
+
const modelFetchImpl = deps.modelFetchImpl ?? fetch;
|
|
248
|
+
const transcribeAudio = deps.transcribeAudio ?? ((params) => transcribeAudioWithWhisperCpp(params, modelFetchImpl));
|
|
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);
|
|
254
|
+
const inputParts = [];
|
|
255
|
+
const transcriptAdditions = [];
|
|
256
|
+
const notices = [];
|
|
257
|
+
for (const attachment of attachments) {
|
|
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;
|
|
262
|
+
try {
|
|
263
|
+
const downloaded = await (0, attachment_download_1.downloadBlueBubblesAttachment)(attachment, config, channelConfig, fetchImpl);
|
|
264
|
+
const base64 = downloaded.buffer.toString("base64");
|
|
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",
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (isAudioAttachment(attachment, downloaded.contentType)) {
|
|
347
|
+
const audioFormat = audioFormatForInput(downloaded.contentType, attachment);
|
|
348
|
+
if (preferAudioInput && audioFormat) {
|
|
349
|
+
inputParts.push({
|
|
350
|
+
type: "input_audio",
|
|
351
|
+
input_audio: {
|
|
352
|
+
data: base64,
|
|
353
|
+
format: audioFormat,
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const transcript = (await transcribeAudio({
|
|
359
|
+
attachment,
|
|
360
|
+
buffer: downloaded.buffer,
|
|
361
|
+
contentType: downloaded.contentType,
|
|
362
|
+
timeoutMs: channelConfig.requestTimeoutMs,
|
|
363
|
+
})).trim();
|
|
364
|
+
if (!transcript) {
|
|
365
|
+
notices.push(`attachment hydration failed for ${name}: empty audio transcript`);
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
transcriptAdditions.push(`voice note transcript: ${transcript}`);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
inputParts.push({
|
|
372
|
+
type: "file",
|
|
373
|
+
file: {
|
|
374
|
+
file_data: base64,
|
|
375
|
+
filename: sanitizeFilename(name),
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
381
|
+
notices.push(`attachment hydration failed for ${name}: ${reason}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
inputParts,
|
|
386
|
+
transcriptAdditions,
|
|
387
|
+
notices,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
@@ -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
|
|
@@ -39,6 +54,7 @@ function extractChatIdentifierFromGuid(chatGuid) {
|
|
|
39
54
|
return parts.length >= 3 ? parts[2]?.trim() || undefined : undefined;
|
|
40
55
|
}
|
|
41
56
|
function buildChatRef(data, threadOriginatorGuid) {
|
|
57
|
+
void threadOriginatorGuid;
|
|
42
58
|
const chats = Array.isArray(data.chats) ? data.chats : [];
|
|
43
59
|
const chat = asRecord(chats[0]) ?? null;
|
|
44
60
|
const chatGuid = readString(chat, "guid");
|
|
@@ -48,12 +64,18 @@ function buildChatRef(data, threadOriginatorGuid) {
|
|
|
48
64
|
const displayName = readString(chat, "displayName")?.trim() || undefined;
|
|
49
65
|
const style = readNumber(chat, "style");
|
|
50
66
|
const isGroup = style === 43 || (chatGuid?.includes(";+;") ?? false) || Boolean(displayName);
|
|
51
|
-
const
|
|
67
|
+
const sessionKey = chatGuid?.trim()
|
|
52
68
|
? `chat:${chatGuid.trim()}`
|
|
53
69
|
: `chat_identifier:${(chatIdentifier ?? "unknown").trim()}`;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
// Extract participant handles from chat.participants (when available from BB API)
|
|
71
|
+
const rawParticipants = Array.isArray(chat?.participants) ? chat.participants : [];
|
|
72
|
+
const participantHandles = rawParticipants
|
|
73
|
+
.map((p) => {
|
|
74
|
+
const rec = asRecord(p);
|
|
75
|
+
const addr = readString(rec, "address") ?? readString(rec, "id");
|
|
76
|
+
return addr ? normalizeHandle(addr) : "";
|
|
77
|
+
})
|
|
78
|
+
.filter(Boolean);
|
|
57
79
|
return {
|
|
58
80
|
chatGuid: chatGuid?.trim() || undefined,
|
|
59
81
|
chatIdentifier: chatIdentifier?.trim() || undefined,
|
|
@@ -63,6 +85,7 @@ function buildChatRef(data, threadOriginatorGuid) {
|
|
|
63
85
|
sendTarget: chatGuid?.trim()
|
|
64
86
|
? { kind: "chat_guid", value: chatGuid.trim() }
|
|
65
87
|
: { kind: "chat_identifier", value: (chatIdentifier ?? "unknown").trim() },
|
|
88
|
+
participantHandles,
|
|
66
89
|
};
|
|
67
90
|
}
|
|
68
91
|
function extractSender(data, chat) {
|
|
@@ -99,18 +122,14 @@ function extractAttachments(data) {
|
|
|
99
122
|
function formatAttachmentText(attachments) {
|
|
100
123
|
if (attachments.length === 0)
|
|
101
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
|
+
}
|
|
102
131
|
const [first] = attachments;
|
|
103
|
-
|
|
104
|
-
const label = mime.startsWith("image/")
|
|
105
|
-
? "image attachment"
|
|
106
|
-
: mime.startsWith("audio/")
|
|
107
|
-
? "audio attachment"
|
|
108
|
-
: "attachment";
|
|
109
|
-
const name = first.transferName ? `: ${first.transferName}` : "";
|
|
110
|
-
const dimensions = typeof first.width === "number" && typeof first.height === "number" && first.width > 0 && first.height > 0
|
|
111
|
-
? ` (${first.width}x${first.height})`
|
|
112
|
-
: "";
|
|
113
|
-
return `[${label}${name}${dimensions}]`;
|
|
132
|
+
return `[attachment: ${first.transferName?.trim() || "unknown"}]`;
|
|
114
133
|
}
|
|
115
134
|
function formatMessageText(data, attachments) {
|
|
116
135
|
const text = readString(data, "text")?.trim() ?? "";
|
|
@@ -119,6 +138,13 @@ function formatMessageText(data, attachments) {
|
|
|
119
138
|
if (balloonBundleId === "com.apple.messages.URLBalloonProvider") {
|
|
120
139
|
return `${text}\n[link preview attached]`;
|
|
121
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
|
+
}
|
|
122
148
|
return text;
|
|
123
149
|
}
|
|
124
150
|
return formatAttachmentText(attachments);
|
|
@@ -190,6 +216,9 @@ function normalizeBlueBubblesEvent(payload) {
|
|
|
190
216
|
message: "ignored bluebubbles payload without guid",
|
|
191
217
|
meta: { eventType },
|
|
192
218
|
});
|
|
219
|
+
if (IGNORABLE_GUIDLESS_EVENT_TYPES.has(eventType)) {
|
|
220
|
+
throw new BlueBubblesIgnoredEventError(eventType, `Ignored BlueBubbles event '${eventType}' without data.guid`);
|
|
221
|
+
}
|
|
193
222
|
throw new Error("BlueBubbles payload is missing data.guid");
|
|
194
223
|
}
|
|
195
224
|
const threadOriginatorGuid = readString(data, "threadOriginatorGuid")?.trim() || undefined;
|
|
@@ -35,15 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getBlueBubblesMutationLogPath = getBlueBubblesMutationLogPath;
|
|
37
37
|
exports.recordBlueBubblesMutation = recordBlueBubblesMutation;
|
|
38
|
+
exports.listBlueBubblesRecoveryCandidates = listBlueBubblesRecoveryCandidates;
|
|
38
39
|
const fs = __importStar(require("node:fs"));
|
|
39
|
-
const os = __importStar(require("node:os"));
|
|
40
40
|
const path = __importStar(require("node:path"));
|
|
41
|
-
const runtime_1 = require("
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
41
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
42
|
+
const identity_1 = require("../../heart/identity");
|
|
43
|
+
const config_1 = require("../../heart/config");
|
|
45
44
|
function getBlueBubblesMutationLogPath(agentName, sessionKey) {
|
|
46
|
-
return path.join(
|
|
45
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
|
|
47
46
|
}
|
|
48
47
|
function recordBlueBubblesMutation(agentName, event) {
|
|
49
48
|
const filePath = getBlueBubblesMutationLogPath(agentName, event.chat.sessionKey);
|
|
@@ -74,3 +73,44 @@ function recordBlueBubblesMutation(agentName, event) {
|
|
|
74
73
|
});
|
|
75
74
|
return filePath;
|
|
76
75
|
}
|
|
76
|
+
function listBlueBubblesRecoveryCandidates(agentName) {
|
|
77
|
+
const rootDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations");
|
|
78
|
+
let files;
|
|
79
|
+
try {
|
|
80
|
+
files = fs.readdirSync(rootDir);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const deduped = new Map();
|
|
86
|
+
for (const file of files.filter((entry) => entry.endsWith(".ndjson")).sort()) {
|
|
87
|
+
const filePath = path.join(rootDir, file);
|
|
88
|
+
let raw = "";
|
|
89
|
+
try {
|
|
90
|
+
raw = fs.readFileSync(filePath, "utf-8");
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
for (const line of raw.split("\n")) {
|
|
96
|
+
const trimmed = line.trim();
|
|
97
|
+
if (!trimmed)
|
|
98
|
+
continue;
|
|
99
|
+
try {
|
|
100
|
+
const entry = JSON.parse(trimmed);
|
|
101
|
+
if (typeof entry.messageGuid !== "string"
|
|
102
|
+
|| !entry.messageGuid.trim()
|
|
103
|
+
|| entry.fromMe
|
|
104
|
+
|| entry.shouldNotifyAgent
|
|
105
|
+
|| (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
deduped.set(entry.messageGuid, entry);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// ignore malformed recovery candidates
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return [...deduped.values()].sort((left, right) => left.recordedAt.localeCompare(right.recordedAt));
|
|
116
|
+
}
|