@ouro.bot/cli 0.1.0-alpha.5 → 0.1.0-alpha.500
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 +226 -183
- package/SerpentGuide.ouro/agent.json +82 -0
- package/SerpentGuide.ouro/psyche/SOUL.md +25 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/assets/ouroboros.png +0 -0
- package/changelog.json +3418 -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 +989 -0
- 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 +426 -0
- package/dist/heart/background-operations.js +281 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +193 -130
- package/dist/heart/core.js +1010 -261
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +490 -0
- package/dist/heart/daemon/agent-discovery.js +157 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +216 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +640 -0
- package/dist/heart/daemon/cli-exec.js +7239 -0
- package/dist/heart/daemon/cli-help.js +493 -0
- package/dist/heart/daemon/cli-parse.js +1533 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +561 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +30 -697
- package/dist/heart/daemon/daemon-entry.js +359 -8
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +268 -0
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +813 -19
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +615 -0
- package/dist/heart/daemon/health-monitor.js +92 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +171 -0
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- 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 +215 -1
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +39 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +191 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +431 -0
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +264 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +524 -0
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-animation.js +10 -3
- package/dist/heart/{daemon → hatch}/hatch-flow.js +54 -136
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/hatch/specialist-orchestrator.js +129 -0
- package/dist/heart/hatch/specialist-prompt.js +102 -0
- package/dist/heart/hatch/specialist-tools.js +306 -0
- package/dist/heart/identity.js +274 -61
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mail-import-discovery.js +353 -0
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +66 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +244 -0
- package/dist/heart/outlook/outlook-http-static.js +103 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +31 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +195 -0
- package/dist/heart/outlook/readers/agent-machine.js +382 -0
- package/dist/heart/outlook/readers/continuity-readers.js +336 -0
- package/dist/heart/outlook/readers/mail.js +362 -0
- package/dist/heart/outlook/readers/runtime-readers.js +644 -0
- package/dist/heart/outlook/readers/sessions.js +232 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-attempt.js +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +424 -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 +202 -50
- package/dist/heart/providers/azure.js +104 -13
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +29 -7
- package/dist/heart/providers/openai-codex.js +63 -39
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +260 -0
- package/dist/heart/sense-truth.js +68 -0
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +1089 -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-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +129 -34
- package/dist/heart/sync.js +332 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +372 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +425 -0
- package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/versioning/staged-restart.js +146 -0
- package/dist/heart/versioning/update-checker.js +115 -0
- package/dist/heart/versioning/update-hooks.js +142 -0
- package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +606 -0
- package/dist/mailroom/core.js +672 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +426 -0
- package/dist/mailroom/mbox-import.js +382 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +219 -0
- package/dist/mailroom/search-cache.js +182 -0
- package/dist/mailroom/search-relevance.js +319 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/thread.js +109 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +77 -1
- package/dist/mind/context.js +173 -94
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +73 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +54 -2
- package/dist/mind/friends/store-file.js +58 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +10 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -0
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +1144 -117
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +22 -3
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +101 -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/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-BPr5vNuM.css +1 -0
- package/dist/outlook-ui/assets/index-Cm51CY9W.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +17 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +774 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +220 -13
- package/dist/repertoire/coding/spawner.js +58 -12
- package/dist/repertoire/coding/tools.js +209 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -0
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +396 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +39 -13
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +16 -79
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +49 -707
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-bridge.js +141 -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 +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-mail.js +1377 -0
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +749 -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 +64 -61
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-trip.js +356 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +149 -98
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +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/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/bluebubbles/client.js +685 -0
- package/dist/senses/bluebubbles/entry.js +73 -0
- package/dist/senses/bluebubbles/inbound-log.js +126 -0
- package/dist/senses/bluebubbles/index.js +1881 -0
- package/dist/senses/bluebubbles/media.js +389 -0
- package/dist/senses/bluebubbles/model.js +282 -0
- package/dist/senses/bluebubbles/mutation-log.js +116 -0
- package/dist/senses/bluebubbles/processed-log.js +111 -0
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/bluebubbles/session-cleanup.js +72 -0
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -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 +83 -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 +768 -264
- package/dist/senses/commands.js +66 -3
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +199 -16
- package/dist/senses/inner-dialog.js +640 -91
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +665 -0
- 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 +844 -197
- package/dist/senses/trust-gate.js +207 -2
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- package/package.json +47 -6
- 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/AdoptionSpecialist.ouro/agent.json +0 -20
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +0 -22
- package/dist/heart/daemon/specialist-orchestrator.js +0 -160
- package/dist/heart/daemon/specialist-prompt.js +0 -40
- package/dist/heart/daemon/specialist-session.js +0 -142
- package/dist/heart/daemon/specialist-tools.js +0 -128
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/dist/mind/associative-recall.js +0 -197
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.codingToolDefinitions = void 0;
|
|
4
|
+
exports.countFilesInSessionOutput = countFilesInSessionOutput;
|
|
4
5
|
const index_1 = require("./index");
|
|
6
|
+
const context_pack_1 = require("./context-pack");
|
|
7
|
+
const identity_1 = require("../../heart/identity");
|
|
8
|
+
const obligations_1 = require("../../arc/obligations");
|
|
5
9
|
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
+
const scrutiny_1 = require("../../mind/scrutiny");
|
|
6
11
|
const RUNNERS = ["claude", "codex"];
|
|
7
12
|
function requireArg(args, key) {
|
|
8
13
|
const value = args[key];
|
|
@@ -29,11 +34,112 @@ function emitCodingToolEvent(toolName) {
|
|
|
29
34
|
meta: { toolName },
|
|
30
35
|
});
|
|
31
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Count distinct file paths mentioned in a coding session's stdout output.
|
|
39
|
+
* Looks for path-like tokens (containing / and a file extension).
|
|
40
|
+
* Returns the count of unique paths found.
|
|
41
|
+
*/
|
|
42
|
+
function countFilesInSessionOutput(session) {
|
|
43
|
+
const text = `${session.stdoutTail}\n${session.stderrTail}`;
|
|
44
|
+
// Match path-like tokens: contain at least one / and a file extension
|
|
45
|
+
const pathPattern = /(?:^|\s)((?:\/|\.\/|\.\.\/)?(?:[\w.@-]+\/)+[\w.-]+\.[\w]+)/gm;
|
|
46
|
+
const paths = new Set();
|
|
47
|
+
let match;
|
|
48
|
+
while ((match = pathPattern.exec(text)) !== null) {
|
|
49
|
+
paths.add(match[1]);
|
|
50
|
+
}
|
|
51
|
+
return paths.size;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* If a coding session is completed, append scrutiny to the result.
|
|
55
|
+
* Returns the original result with scrutiny appended, or unchanged if
|
|
56
|
+
* the session is not completed or has no file changes.
|
|
57
|
+
*/
|
|
58
|
+
function appendCompletionScrutiny(result, session) {
|
|
59
|
+
if (session.status !== "completed")
|
|
60
|
+
return result;
|
|
61
|
+
const fileCount = countFilesInSessionOutput(session);
|
|
62
|
+
const scrutiny = (0, scrutiny_1.getCodingCompletionScrutiny)(fileCount);
|
|
63
|
+
return scrutiny ? `${result}\n\n${scrutiny}` : result;
|
|
64
|
+
}
|
|
65
|
+
function sameOriginSession(left, right) {
|
|
66
|
+
if (!left && !right)
|
|
67
|
+
return true;
|
|
68
|
+
if (!left || !right)
|
|
69
|
+
return false;
|
|
70
|
+
return left.friendId === right.friendId && left.channel === right.channel && left.key === right.key;
|
|
71
|
+
}
|
|
72
|
+
function matchesReusableCodingSession(session, request) {
|
|
73
|
+
if (session.status !== "spawning" && session.status !== "running" && session.status !== "waiting_input" && session.status !== "stalled") {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const scopeMatches = request.scopeFile ? session.scopeFile === request.scopeFile : true;
|
|
77
|
+
const stateMatches = request.stateFile ? session.stateFile === request.stateFile : true;
|
|
78
|
+
return (session.runner === request.runner &&
|
|
79
|
+
session.workdir === request.workdir &&
|
|
80
|
+
session.taskRef === request.taskRef &&
|
|
81
|
+
scopeMatches &&
|
|
82
|
+
stateMatches &&
|
|
83
|
+
session.obligationId === request.obligationId &&
|
|
84
|
+
sameOriginSession(request.originSession, session.originSession));
|
|
85
|
+
}
|
|
86
|
+
function latestSessionFirst(left, right) {
|
|
87
|
+
const lastActivityDelta = Date.parse(right.lastActivityAt) - Date.parse(left.lastActivityAt);
|
|
88
|
+
if (lastActivityDelta !== 0)
|
|
89
|
+
return lastActivityDelta;
|
|
90
|
+
return right.id.localeCompare(left.id);
|
|
91
|
+
}
|
|
92
|
+
function findReusableCodingSession(sessions, request) {
|
|
93
|
+
const matches = sessions.filter((session) => matchesReusableCodingSession(session, request)).sort(latestSessionFirst);
|
|
94
|
+
return matches[0] ?? null;
|
|
95
|
+
}
|
|
96
|
+
function isLiveCodingStatus(status) {
|
|
97
|
+
return status === "spawning" || status === "running" || status === "waiting_input" || status === "stalled";
|
|
98
|
+
}
|
|
99
|
+
function rankCodingStatusSession(session, currentSession) {
|
|
100
|
+
return sameOriginSession({
|
|
101
|
+
friendId: currentSession.friendId,
|
|
102
|
+
channel: currentSession.channel,
|
|
103
|
+
key: currentSession.key,
|
|
104
|
+
}, session.originSession)
|
|
105
|
+
? 0
|
|
106
|
+
: 1;
|
|
107
|
+
}
|
|
108
|
+
function selectCodingStatusSessions(sessions, currentSession) {
|
|
109
|
+
if (sessions.length === 0)
|
|
110
|
+
return [];
|
|
111
|
+
if (!currentSession) {
|
|
112
|
+
return sessions;
|
|
113
|
+
}
|
|
114
|
+
const activeSessions = sessions.filter((session) => isLiveCodingStatus(session.status)).sort(latestSessionFirst);
|
|
115
|
+
if (activeSessions.length > 0) {
|
|
116
|
+
return activeSessions.sort((left, right) => {
|
|
117
|
+
const rankDelta = rankCodingStatusSession(left, currentSession) - rankCodingStatusSession(right, currentSession);
|
|
118
|
+
if (rankDelta !== 0)
|
|
119
|
+
return rankDelta;
|
|
120
|
+
return latestSessionFirst(left, right);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const matchingClosedSessions = sessions
|
|
124
|
+
.filter((session) => sameOriginSession({
|
|
125
|
+
friendId: currentSession.friendId,
|
|
126
|
+
channel: currentSession.channel,
|
|
127
|
+
key: currentSession.key,
|
|
128
|
+
}, session.originSession))
|
|
129
|
+
.sort(latestSessionFirst);
|
|
130
|
+
if (matchingClosedSessions.length > 0) {
|
|
131
|
+
return matchingClosedSessions;
|
|
132
|
+
}
|
|
133
|
+
return [...sessions].sort(latestSessionFirst);
|
|
134
|
+
}
|
|
135
|
+
function buildCodingObligationContent(taskRef) {
|
|
136
|
+
return `finish ${taskRef} and bring the result back`;
|
|
137
|
+
}
|
|
32
138
|
const codingSpawnTool = {
|
|
33
139
|
type: "function",
|
|
34
140
|
function: {
|
|
35
141
|
name: "coding_spawn",
|
|
36
|
-
description: "
|
|
142
|
+
description: "Spawn a coding session using claude or codex with task-threaded guidance. The coding session runs as a separate process with its own context. Give it a COMPLETE, SELF-CONTAINED task description -- it cannot see this conversation, doesn't know what you've tried, doesn't understand the broader context. Include: what to do, why, what files are involved, what 'done' looks like. Never delegate understanding -- don't write 'based on the conversation, fix the bug.' Write the specific file paths, line numbers, and what to change. Include any required verification steps or tests in the task description so the coding session knows how to prove the work is done.",
|
|
37
143
|
parameters: {
|
|
38
144
|
type: "object",
|
|
39
145
|
properties: {
|
|
@@ -52,7 +158,7 @@ const codingStatusTool = {
|
|
|
52
158
|
type: "function",
|
|
53
159
|
function: {
|
|
54
160
|
name: "coding_status",
|
|
55
|
-
description: "
|
|
161
|
+
description: "Inspect coding sessions. Omit sessionId to list all active/known sessions with their status. Use this to check progress before asking the human for a status update.",
|
|
56
162
|
parameters: {
|
|
57
163
|
type: "object",
|
|
58
164
|
properties: {
|
|
@@ -61,6 +167,20 @@ const codingStatusTool = {
|
|
|
61
167
|
},
|
|
62
168
|
},
|
|
63
169
|
};
|
|
170
|
+
const codingTailTool = {
|
|
171
|
+
type: "function",
|
|
172
|
+
function: {
|
|
173
|
+
name: "coding_tail",
|
|
174
|
+
description: "Show recent stdout/stderr output from a coding session. Use this to understand what the session is doing or why it might be stuck. Read the actual output before reporting status -- don't guess.",
|
|
175
|
+
parameters: {
|
|
176
|
+
type: "object",
|
|
177
|
+
properties: {
|
|
178
|
+
sessionId: { type: "string" },
|
|
179
|
+
},
|
|
180
|
+
required: ["sessionId"],
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
};
|
|
64
184
|
const codingSendInputTool = {
|
|
65
185
|
type: "function",
|
|
66
186
|
function: {
|
|
@@ -93,7 +213,7 @@ const codingKillTool = {
|
|
|
93
213
|
exports.codingToolDefinitions = [
|
|
94
214
|
{
|
|
95
215
|
tool: codingSpawnTool,
|
|
96
|
-
handler: async (args) => {
|
|
216
|
+
handler: async (args, ctx) => {
|
|
97
217
|
emitCodingToolEvent("coding_spawn");
|
|
98
218
|
const rawRunner = requireArg(args, "runner");
|
|
99
219
|
if (!rawRunner)
|
|
@@ -116,30 +236,110 @@ exports.codingToolDefinitions = [
|
|
|
116
236
|
prompt,
|
|
117
237
|
taskRef,
|
|
118
238
|
};
|
|
239
|
+
if (ctx?.currentSession && ctx.currentSession.channel !== "inner") {
|
|
240
|
+
request.originSession = {
|
|
241
|
+
friendId: ctx.currentSession.friendId,
|
|
242
|
+
channel: ctx.currentSession.channel,
|
|
243
|
+
key: ctx.currentSession.key,
|
|
244
|
+
};
|
|
245
|
+
const obligation = (0, obligations_1.findPendingObligationForOrigin)((0, identity_1.getAgentRoot)(), request.originSession);
|
|
246
|
+
if (obligation) {
|
|
247
|
+
request.obligationId = obligation.id;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
119
250
|
const scopeFile = optionalArg(args, "scopeFile");
|
|
120
251
|
if (scopeFile)
|
|
121
252
|
request.scopeFile = scopeFile;
|
|
122
253
|
const stateFile = optionalArg(args, "stateFile");
|
|
123
254
|
if (stateFile)
|
|
124
255
|
request.stateFile = stateFile;
|
|
125
|
-
const
|
|
256
|
+
const manager = (0, index_1.getCodingSessionManager)();
|
|
257
|
+
const existingSessions = manager.listSessions();
|
|
258
|
+
const existingSession = findReusableCodingSession(existingSessions, request);
|
|
259
|
+
if (existingSession) {
|
|
260
|
+
(0, runtime_1.emitNervesEvent)({
|
|
261
|
+
component: "repertoire",
|
|
262
|
+
event: "repertoire.coding_session_reused",
|
|
263
|
+
message: "reused active coding session",
|
|
264
|
+
meta: { id: existingSession.id, runner: existingSession.runner, taskRef: existingSession.taskRef },
|
|
265
|
+
});
|
|
266
|
+
if (ctx?.codingFeedback) {
|
|
267
|
+
(0, index_1.attachCodingSessionFeedback)(manager, existingSession, ctx.codingFeedback);
|
|
268
|
+
}
|
|
269
|
+
return JSON.stringify({ ...existingSession, reused: true });
|
|
270
|
+
}
|
|
271
|
+
if (request.originSession && !request.obligationId) {
|
|
272
|
+
const created = (0, obligations_1.createObligation)((0, identity_1.getAgentRoot)(), {
|
|
273
|
+
origin: request.originSession,
|
|
274
|
+
content: buildCodingObligationContent(taskRef),
|
|
275
|
+
});
|
|
276
|
+
request.obligationId = created.id;
|
|
277
|
+
}
|
|
278
|
+
if (!request.scopeFile || !request.stateFile) {
|
|
279
|
+
const generated = (0, context_pack_1.prepareCodingContextPack)({
|
|
280
|
+
request: { ...request },
|
|
281
|
+
existingSessions,
|
|
282
|
+
activeWorkFrame: ctx?.activeWorkFrame,
|
|
283
|
+
});
|
|
284
|
+
if (!request.scopeFile)
|
|
285
|
+
request.scopeFile = generated.scopeFile;
|
|
286
|
+
if (!request.stateFile)
|
|
287
|
+
request.stateFile = generated.stateFile;
|
|
288
|
+
}
|
|
289
|
+
const session = await manager.spawnSession(request);
|
|
290
|
+
if (session.obligationId) {
|
|
291
|
+
(0, obligations_1.advanceObligation)((0, identity_1.getAgentRoot)(), session.obligationId, {
|
|
292
|
+
status: "investigating",
|
|
293
|
+
currentSurface: { kind: "coding", label: `${session.runner} ${session.id}` },
|
|
294
|
+
latestNote: session.originSession
|
|
295
|
+
? `coding session started for ${session.originSession.channel}/${session.originSession.key}`
|
|
296
|
+
: "coding session started",
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (args.runner === "codex" && args.taskRef) {
|
|
300
|
+
(0, runtime_1.emitNervesEvent)({
|
|
301
|
+
component: "repertoire",
|
|
302
|
+
event: "repertoire.coding_codex_spawned",
|
|
303
|
+
message: "spawned codex coding session",
|
|
304
|
+
meta: { sessionId: session.id, taskRef: args.taskRef },
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (ctx?.codingFeedback) {
|
|
308
|
+
(0, index_1.attachCodingSessionFeedback)(manager, session, ctx.codingFeedback);
|
|
309
|
+
}
|
|
126
310
|
return JSON.stringify(session);
|
|
127
311
|
},
|
|
312
|
+
summaryKeys: ["runner", "workdir", "taskRef"],
|
|
128
313
|
},
|
|
129
314
|
{
|
|
130
315
|
tool: codingStatusTool,
|
|
131
|
-
handler: (args) => {
|
|
316
|
+
handler: (args, ctx) => {
|
|
132
317
|
emitCodingToolEvent("coding_status");
|
|
133
318
|
const manager = (0, index_1.getCodingSessionManager)();
|
|
134
319
|
const sessionId = requireArg(args, "sessionId");
|
|
135
320
|
if (!sessionId) {
|
|
136
|
-
return JSON.stringify(manager.listSessions());
|
|
321
|
+
return JSON.stringify(selectCodingStatusSessions(manager.listSessions(), ctx?.currentSession));
|
|
137
322
|
}
|
|
138
323
|
const session = manager.getSession(sessionId);
|
|
139
324
|
if (!session)
|
|
140
325
|
return `session not found: ${sessionId}`;
|
|
141
|
-
return JSON.stringify(session);
|
|
326
|
+
return appendCompletionScrutiny(JSON.stringify(session), session);
|
|
327
|
+
},
|
|
328
|
+
summaryKeys: ["sessionId"],
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
tool: codingTailTool,
|
|
332
|
+
handler: (args) => {
|
|
333
|
+
emitCodingToolEvent("coding_tail");
|
|
334
|
+
const sessionId = requireArg(args, "sessionId");
|
|
335
|
+
if (!sessionId)
|
|
336
|
+
return "sessionId is required";
|
|
337
|
+
const session = (0, index_1.getCodingSessionManager)().getSession(sessionId);
|
|
338
|
+
if (!session)
|
|
339
|
+
return `session not found: ${sessionId}`;
|
|
340
|
+
return appendCompletionScrutiny((0, index_1.formatCodingTail)(session), session);
|
|
142
341
|
},
|
|
342
|
+
summaryKeys: ["sessionId"],
|
|
143
343
|
},
|
|
144
344
|
{
|
|
145
345
|
tool: codingSendInputTool,
|
|
@@ -153,6 +353,7 @@ exports.codingToolDefinitions = [
|
|
|
153
353
|
return "input is required";
|
|
154
354
|
return JSON.stringify((0, index_1.getCodingSessionManager)().sendInput(sessionId, input));
|
|
155
355
|
},
|
|
356
|
+
summaryKeys: ["sessionId", "input"],
|
|
156
357
|
},
|
|
157
358
|
{
|
|
158
359
|
tool: codingKillTool,
|
|
@@ -163,5 +364,6 @@ exports.codingToolDefinitions = [
|
|
|
163
364
|
return "sessionId is required";
|
|
164
365
|
return JSON.stringify((0, index_1.getCodingSessionManager)().killSession(sessionId));
|
|
165
366
|
},
|
|
367
|
+
summaryKeys: ["sessionId"],
|
|
166
368
|
},
|
|
167
369
|
];
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Commerce-specific error types and helpers.
|
|
4
|
+
*
|
|
5
|
+
* These errors carry structured `code` and `meta` fields for nerves event
|
|
6
|
+
* compatibility and provide patterns for common commerce failure modes:
|
|
7
|
+
* retry, price change detection, and partial failure reporting.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ProfileError = exports.BookingError = exports.PaymentError = exports.CommerceError = void 0;
|
|
11
|
+
exports.retryOnce = retryOnce;
|
|
12
|
+
exports.priceChangeGuard = priceChangeGuard;
|
|
13
|
+
exports.partialFailureReport = partialFailureReport;
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Error types
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
class CommerceError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
meta;
|
|
20
|
+
constructor(message, code, meta = {}) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "CommerceError";
|
|
23
|
+
this.code = code;
|
|
24
|
+
this.meta = meta;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.CommerceError = CommerceError;
|
|
28
|
+
class PaymentError extends CommerceError {
|
|
29
|
+
constructor(message, code, meta = {}) {
|
|
30
|
+
super(message, code, meta);
|
|
31
|
+
this.name = "PaymentError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.PaymentError = PaymentError;
|
|
35
|
+
class BookingError extends CommerceError {
|
|
36
|
+
constructor(message, code, meta = {}) {
|
|
37
|
+
super(message, code, meta);
|
|
38
|
+
this.name = "BookingError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.BookingError = BookingError;
|
|
42
|
+
class ProfileError extends CommerceError {
|
|
43
|
+
constructor(message, code, meta = {}) {
|
|
44
|
+
super(message, code, meta);
|
|
45
|
+
this.name = "ProfileError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.ProfileError = ProfileError;
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Transient error detection
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
const TRANSIENT_CODES = new Set(["COMMERCE_TRANSIENT", "COMMERCE_TIMEOUT", "COMMERCE_NETWORK"]);
|
|
53
|
+
function isTransient(err) {
|
|
54
|
+
return err instanceof CommerceError && TRANSIENT_CODES.has(err.code);
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Helpers
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Retry a function once on transient failure, then throw.
|
|
61
|
+
* Non-transient errors are thrown immediately without retry.
|
|
62
|
+
*/
|
|
63
|
+
async function retryOnce(fn) {
|
|
64
|
+
try {
|
|
65
|
+
return await fn();
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (!isTransient(err))
|
|
69
|
+
throw err;
|
|
70
|
+
// One retry
|
|
71
|
+
return fn();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Throw PaymentError if the actual price differs from the approved price
|
|
76
|
+
* by more than 5%. Used to protect against price changes between search
|
|
77
|
+
* and booking.
|
|
78
|
+
*/
|
|
79
|
+
function priceChangeGuard(approved, actual) {
|
|
80
|
+
if (approved === 0 && actual === 0)
|
|
81
|
+
return;
|
|
82
|
+
if (approved === 0) {
|
|
83
|
+
throw new PaymentError(`price changed from $0 to $${actual} — cannot verify percentage change`, "PAYMENT_PRICE_CHANGED", { approved, actual });
|
|
84
|
+
}
|
|
85
|
+
const delta = Math.abs(actual - approved) / approved;
|
|
86
|
+
if (delta > 0.05) {
|
|
87
|
+
throw new PaymentError(`price changed by ${(delta * 100).toFixed(1)}% (approved: $${approved}, actual: $${actual})`, "PAYMENT_PRICE_CHANGED", { approved, actual, deltaPercent: delta * 100 });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Format a human-readable status report for multi-service booking attempts.
|
|
92
|
+
* Each entry has a service name, status, and optional error message.
|
|
93
|
+
*/
|
|
94
|
+
function partialFailureReport(results) {
|
|
95
|
+
if (results.length === 0) {
|
|
96
|
+
return "no services attempted.";
|
|
97
|
+
}
|
|
98
|
+
const lines = results.map((r) => {
|
|
99
|
+
const status = r.status === "success" ? "success" : "failed";
|
|
100
|
+
const detail = r.error ? ` — ${r.error}` : "";
|
|
101
|
+
return ` ${r.service}: ${status}${detail}`;
|
|
102
|
+
});
|
|
103
|
+
const succeeded = results.filter((r) => r.status === "success").length;
|
|
104
|
+
const failed = results.length - succeeded;
|
|
105
|
+
return [
|
|
106
|
+
`booking status: ${succeeded} succeeded, ${failed} failed`,
|
|
107
|
+
...lines,
|
|
108
|
+
].join("\n");
|
|
109
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Commerce self-test — per-service health checks for the agent's
|
|
4
|
+
* commerce infrastructure (Stripe, Duffel, LiteAPI).
|
|
5
|
+
*
|
|
6
|
+
* Used by the setup wizard to verify configuration and provide
|
|
7
|
+
* actionable error messages when services are misconfigured.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.commerceSelfTest = commerceSelfTest;
|
|
11
|
+
const stripe_client_1 = require("./stripe-client");
|
|
12
|
+
const duffel_client_1 = require("./duffel-client");
|
|
13
|
+
const credential_access_1 = require("./credential-access");
|
|
14
|
+
const runtime_1 = require("../nerves/runtime");
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Per-service tests
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
async function testStripe() {
|
|
19
|
+
try {
|
|
20
|
+
const client = await (0, stripe_client_1.createStripeClient)();
|
|
21
|
+
// Create a test card and immediately deactivate it
|
|
22
|
+
const card = await client.createVirtualCard({
|
|
23
|
+
type: "single_use",
|
|
24
|
+
spendLimit: 1,
|
|
25
|
+
currency: "usd",
|
|
26
|
+
});
|
|
27
|
+
await client.deactivateCard(card.cardId);
|
|
28
|
+
return { status: "ok", message: "Stripe Issuing working. Test card created and deactivated." };
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
/* v8 ignore next -- reason @preserve */
|
|
32
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
33
|
+
if (reason.includes("no credential found") || reason.includes("restrictedKey")) {
|
|
34
|
+
return {
|
|
35
|
+
status: "error",
|
|
36
|
+
message: `Stripe key missing. Add your restricted key at https://dashboard.stripe.com/apikeys and store it in the vault as stripe.com/restrictedKey.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (reason.includes("401") || reason.includes("Invalid API Key")) {
|
|
40
|
+
return {
|
|
41
|
+
status: "error",
|
|
42
|
+
message: `Stripe key returned 401. Verify it at https://dashboard.stripe.com/apikeys.`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status: "error",
|
|
47
|
+
message: `Stripe error: ${reason}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function testDuffel() {
|
|
52
|
+
try {
|
|
53
|
+
const client = await (0, duffel_client_1.createDuffelClient)();
|
|
54
|
+
await client.searchFlights({
|
|
55
|
+
origin: "SFO",
|
|
56
|
+
destination: "JFK",
|
|
57
|
+
departureDate: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0],
|
|
58
|
+
passengers: [{ type: "adult" }],
|
|
59
|
+
});
|
|
60
|
+
return { status: "ok", message: "Duffel Flights working. Test search completed." };
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
/* v8 ignore next -- reason @preserve */
|
|
64
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
65
|
+
if (reason.includes("no credential found") || reason.includes("apiKey")) {
|
|
66
|
+
return {
|
|
67
|
+
status: "error",
|
|
68
|
+
message: `Duffel key missing. Add your API key from https://app.duffel.com/tokens and store it in the vault as duffel.com/apiKey.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (reason.includes("401") || reason.includes("Unauthorized")) {
|
|
72
|
+
return {
|
|
73
|
+
status: "error",
|
|
74
|
+
message: `Your Duffel key returned 401. Verify it at https://app.duffel.com/tokens.`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
status: "error",
|
|
79
|
+
message: `Duffel error: ${reason}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function testLiteApi() {
|
|
84
|
+
try {
|
|
85
|
+
const store = (0, credential_access_1.getCredentialStore)();
|
|
86
|
+
await store.getRawSecret("liteapi.travel", "apiKey");
|
|
87
|
+
// If we can retrieve the key, the config is present.
|
|
88
|
+
// LiteAPI is accessed via MCP, so we can't do a direct API call here.
|
|
89
|
+
// The actual health check happens when the MCP server starts.
|
|
90
|
+
return { status: "ok", message: "LiteAPI key found in vault. MCP server will use vault:liteapi.travel/apiKey." };
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
/* v8 ignore next -- reason @preserve */
|
|
94
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
95
|
+
if (reason.includes("no credential found")) {
|
|
96
|
+
return {
|
|
97
|
+
status: "error",
|
|
98
|
+
message: `LiteAPI key missing. Get your API key from https://dashboard.liteapi.travel and store it in the vault as liteapi.travel/apiKey.`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
status: "error",
|
|
103
|
+
message: `LiteAPI error: ${reason}`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Main self-test
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
async function commerceSelfTest() {
|
|
111
|
+
(0, runtime_1.emitNervesEvent)({
|
|
112
|
+
component: "repertoire",
|
|
113
|
+
event: "repertoire.commerce_self_test_start",
|
|
114
|
+
message: "starting commerce self-test",
|
|
115
|
+
meta: {},
|
|
116
|
+
});
|
|
117
|
+
const [stripe, duffel, liteapi] = await Promise.all([
|
|
118
|
+
testStripe(),
|
|
119
|
+
testDuffel(),
|
|
120
|
+
testLiteApi(),
|
|
121
|
+
]);
|
|
122
|
+
const services = { stripe, duffel, liteapi };
|
|
123
|
+
const okCount = Object.values(services).filter((s) => s.status === "ok").length;
|
|
124
|
+
const total = Object.keys(services).length;
|
|
125
|
+
let overall;
|
|
126
|
+
if (okCount === total) {
|
|
127
|
+
overall = "healthy";
|
|
128
|
+
}
|
|
129
|
+
else if (okCount > 0) {
|
|
130
|
+
overall = "partial";
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
overall = "unhealthy";
|
|
134
|
+
}
|
|
135
|
+
const lines = [];
|
|
136
|
+
if (stripe.status === "ok")
|
|
137
|
+
lines.push("Stripe: working");
|
|
138
|
+
else
|
|
139
|
+
lines.push(`Stripe: ${stripe.message}`);
|
|
140
|
+
if (duffel.status === "ok")
|
|
141
|
+
lines.push("Duffel: working");
|
|
142
|
+
else
|
|
143
|
+
lines.push(`Duffel: ${duffel.message}`);
|
|
144
|
+
if (liteapi.status === "ok")
|
|
145
|
+
lines.push("LiteAPI: working");
|
|
146
|
+
else
|
|
147
|
+
lines.push(`LiteAPI: ${liteapi.message}`);
|
|
148
|
+
const summary = `Commerce health: ${okCount}/${total} services ok.\n${lines.join("\n")}`;
|
|
149
|
+
(0, runtime_1.emitNervesEvent)({
|
|
150
|
+
component: "repertoire",
|
|
151
|
+
event: "repertoire.commerce_self_test_end",
|
|
152
|
+
message: "commerce self-test complete",
|
|
153
|
+
meta: { overall, okCount, total },
|
|
154
|
+
});
|
|
155
|
+
return { overall, services, summary };
|
|
156
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Credential access layer.
|
|
4
|
+
*
|
|
5
|
+
* Bitwarden/Vaultwarden is the sole runtime credential store. The only local
|
|
6
|
+
* secret is the vault unlock material held by an explicit local unlock store.
|
|
7
|
+
*
|
|
8
|
+
* Each agent owns one credential vault. getCredentialStore() returns that
|
|
9
|
+
* agent's vault directly; item names are not shared or namespaced across
|
|
10
|
+
* agents.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.getCredentialStore = getCredentialStore;
|
|
47
|
+
exports.resetCredentialStore = resetCredentialStore;
|
|
48
|
+
const crypto = __importStar(require("node:crypto"));
|
|
49
|
+
const fs = __importStar(require("node:fs"));
|
|
50
|
+
const os = __importStar(require("node:os"));
|
|
51
|
+
const path = __importStar(require("node:path"));
|
|
52
|
+
const runtime_1 = require("../nerves/runtime");
|
|
53
|
+
const identity = __importStar(require("../heart/identity"));
|
|
54
|
+
const bitwarden_store_1 = require("./bitwarden-store");
|
|
55
|
+
const vault_unlock_1 = require("./vault-unlock");
|
|
56
|
+
let stores = new Map();
|
|
57
|
+
function loadVaultSectionForAgent(agentName) {
|
|
58
|
+
const configPath = path.join(identity.getAgentRoot(agentName), "agent.json");
|
|
59
|
+
try {
|
|
60
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
61
|
+
return { configPath, vault: parsed.vault };
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { configPath };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function bitwardenAppDataDir(agentName, vaultConfig) {
|
|
68
|
+
const digest = crypto
|
|
69
|
+
.createHash("sha256")
|
|
70
|
+
.update(`${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`)
|
|
71
|
+
.digest("hex")
|
|
72
|
+
.slice(0, 24);
|
|
73
|
+
return path.join(os.homedir(), ".ouro-cli", "bitwarden", digest);
|
|
74
|
+
}
|
|
75
|
+
function getCredentialStore(agentNameInput) {
|
|
76
|
+
const agentName = agentNameInput ?? identity.getAgentName();
|
|
77
|
+
if (agentName === "SerpentGuide") {
|
|
78
|
+
throw new Error("SerpentGuide does not have a persistent credential vault; hatch bootstrap uses provider credentials in memory only.");
|
|
79
|
+
}
|
|
80
|
+
const { configPath, vault } = loadVaultSectionForAgent(agentName);
|
|
81
|
+
if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
|
|
82
|
+
throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
|
|
83
|
+
}
|
|
84
|
+
const vaultConfig = identity.resolveVaultConfig(agentName, vault);
|
|
85
|
+
const cacheKey = `${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`;
|
|
86
|
+
const cached = stores.get(cacheKey);
|
|
87
|
+
if (cached)
|
|
88
|
+
return cached;
|
|
89
|
+
const unlock = (0, vault_unlock_1.readVaultUnlockSecret)({
|
|
90
|
+
agentName,
|
|
91
|
+
email: vaultConfig.email,
|
|
92
|
+
serverUrl: vaultConfig.serverUrl,
|
|
93
|
+
});
|
|
94
|
+
const store = new bitwarden_store_1.BitwardenCredentialStore(vaultConfig.serverUrl, vaultConfig.email, unlock.secret, { appDataDir: bitwardenAppDataDir(agentName, vaultConfig) });
|
|
95
|
+
stores.set(cacheKey, store);
|
|
96
|
+
(0, runtime_1.emitNervesEvent)({
|
|
97
|
+
event: "repertoire.credential_store_init",
|
|
98
|
+
component: "repertoire",
|
|
99
|
+
message: "credential store initialized",
|
|
100
|
+
meta: {
|
|
101
|
+
backend: "bitwarden",
|
|
102
|
+
agentName,
|
|
103
|
+
serverUrl: vaultConfig.serverUrl,
|
|
104
|
+
email: vaultConfig.email,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
return store;
|
|
108
|
+
}
|
|
109
|
+
function resetCredentialStore() {
|
|
110
|
+
stores = new Map();
|
|
111
|
+
}
|