@ouro.bot/cli 0.1.0-alpha.55 → 0.1.0-alpha.550
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -19
- package/RepairGuide.ouro/agent.json +5 -0
- package/RepairGuide.ouro/psyche/IDENTITY.md +19 -0
- package/RepairGuide.ouro/psyche/SOUL.md +55 -0
- package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-broken-remote.md +63 -0
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +35 -0
- package/RepairGuide.ouro/skills/diagnose-sync-blocked.md +54 -0
- package/RepairGuide.ouro/skills/diagnose-vault-expired.md +60 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +4 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3555 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +837 -26
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +479 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +114 -118
- package/dist/heart/core.js +925 -246
- package/dist/heart/cross-chat-delivery.js +3 -18
- package/dist/heart/daemon/agent-config-check.js +512 -0
- package/dist/heart/daemon/agent-discovery.js +102 -3
- package/dist/heart/daemon/agent-service.js +522 -0
- package/dist/heart/daemon/agentic-repair.js +554 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/boot-sync-probe.js +197 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +665 -0
- package/dist/heart/daemon/cli-exec.js +7565 -0
- package/dist/heart/daemon/cli-help.js +498 -0
- package/dist/heart/daemon/cli-parse.js +1590 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +775 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1672
- package/dist/heart/daemon/daemon-entry.js +417 -2
- package/dist/heart/daemon/daemon-health.js +183 -0
- package/dist/heart/daemon/daemon-rollup.js +58 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +87 -13
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +758 -71
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +844 -0
- package/dist/heart/daemon/drift-detection.js +146 -0
- package/dist/heart/daemon/health-monitor.js +122 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +102 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +37 -8
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/mcp-canary.js +297 -0
- package/dist/heart/daemon/message-router.js +2 -2
- package/dist/heart/daemon/os-cron-deps.js +135 -0
- package/dist/heart/daemon/os-cron.js +14 -12
- package/dist/heart/daemon/ouro-bot-entry.js +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +375 -33
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +3 -31
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +353 -38
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +158 -11
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +330 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +162 -17
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +1 -1
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +6 -8
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +200 -51
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mailbox/mailbox-http-hooks.js +66 -0
- package/dist/heart/mailbox/mailbox-http-response.js +7 -0
- package/dist/heart/mailbox/mailbox-http-routes.js +246 -0
- package/dist/heart/mailbox/mailbox-http-static.js +103 -0
- package/dist/heart/mailbox/mailbox-http-transport.js +116 -0
- package/dist/heart/mailbox/mailbox-http.js +99 -0
- package/dist/heart/mailbox/mailbox-read.js +31 -0
- package/dist/heart/mailbox/mailbox-types.js +27 -0
- package/dist/heart/mailbox/mailbox-view.js +195 -0
- package/dist/heart/mailbox/readers/agent-machine.js +382 -0
- package/dist/heart/mailbox/readers/continuity-readers.js +338 -0
- package/dist/heart/mailbox/readers/mail.js +362 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +651 -0
- package/dist/heart/mailbox/readers/sessions.js +232 -0
- package/dist/heart/mailbox/readers/shared.js +111 -0
- package/dist/heart/mcp/mcp-server.js +683 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +19 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +425 -0
- package/dist/heart/provider-failover.js +301 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +139 -52
- package/dist/heart/providers/azure.js +97 -13
- package/dist/heart/providers/error-classification.js +127 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +26 -8
- package/dist/heart/providers/openai-codex.js +55 -40
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +367 -0
- package/dist/heart/runtime-cwd.js +87 -0
- package/dist/heart/sense-truth.js +11 -4
- package/dist/heart/session-activity.js +43 -22
- package/dist/heart/session-events.js +1149 -0
- package/dist/heart/session-playback-cli-main.js +5 -0
- package/dist/heart/session-playback-cli.js +36 -0
- package/dist/heart/session-playback.js +231 -0
- package/dist/heart/session-stats-cli-main.js +5 -0
- package/dist/heart/session-stats.js +182 -0
- package/dist/heart/session-transcript.js +243 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +44 -27
- package/dist/heart/sync-classification.js +176 -0
- package/dist/heart/sync.js +449 -0
- package/dist/heart/target-resolution.js +9 -5
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/timeouts.js +101 -0
- package/dist/heart/tool-activity-callbacks.js +59 -0
- package/dist/heart/tool-description.js +139 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +381 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +6 -5
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +426 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +6 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/mailbox-ui/assets/index-Cm51CY9W.js +61 -0
- package/dist/mailbox-ui/index.html +15 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +674 -0
- package/dist/mailroom/body-cache.js +61 -0
- package/dist/mailroom/core.js +720 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +430 -0
- package/dist/mailroom/mbox-import.js +383 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +233 -0
- package/dist/mailroom/search-cache.js +256 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +165 -101
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +62 -75
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +30 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +39 -3
- package/dist/mind/friends/types.js +2 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +4 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +995 -123
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +139 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/review/cli-main.js +5 -0
- package/dist/nerves/review/cli.js +156 -0
- package/dist/nerves/review/core.js +152 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +816 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +295 -0
- package/dist/repertoire/mcp-manager.js +362 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -4
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +47 -1075
- package/dist/repertoire/tools-bluebubbles.js +1 -0
- package/dist/repertoire/tools-bridge.js +142 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +381 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +119 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1857 -0
- package/dist/repertoire/tools-notes.js +421 -0
- package/dist/repertoire/tools-session.js +750 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +9 -39
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +604 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +108 -100
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +561 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +116 -0
- package/dist/senses/bluebubbles/active-turns.js +216 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +77 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +20 -3
- package/dist/senses/bluebubbles/index.js +2305 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/processed-log.js +133 -0
- package/dist/senses/bluebubbles/replay.js +137 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +30 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +607 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +85 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +520 -209
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +175 -21
- package/dist/senses/inner-dialog.js +330 -27
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +569 -182
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +248 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +387 -98
- package/dist/senses/trust-gate.js +100 -5
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +38 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +138 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1177
- package/dist/senses/debug-activity.js +0 -148
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
|
@@ -0,0 +1,1590 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLI argument parsing — converts argv into OuroCliCommand objects.
|
|
4
|
+
*
|
|
5
|
+
* Pure functions: no side effects, no daemon communication.
|
|
6
|
+
* Each command group has its own parser; parseOuroCommand dispatches.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.extractAgentFlag = extractAgentFlag;
|
|
10
|
+
exports.extractFacingFlag = extractFacingFlag;
|
|
11
|
+
exports.facingToProviderLane = facingToProviderLane;
|
|
12
|
+
exports.isAgentProvider = isAgentProvider;
|
|
13
|
+
exports.usage = usage;
|
|
14
|
+
exports.inferAgentNameFromRemote = inferAgentNameFromRemote;
|
|
15
|
+
exports.parseMcpServeCommand = parseMcpServeCommand;
|
|
16
|
+
exports.parseOuroCommand = parseOuroCommand;
|
|
17
|
+
const types_1 = require("../../mind/friends/types");
|
|
18
|
+
const cli_help_1 = require("./cli-help");
|
|
19
|
+
const vault_items_1 = require("./vault-items");
|
|
20
|
+
// ── Shared helpers ──
|
|
21
|
+
function extractAgentFlag(args) {
|
|
22
|
+
const idx = args.indexOf("--agent");
|
|
23
|
+
if (idx === -1 || idx + 1 >= args.length)
|
|
24
|
+
return { rest: args };
|
|
25
|
+
const agent = args[idx + 1];
|
|
26
|
+
const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
27
|
+
return { agent, rest };
|
|
28
|
+
}
|
|
29
|
+
function extractFacingFlag(args) {
|
|
30
|
+
const idx = args.indexOf("--facing");
|
|
31
|
+
if (idx === -1 || idx + 1 >= args.length)
|
|
32
|
+
return { rest: args };
|
|
33
|
+
const value = args[idx + 1];
|
|
34
|
+
if (value !== "human" && value !== "agent") {
|
|
35
|
+
throw new Error(`--facing must be 'human' or 'agent'`);
|
|
36
|
+
}
|
|
37
|
+
const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
38
|
+
return { facing: value, rest };
|
|
39
|
+
}
|
|
40
|
+
function facingToProviderLane(facing) {
|
|
41
|
+
return facing === "human" ? "outward" : "inner";
|
|
42
|
+
}
|
|
43
|
+
function isProviderLane(value) {
|
|
44
|
+
return value === "outward" || value === "inner";
|
|
45
|
+
}
|
|
46
|
+
function helpCommandName(args) {
|
|
47
|
+
const positional = [];
|
|
48
|
+
for (const arg of args) {
|
|
49
|
+
if (arg === "--help" || arg === "-h")
|
|
50
|
+
break;
|
|
51
|
+
if (arg.startsWith("-"))
|
|
52
|
+
break;
|
|
53
|
+
positional.push(arg);
|
|
54
|
+
}
|
|
55
|
+
return positional.length > 0 ? positional.join(" ") : undefined;
|
|
56
|
+
}
|
|
57
|
+
function extractLaneFlag(args) {
|
|
58
|
+
const idx = args.indexOf("--lane");
|
|
59
|
+
if (idx === -1 || idx + 1 >= args.length)
|
|
60
|
+
return { rest: args };
|
|
61
|
+
const value = args[idx + 1];
|
|
62
|
+
if (!isProviderLane(value)) {
|
|
63
|
+
throw new Error("--lane must be 'outward' or 'inner'");
|
|
64
|
+
}
|
|
65
|
+
const rest = [...args.slice(0, idx), ...args.slice(idx + 2)];
|
|
66
|
+
return { lane: value, rest };
|
|
67
|
+
}
|
|
68
|
+
function isAgentProvider(value) {
|
|
69
|
+
return value === "azure" || value === "anthropic" || value === "minimax" || value === "openai-codex" || value === "github-copilot";
|
|
70
|
+
}
|
|
71
|
+
function usage() {
|
|
72
|
+
return [
|
|
73
|
+
"Usage:",
|
|
74
|
+
" ouro [up] [--no-repair]",
|
|
75
|
+
" ouro dev [--repo-path <path>] [--clone [--clone-path <path>]]",
|
|
76
|
+
" ouro stop|down|status|logs|hatch",
|
|
77
|
+
" ouro status --agent <name>",
|
|
78
|
+
" ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]",
|
|
79
|
+
" ouro check [--agent <name>] --lane outward|inner",
|
|
80
|
+
" ouro repair [--agent <name>]",
|
|
81
|
+
" ouro provider refresh [--agent <name>]",
|
|
82
|
+
" ouro mailbox [--json]",
|
|
83
|
+
" ouro -v|--version",
|
|
84
|
+
" ouro config model [--agent <name>] <model-name>",
|
|
85
|
+
" ouro config models [--agent <name>]",
|
|
86
|
+
" ouro auth [--agent <name>] [--provider <provider>]",
|
|
87
|
+
" ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
88
|
+
" ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]",
|
|
89
|
+
" ouro mail import-mbox --file <path> [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]",
|
|
90
|
+
" ouro mail backfill-indexes [--agent <name>] [--foreground]",
|
|
91
|
+
" ouro auth verify [--agent <name>] [--provider <provider>]",
|
|
92
|
+
" ouro auth switch [--agent <name>] --provider <provider>",
|
|
93
|
+
" ouro vault create [--agent <name>] --email <email> [--server <url>] [--store <store>]",
|
|
94
|
+
" ouro vault replace [--agent <name>] [--email <email>] [--server <url>] [--store <store>]",
|
|
95
|
+
" ouro vault recover [--agent <name>] --from <json> [--from <json>] [--email <email>] [--server <url>] [--store <store>]",
|
|
96
|
+
" ouro vault unlock [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
|
|
97
|
+
" ouro vault status [--agent <name>] [--store auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file]",
|
|
98
|
+
" ouro vault config set [--agent <name>] --key <path> [--value <value>] [--scope agent|machine]",
|
|
99
|
+
" ouro vault config status [--agent <name>] [--scope agent|machine|all]",
|
|
100
|
+
" ouro vault item set [--agent <name>] --item <path> --secret-field <name> [--public-field <key=value>] [--note <text>]",
|
|
101
|
+
" ouro vault item status [--agent <name>] --item <path>",
|
|
102
|
+
" ouro vault item list [--agent <name>] [--prefix <path-prefix>]",
|
|
103
|
+
" ouro vault ops porkbun set [--agent <name>] --account <account>",
|
|
104
|
+
" ouro vault ops porkbun status [--agent <name>] [--account <account>]",
|
|
105
|
+
" ouro dns backup|plan|apply|verify|rollback|certificate [--agent <name>] --binding <path> [--output <path>] [--backup <path>] [--yes]",
|
|
106
|
+
" ouro chat <agent>",
|
|
107
|
+
" ouro msg --to <agent> [--session <id>] [--task <ref>] <message>",
|
|
108
|
+
" ouro poke <agent> --task <task-id>",
|
|
109
|
+
" ouro poke <agent> --habit <name>",
|
|
110
|
+
" ouro habit list [--agent <name>]",
|
|
111
|
+
" ouro habit create [--agent <name>] <name> [--cadence <interval>]",
|
|
112
|
+
" ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
|
|
113
|
+
" ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
|
|
114
|
+
" ouro task board [<status>] [--agent <name>]",
|
|
115
|
+
" ouro task create <title> [--type <type>] [--agent <name>]",
|
|
116
|
+
" ouro task update <id> <status> [--agent <name>]",
|
|
117
|
+
" ouro task show <id> [--agent <name>]",
|
|
118
|
+
" ouro task fix [--safe|--all] [<id> [--option <N>]] [--agent <name>]",
|
|
119
|
+
" ouro task actionable|deps|sessions [--agent <name>]",
|
|
120
|
+
" ouro reminder create <title> --body <body> [--at <iso>] [--cadence <interval>] [--category <category>] [--agent <name>]",
|
|
121
|
+
" ouro friend list [--agent <name>]",
|
|
122
|
+
" ouro friend show <id> [--agent <name>]",
|
|
123
|
+
" ouro friend create --name <name> [--trust <level>] [--agent <name>]",
|
|
124
|
+
" ouro friend update <id> --trust <level> [--agent <name>]",
|
|
125
|
+
" ouro thoughts [--last <n>] [--json] [--follow] [--agent <name>]",
|
|
126
|
+
" ouro inner [--agent <name>]",
|
|
127
|
+
" ouro friend link <agent> --friend <id> --provider <p> --external-id <eid>",
|
|
128
|
+
" ouro friend unlink <agent> --friend <id> --provider <p> --external-id <eid>",
|
|
129
|
+
" ouro whoami [--agent <name>]",
|
|
130
|
+
" ouro session list [--agent <name>]",
|
|
131
|
+
" ouro mcp list",
|
|
132
|
+
" ouro mcp call <server> <tool> [--args '{...}']",
|
|
133
|
+
" ouro rollback [<version>]",
|
|
134
|
+
" ouro versions",
|
|
135
|
+
" ouro clone <remote> [--agent <name>]",
|
|
136
|
+
" ouro doctor",
|
|
137
|
+
].join("\n");
|
|
138
|
+
}
|
|
139
|
+
// ── Per-group parsers ──
|
|
140
|
+
function parseMessageCommand(args) {
|
|
141
|
+
let to;
|
|
142
|
+
let sessionId;
|
|
143
|
+
let taskRef;
|
|
144
|
+
const messageParts = [];
|
|
145
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
146
|
+
const token = args[i];
|
|
147
|
+
if (token === "--to") {
|
|
148
|
+
to = args[i + 1];
|
|
149
|
+
i += 1;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (token === "--session") {
|
|
153
|
+
sessionId = args[i + 1];
|
|
154
|
+
i += 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (token === "--task") {
|
|
158
|
+
taskRef = args[i + 1];
|
|
159
|
+
i += 1;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
messageParts.push(token);
|
|
163
|
+
}
|
|
164
|
+
const content = messageParts.join(" ").trim();
|
|
165
|
+
if (!to || !content)
|
|
166
|
+
throw new Error(`Usage\n${usage()}`);
|
|
167
|
+
return {
|
|
168
|
+
kind: "message.send",
|
|
169
|
+
from: "ouro-cli",
|
|
170
|
+
to,
|
|
171
|
+
content,
|
|
172
|
+
sessionId,
|
|
173
|
+
taskRef,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function parsePokeCommand(args) {
|
|
177
|
+
const agent = args[0];
|
|
178
|
+
if (!agent)
|
|
179
|
+
throw new Error(`Usage\n${usage()}`);
|
|
180
|
+
let taskId;
|
|
181
|
+
let habitName;
|
|
182
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
183
|
+
if (args[i] === "--task") {
|
|
184
|
+
taskId = args[i + 1];
|
|
185
|
+
i += 1;
|
|
186
|
+
}
|
|
187
|
+
if (args[i] === "--habit") {
|
|
188
|
+
habitName = args[i + 1];
|
|
189
|
+
i += 1;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// --habit takes priority over --task
|
|
193
|
+
if (habitName)
|
|
194
|
+
return { kind: "habit.poke", agent, habitName };
|
|
195
|
+
if (!taskId)
|
|
196
|
+
throw new Error(`Usage\n${usage()}`);
|
|
197
|
+
return { kind: "task.poke", agent, taskId };
|
|
198
|
+
}
|
|
199
|
+
function parseHabitCommand(args) {
|
|
200
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
201
|
+
const sub = rest[0];
|
|
202
|
+
if (sub === "list") {
|
|
203
|
+
return { kind: "habit.list", ...(agent ? { agent } : {}) };
|
|
204
|
+
}
|
|
205
|
+
if (sub === "create") {
|
|
206
|
+
const nameArgs = rest.slice(1);
|
|
207
|
+
let name;
|
|
208
|
+
let cadence;
|
|
209
|
+
const positional = [];
|
|
210
|
+
for (let i = 0; i < nameArgs.length; i++) {
|
|
211
|
+
if (nameArgs[i] === "--cadence" && nameArgs[i + 1]) {
|
|
212
|
+
cadence = nameArgs[++i];
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
/* v8 ignore start -- defensive: --agent already extracted by extractAgentFlag; guard prevents regression if parsing flow changes @preserve */
|
|
216
|
+
if (nameArgs[i] === "--agent" && nameArgs[i + 1]) {
|
|
217
|
+
i++; // skip --agent value (already extracted)
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
/* v8 ignore stop */
|
|
221
|
+
positional.push(nameArgs[i]);
|
|
222
|
+
}
|
|
223
|
+
name = positional[0];
|
|
224
|
+
if (!name)
|
|
225
|
+
throw new Error(`Usage\n${usage()}`);
|
|
226
|
+
return { kind: "habit.create", name, ...(agent ? { agent } : {}), ...(cadence ? { cadence } : {}) };
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`Usage\n${usage()}`);
|
|
229
|
+
}
|
|
230
|
+
function parseLinkCommand(args, kind = "friend.link") {
|
|
231
|
+
const agent = args[0];
|
|
232
|
+
if (!agent)
|
|
233
|
+
throw new Error(`Usage\n${usage()}`);
|
|
234
|
+
let friendId;
|
|
235
|
+
let providerRaw;
|
|
236
|
+
let externalId;
|
|
237
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
238
|
+
const token = args[i];
|
|
239
|
+
if (token === "--friend") {
|
|
240
|
+
friendId = args[i + 1];
|
|
241
|
+
i += 1;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (token === "--provider") {
|
|
245
|
+
providerRaw = args[i + 1];
|
|
246
|
+
i += 1;
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (token === "--external-id") {
|
|
250
|
+
externalId = args[i + 1];
|
|
251
|
+
i += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (!friendId || !providerRaw || !externalId) {
|
|
256
|
+
throw new Error(`Usage\n${usage()}`);
|
|
257
|
+
}
|
|
258
|
+
if (!(0, types_1.isIdentityProvider)(providerRaw)) {
|
|
259
|
+
throw new Error(`Unknown identity provider '${providerRaw}'. Use aad|local|teams-conversation.`);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
kind,
|
|
263
|
+
agent,
|
|
264
|
+
friendId,
|
|
265
|
+
provider: providerRaw,
|
|
266
|
+
externalId,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function parseHatchCommand(args) {
|
|
270
|
+
let agentName;
|
|
271
|
+
let humanName;
|
|
272
|
+
let providerRaw;
|
|
273
|
+
let migrationPath;
|
|
274
|
+
const credentials = {};
|
|
275
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
276
|
+
const token = args[i];
|
|
277
|
+
if (token === "--agent") {
|
|
278
|
+
agentName = args[i + 1];
|
|
279
|
+
i += 1;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (token === "--human") {
|
|
283
|
+
humanName = args[i + 1];
|
|
284
|
+
i += 1;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (token === "--provider") {
|
|
288
|
+
providerRaw = args[i + 1];
|
|
289
|
+
i += 1;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
if (token === "--setup-token") {
|
|
293
|
+
credentials.setupToken = args[i + 1];
|
|
294
|
+
i += 1;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (token === "--oauth-token") {
|
|
298
|
+
credentials.oauthAccessToken = args[i + 1];
|
|
299
|
+
i += 1;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (token === "--api-key") {
|
|
303
|
+
credentials.apiKey = args[i + 1];
|
|
304
|
+
i += 1;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (token === "--endpoint") {
|
|
308
|
+
credentials.endpoint = args[i + 1];
|
|
309
|
+
i += 1;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (token === "--deployment") {
|
|
313
|
+
credentials.deployment = args[i + 1];
|
|
314
|
+
i += 1;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (token === "--migration-path") {
|
|
318
|
+
migrationPath = args[i + 1];
|
|
319
|
+
i += 1;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (providerRaw && !isAgentProvider(providerRaw)) {
|
|
324
|
+
throw new Error("Unknown provider. Use azure|anthropic|minimax|openai-codex|github-copilot.");
|
|
325
|
+
}
|
|
326
|
+
const provider = providerRaw && isAgentProvider(providerRaw) ? providerRaw : undefined;
|
|
327
|
+
return {
|
|
328
|
+
kind: "hatch.start",
|
|
329
|
+
agentName,
|
|
330
|
+
humanName,
|
|
331
|
+
provider,
|
|
332
|
+
credentials: Object.keys(credentials).length > 0 ? credentials : undefined,
|
|
333
|
+
migrationPath,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function parseTaskCommand(args) {
|
|
337
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
338
|
+
const [sub, ...rest] = cleaned;
|
|
339
|
+
if (!sub)
|
|
340
|
+
throw new Error(`Usage\n${usage()}`);
|
|
341
|
+
if (sub === "board") {
|
|
342
|
+
const status = rest[0];
|
|
343
|
+
return status
|
|
344
|
+
? { kind: "task.board", status, ...(agent ? { agent } : {}) }
|
|
345
|
+
: { kind: "task.board", ...(agent ? { agent } : {}) };
|
|
346
|
+
}
|
|
347
|
+
if (sub === "create") {
|
|
348
|
+
const title = rest[0];
|
|
349
|
+
if (!title)
|
|
350
|
+
throw new Error(`Usage\n${usage()}`);
|
|
351
|
+
let type;
|
|
352
|
+
for (let i = 1; i < rest.length; i++) {
|
|
353
|
+
if (rest[i] === "--type" && rest[i + 1]) {
|
|
354
|
+
type = rest[i + 1];
|
|
355
|
+
i += 1;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return type
|
|
359
|
+
? { kind: "task.create", title, type, ...(agent ? { agent } : {}) }
|
|
360
|
+
: { kind: "task.create", title, ...(agent ? { agent } : {}) };
|
|
361
|
+
}
|
|
362
|
+
if (sub === "update") {
|
|
363
|
+
const id = rest[0];
|
|
364
|
+
const status = rest[1];
|
|
365
|
+
if (!id || !status)
|
|
366
|
+
throw new Error(`Usage\n${usage()}`);
|
|
367
|
+
return { kind: "task.update", id, status, ...(agent ? { agent } : {}) };
|
|
368
|
+
}
|
|
369
|
+
if (sub === "show") {
|
|
370
|
+
const id = rest[0];
|
|
371
|
+
if (!id)
|
|
372
|
+
throw new Error(`Usage\n${usage()}`);
|
|
373
|
+
return { kind: "task.show", id, ...(agent ? { agent } : {}) };
|
|
374
|
+
}
|
|
375
|
+
if (sub === "actionable")
|
|
376
|
+
return { kind: "task.actionable", ...(agent ? { agent } : {}) };
|
|
377
|
+
if (sub === "deps")
|
|
378
|
+
return { kind: "task.deps", ...(agent ? { agent } : {}) };
|
|
379
|
+
if (sub === "sessions")
|
|
380
|
+
return { kind: "task.sessions", ...(agent ? { agent } : {}) };
|
|
381
|
+
if (sub === "fix") {
|
|
382
|
+
// fix --safe | fix --all | fix <id> [--option N] | fix (dry-run)
|
|
383
|
+
if (rest.length === 0)
|
|
384
|
+
return { kind: "task.fix", mode: "dry-run", ...(agent ? { agent } : {}) };
|
|
385
|
+
const first = rest[0];
|
|
386
|
+
if (first === "--safe" || first === "--all") {
|
|
387
|
+
return { kind: "task.fix", mode: "safe", ...(agent ? { agent } : {}) };
|
|
388
|
+
}
|
|
389
|
+
// first arg is an issue ID (contains a colon, e.g. schema-missing-kind:one-shots/foo.md)
|
|
390
|
+
const issueId = first;
|
|
391
|
+
let option;
|
|
392
|
+
for (let i = 1; i < rest.length; i++) {
|
|
393
|
+
if (rest[i] === "--option" && rest[i + 1]) {
|
|
394
|
+
option = parseInt(rest[i + 1], 10);
|
|
395
|
+
i += 1;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
kind: "task.fix",
|
|
400
|
+
mode: "single",
|
|
401
|
+
issueId,
|
|
402
|
+
...(option !== undefined ? { option } : {}),
|
|
403
|
+
...(agent ? { agent } : {}),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
throw new Error(`Usage\n${usage()}`);
|
|
407
|
+
}
|
|
408
|
+
function parseAuthCommand(args) {
|
|
409
|
+
const first = args[0];
|
|
410
|
+
// Support both positional (`auth switch`) and flag (`auth --switch`) forms
|
|
411
|
+
if (first === "verify" || first === "switch" || first === "--verify" || first === "--switch") {
|
|
412
|
+
const subcommand = first.replace(/^--/, "");
|
|
413
|
+
const { agent, rest: afterAgent } = extractAgentFlag(args.slice(1));
|
|
414
|
+
const { facing, rest } = extractFacingFlag(afterAgent);
|
|
415
|
+
let provider;
|
|
416
|
+
/* v8 ignore start -- provider flag parsing: branches tested via CLI parsing tests @preserve */
|
|
417
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
418
|
+
if (rest[i] === "--provider") {
|
|
419
|
+
const value = rest[i + 1];
|
|
420
|
+
if (!isAgentProvider(value))
|
|
421
|
+
throw new Error(`Usage\n${usage()}`);
|
|
422
|
+
provider = value;
|
|
423
|
+
i += 1;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/* v8 ignore stop */
|
|
428
|
+
if (subcommand === "switch") {
|
|
429
|
+
if (!provider)
|
|
430
|
+
throw new Error(`auth switch requires --provider.\n${usage()}`);
|
|
431
|
+
return {
|
|
432
|
+
kind: "auth.switch",
|
|
433
|
+
...(agent ? { agent } : {}),
|
|
434
|
+
provider,
|
|
435
|
+
...(facing ? { facing } : {}),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
return {
|
|
439
|
+
kind: "auth.verify",
|
|
440
|
+
...(agent ? { agent } : {}),
|
|
441
|
+
...(provider ? { provider } : {}),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const { agent, rest } = extractAgentFlag(args);
|
|
445
|
+
let provider;
|
|
446
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
447
|
+
if (rest[i] === "--provider") {
|
|
448
|
+
const value = rest[i + 1];
|
|
449
|
+
if (!isAgentProvider(value))
|
|
450
|
+
throw new Error(`Usage\n${usage()}`);
|
|
451
|
+
provider = value;
|
|
452
|
+
i += 1;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
kind: "auth.run",
|
|
458
|
+
...(agent ? { agent } : {}),
|
|
459
|
+
...(provider ? { provider } : {}),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function isVaultUnlockStoreKind(value) {
|
|
463
|
+
return value === "auto" || value === "macos-keychain" || value === "windows-dpapi" || value === "linux-secret-service" || value === "plaintext-file";
|
|
464
|
+
}
|
|
465
|
+
function parseVaultCommand(args) {
|
|
466
|
+
const sub = args[0];
|
|
467
|
+
if (sub === "config")
|
|
468
|
+
return parseVaultConfigCommand(args.slice(1));
|
|
469
|
+
if (sub === "item")
|
|
470
|
+
return parseVaultItemCommand(args.slice(1));
|
|
471
|
+
if (sub === "ops")
|
|
472
|
+
return parseVaultOpsCommand(args.slice(1));
|
|
473
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
474
|
+
let email;
|
|
475
|
+
let serverUrl;
|
|
476
|
+
let store;
|
|
477
|
+
let generateUnlockSecret = false;
|
|
478
|
+
const sources = [];
|
|
479
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
480
|
+
const token = rest[i];
|
|
481
|
+
if (token === "--email") {
|
|
482
|
+
email = rest[i + 1];
|
|
483
|
+
i += 1;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (token === "--server") {
|
|
487
|
+
serverUrl = rest[i + 1];
|
|
488
|
+
i += 1;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
if (token === "--store") {
|
|
492
|
+
const value = rest[i + 1];
|
|
493
|
+
if (!isVaultUnlockStoreKind(value)) {
|
|
494
|
+
throw new Error("vault --store must be auto|macos-keychain|windows-dpapi|linux-secret-service|plaintext-file");
|
|
495
|
+
}
|
|
496
|
+
store = value;
|
|
497
|
+
i += 1;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (token === "--from") {
|
|
501
|
+
if (sub !== "recover") {
|
|
502
|
+
throw new Error("--from is only valid with `ouro vault recover`; use `ouro vault replace` when there is no JSON export to import.");
|
|
503
|
+
}
|
|
504
|
+
const value = rest[i + 1];
|
|
505
|
+
if (!value)
|
|
506
|
+
throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
|
|
507
|
+
sources.push(value);
|
|
508
|
+
i += 1;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (token === "--generate-unlock-secret") {
|
|
512
|
+
generateUnlockSecret = true;
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
|
|
516
|
+
}
|
|
517
|
+
if (sub !== "create" && sub !== "replace" && sub !== "recover" && sub !== "unlock" && sub !== "status") {
|
|
518
|
+
throw new Error("Usage: ouro vault create|replace|recover|unlock|status [--agent <name>]");
|
|
519
|
+
}
|
|
520
|
+
if (sub === "create") {
|
|
521
|
+
return {
|
|
522
|
+
kind: "vault.create",
|
|
523
|
+
...(agent ? { agent } : {}),
|
|
524
|
+
...(email ? { email } : {}),
|
|
525
|
+
...(serverUrl ? { serverUrl } : {}),
|
|
526
|
+
...(store ? { store } : {}),
|
|
527
|
+
...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
if (sub === "replace") {
|
|
531
|
+
return {
|
|
532
|
+
kind: "vault.replace",
|
|
533
|
+
...(agent ? { agent } : {}),
|
|
534
|
+
...(email ? { email } : {}),
|
|
535
|
+
...(serverUrl ? { serverUrl } : {}),
|
|
536
|
+
...(store ? { store } : {}),
|
|
537
|
+
...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
if (sub === "recover") {
|
|
541
|
+
if (sources.length === 0) {
|
|
542
|
+
throw new Error("Usage: ouro vault recover [--agent <name>] --from <json> [--from <json> ...]");
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
kind: "vault.recover",
|
|
546
|
+
...(agent ? { agent } : {}),
|
|
547
|
+
sources,
|
|
548
|
+
...(email ? { email } : {}),
|
|
549
|
+
...(serverUrl ? { serverUrl } : {}),
|
|
550
|
+
...(store ? { store } : {}),
|
|
551
|
+
...(generateUnlockSecret ? { generateUnlockSecret: true } : {}),
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
if (sub === "unlock") {
|
|
555
|
+
return { kind: "vault.unlock", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
|
|
556
|
+
}
|
|
557
|
+
return { kind: "vault.status", ...(agent ? { agent } : {}), ...(store ? { store } : {}) };
|
|
558
|
+
}
|
|
559
|
+
function parseVaultItemCommand(args) {
|
|
560
|
+
const action = args[0];
|
|
561
|
+
if (action !== "set" && action !== "status" && action !== "list") {
|
|
562
|
+
throw new Error("Usage: ouro vault item set|status|list [--agent <name>] --item <path>");
|
|
563
|
+
}
|
|
564
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
565
|
+
let item;
|
|
566
|
+
let prefix;
|
|
567
|
+
let template;
|
|
568
|
+
let note;
|
|
569
|
+
const secretFields = [];
|
|
570
|
+
const publicFields = [];
|
|
571
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
572
|
+
const token = rest[i];
|
|
573
|
+
if (token === "--item") {
|
|
574
|
+
item = (0, vault_items_1.normalizeVaultItemName)(rest[i + 1]);
|
|
575
|
+
i += 1;
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
if (token === "--prefix") {
|
|
579
|
+
const value = rest[i + 1]?.trim() ?? "";
|
|
580
|
+
if (!value || /[\r\n\t]/.test(value) || value.startsWith("/")) {
|
|
581
|
+
throw new Error("Vault item prefix must be non-empty, relative, and free of control characters.");
|
|
582
|
+
}
|
|
583
|
+
prefix = value;
|
|
584
|
+
i += 1;
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
if (token === "--template") {
|
|
588
|
+
const value = rest[i + 1];
|
|
589
|
+
if (!(0, vault_items_1.isVaultItemTemplate)(value)) {
|
|
590
|
+
throw new Error("vault item --template must be porkbun-api");
|
|
591
|
+
}
|
|
592
|
+
template = value;
|
|
593
|
+
i += 1;
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (token === "--secret-field") {
|
|
597
|
+
secretFields.push((0, vault_items_1.normalizeVaultItemFieldName)(rest[i + 1]));
|
|
598
|
+
i += 1;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (token === "--public-field") {
|
|
602
|
+
const value = rest[i + 1]?.trim() ?? "";
|
|
603
|
+
const separator = value.indexOf("=");
|
|
604
|
+
if (separator <= 0 || separator === value.length - 1) {
|
|
605
|
+
throw new Error("vault item --public-field must be key=value");
|
|
606
|
+
}
|
|
607
|
+
(0, vault_items_1.normalizeVaultItemFieldName)(value.slice(0, separator));
|
|
608
|
+
publicFields.push(value);
|
|
609
|
+
i += 1;
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
if (token === "--note") {
|
|
613
|
+
note = rest[i + 1] ?? "";
|
|
614
|
+
i += 1;
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
throw new Error(`Usage: ouro vault item ${action} [--agent <name>] --item <path>`);
|
|
618
|
+
}
|
|
619
|
+
if (action === "list") {
|
|
620
|
+
return { kind: "vault.item.list", ...(agent ? { agent } : {}), ...(prefix ? { prefix } : {}) };
|
|
621
|
+
}
|
|
622
|
+
if (!item)
|
|
623
|
+
throw new Error(`Usage: ouro vault item ${action} [--agent <name>] --item <path>`);
|
|
624
|
+
if (action === "status") {
|
|
625
|
+
return { kind: "vault.item.status", ...(agent ? { agent } : {}), item };
|
|
626
|
+
}
|
|
627
|
+
if (!template && secretFields.length === 0) {
|
|
628
|
+
throw new Error("ouro vault item set requires --secret-field or --template");
|
|
629
|
+
}
|
|
630
|
+
return {
|
|
631
|
+
kind: "vault.item.set",
|
|
632
|
+
...(agent ? { agent } : {}),
|
|
633
|
+
item,
|
|
634
|
+
...(template ? { template } : {}),
|
|
635
|
+
...(secretFields.length > 0 ? { secretFields } : {}),
|
|
636
|
+
...(publicFields.length > 0 ? { publicFields } : {}),
|
|
637
|
+
...(note !== undefined ? { note } : {}),
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function parseVaultOpsCommand(args) {
|
|
641
|
+
const provider = args[0];
|
|
642
|
+
const action = args[1];
|
|
643
|
+
if (provider !== "porkbun") {
|
|
644
|
+
throw new Error("Usage: ouro vault ops porkbun set|status [--agent <name>] [--account <account>]");
|
|
645
|
+
}
|
|
646
|
+
if (action !== "set" && action !== "status") {
|
|
647
|
+
throw new Error("Usage: ouro vault ops porkbun set|status [--agent <name>] [--account <account>]");
|
|
648
|
+
}
|
|
649
|
+
const { agent, rest } = extractAgentFlag(args.slice(2));
|
|
650
|
+
let account;
|
|
651
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
652
|
+
const token = rest[i];
|
|
653
|
+
if (token === "--account") {
|
|
654
|
+
account = (0, vault_items_1.normalizePorkbunOpsAccount)(rest[i + 1]);
|
|
655
|
+
i += 1;
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
throw new Error(`Usage: ouro vault ops porkbun ${action} [--agent <name>] [--account <account>]`);
|
|
659
|
+
}
|
|
660
|
+
if (action === "set") {
|
|
661
|
+
if (!account)
|
|
662
|
+
throw new Error("Usage: ouro vault ops porkbun set [--agent <name>] --account <account>");
|
|
663
|
+
return {
|
|
664
|
+
kind: "vault.item.set",
|
|
665
|
+
...(agent ? { agent } : {}),
|
|
666
|
+
item: (0, vault_items_1.porkbunOpsCredentialItemName)(account),
|
|
667
|
+
template: "porkbun-api",
|
|
668
|
+
compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
if (account) {
|
|
672
|
+
return {
|
|
673
|
+
kind: "vault.item.status",
|
|
674
|
+
...(agent ? { agent } : {}),
|
|
675
|
+
item: (0, vault_items_1.porkbunOpsCredentialItemName)(account),
|
|
676
|
+
compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
kind: "vault.item.list",
|
|
681
|
+
...(agent ? { agent } : {}),
|
|
682
|
+
prefix: vault_items_1.PORKBUN_OPS_CREDENTIAL_PREFIX,
|
|
683
|
+
compatibilityAlias: vault_items_1.PORKBUN_OPS_COMPATIBILITY_ALIAS,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
function isDnsWorkflowAction(value) {
|
|
687
|
+
return value === "backup" || value === "plan" || value === "apply" || value === "verify" || value === "rollback" || value === "certificate";
|
|
688
|
+
}
|
|
689
|
+
function normalizeWorkflowPath(value, label) {
|
|
690
|
+
const trimmed = value?.trim() ?? "";
|
|
691
|
+
if (!trimmed || /[\r\n\t]/.test(trimmed)) {
|
|
692
|
+
throw new Error(`${label} must be a non-empty path without control characters.`);
|
|
693
|
+
}
|
|
694
|
+
return trimmed;
|
|
695
|
+
}
|
|
696
|
+
function parseDnsCommand(args) {
|
|
697
|
+
const action = args[0];
|
|
698
|
+
if (!isDnsWorkflowAction(action)) {
|
|
699
|
+
throw new Error("Usage: ouro dns backup|plan|apply|verify|rollback|certificate [--agent <name>] --binding <path>");
|
|
700
|
+
}
|
|
701
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
702
|
+
let bindingPath;
|
|
703
|
+
let outputPath;
|
|
704
|
+
let backupPath;
|
|
705
|
+
let yes = false;
|
|
706
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
707
|
+
const token = rest[i];
|
|
708
|
+
if (token === "--binding") {
|
|
709
|
+
bindingPath = normalizeWorkflowPath(rest[i + 1], "dns --binding");
|
|
710
|
+
i += 1;
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
if (token === "--output") {
|
|
714
|
+
outputPath = normalizeWorkflowPath(rest[i + 1], "dns --output");
|
|
715
|
+
i += 1;
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (token === "--backup") {
|
|
719
|
+
backupPath = normalizeWorkflowPath(rest[i + 1], "dns --backup");
|
|
720
|
+
i += 1;
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if (token === "--yes") {
|
|
724
|
+
yes = true;
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (token === "--credential-item") {
|
|
728
|
+
throw new Error("credential item belongs in the DNS workflow binding");
|
|
729
|
+
}
|
|
730
|
+
throw new Error(`Usage: ouro dns ${action} [--agent <name>] --binding <path>`);
|
|
731
|
+
}
|
|
732
|
+
if (!bindingPath) {
|
|
733
|
+
throw new Error(`Usage: ouro dns ${action} [--agent <name>] --binding <path>`);
|
|
734
|
+
}
|
|
735
|
+
if (action === "apply" && !yes) {
|
|
736
|
+
throw new Error("dns apply requires --yes after a reviewed dry-run");
|
|
737
|
+
}
|
|
738
|
+
if (action === "rollback") {
|
|
739
|
+
if (!backupPath)
|
|
740
|
+
throw new Error("dns rollback requires --backup <path>");
|
|
741
|
+
if (!yes)
|
|
742
|
+
throw new Error("dns rollback requires --yes after choosing a backup");
|
|
743
|
+
}
|
|
744
|
+
return {
|
|
745
|
+
kind: "dns.workflow",
|
|
746
|
+
action,
|
|
747
|
+
...(agent ? { agent } : {}),
|
|
748
|
+
bindingPath,
|
|
749
|
+
...(outputPath ? { outputPath } : {}),
|
|
750
|
+
...(backupPath ? { backupPath } : {}),
|
|
751
|
+
...(yes ? { yes: true } : {}),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
function parseVaultConfigCommand(args) {
|
|
755
|
+
const sub = args[0];
|
|
756
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
757
|
+
let key;
|
|
758
|
+
let value;
|
|
759
|
+
let scope;
|
|
760
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
761
|
+
const token = rest[i];
|
|
762
|
+
if (token === "--key") {
|
|
763
|
+
key = rest[i + 1];
|
|
764
|
+
i += 1;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (token === "--value") {
|
|
768
|
+
value = rest[i + 1];
|
|
769
|
+
i += 1;
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (token === "--scope") {
|
|
773
|
+
const raw = rest[i + 1];
|
|
774
|
+
if (raw !== "agent" && raw !== "machine" && raw !== "all") {
|
|
775
|
+
throw new Error("vault config --scope must be agent, machine, or all");
|
|
776
|
+
}
|
|
777
|
+
scope = raw;
|
|
778
|
+
i += 1;
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
|
|
782
|
+
}
|
|
783
|
+
if (sub !== "set" && sub !== "status") {
|
|
784
|
+
throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>] OR ouro vault config status [--agent <name>]");
|
|
785
|
+
}
|
|
786
|
+
if (sub === "status") {
|
|
787
|
+
if (key || value) {
|
|
788
|
+
throw new Error("Usage: ouro vault config status [--agent <name>]");
|
|
789
|
+
}
|
|
790
|
+
return { kind: "vault.config.status", ...(agent ? { agent } : {}), ...(scope ? { scope } : {}) };
|
|
791
|
+
}
|
|
792
|
+
if (scope === "all")
|
|
793
|
+
throw new Error("vault config --scope all is only valid for status");
|
|
794
|
+
if (!key) {
|
|
795
|
+
throw new Error("Usage: ouro vault config set [--agent <name>] --key <path> [--value <value>]");
|
|
796
|
+
}
|
|
797
|
+
return { kind: "vault.config.set", ...(agent ? { agent } : {}), key, ...(value !== undefined ? { value } : {}), ...(scope ? { scope } : {}) };
|
|
798
|
+
}
|
|
799
|
+
function normalizeConnectTarget(value) {
|
|
800
|
+
if (!value)
|
|
801
|
+
return undefined;
|
|
802
|
+
if (value === "providers" || value === "provider" || value === "auth")
|
|
803
|
+
return "providers";
|
|
804
|
+
if (value === "perplexity" || value === "perplexity-search")
|
|
805
|
+
return "perplexity";
|
|
806
|
+
if (value === "embeddings" || value === "embedding" || value === "memory" || value === "note-search" || value === "notes")
|
|
807
|
+
return "embeddings";
|
|
808
|
+
if (value === "teams" || value === "msteams" || value === "microsoft-teams")
|
|
809
|
+
return "teams";
|
|
810
|
+
if (value === "bluebubbles" || value === "imessage" || value === "messages")
|
|
811
|
+
return "bluebubbles";
|
|
812
|
+
if (value === "mail" || value === "email" || value === "mailroom")
|
|
813
|
+
return "mail";
|
|
814
|
+
throw new Error("Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>]");
|
|
815
|
+
}
|
|
816
|
+
function extractMailSourceFlags(args, usageText) {
|
|
817
|
+
const rest = [];
|
|
818
|
+
let ownerEmail;
|
|
819
|
+
let source;
|
|
820
|
+
let noDelegatedSource = false;
|
|
821
|
+
let rotateMissingMailKeys = false;
|
|
822
|
+
let hasMailSourceFlags = false;
|
|
823
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
824
|
+
const token = args[i];
|
|
825
|
+
if (token === "--owner-email") {
|
|
826
|
+
if (args[i + 1] === undefined)
|
|
827
|
+
throw new Error(usageText);
|
|
828
|
+
ownerEmail = args[++i];
|
|
829
|
+
hasMailSourceFlags = true;
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
if (token === "--source") {
|
|
833
|
+
if (args[i + 1] === undefined)
|
|
834
|
+
throw new Error(usageText);
|
|
835
|
+
source = args[++i];
|
|
836
|
+
hasMailSourceFlags = true;
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
if (token === "--no-delegated-source") {
|
|
840
|
+
noDelegatedSource = true;
|
|
841
|
+
hasMailSourceFlags = true;
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
if (token === "--rotate-missing-mail-keys") {
|
|
845
|
+
rotateMissingMailKeys = true;
|
|
846
|
+
hasMailSourceFlags = true;
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
rest.push(token);
|
|
850
|
+
}
|
|
851
|
+
if (noDelegatedSource && (ownerEmail !== undefined || source !== undefined)) {
|
|
852
|
+
throw new Error("--no-delegated-source cannot be combined with --owner-email or --source");
|
|
853
|
+
}
|
|
854
|
+
if (source !== undefined && ownerEmail === undefined) {
|
|
855
|
+
throw new Error("--source requires --owner-email");
|
|
856
|
+
}
|
|
857
|
+
return {
|
|
858
|
+
rest,
|
|
859
|
+
...(ownerEmail !== undefined ? { ownerEmail } : {}),
|
|
860
|
+
...(source !== undefined ? { source } : {}),
|
|
861
|
+
...(noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
862
|
+
...(rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
863
|
+
hasMailSourceFlags,
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
function parseConnectCommand(args) {
|
|
867
|
+
const usageText = "Usage: ouro connect [providers|perplexity|embeddings|teams|bluebubbles|mail] [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
|
|
868
|
+
const { agent, rest: afterAgent } = extractAgentFlag(args);
|
|
869
|
+
const mailFlags = extractMailSourceFlags(afterAgent, usageText);
|
|
870
|
+
if (mailFlags.rest.length > 1)
|
|
871
|
+
throw new Error(usageText);
|
|
872
|
+
const target = normalizeConnectTarget(mailFlags.rest[0]);
|
|
873
|
+
if (mailFlags.hasMailSourceFlags && target !== "mail") {
|
|
874
|
+
throw new Error("Mail source flags require `ouro connect mail`.");
|
|
875
|
+
}
|
|
876
|
+
return {
|
|
877
|
+
kind: "connect",
|
|
878
|
+
...(agent ? { agent } : {}),
|
|
879
|
+
...(target ? { target } : {}),
|
|
880
|
+
...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
|
|
881
|
+
...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
|
|
882
|
+
...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
883
|
+
...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function parseMailCommand(args) {
|
|
887
|
+
const [sub, ...subArgs] = args;
|
|
888
|
+
const usageText = "Usage: ouro mail import-mbox (--file <path>|--discover) [--owner-email <email>] [--source <label>] [--agent <name>] [--foreground]\n ouro mail backfill-indexes [--agent <name>] [--foreground]";
|
|
889
|
+
if (sub === "backfill-indexes") {
|
|
890
|
+
const { agent, rest } = extractAgentFlag(subArgs);
|
|
891
|
+
let foreground = false;
|
|
892
|
+
let operationId;
|
|
893
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
894
|
+
const token = rest[i];
|
|
895
|
+
if (token === "--foreground") {
|
|
896
|
+
foreground = true;
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (token === "--operation-id" && rest[i + 1]) {
|
|
900
|
+
operationId = rest[++i];
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
throw new Error(usageText);
|
|
904
|
+
}
|
|
905
|
+
return {
|
|
906
|
+
kind: "mail.backfill-indexes",
|
|
907
|
+
...(agent ? { agent } : {}),
|
|
908
|
+
...(foreground ? { foreground: true } : {}),
|
|
909
|
+
...(operationId ? { operationId } : {}),
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
if (sub !== "import-mbox") {
|
|
913
|
+
throw new Error(usageText);
|
|
914
|
+
}
|
|
915
|
+
const { agent, rest } = extractAgentFlag(subArgs);
|
|
916
|
+
let filePath;
|
|
917
|
+
let discover = false;
|
|
918
|
+
let ownerEmail;
|
|
919
|
+
let source;
|
|
920
|
+
let foreground = false;
|
|
921
|
+
let operationId;
|
|
922
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
923
|
+
const token = rest[i];
|
|
924
|
+
if (token === "--file" && rest[i + 1]) {
|
|
925
|
+
filePath = rest[++i];
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
if (token === "--discover") {
|
|
929
|
+
discover = true;
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
if (token === "--owner-email" && rest[i + 1]) {
|
|
933
|
+
ownerEmail = rest[++i];
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (token === "--source" && rest[i + 1]) {
|
|
937
|
+
source = rest[++i];
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
if (token === "--foreground") {
|
|
941
|
+
foreground = true;
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
if (token === "--operation-id" && rest[i + 1]) {
|
|
945
|
+
operationId = rest[++i];
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
throw new Error(usageText);
|
|
949
|
+
}
|
|
950
|
+
if ((filePath ? 1 : 0) + (discover ? 1 : 0) !== 1) {
|
|
951
|
+
throw new Error(usageText);
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
kind: "mail.import-mbox",
|
|
955
|
+
...(agent ? { agent } : {}),
|
|
956
|
+
...(filePath ? { filePath } : {}),
|
|
957
|
+
...(discover ? { discover: true } : {}),
|
|
958
|
+
...(ownerEmail ? { ownerEmail } : {}),
|
|
959
|
+
...(source ? { source } : {}),
|
|
960
|
+
...(foreground ? { foreground: true } : {}),
|
|
961
|
+
...(operationId ? { operationId } : {}),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function parseAccountCommand(args) {
|
|
965
|
+
const [sub, ...subArgs] = args;
|
|
966
|
+
const usageText = "Usage: ouro account ensure [--agent <name>] [--owner-email <email> --source <label>|--no-delegated-source] [--rotate-missing-mail-keys]";
|
|
967
|
+
if (sub !== "ensure") {
|
|
968
|
+
throw new Error(usageText);
|
|
969
|
+
}
|
|
970
|
+
const { agent, rest: afterAgent } = extractAgentFlag(subArgs);
|
|
971
|
+
const mailFlags = extractMailSourceFlags(afterAgent, usageText);
|
|
972
|
+
if (mailFlags.rest.length > 0)
|
|
973
|
+
throw new Error(usageText);
|
|
974
|
+
return {
|
|
975
|
+
kind: "account.ensure",
|
|
976
|
+
...(agent ? { agent } : {}),
|
|
977
|
+
...(mailFlags.ownerEmail !== undefined ? { ownerEmail: mailFlags.ownerEmail } : {}),
|
|
978
|
+
...(mailFlags.source !== undefined ? { source: mailFlags.source } : {}),
|
|
979
|
+
...(mailFlags.noDelegatedSource ? { noDelegatedSource: true } : {}),
|
|
980
|
+
...(mailFlags.rotateMissingMailKeys ? { rotateMissingMailKeys: true } : {}),
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
function parseProviderUseCommand(args) {
|
|
984
|
+
const { agent, rest: afterAgent } = extractAgentFlag(args);
|
|
985
|
+
const { facing, rest: afterFacing } = extractFacingFlag(afterAgent);
|
|
986
|
+
const { lane, rest } = extractLaneFlag(afterFacing);
|
|
987
|
+
let provider;
|
|
988
|
+
let model;
|
|
989
|
+
let force = false;
|
|
990
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
991
|
+
const token = rest[i];
|
|
992
|
+
if (token === "--provider") {
|
|
993
|
+
const value = rest[i + 1];
|
|
994
|
+
if (!isAgentProvider(value))
|
|
995
|
+
throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model>");
|
|
996
|
+
provider = value;
|
|
997
|
+
i += 1;
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
if (token === "--model") {
|
|
1001
|
+
model = rest[i + 1];
|
|
1002
|
+
i += 1;
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (token === "--force") {
|
|
1006
|
+
force = true;
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
|
|
1010
|
+
}
|
|
1011
|
+
const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
|
|
1012
|
+
if (!resolvedLane || !provider || !model) {
|
|
1013
|
+
throw new Error("Usage: ouro use [--agent <name>] --lane outward|inner --provider <provider> --model <model> [--force]");
|
|
1014
|
+
}
|
|
1015
|
+
return {
|
|
1016
|
+
kind: "provider.use",
|
|
1017
|
+
...(agent ? { agent } : {}),
|
|
1018
|
+
lane: resolvedLane,
|
|
1019
|
+
provider,
|
|
1020
|
+
model,
|
|
1021
|
+
...(force ? { force: true } : {}),
|
|
1022
|
+
...(facing ? { legacyFacing: facing } : {}),
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function parseProviderCheckCommand(args) {
|
|
1026
|
+
const { agent, rest: afterAgent } = extractAgentFlag(args);
|
|
1027
|
+
const { facing, rest: afterFacing } = extractFacingFlag(afterAgent);
|
|
1028
|
+
const { lane, rest } = extractLaneFlag(afterFacing);
|
|
1029
|
+
const resolvedLane = lane ?? (facing ? facingToProviderLane(facing) : undefined);
|
|
1030
|
+
if (!resolvedLane || rest.length > 0) {
|
|
1031
|
+
throw new Error("Usage: ouro check [--agent <name>] --lane outward|inner");
|
|
1032
|
+
}
|
|
1033
|
+
return {
|
|
1034
|
+
kind: "provider.check",
|
|
1035
|
+
...(agent ? { agent } : {}),
|
|
1036
|
+
lane: resolvedLane,
|
|
1037
|
+
...(facing ? { legacyFacing: facing } : {}),
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function parseProviderCommand(args) {
|
|
1041
|
+
const sub = args[0];
|
|
1042
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
1043
|
+
if (sub === "refresh" && rest.length === 0) {
|
|
1044
|
+
return { kind: "provider.refresh", ...(agent ? { agent } : {}) };
|
|
1045
|
+
}
|
|
1046
|
+
throw new Error("Usage: ouro provider refresh [--agent <name>]");
|
|
1047
|
+
}
|
|
1048
|
+
function parseReminderCommand(args) {
|
|
1049
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1050
|
+
const [sub, ...rest] = cleaned;
|
|
1051
|
+
if (!sub)
|
|
1052
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1053
|
+
if (sub === "create") {
|
|
1054
|
+
const title = rest[0];
|
|
1055
|
+
if (!title)
|
|
1056
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1057
|
+
let body;
|
|
1058
|
+
let scheduledAt;
|
|
1059
|
+
let cadence;
|
|
1060
|
+
let category;
|
|
1061
|
+
let requester;
|
|
1062
|
+
for (let i = 1; i < rest.length; i++) {
|
|
1063
|
+
if (rest[i] === "--body" && rest[i + 1]) {
|
|
1064
|
+
body = rest[i + 1];
|
|
1065
|
+
i += 1;
|
|
1066
|
+
}
|
|
1067
|
+
else if (rest[i] === "--at" && rest[i + 1]) {
|
|
1068
|
+
scheduledAt = rest[i + 1];
|
|
1069
|
+
i += 1;
|
|
1070
|
+
}
|
|
1071
|
+
else if (rest[i] === "--cadence" && rest[i + 1]) {
|
|
1072
|
+
cadence = rest[i + 1];
|
|
1073
|
+
i += 1;
|
|
1074
|
+
}
|
|
1075
|
+
else if (rest[i] === "--category" && rest[i + 1]) {
|
|
1076
|
+
category = rest[i + 1];
|
|
1077
|
+
i += 1;
|
|
1078
|
+
}
|
|
1079
|
+
else if (rest[i] === "--requester" && rest[i + 1]) {
|
|
1080
|
+
requester = rest[i + 1];
|
|
1081
|
+
i += 1;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
if (!body)
|
|
1085
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1086
|
+
if (!scheduledAt && !cadence)
|
|
1087
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1088
|
+
return {
|
|
1089
|
+
kind: "reminder.create",
|
|
1090
|
+
title,
|
|
1091
|
+
body,
|
|
1092
|
+
...(scheduledAt ? { scheduledAt } : {}),
|
|
1093
|
+
...(cadence ? { cadence } : {}),
|
|
1094
|
+
...(category ? { category } : {}),
|
|
1095
|
+
...(requester ? { requester } : {}),
|
|
1096
|
+
...(agent ? { agent } : {}),
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1100
|
+
}
|
|
1101
|
+
function parseSessionCommand(args) {
|
|
1102
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1103
|
+
const [sub] = cleaned;
|
|
1104
|
+
if (!sub)
|
|
1105
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1106
|
+
if (sub === "list")
|
|
1107
|
+
return { kind: "session.list", ...(agent ? { agent } : {}) };
|
|
1108
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1109
|
+
}
|
|
1110
|
+
function parseAttentionCommand(args) {
|
|
1111
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1112
|
+
const sub = cleaned[0];
|
|
1113
|
+
if (sub === "show" && cleaned[1]) {
|
|
1114
|
+
return { kind: "attention.show", id: cleaned[1], ...(agent ? { agent } : {}) };
|
|
1115
|
+
}
|
|
1116
|
+
if (sub === "history") {
|
|
1117
|
+
return { kind: "attention.history", ...(agent ? { agent } : {}) };
|
|
1118
|
+
}
|
|
1119
|
+
return { kind: "attention.list", ...(agent ? { agent } : {}) };
|
|
1120
|
+
}
|
|
1121
|
+
function parseThoughtsCommand(args) {
|
|
1122
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1123
|
+
let last;
|
|
1124
|
+
let json = false;
|
|
1125
|
+
let follow = false;
|
|
1126
|
+
for (let i = 0; i < cleaned.length; i++) {
|
|
1127
|
+
if (cleaned[i] === "--last" && i + 1 < cleaned.length) {
|
|
1128
|
+
last = Number.parseInt(cleaned[i + 1], 10);
|
|
1129
|
+
i++;
|
|
1130
|
+
}
|
|
1131
|
+
if (cleaned[i] === "--json")
|
|
1132
|
+
json = true;
|
|
1133
|
+
if (cleaned[i] === "--follow" || cleaned[i] === "-f")
|
|
1134
|
+
follow = true;
|
|
1135
|
+
}
|
|
1136
|
+
return { kind: "thoughts", ...(agent ? { agent } : {}), ...(last ? { last } : {}), ...(json ? { json } : {}), ...(follow ? { follow } : {}) };
|
|
1137
|
+
}
|
|
1138
|
+
function parseFriendCommand(args) {
|
|
1139
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1140
|
+
const [sub, ...rest] = cleaned;
|
|
1141
|
+
if (!sub)
|
|
1142
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1143
|
+
if (sub === "list")
|
|
1144
|
+
return { kind: "friend.list", ...(agent ? { agent } : {}) };
|
|
1145
|
+
if (sub === "show") {
|
|
1146
|
+
const friendId = rest[0];
|
|
1147
|
+
if (!friendId)
|
|
1148
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1149
|
+
return { kind: "friend.show", friendId, ...(agent ? { agent } : {}) };
|
|
1150
|
+
}
|
|
1151
|
+
if (sub === "create") {
|
|
1152
|
+
let name;
|
|
1153
|
+
let trustLevel;
|
|
1154
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1155
|
+
if (rest[i] === "--name" && rest[i + 1]) {
|
|
1156
|
+
name = rest[i + 1];
|
|
1157
|
+
i += 1;
|
|
1158
|
+
}
|
|
1159
|
+
else if (rest[i] === "--trust" && rest[i + 1]) {
|
|
1160
|
+
trustLevel = rest[i + 1];
|
|
1161
|
+
i += 1;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
if (!name)
|
|
1165
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1166
|
+
return {
|
|
1167
|
+
kind: "friend.create",
|
|
1168
|
+
name,
|
|
1169
|
+
...(trustLevel ? { trustLevel } : {}),
|
|
1170
|
+
...(agent ? { agent } : {}),
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
if (sub === "update") {
|
|
1174
|
+
const friendId = rest[0];
|
|
1175
|
+
if (!friendId)
|
|
1176
|
+
throw new Error(`Usage: ouro friend update <id> --trust <level>`);
|
|
1177
|
+
let trustLevel;
|
|
1178
|
+
/* v8 ignore start -- flag parsing loop: tested via CLI parsing tests @preserve */
|
|
1179
|
+
for (let i = 1; i < rest.length; i++) {
|
|
1180
|
+
if (rest[i] === "--trust" && rest[i + 1]) {
|
|
1181
|
+
trustLevel = rest[i + 1];
|
|
1182
|
+
i += 1;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
/* v8 ignore stop */
|
|
1186
|
+
const VALID_TRUST_LEVELS = new Set(["stranger", "acquaintance", "friend", "family"]);
|
|
1187
|
+
if (!trustLevel || !VALID_TRUST_LEVELS.has(trustLevel)) {
|
|
1188
|
+
throw new Error(`Usage: ouro friend update <id> --trust <stranger|acquaintance|friend|family>`);
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
kind: "friend.update",
|
|
1192
|
+
friendId,
|
|
1193
|
+
trustLevel: trustLevel,
|
|
1194
|
+
...(agent ? { agent } : {}),
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
if (sub === "link")
|
|
1198
|
+
return parseLinkCommand(rest, "friend.link");
|
|
1199
|
+
if (sub === "unlink")
|
|
1200
|
+
return parseLinkCommand(rest, "friend.unlink");
|
|
1201
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1202
|
+
}
|
|
1203
|
+
function parseConfigCommand(args) {
|
|
1204
|
+
const { agent, rest: afterAgent } = extractAgentFlag(args);
|
|
1205
|
+
const { facing, rest: cleaned } = extractFacingFlag(afterAgent);
|
|
1206
|
+
const [sub, ...rest] = cleaned;
|
|
1207
|
+
if (!sub)
|
|
1208
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1209
|
+
if (sub === "model") {
|
|
1210
|
+
const modelName = rest[0];
|
|
1211
|
+
if (!modelName)
|
|
1212
|
+
throw new Error("Usage: ouro config model [--agent <name>] <model-name>");
|
|
1213
|
+
return {
|
|
1214
|
+
kind: "config.model",
|
|
1215
|
+
...(agent ? { agent } : {}),
|
|
1216
|
+
modelName,
|
|
1217
|
+
...(facing ? { facing } : {}),
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
if (sub === "models") {
|
|
1221
|
+
return { kind: "config.models", ...(agent ? { agent } : {}) };
|
|
1222
|
+
}
|
|
1223
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1224
|
+
}
|
|
1225
|
+
function parseMcpCommand(args) {
|
|
1226
|
+
const { agent, rest: cleaned } = extractAgentFlag(args);
|
|
1227
|
+
const [sub, ...rest] = cleaned;
|
|
1228
|
+
if (!sub)
|
|
1229
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1230
|
+
if (sub === "list")
|
|
1231
|
+
return { kind: "mcp.list" };
|
|
1232
|
+
if (sub === "call") {
|
|
1233
|
+
const server = rest[0];
|
|
1234
|
+
const tool = rest[1];
|
|
1235
|
+
if (!server || !tool)
|
|
1236
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1237
|
+
const argsIdx = rest.indexOf("--args");
|
|
1238
|
+
const mcpArgs = argsIdx !== -1 && rest[argsIdx + 1] ? rest[argsIdx + 1] : undefined;
|
|
1239
|
+
return { kind: "mcp.call", server, tool, ...(mcpArgs ? { args: mcpArgs } : {}) };
|
|
1240
|
+
}
|
|
1241
|
+
if (sub === "canary") {
|
|
1242
|
+
let socketOverride;
|
|
1243
|
+
let json = false;
|
|
1244
|
+
const requiredSenses = [];
|
|
1245
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1246
|
+
if (rest[i] === "--socket" && rest[i + 1]) {
|
|
1247
|
+
socketOverride = rest[++i];
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
if (rest[i] === "--require-sense" && rest[i + 1]) {
|
|
1251
|
+
requiredSenses.push(rest[++i]);
|
|
1252
|
+
continue;
|
|
1253
|
+
}
|
|
1254
|
+
if (rest[i] === "--json") {
|
|
1255
|
+
json = true;
|
|
1256
|
+
continue;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
if (!agent)
|
|
1260
|
+
throw new Error("mcp canary requires --agent <name>");
|
|
1261
|
+
return {
|
|
1262
|
+
kind: "mcp.canary",
|
|
1263
|
+
agent,
|
|
1264
|
+
...(socketOverride ? { socketOverride } : {}),
|
|
1265
|
+
...(requiredSenses.length > 0 ? { requiredSenses } : {}),
|
|
1266
|
+
...(json ? { json: true } : {}),
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1270
|
+
}
|
|
1271
|
+
function inferAgentNameFromRemote(remote) {
|
|
1272
|
+
// Remove trailing slash
|
|
1273
|
+
let name = remote.replace(/\/+$/, "");
|
|
1274
|
+
// Handle SSH URLs (git@host:user/repo) — extract after last / or :
|
|
1275
|
+
const lastSlash = name.lastIndexOf("/");
|
|
1276
|
+
const lastColon = name.lastIndexOf(":");
|
|
1277
|
+
const lastSep = Math.max(lastSlash, lastColon);
|
|
1278
|
+
if (lastSep !== -1) {
|
|
1279
|
+
name = name.slice(lastSep + 1);
|
|
1280
|
+
}
|
|
1281
|
+
// Strip .git suffix
|
|
1282
|
+
name = name.replace(/\.git$/, "");
|
|
1283
|
+
// Strip .ouro suffix
|
|
1284
|
+
name = name.replace(/\.ouro$/, "");
|
|
1285
|
+
return name;
|
|
1286
|
+
}
|
|
1287
|
+
function parseCloneCommand(args) {
|
|
1288
|
+
let remote;
|
|
1289
|
+
let agent;
|
|
1290
|
+
for (let i = 0; i < args.length; i++) {
|
|
1291
|
+
if (args[i] === "--agent" && args[i + 1]) {
|
|
1292
|
+
agent = args[++i];
|
|
1293
|
+
continue;
|
|
1294
|
+
}
|
|
1295
|
+
if (!remote) {
|
|
1296
|
+
remote = args[i];
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (!remote) {
|
|
1300
|
+
throw new Error("clone requires a remote URL.\nUsage: ouro clone <remote> [--agent <name>]");
|
|
1301
|
+
}
|
|
1302
|
+
return agent
|
|
1303
|
+
? { kind: "clone", remote, agent }
|
|
1304
|
+
: { kind: "clone", remote };
|
|
1305
|
+
}
|
|
1306
|
+
function parseMcpServeCommand(args) {
|
|
1307
|
+
let agent;
|
|
1308
|
+
let friendId;
|
|
1309
|
+
let socketOverride;
|
|
1310
|
+
for (let i = 0; i < args.length; i++) {
|
|
1311
|
+
if (args[i] === "--agent" && args[i + 1]) {
|
|
1312
|
+
agent = args[++i];
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
if (args[i] === "--friend" && args[i + 1]) {
|
|
1316
|
+
friendId = args[++i];
|
|
1317
|
+
continue;
|
|
1318
|
+
}
|
|
1319
|
+
if (args[i] === "--socket" && args[i + 1]) {
|
|
1320
|
+
socketOverride = args[++i];
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
if (!agent)
|
|
1325
|
+
throw new Error("mcp-serve requires --agent <name>");
|
|
1326
|
+
return { kind: "mcp-serve", agent, ...(friendId ? { friendId } : {}), ...(socketOverride ? { socketOverride } : {}) };
|
|
1327
|
+
}
|
|
1328
|
+
function parseSetupCommand(args) {
|
|
1329
|
+
let tool;
|
|
1330
|
+
let agent;
|
|
1331
|
+
for (let i = 0; i < args.length; i++) {
|
|
1332
|
+
if (args[i] === "--tool" && args[i + 1]) {
|
|
1333
|
+
tool = args[++i];
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
if (args[i] === "--agent" && args[i + 1]) {
|
|
1337
|
+
agent = args[++i];
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (args.includes("--agent") && !agent)
|
|
1342
|
+
throw new Error("setup requires --agent <name>");
|
|
1343
|
+
if (!tool)
|
|
1344
|
+
throw new Error("setup requires --tool (claude-code | codex)");
|
|
1345
|
+
if (tool !== "claude-code" && tool !== "codex")
|
|
1346
|
+
throw new Error(`Unknown tool: ${tool}. Supported: claude-code, codex`);
|
|
1347
|
+
return { kind: "setup", tool, ...(agent ? { agent } : {}) };
|
|
1348
|
+
}
|
|
1349
|
+
function parseBlueBubblesCommand(args) {
|
|
1350
|
+
const subcommand = args[0];
|
|
1351
|
+
if (subcommand !== "replay") {
|
|
1352
|
+
throw new Error(`Usage\n${usage()}`);
|
|
1353
|
+
}
|
|
1354
|
+
let agent;
|
|
1355
|
+
let messageGuid;
|
|
1356
|
+
let eventType = "new-message";
|
|
1357
|
+
let json = false;
|
|
1358
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
1359
|
+
if (args[i] === "--agent" && args[i + 1]) {
|
|
1360
|
+
agent = args[++i];
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (args[i] === "--message-guid" && args[i + 1]) {
|
|
1364
|
+
messageGuid = args[++i];
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (args[i] === "--event-type" && args[i + 1]) {
|
|
1368
|
+
const candidate = args[++i];
|
|
1369
|
+
if (candidate !== "new-message" && candidate !== "updated-message") {
|
|
1370
|
+
throw new Error("bluebubbles replay --event-type must be new-message or updated-message");
|
|
1371
|
+
}
|
|
1372
|
+
eventType = candidate;
|
|
1373
|
+
continue;
|
|
1374
|
+
}
|
|
1375
|
+
if (args[i] === "--json") {
|
|
1376
|
+
json = true;
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
if (!messageGuid)
|
|
1381
|
+
throw new Error("bluebubbles replay requires --message-guid <guid>");
|
|
1382
|
+
return {
|
|
1383
|
+
kind: "bluebubbles.replay",
|
|
1384
|
+
...(agent ? { agent } : {}),
|
|
1385
|
+
messageGuid,
|
|
1386
|
+
eventType,
|
|
1387
|
+
...(json ? { json: true } : {}),
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
// ── Main dispatch ──
|
|
1391
|
+
function parseOuroCommand(args) {
|
|
1392
|
+
const [head, second] = args;
|
|
1393
|
+
if (!head)
|
|
1394
|
+
return { kind: "daemon.up" };
|
|
1395
|
+
// ── help command ──
|
|
1396
|
+
if (head === "help") {
|
|
1397
|
+
const command = helpCommandName(args.slice(1));
|
|
1398
|
+
return command ? { kind: "help", command } : { kind: "help" };
|
|
1399
|
+
}
|
|
1400
|
+
// ── per-command --help ──
|
|
1401
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
1402
|
+
const command = helpCommandName(args);
|
|
1403
|
+
return command ? { kind: "help", command } : { kind: "help" };
|
|
1404
|
+
}
|
|
1405
|
+
if (head === "--agent" && second) {
|
|
1406
|
+
return parseOuroCommand(args.slice(2));
|
|
1407
|
+
}
|
|
1408
|
+
if (head === "hook") {
|
|
1409
|
+
const hookArgs = args.slice(1);
|
|
1410
|
+
let event;
|
|
1411
|
+
let hookAgent;
|
|
1412
|
+
for (let i = 0; i < hookArgs.length; i++) {
|
|
1413
|
+
if (hookArgs[i] === "--agent" && hookArgs[i + 1]) {
|
|
1414
|
+
hookAgent = hookArgs[++i];
|
|
1415
|
+
continue;
|
|
1416
|
+
}
|
|
1417
|
+
/* v8 ignore start -- false branch: extra positional args after event are ignored */
|
|
1418
|
+
if (!event) {
|
|
1419
|
+
event = hookArgs[i];
|
|
1420
|
+
}
|
|
1421
|
+
/* v8 ignore stop */
|
|
1422
|
+
}
|
|
1423
|
+
if (!event)
|
|
1424
|
+
throw new Error("hook requires an event name (session-start, stop, post-tool-use)");
|
|
1425
|
+
if (!hookAgent)
|
|
1426
|
+
throw new Error("hook requires --agent <name>");
|
|
1427
|
+
return { kind: "hook", event, agent: hookAgent };
|
|
1428
|
+
}
|
|
1429
|
+
if (head === "up") {
|
|
1430
|
+
const noRepair = args.includes("--no-repair");
|
|
1431
|
+
return noRepair ? { kind: "daemon.up", noRepair: true } : { kind: "daemon.up" };
|
|
1432
|
+
}
|
|
1433
|
+
if (head === "dev") {
|
|
1434
|
+
const devArgs = args.slice(1);
|
|
1435
|
+
let repoPath;
|
|
1436
|
+
let clone = false;
|
|
1437
|
+
let clonePath;
|
|
1438
|
+
for (let i = 0; i < devArgs.length; i++) {
|
|
1439
|
+
if (devArgs[i] === "--repo-path" && devArgs[i + 1]) {
|
|
1440
|
+
repoPath = devArgs[++i];
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
if (devArgs[i] === "--clone") {
|
|
1444
|
+
clone = true;
|
|
1445
|
+
continue;
|
|
1446
|
+
}
|
|
1447
|
+
if (devArgs[i] === "--clone-path" && devArgs[i + 1]) {
|
|
1448
|
+
clonePath = devArgs[++i];
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
return { kind: "daemon.dev", repoPath, clone, clonePath };
|
|
1453
|
+
}
|
|
1454
|
+
if (head === "rollback")
|
|
1455
|
+
return { kind: "rollback", ...(second ? { version: second } : {}) };
|
|
1456
|
+
if (head === "versions")
|
|
1457
|
+
return { kind: "versions" };
|
|
1458
|
+
if (head === "stop" || head === "down")
|
|
1459
|
+
return { kind: "daemon.stop" };
|
|
1460
|
+
if (head === "status") {
|
|
1461
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
1462
|
+
const json = rest.includes("--json");
|
|
1463
|
+
const unknown = rest.filter((token) => token !== "--json");
|
|
1464
|
+
if (agent) {
|
|
1465
|
+
if (unknown.length > 0 || json)
|
|
1466
|
+
throw new Error("Usage: ouro status [--json] OR ouro status --agent <name>");
|
|
1467
|
+
return { kind: "provider.status", agent };
|
|
1468
|
+
}
|
|
1469
|
+
if (unknown.length > 0)
|
|
1470
|
+
throw new Error("Usage: ouro status [--json] OR ouro status --agent <name>");
|
|
1471
|
+
return { kind: "daemon.status", ...(json ? { json: true } : {}) };
|
|
1472
|
+
}
|
|
1473
|
+
if (head === "use")
|
|
1474
|
+
return parseProviderUseCommand(args.slice(1));
|
|
1475
|
+
if (head === "check")
|
|
1476
|
+
return parseProviderCheckCommand(args.slice(1));
|
|
1477
|
+
if (head === "repair") {
|
|
1478
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
1479
|
+
if (rest.length > 0)
|
|
1480
|
+
throw new Error("Usage: ouro repair [--agent <name>]");
|
|
1481
|
+
return agent ? { kind: "repair", agent } : { kind: "repair" };
|
|
1482
|
+
}
|
|
1483
|
+
if (head === "provider")
|
|
1484
|
+
return parseProviderCommand(args.slice(1));
|
|
1485
|
+
if (head === "mail")
|
|
1486
|
+
return parseMailCommand(args.slice(1));
|
|
1487
|
+
if (head === "dns")
|
|
1488
|
+
return parseDnsCommand(args.slice(1));
|
|
1489
|
+
if (head === "logs") {
|
|
1490
|
+
if (second === "prune")
|
|
1491
|
+
return { kind: "daemon.logs.prune" };
|
|
1492
|
+
return { kind: "daemon.logs" };
|
|
1493
|
+
}
|
|
1494
|
+
if (head === "mailbox" || head === "outlook")
|
|
1495
|
+
return { kind: "mailbox", ...(args.includes("--json") ? { json: true } : {}) };
|
|
1496
|
+
if (head === "hatch")
|
|
1497
|
+
return parseHatchCommand(args.slice(1));
|
|
1498
|
+
if (head === "auth")
|
|
1499
|
+
return parseAuthCommand(args.slice(1));
|
|
1500
|
+
if (head === "account")
|
|
1501
|
+
return parseAccountCommand(args.slice(1));
|
|
1502
|
+
if (head === "connect")
|
|
1503
|
+
return parseConnectCommand(args.slice(1));
|
|
1504
|
+
if (head === "vault")
|
|
1505
|
+
return parseVaultCommand(args.slice(1));
|
|
1506
|
+
if (head === "task")
|
|
1507
|
+
return parseTaskCommand(args.slice(1));
|
|
1508
|
+
if (head === "reminder")
|
|
1509
|
+
return parseReminderCommand(args.slice(1));
|
|
1510
|
+
if (head === "habit")
|
|
1511
|
+
return parseHabitCommand(args.slice(1));
|
|
1512
|
+
if (head === "friend")
|
|
1513
|
+
return parseFriendCommand(args.slice(1));
|
|
1514
|
+
if (head === "config")
|
|
1515
|
+
return parseConfigCommand(args.slice(1));
|
|
1516
|
+
if (head === "mcp")
|
|
1517
|
+
return parseMcpCommand(args.slice(1));
|
|
1518
|
+
if (head === "whoami") {
|
|
1519
|
+
const { agent } = extractAgentFlag(args.slice(1));
|
|
1520
|
+
return { kind: "whoami", ...(agent ? { agent } : {}) };
|
|
1521
|
+
}
|
|
1522
|
+
if (head === "session")
|
|
1523
|
+
return parseSessionCommand(args.slice(1));
|
|
1524
|
+
if (head === "changelog") {
|
|
1525
|
+
const sliced = args.slice(1);
|
|
1526
|
+
const { agent, rest: remaining } = extractAgentFlag(sliced);
|
|
1527
|
+
let from;
|
|
1528
|
+
const fromIdx = remaining.indexOf("--from");
|
|
1529
|
+
if (fromIdx !== -1 && remaining[fromIdx + 1]) {
|
|
1530
|
+
from = remaining[fromIdx + 1];
|
|
1531
|
+
}
|
|
1532
|
+
return { kind: "changelog", ...(from ? { from } : {}), ...(agent ? { agent } : {}) };
|
|
1533
|
+
}
|
|
1534
|
+
if (head === "thoughts")
|
|
1535
|
+
return parseThoughtsCommand(args.slice(1));
|
|
1536
|
+
if (head === "attention")
|
|
1537
|
+
return parseAttentionCommand(args.slice(1));
|
|
1538
|
+
if (head === "inner") {
|
|
1539
|
+
const { agent } = extractAgentFlag(args.slice(1));
|
|
1540
|
+
return { kind: "inner.status", ...(agent ? { agent } : {}) };
|
|
1541
|
+
}
|
|
1542
|
+
if (head === "chat") {
|
|
1543
|
+
if (!second)
|
|
1544
|
+
return { kind: "chat.connect", agent: "" };
|
|
1545
|
+
return { kind: "chat.connect", agent: second };
|
|
1546
|
+
}
|
|
1547
|
+
if (head === "msg")
|
|
1548
|
+
return parseMessageCommand(args.slice(1));
|
|
1549
|
+
if (head === "poke")
|
|
1550
|
+
return parsePokeCommand(args.slice(1));
|
|
1551
|
+
if (head === "link")
|
|
1552
|
+
return parseLinkCommand(args.slice(1));
|
|
1553
|
+
if (head === "mcp-serve")
|
|
1554
|
+
return parseMcpServeCommand(args.slice(1));
|
|
1555
|
+
if (head === "setup")
|
|
1556
|
+
return parseSetupCommand(args.slice(1));
|
|
1557
|
+
if (head === "clone")
|
|
1558
|
+
return parseCloneCommand(args.slice(1));
|
|
1559
|
+
if (head === "doctor") {
|
|
1560
|
+
const tail = args.slice(1);
|
|
1561
|
+
const json = tail.includes("--json");
|
|
1562
|
+
const hasCategoryFlag = tail.includes("--category");
|
|
1563
|
+
const hasStrictFlag = tail.includes("--strict");
|
|
1564
|
+
let category;
|
|
1565
|
+
let strict = false;
|
|
1566
|
+
for (let i = 0; i < tail.length; i++) {
|
|
1567
|
+
if (tail[i] === "--category" && typeof tail[i + 1] === "string") {
|
|
1568
|
+
category = tail[i + 1];
|
|
1569
|
+
}
|
|
1570
|
+
else if (tail[i] === "--strict") {
|
|
1571
|
+
strict = true;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
const command = { kind: "doctor" };
|
|
1575
|
+
if (category !== undefined)
|
|
1576
|
+
command.category = category;
|
|
1577
|
+
if (strict)
|
|
1578
|
+
command.strict = true;
|
|
1579
|
+
// --json default is only emitted for "plain" doctor invocations.
|
|
1580
|
+
// CI variants (--strict, --category) omit it; consumers go through doctorResult directly.
|
|
1581
|
+
if (!hasCategoryFlag && !hasStrictFlag)
|
|
1582
|
+
command.json = json;
|
|
1583
|
+
return command;
|
|
1584
|
+
}
|
|
1585
|
+
if (head === "bluebubbles")
|
|
1586
|
+
return parseBlueBubblesCommand(args.slice(1));
|
|
1587
|
+
const suggestion = (0, cli_help_1.suggestCommand)(head);
|
|
1588
|
+
const hint = suggestion ? ` Did you mean '${suggestion}'?` : "";
|
|
1589
|
+
throw new Error(`Unknown command '${args.join(" ")}'.${hint}\n${usage()}`);
|
|
1590
|
+
}
|