@ouro.bot/cli 0.1.0-alpha.56 → 0.1.0-alpha.561
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -23
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3604 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +837 -26
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +479 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +322 -0
- package/dist/heart/config.js +114 -118
- package/dist/heart/core.js +913 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +419 -0
- package/dist/heart/daemon/agent-discovery.js +102 -3
- package/dist/heart/daemon/agent-service.js +522 -0
- package/dist/heart/daemon/agentic-repair.js +547 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +776 -0
- package/dist/heart/daemon/cli-exec.js +7457 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1592 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +763 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1698
- package/dist/heart/daemon/daemon-entry.js +387 -2
- package/dist/heart/daemon/daemon-health.js +176 -0
- package/dist/heart/daemon/daemon-rollup.js +57 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +88 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +796 -71
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +826 -0
- package/dist/heart/daemon/health-monitor.js +122 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +14 -12
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +375 -33
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +3 -31
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +389 -38
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +158 -11
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +330 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +32 -56
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +203 -57
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +31 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +195 -0
- package/dist/heart/mailbox/readers/agent-machine.js +382 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
- package/dist/heart/mailbox/readers/mail.js +362 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
- package/dist/heart/mailbox/readers/sessions.js +232 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +683 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +267 -0
- package/dist/heart/provider-credentials.js +425 -0
- package/dist/heart/provider-failover.js +301 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-readiness-cache.js +40 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +139 -52
- package/dist/heart/providers/azure.js +97 -13
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +367 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +13 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1149 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +243 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +9 -5
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-description.js +139 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +389 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailbox-ui/assets/index-B-461hes.js +61 -0
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/index.html +15 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +674 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +720 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +430 -0
- package/dist/mailroom/mbox-import.js +383 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +233 -0
- package/dist/mailroom/search-cache.js +256 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +165 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +62 -75
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +39 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1011 -123
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +129 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +963 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +178 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +295 -0
- package/dist/repertoire/mcp-manager.js +362 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +47 -1075
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +142 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1857 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-session.js +750 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +604 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +108 -100
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +594 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +77 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +2305 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +520 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +549 -181
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +251 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/senses/voice/audio-routing.js +119 -0
- package/dist/senses/voice/elevenlabs.js +178 -0
- package/dist/senses/voice/golden-path.js +116 -0
- package/dist/senses/voice/index.js +26 -0
- package/dist/senses/voice/meeting.js +113 -0
- package/dist/senses/voice/playback.js +139 -0
- package/dist/senses/voice/transcript.js +70 -0
- package/dist/senses/voice/turn.js +85 -0
- package/dist/senses/voice/types.js +2 -0
- package/dist/senses/voice/whisper.js +161 -0
- package/dist/senses/voice-entry.js +80 -0
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +38 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/auth-flow.js +0 -351
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1177
- package/dist/senses/debug-activity.js +0 -148
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -38,8 +38,8 @@ exports.readBlueBubblesRuntimeState = readBlueBubblesRuntimeState;
|
|
|
38
38
|
exports.writeBlueBubblesRuntimeState = writeBlueBubblesRuntimeState;
|
|
39
39
|
const fs = __importStar(require("node:fs"));
|
|
40
40
|
const path = __importStar(require("node:path"));
|
|
41
|
-
const identity_1 = require("
|
|
42
|
-
const runtime_1 = require("
|
|
41
|
+
const identity_1 = require("../../heart/identity");
|
|
42
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
43
43
|
const DEFAULT_RUNTIME_STATE = {
|
|
44
44
|
upstreamStatus: "unknown",
|
|
45
45
|
detail: "startup health probe pending",
|
|
@@ -53,6 +53,9 @@ function readBlueBubblesRuntimeState(agentName, agentRoot) {
|
|
|
53
53
|
try {
|
|
54
54
|
const raw = fs.readFileSync(filePath, "utf-8");
|
|
55
55
|
const parsed = JSON.parse(raw);
|
|
56
|
+
const failedRecoveryCount = typeof parsed.failedRecoveryCount === "number" && Number.isFinite(parsed.failedRecoveryCount)
|
|
57
|
+
? parsed.failedRecoveryCount
|
|
58
|
+
: undefined;
|
|
56
59
|
return {
|
|
57
60
|
upstreamStatus: parsed.upstreamStatus === "ok" || parsed.upstreamStatus === "error"
|
|
58
61
|
? parsed.upstreamStatus
|
|
@@ -61,9 +64,31 @@ function readBlueBubblesRuntimeState(agentName, agentRoot) {
|
|
|
61
64
|
? parsed.detail
|
|
62
65
|
: DEFAULT_RUNTIME_STATE.detail,
|
|
63
66
|
lastCheckedAt: typeof parsed.lastCheckedAt === "string" ? parsed.lastCheckedAt : undefined,
|
|
67
|
+
proofMethod: typeof parsed.proofMethod === "string" && parsed.proofMethod.trim()
|
|
68
|
+
? parsed.proofMethod
|
|
69
|
+
: undefined,
|
|
64
70
|
pendingRecoveryCount: typeof parsed.pendingRecoveryCount === "number" && Number.isFinite(parsed.pendingRecoveryCount)
|
|
65
71
|
? parsed.pendingRecoveryCount
|
|
66
72
|
: 0,
|
|
73
|
+
...(typeof failedRecoveryCount === "number" ? { failedRecoveryCount } : {}),
|
|
74
|
+
oldestPendingRecoveryAt: typeof parsed.oldestPendingRecoveryAt === "string"
|
|
75
|
+
? parsed.oldestPendingRecoveryAt
|
|
76
|
+
: undefined,
|
|
77
|
+
oldestPendingRecoveryAgeMs: typeof parsed.oldestPendingRecoveryAgeMs === "number" && Number.isFinite(parsed.oldestPendingRecoveryAgeMs)
|
|
78
|
+
? parsed.oldestPendingRecoveryAgeMs
|
|
79
|
+
: undefined,
|
|
80
|
+
activeTurnCount: typeof parsed.activeTurnCount === "number" && Number.isFinite(parsed.activeTurnCount)
|
|
81
|
+
? parsed.activeTurnCount
|
|
82
|
+
: undefined,
|
|
83
|
+
stalledTurnCount: typeof parsed.stalledTurnCount === "number" && Number.isFinite(parsed.stalledTurnCount)
|
|
84
|
+
? parsed.stalledTurnCount
|
|
85
|
+
: undefined,
|
|
86
|
+
oldestActiveTurnStartedAt: typeof parsed.oldestActiveTurnStartedAt === "string"
|
|
87
|
+
? parsed.oldestActiveTurnStartedAt
|
|
88
|
+
: undefined,
|
|
89
|
+
oldestActiveTurnAgeMs: typeof parsed.oldestActiveTurnAgeMs === "number" && Number.isFinite(parsed.oldestActiveTurnAgeMs)
|
|
90
|
+
? parsed.oldestActiveTurnAgeMs
|
|
91
|
+
: undefined,
|
|
67
92
|
lastRecoveredAt: typeof parsed.lastRecoveredAt === "string" ? parsed.lastRecoveredAt : undefined,
|
|
68
93
|
lastRecoveredMessageGuid: typeof parsed.lastRecoveredMessageGuid === "string"
|
|
69
94
|
? parsed.lastRecoveredMessageGuid
|
|
@@ -102,6 +127,9 @@ function writeBlueBubblesRuntimeState(agentName, state, agentRoot) {
|
|
|
102
127
|
agentName,
|
|
103
128
|
upstreamStatus: state.upstreamStatus,
|
|
104
129
|
pendingRecoveryCount: state.pendingRecoveryCount,
|
|
130
|
+
failedRecoveryCount: state.failedRecoveryCount ?? 0,
|
|
131
|
+
activeTurnCount: state.activeTurnCount ?? 0,
|
|
132
|
+
stalledTurnCount: state.stalledTurnCount ?? 0,
|
|
105
133
|
path: filePath,
|
|
106
134
|
},
|
|
107
135
|
});
|
|
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.findObsoleteBlueBubblesThreadSessions = findObsoleteBlueBubblesThreadSessions;
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
38
|
const path = __importStar(require("node:path"));
|
|
39
|
-
const runtime_1 = require("
|
|
39
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
40
40
|
function findObsoleteBlueBubblesThreadSessions(trunkSessionPath) {
|
|
41
41
|
const normalized = trunkSessionPath.trim();
|
|
42
42
|
if (!normalized.endsWith(".json"))
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BracketedPasteHandler = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Bracketed paste mode handler for the TUI.
|
|
6
|
+
*
|
|
7
|
+
* Detects \x1b[200~ (paste start) and \x1b[201~ (paste end) markers in
|
|
8
|
+
* raw stdin data. Buffers paste content between markers and emits it as
|
|
9
|
+
* a single "paste" event. Non-paste data is emitted as "data" unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Works alongside Ink's stdin handling by intercepting raw data events.
|
|
12
|
+
*/
|
|
13
|
+
const events_1 = require("events");
|
|
14
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
15
|
+
const PASTE_START = "\x1b[200~";
|
|
16
|
+
const PASTE_END = "\x1b[201~";
|
|
17
|
+
class BracketedPasteHandler extends events_1.EventEmitter {
|
|
18
|
+
stdin;
|
|
19
|
+
stdout;
|
|
20
|
+
pasting = false;
|
|
21
|
+
buffer = "";
|
|
22
|
+
dataHandler;
|
|
23
|
+
constructor(stdin, stdout) {
|
|
24
|
+
super();
|
|
25
|
+
this.stdin = stdin;
|
|
26
|
+
this.stdout = stdout;
|
|
27
|
+
// Enable bracketed paste mode
|
|
28
|
+
stdout.write("\x1b[?2004h");
|
|
29
|
+
this.dataHandler = (chunk) => {
|
|
30
|
+
this.processChunk(chunk.toString());
|
|
31
|
+
};
|
|
32
|
+
stdin.prependListener("data", this.dataHandler);
|
|
33
|
+
}
|
|
34
|
+
processChunk(data) {
|
|
35
|
+
let remaining = data;
|
|
36
|
+
while (remaining.length > 0) {
|
|
37
|
+
if (this.pasting) {
|
|
38
|
+
// Look for end marker in buffer + remaining
|
|
39
|
+
const combined = this.buffer + remaining;
|
|
40
|
+
const endIdx = combined.indexOf(PASTE_END);
|
|
41
|
+
if (endIdx !== -1) {
|
|
42
|
+
// Found end marker -- emit paste content
|
|
43
|
+
const pasteContent = combined.slice(0, endIdx);
|
|
44
|
+
(0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.bracketed_paste", message: "bracketed paste received", meta: { length: pasteContent.length } });
|
|
45
|
+
this.emit("paste", pasteContent);
|
|
46
|
+
this.buffer = "";
|
|
47
|
+
this.pasting = false;
|
|
48
|
+
// Process remaining data after end marker
|
|
49
|
+
remaining = combined.slice(endIdx + PASTE_END.length);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// No end marker yet -- buffer everything so far
|
|
53
|
+
this.buffer = combined;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Not pasting -- look for start marker
|
|
57
|
+
const startIdx = remaining.indexOf(PASTE_START);
|
|
58
|
+
if (startIdx !== -1) {
|
|
59
|
+
// Emit any data before the start marker
|
|
60
|
+
const before = remaining.slice(0, startIdx);
|
|
61
|
+
if (before.length > 0) {
|
|
62
|
+
this.emit("data", before);
|
|
63
|
+
}
|
|
64
|
+
// Enter paste mode
|
|
65
|
+
this.pasting = true;
|
|
66
|
+
this.buffer = "";
|
|
67
|
+
remaining = remaining.slice(startIdx + PASTE_START.length);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// No start marker -- emit as regular data
|
|
71
|
+
this.emit("data", remaining);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Disable bracketed paste mode and remove listeners. */
|
|
76
|
+
destroy() {
|
|
77
|
+
this.stdout.write("\x1b[?2004l");
|
|
78
|
+
this.stdin.removeListener("data", this.dataHandler);
|
|
79
|
+
this.removeAllListeners();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.BracketedPasteHandler = BracketedPasteHandler;
|
|
@@ -0,0 +1,287 @@
|
|
|
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.IMAGE_EXTENSION_REGEX = void 0;
|
|
37
|
+
exports.isImagePath = isImagePath;
|
|
38
|
+
exports.unescapePath = unescapePath;
|
|
39
|
+
exports.tryReadImage = tryReadImage;
|
|
40
|
+
exports.formatImageRef = formatImageRef;
|
|
41
|
+
exports.replacePathsWithRefs = replacePathsWithRefs;
|
|
42
|
+
exports.processSubmitInput = processSubmitInput;
|
|
43
|
+
exports.resolveImageContent = resolveImageContent;
|
|
44
|
+
/**
|
|
45
|
+
* Image paste detection and resolution for the TUI.
|
|
46
|
+
*
|
|
47
|
+
* When a user drags an image file onto the terminal, macOS pastes the absolute
|
|
48
|
+
* path (often with backslash-escaped spaces). This module detects image paths
|
|
49
|
+
* in the input text, replaces them with `[Image #N]` references, reads the
|
|
50
|
+
* files, registers them as shared attachments, and produces OpenAI-compatible
|
|
51
|
+
* `image_url` content blocks.
|
|
52
|
+
*/
|
|
53
|
+
const node_crypto_1 = require("node:crypto");
|
|
54
|
+
const promises_1 = require("fs/promises");
|
|
55
|
+
const child_process_1 = require("child_process");
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
58
|
+
const identity_1 = require("../../heart/identity");
|
|
59
|
+
const render_1 = require("../../heart/attachments/render");
|
|
60
|
+
const store_1 = require("../../heart/attachments/store");
|
|
61
|
+
const materialize_1 = require("../../heart/attachments/materialize");
|
|
62
|
+
const cli_local_file_1 = require("../../heart/attachments/sources/cli-local-file");
|
|
63
|
+
/** Matches image file extensions (case-insensitive) */
|
|
64
|
+
exports.IMAGE_EXTENSION_REGEX = /\.(png|jpe?g|gif|webp)$/i;
|
|
65
|
+
/** Check whether a string (possibly backslash-escaped) ends with an image extension */
|
|
66
|
+
function isImagePath(str) {
|
|
67
|
+
return exports.IMAGE_EXTENSION_REGEX.test(unescapePath(str));
|
|
68
|
+
}
|
|
69
|
+
/** Strip shell escape backslashes from a path (macOS/Linux drag-drop format) */
|
|
70
|
+
function unescapePath(str) {
|
|
71
|
+
// Handle double-backslashes first (actual backslash in filename)
|
|
72
|
+
// then remove single escape backslashes
|
|
73
|
+
return str.replace(/\\(.)/g, "$1");
|
|
74
|
+
}
|
|
75
|
+
/** Detect temp screenshot paths from macOS screencapture */
|
|
76
|
+
const TEMP_SCREENSHOT_RE = /\/TemporaryItems\/.*screencaptureui.*\/Screenshot/i;
|
|
77
|
+
/** Map file extension to MIME media type */
|
|
78
|
+
function extensionToMediaType(ext) {
|
|
79
|
+
switch (ext.toLowerCase()) {
|
|
80
|
+
case ".jpg":
|
|
81
|
+
case ".jpeg":
|
|
82
|
+
return "image/jpeg";
|
|
83
|
+
case ".png":
|
|
84
|
+
return "image/png";
|
|
85
|
+
case ".gif":
|
|
86
|
+
return "image/gif";
|
|
87
|
+
case ".webp":
|
|
88
|
+
return "image/webp";
|
|
89
|
+
default:
|
|
90
|
+
return "image/png";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Read an image file and return base64 + media type.
|
|
95
|
+
* Falls back to clipboard for temp screenshot paths (macOS screencapture
|
|
96
|
+
* creates ephemeral files in TemporaryItems that are cleaned up quickly).
|
|
97
|
+
* Returns null on any error.
|
|
98
|
+
*/
|
|
99
|
+
async function tryReadImage(absolutePath) {
|
|
100
|
+
// Try reading the file directly first
|
|
101
|
+
try {
|
|
102
|
+
const buffer = await (0, promises_1.readFile)(absolutePath);
|
|
103
|
+
if (buffer.length > 0) {
|
|
104
|
+
const ext = path.extname(absolutePath);
|
|
105
|
+
return {
|
|
106
|
+
buffer: Buffer.from(buffer),
|
|
107
|
+
base64: Buffer.from(buffer).toString("base64"),
|
|
108
|
+
mediaType: extensionToMediaType(ext),
|
|
109
|
+
fromClipboard: false,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// File not found or permission denied — try clipboard fallback
|
|
115
|
+
}
|
|
116
|
+
// Clipboard fallback for macOS temp screenshots
|
|
117
|
+
/* v8 ignore start -- clipboard fallback requires real macOS screencapture @preserve */
|
|
118
|
+
if (process.platform === "darwin" && TEMP_SCREENSHOT_RE.test(absolutePath)) {
|
|
119
|
+
const clipboardImage = await getImageFromClipboard();
|
|
120
|
+
if (clipboardImage)
|
|
121
|
+
return clipboardImage;
|
|
122
|
+
}
|
|
123
|
+
/* v8 ignore stop */
|
|
124
|
+
(0, runtime_1.emitNervesEvent)({
|
|
125
|
+
component: "senses",
|
|
126
|
+
event: "senses.image_read_error",
|
|
127
|
+
message: `Failed to read image: ${absolutePath}`,
|
|
128
|
+
meta: { path: absolutePath },
|
|
129
|
+
});
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Read image data from macOS clipboard via osascript.
|
|
134
|
+
* Used as fallback when temp screenshot files are already cleaned up.
|
|
135
|
+
*/
|
|
136
|
+
/* v8 ignore start -- macOS clipboard integration @preserve */
|
|
137
|
+
async function getImageFromClipboard() {
|
|
138
|
+
const tmpPath = "/tmp/ouro_clipboard_image.png";
|
|
139
|
+
try {
|
|
140
|
+
// Check if clipboard has image data
|
|
141
|
+
(0, child_process_1.execFileSync)("osascript", ["-e", "the clipboard as «class PNGf»"], { stdio: "pipe" });
|
|
142
|
+
// Save clipboard image to temp file
|
|
143
|
+
(0, child_process_1.execFileSync)("osascript", [
|
|
144
|
+
"-e", "set png_data to (the clipboard as «class PNGf»)",
|
|
145
|
+
"-e", `set fp to open for access POSIX file "${tmpPath}" with write permission`,
|
|
146
|
+
"-e", "write png_data to fp",
|
|
147
|
+
"-e", "close access fp",
|
|
148
|
+
], { stdio: "pipe" });
|
|
149
|
+
const buffer = await (0, promises_1.readFile)(tmpPath);
|
|
150
|
+
void (0, promises_1.unlink)(tmpPath).catch(() => { });
|
|
151
|
+
if (buffer.length === 0)
|
|
152
|
+
return null;
|
|
153
|
+
return {
|
|
154
|
+
buffer: Buffer.from(buffer),
|
|
155
|
+
base64: Buffer.from(buffer).toString("base64"),
|
|
156
|
+
mediaType: "image/png",
|
|
157
|
+
fromClipboard: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/* v8 ignore stop */
|
|
165
|
+
/** Format an image reference placeholder */
|
|
166
|
+
function formatImageRef(n) {
|
|
167
|
+
return `[Image #${n}]`;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Scan input for absolute image file paths and replace with [Image #N] references.
|
|
171
|
+
* Handles backslash-escaped characters (macOS drag-drop) and paths with spaces.
|
|
172
|
+
*/
|
|
173
|
+
function replacePathsWithRefs(input) {
|
|
174
|
+
const images = new Map();
|
|
175
|
+
// Match absolute paths: start with /, contain non-whitespace or backslash-escaped chars,
|
|
176
|
+
// end with an image extension. The (?:\\.|\S) alternation allows `\ ` sequences.
|
|
177
|
+
const pathRegex = /(?:\/(?:\\.|[^\s])+\.(?:png|jpe?g|gif|webp))/gi;
|
|
178
|
+
let counter = 0;
|
|
179
|
+
const text = input.replace(pathRegex, (match) => {
|
|
180
|
+
counter++;
|
|
181
|
+
images.set(counter, unescapePath(match));
|
|
182
|
+
return formatImageRef(counter);
|
|
183
|
+
});
|
|
184
|
+
return { text, images };
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Process submit input: detect image paths, replace with refs, return map.
|
|
188
|
+
* This is the entry point called by InputArea on submit.
|
|
189
|
+
*/
|
|
190
|
+
function processSubmitInput(text) {
|
|
191
|
+
return replacePathsWithRefs(text);
|
|
192
|
+
}
|
|
193
|
+
function extensionForMediaType(mediaType) {
|
|
194
|
+
switch (mediaType) {
|
|
195
|
+
case "image/jpeg":
|
|
196
|
+
return ".jpg";
|
|
197
|
+
case "image/gif":
|
|
198
|
+
return ".gif";
|
|
199
|
+
case "image/webp":
|
|
200
|
+
return ".webp";
|
|
201
|
+
default:
|
|
202
|
+
return ".png";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function pathExists(targetPath) {
|
|
206
|
+
try {
|
|
207
|
+
await (0, promises_1.access)(targetPath);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async function persistClipboardImage(agentRoot, originalPath, image) {
|
|
215
|
+
const hash = (0, node_crypto_1.createHash)("sha1").update(originalPath).digest("hex").slice(0, 16);
|
|
216
|
+
const targetPath = path.join(agentRoot, "state", "attachments", "imports", "cli", `${hash}${extensionForMediaType(image.mediaType)}`);
|
|
217
|
+
await (0, promises_1.mkdir)(path.dirname(targetPath), { recursive: true });
|
|
218
|
+
await (0, promises_1.writeFile)(targetPath, image.buffer);
|
|
219
|
+
return targetPath;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Build OpenAI content parts from text + image map.
|
|
223
|
+
* For each image in the map, reads the file and creates an `image_url` content part.
|
|
224
|
+
* Images that fail to read are silently skipped.
|
|
225
|
+
* Returns `[{ type: "text", text }]` when no images resolve.
|
|
226
|
+
*/
|
|
227
|
+
async function resolveImageContent(text, images) {
|
|
228
|
+
if (images.size === 0) {
|
|
229
|
+
return [{ type: "text", text }];
|
|
230
|
+
}
|
|
231
|
+
const agentName = (0, identity_1.getAgentName)();
|
|
232
|
+
const agentRoot = (0, identity_1.getAgentRoot)(agentName);
|
|
233
|
+
const parts = [];
|
|
234
|
+
const cachedAttachments = [];
|
|
235
|
+
// Read all images in parallel
|
|
236
|
+
const entries = Array.from(images.entries());
|
|
237
|
+
const results = await Promise.all(entries.map(async ([, absolutePath]) => {
|
|
238
|
+
const image = await tryReadImage(absolutePath);
|
|
239
|
+
if (!image)
|
|
240
|
+
return null;
|
|
241
|
+
const sourcePath = image.fromClipboard || !await pathExists(absolutePath)
|
|
242
|
+
? await persistClipboardImage(agentRoot, absolutePath, image)
|
|
243
|
+
: absolutePath;
|
|
244
|
+
const attachment = (0, store_1.cacheRecentAttachment)(agentName, (0, cli_local_file_1.buildCliLocalFileAttachmentRecord)({
|
|
245
|
+
path: sourcePath,
|
|
246
|
+
mimeType: image.mediaType,
|
|
247
|
+
byteCount: image.buffer.length,
|
|
248
|
+
}), agentRoot);
|
|
249
|
+
cachedAttachments.push(attachment);
|
|
250
|
+
try {
|
|
251
|
+
const materialized = await (0, materialize_1.materializeAttachment)(agentName, attachment.id, {
|
|
252
|
+
agentRoot,
|
|
253
|
+
variant: "vision_safe",
|
|
254
|
+
});
|
|
255
|
+
const normalizedBuffer = await (0, promises_1.readFile)(materialized.path);
|
|
256
|
+
return {
|
|
257
|
+
attachment,
|
|
258
|
+
mediaType: materialized.mimeType ?? image.mediaType,
|
|
259
|
+
base64: Buffer.from(normalizedBuffer).toString("base64"),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return {
|
|
264
|
+
attachment,
|
|
265
|
+
mediaType: image.mediaType,
|
|
266
|
+
base64: image.base64,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}));
|
|
270
|
+
for (const result of results) {
|
|
271
|
+
if (result) {
|
|
272
|
+
parts.push({
|
|
273
|
+
type: "image_url",
|
|
274
|
+
image_url: { url: `data:${result.mediaType};base64,${result.base64}` },
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Always include the text part
|
|
279
|
+
const attachmentBlock = (0, render_1.renderAttachmentBlock)(cachedAttachments);
|
|
280
|
+
const textWithAttachments = [text, attachmentBlock].filter(Boolean).join("\n");
|
|
281
|
+
parts.push({ type: "text", text: textWithAttachments || text });
|
|
282
|
+
// If no images resolved, return just text
|
|
283
|
+
if (parts.length === 1) {
|
|
284
|
+
return [{ type: "text", text }];
|
|
285
|
+
}
|
|
286
|
+
return parts;
|
|
287
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.imageRefEndingAt = imageRefEndingAt;
|
|
4
|
+
exports.imageRefStartingAt = imageRefStartingAt;
|
|
5
|
+
exports.deleteTokenBefore = deleteTokenBefore;
|
|
6
|
+
exports.deleteTokenAfter = deleteTokenAfter;
|
|
7
|
+
/**
|
|
8
|
+
* Token-aware navigation and deletion for [Image #N] references.
|
|
9
|
+
*
|
|
10
|
+
* Image refs are treated as atomic "chips" — arrow keys hop over them,
|
|
11
|
+
* backspace/delete removes them atomically, and word-kill treats them
|
|
12
|
+
* as single words.
|
|
13
|
+
*/
|
|
14
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
15
|
+
const IMAGE_REF_PATTERN = /\[Image #\d+\]/g;
|
|
16
|
+
/**
|
|
17
|
+
* If an [Image #N] ref ends exactly at the given position, return its start index.
|
|
18
|
+
* Otherwise return undefined.
|
|
19
|
+
*/
|
|
20
|
+
function imageRefEndingAt(text, pos) {
|
|
21
|
+
// Search backward from pos for a potential image ref
|
|
22
|
+
// Max length of [Image #NNN] is ~14 chars, search a window
|
|
23
|
+
const windowStart = Math.max(0, pos - 20);
|
|
24
|
+
const window = text.slice(windowStart, pos);
|
|
25
|
+
IMAGE_REF_PATTERN.lastIndex = 0;
|
|
26
|
+
let match;
|
|
27
|
+
while ((match = IMAGE_REF_PATTERN.exec(window)) !== null) {
|
|
28
|
+
const matchEnd = windowStart + match.index + match[0].length;
|
|
29
|
+
if (matchEnd === pos) {
|
|
30
|
+
return windowStart + match.index;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* If an [Image #N] ref starts exactly at the given position, return its end index.
|
|
37
|
+
* Otherwise return undefined.
|
|
38
|
+
*/
|
|
39
|
+
function imageRefStartingAt(text, pos) {
|
|
40
|
+
if (pos >= text.length)
|
|
41
|
+
return undefined;
|
|
42
|
+
// Check if text at pos matches an image ref
|
|
43
|
+
const window = text.slice(pos, pos + 20);
|
|
44
|
+
IMAGE_REF_PATTERN.lastIndex = 0;
|
|
45
|
+
const match = IMAGE_REF_PATTERN.exec(window);
|
|
46
|
+
if (match && match.index === 0) {
|
|
47
|
+
return pos + match[0].length;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* If cursor is right after an [Image #N], remove the entire ref.
|
|
53
|
+
* Returns { text, pos } with the ref removed, or null if no ref found.
|
|
54
|
+
*/
|
|
55
|
+
function deleteTokenBefore(text, pos) {
|
|
56
|
+
const start = imageRefEndingAt(text, pos);
|
|
57
|
+
if (start === undefined)
|
|
58
|
+
return null;
|
|
59
|
+
(0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.image_ref_delete", message: "deleted image ref token", meta: { pos } });
|
|
60
|
+
const before = text.slice(0, start);
|
|
61
|
+
const after = text.slice(pos);
|
|
62
|
+
return { text: before + after, pos: start };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* If cursor is right before an [Image #N], remove the entire ref.
|
|
66
|
+
* Returns { text, pos } with the ref removed, or null if no ref found.
|
|
67
|
+
*/
|
|
68
|
+
function deleteTokenAfter(text, pos) {
|
|
69
|
+
const end = imageRefStartingAt(text, pos);
|
|
70
|
+
if (end === undefined)
|
|
71
|
+
return null;
|
|
72
|
+
const before = text.slice(0, pos);
|
|
73
|
+
const after = text.slice(end);
|
|
74
|
+
return { text: before + after, pos };
|
|
75
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
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.InkApp = InkApp;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const react_1 = __importStar(require("react"));
|
|
39
|
+
const ink_1 = require("ink");
|
|
40
|
+
const streaming_markdown_1 = require("./streaming-markdown");
|
|
41
|
+
/**
|
|
42
|
+
* Ouroboros CLI TUI — Ink application shell.
|
|
43
|
+
*
|
|
44
|
+
* Replaces the imperative readline-based CLI with a React/Ink component tree.
|
|
45
|
+
* Provides: message list, input area, spinner, tool result display.
|
|
46
|
+
*
|
|
47
|
+
* Design: Ouroboros-themed (green serpent), NOT Claude/Anthropic design language.
|
|
48
|
+
* Copy-paste integrity: no padding characters. Visual hierarchy via color/bold/dim only.
|
|
49
|
+
*/
|
|
50
|
+
// Ouroboros brand palette
|
|
51
|
+
const OURO_GREEN = "#2ecc40";
|
|
52
|
+
const OURO_TEAL = "#4ec9b0";
|
|
53
|
+
const OURO_DIM = true;
|
|
54
|
+
// Snake-themed spinner frames: serpent eating its own tail
|
|
55
|
+
const SNAKE_FRAMES = [
|
|
56
|
+
"\u{1F40D}\u2003", // snake emoji
|
|
57
|
+
"\u25E0\u2003", // upper half circle
|
|
58
|
+
"\u25D4\u2003", // circle with upper right quadrant
|
|
59
|
+
"\u25D1\u2003", // circle with right half
|
|
60
|
+
"\u25D5\u2003", // circle with all but upper left quadrant
|
|
61
|
+
"\u25E1\u2003", // lower half circle
|
|
62
|
+
"\u{1F40D}\u2003", // snake emoji again
|
|
63
|
+
"\u25CB\u2003", // white circle (tail eaten)
|
|
64
|
+
];
|
|
65
|
+
function UserMessage({ content }) {
|
|
66
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: content })] }));
|
|
67
|
+
}
|
|
68
|
+
function AssistantMessage({ content }) {
|
|
69
|
+
return ((0, jsx_runtime_1.jsx)(ink_1.Box, { children: (0, jsx_runtime_1.jsx)(streaming_markdown_1.StreamingMarkdown, { text: content }) }));
|
|
70
|
+
}
|
|
71
|
+
function ToolCallDisplay({ toolCall }) {
|
|
72
|
+
let argSummary = "";
|
|
73
|
+
try {
|
|
74
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
75
|
+
const first = Object.values(args)[0];
|
|
76
|
+
if (typeof first === "string")
|
|
77
|
+
argSummary = first.length > 60 ? first.slice(0, 57) + "..." : first;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
argSummary = toolCall.function.arguments.slice(0, 60);
|
|
81
|
+
}
|
|
82
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_GREEN, bold: true, children: toolCall.function.name }), argSummary ? (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", argSummary] }) : null] }));
|
|
83
|
+
}
|
|
84
|
+
function ToolResultDisplay({ result }) {
|
|
85
|
+
const color = result.success ? OURO_GREEN : "#e74c3c";
|
|
86
|
+
const icon = result.success ? "\u2713" : "\u2717";
|
|
87
|
+
const summary = result.result.length > 120
|
|
88
|
+
? result.result.slice(0, 117) + "..."
|
|
89
|
+
: result.result;
|
|
90
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { color: color, children: [icon, " ", result.name] }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", summary.replace(/\n/g, " ")] })] }));
|
|
91
|
+
}
|
|
92
|
+
function SpinnerComponent({ text, frame }) {
|
|
93
|
+
const char = SNAKE_FRAMES[frame % SNAKE_FRAMES.length];
|
|
94
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_GREEN, children: char }), (0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: OURO_DIM, children: [text, "..."] })] }));
|
|
95
|
+
}
|
|
96
|
+
function InputArea({ onSubmit, }) {
|
|
97
|
+
const [input, setInput] = (0, react_1.useState)("");
|
|
98
|
+
// Ref tracks the latest input value so useInput callback always sees current state
|
|
99
|
+
const inputRef = (0, react_1.useRef)("");
|
|
100
|
+
(0, ink_1.useInput)((inputChar, key) => {
|
|
101
|
+
if (key.return) {
|
|
102
|
+
if (inputRef.current.trim() && onSubmit) {
|
|
103
|
+
onSubmit(inputRef.current);
|
|
104
|
+
}
|
|
105
|
+
inputRef.current = "";
|
|
106
|
+
setInput("");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (key.backspace || key.delete) {
|
|
110
|
+
inputRef.current = inputRef.current.slice(0, -1);
|
|
111
|
+
setInput(inputRef.current);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!key.ctrl && !key.meta && inputChar) {
|
|
115
|
+
inputRef.current += inputChar;
|
|
116
|
+
setInput(inputRef.current);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO_TEAL, bold: true, children: ") " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: input })] }));
|
|
120
|
+
}
|
|
121
|
+
function MessageList({ messages, toolResults, }) {
|
|
122
|
+
const toolResultMap = new Map();
|
|
123
|
+
if (toolResults) {
|
|
124
|
+
for (const tr of toolResults) {
|
|
125
|
+
toolResultMap.set(tr.toolCallId, tr);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: messages.map((msg, i) => {
|
|
129
|
+
if (msg.role === "user" && msg.content) {
|
|
130
|
+
return (0, jsx_runtime_1.jsx)(UserMessage, { content: msg.content }, i);
|
|
131
|
+
}
|
|
132
|
+
if (msg.role === "assistant") {
|
|
133
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [msg.content ? (0, jsx_runtime_1.jsx)(AssistantMessage, { content: msg.content }) : null, msg.tool_calls?.map(tc => {
|
|
134
|
+
const tr = toolResultMap.get(tc.id);
|
|
135
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ToolCallDisplay, { toolCall: tc }), tr ? (0, jsx_runtime_1.jsx)(ToolResultDisplay, { result: tr }) : null] }, tc.id));
|
|
136
|
+
})] }, i));
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}) }));
|
|
140
|
+
}
|
|
141
|
+
function InkApp({ messages, onSubmit, loading, spinnerText, toolResults, }) {
|
|
142
|
+
const [spinnerFrame, setSpinnerFrame] = (0, react_1.useState)(0);
|
|
143
|
+
// Animate spinner
|
|
144
|
+
react_1.default.useEffect(() => {
|
|
145
|
+
if (!loading)
|
|
146
|
+
return;
|
|
147
|
+
const iv = setInterval(() => {
|
|
148
|
+
setSpinnerFrame(f => (f + 1) % SNAKE_FRAMES.length);
|
|
149
|
+
}, 120);
|
|
150
|
+
return () => clearInterval(iv);
|
|
151
|
+
}, [loading]);
|
|
152
|
+
const handleSubmit = (0, react_1.useCallback)((text) => {
|
|
153
|
+
onSubmit?.(text);
|
|
154
|
+
}, [onSubmit]);
|
|
155
|
+
return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(MessageList, { messages: messages, toolResults: toolResults }), loading && spinnerText ? ((0, jsx_runtime_1.jsx)(SpinnerComponent, { text: spinnerText, frame: spinnerFrame })) : null, (0, jsx_runtime_1.jsx)(InputArea, { onSubmit: handleSubmit })] }));
|
|
156
|
+
}
|