@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.551
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -19
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3561 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +837 -26
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +479 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +114 -118
- package/dist/heart/core.js +925 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +512 -0
- package/dist/heart/daemon/agent-discovery.js +102 -3
- package/dist/heart/daemon/agent-service.js +522 -0
- package/dist/heart/daemon/agentic-repair.js +554 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +665 -0
- package/dist/heart/daemon/cli-exec.js +7565 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1590 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +775 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1672
- package/dist/heart/daemon/daemon-entry.js +417 -2
- package/dist/heart/daemon/daemon-health.js +183 -0
- package/dist/heart/daemon/daemon-rollup.js +58 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +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 +844 -0
- package/dist/heart/daemon/drift-detection.js +146 -0
- package/dist/heart/daemon/health-monitor.js +122 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +102 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +14 -12
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +375 -33
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +3 -31
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +353 -38
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +158 -11
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +330 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +200 -51
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +31 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +195 -0
- package/dist/heart/mailbox/readers/agent-machine.js +382 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
- package/dist/heart/mailbox/readers/mail.js +362 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
- package/dist/heart/mailbox/readers/sessions.js +232 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +683 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +425 -0
- package/dist/heart/provider-failover.js +301 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +139 -52
- package/dist/heart/providers/azure.js +97 -13
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +367 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +11 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1149 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +243 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +9 -5
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-description.js +139 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +381 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -0
- package/dist/mailbox-ui/index.html +15 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +674 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +720 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +430 -0
- package/dist/mailroom/mbox-import.js +383 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +233 -0
- package/dist/mailroom/search-cache.js +256 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +165 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +62 -75
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +30 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +995 -123
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +139 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +816 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +295 -0
- package/dist/repertoire/mcp-manager.js +362 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +47 -1075
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +142 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1857 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-session.js +750 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +604 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +108 -100
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +561 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +77 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +2305 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +520 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +569 -182
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +248 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +38 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1177
- package/dist/senses/debug-activity.js +0 -148
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -93,6 +93,91 @@ function writeInnerPendingNotice(bundleRoot, noticeContent, nowIso) {
|
|
|
93
93
|
fs.mkdirSync(innerPendingDir, { recursive: true });
|
|
94
94
|
fs.writeFileSync(filePath, JSON.stringify(payload), "utf-8");
|
|
95
95
|
}
|
|
96
|
+
const ACKNOWLEDGED_GROUPS_FILENAME = "acknowledged-auto-groups.json";
|
|
97
|
+
function acknowledgedGroupsPath(bundleRoot) {
|
|
98
|
+
return path.join(bundleRoot, "state", ACKNOWLEDGED_GROUPS_FILENAME);
|
|
99
|
+
}
|
|
100
|
+
function loadAcknowledgedGroupsState(bundleRoot) {
|
|
101
|
+
try {
|
|
102
|
+
const raw = fs.readFileSync(acknowledgedGroupsPath(bundleRoot), "utf-8");
|
|
103
|
+
if (!raw.trim())
|
|
104
|
+
return {};
|
|
105
|
+
const parsed = JSON.parse(raw);
|
|
106
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
107
|
+
return {};
|
|
108
|
+
return parsed;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return {};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function persistAcknowledgedGroupsState(bundleRoot, state) {
|
|
115
|
+
const target = acknowledgedGroupsPath(bundleRoot);
|
|
116
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
117
|
+
fs.writeFileSync(target, `${JSON.stringify(state, null, 2)}\n`, "utf-8");
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* For BlueBubbles group chats that were auto-created at stranger trust (no
|
|
121
|
+
* explicit operator/agent action ever bound the harness to this group), the
|
|
122
|
+
* gate's family-member bypass would otherwise let messages flow through
|
|
123
|
+
* silently and the agent would accumulate a session it has no mental model
|
|
124
|
+
* for. Surface the relationship as an inner-pending notice exactly once so
|
|
125
|
+
* the agent can categorize / rename / dismiss the group on its next turn.
|
|
126
|
+
*
|
|
127
|
+
* Returns true if a notice was written so callers can emit a telemetry event.
|
|
128
|
+
*/
|
|
129
|
+
function maybeSurfaceAutoCreatedGroup(input, bundleRoot, nowIso) {
|
|
130
|
+
// Caller guarantees isGroupChat = true (only invoked from the family-member
|
|
131
|
+
// bypass branch); skip a redundant guard here.
|
|
132
|
+
if (input.friend.trustLevel !== "stranger")
|
|
133
|
+
return false;
|
|
134
|
+
if (!input.friend.notes?.["autoCreatedGroup"])
|
|
135
|
+
return false;
|
|
136
|
+
// loadAcknowledgedGroupsState is defensive (its own try/catch returns {})
|
|
137
|
+
// so we don't wrap it in another try here.
|
|
138
|
+
const state = loadAcknowledgedGroupsState(bundleRoot);
|
|
139
|
+
if (state[input.friend.id])
|
|
140
|
+
return false;
|
|
141
|
+
const noticeContent = `New BlueBubbles group "${input.friend.name}" became active without explicit acknowledgment. ` +
|
|
142
|
+
`It was auto-created at stranger trust the first time a message routed through it. ` +
|
|
143
|
+
`If you recognize the group, label or rename it (and consider promoting trust); if not, you can leave it as a stranger group or rename it for clarity. ` +
|
|
144
|
+
`external id: ${input.externalId}; friend id: ${input.friend.id}.`;
|
|
145
|
+
try {
|
|
146
|
+
writeInnerPendingNotice(bundleRoot, noticeContent, nowIso);
|
|
147
|
+
persistAcknowledgedGroupsState(bundleRoot, {
|
|
148
|
+
...state,
|
|
149
|
+
[input.friend.id]: { surfacedAt: nowIso },
|
|
150
|
+
});
|
|
151
|
+
(0, runtime_1.emitNervesEvent)({
|
|
152
|
+
level: "info",
|
|
153
|
+
component: "senses",
|
|
154
|
+
event: "senses.trust_gate_group_acknowledgment_surfaced",
|
|
155
|
+
message: "auto-created group surfaced for agent acknowledgment",
|
|
156
|
+
meta: {
|
|
157
|
+
friendId: input.friend.id,
|
|
158
|
+
friendName: input.friend.name,
|
|
159
|
+
externalId: input.externalId,
|
|
160
|
+
provider: input.provider,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
return true;
|
|
164
|
+
/* v8 ignore start -- defensive: surfacing failure must not block the gate decision @preserve */
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
(0, runtime_1.emitNervesEvent)({
|
|
168
|
+
level: "error",
|
|
169
|
+
component: "senses",
|
|
170
|
+
event: "senses.trust_gate_error",
|
|
171
|
+
message: "failed to surface auto-created group for acknowledgment",
|
|
172
|
+
meta: {
|
|
173
|
+
friendId: input.friend.id,
|
|
174
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
/* v8 ignore stop */
|
|
180
|
+
}
|
|
96
181
|
function enforceTrustGate(input) {
|
|
97
182
|
const { senseType } = input;
|
|
98
183
|
// Local (CLI) and internal (inner dialog) — always allow
|
|
@@ -104,6 +189,20 @@ function enforceTrustGate(input) {
|
|
|
104
189
|
return { allowed: true };
|
|
105
190
|
}
|
|
106
191
|
// Open senses (BlueBubbles/iMessage) — enforce trust rules
|
|
192
|
+
// Group chat with a family member present — allow regardless of trust level.
|
|
193
|
+
// BUT if this is an auto-created stranger group (the harness picked it up
|
|
194
|
+
// silently via the family-member shortcut and the agent never explicitly
|
|
195
|
+
// acknowledged it), surface a one-time inner-pending notice so the agent
|
|
196
|
+
// gets a chance to categorize / rename / dismiss the relationship instead
|
|
197
|
+
// of accumulating activity invisibly.
|
|
198
|
+
if (input.isGroupChat && input.groupHasFamilyMember) {
|
|
199
|
+
/* v8 ignore start -- defaults shared with the rest of the gate; tested via the stranger-trust path */
|
|
200
|
+
const bundleRoot = input.bundleRoot ?? (0, identity_1.getAgentRoot)();
|
|
201
|
+
const nowIso = (input.now ?? (() => new Date()))().toISOString();
|
|
202
|
+
/* v8 ignore stop */
|
|
203
|
+
maybeSurfaceAutoCreatedGroup(input, bundleRoot, nowIso);
|
|
204
|
+
return { allowed: true };
|
|
205
|
+
}
|
|
107
206
|
const trustLevel = input.friend.trustLevel ?? "friend";
|
|
108
207
|
// Family and friend — always allow on open
|
|
109
208
|
if ((0, types_1.isTrustedLevel)(trustLevel)) {
|
|
@@ -119,11 +218,7 @@ function enforceTrustGate(input) {
|
|
|
119
218
|
return handleStranger(input, bundleRoot, nowIso);
|
|
120
219
|
}
|
|
121
220
|
function handleAcquaintance(input, bundleRoot, nowIso) {
|
|
122
|
-
const { isGroupChat,
|
|
123
|
-
// Group chat with family member present — allow
|
|
124
|
-
if (isGroupChat && groupHasFamilyMember) {
|
|
125
|
-
return { allowed: true };
|
|
126
|
-
}
|
|
221
|
+
const { isGroupChat, hasExistingGroupWithFamily } = input;
|
|
127
222
|
let result;
|
|
128
223
|
let noticeDetail;
|
|
129
224
|
if (isGroupChat) {
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Harness-side trip ledger primitive.
|
|
3
|
+
//
|
|
4
|
+
// Mirrors the substrate's @ouro/work-protocol/src/trip.ts contract (vendored
|
|
5
|
+
// the same way mailroom/core.ts vendors mail). Slugger's framing: today,
|
|
6
|
+
// doc-edits-from-mail keep falling back on freeform parsing because there is
|
|
7
|
+
// no structured object between "mail body" and "travel doc". TripRecord +
|
|
8
|
+
// TripLeg are that object — every leg fact carries non-optional provenance
|
|
9
|
+
// (TripEvidence with discoveryMethod) so the ledger can be audited cleanly
|
|
10
|
+
// and reasoned about under conflict.
|
|
11
|
+
//
|
|
12
|
+
// Per-agent ledger keypair design: in v1 each agent has ONE ledger keypair.
|
|
13
|
+
// All TripRecord blobs are encrypted with that key. Cross-trip sharing
|
|
14
|
+
// (handing one trip's facts to another party without their owning the whole
|
|
15
|
+
// ledger) is a follow-on; it would shard to per-trip keys, which the
|
|
16
|
+
// substrate's TripLedgerRegistry can already represent.
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.generateTripKeyPair = generateTripKeyPair;
|
|
52
|
+
exports.encryptTripRecord = encryptTripRecord;
|
|
53
|
+
exports.decryptTripRecord = decryptTripRecord;
|
|
54
|
+
exports.newTripId = newTripId;
|
|
55
|
+
exports.newLegId = newLegId;
|
|
56
|
+
exports.newTripLedgerRecord = newTripLedgerRecord;
|
|
57
|
+
const crypto = __importStar(require("node:crypto"));
|
|
58
|
+
// ── Helpers: keys + crypto ─────────────────────────────────────────
|
|
59
|
+
function safeLabel(label) {
|
|
60
|
+
return label.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
61
|
+
}
|
|
62
|
+
function generateTripKeyPair(label) {
|
|
63
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
64
|
+
modulusLength: 2048,
|
|
65
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
66
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
67
|
+
});
|
|
68
|
+
const slug = safeLabel(label) || "ledger";
|
|
69
|
+
const fingerprint = crypto.createHash("sha256").update(publicKey).digest("hex").slice(0, 16);
|
|
70
|
+
return {
|
|
71
|
+
keyId: `trip_${slug}_${fingerprint}`,
|
|
72
|
+
publicKeyPem: publicKey,
|
|
73
|
+
privateKeyPem: privateKey,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function encryptTripRecord(trip, publicKeyPem, keyId) {
|
|
77
|
+
const contentKey = crypto.randomBytes(32);
|
|
78
|
+
const iv = crypto.randomBytes(12);
|
|
79
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", contentKey, iv);
|
|
80
|
+
const ciphertext = Buffer.concat([cipher.update(Buffer.from(JSON.stringify(trip), "utf-8")), cipher.final()]);
|
|
81
|
+
const authTag = cipher.getAuthTag();
|
|
82
|
+
const wrappedKey = crypto.publicEncrypt({ key: publicKeyPem, oaepHash: "sha256" }, contentKey);
|
|
83
|
+
return {
|
|
84
|
+
algorithm: "RSA-OAEP-SHA256+A256GCM",
|
|
85
|
+
keyId,
|
|
86
|
+
wrappedKey: wrappedKey.toString("base64"),
|
|
87
|
+
iv: iv.toString("base64"),
|
|
88
|
+
authTag: authTag.toString("base64"),
|
|
89
|
+
ciphertext: ciphertext.toString("base64"),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function decryptTripRecord(payload, privateKeyPem) {
|
|
93
|
+
const contentKey = crypto.privateDecrypt({
|
|
94
|
+
key: privateKeyPem,
|
|
95
|
+
oaepHash: "sha256",
|
|
96
|
+
}, Buffer.from(payload.wrappedKey, "base64"));
|
|
97
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", contentKey, Buffer.from(payload.iv, "base64"));
|
|
98
|
+
decipher.setAuthTag(Buffer.from(payload.authTag, "base64"));
|
|
99
|
+
const plaintext = Buffer.concat([
|
|
100
|
+
decipher.update(Buffer.from(payload.ciphertext, "base64")),
|
|
101
|
+
decipher.final(),
|
|
102
|
+
]);
|
|
103
|
+
return JSON.parse(plaintext.toString("utf-8"));
|
|
104
|
+
}
|
|
105
|
+
// ── Helpers: deterministic ids ─────────────────────────────────────
|
|
106
|
+
function newTripId(agentId, name, createdAt) {
|
|
107
|
+
const fingerprint = crypto.createHash("sha256")
|
|
108
|
+
.update(`${agentId}\n${name}\n${createdAt}`)
|
|
109
|
+
.digest("hex")
|
|
110
|
+
.slice(0, 16);
|
|
111
|
+
const slug = safeLabel(name) || "trip";
|
|
112
|
+
return `trip_${slug}_${fingerprint}`;
|
|
113
|
+
}
|
|
114
|
+
function newLegId(input) {
|
|
115
|
+
const distinguish = input.vendor || input.confirmationCode || crypto.randomUUID();
|
|
116
|
+
const fingerprint = crypto.createHash("sha256")
|
|
117
|
+
.update(`${input.tripId}\n${input.kind}\n${distinguish}\n${input.createdAt}`)
|
|
118
|
+
.digest("hex")
|
|
119
|
+
.slice(0, 16);
|
|
120
|
+
return `leg_${input.kind}_${fingerprint}`;
|
|
121
|
+
}
|
|
122
|
+
// ── Ledger record helpers ──────────────────────────────────────────
|
|
123
|
+
function newTripLedgerRecord(input) {
|
|
124
|
+
const now = (input.now ?? (() => new Date().toISOString()))();
|
|
125
|
+
const keypair = generateTripKeyPair(input.label ?? input.agentId);
|
|
126
|
+
const ledgerId = `ledger_${safeLabel(input.agentId) || "agent"}_${crypto.createHash("sha256").update(`${input.agentId}\n${now}\n${keypair.keyId}`).digest("hex").slice(0, 16)}`;
|
|
127
|
+
return {
|
|
128
|
+
ledger: {
|
|
129
|
+
schemaVersion: 1,
|
|
130
|
+
agentId: input.agentId,
|
|
131
|
+
ledgerId,
|
|
132
|
+
keyId: keypair.keyId,
|
|
133
|
+
publicKeyPem: keypair.publicKeyPem,
|
|
134
|
+
createdAt: now,
|
|
135
|
+
},
|
|
136
|
+
keypair,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
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.TripNotFoundError = void 0;
|
|
37
|
+
exports.ensureAgentTripLedger = ensureAgentTripLedger;
|
|
38
|
+
exports.readAgentTripKeypair = readAgentTripKeypair;
|
|
39
|
+
exports.upsertTripRecord = upsertTripRecord;
|
|
40
|
+
exports.readTripRecord = readTripRecord;
|
|
41
|
+
exports.listTripIds = listTripIds;
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const identity_1 = require("../heart/identity");
|
|
45
|
+
const runtime_1 = require("../nerves/runtime");
|
|
46
|
+
const core_1 = require("./core");
|
|
47
|
+
function tripsRoot(agentName) {
|
|
48
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "trips");
|
|
49
|
+
}
|
|
50
|
+
function ledgerPath(agentName) {
|
|
51
|
+
return path.join(tripsRoot(agentName), "ledger.json");
|
|
52
|
+
}
|
|
53
|
+
function recordsDir(agentName) {
|
|
54
|
+
return path.join(tripsRoot(agentName), "records");
|
|
55
|
+
}
|
|
56
|
+
function recordPath(agentName, tripId) {
|
|
57
|
+
return path.join(recordsDir(agentName), `${tripId}.json`);
|
|
58
|
+
}
|
|
59
|
+
function readJsonFile(filePath) {
|
|
60
|
+
if (!fs.existsSync(filePath))
|
|
61
|
+
return null;
|
|
62
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
63
|
+
}
|
|
64
|
+
function writeJsonAtomic(filePath, value) {
|
|
65
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
66
|
+
const tmp = `${filePath}.tmp`;
|
|
67
|
+
fs.writeFileSync(tmp, JSON.stringify(value, null, 2), "utf-8");
|
|
68
|
+
fs.renameSync(tmp, filePath);
|
|
69
|
+
}
|
|
70
|
+
class TripNotFoundError extends Error {
|
|
71
|
+
statusCode = 404;
|
|
72
|
+
constructor(input) {
|
|
73
|
+
super(`trip not found: agent=${input.agentName} trip=${input.tripId}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.TripNotFoundError = TripNotFoundError;
|
|
77
|
+
/**
|
|
78
|
+
* Idempotent — if the agent already has a ledger on disk, return it; otherwise
|
|
79
|
+
* generate a fresh keypair and persist both halves.
|
|
80
|
+
*/
|
|
81
|
+
function ensureAgentTripLedger(input) {
|
|
82
|
+
const existing = readJsonFile(ledgerPath(input.agentName));
|
|
83
|
+
if (existing) {
|
|
84
|
+
return { ledger: existing.ledger, added: false };
|
|
85
|
+
}
|
|
86
|
+
const created = (0, core_1.newTripLedgerRecord)({
|
|
87
|
+
agentId: input.agentName,
|
|
88
|
+
...(input.label ? { label: input.label } : {}),
|
|
89
|
+
...(input.now ? { now: input.now } : {}),
|
|
90
|
+
});
|
|
91
|
+
const stored = {
|
|
92
|
+
schemaVersion: 1,
|
|
93
|
+
ledger: created.ledger,
|
|
94
|
+
privateKeyPem: created.keypair.privateKeyPem,
|
|
95
|
+
};
|
|
96
|
+
writeJsonAtomic(ledgerPath(input.agentName), stored);
|
|
97
|
+
(0, runtime_1.emitNervesEvent)({
|
|
98
|
+
component: "trips",
|
|
99
|
+
event: "trips.ledger_created",
|
|
100
|
+
message: "agent trip ledger keypair created",
|
|
101
|
+
meta: { agentId: input.agentName, ledgerId: created.ledger.ledgerId, keyId: created.ledger.keyId },
|
|
102
|
+
});
|
|
103
|
+
return { ledger: created.ledger, added: true };
|
|
104
|
+
}
|
|
105
|
+
function readLedgerOrThrow(agentName) {
|
|
106
|
+
const stored = readJsonFile(ledgerPath(agentName));
|
|
107
|
+
if (!stored) {
|
|
108
|
+
throw new Error(`no trip ledger for agent ${agentName} — call ensureAgentTripLedger first`);
|
|
109
|
+
}
|
|
110
|
+
return stored;
|
|
111
|
+
}
|
|
112
|
+
function readAgentTripKeypair(agentName) {
|
|
113
|
+
const stored = readLedgerOrThrow(agentName);
|
|
114
|
+
return {
|
|
115
|
+
keyId: stored.ledger.keyId,
|
|
116
|
+
publicKeyPem: stored.ledger.publicKeyPem,
|
|
117
|
+
privateKeyPem: stored.privateKeyPem,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function upsertTripRecord(agentName, trip) {
|
|
121
|
+
const stored = readLedgerOrThrow(agentName);
|
|
122
|
+
const payload = (0, core_1.encryptTripRecord)(trip, stored.ledger.publicKeyPem, stored.ledger.keyId);
|
|
123
|
+
writeJsonAtomic(recordPath(agentName, trip.tripId), payload);
|
|
124
|
+
(0, runtime_1.emitNervesEvent)({
|
|
125
|
+
component: "trips",
|
|
126
|
+
event: "trips.record_upserted",
|
|
127
|
+
message: "trip record upserted",
|
|
128
|
+
meta: { agentId: agentName, tripId: trip.tripId, legCount: trip.legs.length, status: trip.status },
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function readTripRecord(agentName, tripId) {
|
|
132
|
+
const payload = readJsonFile(recordPath(agentName, tripId));
|
|
133
|
+
if (!payload)
|
|
134
|
+
throw new TripNotFoundError({ agentName, tripId });
|
|
135
|
+
const stored = readLedgerOrThrow(agentName);
|
|
136
|
+
return (0, core_1.decryptTripRecord)(payload, stored.privateKeyPem);
|
|
137
|
+
}
|
|
138
|
+
function listTripIds(agentName) {
|
|
139
|
+
const dir = recordsDir(agentName);
|
|
140
|
+
if (!fs.existsSync(dir))
|
|
141
|
+
return [];
|
|
142
|
+
return fs.readdirSync(dir)
|
|
143
|
+
.filter((entry) => entry.endsWith(".json"))
|
|
144
|
+
.map((entry) => entry.slice(0, -".json".length))
|
|
145
|
+
.sort();
|
|
146
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.551",
|
|
4
4
|
"main": "dist/heart/daemon/ouro-entry.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cli": "dist/heart/daemon/ouro-bot-entry.js",
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
12
|
+
"SerpentGuide.ouro/",
|
|
13
|
+
"RepairGuide.ouro/",
|
|
14
|
+
"skills/",
|
|
14
15
|
"assets/",
|
|
15
16
|
"changelog.json"
|
|
16
17
|
],
|
|
@@ -19,36 +20,66 @@
|
|
|
19
20
|
"./runOuroCli": "./dist/heart/daemon/daemon-cli.js"
|
|
20
21
|
},
|
|
21
22
|
"scripts": {
|
|
22
|
-
"dev": "tsc && node dist/
|
|
23
|
+
"dev": "tsc && node dist/heart/daemon/ouro-bot-entry.js dev",
|
|
24
|
+
"cli": "tsc && node dist/senses/cli-entry.js",
|
|
23
25
|
"daemon": "tsc && node dist/heart/daemon/daemon-entry.js",
|
|
24
26
|
"ouro": "tsc && node dist/heart/daemon/ouro-entry.js",
|
|
25
27
|
"teams": "tsc && node dist/senses/teams-entry.js --agent ouroboros",
|
|
26
|
-
"bluebubbles": "tsc && node dist/senses/bluebubbles
|
|
28
|
+
"bluebubbles": "tsc && node dist/senses/bluebubbles/entry.js --agent ouroboros",
|
|
27
29
|
"test": "vitest run",
|
|
30
|
+
"test:integration": "npm run build && vitest run --config vitest.integration.config.ts",
|
|
31
|
+
"test:e2e:package": "npm run build && node scripts/package-e2e.cjs",
|
|
32
|
+
"test:e2e:real-smoke": "npm run build && node scripts/nightly-real-smoke.cjs",
|
|
33
|
+
"typecheck:mailbox-ui": "tsc --noEmit -p packages/mailbox-ui/tsconfig.json",
|
|
34
|
+
"test:mailbox-ui": "npm test --prefix packages/mailbox-ui",
|
|
28
35
|
"test:coverage:vitest": "vitest run --coverage",
|
|
29
36
|
"test:coverage": "node scripts/run-coverage-gate.cjs",
|
|
30
|
-
"build": "tsc",
|
|
37
|
+
"build": "tsc && (cd packages/mailbox-ui && npm install --ignore-scripts 2>/dev/null && npm run build && cd ../.. && node scripts/copy-mailbox-ui.cjs) || echo 'mailbox-ui build skipped'",
|
|
31
38
|
"lint": "eslint src/",
|
|
39
|
+
"release:preflight": "node scripts/release-preflight.cjs",
|
|
40
|
+
"release:smoke": "node scripts/release-smoke.cjs",
|
|
32
41
|
"audit:nerves": "npm run build && node dist/nerves/coverage/cli-main.js"
|
|
33
42
|
},
|
|
34
43
|
"dependencies": {
|
|
35
44
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
45
|
+
"@azure/identity": "^4.13.0",
|
|
46
|
+
"@azure/storage-blob": "^12.31.0",
|
|
47
|
+
"@microsoft/teams.api": "2.0.5",
|
|
36
48
|
"@microsoft/teams.apps": "^2.0.5",
|
|
49
|
+
"@microsoft/teams.cards": "2.0.5",
|
|
50
|
+
"@microsoft/teams.common": "2.0.5",
|
|
37
51
|
"@microsoft/teams.dev": "^2.0.5",
|
|
52
|
+
"@microsoft/teams.graph": "2.0.5",
|
|
53
|
+
"@types/react": "^17.0.91",
|
|
38
54
|
"fast-glob": "^3.3.3",
|
|
55
|
+
"ink": "^3.2.0",
|
|
56
|
+
"mailparser": "^3.9.8",
|
|
39
57
|
"openai": "^6.27.0",
|
|
40
|
-
"
|
|
58
|
+
"react": "^17.0.2",
|
|
59
|
+
"semver": "^7.7.4",
|
|
60
|
+
"smtp-server": "^3.18.4",
|
|
61
|
+
"stripe": "^22.0.0"
|
|
41
62
|
},
|
|
42
63
|
"repository": {
|
|
43
64
|
"type": "git",
|
|
44
65
|
"url": "https://github.com/ouroborosbot/ouroboros"
|
|
45
66
|
},
|
|
46
67
|
"devDependencies": {
|
|
68
|
+
"@testing-library/react": "^16.3.2",
|
|
69
|
+
"@types/mailparser": "^3.4.6",
|
|
47
70
|
"@types/semver": "^7.7.1",
|
|
71
|
+
"@types/smtp-server": "^3.5.13",
|
|
48
72
|
"@vitest/coverage-v8": "^4.0.18",
|
|
49
73
|
"eslint": "^10.0.2",
|
|
74
|
+
"jsdom": "^29.0.2",
|
|
50
75
|
"typescript": "^5.7.0",
|
|
51
76
|
"typescript-eslint": "^8.56.1",
|
|
52
77
|
"vitest": "^4.0.18"
|
|
78
|
+
},
|
|
79
|
+
"overrides": {
|
|
80
|
+
"@testing-library/react": {
|
|
81
|
+
"react": "$react",
|
|
82
|
+
"@types/react": "$@types/react"
|
|
83
|
+
}
|
|
53
84
|
}
|
|
54
85
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Agent Commerce Skill
|
|
2
|
+
|
|
3
|
+
How to book, purchase, and pay for things on behalf of humans.
|
|
4
|
+
|
|
5
|
+
## Three Patterns
|
|
6
|
+
|
|
7
|
+
### Pattern A: API (Structured, Preferred)
|
|
8
|
+
|
|
9
|
+
For services with direct API access: Duffel flights, LiteAPI hotels.
|
|
10
|
+
|
|
11
|
+
1. Search using the API tool (`flight_search`, LiteAPI MCP)
|
|
12
|
+
2. Present options to the human with prices and details
|
|
13
|
+
3. Human approves a specific option and price
|
|
14
|
+
4. Book using the API tool with passenger data from `user_profile_get`
|
|
15
|
+
5. Create a single-use virtual card via `stripe_create_card`
|
|
16
|
+
6. Complete payment through the API
|
|
17
|
+
7. Deactivate the card via `stripe_deactivate_card`
|
|
18
|
+
8. Confirm booking to the human
|
|
19
|
+
|
|
20
|
+
**Key tools**: `flight_search`, `flight_book`, `flight_cancel`, `user_profile_get`, `user_profile_store`, `stripe_create_card`, `stripe_deactivate_card`, `stripe_list_cards`
|
|
21
|
+
|
|
22
|
+
### Pattern B: Browser (Best-Effort)
|
|
23
|
+
|
|
24
|
+
For sites without API access, use browser automation via Playwright MCP.
|
|
25
|
+
|
|
26
|
+
1. Navigate to the booking site
|
|
27
|
+
2. Search for the requested service
|
|
28
|
+
3. Fill forms using data from `user_profile_get`
|
|
29
|
+
4. Use a virtual card from `stripe_create_card` for payment
|
|
30
|
+
5. If blocked by anti-bot measures, fall back to Pattern C
|
|
31
|
+
6. Complete and confirm the booking
|
|
32
|
+
|
|
33
|
+
**Limitations**: Browser automation is fragile. Sites may block, layouts change, CAPTCHAs appear. Always have Pattern C as fallback.
|
|
34
|
+
|
|
35
|
+
### Pattern C: Link-Only (Primary for Hostile Sites)
|
|
36
|
+
|
|
37
|
+
For sites that block automation or require complex human interaction.
|
|
38
|
+
|
|
39
|
+
1. Research the best options using browser tools or API tools
|
|
40
|
+
2. Prepare a curated link with pre-filled parameters where possible
|
|
41
|
+
3. Send the link to the human with a summary of what to book
|
|
42
|
+
4. Human completes the booking in their own browser
|
|
43
|
+
|
|
44
|
+
**When to use**: Always use Pattern C as the primary approach for sites known to block automation (most airline direct sites, hotel chains, rental car sites). Pattern B is best-effort, not reliable.
|
|
45
|
+
|
|
46
|
+
## Payment autonomy Levels
|
|
47
|
+
|
|
48
|
+
- **Level 0**: No autonomous payments. Agent researches, human pays manually.
|
|
49
|
+
- **Level 1**: Agent creates virtual cards, human approves each transaction explicitly.
|
|
50
|
+
- **Level 2**: Agent can book pre-approved items (within budget, approved categories) without per-transaction approval.
|
|
51
|
+
- **Level 3**: Full delegation with spending limits. Agent manages a budget and books as needed.
|
|
52
|
+
|
|
53
|
+
Default is Level 1. Level changes require explicit human approval.
|
|
54
|
+
|
|
55
|
+
## Error Handling
|
|
56
|
+
|
|
57
|
+
### Price Change Guard
|
|
58
|
+
Before completing a booking, verify the final price matches the approved price within 5%. If the price changed more than 5%, stop and report to the human. Never pay a price the human didn't approve.
|
|
59
|
+
|
|
60
|
+
### Partial Failure Reporting
|
|
61
|
+
When booking involves multiple services (e.g., flight + hotel), each service may succeed or fail independently — this is a partial failure scenario. Report the status of each service separately. **Never auto-cancel a successful booking because a related booking failed.** Let the human decide.
|
|
62
|
+
|
|
63
|
+
Example: "Flight SFO-JFK booked (confirmation: ABC123). Hotel booking failed: no availability for those dates. Would you like me to search for alternative hotels?"
|
|
64
|
+
|
|
65
|
+
### Refund Flow
|
|
66
|
+
If a booking fails after card creation:
|
|
67
|
+
1. Deactivate the virtual card immediately
|
|
68
|
+
2. Report the failure to the human
|
|
69
|
+
3. If a charge was made, note it for the human to follow up with the provider
|
|
70
|
+
|
|
71
|
+
## CAPTCHA Handling
|
|
72
|
+
|
|
73
|
+
When a CAPTCHA appears during browser automation (Pattern B):
|
|
74
|
+
1. Take a screenshot and send it to the human
|
|
75
|
+
2. Explain what page you're on and what you were trying to do
|
|
76
|
+
3. Ask the human to solve the CAPTCHA in their own browser
|
|
77
|
+
4. Switch to Pattern C (link-only) for this transaction
|
|
78
|
+
|
|
79
|
+
Never attempt to solve CAPTCHAs programmatically.
|
|
80
|
+
|
|
81
|
+
## Card Number Isolation
|
|
82
|
+
|
|
83
|
+
Card numbers must NEVER appear in:
|
|
84
|
+
- Tool return values shown to the model
|
|
85
|
+
- Nerves events or logs
|
|
86
|
+
- Chat messages to the human
|
|
87
|
+
- Any stored state or written notes
|
|
88
|
+
|
|
89
|
+
The only place card numbers exist is inside the Stripe client's internal payment flow functions, scoped to a single function call. The model only ever sees card IDs and last-4 digits.
|
|
90
|
+
|
|
91
|
+
## Profile Data Usage
|
|
92
|
+
|
|
93
|
+
Access profile data only when needed for the current transaction:
|
|
94
|
+
- `user_profile_get` to retrieve specific fields (never dump full profile)
|
|
95
|
+
- Passport data only for international bookings
|
|
96
|
+
- Loyalty program numbers only when booking with that program
|
|
97
|
+
- Emergency contact only when the booking service requires it
|
|
98
|
+
|
|
99
|
+
## Self-Test
|
|
100
|
+
|
|
101
|
+
Before first use, run the commerce self-test to verify all services are configured:
|
|
102
|
+
- Stripe: creates and deactivates a test virtual card
|
|
103
|
+
- Duffel: runs a test flight search
|
|
104
|
+
- LiteAPI: verifies API key in vault
|
|
105
|
+
|
|
106
|
+
Report results to the human with actionable next steps for any failures.
|