@ouro.bot/cli 0.1.0-alpha.553 → 0.1.0-alpha.555

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.
@@ -108,15 +108,6 @@ const SENSITIVE_CONFIG_KEYS = ["apiKey", "token", "secret", "password"];
108
108
  function credentialKeyLeaks(raw) {
109
109
  return SENSITIVE_CONFIG_KEYS.filter((key) => raw.includes(`"${key}"`));
110
110
  }
111
- function checkCredentialLeak(checks, label, raw) {
112
- const found = credentialKeyLeaks(raw);
113
- if (found.length > 0) {
114
- checks.push({ label, status: "warn", detail: `contains credential-looking keys: ${found.join(", ")}` });
115
- }
116
- else {
117
- checks.push({ label, status: "pass", detail: "no credential keys" });
118
- }
119
- }
120
111
  function checkAgents(deps) {
121
112
  const checks = [];
122
113
  if (!deps.existsSync(deps.bundlesRoot)) {
@@ -368,15 +359,6 @@ function checkSecurity(deps) {
368
359
  checks.push({ label: `${agentDir} credential leak`, status: "fail", detail: "could not read agent.json" });
369
360
  }
370
361
  }
371
- const providerStatePath = `${deps.bundlesRoot}/${agentDir}/state/providers.json`;
372
- if (deps.existsSync(providerStatePath)) {
373
- try {
374
- checkCredentialLeak(checks, `${agentDir} state/providers.json credential leak`, deps.readFileSync(providerStatePath));
375
- }
376
- catch {
377
- checks.push({ label: `${agentDir} state/providers.json credential leak`, status: "fail", detail: "could not read state/providers.json" });
378
- }
379
- }
380
362
  }
381
363
  if (checks.length === 0) {
382
364
  checks.push({ label: "security", status: "warn", detail: "no agents found" });
@@ -74,18 +74,6 @@ function buildInnerStatusOutput(input) {
74
74
  // Attention
75
75
  const thoughtWord = attentionCount === 1 ? "thought" : "thoughts";
76
76
  lines.push(` attention: ${attentionCount} held ${thoughtWord}`);
77
- // Layer 4 drift advisory. Renders one line per finding with the
78
- // lane, intent vs observed binding, and the copy-pasteable repair
79
- // command. Suppressed entirely when no findings exist (or the field
80
- // is absent — pre-Layer-4 callers).
81
- const driftFindings = input.driftFindings ?? [];
82
- if (driftFindings.length > 0) {
83
- lines.push(" drift advisory:");
84
- for (const finding of driftFindings) {
85
- lines.push(` - ${finding.lane}: intent ${finding.intentProvider}/${finding.intentModel} vs observed ${finding.observedProvider}/${finding.observedModel}`);
86
- lines.push(` repair: ${finding.repairCommand}`);
87
- }
88
- }
89
77
  (0, runtime_1.emitNervesEvent)({
90
78
  component: "daemon",
91
79
  event: "daemon.inner_status_read",
@@ -95,7 +83,6 @@ function buildInnerStatusOutput(input) {
95
83
  status: runtimeState?.status ?? "unknown",
96
84
  journalCount: journalFiles.length,
97
85
  attentionCount,
98
- driftCount: driftFindings.length,
99
86
  },
100
87
  });
101
88
  return lines.join("\n");
@@ -44,9 +44,6 @@ const runtime_1 = require("../../nerves/runtime");
44
44
  const auth_flow_1 = require("../auth/auth-flow");
45
45
  const provider_models_1 = require("../provider-models");
46
46
  const habit_parser_1 = require("../habits/habit-parser");
47
- const machine_identity_1 = require("../machine-identity");
48
- const provider_credentials_1 = require("../provider-credentials");
49
- const provider_state_1 = require("../provider-state");
50
47
  const hatch_specialist_1 = require("./hatch-specialist");
51
48
  function requiredCredentialKeys(provider) {
52
49
  return identity_1.PROVIDER_CREDENTIALS[provider].required;
@@ -134,22 +131,6 @@ function writeHatchlingAgentConfig(bundleRoot, input) {
134
131
  template.enabled = true;
135
132
  fs.writeFileSync(path.join(bundleRoot, "agent.json"), `${JSON.stringify(template, null, 2)}\n`, "utf-8");
136
133
  }
137
- function writeHatchlingProviderState(bundleRoot, input, now) {
138
- const model = (0, provider_models_1.getDefaultModelForProvider)(input.provider);
139
- const machine = (0, machine_identity_1.loadOrCreateMachineIdentity)({
140
- homeDir: (0, provider_credentials_1.providerCredentialMachineHomeDir)(),
141
- now: () => now,
142
- });
143
- const state = (0, provider_state_1.bootstrapProviderStateFromAgentConfig)({
144
- machineId: machine.machineId,
145
- now,
146
- agentConfig: {
147
- humanFacing: { provider: input.provider, model },
148
- agentFacing: { provider: input.provider, model },
149
- },
150
- });
151
- (0, provider_state_1.writeProviderState)(bundleRoot, state);
152
- }
153
134
  async function runHatchFlow(input, deps = {}) {
154
135
  (0, runtime_1.emitNervesEvent)({
155
136
  component: "daemon",
@@ -186,7 +167,6 @@ async function runHatchFlow(input, deps = {}) {
186
167
  writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
187
168
  writeHatchlingAgentConfig(bundleRoot, input);
188
169
  const credentialPath = await storeHatchlingProviderCredentials(input.agentName, input.provider, input.credentials);
189
- writeHatchlingProviderState(bundleRoot, input, now);
190
170
  writeDiaryScaffold(bundleRoot);
191
171
  writeFriendImprint(bundleRoot, input.humanName, now);
192
172
  writeHeartbeatHabit(bundleRoot, now);
@@ -1,16 +1,55 @@
1
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
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.normalizeProviderLane = normalizeProviderLane;
4
37
  exports.resolveEffectiveProviderBinding = resolveEffectiveProviderBinding;
38
+ const path = __importStar(require("path"));
5
39
  const runtime_1 = require("../nerves/runtime");
40
+ const identity_1 = require("./identity");
41
+ const auth_flow_1 = require("./auth/auth-flow");
6
42
  const provider_credentials_1 = require("./provider-credentials");
7
- const provider_state_1 = require("./provider-state");
43
+ const provider_readiness_cache_1 = require("./provider-readiness-cache");
8
44
  function legacyLaneWarning(selector, lane) {
9
45
  return {
10
46
  code: "legacy-lane-selector",
11
47
  message: `${selector} is legacy provider wording; using ${lane} lane`,
12
48
  };
13
49
  }
50
+ function facingKeyForProviderLane(lane) {
51
+ return lane === "outward" ? "humanFacing" : "agentFacing";
52
+ }
14
53
  function normalizeProviderLane(selector) {
15
54
  switch (selector) {
16
55
  case "outward":
@@ -25,12 +64,10 @@ function normalizeProviderLane(selector) {
25
64
  return { lane: "inner", warnings: [legacyLaneWarning(selector, "inner")] };
26
65
  }
27
66
  }
28
- function buildUseRepair(agentName, lane, force = false) {
67
+ function buildUseRepair(agentName, lane) {
29
68
  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.`,
69
+ command: `ouro use --agent ${agentName} --lane ${lane} --provider <provider> --model <model>`,
70
+ message: `Choose the provider/model ${agentName}'s ${lane} lane should use in agent.json.`,
34
71
  };
35
72
  }
36
73
  function buildAuthRepair(agentName, provider) {
@@ -39,16 +76,10 @@ function buildAuthRepair(agentName, provider) {
39
76
  message: `Store ${provider} credentials in ${agentName}'s vault.`,
40
77
  };
41
78
  }
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) {
79
+ function invalidAgentConfigWarning(agentName, error) {
49
80
  return {
50
- code: "provider-state-invalid",
51
- message: `Local provider binding state for ${agentName} is invalid.`,
81
+ code: "agent-config-invalid",
82
+ message: `agent.json provider selection for ${agentName} is invalid: ${error}`,
52
83
  };
53
84
  }
54
85
  function missingCredentialWarning(provider) {
@@ -121,120 +152,101 @@ function resolveCredential(poolResult, provider, agentName) {
121
152
  warnings: [missingCredentialWarning(provider)],
122
153
  };
123
154
  }
124
- function readinessFromState(readiness) {
125
- return {
126
- status: readiness.status,
127
- checkedAt: readiness.checkedAt,
128
- credentialRevision: readiness.credentialRevision,
129
- error: readiness.error,
130
- attempts: readiness.attempts,
131
- };
155
+ function resolveReadiness(agentName, lane, provider, model, credential) {
156
+ if (credential.status === "missing") {
157
+ return { status: "unknown", reason: "credential-missing" };
158
+ }
159
+ if (credential.status === "invalid-pool") {
160
+ return { status: "unknown", reason: "credential-pool-invalid" };
161
+ }
162
+ if (credential.status === "present") {
163
+ const cached = (0, provider_readiness_cache_1.readProviderLaneReadiness)({
164
+ agentName,
165
+ lane,
166
+ provider,
167
+ model,
168
+ credentialRevision: credential.revision,
169
+ });
170
+ if (cached) {
171
+ return {
172
+ status: cached.status,
173
+ checkedAt: cached.checkedAt,
174
+ ...(cached.error ? { error: cached.error } : {}),
175
+ ...(cached.attempts !== undefined ? { attempts: cached.attempts } : {}),
176
+ };
177
+ }
178
+ }
179
+ return { status: "unknown" };
132
180
  }
133
- function staleReadiness(readiness, reason) {
134
- return {
135
- ...readinessFromState(readiness),
136
- status: "stale",
137
- previousStatus: readiness.status,
138
- reason,
139
- };
181
+ function isAgentProvider(value) {
182
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
140
183
  }
141
- function resolveReadiness(input) {
142
- if (!input.readiness) {
143
- if (input.credential.status === "not-loaded") {
144
- return { readiness: { status: "unknown" }, warnings: [] };
145
- }
146
- if (input.credential.status === "missing") {
147
- return { readiness: { status: "unknown", reason: "credential-missing" }, warnings: [] };
184
+ function resolveAgentConfigLane(input, lane) {
185
+ const configPath = path.join(input.agentRoot, "agent.json");
186
+ try {
187
+ const { config, configPath: resolvedConfigPath } = (0, auth_flow_1.readAgentConfigForAgent)(input.agentName, path.dirname(input.agentRoot));
188
+ const facingKey = facingKeyForProviderLane(lane);
189
+ const binding = config[facingKey];
190
+ /* v8 ignore next -- readAgentConfigForAgent rejects unsupported providers before this defensive guard @preserve */
191
+ if (!isAgentProvider(binding.provider)) {
192
+ return { ok: false, configPath: resolvedConfigPath, error: `${facingKey}.provider must be a supported provider` };
148
193
  }
149
- if (input.credential.status === "invalid-pool") {
150
- return { readiness: { status: "unknown", reason: "credential-pool-invalid" }, warnings: [] };
194
+ const model = typeof binding.model === "string" ? binding.model.trim() : "";
195
+ if (model.length === 0) {
196
+ return { ok: false, configPath: resolvedConfigPath, error: `${facingKey}.model must be a non-empty string` };
151
197
  }
152
- return { readiness: { status: "unknown" }, warnings: [] };
153
- }
154
- if (input.readiness.provider !== input.provider || input.readiness.model !== input.model) {
155
198
  return {
156
- readiness: staleReadiness(input.readiness, "provider-model-changed"),
157
- warnings: [{
158
- code: "readiness-stale",
159
- message: `${input.provider}/${input.model} readiness is stale because the last check was for ${input.readiness.provider}/${input.readiness.model}.`,
160
- }],
161
- };
162
- }
163
- if (input.credential.status === "present"
164
- && input.readiness.credentialRevision !== undefined
165
- && input.readiness.credentialRevision !== input.credential.revision) {
166
- return {
167
- readiness: staleReadiness(input.readiness, "credential-revision-changed"),
168
- warnings: [{
169
- code: "readiness-stale",
170
- message: `${input.provider}/${input.model} readiness is stale because credential revision changed from ${input.readiness.credentialRevision} to ${input.credential.revision}.`,
171
- }],
172
- };
173
- }
174
- if (input.credential.status === "missing") {
175
- return {
176
- readiness: staleReadiness(input.readiness, "credential-missing"),
177
- warnings: [],
199
+ ok: true,
200
+ configPath: resolvedConfigPath,
201
+ provider: binding.provider,
202
+ model,
178
203
  };
179
204
  }
180
- if (input.credential.status === "invalid-pool") {
205
+ catch (error) {
181
206
  return {
182
- readiness: staleReadiness(input.readiness, "credential-pool-invalid"),
183
- warnings: [],
207
+ ok: false,
208
+ configPath,
209
+ /* v8 ignore next -- readAgentConfigForAgent/file IO failures are Error instances in supported runtimes @preserve */
210
+ error: error instanceof Error ? error.message : String(error),
184
211
  };
185
212
  }
186
- if (input.credential.status === "not-loaded") {
187
- return { readiness: readinessFromState(input.readiness), warnings: [] };
188
- }
189
- return { readiness: readinessFromState(input.readiness), warnings: [] };
190
213
  }
191
214
  function resolveEffectiveProviderBinding(input) {
192
215
  const laneResolution = normalizeProviderLane(input.lane);
193
- const stateResult = (0, provider_state_1.readProviderState)(input.agentRoot);
194
- if (!stateResult.ok) {
195
- const reason = stateResult.reason === "missing" ? "provider-state-missing" : "provider-state-invalid";
196
- const stateWarning = stateResult.reason === "missing"
197
- ? missingProviderStateWarning(input.agentName)
198
- : invalidProviderStateWarning(input.agentName);
216
+ const agentConfigResult = resolveAgentConfigLane(input, laneResolution.lane);
217
+ if (!agentConfigResult.ok) {
199
218
  const result = {
200
219
  ok: false,
201
220
  lane: laneResolution.lane,
202
- reason,
203
- statePath: stateResult.statePath,
204
- warnings: [...laneResolution.warnings, stateWarning],
205
- repair: buildUseRepair(input.agentName, laneResolution.lane, stateResult.reason === "invalid"),
221
+ reason: "agent-config-invalid",
222
+ configPath: agentConfigResult.configPath,
223
+ error: agentConfigResult.error,
224
+ warnings: [...laneResolution.warnings, invalidAgentConfigWarning(input.agentName, agentConfigResult.error)],
225
+ repair: buildUseRepair(input.agentName, laneResolution.lane),
206
226
  };
207
227
  (0, runtime_1.emitNervesEvent)({
208
228
  component: "config/identity",
209
229
  event: "config.provider_binding_resolution_failed",
210
230
  message: "provider binding resolution failed",
211
- meta: { agentName: input.agentName, lane: laneResolution.lane, reason },
231
+ meta: { agentName: input.agentName, lane: laneResolution.lane, reason: result.reason },
212
232
  });
213
233
  return result;
214
234
  }
215
- const laneBinding = stateResult.state.lanes[laneResolution.lane];
216
235
  const poolResult = (0, provider_credentials_1.readProviderCredentialPool)(input.agentName);
217
- const credentialResult = resolveCredential(poolResult, laneBinding.provider, input.agentName);
218
- const readinessResult = resolveReadiness({
219
- provider: laneBinding.provider,
220
- model: laneBinding.model,
221
- readiness: stateResult.state.readiness[laneResolution.lane],
222
- credential: credentialResult.credential,
223
- });
236
+ const credentialResult = resolveCredential(poolResult, agentConfigResult.provider, input.agentName);
237
+ const readiness = resolveReadiness(input.agentName, laneResolution.lane, agentConfigResult.provider, agentConfigResult.model, credentialResult.credential);
224
238
  const warnings = [
225
239
  ...laneResolution.warnings,
226
240
  ...credentialResult.warnings,
227
- ...readinessResult.warnings,
228
241
  ];
229
242
  const binding = {
230
243
  lane: laneResolution.lane,
231
- provider: laneBinding.provider,
232
- model: laneBinding.model,
233
- source: laneBinding.source,
234
- machineId: stateResult.state.machineId,
235
- statePath: stateResult.statePath,
244
+ provider: agentConfigResult.provider,
245
+ model: agentConfigResult.model,
246
+ source: "agent.json",
247
+ configPath: agentConfigResult.configPath,
236
248
  credential: credentialResult.credential,
237
- readiness: readinessResult.readiness,
249
+ readiness,
238
250
  warnings,
239
251
  };
240
252
  (0, runtime_1.emitNervesEvent)({
@@ -372,13 +372,13 @@ async function upsertProviderCredential(input) {
372
372
  password: JSON.stringify(payload),
373
373
  notes: "Ouro provider credentials. The vault item password is a versioned JSON payload.",
374
374
  });
375
- input.onProgress?.(`refreshing local provider snapshot from ${input.agentName}'s vault...`);
375
+ input.onProgress?.(`refreshing in-memory provider credential pool from ${input.agentName}'s vault...`);
376
376
  const refreshResult = await refreshProviderCredentialPool(input.agentName, {
377
377
  providers: [input.provider],
378
378
  onProgress: input.onProgress,
379
379
  });
380
380
  if (!refreshResult.ok) {
381
- throw new Error(`credential stored in vault, but the local provider snapshot could not be refreshed: ${refreshResult.error}. ` +
381
+ throw new Error(`credential stored in vault, but the in-memory provider credential pool could not be refreshed: ${refreshResult.error}. ` +
382
382
  `Run 'ouro provider refresh --agent ${input.agentName}' after fixing vault access, then run 'ouro auth verify --agent ${input.agentName}'.`);
383
383
  }
384
384
  (0, runtime_1.emitNervesEvent)({
@@ -268,7 +268,7 @@ async function runMachineProviderFailoverInventory(agentName, currentProvider, o
268
268
  }
269
269
  /**
270
270
  * Re-verify a failover candidate is actually reachable right before we mutate
271
- * provider state. The inventory ping that produced the candidate may be stale
271
+ * agent.json. The inventory ping that produced the candidate may be stale
272
272
  * (creds revoked between inventory and reply); without this preflight, an
273
273
  * agent-driven "switch to <provider>" can move the lane onto an unreachable
274
274
  * provider and brick the next turn.
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.recordProviderLaneReadiness = recordProviderLaneReadiness;
4
+ exports.readProviderLaneReadiness = readProviderLaneReadiness;
5
+ exports.clearProviderReadinessCache = clearProviderReadinessCache;
6
+ const runtime_1 = require("../nerves/runtime");
7
+ const readinessByLane = new Map();
8
+ function cacheKey(agentName, lane) {
9
+ return `${agentName}\0${lane}`;
10
+ }
11
+ function recordProviderLaneReadiness(entry) {
12
+ readinessByLane.set(cacheKey(entry.agentName, entry.lane), { ...entry });
13
+ (0, runtime_1.emitNervesEvent)({
14
+ component: "config/identity",
15
+ event: "config.provider_readiness_recorded",
16
+ message: "recorded in-memory provider readiness",
17
+ meta: {
18
+ agentName: entry.agentName,
19
+ lane: entry.lane,
20
+ provider: entry.provider,
21
+ model: entry.model,
22
+ status: entry.status,
23
+ },
24
+ });
25
+ }
26
+ function readProviderLaneReadiness(input) {
27
+ const entry = readinessByLane.get(cacheKey(input.agentName, input.lane));
28
+ if (!entry)
29
+ return null;
30
+ if (entry.provider !== input.provider)
31
+ return null;
32
+ if (entry.model !== input.model)
33
+ return null;
34
+ if (entry.credentialRevision !== input.credentialRevision)
35
+ return null;
36
+ return { ...entry };
37
+ }
38
+ function clearProviderReadinessCache() {
39
+ readinessByLane.clear();
40
+ }
@@ -128,12 +128,12 @@ function formatProviderVisibilityLine(lane) {
128
128
  function formatAgentProviderVisibilityForPrompt(visibility) {
129
129
  if (visibility.lanes.every((lane) => lane.status === "unconfigured")) {
130
130
  return [
131
- "provider bindings are not configured on this machine.",
131
+ "provider bindings are not configured in agent.json.",
132
132
  ...visibility.lanes.map((lane) => `- ${formatProviderVisibilityLine(lane)}`),
133
133
  ].join("\n");
134
134
  }
135
135
  return [
136
- "runtime uses local provider bindings for this machine:",
136
+ "runtime uses provider bindings from agent.json:",
137
137
  ...visibility.lanes.map((lane) => `- ${formatProviderVisibilityLine(lane)}`),
138
138
  ].join("\n");
139
139
  }
@@ -228,7 +228,7 @@ function renderStartOfTurnPacket(packet) {
228
228
  // are actionable "fix your git" signals. bundleState is preferred
229
229
  // because it's structured (array of enum values) while syncFailure is
230
230
  // a legacy free-form string; both render when populated.
231
- { label: "provider", content: packet.providerState ?? "", priority: 8 },
231
+ { label: "provider", content: packet.providerSelection ?? "", priority: 8 },
232
232
  { label: "bundleState", content: (0, bundle_state_1.renderBundleStateHint)(packet.bundleState ?? []), priority: 7 },
233
233
  { label: "syncFailure", content: packet.syncFailure ?? "", priority: 7 },
234
234
  { label: "resume", content: packet.resumeHint, priority: 6 },
@@ -93,16 +93,6 @@ const DISPATCH_EXEMPT_PATTERNS = [
93
93
  // buildDaemonHealthState → DaemonHealthWriter) owns observability via
94
94
  // daemon.health_written when the rolled-up state is persisted.
95
95
  "daemon/daemon-rollup",
96
- // Drift comparator + thin I/O loader: `detectProviderBindingDrift`
97
- // is a pure intent-vs-observed comparator with no side effects;
98
- // `loadDriftInputsForAgent` is a small fs-read wrapper that returns
99
- // `null` on missing/invalid state rather than emitting. The caller
100
- // (daemon-entry.ts buildDaemonHealthState's per-agent drift probe)
101
- // owns observability — drift findings ride along through
102
- // `daemon.health_written` as part of the rolled-up state, and
103
- // `agent-config-check.ts` carries `driftFindings` through its
104
- // existing instrumentation. Same pattern as `daemon-rollup`.
105
- "daemon/drift-detection",
106
96
  // Attachment helper modules: generic file-path/extension utilities and the
107
97
  // source registry are pure support seams. The orchestrator/adapters that
108
98
  // call them own the observability.
@@ -47,12 +47,12 @@ const commands_1 = require("./commands");
47
47
  const continuity_1 = require("./continuity");
48
48
  const manager_1 = require("../heart/bridges/manager");
49
49
  const identity_1 = require("../heart/identity");
50
+ const auth_flow_1 = require("../heart/auth/auth-flow");
50
51
  const socket_client_1 = require("../heart/daemon/socket-client");
51
52
  const active_work_1 = require("../heart/active-work");
52
53
  const delegation_1 = require("../heart/delegation");
53
54
  const obligations_1 = require("../arc/obligations");
54
55
  const provider_failover_1 = require("../heart/provider-failover");
55
- const provider_state_1 = require("../heart/provider-state");
56
56
  const tempo_1 = require("../heart/tempo");
57
57
  const temporal_view_1 = require("../heart/temporal-view");
58
58
  const start_of_turn_packet_1 = require("../heart/start-of-turn-packet");
@@ -88,17 +88,13 @@ function providerLaneForChannel(channel) {
88
88
  return channel === "inner" ? "inner" : "outward";
89
89
  }
90
90
  function resolveCurrentFailoverBinding(agentName, lane) {
91
- const stateResult = (0, provider_state_1.readProviderState)((0, identity_1.getAgentRoot)(agentName));
92
- if (stateResult.ok) {
93
- const binding = stateResult.state.lanes[lane];
94
- return { provider: binding.provider, model: binding.model };
95
- }
96
- const agentConfig = (0, identity_1.loadAgentConfig)();
91
+ const agentRoot = (0, identity_1.getAgentRoot)();
92
+ const { config: agentConfig } = (0, auth_flow_1.readAgentConfigForAgent)(agentName, path.dirname(agentRoot));
97
93
  const fallback = lane === "inner" ? agentConfig.agentFacing : agentConfig.humanFacing;
98
94
  return { provider: fallback.provider, model: fallback.model };
99
95
  }
100
96
  /**
101
- * Apply an agent-driven failover switch to provider state, but only after
97
+ * Apply an agent-driven failover switch to agent.json, but only after
102
98
  * re-pinging the candidate. The inventory ping that produced the candidate
103
99
  * may be stale by the time the agent replies — without this preflight, a
104
100
  * "switch to <provider>" reply can move the lane onto an unreachable provider.
@@ -109,38 +105,23 @@ function resolveCurrentFailoverBinding(agentName, lane) {
109
105
  * surface the refusal to the agent
110
106
  * Throws on disk errors only (caught by caller as before).
111
107
  */
112
- async function writeFailoverProviderStateSwitch(agentName, action) {
108
+ async function writeFailoverAgentConfigSwitch(agentName, action) {
113
109
  const validation = await (0, provider_failover_1.validateFailoverSwitchCandidate)(agentName, { provider: action.provider, model: action.model });
114
110
  if (!validation.ok) {
115
111
  return { ok: false, refused: true, classification: validation.classification, message: validation.message };
116
112
  }
117
- const agentRoot = (0, identity_1.getAgentRoot)(agentName);
118
- const stateResult = (0, provider_state_1.readProviderState)(agentRoot);
119
- if (!stateResult.ok) {
120
- throw new Error(`Cannot switch ${action.lane} lane for ${agentName}: ${stateResult.error}`);
121
- }
122
- const updatedAt = new Date().toISOString();
123
- const lanes = { ...stateResult.state.lanes };
124
- lanes[action.lane] = {
125
- provider: action.provider,
126
- model: action.model,
127
- source: "local",
128
- updatedAt,
129
- };
130
- const readiness = { ...stateResult.state.readiness };
131
- readiness[action.lane] = {
132
- status: "ready",
133
- provider: action.provider,
134
- model: action.model,
135
- checkedAt: updatedAt,
136
- ...(action.credentialRevision ? { credentialRevision: action.credentialRevision } : {}),
113
+ const agentRoot = (0, identity_1.getAgentRoot)();
114
+ const { configPath, config } = (0, auth_flow_1.readAgentConfigForAgent)(agentName, path.dirname(agentRoot));
115
+ const facingKey = action.lane === "inner" ? "agentFacing" : "humanFacing";
116
+ const nextConfig = {
117
+ ...config,
118
+ [facingKey]: {
119
+ ...config[facingKey],
120
+ provider: action.provider,
121
+ model: action.model,
122
+ },
137
123
  };
138
- (0, provider_state_1.writeProviderState)(agentRoot, {
139
- ...stateResult.state,
140
- updatedAt,
141
- lanes,
142
- readiness,
143
- });
124
+ fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf-8");
144
125
  return { ok: true };
145
126
  }
146
127
  function formatFailoverSwitchLabel(action) {
@@ -219,7 +200,7 @@ async function handleInboundTurn(input) {
219
200
  if (failoverAction.action === "switch") {
220
201
  let switchOutcome = null;
221
202
  try {
222
- switchOutcome = await writeFailoverProviderStateSwitch(failoverAgentName, failoverAction);
203
+ switchOutcome = await writeFailoverAgentConfigSwitch(failoverAgentName, failoverAction);
223
204
  /* v8 ignore start -- defensive: write failure during provider switch @preserve */
224
205
  }
225
206
  catch (switchError) {
@@ -499,7 +480,7 @@ async function handleInboundTurn(input) {
499
480
  startOfTurnPacket.syncFailure = syncFailure;
500
481
  }
501
482
  if (ctx.providerVisibility) {
502
- startOfTurnPacket.providerState = (0, provider_visibility_1.formatAgentProviderVisibilityForStartOfTurn)(ctx.providerVisibility);
483
+ startOfTurnPacket.providerSelection = (0, provider_visibility_1.formatAgentProviderVisibilityForStartOfTurn)(ctx.providerVisibility);
503
484
  }
504
485
  // Structured bundle state detection — surfaces discrete issues the
505
486
  // agent can remediate via the bundle_* tools. Runs independently of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.553",
3
+ "version": "0.1.0-alpha.555",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",
@@ -34,7 +34,7 @@
34
34
  "test:mailbox-ui": "npm test --prefix packages/mailbox-ui",
35
35
  "test:coverage:vitest": "vitest run --coverage",
36
36
  "test:coverage": "node scripts/run-coverage-gate.cjs",
37
- "build": "tsc && (cd packages/mailbox-ui && npm install --ignore-scripts 2>/dev/null && npm run build && cd ../.. && node scripts/copy-mailbox-ui.cjs) || echo 'mailbox-ui build skipped'",
37
+ "build": "node scripts/clean-dist.cjs && tsc && (cd packages/mailbox-ui && npm install --ignore-scripts 2>/dev/null && npm run build && cd ../.. && node scripts/copy-mailbox-ui.cjs) || echo 'mailbox-ui build skipped'",
38
38
  "lint": "eslint src/",
39
39
  "release:preflight": "node scripts/release-preflight.cjs",
40
40
  "release:smoke": "node scripts/release-smoke.cjs",