@ouro.bot/cli 0.1.0-alpha.552 → 0.1.0-alpha.554
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 +2 -2
- package/RepairGuide.ouro/psyche/IDENTITY.md +1 -1
- package/RepairGuide.ouro/psyche/SOUL.md +1 -1
- package/RepairGuide.ouro/skills/diagnose-stacked-typed-issues.md +4 -4
- package/changelog.json +35 -43
- package/dist/heart/auth/auth-flow.js +3 -3
- package/dist/heart/core.js +0 -12
- package/dist/heart/daemon/agent-config-check.js +75 -168
- package/dist/heart/daemon/agentic-repair.js +2 -9
- package/dist/heart/daemon/cli-defaults.js +72 -42
- package/dist/heart/daemon/cli-exec.js +67 -230
- package/dist/heart/daemon/cli-help.js +1 -1
- package/dist/heart/daemon/cli-render.js +2 -14
- package/dist/heart/daemon/daemon-entry.js +0 -30
- package/dist/heart/daemon/daemon-health.js +0 -7
- package/dist/heart/daemon/daemon-rollup.js +1 -2
- package/dist/heart/daemon/doctor.js +0 -18
- package/dist/heart/daemon/inner-status.js +0 -13
- package/dist/heart/hatch/hatch-flow.js +0 -20
- package/dist/heart/provider-binding-resolver.js +109 -97
- package/dist/heart/provider-credentials.js +2 -2
- package/dist/heart/provider-failover.js +1 -1
- package/dist/heart/provider-readiness-cache.js +40 -0
- package/dist/heart/provider-visibility.js +2 -2
- package/dist/heart/start-of-turn-packet.js +1 -1
- package/dist/senses/pipeline.js +18 -37
- package/package.json +1 -1
- package/RepairGuide.ouro/skills/diagnose-bootstrap-drift.md +0 -54
- package/dist/heart/daemon/drift-detection.js +0 -146
- package/dist/heart/provider-state.js +0 -216
|
@@ -40,8 +40,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
42
|
exports.summarizeDaemonStartupFailure = summarizeDaemonStartupFailure;
|
|
43
|
-
exports.writeDriftAdvisorySummary = writeDriftAdvisorySummary;
|
|
44
|
-
exports.collectAgentDriftAdvisories = collectAgentDriftAdvisories;
|
|
45
43
|
exports.writeSyncProbeSummary = writeSyncProbeSummary;
|
|
46
44
|
exports.summarizeSyncProbeFindings = summarizeSyncProbeFindings;
|
|
47
45
|
exports.mergeStartupStability = mergeStartupStability;
|
|
@@ -78,7 +76,6 @@ const provider_credentials_1 = require("../provider-credentials");
|
|
|
78
76
|
const runtime_credentials_1 = require("../runtime-credentials");
|
|
79
77
|
const provider_binding_resolver_1 = require("../provider-binding-resolver");
|
|
80
78
|
const provider_visibility_1 = require("../provider-visibility");
|
|
81
|
-
const provider_state_1 = require("../provider-state");
|
|
82
79
|
const machine_identity_1 = require("../machine-identity");
|
|
83
80
|
const provider_models_1 = require("../provider-models");
|
|
84
81
|
const ouro_version_manager_1 = require("../versioning/ouro-version-manager");
|
|
@@ -98,7 +95,6 @@ const cli_help_1 = require("./cli-help");
|
|
|
98
95
|
const cli_render_1 = require("./cli-render");
|
|
99
96
|
const cli_defaults_1 = require("./cli-defaults");
|
|
100
97
|
const agent_config_check_1 = require("./agent-config-check");
|
|
101
|
-
const drift_detection_1 = require("./drift-detection");
|
|
102
98
|
const doctor_1 = require("./doctor");
|
|
103
99
|
const cli_render_doctor_1 = require("./cli-render-doctor");
|
|
104
100
|
const interactive_repair_1 = require("./interactive-repair");
|
|
@@ -486,61 +482,6 @@ function daemonUnavailableStatusJsonOutput(socketPath, healthFilePath) {
|
|
|
486
482
|
...(healthFilePath ? { healthFilePath } : {}),
|
|
487
483
|
}, null, 2);
|
|
488
484
|
}
|
|
489
|
-
/**
|
|
490
|
-
* Layer 4: render a per-agent drift advisory block to stdout. Called from
|
|
491
|
-
* the `--no-repair` summary path when one or more enabled agents have a
|
|
492
|
-
* mismatch between `agent.json` (intent) and `state/providers.json`
|
|
493
|
-
* (observation). The block surfaces the lane, intent vs observed
|
|
494
|
-
* binding, and the copy-pasteable `ouro use` repair command per finding.
|
|
495
|
-
*
|
|
496
|
-
* Drift is advisory: this helper only PRINTS the advisory; running the
|
|
497
|
-
* repair command is the operator's call (and is Layer 3 RepairGuide's
|
|
498
|
-
* domain when the daemon does it automatically).
|
|
499
|
-
*
|
|
500
|
-
* Exported for direct unit-testing; the production callers are
|
|
501
|
-
* inside this module.
|
|
502
|
-
*/
|
|
503
|
-
function writeDriftAdvisorySummary(deps, advisories) {
|
|
504
|
-
if (advisories.length === 0)
|
|
505
|
-
return;
|
|
506
|
-
const lines = ["Drift advisory: agent intent does not match this machine's observed binding"];
|
|
507
|
-
for (const advisory of advisories) {
|
|
508
|
-
lines.push("");
|
|
509
|
-
lines.push(` ${advisory.agent} (${advisory.lane}):`);
|
|
510
|
-
lines.push(` intent: ${advisory.intentProvider}/${advisory.intentModel}`);
|
|
511
|
-
lines.push(` observed: ${advisory.observedProvider}/${advisory.observedModel}`);
|
|
512
|
-
lines.push(` repair: ${advisory.repairCommand}`);
|
|
513
|
-
}
|
|
514
|
-
deps.writeStdout(lines.join("\n"));
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Collect drift findings across every enabled agent in the bundles
|
|
518
|
-
* directory. Used by the `--no-repair` summary path so that drift
|
|
519
|
-
* advisories ride along with (or stand alone in place of) the existing
|
|
520
|
-
* provider-repair summary. Errors during a single agent's load (e.g.
|
|
521
|
-
* malformed `agent.json`) are swallowed: drift detection is advisory
|
|
522
|
-
* and must not block the rest of the boot path.
|
|
523
|
-
*/
|
|
524
|
-
async function collectAgentDriftAdvisories(deps) {
|
|
525
|
-
const agents = await listCliAgents(deps);
|
|
526
|
-
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
527
|
-
const findings = [];
|
|
528
|
-
for (const agent of [...new Set(agents)]) {
|
|
529
|
-
try {
|
|
530
|
-
const inputs = (0, drift_detection_1.loadDriftInputsForAgent)(bundlesRoot, agent);
|
|
531
|
-
const agentFindings = (0, drift_detection_1.detectProviderBindingDrift)({
|
|
532
|
-
agentName: agent,
|
|
533
|
-
agentJson: inputs.agentJson,
|
|
534
|
-
providerState: inputs.providerState,
|
|
535
|
-
});
|
|
536
|
-
findings.push(...agentFindings);
|
|
537
|
-
}
|
|
538
|
-
catch {
|
|
539
|
-
// Best-effort: a per-agent read failure is not blocking.
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return findings;
|
|
543
|
-
}
|
|
544
485
|
function providerRepairCountSummary(count) {
|
|
545
486
|
if (count === 0)
|
|
546
487
|
return "selected providers answered live checks";
|
|
@@ -1305,7 +1246,7 @@ async function resolveHatchInput(command, deps) {
|
|
|
1305
1246
|
migrationPath: command.migrationPath,
|
|
1306
1247
|
};
|
|
1307
1248
|
}
|
|
1308
|
-
// ── Provider
|
|
1249
|
+
// ── Provider selection CLI helpers ──
|
|
1309
1250
|
function providerCliHomeDir(deps) {
|
|
1310
1251
|
return (0, provider_credentials_1.providerCredentialMachineHomeDir)(deps.homeDir);
|
|
1311
1252
|
}
|
|
@@ -4343,56 +4284,12 @@ async function executeConnect(command, deps) {
|
|
|
4343
4284
|
deps.writeStdout(message);
|
|
4344
4285
|
return message;
|
|
4345
4286
|
}
|
|
4346
|
-
function readOrBootstrapProviderState(agentName, deps) {
|
|
4347
|
-
const agentRoot = providerCliAgentRoot({ agent: agentName }, deps);
|
|
4348
|
-
const readResult = (0, provider_state_1.readProviderState)(agentRoot);
|
|
4349
|
-
if (readResult.ok)
|
|
4350
|
-
return { agentRoot, state: readResult.state };
|
|
4351
|
-
if (readResult.reason === "invalid") {
|
|
4352
|
-
throw new Error(`provider state for ${agentName} is invalid at ${readResult.statePath}: ${readResult.error}`);
|
|
4353
|
-
}
|
|
4354
|
-
const { config } = (0, auth_flow_1.readAgentConfigForAgent)(agentName, deps.bundlesRoot);
|
|
4355
|
-
const homeDir = providerCliHomeDir(deps);
|
|
4356
|
-
const machine = (0, machine_identity_1.loadOrCreateMachineIdentity)({
|
|
4357
|
-
homeDir,
|
|
4358
|
-
now: () => providerCliNow(deps),
|
|
4359
|
-
});
|
|
4360
|
-
const state = (0, provider_state_1.bootstrapProviderStateFromAgentConfig)({
|
|
4361
|
-
machineId: machine.machineId,
|
|
4362
|
-
now: providerCliNow(deps),
|
|
4363
|
-
agentConfig: {
|
|
4364
|
-
humanFacing: {
|
|
4365
|
-
provider: config.humanFacing.provider,
|
|
4366
|
-
model: config.humanFacing.model || (0, provider_models_1.getDefaultModelForProvider)(config.humanFacing.provider),
|
|
4367
|
-
},
|
|
4368
|
-
agentFacing: {
|
|
4369
|
-
provider: config.agentFacing.provider,
|
|
4370
|
-
model: config.agentFacing.model || (0, provider_models_1.getDefaultModelForProvider)(config.agentFacing.provider),
|
|
4371
|
-
},
|
|
4372
|
-
},
|
|
4373
|
-
});
|
|
4374
|
-
(0, provider_state_1.writeProviderState)(agentRoot, state);
|
|
4375
|
-
(0, runtime_1.emitNervesEvent)({
|
|
4376
|
-
component: "daemon",
|
|
4377
|
-
event: "daemon.provider_state_bootstrapped",
|
|
4378
|
-
message: "bootstrapped local provider state from agent config",
|
|
4379
|
-
meta: { agent: agentName, agentRoot },
|
|
4380
|
-
});
|
|
4381
|
-
return { agentRoot, state };
|
|
4382
|
-
}
|
|
4383
4287
|
function credentialPingConfig(record) {
|
|
4384
4288
|
return {
|
|
4385
4289
|
...record.credentials,
|
|
4386
4290
|
...record.config,
|
|
4387
4291
|
};
|
|
4388
4292
|
}
|
|
4389
|
-
function pingAttemptCount(result) {
|
|
4390
|
-
if (typeof result.attempts === "number")
|
|
4391
|
-
return result.attempts;
|
|
4392
|
-
if (Array.isArray(result.attempts))
|
|
4393
|
-
return result.attempts.length;
|
|
4394
|
-
return undefined;
|
|
4395
|
-
}
|
|
4396
4293
|
async function readProviderCredentialRecord(agent, provider, _deps, options = {}) {
|
|
4397
4294
|
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(agent, { ...options, providers: [provider] });
|
|
4398
4295
|
if (poolResult.ok) {
|
|
@@ -4410,39 +4307,38 @@ async function readProviderCredentialRecord(agent, provider, _deps, options = {}
|
|
|
4410
4307
|
error: `no credentials stored for ${provider}`,
|
|
4411
4308
|
};
|
|
4412
4309
|
}
|
|
4413
|
-
function
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
};
|
|
4422
|
-
input.state.readiness[input.lane] = {
|
|
4423
|
-
status: input.status,
|
|
4424
|
-
provider: input.provider,
|
|
4425
|
-
model: input.model,
|
|
4426
|
-
checkedAt: updatedAt,
|
|
4427
|
-
...(input.credentialRevision ? { credentialRevision: input.credentialRevision } : {}),
|
|
4428
|
-
...(input.error ? { error: input.error } : {}),
|
|
4429
|
-
...(input.attempts !== undefined ? { attempts: input.attempts } : {}),
|
|
4310
|
+
function providerFacingKeyForLane(lane) {
|
|
4311
|
+
return lane === "inner" ? "agentFacing" : "humanFacing";
|
|
4312
|
+
}
|
|
4313
|
+
function providerConfigBinding(config, lane) {
|
|
4314
|
+
const binding = config[providerFacingKeyForLane(lane)];
|
|
4315
|
+
return {
|
|
4316
|
+
provider: binding.provider,
|
|
4317
|
+
model: binding.model || (0, provider_models_1.getDefaultModelForProvider)(binding.provider),
|
|
4430
4318
|
};
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
const
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
...(input.error ? { error: input.error } : {}),
|
|
4443
|
-
...(input.attempts !== undefined ? { attempts: input.attempts } : {}),
|
|
4319
|
+
}
|
|
4320
|
+
function writeAgentProviderBinding(input) {
|
|
4321
|
+
const { configPath, config } = (0, auth_flow_1.readAgentConfigForAgent)(input.agent, input.deps.bundlesRoot);
|
|
4322
|
+
const facingKey = providerFacingKeyForLane(input.lane);
|
|
4323
|
+
const nextConfig = {
|
|
4324
|
+
...config,
|
|
4325
|
+
[facingKey]: {
|
|
4326
|
+
...config[facingKey],
|
|
4327
|
+
provider: input.provider,
|
|
4328
|
+
model: input.model,
|
|
4329
|
+
},
|
|
4444
4330
|
};
|
|
4445
|
-
(
|
|
4331
|
+
fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf-8");
|
|
4332
|
+
(0, runtime_1.emitNervesEvent)({
|
|
4333
|
+
component: "daemon",
|
|
4334
|
+
event: "daemon.provider_selection_updated",
|
|
4335
|
+
message: "updated provider selection in agent config",
|
|
4336
|
+
meta: { agent: input.agent, lane: input.lane, provider: input.provider, model: input.model, configPath },
|
|
4337
|
+
});
|
|
4338
|
+
}
|
|
4339
|
+
function appendBundleSyncSummary(message, agent, deps) {
|
|
4340
|
+
const syncSummary = pushAgentBundleAfterCliMutation(agent, deps);
|
|
4341
|
+
return syncSummary ? [message, syncSummary].join("\n") : message;
|
|
4446
4342
|
}
|
|
4447
4343
|
async function executeProviderUse(command, deps, options = {}) {
|
|
4448
4344
|
const progress = options.writeStdout === false ? null : createHumanCommandProgress(deps, "provider use");
|
|
@@ -4453,7 +4349,6 @@ async function executeProviderUse(command, deps, options = {}) {
|
|
|
4453
4349
|
return message;
|
|
4454
4350
|
};
|
|
4455
4351
|
try {
|
|
4456
|
-
const { agentRoot, state } = readOrBootstrapProviderState(command.agent, deps);
|
|
4457
4352
|
progress?.startPhase(`reading ${command.provider} credentials`);
|
|
4458
4353
|
const credential = await readProviderCredentialRecord(command.agent, command.provider, deps, {
|
|
4459
4354
|
onProgress: (message) => progress?.updateDetail(message),
|
|
@@ -4467,17 +4362,14 @@ async function executeProviderUse(command, deps, options = {}) {
|
|
|
4467
4362
|
].join("\n");
|
|
4468
4363
|
return writeMessage(message);
|
|
4469
4364
|
}
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
state,
|
|
4365
|
+
writeAgentProviderBinding({
|
|
4366
|
+
agent: command.agent,
|
|
4473
4367
|
lane: command.lane,
|
|
4474
4368
|
provider: command.provider,
|
|
4475
4369
|
model: command.model,
|
|
4476
4370
|
deps,
|
|
4477
|
-
status: "failed",
|
|
4478
|
-
error: credential.error,
|
|
4479
4371
|
});
|
|
4480
|
-
const message = `forced ${command.agent} ${command.lane} to ${command.provider} / ${command.model}: failed (${credential.error})
|
|
4372
|
+
const message = appendBundleSyncSummary(`forced ${command.agent} ${command.lane} to ${command.provider} / ${command.model}: failed (${credential.error})`, command.agent, deps);
|
|
4481
4373
|
return writeMessage(message);
|
|
4482
4374
|
}
|
|
4483
4375
|
progress?.completePhase(`reading ${command.provider} credentials`, "found");
|
|
@@ -4488,29 +4380,23 @@ async function executeProviderUse(command, deps, options = {}) {
|
|
|
4488
4380
|
sleep: deps.sleep,
|
|
4489
4381
|
...(0, provider_ping_progress_1.createProviderPingProgressReporter)({ provider: command.provider, model: command.model }, (message) => progress?.updateDetail(message)),
|
|
4490
4382
|
});
|
|
4491
|
-
const attempts = pingAttemptCount(pingResult);
|
|
4492
4383
|
const status = pingResult.ok ? "ready" : `failed (${pingResult.message})`;
|
|
4493
4384
|
progress?.completePhase(`checking ${command.provider} / ${command.model}`, status);
|
|
4494
4385
|
if (!pingResult.ok && !command.force) {
|
|
4495
4386
|
const message = [
|
|
4496
4387
|
`${command.agent} ${command.lane} ${command.provider} / ${command.model}: failed (${pingResult.message})`,
|
|
4497
|
-
`Fix credentials with \`ouro auth --agent ${command.agent} --provider ${command.provider}\` or force
|
|
4388
|
+
`Fix credentials with \`ouro auth --agent ${command.agent} --provider ${command.provider}\` or force agent.json with \`ouro use --agent ${command.agent} --lane ${command.lane} --provider ${command.provider} --model ${command.model} --force\`.`,
|
|
4498
4389
|
].join("\n");
|
|
4499
4390
|
return writeMessage(message);
|
|
4500
4391
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
state,
|
|
4392
|
+
writeAgentProviderBinding({
|
|
4393
|
+
agent: command.agent,
|
|
4504
4394
|
lane: command.lane,
|
|
4505
4395
|
provider: command.provider,
|
|
4506
4396
|
model: command.model,
|
|
4507
4397
|
deps,
|
|
4508
|
-
status: pingResult.ok ? "ready" : "failed",
|
|
4509
|
-
credentialRevision: credential.record.revision,
|
|
4510
|
-
...(!pingResult.ok ? { error: pingResult.message } : {}),
|
|
4511
|
-
...(attempts !== undefined ? { attempts } : {}),
|
|
4512
4398
|
});
|
|
4513
|
-
const message = `${command.force ? "forced " : ""}${command.agent} ${command.lane} ${command.provider} / ${command.model}: ${status}
|
|
4399
|
+
const message = appendBundleSyncSummary(`${command.force ? "forced " : ""}${command.agent} ${command.lane} ${command.provider} / ${command.model}: ${status}`, command.agent, deps);
|
|
4514
4400
|
(0, runtime_1.emitNervesEvent)({
|
|
4515
4401
|
component: "daemon",
|
|
4516
4402
|
event: "daemon.provider_use_completed",
|
|
@@ -4532,8 +4418,8 @@ async function executeProviderCheck(command, deps) {
|
|
|
4532
4418
|
return message;
|
|
4533
4419
|
};
|
|
4534
4420
|
try {
|
|
4535
|
-
const {
|
|
4536
|
-
const binding =
|
|
4421
|
+
const { config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
|
|
4422
|
+
const binding = providerConfigBinding(config, command.lane);
|
|
4537
4423
|
progress.startPhase(`reading ${binding.provider} credentials`);
|
|
4538
4424
|
const credential = await readProviderCredentialRecord(command.agent, binding.provider, deps, {
|
|
4539
4425
|
onProgress: (message) => progress.updateDetail(message),
|
|
@@ -4554,21 +4440,8 @@ async function executeProviderCheck(command, deps) {
|
|
|
4554
4440
|
sleep: deps.sleep,
|
|
4555
4441
|
...(0, provider_ping_progress_1.createProviderPingProgressReporter)({ provider: binding.provider, model: binding.model }, (message) => progress.updateDetail(message)),
|
|
4556
4442
|
});
|
|
4557
|
-
const attempts = pingAttemptCount(pingResult);
|
|
4558
4443
|
const status = pingResult.ok ? "ready" : `failed (${pingResult.message})`;
|
|
4559
4444
|
progress.completePhase(`checking ${binding.provider} / ${binding.model}`, status);
|
|
4560
|
-
writeProviderReadiness({
|
|
4561
|
-
agentRoot,
|
|
4562
|
-
state,
|
|
4563
|
-
lane: command.lane,
|
|
4564
|
-
provider: binding.provider,
|
|
4565
|
-
model: binding.model,
|
|
4566
|
-
deps,
|
|
4567
|
-
status: pingResult.ok ? "ready" : "failed",
|
|
4568
|
-
credentialRevision: credential.record.revision,
|
|
4569
|
-
...(!pingResult.ok ? { error: pingResult.message } : {}),
|
|
4570
|
-
...(attempts !== undefined ? { attempts } : {}),
|
|
4571
|
-
});
|
|
4572
4445
|
const message = `${command.agent} ${command.lane} ${binding.provider} / ${binding.model}: ${status}`;
|
|
4573
4446
|
(0, runtime_1.emitNervesEvent)({
|
|
4574
4447
|
component: "daemon",
|
|
@@ -4577,11 +4450,13 @@ async function executeProviderCheck(command, deps) {
|
|
|
4577
4450
|
meta: { agent: command.agent, lane: command.lane, provider: binding.provider, model: binding.model, status: pingResult.ok ? "ready" : "failed" },
|
|
4578
4451
|
});
|
|
4579
4452
|
return writeMessage(message);
|
|
4453
|
+
/* v8 ignore start -- defensive rethrow: provider-check dependency failures are covered at the caller boundary @preserve */
|
|
4580
4454
|
}
|
|
4581
4455
|
catch (error) {
|
|
4582
4456
|
progress.end();
|
|
4583
4457
|
throw error;
|
|
4584
4458
|
}
|
|
4459
|
+
/* v8 ignore stop */
|
|
4585
4460
|
}
|
|
4586
4461
|
function renderProviderCredentialLine(agentName, credential) {
|
|
4587
4462
|
if (credential.status === "present") {
|
|
@@ -4600,12 +4475,12 @@ function renderProviderCredentialLine(agentName, credential) {
|
|
|
4600
4475
|
async function executeProviderStatus(command, deps) {
|
|
4601
4476
|
const agentRoot = providerCliAgentRoot(command, deps);
|
|
4602
4477
|
const progress = createHumanCommandProgress(deps, "provider status");
|
|
4603
|
-
const stateResult = (0, provider_state_1.readProviderState)(agentRoot);
|
|
4604
4478
|
try {
|
|
4605
|
-
|
|
4479
|
+
const { config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
|
|
4480
|
+
{
|
|
4606
4481
|
const selectedProviders = [...new Set([
|
|
4607
|
-
|
|
4608
|
-
|
|
4482
|
+
config.humanFacing.provider,
|
|
4483
|
+
config.agentFacing.provider,
|
|
4609
4484
|
])];
|
|
4610
4485
|
await runCommandProgressPhase(progress, "reading selected provider credentials", () => (0, provider_credentials_1.refreshProviderCredentialPool)(command.agent, {
|
|
4611
4486
|
providers: selectedProviders,
|
|
@@ -4630,14 +4505,17 @@ async function executeProviderStatus(command, deps) {
|
|
|
4630
4505
|
homeDir,
|
|
4631
4506
|
lane,
|
|
4632
4507
|
});
|
|
4508
|
+
/* v8 ignore start -- defensive: provider status pre-validates agent.json before resolving lane details @preserve */
|
|
4633
4509
|
if (!resolved.ok) {
|
|
4634
4510
|
lines.push(` ${lane}: unavailable`);
|
|
4635
|
-
lines.push(` ${resolved.reason}: ${resolved.
|
|
4511
|
+
lines.push(` ${resolved.reason}: ${resolved.error}`);
|
|
4512
|
+
lines.push(` repair: ${resolved.repair.command}`);
|
|
4636
4513
|
continue;
|
|
4637
4514
|
}
|
|
4515
|
+
/* v8 ignore stop */
|
|
4638
4516
|
const binding = resolved.binding;
|
|
4639
4517
|
lines.push(` ${lane}: ${binding.provider} / ${binding.model} (${binding.source})`);
|
|
4640
|
-
lines.push(` readiness: ${binding.readiness.status}
|
|
4518
|
+
lines.push(` readiness: ${binding.readiness.status}`);
|
|
4641
4519
|
lines.push(` ${renderProviderCredentialLine(command.agent, binding.credential)}`);
|
|
4642
4520
|
for (const warning of binding.warnings) {
|
|
4643
4521
|
lines.push(` warning: ${warning.message}`);
|
|
@@ -4668,7 +4546,7 @@ async function executeProviderRefresh(command, deps) {
|
|
|
4668
4546
|
const lines = [];
|
|
4669
4547
|
if (pool.ok) {
|
|
4670
4548
|
const summary = (0, provider_credentials_1.summarizeProviderCredentialPool)(pool.pool);
|
|
4671
|
-
lines.push(`refreshed provider
|
|
4549
|
+
lines.push(`refreshed in-memory provider credentials for ${command.agent}`);
|
|
4672
4550
|
lines.push(`providers: ${summary.providers.map((provider) => provider.provider).join(", ") || "none"}`);
|
|
4673
4551
|
progress.completePhase("refreshing provider credentials", summary.providers.map((provider) => provider.provider).join(", ") || "none");
|
|
4674
4552
|
}
|
|
@@ -4910,13 +4788,13 @@ async function runReadinessRepairForDegraded(degraded, deps) {
|
|
|
4910
4788
|
return { repairsAttempted, remainingDegraded: current };
|
|
4911
4789
|
}
|
|
4912
4790
|
async function executeLegacyAuthSwitch(command, deps) {
|
|
4913
|
-
const {
|
|
4791
|
+
const { config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
|
|
4914
4792
|
const lanes = command.facing
|
|
4915
4793
|
? [command.facing === "human" ? "outward" : "inner"]
|
|
4916
4794
|
: ["outward", "inner"];
|
|
4917
4795
|
const messages = [];
|
|
4918
4796
|
for (const lane of lanes) {
|
|
4919
|
-
const model =
|
|
4797
|
+
const model = providerConfigBinding(config, lane).model;
|
|
4920
4798
|
messages.push(await executeProviderUse({
|
|
4921
4799
|
kind: "provider.use",
|
|
4922
4800
|
agent: command.agent,
|
|
@@ -4928,7 +4806,7 @@ async function executeLegacyAuthSwitch(command, deps) {
|
|
|
4928
4806
|
}, deps, { writeStdout: false }));
|
|
4929
4807
|
}
|
|
4930
4808
|
const message = [
|
|
4931
|
-
`deprecated: switched
|
|
4809
|
+
`deprecated: switched provider selection in agent.json.`,
|
|
4932
4810
|
...messages,
|
|
4933
4811
|
`Use \`ouro use --agent ${command.agent} --lane <outward|inner> --provider ${command.provider} --model <model>\` for explicit provider/model selection.`,
|
|
4934
4812
|
].join("\n");
|
|
@@ -4937,8 +4815,8 @@ async function executeLegacyAuthSwitch(command, deps) {
|
|
|
4937
4815
|
}
|
|
4938
4816
|
async function executeLegacyConfigModel(command, deps) {
|
|
4939
4817
|
const lane = command.facing === "agent" ? "inner" : "outward";
|
|
4940
|
-
const {
|
|
4941
|
-
const binding =
|
|
4818
|
+
const { configPath, config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
|
|
4819
|
+
const binding = providerConfigBinding(config, lane);
|
|
4942
4820
|
const progress = binding.provider === "github-copilot" ? createHumanCommandProgress(deps, "config model") : null;
|
|
4943
4821
|
const writeMessage = (message) => {
|
|
4944
4822
|
progress?.end();
|
|
@@ -4996,17 +4874,16 @@ async function executeLegacyConfigModel(command, deps) {
|
|
|
4996
4874
|
throw error;
|
|
4997
4875
|
}
|
|
4998
4876
|
}
|
|
4999
|
-
const
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
4877
|
+
const facingKey = providerFacingKeyForLane(lane);
|
|
4878
|
+
const nextConfig = {
|
|
4879
|
+
...config,
|
|
4880
|
+
[facingKey]: {
|
|
4881
|
+
...config[facingKey],
|
|
4882
|
+
model: command.modelName,
|
|
4883
|
+
},
|
|
5006
4884
|
};
|
|
5007
|
-
|
|
5008
|
-
(
|
|
5009
|
-
const message = `deprecated: updated ${command.agent} model on ${lane}/${binding.provider}: ${binding.model} -> ${command.modelName}\nUse \`ouro use --agent ${command.agent} --lane ${lane} --provider ${binding.provider} --model ${command.modelName}\` next time.`;
|
|
4885
|
+
fs.writeFileSync(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf-8");
|
|
4886
|
+
const message = appendBundleSyncSummary(`deprecated: updated ${command.agent} model in agent.json on ${lane}/${binding.provider}: ${binding.model} -> ${command.modelName}\nUse \`ouro use --agent ${command.agent} --lane ${lane} --provider ${binding.provider} --model ${command.modelName}\` next time.`, command.agent, deps);
|
|
5010
4887
|
return writeMessage(message);
|
|
5011
4888
|
}
|
|
5012
4889
|
// ── System setup ──
|
|
@@ -5942,10 +5819,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5942
5819
|
if (command.noRepair) {
|
|
5943
5820
|
// --no-repair: write degraded summary and skip interactive repair
|
|
5944
5821
|
writeProviderRepairSummary(deps, "Provider checks need attention", daemonResult.stability.degraded);
|
|
5945
|
-
// Layer 4: drift advisories ride along with the post-startup
|
|
5946
|
-
// degraded summary too — same rationale as the preflight path.
|
|
5947
|
-
const driftAdvisories = await collectAgentDriftAdvisories(deps);
|
|
5948
|
-
writeDriftAdvisorySummary(deps, driftAdvisories);
|
|
5949
5822
|
deps.setExitCode?.(1);
|
|
5950
5823
|
(0, runtime_1.emitNervesEvent)({
|
|
5951
5824
|
level: "warn",
|
|
@@ -5954,7 +5827,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5954
5827
|
message: "degraded agents detected with --no-repair, skipping interactive repair",
|
|
5955
5828
|
meta: {
|
|
5956
5829
|
degradedCount: daemonResult.stability.degraded.length,
|
|
5957
|
-
driftCount: driftAdvisories.length,
|
|
5958
5830
|
},
|
|
5959
5831
|
});
|
|
5960
5832
|
}
|
|
@@ -5988,16 +5860,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
5988
5860
|
if (repairGuideShouldFire) {
|
|
5989
5861
|
const repairInput = [...untypedDegraded, ...typedDegraded];
|
|
5990
5862
|
const forceDiagnosis = untypedDegraded.length === 0 && typedDegraded.length >= 3;
|
|
5991
|
-
// Layer 3: collect drift findings here so the RepairGuide
|
|
5992
|
-
// prompt receives them as a structured JSON block. Drift is
|
|
5993
|
-
// already collected for the no-repair path above; we collect
|
|
5994
|
-
// again here because the repair path is a separate branch.
|
|
5995
|
-
// Filter to agents in repairInput so the diagnostic prompt
|
|
5996
|
-
// doesn't carry drift from healthy peers — narrows the
|
|
5997
|
-
// signal to the set being diagnosed.
|
|
5998
|
-
const repairAgentNames = new Set(repairInput.map((entry) => entry.agent));
|
|
5999
|
-
const repairDriftFindings = (await collectAgentDriftAdvisories(deps))
|
|
6000
|
-
.filter((finding) => repairAgentNames.has(finding.agent));
|
|
6001
5863
|
const repairResult = await (0, agentic_repair_1.runAgenticRepair)(repairInput, {
|
|
6002
5864
|
/* v8 ignore start -- production provider discovery wiring @preserve */
|
|
6003
5865
|
discoverWorkingProvider: async (agentName) => {
|
|
@@ -6043,7 +5905,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6043
5905
|
isTTY: deps.isTTY ?? process.stdout.isTTY === true,
|
|
6044
5906
|
stdoutColumns: deps.stdoutColumns ?? process.stdout.columns,
|
|
6045
5907
|
forceDiagnosis,
|
|
6046
|
-
driftFindings: repairDriftFindings,
|
|
6047
5908
|
syncFindings: bootSyncFindings,
|
|
6048
5909
|
});
|
|
6049
5910
|
if (repairResult.repairsAttempted) {
|
|
@@ -6077,13 +5938,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6077
5938
|
}
|
|
6078
5939
|
}
|
|
6079
5940
|
}
|
|
6080
|
-
else if (command.noRepair) {
|
|
6081
|
-
// Layer 4: no degraded agents to summarize, but --no-repair still
|
|
6082
|
-
// surfaces drift advisories so the operator sees them without
|
|
6083
|
-
// having to run `ouro inner status` per agent.
|
|
6084
|
-
const driftAdvisories = await collectAgentDriftAdvisories(deps);
|
|
6085
|
-
writeDriftAdvisorySummary(deps, driftAdvisories);
|
|
6086
|
-
}
|
|
6087
5941
|
return daemonResult.message;
|
|
6088
5942
|
}
|
|
6089
5943
|
if (command.kind === "daemon.dev") {
|
|
@@ -6680,7 +6534,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
6680
6534
|
deps.writeStdout(message);
|
|
6681
6535
|
return message;
|
|
6682
6536
|
}
|
|
6683
|
-
// ── provider
|
|
6537
|
+
// ── provider commands (local, no daemon socket needed) ──
|
|
6684
6538
|
if (command.kind === "provider.use") {
|
|
6685
6539
|
return executeProviderUse(command, deps);
|
|
6686
6540
|
}
|
|
@@ -7196,22 +7050,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
7196
7050
|
catch { /* no habits — heartbeat unknown */ }
|
|
7197
7051
|
// Attention count
|
|
7198
7052
|
const activeObligations = listActiveReturnObligations(command.agent);
|
|
7199
|
-
// Layer 4 drift findings for this agent. Best-effort: if agent.json
|
|
7200
|
-
// is unreadable mid-call we just suppress the advisory rather than
|
|
7201
|
-
// failing the inner-status render.
|
|
7202
|
-
let driftFindings = [];
|
|
7203
|
-
try {
|
|
7204
|
-
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
7205
|
-
const inputs = (0, drift_detection_1.loadDriftInputsForAgent)(bundlesRoot, command.agent);
|
|
7206
|
-
driftFindings = (0, drift_detection_1.detectProviderBindingDrift)({
|
|
7207
|
-
agentName: command.agent,
|
|
7208
|
-
agentJson: inputs.agentJson,
|
|
7209
|
-
providerState: inputs.providerState,
|
|
7210
|
-
});
|
|
7211
|
-
}
|
|
7212
|
-
catch {
|
|
7213
|
-
driftFindings = [];
|
|
7214
|
-
}
|
|
7215
7053
|
const message = buildInnerStatusOutput({
|
|
7216
7054
|
agentName: command.agent,
|
|
7217
7055
|
runtimeState,
|
|
@@ -7219,7 +7057,6 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
7219
7057
|
heartbeat,
|
|
7220
7058
|
attentionCount: activeObligations.length,
|
|
7221
7059
|
now: Date.now(),
|
|
7222
|
-
driftFindings,
|
|
7223
7060
|
});
|
|
7224
7061
|
deps.writeStdout(message);
|
|
7225
7062
|
return message;
|
|
@@ -289,7 +289,7 @@ const SUBCOMMAND_HELP = {
|
|
|
289
289
|
example: "ouro auth verify --provider openai-codex",
|
|
290
290
|
},
|
|
291
291
|
"auth switch": {
|
|
292
|
-
description: "Switch
|
|
292
|
+
description: "Switch agent.json provider/model lanes after credentials are available",
|
|
293
293
|
usage: "ouro auth switch [--agent <name>] --provider <provider> [--facing human|agent]",
|
|
294
294
|
example: "ouro auth switch --provider minimax",
|
|
295
295
|
},
|
|
@@ -623,26 +623,14 @@ function renderRollupStatusLine(health) {
|
|
|
623
623
|
case "healthy":
|
|
624
624
|
return `Last known status: healthy ${tail}`;
|
|
625
625
|
case "partial": {
|
|
626
|
-
// `partial` arises from two independent sources:
|
|
627
|
-
// (a) some enabled agents not in `running` state, or
|
|
628
|
-
// (b) Layer-4 drift between agent.json (intent) and state/providers.json (observed).
|
|
629
|
-
// Either or both can be true. Render mentions both when applicable so
|
|
630
|
-
// the operator isn't misled into thinking agents are unhealthy when the
|
|
631
|
-
// only anomaly is configuration drift.
|
|
632
626
|
const unhealthyCount = Object.values(health.agents).filter((agent) => agent.status !== "running").length;
|
|
633
|
-
const driftCount = (health.drift ?? []).length;
|
|
634
627
|
const parts = [];
|
|
635
628
|
if (unhealthyCount > 0) {
|
|
636
629
|
parts.push(`${unhealthyCount} agent${unhealthyCount === 1 ? "" : "s"} unhealthy`);
|
|
637
630
|
}
|
|
638
|
-
if (driftCount > 0) {
|
|
639
|
-
parts.push(`drift on ${driftCount} agent${driftCount === 1 ? "" : "s"}`);
|
|
640
|
-
}
|
|
641
631
|
// Fallback for legacy cached files: status="partial" with no
|
|
642
|
-
// visible cause
|
|
643
|
-
//
|
|
644
|
-
// partial via some signal that's no longer expressible. Prompt
|
|
645
|
-
// refresh via `ouro up` rather than asserting a specific cause.
|
|
632
|
+
// visible cause. Prompt refresh via `ouro up` rather than asserting
|
|
633
|
+
// a specific cause.
|
|
646
634
|
const detail = parts.length > 0
|
|
647
635
|
? ` — ${parts.join("; ")}`
|
|
648
636
|
: " — stale cache, run `ouro up` to refresh";
|
|
@@ -56,7 +56,6 @@ const os_cron_deps_1 = require("./os-cron-deps");
|
|
|
56
56
|
const os_cron_1 = require("./os-cron");
|
|
57
57
|
const daemon_tombstone_1 = require("./daemon-tombstone");
|
|
58
58
|
const agent_config_check_1 = require("./agent-config-check");
|
|
59
|
-
const drift_detection_1 = require("./drift-detection");
|
|
60
59
|
const pulse_1 = require("./pulse");
|
|
61
60
|
const socket_client_1 = require("./socket-client");
|
|
62
61
|
const bundle_manifest_1 = require("../../mind/bundle-manifest");
|
|
@@ -235,33 +234,6 @@ function buildDaemonHealthState() {
|
|
|
235
234
|
...degradedComponents.map((entry) => ({ ...entry })),
|
|
236
235
|
...agentDegradedComponents,
|
|
237
236
|
];
|
|
238
|
-
// Layer 4: probe each enabled agent for drift between agent.json
|
|
239
|
-
// (intent) and state/providers.json (observed binding). The result is
|
|
240
|
-
// a single boolean — driftDetected — that downgrades the rollup from
|
|
241
|
-
// healthy to partial when true. Per-finding detail is consumed by
|
|
242
|
-
// render-side surfaces (inner-status, --no-repair summary) and by
|
|
243
|
-
// Layer 3 RepairGuide; the rollup itself only cares about presence.
|
|
244
|
-
// Best-effort: a single agent's read failure is not blocking — the
|
|
245
|
-
// function returns "no drift detected for that agent" and continues.
|
|
246
|
-
const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
|
|
247
|
-
const drift = [];
|
|
248
|
-
for (const snapshot of snapshots) {
|
|
249
|
-
try {
|
|
250
|
-
const inputs = (0, drift_detection_1.loadDriftInputsForAgent)(bundlesRoot, snapshot.name);
|
|
251
|
-
const findings = (0, drift_detection_1.detectProviderBindingDrift)({
|
|
252
|
-
agentName: snapshot.name,
|
|
253
|
-
agentJson: inputs.agentJson,
|
|
254
|
-
providerState: inputs.providerState,
|
|
255
|
-
});
|
|
256
|
-
if (findings.length > 0) {
|
|
257
|
-
drift.push(...findings);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
catch {
|
|
261
|
-
// best-effort: continue scanning
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
const driftDetected = drift.length > 0;
|
|
265
237
|
// Layer 1 rollup: project per-agent snapshots into the minimal
|
|
266
238
|
// AgentRollupInput shape and let computeDaemonRollup decide. The
|
|
267
239
|
// input is "every enabled agent" — managedAgents was filtered via
|
|
@@ -284,7 +256,6 @@ function buildDaemonHealthState() {
|
|
|
284
256
|
})),
|
|
285
257
|
bootstrapDegraded: degradedComponents,
|
|
286
258
|
safeMode: false,
|
|
287
|
-
driftDetected,
|
|
288
259
|
});
|
|
289
260
|
return {
|
|
290
261
|
status: rollupStatus,
|
|
@@ -294,7 +265,6 @@ function buildDaemonHealthState() {
|
|
|
294
265
|
uptimeSeconds: Math.floor(process.uptime()),
|
|
295
266
|
safeMode: null,
|
|
296
267
|
degraded,
|
|
297
|
-
drift,
|
|
298
268
|
agents: Object.fromEntries(snapshots.map((snapshot) => [
|
|
299
269
|
snapshot.name,
|
|
300
270
|
{
|
|
@@ -158,12 +158,6 @@ function readHealth(healthPath) {
|
|
|
158
158
|
parsed.habits === null) {
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
|
-
// `drift` is required in DaemonHealthState but absent from cached
|
|
162
|
-
// health files written by pre-Layer-4 daemons. Tolerate that legacy
|
|
163
|
-
// shape by defaulting to []; the rest of the file is still valid.
|
|
164
|
-
const drift = Array.isArray(parsed.drift)
|
|
165
|
-
? parsed.drift
|
|
166
|
-
: [];
|
|
167
161
|
return {
|
|
168
162
|
status: parsed.status,
|
|
169
163
|
mode: parsed.mode,
|
|
@@ -172,7 +166,6 @@ function readHealth(healthPath) {
|
|
|
172
166
|
uptimeSeconds: parsed.uptimeSeconds,
|
|
173
167
|
safeMode: parsed.safeMode,
|
|
174
168
|
degraded: parsed.degraded,
|
|
175
|
-
drift,
|
|
176
169
|
agents: parsed.agents,
|
|
177
170
|
habits: parsed.habits,
|
|
178
171
|
};
|
|
@@ -50,8 +50,7 @@ function computeDaemonRollup(input) {
|
|
|
50
50
|
// healthy vs partial.
|
|
51
51
|
const hasUnhealthyAgent = notServing > 0;
|
|
52
52
|
const hasBootstrapDegraded = input.bootstrapDegraded.length > 0;
|
|
53
|
-
|
|
54
|
-
if (hasUnhealthyAgent || hasBootstrapDegraded || hasDrift) {
|
|
53
|
+
if (hasUnhealthyAgent || hasBootstrapDegraded) {
|
|
55
54
|
return "partial";
|
|
56
55
|
}
|
|
57
56
|
return "healthy";
|