@ouro.bot/cli 0.1.0-alpha.35 → 0.1.0-alpha.350
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 +188 -187
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +2088 -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 +832 -0
- package/dist/heart/agent-entry.js +37 -2
- 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 +463 -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 +53 -21
- package/dist/heart/core.js +744 -252
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +561 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +170 -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 +591 -0
- package/dist/heart/daemon/cli-exec.js +2633 -0
- package/dist/heart/daemon/cli-help.js +306 -0
- package/dist/heart/daemon/cli-parse.js +913 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +512 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +30 -1171
- package/dist/heart/daemon/daemon-entry.js +358 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +157 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +751 -58
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +465 -0
- package/dist/heart/daemon/health-monitor.js +79 -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/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +91 -0
- package/dist/heart/daemon/launchd.js +46 -9
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -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 +1 -1
- package/dist/heart/daemon/process-manager.js +201 -0
- package/dist/heart/daemon/provider-discovery.js +105 -0
- package/dist/heart/daemon/pulse.js +463 -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 +101 -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 +72 -3
- 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 +237 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +135 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -120
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
- package/dist/heart/{daemon → hatch}/specialist-tools.js +56 -10
- package/dist/heart/identity.js +154 -59
- 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/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -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 +28 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +194 -0
- package/dist/heart/outlook/readers/agent-machine.js +355 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/runtime-readers.js +660 -0
- package/dist/heart/outlook/readers/sessions.js +231 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-attempt.js +133 -0
- package/dist/heart/provider-binding-resolver.js +240 -0
- package/dist/heart/provider-credential-pool.js +395 -0
- package/dist/heart/provider-failover.js +135 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +258 -0
- package/dist/heart/provider-state.js +208 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +171 -50
- package/dist/heart/providers/azure.js +97 -11
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +135 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +23 -6
- package/dist/heart/providers/openai-codex.js +33 -23
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +727 -0
- package/dist/heart/session-transcript.js +162 -0
- package/dist/heart/start-of-turn-packet.js +341 -0
- package/dist/heart/streaming.js +36 -27
- 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 +358 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +296 -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 +12 -2
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +140 -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 +14 -1
- package/dist/mind/friends/channel.js +56 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +38 -1
- package/dist/mind/friends/store-file.js +58 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +9 -1
- 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 +74 -7
- package/dist/mind/prompt.js +1000 -112
- 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 +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/file-completeness.js +83 -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-LwChZTgL.css +1 -0
- package/dist/outlook-ui/assets/index-xTdv64BV.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- 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 +319 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -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 +527 -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 +375 -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 +28 -10
- 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 +316 -0
- package/dist/repertoire/tools-base.js +45 -771
- package/dist/repertoire/tools-bluebubbles.js +1 -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 +182 -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-notes.js +376 -0
- package/dist/repertoire/tools-session.js +739 -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 +12 -62
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +110 -0
- package/dist/repertoire/tools.js +144 -138
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +118 -0
- package/dist/repertoire/vault-setup.js +241 -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 → bluebubbles/client.js} +225 -9
- package/dist/senses/bluebubbles/entry.js +13 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1590 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +43 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- 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 +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 +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +603 -246
- package/dist/senses/commands.js +65 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +633 -86
- package/dist/senses/pipeline.js +567 -0
- package/dist/senses/shared-turn.js +199 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams.js +665 -160
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +29 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +110 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +81 -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 -134
- package/dist/mind/associative-recall.js +0 -197
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -548
- package/dist/senses/debug-activity.js +0 -127
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /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,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeProviderLane = normalizeProviderLane;
|
|
4
|
+
exports.resolveEffectiveProviderBinding = resolveEffectiveProviderBinding;
|
|
5
|
+
const runtime_1 = require("../nerves/runtime");
|
|
6
|
+
const provider_credential_pool_1 = require("./provider-credential-pool");
|
|
7
|
+
const provider_state_1 = require("./provider-state");
|
|
8
|
+
function legacyLaneWarning(selector, lane) {
|
|
9
|
+
return {
|
|
10
|
+
code: "legacy-lane-selector",
|
|
11
|
+
message: `${selector} is legacy provider wording; using ${lane} lane`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function normalizeProviderLane(selector) {
|
|
15
|
+
switch (selector) {
|
|
16
|
+
case "outward":
|
|
17
|
+
return { lane: "outward", warnings: [] };
|
|
18
|
+
case "inner":
|
|
19
|
+
return { lane: "inner", warnings: [] };
|
|
20
|
+
case "human":
|
|
21
|
+
case "humanFacing":
|
|
22
|
+
return { lane: "outward", warnings: [legacyLaneWarning(selector, "outward")] };
|
|
23
|
+
case "agent":
|
|
24
|
+
case "agentFacing":
|
|
25
|
+
return { lane: "inner", warnings: [legacyLaneWarning(selector, "inner")] };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function buildUseRepair(agentName, lane, force = false) {
|
|
29
|
+
return {
|
|
30
|
+
command: `ouro use --agent ${agentName} --lane ${lane} --provider <provider> --model <model>${force ? " --force" : ""}`,
|
|
31
|
+
message: force
|
|
32
|
+
? `Rewrite this machine's ${lane} provider binding for ${agentName}.`
|
|
33
|
+
: `Choose the provider/model this machine should use for ${agentName}'s ${lane} lane.`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function buildAuthRepair(agentName, provider) {
|
|
37
|
+
return {
|
|
38
|
+
command: `ouro auth --agent ${agentName} --provider ${provider}`,
|
|
39
|
+
message: `Authenticate ${provider} once for this machine's shared credential pool.`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function missingProviderStateWarning(agentName) {
|
|
43
|
+
return {
|
|
44
|
+
code: "provider-state-missing",
|
|
45
|
+
message: `No local provider binding exists for ${agentName} on this machine.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function invalidProviderStateWarning(agentName) {
|
|
49
|
+
return {
|
|
50
|
+
code: "provider-state-invalid",
|
|
51
|
+
message: `Local provider binding state for ${agentName} is invalid.`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function missingCredentialWarning(provider) {
|
|
55
|
+
return {
|
|
56
|
+
code: "credential-missing",
|
|
57
|
+
message: `${provider} has no credential record in the machine credential pool.`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function invalidCredentialPoolWarning(provider) {
|
|
61
|
+
return {
|
|
62
|
+
code: "credential-pool-invalid",
|
|
63
|
+
message: `${provider} cannot read credentials because the machine credential pool is invalid.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function presentCredential(record) {
|
|
67
|
+
return {
|
|
68
|
+
status: "present",
|
|
69
|
+
provider: record.provider,
|
|
70
|
+
revision: record.revision,
|
|
71
|
+
source: record.provenance.source,
|
|
72
|
+
contributedByAgent: record.provenance.contributedByAgent,
|
|
73
|
+
updatedAt: record.updatedAt,
|
|
74
|
+
credentialFields: Object.keys(record.credentials).sort(),
|
|
75
|
+
configFields: Object.keys(record.config).sort(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function resolveCredential(poolResult, provider, agentName) {
|
|
79
|
+
if (poolResult.ok) {
|
|
80
|
+
const record = poolResult.pool.providers[provider];
|
|
81
|
+
if (record)
|
|
82
|
+
return { credential: presentCredential(record), warnings: [] };
|
|
83
|
+
return {
|
|
84
|
+
credential: {
|
|
85
|
+
status: "missing",
|
|
86
|
+
provider,
|
|
87
|
+
poolPath: poolResult.poolPath,
|
|
88
|
+
repair: buildAuthRepair(agentName, provider),
|
|
89
|
+
},
|
|
90
|
+
warnings: [missingCredentialWarning(provider)],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (poolResult.reason === "invalid") {
|
|
94
|
+
return {
|
|
95
|
+
credential: {
|
|
96
|
+
status: "invalid-pool",
|
|
97
|
+
provider,
|
|
98
|
+
poolPath: poolResult.poolPath,
|
|
99
|
+
error: poolResult.error,
|
|
100
|
+
repair: buildAuthRepair(agentName, provider),
|
|
101
|
+
},
|
|
102
|
+
warnings: [invalidCredentialPoolWarning(provider)],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
credential: {
|
|
107
|
+
status: "missing",
|
|
108
|
+
provider,
|
|
109
|
+
poolPath: poolResult.poolPath,
|
|
110
|
+
repair: buildAuthRepair(agentName, provider),
|
|
111
|
+
},
|
|
112
|
+
warnings: [missingCredentialWarning(provider)],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function readinessFromState(readiness) {
|
|
116
|
+
return {
|
|
117
|
+
status: readiness.status,
|
|
118
|
+
checkedAt: readiness.checkedAt,
|
|
119
|
+
credentialRevision: readiness.credentialRevision,
|
|
120
|
+
error: readiness.error,
|
|
121
|
+
attempts: readiness.attempts,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function staleReadiness(readiness, reason) {
|
|
125
|
+
return {
|
|
126
|
+
...readinessFromState(readiness),
|
|
127
|
+
status: "stale",
|
|
128
|
+
previousStatus: readiness.status,
|
|
129
|
+
reason,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function resolveReadiness(input) {
|
|
133
|
+
if (!input.readiness) {
|
|
134
|
+
if (input.credential.status === "missing") {
|
|
135
|
+
return { readiness: { status: "unknown", reason: "credential-missing" }, warnings: [] };
|
|
136
|
+
}
|
|
137
|
+
if (input.credential.status === "invalid-pool") {
|
|
138
|
+
return { readiness: { status: "unknown", reason: "credential-pool-invalid" }, warnings: [] };
|
|
139
|
+
}
|
|
140
|
+
return { readiness: { status: "unknown" }, warnings: [] };
|
|
141
|
+
}
|
|
142
|
+
if (input.readiness.provider !== input.provider || input.readiness.model !== input.model) {
|
|
143
|
+
return {
|
|
144
|
+
readiness: staleReadiness(input.readiness, "provider-model-changed"),
|
|
145
|
+
warnings: [{
|
|
146
|
+
code: "readiness-stale",
|
|
147
|
+
message: `${input.provider}/${input.model} readiness is stale because the last check was for ${input.readiness.provider}/${input.readiness.model}.`,
|
|
148
|
+
}],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (input.credential.status === "present"
|
|
152
|
+
&& input.readiness.credentialRevision !== undefined
|
|
153
|
+
&& input.readiness.credentialRevision !== input.credential.revision) {
|
|
154
|
+
return {
|
|
155
|
+
readiness: staleReadiness(input.readiness, "credential-revision-changed"),
|
|
156
|
+
warnings: [{
|
|
157
|
+
code: "readiness-stale",
|
|
158
|
+
message: `${input.provider}/${input.model} readiness is stale because credential revision changed from ${input.readiness.credentialRevision} to ${input.credential.revision}.`,
|
|
159
|
+
}],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (input.credential.status === "missing") {
|
|
163
|
+
return {
|
|
164
|
+
readiness: staleReadiness(input.readiness, "credential-missing"),
|
|
165
|
+
warnings: [],
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
if (input.credential.status === "invalid-pool") {
|
|
169
|
+
return {
|
|
170
|
+
readiness: staleReadiness(input.readiness, "credential-pool-invalid"),
|
|
171
|
+
warnings: [],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return { readiness: readinessFromState(input.readiness), warnings: [] };
|
|
175
|
+
}
|
|
176
|
+
function resolveEffectiveProviderBinding(input) {
|
|
177
|
+
const laneResolution = normalizeProviderLane(input.lane);
|
|
178
|
+
const stateResult = (0, provider_state_1.readProviderState)(input.agentRoot);
|
|
179
|
+
if (!stateResult.ok) {
|
|
180
|
+
const reason = stateResult.reason === "missing" ? "provider-state-missing" : "provider-state-invalid";
|
|
181
|
+
const stateWarning = stateResult.reason === "missing"
|
|
182
|
+
? missingProviderStateWarning(input.agentName)
|
|
183
|
+
: invalidProviderStateWarning(input.agentName);
|
|
184
|
+
const result = {
|
|
185
|
+
ok: false,
|
|
186
|
+
lane: laneResolution.lane,
|
|
187
|
+
reason,
|
|
188
|
+
statePath: stateResult.statePath,
|
|
189
|
+
warnings: [...laneResolution.warnings, stateWarning],
|
|
190
|
+
repair: buildUseRepair(input.agentName, laneResolution.lane, stateResult.reason === "invalid"),
|
|
191
|
+
};
|
|
192
|
+
(0, runtime_1.emitNervesEvent)({
|
|
193
|
+
component: "config/identity",
|
|
194
|
+
event: "config.provider_binding_resolution_failed",
|
|
195
|
+
message: "provider binding resolution failed",
|
|
196
|
+
meta: { agentName: input.agentName, lane: laneResolution.lane, reason },
|
|
197
|
+
});
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
const laneBinding = stateResult.state.lanes[laneResolution.lane];
|
|
201
|
+
const poolResult = (0, provider_credential_pool_1.readProviderCredentialPool)(input.homeDir);
|
|
202
|
+
const credentialResult = resolveCredential(poolResult, laneBinding.provider, input.agentName);
|
|
203
|
+
const readinessResult = resolveReadiness({
|
|
204
|
+
provider: laneBinding.provider,
|
|
205
|
+
model: laneBinding.model,
|
|
206
|
+
readiness: stateResult.state.readiness[laneResolution.lane],
|
|
207
|
+
credential: credentialResult.credential,
|
|
208
|
+
});
|
|
209
|
+
const warnings = [
|
|
210
|
+
...laneResolution.warnings,
|
|
211
|
+
...credentialResult.warnings,
|
|
212
|
+
...readinessResult.warnings,
|
|
213
|
+
];
|
|
214
|
+
const binding = {
|
|
215
|
+
lane: laneResolution.lane,
|
|
216
|
+
provider: laneBinding.provider,
|
|
217
|
+
model: laneBinding.model,
|
|
218
|
+
source: laneBinding.source,
|
|
219
|
+
machineId: stateResult.state.machineId,
|
|
220
|
+
statePath: stateResult.statePath,
|
|
221
|
+
credential: credentialResult.credential,
|
|
222
|
+
readiness: readinessResult.readiness,
|
|
223
|
+
warnings,
|
|
224
|
+
};
|
|
225
|
+
(0, runtime_1.emitNervesEvent)({
|
|
226
|
+
component: "config/identity",
|
|
227
|
+
event: "config.provider_binding_resolved",
|
|
228
|
+
message: "resolved effective provider binding",
|
|
229
|
+
meta: {
|
|
230
|
+
agentName: input.agentName,
|
|
231
|
+
lane: binding.lane,
|
|
232
|
+
provider: binding.provider,
|
|
233
|
+
model: binding.model,
|
|
234
|
+
credentialStatus: binding.credential.status,
|
|
235
|
+
readinessStatus: binding.readiness.status,
|
|
236
|
+
warningCount: warnings.length,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
return { ok: true, binding };
|
|
240
|
+
}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.splitProviderCredentialFields = splitProviderCredentialFields;
|
|
37
|
+
exports.getProviderCredentialPoolPath = getProviderCredentialPoolPath;
|
|
38
|
+
exports.providerCredentialHomeDirFromSecretsRoot = providerCredentialHomeDirFromSecretsRoot;
|
|
39
|
+
exports.validateProviderCredentialPool = validateProviderCredentialPool;
|
|
40
|
+
exports.readProviderCredentialPool = readProviderCredentialPool;
|
|
41
|
+
exports.writeProviderCredentialPool = writeProviderCredentialPool;
|
|
42
|
+
exports.upsertProviderCredential = upsertProviderCredential;
|
|
43
|
+
exports.redactProviderCredentialPool = redactProviderCredentialPool;
|
|
44
|
+
exports.summarizeProviderCredentialPool = summarizeProviderCredentialPool;
|
|
45
|
+
exports.readLegacyAgentProviderCredentials = readLegacyAgentProviderCredentials;
|
|
46
|
+
exports.migrateLegacyAgentProviderCredentials = migrateLegacyAgentProviderCredentials;
|
|
47
|
+
const crypto = __importStar(require("crypto"));
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const os = __importStar(require("os"));
|
|
50
|
+
const path = __importStar(require("path"));
|
|
51
|
+
const runtime_1 = require("../nerves/runtime");
|
|
52
|
+
const VALID_PROVIDERS = ["azure", "minimax", "anthropic", "openai-codex", "github-copilot"];
|
|
53
|
+
const VALID_PROVENANCE_SOURCES = ["auth-flow", "legacy-agent-secrets", "manual"];
|
|
54
|
+
const PROVIDER_FIELD_SPLITS = {
|
|
55
|
+
anthropic: {
|
|
56
|
+
credentials: ["setupToken", "refreshToken", "expiresAt"],
|
|
57
|
+
config: [],
|
|
58
|
+
meaningfulCredentials: ["setupToken", "refreshToken"],
|
|
59
|
+
},
|
|
60
|
+
"openai-codex": {
|
|
61
|
+
credentials: ["oauthAccessToken"],
|
|
62
|
+
config: [],
|
|
63
|
+
meaningfulCredentials: ["oauthAccessToken"],
|
|
64
|
+
},
|
|
65
|
+
azure: {
|
|
66
|
+
credentials: ["apiKey"],
|
|
67
|
+
config: ["endpoint", "deployment", "apiVersion", "managedIdentityClientId"],
|
|
68
|
+
meaningfulCredentials: ["apiKey", "managedIdentityClientId"],
|
|
69
|
+
},
|
|
70
|
+
minimax: {
|
|
71
|
+
credentials: ["apiKey"],
|
|
72
|
+
config: [],
|
|
73
|
+
meaningfulCredentials: ["apiKey"],
|
|
74
|
+
},
|
|
75
|
+
"github-copilot": {
|
|
76
|
+
credentials: ["githubToken"],
|
|
77
|
+
config: ["baseUrl"],
|
|
78
|
+
meaningfulCredentials: ["githubToken"],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
function isRecord(value) {
|
|
82
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
83
|
+
}
|
|
84
|
+
function isAgentProvider(value) {
|
|
85
|
+
return VALID_PROVIDERS.includes(value);
|
|
86
|
+
}
|
|
87
|
+
function isProvenanceSource(value) {
|
|
88
|
+
return typeof value === "string" && VALID_PROVENANCE_SOURCES.includes(value);
|
|
89
|
+
}
|
|
90
|
+
function isCredentialValue(value) {
|
|
91
|
+
return typeof value === "string" || typeof value === "number";
|
|
92
|
+
}
|
|
93
|
+
function isPresentCredentialValue(value) {
|
|
94
|
+
if (!isCredentialValue(value))
|
|
95
|
+
return false;
|
|
96
|
+
if (typeof value === "string")
|
|
97
|
+
return value.trim().length > 0;
|
|
98
|
+
return Number.isFinite(value) && value !== 0;
|
|
99
|
+
}
|
|
100
|
+
function copyKnownFields(source, fields) {
|
|
101
|
+
const result = {};
|
|
102
|
+
for (const field of fields) {
|
|
103
|
+
const value = source[field];
|
|
104
|
+
if (isPresentCredentialValue(value)) {
|
|
105
|
+
result[field] = value;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
function splitProviderCredentialFields(provider, rawConfig) {
|
|
111
|
+
const fields = PROVIDER_FIELD_SPLITS[provider];
|
|
112
|
+
return {
|
|
113
|
+
credentials: copyKnownFields(rawConfig, fields.credentials),
|
|
114
|
+
config: copyKnownFields(rawConfig, fields.config),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function legacyProviderHasCredentialData(provider, rawConfig) {
|
|
118
|
+
const fields = PROVIDER_FIELD_SPLITS[provider];
|
|
119
|
+
return fields.meaningfulCredentials.some((field) => isPresentCredentialValue(rawConfig[field]));
|
|
120
|
+
}
|
|
121
|
+
function makeEmptyProviderCredentialPool(now) {
|
|
122
|
+
return {
|
|
123
|
+
schemaVersion: 1,
|
|
124
|
+
updatedAt: now.toISOString(),
|
|
125
|
+
providers: {},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function makeRevision() {
|
|
129
|
+
return `cred_${crypto.randomUUID()}`;
|
|
130
|
+
}
|
|
131
|
+
function getProviderCredentialPoolPath(homeDir = os.homedir()) {
|
|
132
|
+
return path.join(homeDir, ".agentsecrets", "providers.json");
|
|
133
|
+
}
|
|
134
|
+
function providerCredentialHomeDirFromSecretsRoot(secretsRoot) {
|
|
135
|
+
if (!secretsRoot)
|
|
136
|
+
return os.homedir();
|
|
137
|
+
return path.basename(secretsRoot) === ".agentsecrets"
|
|
138
|
+
? path.dirname(secretsRoot)
|
|
139
|
+
: secretsRoot;
|
|
140
|
+
}
|
|
141
|
+
function validateProviderCredentialPool(value) {
|
|
142
|
+
if (!isRecord(value)) {
|
|
143
|
+
throw new Error("provider credential pool must be an object");
|
|
144
|
+
}
|
|
145
|
+
if (value.schemaVersion !== 1) {
|
|
146
|
+
throw new Error("provider credential pool schemaVersion must be 1");
|
|
147
|
+
}
|
|
148
|
+
if (typeof value.updatedAt !== "string" || value.updatedAt.length === 0) {
|
|
149
|
+
throw new Error("provider credential pool updatedAt must be a non-empty string");
|
|
150
|
+
}
|
|
151
|
+
if (!isRecord(value.providers)) {
|
|
152
|
+
throw new Error("provider credential pool providers must be an object");
|
|
153
|
+
}
|
|
154
|
+
const providers = value.providers;
|
|
155
|
+
for (const [providerKey, rawRecord] of Object.entries(providers)) {
|
|
156
|
+
if (!isAgentProvider(providerKey)) {
|
|
157
|
+
throw new Error(`provider credential pool has unsupported provider ${providerKey}`);
|
|
158
|
+
}
|
|
159
|
+
if (!isRecord(rawRecord)) {
|
|
160
|
+
throw new Error(`${providerKey} credential record must be an object`);
|
|
161
|
+
}
|
|
162
|
+
if (rawRecord.provider !== providerKey) {
|
|
163
|
+
throw new Error(`${providerKey}.provider must match its provider key`);
|
|
164
|
+
}
|
|
165
|
+
if (typeof rawRecord.revision !== "string" || rawRecord.revision.length === 0) {
|
|
166
|
+
throw new Error(`${providerKey}.revision must be a non-empty string`);
|
|
167
|
+
}
|
|
168
|
+
if (typeof rawRecord.updatedAt !== "string" || rawRecord.updatedAt.length === 0) {
|
|
169
|
+
throw new Error(`${providerKey}.updatedAt must be a non-empty string`);
|
|
170
|
+
}
|
|
171
|
+
if (!isRecord(rawRecord.credentials)) {
|
|
172
|
+
throw new Error(`${providerKey}.credentials must be an object`);
|
|
173
|
+
}
|
|
174
|
+
if (!isRecord(rawRecord.config)) {
|
|
175
|
+
throw new Error(`${providerKey}.config must be an object`);
|
|
176
|
+
}
|
|
177
|
+
for (const [field, fieldValue] of Object.entries(rawRecord.credentials)) {
|
|
178
|
+
if (!isCredentialValue(fieldValue)) {
|
|
179
|
+
throw new Error(`${providerKey}.credentials.${field} must be a string or number`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
for (const [field, fieldValue] of Object.entries(rawRecord.config)) {
|
|
183
|
+
if (!isCredentialValue(fieldValue)) {
|
|
184
|
+
throw new Error(`${providerKey}.config.${field} must be a string or number`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (!isRecord(rawRecord.provenance)) {
|
|
188
|
+
throw new Error(`${providerKey}.provenance must be an object`);
|
|
189
|
+
}
|
|
190
|
+
if (!isProvenanceSource(rawRecord.provenance.source)) {
|
|
191
|
+
throw new Error(`${providerKey}.provenance.source must be auth-flow, legacy-agent-secrets, or manual`);
|
|
192
|
+
}
|
|
193
|
+
const contributedByAgent = rawRecord.provenance.contributedByAgent;
|
|
194
|
+
if (contributedByAgent !== undefined && typeof contributedByAgent !== "string") {
|
|
195
|
+
throw new Error(`${providerKey}.provenance.contributedByAgent must be a string when present`);
|
|
196
|
+
}
|
|
197
|
+
if (typeof rawRecord.provenance.updatedAt !== "string" || rawRecord.provenance.updatedAt.length === 0) {
|
|
198
|
+
throw new Error(`${providerKey}.provenance.updatedAt must be a non-empty string`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
function readProviderCredentialPool(homeDir = os.homedir()) {
|
|
204
|
+
const poolPath = getProviderCredentialPoolPath(homeDir);
|
|
205
|
+
try {
|
|
206
|
+
const raw = fs.readFileSync(poolPath, "utf-8");
|
|
207
|
+
const parsed = JSON.parse(raw);
|
|
208
|
+
const pool = validateProviderCredentialPool(parsed);
|
|
209
|
+
(0, runtime_1.emitNervesEvent)({
|
|
210
|
+
component: "config/identity",
|
|
211
|
+
event: "config.provider_credential_pool_read",
|
|
212
|
+
message: "read provider credential pool",
|
|
213
|
+
meta: { poolPath },
|
|
214
|
+
});
|
|
215
|
+
return { ok: true, poolPath, pool };
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (error.code === "ENOENT") {
|
|
219
|
+
(0, runtime_1.emitNervesEvent)({
|
|
220
|
+
component: "config/identity",
|
|
221
|
+
event: "config.provider_credential_pool_missing",
|
|
222
|
+
message: "provider credential pool not found",
|
|
223
|
+
meta: { poolPath },
|
|
224
|
+
});
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
reason: "missing",
|
|
228
|
+
poolPath,
|
|
229
|
+
error: "provider credential pool not found",
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
(0, runtime_1.emitNervesEvent)({
|
|
233
|
+
level: "error",
|
|
234
|
+
component: "config/identity",
|
|
235
|
+
event: "config.provider_credential_pool_invalid",
|
|
236
|
+
message: "provider credential pool invalid",
|
|
237
|
+
meta: { poolPath, reason: String(error) },
|
|
238
|
+
});
|
|
239
|
+
return {
|
|
240
|
+
ok: false,
|
|
241
|
+
reason: "invalid",
|
|
242
|
+
poolPath,
|
|
243
|
+
error: String(error),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function writeProviderCredentialPool(homeDir, pool) {
|
|
248
|
+
const validated = validateProviderCredentialPool(pool);
|
|
249
|
+
const poolPath = getProviderCredentialPoolPath(homeDir);
|
|
250
|
+
fs.mkdirSync(path.dirname(poolPath), { recursive: true });
|
|
251
|
+
fs.writeFileSync(poolPath, `${JSON.stringify(validated, null, 2)}\n`, "utf-8");
|
|
252
|
+
(0, runtime_1.emitNervesEvent)({
|
|
253
|
+
component: "config/identity",
|
|
254
|
+
event: "config.provider_credential_pool_written",
|
|
255
|
+
message: "wrote provider credential pool",
|
|
256
|
+
meta: { poolPath, providerCount: Object.keys(validated.providers).length },
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function upsertProviderCredential(input) {
|
|
260
|
+
const homeDir = input.homeDir ?? os.homedir();
|
|
261
|
+
const now = input.now ?? new Date();
|
|
262
|
+
const updatedAt = now.toISOString();
|
|
263
|
+
const readResult = readProviderCredentialPool(homeDir);
|
|
264
|
+
const pool = readResult.ok ? readResult.pool : makeEmptyProviderCredentialPool(now);
|
|
265
|
+
if (!readResult.ok && readResult.reason === "invalid") {
|
|
266
|
+
throw new Error(`Cannot update invalid provider credential pool at ${readResult.poolPath}: ${readResult.error}`);
|
|
267
|
+
}
|
|
268
|
+
const record = {
|
|
269
|
+
provider: input.provider,
|
|
270
|
+
revision: (input.makeRevision ?? makeRevision)(),
|
|
271
|
+
updatedAt,
|
|
272
|
+
credentials: { ...input.credentials },
|
|
273
|
+
config: { ...input.config },
|
|
274
|
+
provenance: {
|
|
275
|
+
...input.provenance,
|
|
276
|
+
updatedAt,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
pool.updatedAt = updatedAt;
|
|
280
|
+
pool.providers[input.provider] = record;
|
|
281
|
+
writeProviderCredentialPool(homeDir, pool);
|
|
282
|
+
(0, runtime_1.emitNervesEvent)({
|
|
283
|
+
component: "config/identity",
|
|
284
|
+
event: "config.provider_credential_upserted",
|
|
285
|
+
message: "upserted provider credential record",
|
|
286
|
+
meta: { provider: input.provider, revision: record.revision, source: record.provenance.source },
|
|
287
|
+
});
|
|
288
|
+
return record;
|
|
289
|
+
}
|
|
290
|
+
function redactProviderCredentialPool(pool) {
|
|
291
|
+
const validated = validateProviderCredentialPool(pool);
|
|
292
|
+
const providers = {};
|
|
293
|
+
for (const [provider, record] of Object.entries(validated.providers)) {
|
|
294
|
+
const redactedCredentials = {};
|
|
295
|
+
for (const key of Object.keys(record.credentials)) {
|
|
296
|
+
redactedCredentials[key] = "[redacted]";
|
|
297
|
+
}
|
|
298
|
+
providers[provider] = {
|
|
299
|
+
...record,
|
|
300
|
+
credentials: redactedCredentials,
|
|
301
|
+
config: { ...record.config },
|
|
302
|
+
provenance: { ...record.provenance },
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
...validated,
|
|
307
|
+
providers,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function summarizeProviderCredentialPool(pool) {
|
|
311
|
+
const validated = validateProviderCredentialPool(pool);
|
|
312
|
+
return {
|
|
313
|
+
providers: Object.entries(validated.providers).map(([, record]) => ({
|
|
314
|
+
provider: record.provider,
|
|
315
|
+
revision: record.revision,
|
|
316
|
+
source: record.provenance.source,
|
|
317
|
+
contributedByAgent: record.provenance.contributedByAgent,
|
|
318
|
+
updatedAt: record.updatedAt,
|
|
319
|
+
credentialFields: Object.keys(record.credentials).sort(),
|
|
320
|
+
configFields: Object.keys(record.config).sort(),
|
|
321
|
+
})),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function readLegacyAgentProviderCredentials(input) {
|
|
325
|
+
const homeDir = input.homeDir ?? os.homedir();
|
|
326
|
+
const secretsPath = path.join(homeDir, ".agentsecrets", input.agentName, "secrets.json");
|
|
327
|
+
let parsed;
|
|
328
|
+
try {
|
|
329
|
+
parsed = JSON.parse(fs.readFileSync(secretsPath, "utf-8"));
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
if (error.code === "ENOENT") {
|
|
333
|
+
return [];
|
|
334
|
+
}
|
|
335
|
+
throw new Error(`Failed to read legacy provider credentials for ${input.agentName}: ${String(error)}`);
|
|
336
|
+
}
|
|
337
|
+
if (!isRecord(parsed) || !isRecord(parsed.providers)) {
|
|
338
|
+
return [];
|
|
339
|
+
}
|
|
340
|
+
const candidates = [];
|
|
341
|
+
for (const [providerKey, rawProviderConfig] of Object.entries(parsed.providers)) {
|
|
342
|
+
if (!isAgentProvider(providerKey) || !isRecord(rawProviderConfig)) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (!legacyProviderHasCredentialData(providerKey, rawProviderConfig)) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const { credentials, config } = splitProviderCredentialFields(providerKey, rawProviderConfig);
|
|
349
|
+
candidates.push({
|
|
350
|
+
provider: providerKey,
|
|
351
|
+
credentials,
|
|
352
|
+
config,
|
|
353
|
+
provenance: {
|
|
354
|
+
source: "legacy-agent-secrets",
|
|
355
|
+
contributedByAgent: input.agentName,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
(0, runtime_1.emitNervesEvent)({
|
|
360
|
+
component: "config/identity",
|
|
361
|
+
event: "config.provider_credential_legacy_read",
|
|
362
|
+
message: "read legacy provider credential candidates",
|
|
363
|
+
meta: { agentName: input.agentName, providerCount: candidates.length },
|
|
364
|
+
});
|
|
365
|
+
return candidates;
|
|
366
|
+
}
|
|
367
|
+
function migrateLegacyAgentProviderCredentials(input) {
|
|
368
|
+
const homeDir = input.homeDir ?? os.homedir();
|
|
369
|
+
const migrated = [];
|
|
370
|
+
for (const agentName of input.agentNames) {
|
|
371
|
+
const candidates = readLegacyAgentProviderCredentials({ homeDir, agentName });
|
|
372
|
+
for (const candidate of candidates) {
|
|
373
|
+
const record = upsertProviderCredential({
|
|
374
|
+
homeDir,
|
|
375
|
+
provider: candidate.provider,
|
|
376
|
+
credentials: candidate.credentials,
|
|
377
|
+
config: candidate.config,
|
|
378
|
+
provenance: candidate.provenance,
|
|
379
|
+
now: input.now,
|
|
380
|
+
makeRevision: input.makeRevision,
|
|
381
|
+
});
|
|
382
|
+
migrated.push({ agentName, provider: candidate.provider, revision: record.revision });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
(0, runtime_1.emitNervesEvent)({
|
|
386
|
+
component: "config/identity",
|
|
387
|
+
event: "config.provider_credential_legacy_migrated",
|
|
388
|
+
message: "migrated legacy provider credentials",
|
|
389
|
+
meta: { migratedCount: migrated.length },
|
|
390
|
+
});
|
|
391
|
+
return {
|
|
392
|
+
poolPath: getProviderCredentialPoolPath(homeDir),
|
|
393
|
+
migrated,
|
|
394
|
+
};
|
|
395
|
+
}
|