@ouro.bot/cli 0.1.0-alpha.395 → 0.1.0-alpha.397
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/changelog.json +21 -0
- package/dist/heart/daemon/agent-config-check.js +16 -0
- package/dist/heart/daemon/agentic-repair.js +8 -0
- package/dist/heart/daemon/cli-exec.js +188 -49
- package/dist/heart/daemon/cli-help.js +6 -0
- package/dist/heart/daemon/cli-parse.js +7 -0
- package/dist/heart/daemon/interactive-repair.js +24 -0
- package/dist/heart/daemon/readiness-repair.js +216 -0
- package/dist/heart/identity.js +9 -1
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.397",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro up` provider repair output now uses compact readiness cards and `need repair` progress labels instead of dense degraded-agent prose.",
|
|
8
|
+
"Guided readiness repair and post-repair summaries now share the same typed issue renderer, so locked vaults, missing provider credentials, and generic repair hints show consistent `next`/`or` commands.",
|
|
9
|
+
"`ouro vault replace` now prompts for a `new` unlock secret and prints a short recovery handoff to `ouro repair --agent <agent>` instead of dumping generic provider/runtime credential commands into the middle of `ouro up`.",
|
|
10
|
+
"`ouro vault recover` also prompts for a `new` unlock secret while continuing to avoid printing credential values or portable unlock material.",
|
|
11
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the provider repair visual cleanup release."
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.1.0-alpha.396",
|
|
16
|
+
"changes": [
|
|
17
|
+
"Added `ouro repair [--agent <agent>]`, a deterministic vault/provider readiness guide that uses typed repair issues and clear human choices instead of asking for AI diagnosis on known failures.",
|
|
18
|
+
"Provider health checks now attach shared typed repair metadata for locked vaults, missing provider credentials, and failed live provider/model pings, keeping CLI repair, `ouro up`, and agent-facing guidance aligned.",
|
|
19
|
+
"`ouro up` now always runs the live provider-check phase after startup, not only when the daemon was already running, so broken selected providers are surfaced during startup instead of later through confusing agent crashes.",
|
|
20
|
+
"`ouro vault create --agent <agent>` now defaults to the stable agent vault email when no vault locator exists, while still requiring a non-echoing human-provided unlock secret.",
|
|
21
|
+
"Cross-machine and auth/provider docs now include `ouro repair --agent <agent>` in the continuation path for existing bundles and old auth-style agents.",
|
|
22
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the typed readiness repair release."
|
|
23
|
+
]
|
|
24
|
+
},
|
|
4
25
|
{
|
|
5
26
|
"version": "0.1.0-alpha.395",
|
|
6
27
|
"changes": [
|
|
@@ -45,6 +45,7 @@ const machine_identity_1 = require("../machine-identity");
|
|
|
45
45
|
const provider_state_1 = require("../provider-state");
|
|
46
46
|
const provider_credentials_1 = require("../provider-credentials");
|
|
47
47
|
const vault_unlock_1 = require("../../repertoire/vault-unlock");
|
|
48
|
+
const readiness_repair_1 = require("./readiness-repair");
|
|
48
49
|
function isAgentProvider(value) {
|
|
49
50
|
return Object.prototype.hasOwnProperty.call(identity_1.PROVIDER_CREDENTIALS, value);
|
|
50
51
|
}
|
|
@@ -233,6 +234,13 @@ function missingCredentialResult(agentName, lane, provider, model, credentialPat
|
|
|
233
234
|
ok: false,
|
|
234
235
|
error: `${lane} provider ${provider} model ${model} has no credentials in ${agentName}'s vault at ${credentialPath}`,
|
|
235
236
|
fix: `Run 'ouro auth --agent ${agentName} --provider ${provider}' to authenticate this machine, or run 'ouro use --agent ${agentName} --lane ${lane} --provider <provider> --model <model>' to choose a working provider/model.`,
|
|
237
|
+
issue: (0, readiness_repair_1.providerCredentialMissingIssue)({
|
|
238
|
+
agentName,
|
|
239
|
+
lane,
|
|
240
|
+
provider,
|
|
241
|
+
model,
|
|
242
|
+
credentialPath,
|
|
243
|
+
}),
|
|
236
244
|
};
|
|
237
245
|
}
|
|
238
246
|
function invalidPoolResult(agentName, lane, provider, model, pool) {
|
|
@@ -241,6 +249,7 @@ function invalidPoolResult(agentName, lane, provider, model, pool) {
|
|
|
241
249
|
ok: false,
|
|
242
250
|
error: `${lane} provider ${provider} model ${model} cannot read provider credentials because ${agentName}'s credential vault is locked on this machine.`,
|
|
243
251
|
fix: vaultUnlockOrRecoverFix(agentName),
|
|
252
|
+
issue: (0, readiness_repair_1.vaultLockedIssue)(agentName),
|
|
244
253
|
};
|
|
245
254
|
}
|
|
246
255
|
if (pool.reason === "invalid") {
|
|
@@ -268,6 +277,13 @@ function failedPingResult(agentName, lane, provider, model, result) {
|
|
|
268
277
|
ok: false,
|
|
269
278
|
error: `${lane} provider ${provider} model ${model} failed live check: ${result.message}`,
|
|
270
279
|
fix: `Run 'ouro auth --agent ${agentName} --provider ${provider}' to refresh credentials, or run 'ouro use --agent ${agentName} --lane ${lane} --provider <provider> --model <model>' to switch this lane.`,
|
|
280
|
+
issue: (0, readiness_repair_1.providerLiveCheckFailedIssue)({
|
|
281
|
+
agentName,
|
|
282
|
+
lane,
|
|
283
|
+
provider,
|
|
284
|
+
model,
|
|
285
|
+
message: result.message,
|
|
286
|
+
}),
|
|
271
287
|
};
|
|
272
288
|
}
|
|
273
289
|
function credentialRecordForLane(pool, provider) {
|
|
@@ -12,6 +12,7 @@ exports.runAgenticRepair = runAgenticRepair;
|
|
|
12
12
|
const runtime_1 = require("../../nerves/runtime");
|
|
13
13
|
const interactive_repair_1 = require("./interactive-repair");
|
|
14
14
|
const provider_ping_1 = require("../provider-ping");
|
|
15
|
+
const readiness_repair_1 = require("./readiness-repair");
|
|
15
16
|
function buildSystemPrompt(degraded) {
|
|
16
17
|
const agentList = degraded
|
|
17
18
|
.map((d) => `- ${d.agent}: error="${d.errorReason}", hint="${d.fixHint}"`)
|
|
@@ -114,11 +115,18 @@ async function runAgenticRepair(degraded, deps) {
|
|
|
114
115
|
return { repairsAttempted: false, usedAgentic: false };
|
|
115
116
|
}
|
|
116
117
|
const hasLocalRepair = degraded.some(interactive_repair_1.hasRunnableInteractiveRepair);
|
|
118
|
+
const hasKnownTypedRepair = degraded.some((entry) => (0, readiness_repair_1.isKnownReadinessIssue)(entry.issue));
|
|
117
119
|
if (hasLocalRepair) {
|
|
118
120
|
const interactiveResult = await runDeterministicRepair(degraded, deps);
|
|
119
121
|
if (interactiveResult.repairsAttempted) {
|
|
120
122
|
return { repairsAttempted: true, usedAgentic: false };
|
|
121
123
|
}
|
|
124
|
+
if (hasKnownTypedRepair) {
|
|
125
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (hasKnownTypedRepair) {
|
|
129
|
+
return { repairsAttempted: false, usedAgentic: false };
|
|
122
130
|
}
|
|
123
131
|
// Try to discover a working provider for agentic diagnosis
|
|
124
132
|
let discoveredProvider = null;
|
|
@@ -85,10 +85,12 @@ const doctor_1 = require("./doctor");
|
|
|
85
85
|
const cli_render_doctor_1 = require("./cli-render-doctor");
|
|
86
86
|
const interactive_repair_1 = require("./interactive-repair");
|
|
87
87
|
const agentic_repair_1 = require("./agentic-repair");
|
|
88
|
+
const readiness_repair_1 = require("./readiness-repair");
|
|
88
89
|
const startup_tui_1 = require("./startup-tui");
|
|
89
90
|
const stale_bundle_prune_1 = require("./stale-bundle-prune");
|
|
90
91
|
const up_progress_1 = require("./up-progress");
|
|
91
92
|
const provider_ping_1 = require("../provider-ping");
|
|
93
|
+
const agent_discovery_1 = require("./agent-discovery");
|
|
92
94
|
// ── ensureDaemonRunning ──
|
|
93
95
|
const DEFAULT_DAEMON_STARTUP_TIMEOUT_MS = 10_000;
|
|
94
96
|
const DEFAULT_DAEMON_STARTUP_POLL_INTERVAL_MS = 500;
|
|
@@ -96,23 +98,23 @@ const DEFAULT_DAEMON_STARTUP_STABILITY_WINDOW_MS = 1_500;
|
|
|
96
98
|
const DEFAULT_DAEMON_STARTUP_RETRY_LIMIT = 1;
|
|
97
99
|
const DEFAULT_DAEMON_STARTUP_LOG_LINES = 10;
|
|
98
100
|
async function checkAgentProviders(deps, agentsOverride) {
|
|
99
|
-
const agents = agentsOverride ?? await
|
|
101
|
+
const agents = agentsOverride ?? await listCliAgents(deps);
|
|
100
102
|
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
101
103
|
const degraded = [];
|
|
102
104
|
for (const agent of [...new Set(agents)]) {
|
|
103
105
|
try {
|
|
104
|
-
const result = await (
|
|
106
|
+
const result = await checkAgentProviderHealth(agent, bundlesRoot, deps);
|
|
105
107
|
if (result.ok)
|
|
106
108
|
continue;
|
|
107
109
|
const errorReason = result.error ?? "agent provider health check failed";
|
|
108
110
|
const fixHint = result.fix ?? "";
|
|
109
|
-
degraded.push({ agent, errorReason, fixHint });
|
|
111
|
+
degraded.push({ agent, errorReason, fixHint, ...(result.issue ? { issue: result.issue } : {}) });
|
|
110
112
|
(0, runtime_1.emitNervesEvent)({
|
|
111
113
|
level: "error",
|
|
112
114
|
component: "daemon",
|
|
113
115
|
event: "daemon.agent_config_invalid",
|
|
114
116
|
message: errorReason,
|
|
115
|
-
meta: { agent,
|
|
117
|
+
meta: { agent, fixProvided: fixHint.length > 0, source: "already-running-provider-check" },
|
|
116
118
|
});
|
|
117
119
|
}
|
|
118
120
|
catch (error) {
|
|
@@ -127,15 +129,49 @@ async function checkAgentProviders(deps, agentsOverride) {
|
|
|
127
129
|
component: "daemon",
|
|
128
130
|
event: "daemon.agent_config_invalid",
|
|
129
131
|
message: errorReason,
|
|
130
|
-
meta: { agent,
|
|
132
|
+
meta: { agent, fixProvided: true, source: "already-running-provider-check" },
|
|
131
133
|
});
|
|
132
134
|
}
|
|
133
135
|
}
|
|
134
136
|
return degraded;
|
|
135
137
|
}
|
|
138
|
+
async function checkAgentProviderHealth(agentName, bundlesRoot, deps) {
|
|
139
|
+
if (deps.homeDir) {
|
|
140
|
+
return (0, agent_config_check_1.checkAgentConfigWithProviderHealth)(agentName, bundlesRoot, { homeDir: deps.homeDir });
|
|
141
|
+
}
|
|
142
|
+
return (0, agent_config_check_1.checkAgentConfigWithProviderHealth)(agentName, bundlesRoot);
|
|
143
|
+
}
|
|
144
|
+
async function listCliAgents(deps) {
|
|
145
|
+
if (deps.listDiscoveredAgents) {
|
|
146
|
+
return Promise.resolve(deps.listDiscoveredAgents());
|
|
147
|
+
}
|
|
148
|
+
if (deps.bundlesRoot) {
|
|
149
|
+
return (0, agent_discovery_1.listEnabledBundleAgents)({ bundlesRoot: deps.bundlesRoot });
|
|
150
|
+
}
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
136
153
|
async function checkAlreadyRunningAgentProviders(deps) {
|
|
137
154
|
return checkAgentProviders(deps);
|
|
138
155
|
}
|
|
156
|
+
function readinessIssueFromDegraded(entry) {
|
|
157
|
+
return entry.issue ?? (0, readiness_repair_1.genericReadinessIssue)({
|
|
158
|
+
summary: `${entry.agent}: ${entry.errorReason}`,
|
|
159
|
+
...(entry.fixHint ? { fix: entry.fixHint } : {}),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function writeProviderRepairSummary(deps, title, degraded) {
|
|
163
|
+
deps.writeStdout(title);
|
|
164
|
+
for (const entry of degraded) {
|
|
165
|
+
for (const line of (0, readiness_repair_1.renderReadinessIssueNextSteps)(readinessIssueFromDegraded(entry))) {
|
|
166
|
+
deps.writeStdout(line);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function providerRepairCountSummary(count) {
|
|
171
|
+
if (count === 0)
|
|
172
|
+
return "ok";
|
|
173
|
+
return `${count} ${count === 1 ? "needs" : "need"} repair`;
|
|
174
|
+
}
|
|
139
175
|
async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
140
176
|
const remainingDegraded = await checkAgentProviders(deps, repairedAgents);
|
|
141
177
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -149,20 +185,15 @@ async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
|
149
185
|
});
|
|
150
186
|
if (remainingDegraded.length === 0) {
|
|
151
187
|
deps.writeStdout("provider checks recovered after repair");
|
|
152
|
-
return;
|
|
188
|
+
return remainingDegraded;
|
|
153
189
|
}
|
|
154
|
-
deps
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (d.fixHint) {
|
|
158
|
-
deps.writeStdout(` fix: ${d.fixHint}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
deps.writeStdout("run `ouro up` again after applying the remaining fixes.");
|
|
190
|
+
writeProviderRepairSummary(deps, "Still blocked:", remainingDegraded);
|
|
191
|
+
deps.writeStdout("Run `ouro up` again after these are fixed.");
|
|
192
|
+
return remainingDegraded;
|
|
162
193
|
}
|
|
163
194
|
async function checkProviderHealthBeforeChat(agentName, deps) {
|
|
164
195
|
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
165
|
-
const result = await (
|
|
196
|
+
const result = await checkAgentProviderHealth(agentName, bundlesRoot, deps);
|
|
166
197
|
if (!result.ok) {
|
|
167
198
|
const output = `${result.error}\n${result.fix ? ` fix: ${result.fix}` : ""}`;
|
|
168
199
|
deps.writeStdout(output);
|
|
@@ -186,7 +217,7 @@ function mergeStartupStability(stability, extraDegraded) {
|
|
|
186
217
|
}
|
|
187
218
|
return { stable, degraded };
|
|
188
219
|
}
|
|
189
|
-
async function ensureDaemonRunning(deps) {
|
|
220
|
+
async function ensureDaemonRunning(deps, options = {}) {
|
|
190
221
|
const readLatestDaemonStartupEvent = () => {
|
|
191
222
|
try {
|
|
192
223
|
// The daemon writes structured events to daemon.ndjson in the first
|
|
@@ -230,7 +261,7 @@ async function ensureDaemonRunning(deps) {
|
|
|
230
261
|
}
|
|
231
262
|
return null;
|
|
232
263
|
};
|
|
233
|
-
const alive = await deps.checkSocketAlive(deps.socketPath);
|
|
264
|
+
const alive = options.initialAlive ?? await deps.checkSocketAlive(deps.socketPath);
|
|
234
265
|
if (alive) {
|
|
235
266
|
const localRuntime = (0, runtime_metadata_1.getRuntimeMetadata)();
|
|
236
267
|
let runningRuntimePromise = null;
|
|
@@ -686,13 +717,6 @@ function readVaultRecoverSource(sourcePath) {
|
|
|
686
717
|
runtimeConfig: recoverRuntimeConfig(parsed),
|
|
687
718
|
};
|
|
688
719
|
}
|
|
689
|
-
function defaultStableVaultEmail(agentName) {
|
|
690
|
-
const local = agentName
|
|
691
|
-
.toLowerCase()
|
|
692
|
-
.replace(/[^a-z0-9._-]+/g, "-")
|
|
693
|
-
.replace(/^-+|-+$/g, "") || "agent";
|
|
694
|
-
return `${local}@ouro.bot`;
|
|
695
|
-
}
|
|
696
720
|
function isGeneratedRepairVaultEmail(email) {
|
|
697
721
|
const [local, domain] = email.trim().split("@");
|
|
698
722
|
return domain?.toLowerCase() === "ouro.bot" && /\+(?:replaced|recovered)-\d{14}(?:$|\+)/i.test(local);
|
|
@@ -701,7 +725,7 @@ function defaultRepairVaultEmail(agentName, config) {
|
|
|
701
725
|
const configuredEmail = config.vault?.email?.trim();
|
|
702
726
|
if (configuredEmail && !isGeneratedRepairVaultEmail(configuredEmail))
|
|
703
727
|
return configuredEmail;
|
|
704
|
-
return defaultStableVaultEmail(agentName);
|
|
728
|
+
return (0, identity_1.defaultStableVaultEmail)(agentName);
|
|
705
729
|
}
|
|
706
730
|
function ensureVaultSecretPrompt(promptSecret, action) {
|
|
707
731
|
if (promptSecret)
|
|
@@ -765,13 +789,9 @@ async function executeVaultCreate(command, deps) {
|
|
|
765
789
|
}
|
|
766
790
|
if (command.generateUnlockSecret)
|
|
767
791
|
rejectGeneratedVaultUnlockSecret("create");
|
|
768
|
-
const prompt = deps.promptInput;
|
|
769
792
|
const { configPath, config } = (0, auth_flow_1.readAgentConfigForAgent)(command.agent, deps.bundlesRoot);
|
|
770
793
|
const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
|
|
771
|
-
const email = command.email ?? config.vault?.email ??
|
|
772
|
-
if (!email) {
|
|
773
|
-
throw new Error("vault create requires --email <email> when the agent bundle has no vault.email");
|
|
774
|
-
}
|
|
794
|
+
const email = command.email ?? config.vault?.email ?? configuredVault.email;
|
|
775
795
|
const promptSecret = ensureVaultSecretPrompt(deps.promptSecret, "create");
|
|
776
796
|
const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
|
|
777
797
|
const unlockSecret = (await promptSecret(`Choose Ouro vault unlock secret for ${email}: `)).trim();
|
|
@@ -818,7 +838,7 @@ async function executeVaultReplace(command, deps) {
|
|
|
818
838
|
const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
|
|
819
839
|
const email = command.email ?? defaultRepairVaultEmail(command.agent, config);
|
|
820
840
|
const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
|
|
821
|
-
const unlockSecret = (await promptSecret(`Choose Ouro vault unlock secret for ${email}: `)).trim();
|
|
841
|
+
const unlockSecret = (await promptSecret(`Choose new Ouro vault unlock secret for ${email}: `)).trim();
|
|
822
842
|
if (!unlockSecret) {
|
|
823
843
|
throw new Error("vault replace requires an unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
|
|
824
844
|
}
|
|
@@ -839,13 +859,8 @@ async function executeVaultReplace(command, deps) {
|
|
|
839
859
|
`vault replaced for ${command.agent}`,
|
|
840
860
|
`vault: ${email} at ${serverUrl}`,
|
|
841
861
|
`local unlock store: ${repair.store.kind}${repair.store.secure ? "" : " (explicit plaintext fallback)"}`,
|
|
842
|
-
"
|
|
843
|
-
|
|
844
|
-
"Re-auth/re-enter the credentials this agent should use:",
|
|
845
|
-
` ouro auth --agent ${command.agent} --provider <provider>`,
|
|
846
|
-
` ouro vault config set --agent ${command.agent} --key <field>`,
|
|
847
|
-
` ouro provider refresh --agent ${command.agent}`,
|
|
848
|
-
` ouro auth verify --agent ${command.agent}`,
|
|
862
|
+
"imported: none",
|
|
863
|
+
`next: ouro repair --agent ${command.agent}`,
|
|
849
864
|
"Keep the vault unlock secret saved outside Ouro. Another machine will need it once.",
|
|
850
865
|
].join("\n");
|
|
851
866
|
deps.writeStdout(message);
|
|
@@ -864,7 +879,7 @@ async function executeVaultRecover(command, deps) {
|
|
|
864
879
|
const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
|
|
865
880
|
const email = command.email ?? defaultRepairVaultEmail(command.agent, config);
|
|
866
881
|
const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
|
|
867
|
-
const unlockSecret = (await promptSecret(`Choose Ouro vault unlock secret for ${email}: `)).trim();
|
|
882
|
+
const unlockSecret = (await promptSecret(`Choose new Ouro vault unlock secret for ${email}: `)).trim();
|
|
868
883
|
if (!unlockSecret) {
|
|
869
884
|
throw new Error("vault recover requires an unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
|
|
870
885
|
}
|
|
@@ -1356,6 +1371,103 @@ async function executeProviderRefresh(command, deps) {
|
|
|
1356
1371
|
deps.writeStdout(message);
|
|
1357
1372
|
return message;
|
|
1358
1373
|
}
|
|
1374
|
+
async function readinessReportForAgent(agent, deps) {
|
|
1375
|
+
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
1376
|
+
try {
|
|
1377
|
+
const result = await checkAgentProviderHealth(agent, bundlesRoot, deps);
|
|
1378
|
+
if (result.ok) {
|
|
1379
|
+
return { agent, ok: true, issues: [] };
|
|
1380
|
+
}
|
|
1381
|
+
else {
|
|
1382
|
+
const issue = result.issue ?? (0, readiness_repair_1.genericReadinessIssue)({
|
|
1383
|
+
summary: result.error ?? `${agent} is not ready.`,
|
|
1384
|
+
...(result.fix ? { fix: result.fix } : {}),
|
|
1385
|
+
});
|
|
1386
|
+
return { agent, ok: false, issues: [issue] };
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
catch (error) {
|
|
1390
|
+
return {
|
|
1391
|
+
agent,
|
|
1392
|
+
ok: false,
|
|
1393
|
+
issues: [(0, readiness_repair_1.genericReadinessIssue)({
|
|
1394
|
+
summary: `${agent} readiness check failed.`,
|
|
1395
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
1396
|
+
fix: "Run 'ouro doctor' for diagnostics, then retry 'ouro repair'.",
|
|
1397
|
+
})],
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
async function executeReadinessRepairAction(agent, action, deps) {
|
|
1402
|
+
if (action.kind === "vault-unlock") {
|
|
1403
|
+
await executeVaultUnlock({ kind: "vault.unlock", agent }, deps);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
if (action.kind === "vault-replace") {
|
|
1407
|
+
await executeVaultReplace({ kind: "vault.replace", agent }, deps);
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (action.kind === "provider-auth") {
|
|
1411
|
+
const provider = action.provider;
|
|
1412
|
+
const authRunner = deps.runAuthFlow ?? auth_flow_1.runRuntimeAuthFlow;
|
|
1413
|
+
const result = await authRunner({
|
|
1414
|
+
agentName: agent,
|
|
1415
|
+
provider,
|
|
1416
|
+
promptInput: deps.promptInput,
|
|
1417
|
+
});
|
|
1418
|
+
deps.writeStdout(result.message);
|
|
1419
|
+
await executeProviderRefresh({ kind: "provider.refresh", agent }, deps);
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
deps.writeStdout(`manual step for ${agent}: ${action.command}`);
|
|
1423
|
+
}
|
|
1424
|
+
async function executeRepair(command, deps) {
|
|
1425
|
+
const agents = command.agent
|
|
1426
|
+
? [command.agent]
|
|
1427
|
+
: await listCliAgents(deps);
|
|
1428
|
+
const uniqueAgents = [...new Set(agents)];
|
|
1429
|
+
const lines = [];
|
|
1430
|
+
const repairDeps = {
|
|
1431
|
+
...deps,
|
|
1432
|
+
writeStdout: (text) => {
|
|
1433
|
+
lines.push(text);
|
|
1434
|
+
deps.writeStdout(text);
|
|
1435
|
+
},
|
|
1436
|
+
};
|
|
1437
|
+
if (uniqueAgents.length === 0) {
|
|
1438
|
+
const message = "no agents found to repair.";
|
|
1439
|
+
repairDeps.writeStdout(message);
|
|
1440
|
+
return message;
|
|
1441
|
+
}
|
|
1442
|
+
else {
|
|
1443
|
+
const reports = await Promise.all(uniqueAgents.map((agent) => readinessReportForAgent(agent, repairDeps)));
|
|
1444
|
+
for (const report of reports) {
|
|
1445
|
+
if (report.ok) {
|
|
1446
|
+
repairDeps.writeStdout(`${report.agent}: ready`);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
await (0, readiness_repair_1.runGuidedReadinessRepair)(reports, {
|
|
1450
|
+
promptInput: deps.promptInput,
|
|
1451
|
+
writeStdout: repairDeps.writeStdout,
|
|
1452
|
+
runRepairAction: async (agentName, action) => executeReadinessRepairAction(agentName, action, repairDeps),
|
|
1453
|
+
});
|
|
1454
|
+
return lines.join("\n");
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
function readinessReportsFromDegraded(degraded) {
|
|
1458
|
+
return degraded.map((entry) => ({
|
|
1459
|
+
agent: entry.agent,
|
|
1460
|
+
ok: false,
|
|
1461
|
+
issues: [readinessIssueFromDegraded(entry)],
|
|
1462
|
+
}));
|
|
1463
|
+
}
|
|
1464
|
+
async function runReadinessRepairForDegraded(degraded, deps) {
|
|
1465
|
+
return (0, readiness_repair_1.runGuidedReadinessRepair)(readinessReportsFromDegraded(degraded), {
|
|
1466
|
+
promptInput: deps.promptInput,
|
|
1467
|
+
writeStdout: deps.writeStdout,
|
|
1468
|
+
runRepairAction: async (agentName, action) => executeReadinessRepairAction(agentName, action, deps),
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1359
1471
|
async function executeLegacyAuthSwitch(command, deps) {
|
|
1360
1472
|
const { state } = readOrBootstrapProviderState(command.agent, deps);
|
|
1361
1473
|
const lanes = command.facing
|
|
@@ -2119,6 +2231,36 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2119
2231
|
bundlesRoot: deps.bundlesRoot ?? bundlesRoot,
|
|
2120
2232
|
promptInput: deps.promptInput,
|
|
2121
2233
|
});
|
|
2234
|
+
const daemonAliveBeforeStart = await deps.checkSocketAlive(deps.socketPath);
|
|
2235
|
+
let providerChecksAlreadyRun = false;
|
|
2236
|
+
if (!daemonAliveBeforeStart) {
|
|
2237
|
+
progress.startPhase("provider checks");
|
|
2238
|
+
const preflightProviderDegraded = await checkAgentProviders(deps);
|
|
2239
|
+
providerChecksAlreadyRun = true;
|
|
2240
|
+
progress.completePhase("provider checks", providerRepairCountSummary(preflightProviderDegraded.length));
|
|
2241
|
+
if (preflightProviderDegraded.length > 0) {
|
|
2242
|
+
progress.end();
|
|
2243
|
+
if (command.noRepair) {
|
|
2244
|
+
writeProviderRepairSummary(deps, "Provider checks need repair:", preflightProviderDegraded);
|
|
2245
|
+
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2246
|
+
deps.writeStdout(message);
|
|
2247
|
+
return message;
|
|
2248
|
+
}
|
|
2249
|
+
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
2250
|
+
if (!repairResult.repairsAttempted) {
|
|
2251
|
+
writeProviderRepairSummary(deps, "Provider checks still need repair:", preflightProviderDegraded);
|
|
2252
|
+
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2253
|
+
deps.writeStdout(message);
|
|
2254
|
+
return message;
|
|
2255
|
+
}
|
|
2256
|
+
const remainingDegraded = await reportPostRepairProviderHealth(deps, preflightProviderDegraded.map((entry) => entry.agent));
|
|
2257
|
+
if (remainingDegraded.length > 0) {
|
|
2258
|
+
const message = "daemon not started: provider checks still need repair.";
|
|
2259
|
+
deps.writeStdout(message);
|
|
2260
|
+
return message;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2122
2264
|
progress.startPhase("starting daemon");
|
|
2123
2265
|
const daemonResult = await ensureDaemonRunning({
|
|
2124
2266
|
...deps,
|
|
@@ -2126,12 +2268,12 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2126
2268
|
;
|
|
2127
2269
|
progress.announceStep?.(label);
|
|
2128
2270
|
},
|
|
2129
|
-
});
|
|
2130
|
-
if (daemonResult.alreadyRunning) {
|
|
2271
|
+
}, { initialAlive: daemonAliveBeforeStart });
|
|
2272
|
+
if (!providerChecksAlreadyRun || daemonResult.alreadyRunning) {
|
|
2131
2273
|
progress.startPhase("provider checks");
|
|
2132
2274
|
const providerDegraded = await checkAlreadyRunningAgentProviders(deps);
|
|
2133
2275
|
daemonResult.stability = mergeStartupStability(daemonResult.stability, providerDegraded);
|
|
2134
|
-
progress.completePhase("provider checks", providerDegraded.length
|
|
2276
|
+
progress.completePhase("provider checks", providerRepairCountSummary(providerDegraded.length));
|
|
2135
2277
|
}
|
|
2136
2278
|
progress.end();
|
|
2137
2279
|
deps.writeStdout(daemonResult.message);
|
|
@@ -2139,13 +2281,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2139
2281
|
if (daemonResult.stability?.degraded && daemonResult.stability.degraded.length > 0) {
|
|
2140
2282
|
if (command.noRepair) {
|
|
2141
2283
|
// --no-repair: write degraded summary and skip interactive repair
|
|
2142
|
-
deps
|
|
2143
|
-
for (const d of daemonResult.stability.degraded) {
|
|
2144
|
-
deps.writeStdout(` ${d.agent}: ${d.errorReason}`);
|
|
2145
|
-
if (d.fixHint) {
|
|
2146
|
-
deps.writeStdout(` fix: ${d.fixHint}`);
|
|
2147
|
-
}
|
|
2148
|
-
}
|
|
2284
|
+
writeProviderRepairSummary(deps, "Provider checks need repair:", daemonResult.stability.degraded);
|
|
2149
2285
|
(0, runtime_1.emitNervesEvent)({
|
|
2150
2286
|
level: "warn",
|
|
2151
2287
|
component: "daemon",
|
|
@@ -2794,6 +2930,9 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2794
2930
|
if (command.kind === "provider.refresh") {
|
|
2795
2931
|
return executeProviderRefresh(command, deps);
|
|
2796
2932
|
}
|
|
2933
|
+
if (command.kind === "repair") {
|
|
2934
|
+
return executeRepair(command, deps);
|
|
2935
|
+
}
|
|
2797
2936
|
if (command.kind === "vault.unlock") {
|
|
2798
2937
|
return executeVaultUnlock(command, deps);
|
|
2799
2938
|
}
|
|
@@ -175,6 +175,12 @@ exports.COMMAND_REGISTRY = {
|
|
|
175
175
|
usage: "ouro check --agent <name> --lane outward|inner",
|
|
176
176
|
example: "ouro check --agent ouroboros --lane outward",
|
|
177
177
|
},
|
|
178
|
+
repair: {
|
|
179
|
+
category: "Auth",
|
|
180
|
+
description: "Guide vault and provider readiness repair without invoking AI diagnosis for known issues",
|
|
181
|
+
usage: "ouro repair [--agent <name>]",
|
|
182
|
+
example: "ouro repair --agent ouroboros",
|
|
183
|
+
},
|
|
178
184
|
provider: {
|
|
179
185
|
category: "Auth",
|
|
180
186
|
description: "Refresh daemon provider credentials from an agent vault",
|
|
@@ -76,6 +76,7 @@ function usage() {
|
|
|
76
76
|
" ouro status --agent <name>",
|
|
77
77
|
" ouro use --agent <name> --lane outward|inner --provider <provider> --model <model> [--force]",
|
|
78
78
|
" ouro check --agent <name> --lane outward|inner",
|
|
79
|
+
" ouro repair [--agent <name>]",
|
|
79
80
|
" ouro provider refresh --agent <name>",
|
|
80
81
|
" ouro outlook [--json]",
|
|
81
82
|
" ouro -v|--version",
|
|
@@ -1033,6 +1034,12 @@ function parseOuroCommand(args) {
|
|
|
1033
1034
|
return parseProviderUseCommand(args.slice(1));
|
|
1034
1035
|
if (head === "check")
|
|
1035
1036
|
return parseProviderCheckCommand(args.slice(1));
|
|
1037
|
+
if (head === "repair") {
|
|
1038
|
+
const { agent, rest } = extractAgentFlag(args.slice(1));
|
|
1039
|
+
if (rest.length > 0)
|
|
1040
|
+
throw new Error("Usage: ouro repair [--agent <name>]");
|
|
1041
|
+
return agent ? { kind: "repair", agent } : { kind: "repair" };
|
|
1042
|
+
}
|
|
1036
1043
|
if (head === "provider")
|
|
1037
1044
|
return parseProviderCommand(args.slice(1));
|
|
1038
1045
|
if (head === "logs") {
|
|
@@ -24,6 +24,9 @@ function isConfigError(degraded) {
|
|
|
24
24
|
return degraded.fixHint.length > 0 && !isVaultUnlockIssue(degraded) && !isCredentialIssue(degraded);
|
|
25
25
|
}
|
|
26
26
|
function hasRunnableInteractiveRepair(degraded) {
|
|
27
|
+
if (degraded.issue?.actions.some((action) => typedActionToRunnable(degraded, action) !== undefined)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
27
30
|
return isVaultUnlockIssue(degraded) || isCredentialIssue(degraded);
|
|
28
31
|
}
|
|
29
32
|
function isAgentProvider(value) {
|
|
@@ -68,6 +71,11 @@ function writeDeclinedRepair(degraded, command, deps) {
|
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
function runnableRepairActionFor(degraded) {
|
|
74
|
+
const typedAction = degraded.issue?.actions
|
|
75
|
+
.map((action) => typedActionToRunnable(degraded, action))
|
|
76
|
+
.find((action) => action !== undefined);
|
|
77
|
+
if (typedAction)
|
|
78
|
+
return typedAction;
|
|
71
79
|
if (isVaultUnlockIssue(degraded)) {
|
|
72
80
|
return { kind: "vault-unlock", label: "vault unlock", command: vaultUnlockCommandFor(degraded) };
|
|
73
81
|
}
|
|
@@ -81,6 +89,22 @@ function runnableRepairActionFor(degraded) {
|
|
|
81
89
|
}
|
|
82
90
|
return undefined;
|
|
83
91
|
}
|
|
92
|
+
function typedActionToRunnable(degraded, action) {
|
|
93
|
+
if (action.executable === false || action.command.includes("<"))
|
|
94
|
+
return undefined;
|
|
95
|
+
if (action.kind === "vault-unlock") {
|
|
96
|
+
return { kind: "vault-unlock", label: "vault unlock", command: action.command };
|
|
97
|
+
}
|
|
98
|
+
if (action.kind === "provider-auth") {
|
|
99
|
+
return {
|
|
100
|
+
kind: "provider-auth",
|
|
101
|
+
label: "provider auth",
|
|
102
|
+
command: action.command || `ouro auth --agent ${degraded.agent}`,
|
|
103
|
+
provider: action.provider,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
84
108
|
function writeRepairQueueSummary(degraded, deps) {
|
|
85
109
|
const repairable = degraded
|
|
86
110
|
.map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.vaultLockedIssue = vaultLockedIssue;
|
|
4
|
+
exports.providerCredentialMissingIssue = providerCredentialMissingIssue;
|
|
5
|
+
exports.providerLiveCheckFailedIssue = providerLiveCheckFailedIssue;
|
|
6
|
+
exports.genericReadinessIssue = genericReadinessIssue;
|
|
7
|
+
exports.isKnownReadinessIssue = isKnownReadinessIssue;
|
|
8
|
+
exports.renderReadinessIssue = renderReadinessIssue;
|
|
9
|
+
exports.renderReadinessIssueNextSteps = renderReadinessIssueNextSteps;
|
|
10
|
+
exports.runGuidedReadinessRepair = runGuidedReadinessRepair;
|
|
11
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
12
|
+
function vaultLockedIssue(agentName) {
|
|
13
|
+
return {
|
|
14
|
+
kind: "vault-locked",
|
|
15
|
+
severity: "blocked",
|
|
16
|
+
actor: "human-required",
|
|
17
|
+
summary: `${agentName}: vault locked`,
|
|
18
|
+
detail: "Pick the path that matches what the human actually has. Ouro will not print or store the unlock secret as a portable file.",
|
|
19
|
+
actions: [
|
|
20
|
+
{
|
|
21
|
+
kind: "vault-unlock",
|
|
22
|
+
label: "Unlock with saved secret",
|
|
23
|
+
command: `ouro vault unlock --agent ${agentName}`,
|
|
24
|
+
actor: "human-required",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
kind: "vault-replace",
|
|
28
|
+
label: "Create empty replacement vault",
|
|
29
|
+
command: `ouro vault replace --agent ${agentName}`,
|
|
30
|
+
actor: "human-required",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
kind: "vault-recover",
|
|
34
|
+
label: "Recover from JSON export",
|
|
35
|
+
command: `ouro vault recover --agent ${agentName} --from <json>`,
|
|
36
|
+
actor: "human-required",
|
|
37
|
+
executable: false,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function providerCredentialMissingIssue(input) {
|
|
43
|
+
return {
|
|
44
|
+
kind: "provider-credentials-missing",
|
|
45
|
+
severity: "blocked",
|
|
46
|
+
actor: "human-required",
|
|
47
|
+
summary: `${input.agentName}: missing ${input.provider} credentials (${input.lane}, ${input.model})`,
|
|
48
|
+
detail: `source: ${input.credentialPath}`,
|
|
49
|
+
actions: [
|
|
50
|
+
{
|
|
51
|
+
kind: "provider-auth",
|
|
52
|
+
label: `Authenticate ${input.provider}`,
|
|
53
|
+
command: `ouro auth --agent ${input.agentName} --provider ${input.provider}`,
|
|
54
|
+
actor: "human-required",
|
|
55
|
+
provider: input.provider,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
kind: "provider-use",
|
|
59
|
+
label: "Choose another provider/model",
|
|
60
|
+
command: `ouro use --agent ${input.agentName} --lane ${input.lane} --provider <provider> --model <model>`,
|
|
61
|
+
actor: "human-choice",
|
|
62
|
+
executable: false,
|
|
63
|
+
lane: input.lane,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function providerLiveCheckFailedIssue(input) {
|
|
69
|
+
return {
|
|
70
|
+
kind: "provider-live-check-failed",
|
|
71
|
+
severity: "blocked",
|
|
72
|
+
actor: "human-choice",
|
|
73
|
+
summary: `${input.agentName}: ${input.lane} provider ${input.provider} / ${input.model} failed live check`,
|
|
74
|
+
detail: input.message,
|
|
75
|
+
actions: [
|
|
76
|
+
{
|
|
77
|
+
kind: "provider-auth",
|
|
78
|
+
label: `Refresh ${input.provider} credentials`,
|
|
79
|
+
command: `ouro auth --agent ${input.agentName} --provider ${input.provider}`,
|
|
80
|
+
actor: "human-required",
|
|
81
|
+
provider: input.provider,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
kind: "provider-use",
|
|
85
|
+
label: "Choose a different working provider/model for this lane",
|
|
86
|
+
command: `ouro use --agent ${input.agentName} --lane ${input.lane} --provider <provider> --model <model>`,
|
|
87
|
+
actor: "human-choice",
|
|
88
|
+
executable: false,
|
|
89
|
+
lane: input.lane,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function genericReadinessIssue(input) {
|
|
95
|
+
return {
|
|
96
|
+
kind: "generic",
|
|
97
|
+
severity: "degraded",
|
|
98
|
+
actor: "human-choice",
|
|
99
|
+
summary: input.summary,
|
|
100
|
+
...(input.detail ? { detail: input.detail } : {}),
|
|
101
|
+
actions: input.fix
|
|
102
|
+
? [{
|
|
103
|
+
kind: "provider-use",
|
|
104
|
+
label: "Follow the printed fix",
|
|
105
|
+
command: input.fix,
|
|
106
|
+
actor: "human-choice",
|
|
107
|
+
executable: false,
|
|
108
|
+
}]
|
|
109
|
+
: [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function isKnownReadinessIssue(issue) {
|
|
113
|
+
return !!issue && issue.kind !== "generic";
|
|
114
|
+
}
|
|
115
|
+
function renderReadinessIssue(issue) {
|
|
116
|
+
const lines = [issue.summary];
|
|
117
|
+
if (issue.detail) {
|
|
118
|
+
lines.push(` ${issue.detail}`);
|
|
119
|
+
}
|
|
120
|
+
issue.actions.forEach((action, index) => {
|
|
121
|
+
lines.push(`${index + 1}. ${action.label}`);
|
|
122
|
+
lines.push(` ${action.command}`);
|
|
123
|
+
});
|
|
124
|
+
lines.push(`${issue.actions.length + 1}. Skip for now`);
|
|
125
|
+
return lines.join("\n");
|
|
126
|
+
}
|
|
127
|
+
function renderReadinessIssueNextSteps(issue) {
|
|
128
|
+
const lines = [` ${issue.summary}`];
|
|
129
|
+
if (issue.detail && issue.kind !== "vault-locked") {
|
|
130
|
+
lines.push(` ${issue.detail}`);
|
|
131
|
+
}
|
|
132
|
+
issue.actions.forEach((action, index) => {
|
|
133
|
+
lines.push(` ${index === 0 ? "next" : "or"}: ${action.command}`);
|
|
134
|
+
});
|
|
135
|
+
return lines;
|
|
136
|
+
}
|
|
137
|
+
function selectedActionFor(answer, issue) {
|
|
138
|
+
const selected = Number.parseInt(answer.trim(), 10);
|
|
139
|
+
if (!Number.isFinite(selected))
|
|
140
|
+
return null;
|
|
141
|
+
if (selected === issue.actions.length + 1)
|
|
142
|
+
return "skip";
|
|
143
|
+
if (selected < 1 || selected > issue.actions.length)
|
|
144
|
+
return null;
|
|
145
|
+
/* v8 ignore next -- defensive: bounds were checked above, but keep sparse arrays harmless @preserve */
|
|
146
|
+
return issue.actions[selected - 1] ?? null;
|
|
147
|
+
}
|
|
148
|
+
function isExecutableAction(action) {
|
|
149
|
+
if (action.executable === false)
|
|
150
|
+
return false;
|
|
151
|
+
return !action.command.includes("<");
|
|
152
|
+
}
|
|
153
|
+
async function runGuidedReadinessRepair(reports, deps) {
|
|
154
|
+
(0, runtime_1.emitNervesEvent)({
|
|
155
|
+
level: "info",
|
|
156
|
+
component: "daemon",
|
|
157
|
+
event: "daemon.readiness_repair_start",
|
|
158
|
+
message: "guided readiness repair started",
|
|
159
|
+
meta: { reportCount: reports.length },
|
|
160
|
+
});
|
|
161
|
+
let repairsAttempted = false;
|
|
162
|
+
for (const report of reports) {
|
|
163
|
+
if (report.ok || report.issues.length === 0)
|
|
164
|
+
continue;
|
|
165
|
+
for (const issue of report.issues) {
|
|
166
|
+
deps.writeStdout(renderReadinessIssue(issue));
|
|
167
|
+
if (!deps.promptInput) {
|
|
168
|
+
deps.writeStdout(`manual repair required for ${report.agent}; run one of the commands above.`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const answer = await deps.promptInput(`Choose [1-${issue.actions.length + 1}]: `);
|
|
172
|
+
const action = selectedActionFor(answer, issue);
|
|
173
|
+
if (action === "skip") {
|
|
174
|
+
deps.writeStdout(`skipped ${report.agent} for now.`);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (!action) {
|
|
178
|
+
deps.writeStdout(`invalid choice for ${report.agent}; no repair attempted.`);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!isExecutableAction(action)) {
|
|
182
|
+
deps.writeStdout(`manual step for ${report.agent}: ${action.command}`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (!deps.runRepairAction) {
|
|
186
|
+
deps.writeStdout(`repair runner unavailable for ${report.agent}; run \`${action.command}\` manually.`);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
await deps.runRepairAction(report.agent, action, issue);
|
|
191
|
+
repairsAttempted = true;
|
|
192
|
+
deps.writeStdout(`repair step finished for ${report.agent}.`);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
196
|
+
repairsAttempted = true;
|
|
197
|
+
deps.writeStdout(`repair error for ${report.agent}: ${message}`);
|
|
198
|
+
(0, runtime_1.emitNervesEvent)({
|
|
199
|
+
level: "error",
|
|
200
|
+
component: "daemon",
|
|
201
|
+
event: "daemon.readiness_repair_error",
|
|
202
|
+
message: "guided readiness repair action failed",
|
|
203
|
+
meta: { agent: report.agent, issue: issue.kind, action: action.kind, error: message },
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
(0, runtime_1.emitNervesEvent)({
|
|
209
|
+
level: "info",
|
|
210
|
+
component: "daemon",
|
|
211
|
+
event: "daemon.readiness_repair_end",
|
|
212
|
+
message: "guided readiness repair completed",
|
|
213
|
+
meta: { repairsAttempted },
|
|
214
|
+
});
|
|
215
|
+
return { repairsAttempted };
|
|
216
|
+
}
|
package/dist/heart/identity.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.PROVIDER_CREDENTIALS = void 0;
|
|
37
|
+
exports.defaultStableVaultEmail = defaultStableVaultEmail;
|
|
37
38
|
exports.resolveVaultConfig = resolveVaultConfig;
|
|
38
39
|
exports.normalizeSenses = normalizeSenses;
|
|
39
40
|
exports.buildDefaultAgentTemplate = buildDefaultAgentTemplate;
|
|
@@ -76,13 +77,20 @@ exports.DEFAULT_AGENT_PHRASES = {
|
|
|
76
77
|
followup: ["processing"],
|
|
77
78
|
};
|
|
78
79
|
exports.DEFAULT_VAULT_SERVER_URL = "https://vault.ouroboros.bot";
|
|
80
|
+
function defaultStableVaultEmail(agentName) {
|
|
81
|
+
const local = agentName
|
|
82
|
+
.toLowerCase()
|
|
83
|
+
.replace(/[^a-z0-9._-]+/g, "-")
|
|
84
|
+
.replace(/^-+|-+$/g, "") || "agent";
|
|
85
|
+
return `${local}@ouro.bot`;
|
|
86
|
+
}
|
|
79
87
|
/**
|
|
80
88
|
* Resolve the vault config for an agent, applying defaults.
|
|
81
89
|
* If vault is not configured in agent.json, returns default values.
|
|
82
90
|
*/
|
|
83
91
|
function resolveVaultConfig(agentName, config) {
|
|
84
92
|
return {
|
|
85
|
-
email: config?.email ??
|
|
93
|
+
email: config?.email ?? defaultStableVaultEmail(agentName),
|
|
86
94
|
serverUrl: config?.serverUrl ?? exports.DEFAULT_VAULT_SERVER_URL,
|
|
87
95
|
};
|
|
88
96
|
}
|