@ouro.bot/cli 0.1.0-alpha.396 → 0.1.0-alpha.398
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 +19 -0
- package/dist/heart/auth/auth-flow.js +14 -0
- package/dist/heart/daemon/cli-exec.js +39 -43
- package/dist/heart/daemon/readiness-repair.js +25 -14
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
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.398",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro auth --agent <agent> --provider <provider>` now prints safe progress breadcrumbs while it checks vault access, runs provider login, stores credentials in the agent vault, refreshes the local provider snapshot, and verifies the provider.",
|
|
8
|
+
"Provider auth launched from `ouro repair` and hatch bootstrap now uses the same auth progress hook, so browser/login flows no longer leave humans staring at a silent cursor after the provider says login succeeded.",
|
|
9
|
+
"Auth progress messages are phase labels only; they never include OAuth tokens, API keys, vault unlock secrets, or credential payload values.",
|
|
10
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the auth progress breadcrumb release."
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"version": "0.1.0-alpha.397",
|
|
15
|
+
"changes": [
|
|
16
|
+
"`ouro up` provider repair output now uses compact readiness cards and `need repair` progress labels instead of dense degraded-agent prose.",
|
|
17
|
+
"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.",
|
|
18
|
+
"`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`.",
|
|
19
|
+
"`ouro vault recover` also prompts for a `new` unlock secret while continuing to avoid printing credential values or portable unlock material.",
|
|
20
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the provider repair visual cleanup release."
|
|
21
|
+
]
|
|
22
|
+
},
|
|
4
23
|
{
|
|
5
24
|
"version": "0.1.0-alpha.396",
|
|
6
25
|
"changes": [
|
|
@@ -187,6 +187,9 @@ function ensurePromptInput(promptInput, provider) {
|
|
|
187
187
|
return promptInput;
|
|
188
188
|
throw new Error(`No prompt input is available for ${provider} authentication.`);
|
|
189
189
|
}
|
|
190
|
+
function writeAuthProgress(input, message) {
|
|
191
|
+
input.onProgress?.(message);
|
|
192
|
+
}
|
|
190
193
|
function validateAnthropicToken(token) {
|
|
191
194
|
const trimmed = token.trim();
|
|
192
195
|
if (!trimmed) {
|
|
@@ -206,10 +209,12 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
206
209
|
if (input.provider === "github-copilot") {
|
|
207
210
|
let token = process.env.GH_TOKEN?.trim() || process.env.GITHUB_TOKEN?.trim() || "";
|
|
208
211
|
if (!token) {
|
|
212
|
+
writeAuthProgress(input, "checking GitHub CLI credentials...");
|
|
209
213
|
const result = spawnSync("gh", ["auth", "token"], { encoding: "utf8" });
|
|
210
214
|
token = (result.status === 0 && result.stdout ? result.stdout.trim() : "");
|
|
211
215
|
}
|
|
212
216
|
if (!token) {
|
|
217
|
+
writeAuthProgress(input, "starting GitHub login...");
|
|
213
218
|
(0, runtime_1.emitNervesEvent)({
|
|
214
219
|
component: "daemon",
|
|
215
220
|
event: "daemon.auth_gh_login_start",
|
|
@@ -228,6 +233,7 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
228
233
|
throw new Error("gh auth login completed but no token was found. Run `gh auth login` and try again.");
|
|
229
234
|
}
|
|
230
235
|
}
|
|
236
|
+
writeAuthProgress(input, "checking GitHub Copilot access...");
|
|
231
237
|
const response = await fetch("https://api.github.com/copilot_internal/user", {
|
|
232
238
|
headers: { Authorization: `Bearer ${token}` },
|
|
233
239
|
});
|
|
@@ -252,6 +258,7 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
252
258
|
message: "starting codex login for runtime auth",
|
|
253
259
|
meta: { agentName: input.agentName },
|
|
254
260
|
});
|
|
261
|
+
writeAuthProgress(input, "starting openai-codex browser login...");
|
|
255
262
|
const result = spawnSync("codex", ["login"], { stdio: "inherit" });
|
|
256
263
|
if (result.error) {
|
|
257
264
|
throw new Error(`Failed to run 'codex login': ${result.error.message}`);
|
|
@@ -259,6 +266,7 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
259
266
|
if (result.status !== 0) {
|
|
260
267
|
throw new Error(`'codex login' exited with status ${result.status}.`);
|
|
261
268
|
}
|
|
269
|
+
writeAuthProgress(input, "openai-codex login complete; reading local Codex token...");
|
|
262
270
|
const token = readCodexAccessToken(homeDir);
|
|
263
271
|
if (!token) {
|
|
264
272
|
throw new Error("Codex login completed but no token was found in ~/.codex/auth.json. Re-run `codex login` and try again.");
|
|
@@ -272,6 +280,7 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
272
280
|
message: "starting claude setup-token for runtime auth",
|
|
273
281
|
meta: { agentName: input.agentName },
|
|
274
282
|
});
|
|
283
|
+
writeAuthProgress(input, "starting anthropic setup-token flow...");
|
|
275
284
|
const result = spawnSync("claude", ["setup-token"], { stdio: "inherit" });
|
|
276
285
|
if (result.error) {
|
|
277
286
|
throw new Error(`Failed to run 'claude setup-token': ${result.error.message}`);
|
|
@@ -287,6 +296,7 @@ async function collectRuntimeAuthCredentials(input, deps) {
|
|
|
287
296
|
/* v8 ignore start -- token exchange: requires live Anthropic OAuth endpoint @preserve */
|
|
288
297
|
try {
|
|
289
298
|
const { refreshAnthropicToken } = await Promise.resolve().then(() => __importStar(require("../providers/anthropic-token")));
|
|
299
|
+
writeAuthProgress(input, "exchanging anthropic setup token...");
|
|
290
300
|
const tokenState = await refreshAnthropicToken(setupToken);
|
|
291
301
|
if (tokenState) {
|
|
292
302
|
return {
|
|
@@ -329,6 +339,7 @@ async function resolveHatchCredentials(input) {
|
|
|
329
339
|
agentName: input.agentName,
|
|
330
340
|
provider: input.provider,
|
|
331
341
|
promptInput: input.promptInput,
|
|
342
|
+
onProgress: input.onProgress,
|
|
332
343
|
});
|
|
333
344
|
Object.assign(credentials, result.credentials);
|
|
334
345
|
/* v8 ignore next 3 -- branch: auth flow always fills all required fields in production @preserve */
|
|
@@ -357,12 +368,15 @@ async function runRuntimeAuthFlow(input, deps = {}) {
|
|
|
357
368
|
message: "starting runtime auth flow",
|
|
358
369
|
meta: { agentName: input.agentName, provider: input.provider },
|
|
359
370
|
});
|
|
371
|
+
writeAuthProgress(input, `checking ${input.agentName}'s vault access...`);
|
|
360
372
|
const vault = await (0, provider_credentials_1.refreshProviderCredentialPool)(input.agentName);
|
|
361
373
|
if (!vault.ok && vault.reason === "unavailable") {
|
|
362
374
|
throw new Error(`${vault.error}\n${(0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(input.agentName, `Then retry 'ouro auth --agent ${input.agentName} --provider ${input.provider}'.`)}`);
|
|
363
375
|
}
|
|
364
376
|
const credentials = await collectRuntimeAuthCredentials(input, deps);
|
|
377
|
+
writeAuthProgress(input, `${input.provider} credentials collected; storing in ${input.agentName}'s vault...`);
|
|
365
378
|
const { credentialPath } = await storeProviderCredentials(input.agentName, input.provider, credentials);
|
|
379
|
+
writeAuthProgress(input, `credentials stored at ${credentialPath}; local provider snapshot refreshed.`);
|
|
366
380
|
(0, runtime_1.emitNervesEvent)({
|
|
367
381
|
component: "daemon",
|
|
368
382
|
event: "daemon.auth_flow_end",
|
|
@@ -153,6 +153,25 @@ async function listCliAgents(deps) {
|
|
|
153
153
|
async function checkAlreadyRunningAgentProviders(deps) {
|
|
154
154
|
return checkAgentProviders(deps);
|
|
155
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
|
+
}
|
|
156
175
|
async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
157
176
|
const remainingDegraded = await checkAgentProviders(deps, repairedAgents);
|
|
158
177
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -168,14 +187,8 @@ async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
|
168
187
|
deps.writeStdout("provider checks recovered after repair");
|
|
169
188
|
return remainingDegraded;
|
|
170
189
|
}
|
|
171
|
-
deps
|
|
172
|
-
|
|
173
|
-
deps.writeStdout(` ${d.agent}: ${d.errorReason}`);
|
|
174
|
-
if (d.fixHint) {
|
|
175
|
-
deps.writeStdout(` fix: ${d.fixHint}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
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.");
|
|
179
192
|
return remainingDegraded;
|
|
180
193
|
}
|
|
181
194
|
async function checkProviderHealthBeforeChat(agentName, deps) {
|
|
@@ -582,6 +595,7 @@ async function resolveHatchInput(command, deps) {
|
|
|
582
595
|
credentials: command.credentials,
|
|
583
596
|
promptInput: prompt,
|
|
584
597
|
runAuthFlow: deps.runAuthFlow,
|
|
598
|
+
onProgress: deps.writeStdout,
|
|
585
599
|
});
|
|
586
600
|
return {
|
|
587
601
|
agentName,
|
|
@@ -825,7 +839,7 @@ async function executeVaultReplace(command, deps) {
|
|
|
825
839
|
const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
|
|
826
840
|
const email = command.email ?? defaultRepairVaultEmail(command.agent, config);
|
|
827
841
|
const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
|
|
828
|
-
const unlockSecret = (await promptSecret(`Choose Ouro vault unlock secret for ${email}: `)).trim();
|
|
842
|
+
const unlockSecret = (await promptSecret(`Choose new Ouro vault unlock secret for ${email}: `)).trim();
|
|
829
843
|
if (!unlockSecret) {
|
|
830
844
|
throw new Error("vault replace requires an unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
|
|
831
845
|
}
|
|
@@ -846,13 +860,8 @@ async function executeVaultReplace(command, deps) {
|
|
|
846
860
|
`vault replaced for ${command.agent}`,
|
|
847
861
|
`vault: ${email} at ${serverUrl}`,
|
|
848
862
|
`local unlock store: ${repair.store.kind}${repair.store.secure ? "" : " (explicit plaintext fallback)"}`,
|
|
849
|
-
"
|
|
850
|
-
|
|
851
|
-
"Re-auth/re-enter the credentials this agent should use:",
|
|
852
|
-
` ouro auth --agent ${command.agent} --provider <provider>`,
|
|
853
|
-
` ouro vault config set --agent ${command.agent} --key <field>`,
|
|
854
|
-
` ouro provider refresh --agent ${command.agent}`,
|
|
855
|
-
` ouro auth verify --agent ${command.agent}`,
|
|
863
|
+
"imported: none",
|
|
864
|
+
`next: ouro repair --agent ${command.agent}`,
|
|
856
865
|
"Keep the vault unlock secret saved outside Ouro. Another machine will need it once.",
|
|
857
866
|
].join("\n");
|
|
858
867
|
deps.writeStdout(message);
|
|
@@ -871,7 +880,7 @@ async function executeVaultRecover(command, deps) {
|
|
|
871
880
|
const configuredVault = (0, identity_1.resolveVaultConfig)(command.agent, config.vault);
|
|
872
881
|
const email = command.email ?? defaultRepairVaultEmail(command.agent, config);
|
|
873
882
|
const serverUrl = command.serverUrl ?? config.vault?.serverUrl ?? configuredVault.serverUrl;
|
|
874
|
-
const unlockSecret = (await promptSecret(`Choose Ouro vault unlock secret for ${email}: `)).trim();
|
|
883
|
+
const unlockSecret = (await promptSecret(`Choose new Ouro vault unlock secret for ${email}: `)).trim();
|
|
875
884
|
if (!unlockSecret) {
|
|
876
885
|
throw new Error("vault recover requires an unlock secret. Re-run in an interactive terminal and enter a human-chosen unlock secret.");
|
|
877
886
|
}
|
|
@@ -1406,6 +1415,7 @@ async function executeReadinessRepairAction(agent, action, deps) {
|
|
|
1406
1415
|
agentName: agent,
|
|
1407
1416
|
provider,
|
|
1408
1417
|
promptInput: deps.promptInput,
|
|
1418
|
+
onProgress: deps.writeStdout,
|
|
1409
1419
|
});
|
|
1410
1420
|
deps.writeStdout(result.message);
|
|
1411
1421
|
await executeProviderRefresh({ kind: "provider.refresh", agent }, deps);
|
|
@@ -1450,12 +1460,7 @@ function readinessReportsFromDegraded(degraded) {
|
|
|
1450
1460
|
return degraded.map((entry) => ({
|
|
1451
1461
|
agent: entry.agent,
|
|
1452
1462
|
ok: false,
|
|
1453
|
-
issues: [
|
|
1454
|
-
entry.issue ?? (0, readiness_repair_1.genericReadinessIssue)({
|
|
1455
|
-
summary: entry.errorReason,
|
|
1456
|
-
...(entry.fixHint ? { fix: entry.fixHint } : {}),
|
|
1457
|
-
}),
|
|
1458
|
-
],
|
|
1463
|
+
issues: [readinessIssueFromDegraded(entry)],
|
|
1459
1464
|
}));
|
|
1460
1465
|
}
|
|
1461
1466
|
async function runReadinessRepairForDegraded(degraded, deps) {
|
|
@@ -2234,30 +2239,25 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2234
2239
|
progress.startPhase("provider checks");
|
|
2235
2240
|
const preflightProviderDegraded = await checkAgentProviders(deps);
|
|
2236
2241
|
providerChecksAlreadyRun = true;
|
|
2237
|
-
progress.completePhase("provider checks", preflightProviderDegraded.length
|
|
2242
|
+
progress.completePhase("provider checks", providerRepairCountSummary(preflightProviderDegraded.length));
|
|
2238
2243
|
if (preflightProviderDegraded.length > 0) {
|
|
2239
2244
|
progress.end();
|
|
2240
2245
|
if (command.noRepair) {
|
|
2241
|
-
deps
|
|
2242
|
-
|
|
2243
|
-
deps.writeStdout(` ${d.agent}: ${d.errorReason}`);
|
|
2244
|
-
if (d.fixHint) {
|
|
2245
|
-
deps.writeStdout(` fix: ${d.fixHint}`);
|
|
2246
|
-
}
|
|
2247
|
-
}
|
|
2248
|
-
const message = "daemon not started because provider checks are degraded; run `ouro repair` after applying the fixes.";
|
|
2246
|
+
writeProviderRepairSummary(deps, "Provider checks need repair:", preflightProviderDegraded);
|
|
2247
|
+
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2249
2248
|
deps.writeStdout(message);
|
|
2250
2249
|
return message;
|
|
2251
2250
|
}
|
|
2252
2251
|
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
2253
2252
|
if (!repairResult.repairsAttempted) {
|
|
2254
|
-
|
|
2253
|
+
writeProviderRepairSummary(deps, "Provider checks still need repair:", preflightProviderDegraded);
|
|
2254
|
+
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2255
2255
|
deps.writeStdout(message);
|
|
2256
2256
|
return message;
|
|
2257
2257
|
}
|
|
2258
2258
|
const remainingDegraded = await reportPostRepairProviderHealth(deps, preflightProviderDegraded.map((entry) => entry.agent));
|
|
2259
2259
|
if (remainingDegraded.length > 0) {
|
|
2260
|
-
const message = "daemon not started
|
|
2260
|
+
const message = "daemon not started: provider checks still need repair.";
|
|
2261
2261
|
deps.writeStdout(message);
|
|
2262
2262
|
return message;
|
|
2263
2263
|
}
|
|
@@ -2275,7 +2275,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2275
2275
|
progress.startPhase("provider checks");
|
|
2276
2276
|
const providerDegraded = await checkAlreadyRunningAgentProviders(deps);
|
|
2277
2277
|
daemonResult.stability = mergeStartupStability(daemonResult.stability, providerDegraded);
|
|
2278
|
-
progress.completePhase("provider checks", providerDegraded.length
|
|
2278
|
+
progress.completePhase("provider checks", providerRepairCountSummary(providerDegraded.length));
|
|
2279
2279
|
}
|
|
2280
2280
|
progress.end();
|
|
2281
2281
|
deps.writeStdout(daemonResult.message);
|
|
@@ -2283,13 +2283,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2283
2283
|
if (daemonResult.stability?.degraded && daemonResult.stability.degraded.length > 0) {
|
|
2284
2284
|
if (command.noRepair) {
|
|
2285
2285
|
// --no-repair: write degraded summary and skip interactive repair
|
|
2286
|
-
deps
|
|
2287
|
-
for (const d of daemonResult.stability.degraded) {
|
|
2288
|
-
deps.writeStdout(` ${d.agent}: ${d.errorReason}`);
|
|
2289
|
-
if (d.fixHint) {
|
|
2290
|
-
deps.writeStdout(` fix: ${d.fixHint}`);
|
|
2291
|
-
}
|
|
2292
|
-
}
|
|
2286
|
+
writeProviderRepairSummary(deps, "Provider checks need repair:", daemonResult.stability.degraded);
|
|
2293
2287
|
(0, runtime_1.emitNervesEvent)({
|
|
2294
2288
|
level: "warn",
|
|
2295
2289
|
component: "daemon",
|
|
@@ -2335,7 +2329,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2335
2329
|
const provider = providerOverride ?? config.humanFacing.provider;
|
|
2336
2330
|
/* v8 ignore next -- tests always inject runAuthFlow; default is for production @preserve */
|
|
2337
2331
|
const authRunner = deps.runAuthFlow ?? (await Promise.resolve().then(() => __importStar(require("../auth/auth-flow")))).runRuntimeAuthFlow;
|
|
2338
|
-
await authRunner({ agentName: agent, provider, promptInput: deps.promptInput });
|
|
2332
|
+
await authRunner({ agentName: agent, provider, promptInput: deps.promptInput, onProgress: deps.writeStdout });
|
|
2339
2333
|
},
|
|
2340
2334
|
runVaultUnlock: async (agent) => {
|
|
2341
2335
|
await executeVaultUnlock({ kind: "vault.unlock", agent }, deps);
|
|
@@ -2971,6 +2965,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2971
2965
|
agentName: command.agent,
|
|
2972
2966
|
provider,
|
|
2973
2967
|
promptInput: deps.promptInput,
|
|
2968
|
+
onProgress: deps.writeStdout,
|
|
2974
2969
|
});
|
|
2975
2970
|
// Behavior: ouro auth stores credentials only — does NOT switch provider.
|
|
2976
2971
|
// Use `ouro auth switch` to change the active provider.
|
|
@@ -2978,6 +2973,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2978
2973
|
// Verify the credentials actually work by pinging the provider
|
|
2979
2974
|
/* v8 ignore start -- integration: real API ping after auth @preserve */
|
|
2980
2975
|
try {
|
|
2976
|
+
deps.writeStdout(`verifying ${provider} credentials...`);
|
|
2981
2977
|
const credential = await readProviderCredentialRecord(command.agent, provider, deps);
|
|
2982
2978
|
const status = credential.ok
|
|
2983
2979
|
? await verifyProviderCredentials(provider, {
|
|
@@ -6,6 +6,7 @@ exports.providerLiveCheckFailedIssue = providerLiveCheckFailedIssue;
|
|
|
6
6
|
exports.genericReadinessIssue = genericReadinessIssue;
|
|
7
7
|
exports.isKnownReadinessIssue = isKnownReadinessIssue;
|
|
8
8
|
exports.renderReadinessIssue = renderReadinessIssue;
|
|
9
|
+
exports.renderReadinessIssueNextSteps = renderReadinessIssueNextSteps;
|
|
9
10
|
exports.runGuidedReadinessRepair = runGuidedReadinessRepair;
|
|
10
11
|
const runtime_1 = require("../../nerves/runtime");
|
|
11
12
|
function vaultLockedIssue(agentName) {
|
|
@@ -13,24 +14,24 @@ function vaultLockedIssue(agentName) {
|
|
|
13
14
|
kind: "vault-locked",
|
|
14
15
|
severity: "blocked",
|
|
15
16
|
actor: "human-required",
|
|
16
|
-
summary: `${agentName}
|
|
17
|
-
detail: "
|
|
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.",
|
|
18
19
|
actions: [
|
|
19
20
|
{
|
|
20
21
|
kind: "vault-unlock",
|
|
21
|
-
label: "
|
|
22
|
+
label: "Unlock with saved secret",
|
|
22
23
|
command: `ouro vault unlock --agent ${agentName}`,
|
|
23
24
|
actor: "human-required",
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
27
|
kind: "vault-replace",
|
|
27
|
-
label: "
|
|
28
|
+
label: "Create empty replacement vault",
|
|
28
29
|
command: `ouro vault replace --agent ${agentName}`,
|
|
29
30
|
actor: "human-required",
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
33
|
kind: "vault-recover",
|
|
33
|
-
label: "
|
|
34
|
+
label: "Recover from JSON export",
|
|
34
35
|
command: `ouro vault recover --agent ${agentName} --from <json>`,
|
|
35
36
|
actor: "human-required",
|
|
36
37
|
executable: false,
|
|
@@ -43,19 +44,19 @@ function providerCredentialMissingIssue(input) {
|
|
|
43
44
|
kind: "provider-credentials-missing",
|
|
44
45
|
severity: "blocked",
|
|
45
46
|
actor: "human-required",
|
|
46
|
-
summary: `${input.agentName}
|
|
47
|
-
detail: `
|
|
47
|
+
summary: `${input.agentName}: missing ${input.provider} credentials (${input.lane}, ${input.model})`,
|
|
48
|
+
detail: `source: ${input.credentialPath}`,
|
|
48
49
|
actions: [
|
|
49
50
|
{
|
|
50
51
|
kind: "provider-auth",
|
|
51
|
-
label: `Authenticate ${input.provider}
|
|
52
|
+
label: `Authenticate ${input.provider}`,
|
|
52
53
|
command: `ouro auth --agent ${input.agentName} --provider ${input.provider}`,
|
|
53
54
|
actor: "human-required",
|
|
54
55
|
provider: input.provider,
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
kind: "provider-use",
|
|
58
|
-
label: "Choose
|
|
59
|
+
label: "Choose another provider/model",
|
|
59
60
|
command: `ouro use --agent ${input.agentName} --lane ${input.lane} --provider <provider> --model <model>`,
|
|
60
61
|
actor: "human-choice",
|
|
61
62
|
executable: false,
|
|
@@ -69,7 +70,7 @@ function providerLiveCheckFailedIssue(input) {
|
|
|
69
70
|
kind: "provider-live-check-failed",
|
|
70
71
|
severity: "blocked",
|
|
71
72
|
actor: "human-choice",
|
|
72
|
-
summary: `${input.agentName}
|
|
73
|
+
summary: `${input.agentName}: ${input.lane} provider ${input.provider} / ${input.model} failed live check`,
|
|
73
74
|
detail: input.message,
|
|
74
75
|
actions: [
|
|
75
76
|
{
|
|
@@ -118,11 +119,21 @@ function renderReadinessIssue(issue) {
|
|
|
118
119
|
}
|
|
119
120
|
issue.actions.forEach((action, index) => {
|
|
120
121
|
lines.push(`${index + 1}. ${action.label}`);
|
|
121
|
-
lines.push(`
|
|
122
|
+
lines.push(` ${action.command}`);
|
|
122
123
|
});
|
|
123
124
|
lines.push(`${issue.actions.length + 1}. Skip for now`);
|
|
124
125
|
return lines.join("\n");
|
|
125
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
|
+
}
|
|
126
137
|
function selectedActionFor(answer, issue) {
|
|
127
138
|
const selected = Number.parseInt(answer.trim(), 10);
|
|
128
139
|
if (!Number.isFinite(selected))
|
|
@@ -160,11 +171,11 @@ async function runGuidedReadinessRepair(reports, deps) {
|
|
|
160
171
|
const answer = await deps.promptInput(`Choose [1-${issue.actions.length + 1}]: `);
|
|
161
172
|
const action = selectedActionFor(answer, issue);
|
|
162
173
|
if (action === "skip") {
|
|
163
|
-
deps.writeStdout(`
|
|
174
|
+
deps.writeStdout(`skipped ${report.agent} for now.`);
|
|
164
175
|
continue;
|
|
165
176
|
}
|
|
166
177
|
if (!action) {
|
|
167
|
-
deps.writeStdout(`invalid
|
|
178
|
+
deps.writeStdout(`invalid choice for ${report.agent}; no repair attempted.`);
|
|
168
179
|
continue;
|
|
169
180
|
}
|
|
170
181
|
if (!isExecutableAction(action)) {
|
|
@@ -178,7 +189,7 @@ async function runGuidedReadinessRepair(reports, deps) {
|
|
|
178
189
|
try {
|
|
179
190
|
await deps.runRepairAction(report.agent, action, issue);
|
|
180
191
|
repairsAttempted = true;
|
|
181
|
-
deps.writeStdout(`repair
|
|
192
|
+
deps.writeStdout(`repair step finished for ${report.agent}.`);
|
|
182
193
|
}
|
|
183
194
|
catch (error) {
|
|
184
195
|
const message = error instanceof Error ? error.message : String(error);
|