@ouro.bot/cli 0.1.0-alpha.56 → 0.1.0-alpha.560
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 +3596 -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 +248 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/senses/voice/elevenlabs.js +125 -0
- package/dist/senses/voice/index.js +22 -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 +133 -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
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agentic repair flow for degraded agents detected during `ouro up`.
|
|
4
|
+
*
|
|
5
|
+
* Runs known local repair prompts first, then offers AI-assisted diagnosis
|
|
6
|
+
* when no local repair was attempted and a working LLM provider is available.
|
|
7
|
+
* This is a lightweight integration: one diagnostic LLM call, not a chat loop.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.createAgenticDiagnosisProviderRuntime = createAgenticDiagnosisProviderRuntime;
|
|
44
|
+
exports.runAgenticRepair = runAgenticRepair;
|
|
45
|
+
exports.shouldFireRepairGuide = shouldFireRepairGuide;
|
|
46
|
+
exports.loadRepairGuideContent = loadRepairGuideContent;
|
|
47
|
+
exports.parseRepairProposals = parseRepairProposals;
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
51
|
+
const interactive_repair_1 = require("./interactive-repair");
|
|
52
|
+
const identity_1 = require("../identity");
|
|
53
|
+
const provider_ping_1 = require("../provider-ping");
|
|
54
|
+
const readiness_repair_1 = require("./readiness-repair");
|
|
55
|
+
function buildSystemPrompt(degraded) {
|
|
56
|
+
const agentList = degraded
|
|
57
|
+
.map((d) => `- ${d.agent}: error="${d.errorReason}", hint="${d.fixHint}"`)
|
|
58
|
+
.join("\n");
|
|
59
|
+
return [
|
|
60
|
+
"You are a diagnostic assistant for the Ouroboros agent daemon.",
|
|
61
|
+
"The daemon detected degraded agents during startup.",
|
|
62
|
+
"Analyze the errors below and provide a concise diagnosis with suggested fixes.",
|
|
63
|
+
"",
|
|
64
|
+
"Degraded agents:",
|
|
65
|
+
agentList,
|
|
66
|
+
"",
|
|
67
|
+
"Keep your response brief and actionable. Focus on the most likely root cause",
|
|
68
|
+
"and the simplest fix the user can apply.",
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
function buildUserMessage(degraded, logsTail, syncFindings = []) {
|
|
72
|
+
const agentDetails = degraded
|
|
73
|
+
.map((d) => `Agent: ${d.agent}\n Error: ${d.errorReason}\n Fix hint: ${d.fixHint}`)
|
|
74
|
+
.join("\n\n");
|
|
75
|
+
const sections = [
|
|
76
|
+
"Here are the degraded agents and recent daemon logs:",
|
|
77
|
+
"",
|
|
78
|
+
agentDetails,
|
|
79
|
+
"",
|
|
80
|
+
"Recent daemon logs:",
|
|
81
|
+
logsTail,
|
|
82
|
+
];
|
|
83
|
+
// Layer 3: thread Layer 2's structured sync-probe findings into the
|
|
84
|
+
// prompt as a JSON block. `diagnose-broken-remote` (auth/404/network/
|
|
85
|
+
// timeout-hard) and `diagnose-sync-blocked` (dirty/non-fast-forward/
|
|
86
|
+
// merge-conflict/timeout-soft) consume this shape.
|
|
87
|
+
if (syncFindings.length > 0) {
|
|
88
|
+
sections.push("", "bootSyncFindings (BootSyncProbeFinding[]):", "```json", JSON.stringify(syncFindings, null, 2), "```");
|
|
89
|
+
}
|
|
90
|
+
sections.push("", "What is the most likely cause and how should I fix it?");
|
|
91
|
+
return sections.join("\n");
|
|
92
|
+
}
|
|
93
|
+
function makeInteractiveRepairDeps(deps) {
|
|
94
|
+
return {
|
|
95
|
+
promptInput: deps.promptInput,
|
|
96
|
+
writeStdout: deps.writeStdout,
|
|
97
|
+
/* v8 ignore next -- fallback no-op: tests always inject runAuthFlow; default is for production @preserve */
|
|
98
|
+
runAuthFlow: deps.runAuthFlow ?? (async () => undefined),
|
|
99
|
+
runVaultUnlock: deps.runVaultUnlock,
|
|
100
|
+
skipQueueSummary: deps.skipQueueSummary,
|
|
101
|
+
isTTY: deps.isTTY,
|
|
102
|
+
stdoutColumns: deps.stdoutColumns,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function runDeterministicRepair(degraded, deps) {
|
|
106
|
+
return deps.runInteractiveRepair(degraded, makeInteractiveRepairDeps(deps));
|
|
107
|
+
}
|
|
108
|
+
function discoveredProviderModel(provider) {
|
|
109
|
+
const model = provider.providerConfig.model?.trim();
|
|
110
|
+
return model ? model : undefined;
|
|
111
|
+
}
|
|
112
|
+
function createAgenticDiagnosisProviderRuntime(provider) {
|
|
113
|
+
const config = {
|
|
114
|
+
...provider.providerConfig,
|
|
115
|
+
...provider.credentials,
|
|
116
|
+
};
|
|
117
|
+
return (0, provider_ping_1.createProviderRuntimeForConfig)(provider.provider, config, {
|
|
118
|
+
model: discoveredProviderModel(provider),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Layer 3: build the system prompt for the diagnostic call. Prepends
|
|
123
|
+
* RepairGuide bundle content (`psyche/SOUL.md`, `psyche/IDENTITY.md`, all
|
|
124
|
+
* skills) when the bundle is present and readable; falls back to today's
|
|
125
|
+
* pre-RepairGuide prompt when the loader returns null.
|
|
126
|
+
*/
|
|
127
|
+
function buildSystemPromptWithRepairGuide(degraded, repairGuide) {
|
|
128
|
+
const basePrompt = buildSystemPrompt(degraded);
|
|
129
|
+
if (repairGuide === null)
|
|
130
|
+
return basePrompt;
|
|
131
|
+
const sections = [];
|
|
132
|
+
if (repairGuide.psyche.soul) {
|
|
133
|
+
sections.push("# RepairGuide SOUL\n\n" + repairGuide.psyche.soul);
|
|
134
|
+
}
|
|
135
|
+
if (repairGuide.psyche.identity) {
|
|
136
|
+
sections.push("# RepairGuide IDENTITY\n\n" + repairGuide.psyche.identity);
|
|
137
|
+
}
|
|
138
|
+
for (const [name, body] of Object.entries(repairGuide.skills)) {
|
|
139
|
+
sections.push(`# RepairGuide skill: ${name}\n\n${body}`);
|
|
140
|
+
}
|
|
141
|
+
if (sections.length === 0)
|
|
142
|
+
return basePrompt;
|
|
143
|
+
return [...sections, "---", basePrompt].join("\n\n");
|
|
144
|
+
}
|
|
145
|
+
async function tryAgenticDiagnosis(degraded, provider, deps) {
|
|
146
|
+
const logsTail = deps.readDaemonLogsTail();
|
|
147
|
+
const runtime = deps.createProviderRuntime(provider);
|
|
148
|
+
// Layer 3: prepend RepairGuide bundle content when present. Loader
|
|
149
|
+
// returns null on missing bundle / I/O error — caller silently falls back
|
|
150
|
+
// to today's pre-RepairGuide prompt.
|
|
151
|
+
const repoRoot = deps.repoRootOverride ?? (0, identity_1.getRepoRoot)();
|
|
152
|
+
const repairGuide = loadRepairGuideContent(repoRoot);
|
|
153
|
+
const systemPrompt = buildSystemPromptWithRepairGuide(degraded, repairGuide);
|
|
154
|
+
const userMessage = buildUserMessage(degraded, logsTail, deps.syncFindings);
|
|
155
|
+
const messages = [
|
|
156
|
+
{ role: "system", content: systemPrompt },
|
|
157
|
+
{ role: "user", content: userMessage },
|
|
158
|
+
];
|
|
159
|
+
/* v8 ignore start -- no-op callbacks: satisfy interface contract, never invoked by diagnostic call @preserve */
|
|
160
|
+
const noopCallbacks = {
|
|
161
|
+
onModelStart: () => { },
|
|
162
|
+
onModelStreamStart: () => { },
|
|
163
|
+
onTextChunk: () => { },
|
|
164
|
+
onReasoningChunk: () => { },
|
|
165
|
+
onToolStart: () => { },
|
|
166
|
+
onToolEnd: () => { },
|
|
167
|
+
onError: () => { },
|
|
168
|
+
};
|
|
169
|
+
/* v8 ignore stop */
|
|
170
|
+
const result = await runtime.streamTurn({
|
|
171
|
+
messages,
|
|
172
|
+
activeTools: [],
|
|
173
|
+
callbacks: noopCallbacks,
|
|
174
|
+
});
|
|
175
|
+
if (result.content) {
|
|
176
|
+
// Layer 3: when RepairGuide content was prepended, parse the LLM output
|
|
177
|
+
// through the typed-action catalog. If actions are extracted, surface
|
|
178
|
+
// them as structured proposals; otherwise fall back to today's plain
|
|
179
|
+
// text-blob diagnosis. `parseRepairProposals` handles the unparseable
|
|
180
|
+
// case by returning `fallbackBlob` set to the raw output.
|
|
181
|
+
if (repairGuide !== null) {
|
|
182
|
+
const parsed = parseRepairProposals(result.content);
|
|
183
|
+
if (parsed.actions.length > 0) {
|
|
184
|
+
deps.writeStdout("");
|
|
185
|
+
deps.writeStdout("--- RepairGuide proposals ---");
|
|
186
|
+
for (const action of parsed.actions) {
|
|
187
|
+
deps.writeStdout(` • ${action.kind}: ${action.label}`);
|
|
188
|
+
}
|
|
189
|
+
for (const warning of parsed.warnings) {
|
|
190
|
+
deps.writeStdout(` (warning) ${warning}`);
|
|
191
|
+
}
|
|
192
|
+
deps.writeStdout("--- End RepairGuide proposals ---");
|
|
193
|
+
deps.writeStdout("");
|
|
194
|
+
}
|
|
195
|
+
else if (parsed.fallbackBlob !== undefined) {
|
|
196
|
+
deps.writeStdout("");
|
|
197
|
+
deps.writeStdout("--- AI Diagnosis ---");
|
|
198
|
+
deps.writeStdout(parsed.fallbackBlob);
|
|
199
|
+
deps.writeStdout("--- End Diagnosis ---");
|
|
200
|
+
deps.writeStdout("");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
deps.writeStdout("");
|
|
205
|
+
deps.writeStdout("--- AI Diagnosis ---");
|
|
206
|
+
deps.writeStdout(result.content);
|
|
207
|
+
deps.writeStdout("--- End Diagnosis ---");
|
|
208
|
+
deps.writeStdout("");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
async function runAgenticRepair(degraded, deps) {
|
|
214
|
+
(0, runtime_1.emitNervesEvent)({
|
|
215
|
+
level: "info",
|
|
216
|
+
component: "daemon",
|
|
217
|
+
event: "daemon.agentic_repair_start",
|
|
218
|
+
message: "agentic repair flow started",
|
|
219
|
+
meta: { degradedCount: degraded.length },
|
|
220
|
+
});
|
|
221
|
+
if (degraded.length === 0) {
|
|
222
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
223
|
+
}
|
|
224
|
+
const hasLocalRepair = degraded.some(interactive_repair_1.hasRunnableInteractiveRepair);
|
|
225
|
+
const hasKnownTypedRepair = degraded.some((entry) => (0, readiness_repair_1.isKnownReadinessIssue)(entry.issue));
|
|
226
|
+
const forceDiagnosis = deps.forceDiagnosis === true;
|
|
227
|
+
if (hasLocalRepair) {
|
|
228
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
229
|
+
if (interactiveResult.repairsAttempted) {
|
|
230
|
+
return { repairsAttempted: true, usedAgentic: false };
|
|
231
|
+
}
|
|
232
|
+
if (hasKnownTypedRepair && !forceDiagnosis) {
|
|
233
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (hasKnownTypedRepair && !forceDiagnosis) {
|
|
237
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
238
|
+
}
|
|
239
|
+
// Try to discover a working provider for agentic diagnosis
|
|
240
|
+
let discoveredProvider = null;
|
|
241
|
+
try {
|
|
242
|
+
discoveredProvider = await deps.discoverWorkingProvider(degraded[0].agent);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
246
|
+
(0, runtime_1.emitNervesEvent)({
|
|
247
|
+
level: "warn",
|
|
248
|
+
component: "daemon",
|
|
249
|
+
event: "daemon.agentic_repair_discovery_error",
|
|
250
|
+
message: `provider discovery failed during agentic repair: ${msg}`,
|
|
251
|
+
meta: { error: msg },
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (!discoveredProvider) {
|
|
255
|
+
// No working provider — fall back to deterministic repair
|
|
256
|
+
(0, runtime_1.emitNervesEvent)({
|
|
257
|
+
level: "info",
|
|
258
|
+
component: "daemon",
|
|
259
|
+
event: "daemon.agentic_repair_no_provider",
|
|
260
|
+
message: "no working provider found, falling back to deterministic repair",
|
|
261
|
+
meta: {},
|
|
262
|
+
});
|
|
263
|
+
if (hasLocalRepair) {
|
|
264
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
265
|
+
}
|
|
266
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
267
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic: false };
|
|
268
|
+
}
|
|
269
|
+
// Offer agentic diagnosis
|
|
270
|
+
const answer = await deps.promptInput("would you like AI-assisted diagnosis? [y/n] ");
|
|
271
|
+
if (!(0, interactive_repair_1.isAffirmativeAnswer)(answer)) {
|
|
272
|
+
// User declined — fall back to deterministic repair
|
|
273
|
+
(0, runtime_1.emitNervesEvent)({
|
|
274
|
+
level: "info",
|
|
275
|
+
component: "daemon",
|
|
276
|
+
event: "daemon.agentic_repair_declined",
|
|
277
|
+
message: "user declined agentic diagnosis",
|
|
278
|
+
meta: {},
|
|
279
|
+
});
|
|
280
|
+
if (hasLocalRepair) {
|
|
281
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
282
|
+
}
|
|
283
|
+
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
284
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic: false };
|
|
285
|
+
}
|
|
286
|
+
// User accepted — run agentic diagnosis then fall through to deterministic repair
|
|
287
|
+
let usedAgentic = false;
|
|
288
|
+
try {
|
|
289
|
+
usedAgentic = await tryAgenticDiagnosis(degraded, discoveredProvider, deps);
|
|
290
|
+
(0, runtime_1.emitNervesEvent)({
|
|
291
|
+
level: "info",
|
|
292
|
+
component: "daemon",
|
|
293
|
+
event: "daemon.agentic_repair_diagnosis_complete",
|
|
294
|
+
message: "agentic diagnosis completed, proceeding to deterministic repair",
|
|
295
|
+
meta: { provider: discoveredProvider.provider },
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
300
|
+
deps.writeStdout(`AI diagnosis failed: ${msg}`);
|
|
301
|
+
(0, runtime_1.emitNervesEvent)({
|
|
302
|
+
level: "warn",
|
|
303
|
+
component: "daemon",
|
|
304
|
+
event: "daemon.agentic_repair_diagnosis_error",
|
|
305
|
+
message: `agentic diagnosis failed: ${msg}`,
|
|
306
|
+
meta: { error: msg, provider: discoveredProvider.provider },
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
// Always fall through to deterministic repair for actionable fixes
|
|
310
|
+
const interactiveResult = hasLocalRepair
|
|
311
|
+
? { repairsAttempted: false }
|
|
312
|
+
: await runDeterministicRepair(degraded, deps);
|
|
313
|
+
(0, runtime_1.emitNervesEvent)({
|
|
314
|
+
level: "info",
|
|
315
|
+
component: "daemon",
|
|
316
|
+
event: "daemon.agentic_repair_end",
|
|
317
|
+
message: "agentic repair flow completed",
|
|
318
|
+
meta: { usedAgentic, repairsAttempted: interactiveResult.repairsAttempted },
|
|
319
|
+
});
|
|
320
|
+
return { repairsAttempted: interactiveResult.repairsAttempted, usedAgentic };
|
|
321
|
+
}
|
|
322
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
323
|
+
// Layer 3: RepairGuide activation contract
|
|
324
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
325
|
+
/**
|
|
326
|
+
* Threshold for compound typed-degraded findings to activate RepairGuide.
|
|
327
|
+
* Set to 3 (not 2) so that common pairs — vault-locked + provider-auth-needed,
|
|
328
|
+
* for example — do NOT trigger the new path on every boot. Encoded once here;
|
|
329
|
+
* never duplicate at call sites.
|
|
330
|
+
*/
|
|
331
|
+
const REPAIR_GUIDE_TYPED_THRESHOLD = 3;
|
|
332
|
+
/**
|
|
333
|
+
* Single decision function for whether to fire the RepairGuide-driven
|
|
334
|
+
* diagnostic flow.
|
|
335
|
+
*
|
|
336
|
+
* Contract (LOCKED, planning O4):
|
|
337
|
+
* - `noRepair: true` → false unconditionally (escape hatch).
|
|
338
|
+
* - `untypedDegraded.length > 0` → true (preserves today's gate at
|
|
339
|
+
* `cli-exec.ts:6706`).
|
|
340
|
+
* - `typedDegraded.length >= REPAIR_GUIDE_TYPED_THRESHOLD` → true (compound
|
|
341
|
+
* stack of typed issues; the new behavior this PR introduces).
|
|
342
|
+
* - Otherwise → false.
|
|
343
|
+
*/
|
|
344
|
+
function shouldFireRepairGuide(input) {
|
|
345
|
+
if (input.noRepair)
|
|
346
|
+
return false;
|
|
347
|
+
if (input.untypedDegraded.length > 0)
|
|
348
|
+
return true;
|
|
349
|
+
if (input.typedDegraded.length >= REPAIR_GUIDE_TYPED_THRESHOLD)
|
|
350
|
+
return true;
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Read `RepairGuide.ouro/{psyche,skills}/*.md` from the given repo root and
|
|
355
|
+
* return a structured shape suitable for prepending to a diagnostic LLM call.
|
|
356
|
+
*
|
|
357
|
+
* Behavior:
|
|
358
|
+
* - Returns `null` if `RepairGuide.ouro/` does not exist at all (graceful: caller
|
|
359
|
+
* should fall back to today's pre-RepairGuide pipeline).
|
|
360
|
+
* - Returns `null` on any I/O error (`readdirSync`/`readFileSync` throws).
|
|
361
|
+
* - Returns a populated `RepairGuideContent` when the bundle exists, even if
|
|
362
|
+
* psyche or skills are partially populated.
|
|
363
|
+
* - Skips files that are not `.md`, are not regular files, or have empty
|
|
364
|
+
* contents.
|
|
365
|
+
* - `skills` map is iterated in alphabetical order so callers can rely on
|
|
366
|
+
* deterministic prompt assembly.
|
|
367
|
+
*
|
|
368
|
+
* The loader is intentionally inline in `agentic-repair.ts` per the planning
|
|
369
|
+
* O5 lock — splitting into its own module is allowed only if the validator
|
|
370
|
+
* grows large.
|
|
371
|
+
*/
|
|
372
|
+
function loadRepairGuideContent(repoRoot) {
|
|
373
|
+
const bundleRoot = path.join(repoRoot, "RepairGuide.ouro");
|
|
374
|
+
if (!fs.existsSync(bundleRoot))
|
|
375
|
+
return null;
|
|
376
|
+
try {
|
|
377
|
+
const psyche = {};
|
|
378
|
+
const skills = {};
|
|
379
|
+
const psycheDir = path.join(bundleRoot, "psyche");
|
|
380
|
+
if (fs.existsSync(psycheDir)) {
|
|
381
|
+
const psycheEntries = fs.readdirSync(psycheDir, { withFileTypes: true });
|
|
382
|
+
for (const entry of psycheEntries) {
|
|
383
|
+
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
384
|
+
continue;
|
|
385
|
+
const content = fs.readFileSync(path.join(psycheDir, entry.name), "utf-8");
|
|
386
|
+
if (entry.name === "SOUL.md")
|
|
387
|
+
psyche.soul = content;
|
|
388
|
+
else if (entry.name === "IDENTITY.md")
|
|
389
|
+
psyche.identity = content;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const skillsDir = path.join(bundleRoot, "skills");
|
|
393
|
+
if (fs.existsSync(skillsDir)) {
|
|
394
|
+
const skillEntries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
395
|
+
const sorted = skillEntries
|
|
396
|
+
.filter((e) => e.isFile() && e.name.endsWith(".md"))
|
|
397
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
398
|
+
for (const entry of sorted) {
|
|
399
|
+
const content = fs.readFileSync(path.join(skillsDir, entry.name), "utf-8");
|
|
400
|
+
if (content.length === 0)
|
|
401
|
+
continue;
|
|
402
|
+
skills[entry.name] = content;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return { psyche, skills };
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
// Best-effort: any I/O error in the bundle leads to null and the caller
|
|
409
|
+
// falls back to today's pre-RepairGuide diagnostic prompt.
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
414
|
+
// Layer 3: RepairGuide LLM output parser → typed `RepairAction[]`
|
|
415
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
416
|
+
/**
|
|
417
|
+
* The set of `RepairActionKind` literals the typed catalog recognizes.
|
|
418
|
+
* Encoded once here; the parser uses this for membership checks. Any other
|
|
419
|
+
* kind in the LLM output is dropped with a warning.
|
|
420
|
+
*/
|
|
421
|
+
const KNOWN_REPAIR_ACTION_KINDS = new Set([
|
|
422
|
+
"vault-create",
|
|
423
|
+
"vault-unlock",
|
|
424
|
+
"vault-replace",
|
|
425
|
+
"vault-recover",
|
|
426
|
+
"provider-auth",
|
|
427
|
+
"provider-retry",
|
|
428
|
+
"provider-use",
|
|
429
|
+
]);
|
|
430
|
+
function extractFirstJsonBlock(text) {
|
|
431
|
+
// Look for a triple-backtick fence labeled `json` and grab its body.
|
|
432
|
+
const fenceMatch = text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
433
|
+
if (fenceMatch)
|
|
434
|
+
return fenceMatch[1];
|
|
435
|
+
// Fallback: the LLM may have emitted a bare JSON object (no fence).
|
|
436
|
+
const objectMatch = text.match(/\{[\s\S]*\}/);
|
|
437
|
+
if (objectMatch)
|
|
438
|
+
return objectMatch[0];
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
function isPlainObject(value) {
|
|
442
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Parse a single LLM-emitted action object into a typed `RepairAction`. Returns
|
|
446
|
+
* `null` when the entry is shaped wrong — the caller logs a warning and drops
|
|
447
|
+
* it. The parser backfills `label`, `command`, and `actor` so the result plugs
|
|
448
|
+
* into the existing interactive-repair surface without further massaging.
|
|
449
|
+
*/
|
|
450
|
+
function buildRepairAction(entry) {
|
|
451
|
+
const kind = entry.kind;
|
|
452
|
+
if (typeof kind !== "string")
|
|
453
|
+
return null;
|
|
454
|
+
if (!KNOWN_REPAIR_ACTION_KINDS.has(kind))
|
|
455
|
+
return null;
|
|
456
|
+
const reason = typeof entry.reason === "string" ? entry.reason : "(no reason given)";
|
|
457
|
+
const agent = typeof entry.agent === "string" ? entry.agent : "(unknown agent)";
|
|
458
|
+
const label = `RepairGuide: ${kind} for ${agent}`;
|
|
459
|
+
const command = `# ${kind} (${agent}): ${reason}`;
|
|
460
|
+
switch (kind) {
|
|
461
|
+
case "provider-auth": {
|
|
462
|
+
const provider = typeof entry.provider === "string" ? entry.provider : "anthropic";
|
|
463
|
+
return {
|
|
464
|
+
kind: "provider-auth",
|
|
465
|
+
label,
|
|
466
|
+
command,
|
|
467
|
+
actor: "human-required",
|
|
468
|
+
provider: provider,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
case "provider-use": {
|
|
472
|
+
// `provider-use` may carry an optional `lane` — pass it through when
|
|
473
|
+
// present and validly typed (`outward` or `inner`).
|
|
474
|
+
const lane = entry.lane === "outward" || entry.lane === "inner" ? entry.lane : undefined;
|
|
475
|
+
const action = {
|
|
476
|
+
kind: "provider-use",
|
|
477
|
+
label,
|
|
478
|
+
command,
|
|
479
|
+
actor: "human-choice",
|
|
480
|
+
...(lane ? { lane } : {}),
|
|
481
|
+
};
|
|
482
|
+
return action;
|
|
483
|
+
}
|
|
484
|
+
case "vault-create":
|
|
485
|
+
case "vault-unlock":
|
|
486
|
+
case "vault-replace":
|
|
487
|
+
case "vault-recover":
|
|
488
|
+
case "provider-retry": {
|
|
489
|
+
return {
|
|
490
|
+
kind: kind,
|
|
491
|
+
label,
|
|
492
|
+
command,
|
|
493
|
+
actor: "human-required",
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/* v8 ignore next 4 -- exhaustiveness guard: unreachable since membership
|
|
497
|
+
* was checked above; left in place to satisfy `never` on future
|
|
498
|
+
* RepairActionKind extensions. @preserve */
|
|
499
|
+
default: {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Parse RepairGuide LLM output. The persona content (`SOUL.md`) instructs the
|
|
506
|
+
* model to emit exactly one ```json fenced block containing
|
|
507
|
+
* `{ actions: RepairAction[], notes?: string[] }`. The parser extracts that
|
|
508
|
+
* block, walks `actions[]`, drops entries with unknown kinds (with warnings),
|
|
509
|
+
* and falls back to the raw output when no JSON can be extracted at all
|
|
510
|
+
* (preserving today's text-blob behavior).
|
|
511
|
+
*/
|
|
512
|
+
function parseRepairProposals(llmOutput) {
|
|
513
|
+
const block = extractFirstJsonBlock(llmOutput);
|
|
514
|
+
if (block === null) {
|
|
515
|
+
return { actions: [], warnings: [], fallbackBlob: llmOutput };
|
|
516
|
+
}
|
|
517
|
+
let parsed;
|
|
518
|
+
try {
|
|
519
|
+
parsed = JSON.parse(block);
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
return { actions: [], warnings: [], fallbackBlob: llmOutput };
|
|
523
|
+
}
|
|
524
|
+
if (!isPlainObject(parsed)) {
|
|
525
|
+
return { actions: [], warnings: [] };
|
|
526
|
+
}
|
|
527
|
+
const rawActions = parsed.actions;
|
|
528
|
+
if (!Array.isArray(rawActions)) {
|
|
529
|
+
return { actions: [], warnings: [] };
|
|
530
|
+
}
|
|
531
|
+
const actions = [];
|
|
532
|
+
const warnings = [];
|
|
533
|
+
for (const entry of rawActions) {
|
|
534
|
+
if (!isPlainObject(entry)) {
|
|
535
|
+
warnings.push(`dropped non-object entry from actions[]: ${JSON.stringify(entry)}`);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const built = buildRepairAction(entry);
|
|
539
|
+
if (built === null) {
|
|
540
|
+
const kindLabel = typeof entry.kind === "string" ? entry.kind : "(no kind)";
|
|
541
|
+
warnings.push(`dropped action with unknown or missing kind: ${kindLabel}`);
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
actions.push(built);
|
|
545
|
+
}
|
|
546
|
+
return { actions, warnings };
|
|
547
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stringifyBlueBubblesHealthError = stringifyBlueBubblesHealthError;
|
|
4
|
+
exports.redactBlueBubblesHealthDetailForNerves = redactBlueBubblesHealthDetailForNerves;
|
|
5
|
+
exports.formatBlueBubblesHealthcheckFailure = formatBlueBubblesHealthcheckFailure;
|
|
6
|
+
exports.probeBlueBubblesHealth = probeBlueBubblesHealth;
|
|
7
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
8
|
+
const error_classification_1 = require("../providers/error-classification");
|
|
9
|
+
function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
|
|
10
|
+
const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
11
|
+
const url = new URL(endpoint.replace(/^\//, ""), root);
|
|
12
|
+
url.searchParams.set("password", password);
|
|
13
|
+
return url.toString();
|
|
14
|
+
}
|
|
15
|
+
function stringifyBlueBubblesHealthError(error) {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
const message = error.message.trim();
|
|
18
|
+
if (message)
|
|
19
|
+
return message;
|
|
20
|
+
return error.name || "unknown";
|
|
21
|
+
}
|
|
22
|
+
const value = String(error).trim();
|
|
23
|
+
return value || "unknown";
|
|
24
|
+
}
|
|
25
|
+
function redactBlueBubblesHealthDetailForNerves(detail) {
|
|
26
|
+
return detail
|
|
27
|
+
.replace(/\bbluebubbles\.password\b/gi, "bluebubbles credential")
|
|
28
|
+
.replace(/\bpassword\b/gi, "credential");
|
|
29
|
+
}
|
|
30
|
+
function blueBubblesHealthStatus(error) {
|
|
31
|
+
return error instanceof Error && typeof error.status === "number"
|
|
32
|
+
? error.status
|
|
33
|
+
: null;
|
|
34
|
+
}
|
|
35
|
+
function blueBubblesHealthClassification(error) {
|
|
36
|
+
return error instanceof Error ? (0, error_classification_1.classifyHttpError)(error) : "unknown";
|
|
37
|
+
}
|
|
38
|
+
function formatBlueBubblesHealthcheckFailure(serverUrlInput, error) {
|
|
39
|
+
const serverUrl = serverUrlInput.trim() || "configured BlueBubbles server";
|
|
40
|
+
const rawReason = stringifyBlueBubblesHealthError(error);
|
|
41
|
+
const status = blueBubblesHealthStatus(error);
|
|
42
|
+
if (!(error instanceof Error)) {
|
|
43
|
+
return `BlueBubbles health check failed at ${serverUrl}. Check \`bluebubbles.serverUrl\`, confirm the BlueBubbles app/API is running, and inspect daemon logs. Raw error: ${rawReason}`;
|
|
44
|
+
}
|
|
45
|
+
switch (blueBubblesHealthClassification(error)) {
|
|
46
|
+
case "network-error":
|
|
47
|
+
return `Cannot reach BlueBubbles at ${serverUrl}. Check \`bluebubbles.serverUrl\`, confirm the BlueBubbles app/API is running, and verify this machine can reach it. Raw error: ${rawReason}`;
|
|
48
|
+
case "auth-failure":
|
|
49
|
+
return `BlueBubbles auth failed at ${serverUrl} (HTTP ${status}). Check this machine's BlueBubbles attachment with \`ouro connect bluebubbles --agent <agent>\` and confirm the server accepts the password. Raw error: ${rawReason}`;
|
|
50
|
+
case "server-error":
|
|
51
|
+
return `BlueBubbles upstream returned HTTP ${status} at ${serverUrl}. Check the BlueBubbles app/server logs and confirm the upstream API is healthy. Raw error: ${rawReason}`;
|
|
52
|
+
default:
|
|
53
|
+
return `BlueBubbles health check failed at ${serverUrl}${status === null ? "" : ` (HTTP ${status})`}. Check \`bluebubbles.serverUrl\`, the BlueBubbles server configuration, and daemon logs. Raw error: ${rawReason}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function probeBlueBubblesHealth(input) {
|
|
57
|
+
try {
|
|
58
|
+
const url = buildBlueBubblesApiUrl(input.serverUrl, "/api/v1/message/count", input.password);
|
|
59
|
+
const response = await input.fetchImpl(url, {
|
|
60
|
+
method: "GET",
|
|
61
|
+
signal: AbortSignal.timeout(input.requestTimeoutMs),
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
const errorText = await response.text().catch(() => "");
|
|
65
|
+
const error = new Error(errorText || "unknown");
|
|
66
|
+
error.status = response.status;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
(0, runtime_1.emitNervesEvent)({
|
|
70
|
+
component: "daemon",
|
|
71
|
+
event: "daemon.bluebubbles_health_probe_checked",
|
|
72
|
+
message: "checked bluebubbles upstream health",
|
|
73
|
+
meta: {
|
|
74
|
+
serverUrl: input.serverUrl,
|
|
75
|
+
ok: true,
|
|
76
|
+
status: response.status,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
ok: true,
|
|
81
|
+
detail: "upstream reachable",
|
|
82
|
+
reason: null,
|
|
83
|
+
status: response.status,
|
|
84
|
+
classification: null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const detail = formatBlueBubblesHealthcheckFailure(input.serverUrl, error);
|
|
89
|
+
const reason = stringifyBlueBubblesHealthError(error);
|
|
90
|
+
const status = blueBubblesHealthStatus(error);
|
|
91
|
+
const classification = blueBubblesHealthClassification(error);
|
|
92
|
+
(0, runtime_1.emitNervesEvent)({
|
|
93
|
+
level: "warn",
|
|
94
|
+
component: "daemon",
|
|
95
|
+
event: "daemon.bluebubbles_health_probe_checked",
|
|
96
|
+
message: "checked bluebubbles upstream health",
|
|
97
|
+
meta: {
|
|
98
|
+
serverUrl: input.serverUrl,
|
|
99
|
+
ok: false,
|
|
100
|
+
status,
|
|
101
|
+
reason,
|
|
102
|
+
classification,
|
|
103
|
+
detail: redactBlueBubblesHealthDetailForNerves(detail),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
detail,
|
|
109
|
+
reason,
|
|
110
|
+
status,
|
|
111
|
+
classification,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/* v8 ignore start -- module load observability event */
|
|
116
|
+
(0, runtime_1.emitNervesEvent)({
|
|
117
|
+
component: "daemon",
|
|
118
|
+
event: "daemon.bluebubbles_health_diagnostics_loaded",
|
|
119
|
+
message: "bluebubbles health diagnostics loaded",
|
|
120
|
+
meta: {},
|
|
121
|
+
});
|
|
122
|
+
/* v8 ignore stop */
|