@ouro.bot/cli 0.1.0-alpha.407 → 0.1.0-alpha.409
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 +20 -0
- package/dist/heart/auth/auth-flow.js +4 -1
- package/dist/heart/daemon/agent-config-check.js +8 -0
- package/dist/heart/daemon/cli-exec.js +12 -8
- package/dist/heart/daemon/daemon-runtime-sync.js +2 -2
- package/dist/heart/daemon/interactive-repair.js +88 -21
- package/dist/heart/daemon/readiness-repair.js +36 -3
- package/dist/repertoire/credential-access.js +7 -3
- package/dist/repertoire/vault-unlock.js +18 -0
- package/package.json +2 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
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.409",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro up` interactive repair now presents each agent's next step as a compact panel with `needs`, `run`, and `note` lines, followed by a short human prompt like `Unlock it now?` or `Open the auth flow now?` instead of embedding commands and warnings into one long question.",
|
|
8
|
+
"Declined repair output now collapses into short `next` / `or` follow-up commands, so vault unlock, replace, recover, and provider-auth paths stay visible without reprinting a wall of explanatory prose.",
|
|
9
|
+
"Guided readiness repair and no-repair summaries now use blank-line grouping plus calmer `Provider checks need attention` and `Still needs attention` headings, and stale-daemon restart output now splits its repair handoff onto a second line instead of bolting it onto one overlong sentence.",
|
|
10
|
+
"Added regression coverage for the new interactive repair copy, grouped repair queue, readiness summary spacing, no-repair output, and the revised stale-daemon restart message.",
|
|
11
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the repair UX polish release."
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.1.0-alpha.408",
|
|
16
|
+
"changes": [
|
|
17
|
+
"Existing agents without a `vault` block in `agent.json` now fail fast with explicit `ouro vault create --agent <agent>` guidance instead of silently deriving a stable vault account and misreporting missing provider credentials.",
|
|
18
|
+
"`ouro auth`, `ouro up`, and `ouro repair` now treat a missing agent vault locator as a first-class readiness state with create/recover choices, then continue through the normal provider-auth repair path after the vault exists.",
|
|
19
|
+
"Runtime credential access now requires an explicit agent vault locator before opening Bitwarden or Vaultwarden, which keeps provider, runtime, travel, and tool credential flows truthful for pre-vault agent migrations.",
|
|
20
|
+
"Added regression coverage for missing-vault-locator auth, provider readiness, guided repair, and the real Bitwarden-backed auth path, plus the default local `spawnSync` fallback used by Linux secure-store probing.",
|
|
21
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the pre-vault agent locator repair release."
|
|
22
|
+
]
|
|
23
|
+
},
|
|
4
24
|
{
|
|
5
25
|
"version": "0.1.0-alpha.407",
|
|
6
26
|
"changes": [
|
|
@@ -389,7 +389,10 @@ async function runRuntimeAuthFlow(input, deps = {}) {
|
|
|
389
389
|
writeAuthProgress(input, `checking ${input.agentName}'s vault access...`);
|
|
390
390
|
const vault = await (0, provider_credentials_1.refreshProviderCredentialPool)(input.agentName);
|
|
391
391
|
if (!vault.ok && vault.reason === "unavailable") {
|
|
392
|
-
|
|
392
|
+
const fix = (0, vault_unlock_1.isCredentialVaultNotConfiguredError)(vault.error)
|
|
393
|
+
? (0, vault_unlock_1.vaultCreateRecoverFix)(input.agentName, `Then retry 'ouro auth --agent ${input.agentName} --provider ${input.provider}'.`)
|
|
394
|
+
: (0, vault_unlock_1.vaultUnlockReplaceRecoverFix)(input.agentName, `Then retry 'ouro auth --agent ${input.agentName} --provider ${input.provider}'.`);
|
|
395
|
+
throw new Error(`${vault.error}\n${fix}`);
|
|
393
396
|
}
|
|
394
397
|
const credentials = await collectRuntimeAuthCredentials(input, deps);
|
|
395
398
|
let credentialPath;
|
|
@@ -252,6 +252,14 @@ function invalidPoolResult(agentName, lane, provider, model, pool) {
|
|
|
252
252
|
issue: (0, readiness_repair_1.vaultLockedIssue)(agentName),
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
|
+
if (pool.reason === "unavailable" && (0, vault_unlock_1.isCredentialVaultNotConfiguredError)(pool.error)) {
|
|
256
|
+
return {
|
|
257
|
+
ok: false,
|
|
258
|
+
error: `${lane} provider ${provider} model ${model} cannot read provider credentials because ${agentName}'s credential vault is not configured in agent.json.`,
|
|
259
|
+
fix: (0, vault_unlock_1.vaultCreateRecoverFix)(agentName, `Then run 'ouro auth --agent ${agentName} --provider ${provider}' and rerun 'ouro up'.`),
|
|
260
|
+
issue: (0, readiness_repair_1.vaultUnconfiguredIssue)(agentName),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
255
263
|
if (pool.reason === "invalid") {
|
|
256
264
|
return {
|
|
257
265
|
ok: false,
|
|
@@ -166,7 +166,7 @@ function writeProviderRepairSummary(deps, title, degraded) {
|
|
|
166
166
|
function providerRepairCountSummary(count) {
|
|
167
167
|
if (count === 0)
|
|
168
168
|
return "ok";
|
|
169
|
-
return `${count} ${count === 1 ? "needs" : "need"}
|
|
169
|
+
return `${count} ${count === 1 ? "needs" : "need"} attention`;
|
|
170
170
|
}
|
|
171
171
|
async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
172
172
|
const remainingDegraded = await checkAgentProviders(deps, repairedAgents);
|
|
@@ -180,10 +180,10 @@ async function reportPostRepairProviderHealth(deps, repairedAgents) {
|
|
|
180
180
|
meta: { degradedCount: remainingDegraded.length, repairedAgents },
|
|
181
181
|
});
|
|
182
182
|
if (remainingDegraded.length === 0) {
|
|
183
|
-
deps.writeStdout("
|
|
183
|
+
deps.writeStdout("All set. Provider checks recovered after repair.");
|
|
184
184
|
return remainingDegraded;
|
|
185
185
|
}
|
|
186
|
-
writeProviderRepairSummary(deps, "Still
|
|
186
|
+
writeProviderRepairSummary(deps, "Still needs attention", remainingDegraded);
|
|
187
187
|
deps.writeStdout("Run `ouro up` again after these are fixed.");
|
|
188
188
|
return remainingDegraded;
|
|
189
189
|
}
|
|
@@ -1396,6 +1396,10 @@ async function readinessReportForAgent(agent, deps) {
|
|
|
1396
1396
|
}
|
|
1397
1397
|
}
|
|
1398
1398
|
async function executeReadinessRepairAction(agent, action, deps) {
|
|
1399
|
+
if (action.kind === "vault-create") {
|
|
1400
|
+
await executeVaultCreate({ kind: "vault.create", agent }, deps);
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1399
1403
|
if (action.kind === "vault-unlock") {
|
|
1400
1404
|
await executeVaultUnlock({ kind: "vault.unlock", agent }, deps);
|
|
1401
1405
|
return;
|
|
@@ -2291,26 +2295,26 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2291
2295
|
if (preflightProviderDegraded.length > 0) {
|
|
2292
2296
|
progress.end();
|
|
2293
2297
|
if (command.noRepair) {
|
|
2294
|
-
writeProviderRepairSummary(deps, "Provider checks need
|
|
2298
|
+
writeProviderRepairSummary(deps, "Provider checks need attention", preflightProviderDegraded);
|
|
2295
2299
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2296
2300
|
deps.writeStdout(message);
|
|
2297
2301
|
return message;
|
|
2298
2302
|
}
|
|
2299
2303
|
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
2300
2304
|
if (!repairResult.repairsAttempted) {
|
|
2301
|
-
writeProviderRepairSummary(deps, "Provider checks still need
|
|
2305
|
+
writeProviderRepairSummary(deps, "Provider checks still need attention", repairResult.remainingDegraded);
|
|
2302
2306
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2303
2307
|
deps.writeStdout(message);
|
|
2304
2308
|
return message;
|
|
2305
2309
|
}
|
|
2306
2310
|
const remainingDegraded = repairResult.remainingDegraded;
|
|
2307
2311
|
if (remainingDegraded.length > 0) {
|
|
2308
|
-
writeProviderRepairSummary(deps, "Still
|
|
2312
|
+
writeProviderRepairSummary(deps, "Still needs attention", remainingDegraded);
|
|
2309
2313
|
const message = "daemon not started: provider checks still need repair.";
|
|
2310
2314
|
deps.writeStdout(message);
|
|
2311
2315
|
return message;
|
|
2312
2316
|
}
|
|
2313
|
-
deps.writeStdout("
|
|
2317
|
+
deps.writeStdout("All set. Provider checks recovered after repair.");
|
|
2314
2318
|
}
|
|
2315
2319
|
}
|
|
2316
2320
|
progress.startPhase("starting daemon");
|
|
@@ -2333,7 +2337,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2333
2337
|
if (daemonResult.stability?.degraded && daemonResult.stability.degraded.length > 0) {
|
|
2334
2338
|
if (command.noRepair) {
|
|
2335
2339
|
// --no-repair: write degraded summary and skip interactive repair
|
|
2336
|
-
writeProviderRepairSummary(deps, "Provider checks need
|
|
2340
|
+
writeProviderRepairSummary(deps, "Provider checks need attention", daemonResult.stability.degraded);
|
|
2337
2341
|
(0, runtime_1.emitNervesEvent)({
|
|
2338
2342
|
level: "warn",
|
|
2339
2343
|
component: "daemon",
|
|
@@ -134,11 +134,11 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
134
134
|
const pid = started.pid ?? "unknown";
|
|
135
135
|
const verified = await verifyDaemonStarted(deps);
|
|
136
136
|
/* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
|
|
137
|
-
const suffix = verified ? "" : "
|
|
137
|
+
const suffix = verified ? "" : "\ndaemon did not answer yet, so Ouro is checking repair paths next.";
|
|
138
138
|
result = {
|
|
139
139
|
alreadyRunning: false,
|
|
140
140
|
message: includesVersionDrift
|
|
141
|
-
? `restarted stale daemon
|
|
141
|
+
? `restarted stale daemon ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
|
|
142
142
|
: `restarted drifted daemon (${driftSummary}) (pid ${pid})${suffix}`,
|
|
143
143
|
verifyStartupStatus: verified,
|
|
144
144
|
startedPid: started.pid ?? null,
|
|
@@ -64,11 +64,83 @@ function vaultUnlockCommandFor(degraded) {
|
|
|
64
64
|
function isAffirmativeAnswer(answer) {
|
|
65
65
|
return /^(y|yes)$/i.test(answer.trim());
|
|
66
66
|
}
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
function uniqueCommands(commands) {
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
const unique = [];
|
|
70
|
+
commands.forEach((command) => {
|
|
71
|
+
if (!command)
|
|
72
|
+
return;
|
|
73
|
+
if (seen.has(command))
|
|
74
|
+
return;
|
|
75
|
+
seen.add(command);
|
|
76
|
+
unique.push(command);
|
|
77
|
+
});
|
|
78
|
+
return unique;
|
|
79
|
+
}
|
|
80
|
+
function fallbackCommandsFor(degraded, primaryCommand) {
|
|
81
|
+
const issueCommands = degraded.issue?.actions.map((action) => action.command) ?? [];
|
|
82
|
+
return uniqueCommands([
|
|
83
|
+
primaryCommand,
|
|
84
|
+
...issueCommands,
|
|
85
|
+
extractRepairCommand(degraded.fixHint, "ouro vault replace"),
|
|
86
|
+
extractRepairCommand(degraded.fixHint, "ouro vault recover"),
|
|
87
|
+
extractRepairCommand(degraded.fixHint, "ouro use"),
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
function renderRepairChoices(prefix, commands) {
|
|
91
|
+
return commands.map((command, index) => ` ${index === 0 ? prefix : "or"}: ${command}`);
|
|
92
|
+
}
|
|
93
|
+
function renderRepairQueueSummaryLines(degraded) {
|
|
94
|
+
const repairable = degraded
|
|
95
|
+
.map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
|
|
96
|
+
.filter((item) => item.action !== undefined);
|
|
97
|
+
if (repairable.length < 2)
|
|
98
|
+
return [];
|
|
99
|
+
const lines = [
|
|
100
|
+
"Repair queue",
|
|
101
|
+
`${repairable.length} agents need attention before startup can finish.`,
|
|
102
|
+
"",
|
|
103
|
+
];
|
|
104
|
+
repairable.forEach(({ entry, action }, index) => {
|
|
105
|
+
lines.push(`${entry.agent} - ${action.label}`);
|
|
106
|
+
lines.push(` ${action.command}`);
|
|
107
|
+
if (index < repairable.length - 1)
|
|
108
|
+
lines.push("");
|
|
109
|
+
});
|
|
110
|
+
return lines;
|
|
111
|
+
}
|
|
112
|
+
function renderActionPromptLines(agent, action) {
|
|
113
|
+
const lines = [
|
|
114
|
+
`${agent}`,
|
|
115
|
+
` needs: ${action.label}`,
|
|
116
|
+
` run: ${action.command}`,
|
|
117
|
+
];
|
|
118
|
+
if (action.kind === "vault-unlock") {
|
|
119
|
+
lines.push(" note: use the saved vault unlock secret");
|
|
71
120
|
}
|
|
121
|
+
return lines;
|
|
122
|
+
}
|
|
123
|
+
function renderDeferredRepair(agent, commands) {
|
|
124
|
+
return [
|
|
125
|
+
`Leaving ${agent} for later.`,
|
|
126
|
+
...renderRepairChoices("next", commands),
|
|
127
|
+
].join("\n");
|
|
128
|
+
}
|
|
129
|
+
function renderManualRepairHint(agent, fixHint) {
|
|
130
|
+
return [
|
|
131
|
+
`${agent}`,
|
|
132
|
+
" needs manual attention",
|
|
133
|
+
` next: ${fixHint}`,
|
|
134
|
+
].join("\n");
|
|
135
|
+
}
|
|
136
|
+
function renderUnknownRepair(agent, errorReason) {
|
|
137
|
+
return [
|
|
138
|
+
`${agent}`,
|
|
139
|
+
` ${errorReason}`,
|
|
140
|
+
].join("\n");
|
|
141
|
+
}
|
|
142
|
+
function writeDeclinedRepair(degraded, command, deps) {
|
|
143
|
+
deps.writeStdout(renderDeferredRepair(degraded.agent, fallbackCommandsFor(degraded, command)));
|
|
72
144
|
}
|
|
73
145
|
function runnableRepairActionFor(degraded) {
|
|
74
146
|
const typedAction = degraded.issue?.actions
|
|
@@ -106,16 +178,9 @@ function typedActionToRunnable(degraded, action) {
|
|
|
106
178
|
return undefined;
|
|
107
179
|
}
|
|
108
180
|
function writeRepairQueueSummary(degraded, deps) {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
.
|
|
112
|
-
if (repairable.length < 2)
|
|
113
|
-
return;
|
|
114
|
-
const lines = [
|
|
115
|
-
"repair queue:",
|
|
116
|
-
...repairable.map(({ entry, action }) => ` - ${entry.agent}: ${action.label}: \`${action.command}\``),
|
|
117
|
-
];
|
|
118
|
-
deps.writeStdout(lines.join("\n"));
|
|
181
|
+
const lines = renderRepairQueueSummaryLines(degraded);
|
|
182
|
+
if (lines.length > 0)
|
|
183
|
+
deps.writeStdout(lines.join("\n"));
|
|
119
184
|
}
|
|
120
185
|
async function runInteractiveRepair(degraded, deps) {
|
|
121
186
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -133,11 +198,12 @@ async function runInteractiveRepair(degraded, deps) {
|
|
|
133
198
|
for (const entry of degraded) {
|
|
134
199
|
const action = runnableRepairActionFor(entry);
|
|
135
200
|
if (action?.kind === "vault-unlock") {
|
|
136
|
-
|
|
201
|
+
deps.writeStdout(renderActionPromptLines(entry.agent, action).join("\n"));
|
|
202
|
+
const answer = await deps.promptInput("Unlock it now? [y/N] ");
|
|
137
203
|
if (isAffirmativeAnswer(answer)) {
|
|
138
204
|
try {
|
|
139
205
|
if (!deps.runVaultUnlock) {
|
|
140
|
-
deps.writeStdout(
|
|
206
|
+
deps.writeStdout(renderManualRepairHint(entry.agent, entry.fixHint));
|
|
141
207
|
}
|
|
142
208
|
else {
|
|
143
209
|
await deps.runVaultUnlock(entry.agent);
|
|
@@ -146,7 +212,7 @@ async function runInteractiveRepair(degraded, deps) {
|
|
|
146
212
|
}
|
|
147
213
|
catch (error) {
|
|
148
214
|
const msg = error instanceof Error ? error.message : String(error);
|
|
149
|
-
deps.writeStdout(`
|
|
215
|
+
deps.writeStdout(`Vault unlock did not finish for ${entry.agent}.\n ${msg}`);
|
|
150
216
|
repairsAttempted = true;
|
|
151
217
|
(0, runtime_1.emitNervesEvent)({
|
|
152
218
|
level: "error",
|
|
@@ -162,7 +228,8 @@ async function runInteractiveRepair(degraded, deps) {
|
|
|
162
228
|
}
|
|
163
229
|
}
|
|
164
230
|
else if (action?.kind === "provider-auth") {
|
|
165
|
-
|
|
231
|
+
deps.writeStdout(renderActionPromptLines(entry.agent, action).join("\n"));
|
|
232
|
+
const answer = await deps.promptInput("Open the auth flow now? [y/N] ");
|
|
166
233
|
if (isAffirmativeAnswer(answer)) {
|
|
167
234
|
try {
|
|
168
235
|
if (action.provider) {
|
|
@@ -175,7 +242,7 @@ async function runInteractiveRepair(degraded, deps) {
|
|
|
175
242
|
}
|
|
176
243
|
catch (error) {
|
|
177
244
|
const msg = error instanceof Error ? error.message : String(error);
|
|
178
|
-
deps.writeStdout(`
|
|
245
|
+
deps.writeStdout(`Auth did not finish for ${entry.agent}.\n ${msg}`);
|
|
179
246
|
repairsAttempted = true;
|
|
180
247
|
(0, runtime_1.emitNervesEvent)({
|
|
181
248
|
level: "error",
|
|
@@ -191,11 +258,11 @@ async function runInteractiveRepair(degraded, deps) {
|
|
|
191
258
|
}
|
|
192
259
|
}
|
|
193
260
|
else if (isConfigError(entry)) {
|
|
194
|
-
deps.writeStdout(
|
|
261
|
+
deps.writeStdout(renderManualRepairHint(entry.agent, entry.fixHint));
|
|
195
262
|
}
|
|
196
263
|
else {
|
|
197
264
|
// Unknown error with no actionable fix hint
|
|
198
|
-
deps.writeStdout(
|
|
265
|
+
deps.writeStdout(renderUnknownRepair(entry.agent, entry.errorReason));
|
|
199
266
|
}
|
|
200
267
|
}
|
|
201
268
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.vaultLockedIssue = vaultLockedIssue;
|
|
4
|
+
exports.vaultUnconfiguredIssue = vaultUnconfiguredIssue;
|
|
4
5
|
exports.providerCredentialMissingIssue = providerCredentialMissingIssue;
|
|
5
6
|
exports.providerLiveCheckFailedIssue = providerLiveCheckFailedIssue;
|
|
6
7
|
exports.genericReadinessIssue = genericReadinessIssue;
|
|
@@ -39,6 +40,30 @@ function vaultLockedIssue(agentName) {
|
|
|
39
40
|
],
|
|
40
41
|
};
|
|
41
42
|
}
|
|
43
|
+
function vaultUnconfiguredIssue(agentName) {
|
|
44
|
+
return {
|
|
45
|
+
kind: "vault-unconfigured",
|
|
46
|
+
severity: "blocked",
|
|
47
|
+
actor: "human-required",
|
|
48
|
+
summary: `${agentName}: vault not configured`,
|
|
49
|
+
detail: "This bundle does not have a vault locator in agent.json yet. Create the agent vault before authenticating providers.",
|
|
50
|
+
actions: [
|
|
51
|
+
{
|
|
52
|
+
kind: "vault-create",
|
|
53
|
+
label: "Create this agent's vault",
|
|
54
|
+
command: `ouro vault create --agent ${agentName}`,
|
|
55
|
+
actor: "human-required",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
kind: "vault-recover",
|
|
59
|
+
label: "Recover from JSON export",
|
|
60
|
+
command: `ouro vault recover --agent ${agentName} --from <json>`,
|
|
61
|
+
actor: "human-required",
|
|
62
|
+
executable: false,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
42
67
|
function providerCredentialMissingIssue(input) {
|
|
43
68
|
return {
|
|
44
69
|
kind: "provider-credentials-missing",
|
|
@@ -117,20 +142,28 @@ function renderReadinessIssue(issue) {
|
|
|
117
142
|
if (issue.detail) {
|
|
118
143
|
lines.push(` ${issue.detail}`);
|
|
119
144
|
}
|
|
145
|
+
if (issue.actions.length > 0) {
|
|
146
|
+
lines.push("");
|
|
147
|
+
}
|
|
120
148
|
issue.actions.forEach((action, index) => {
|
|
149
|
+
if (index > 0)
|
|
150
|
+
lines.push("");
|
|
121
151
|
lines.push(`${index + 1}. ${action.label}`);
|
|
122
152
|
lines.push(` ${action.command}`);
|
|
123
153
|
});
|
|
154
|
+
if (issue.actions.length > 0) {
|
|
155
|
+
lines.push("");
|
|
156
|
+
}
|
|
124
157
|
lines.push(`${issue.actions.length + 1}. Skip for now`);
|
|
125
158
|
return lines.join("\n");
|
|
126
159
|
}
|
|
127
160
|
function renderReadinessIssueNextSteps(issue) {
|
|
128
|
-
const lines = [
|
|
161
|
+
const lines = [issue.summary];
|
|
129
162
|
if (issue.detail && issue.kind !== "vault-locked") {
|
|
130
|
-
lines.push(`
|
|
163
|
+
lines.push(` ${issue.detail}`);
|
|
131
164
|
}
|
|
132
165
|
issue.actions.forEach((action, index) => {
|
|
133
|
-
lines.push(`
|
|
166
|
+
lines.push(` ${index === 0 ? "next" : "or"}: ${action.command}`);
|
|
134
167
|
});
|
|
135
168
|
return lines;
|
|
136
169
|
}
|
|
@@ -58,10 +58,10 @@ function loadVaultSectionForAgent(agentName) {
|
|
|
58
58
|
const configPath = path.join(identity.getAgentRoot(agentName), "agent.json");
|
|
59
59
|
try {
|
|
60
60
|
const parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
61
|
-
return parsed.vault;
|
|
61
|
+
return { configPath, vault: parsed.vault };
|
|
62
62
|
}
|
|
63
63
|
catch {
|
|
64
|
-
return
|
|
64
|
+
return { configPath };
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
function bitwardenAppDataDir(agentName, vaultConfig) {
|
|
@@ -77,7 +77,11 @@ function getCredentialStore(agentNameInput) {
|
|
|
77
77
|
if (agentName === "SerpentGuide") {
|
|
78
78
|
throw new Error("SerpentGuide does not have a persistent credential vault; hatch bootstrap uses provider credentials in memory only.");
|
|
79
79
|
}
|
|
80
|
-
const
|
|
80
|
+
const { configPath, vault } = loadVaultSectionForAgent(agentName);
|
|
81
|
+
if (!vault || typeof vault.email !== "string" || vault.email.trim().length === 0) {
|
|
82
|
+
throw new Error((0, vault_unlock_1.credentialVaultNotConfiguredError)(agentName, configPath));
|
|
83
|
+
}
|
|
84
|
+
const vaultConfig = identity.resolveVaultConfig(agentName, vault);
|
|
81
85
|
const cacheKey = `${agentName}:${vaultConfig.serverUrl}:${vaultConfig.email}`;
|
|
82
86
|
const cached = stores.get(cacheKey);
|
|
83
87
|
if (cached)
|
|
@@ -34,6 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.vaultUnlockReplaceRecoverFix = vaultUnlockReplaceRecoverFix;
|
|
37
|
+
exports.credentialVaultNotConfiguredError = credentialVaultNotConfiguredError;
|
|
38
|
+
exports.isCredentialVaultNotConfiguredError = isCredentialVaultNotConfiguredError;
|
|
39
|
+
exports.vaultCreateRecoverFix = vaultCreateRecoverFix;
|
|
37
40
|
exports.resolveVaultUnlockStore = resolveVaultUnlockStore;
|
|
38
41
|
exports.readVaultUnlockSecret = readVaultUnlockSecret;
|
|
39
42
|
exports.storeVaultUnlockSecret = storeVaultUnlockSecret;
|
|
@@ -45,6 +48,7 @@ const os = __importStar(require("node:os"));
|
|
|
45
48
|
const path = __importStar(require("node:path"));
|
|
46
49
|
const runtime_1 = require("../nerves/runtime");
|
|
47
50
|
const VAULT_UNLOCK_SERVICE = "ouro.vault";
|
|
51
|
+
const CREDENTIAL_VAULT_NOT_CONFIGURED_PREFIX = "credential vault is not configured in ";
|
|
48
52
|
const PLAINTEXT_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock");
|
|
49
53
|
const WINDOWS_DPAPI_UNLOCK_DIR = path.join(".ouro-cli", "vault-unlock-dpapi");
|
|
50
54
|
const SUPPORTED_STORES = ["auto", "macos-keychain", "windows-dpapi", "linux-secret-service", "plaintext-file"];
|
|
@@ -104,6 +108,20 @@ function vaultUnlockReplaceRecoverFix(agentName, nextStep = "Then run 'ouro up'
|
|
|
104
108
|
nextStep,
|
|
105
109
|
].join(" ");
|
|
106
110
|
}
|
|
111
|
+
function credentialVaultNotConfiguredError(agentName, configPath) {
|
|
112
|
+
return (`${CREDENTIAL_VAULT_NOT_CONFIGURED_PREFIX}${configPath}. ` +
|
|
113
|
+
`Run 'ouro vault create --agent ${agentName}' to create this agent's vault before loading or storing credentials.`);
|
|
114
|
+
}
|
|
115
|
+
function isCredentialVaultNotConfiguredError(message) {
|
|
116
|
+
return message.includes(CREDENTIAL_VAULT_NOT_CONFIGURED_PREFIX);
|
|
117
|
+
}
|
|
118
|
+
function vaultCreateRecoverFix(agentName, nextStep = "Then run 'ouro up' again.") {
|
|
119
|
+
return [
|
|
120
|
+
`Run 'ouro vault create --agent ${agentName}' to create this agent's vault.`,
|
|
121
|
+
`If you still have a local JSON credential export from an earlier alpha, run 'ouro vault recover --agent ${agentName} --from <json>' instead.`,
|
|
122
|
+
nextStep,
|
|
123
|
+
].join(" ");
|
|
124
|
+
}
|
|
107
125
|
function lostUnlockSecretGuidance(config) {
|
|
108
126
|
if (!config.agentName) {
|
|
109
127
|
return "If nobody saved that unlock secret, run `ouro vault replace --agent <agent>` to create a new empty vault and re-enter credentials. If you do have a local JSON credential export, run `ouro vault recover --agent <agent> --from <json>` to import it.";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.409",
|
|
4
4
|
"main": "dist/heart/daemon/ouro-entry.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cli": "dist/heart/daemon/ouro-bot-entry.js",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"test:coverage": "node scripts/run-coverage-gate.cjs",
|
|
33
33
|
"build": "tsc && (cd packages/outlook-ui && npm install --ignore-scripts 2>/dev/null && npm run build && cp -r dist ../../dist/outlook-ui) || echo 'outlook-ui build skipped'",
|
|
34
34
|
"lint": "eslint src/",
|
|
35
|
+
"release:preflight": "node scripts/release-preflight.cjs",
|
|
35
36
|
"release:smoke": "node scripts/release-smoke.cjs",
|
|
36
37
|
"audit:nerves": "npm run build && node dist/nerves/coverage/cli-main.js"
|
|
37
38
|
},
|