@ouro.bot/cli 0.1.0-alpha.408 → 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
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
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
|
+
},
|
|
4
14
|
{
|
|
5
15
|
"version": "0.1.0-alpha.408",
|
|
6
16
|
"changes": [
|
|
@@ -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
|
}
|
|
@@ -2295,26 +2295,26 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2295
2295
|
if (preflightProviderDegraded.length > 0) {
|
|
2296
2296
|
progress.end();
|
|
2297
2297
|
if (command.noRepair) {
|
|
2298
|
-
writeProviderRepairSummary(deps, "Provider checks need
|
|
2298
|
+
writeProviderRepairSummary(deps, "Provider checks need attention", preflightProviderDegraded);
|
|
2299
2299
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2300
2300
|
deps.writeStdout(message);
|
|
2301
2301
|
return message;
|
|
2302
2302
|
}
|
|
2303
2303
|
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
2304
2304
|
if (!repairResult.repairsAttempted) {
|
|
2305
|
-
writeProviderRepairSummary(deps, "Provider checks still need
|
|
2305
|
+
writeProviderRepairSummary(deps, "Provider checks still need attention", repairResult.remainingDegraded);
|
|
2306
2306
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
2307
2307
|
deps.writeStdout(message);
|
|
2308
2308
|
return message;
|
|
2309
2309
|
}
|
|
2310
2310
|
const remainingDegraded = repairResult.remainingDegraded;
|
|
2311
2311
|
if (remainingDegraded.length > 0) {
|
|
2312
|
-
writeProviderRepairSummary(deps, "Still
|
|
2312
|
+
writeProviderRepairSummary(deps, "Still needs attention", remainingDegraded);
|
|
2313
2313
|
const message = "daemon not started: provider checks still need repair.";
|
|
2314
2314
|
deps.writeStdout(message);
|
|
2315
2315
|
return message;
|
|
2316
2316
|
}
|
|
2317
|
-
deps.writeStdout("
|
|
2317
|
+
deps.writeStdout("All set. Provider checks recovered after repair.");
|
|
2318
2318
|
}
|
|
2319
2319
|
}
|
|
2320
2320
|
progress.startPhase("starting daemon");
|
|
@@ -2337,7 +2337,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
2337
2337
|
if (daemonResult.stability?.degraded && daemonResult.stability.degraded.length > 0) {
|
|
2338
2338
|
if (command.noRepair) {
|
|
2339
2339
|
// --no-repair: write degraded summary and skip interactive repair
|
|
2340
|
-
writeProviderRepairSummary(deps, "Provider checks need
|
|
2340
|
+
writeProviderRepairSummary(deps, "Provider checks need attention", daemonResult.stability.degraded);
|
|
2341
2341
|
(0, runtime_1.emitNervesEvent)({
|
|
2342
2342
|
level: "warn",
|
|
2343
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)({
|
|
@@ -142,20 +142,28 @@ function renderReadinessIssue(issue) {
|
|
|
142
142
|
if (issue.detail) {
|
|
143
143
|
lines.push(` ${issue.detail}`);
|
|
144
144
|
}
|
|
145
|
+
if (issue.actions.length > 0) {
|
|
146
|
+
lines.push("");
|
|
147
|
+
}
|
|
145
148
|
issue.actions.forEach((action, index) => {
|
|
149
|
+
if (index > 0)
|
|
150
|
+
lines.push("");
|
|
146
151
|
lines.push(`${index + 1}. ${action.label}`);
|
|
147
152
|
lines.push(` ${action.command}`);
|
|
148
153
|
});
|
|
154
|
+
if (issue.actions.length > 0) {
|
|
155
|
+
lines.push("");
|
|
156
|
+
}
|
|
149
157
|
lines.push(`${issue.actions.length + 1}. Skip for now`);
|
|
150
158
|
return lines.join("\n");
|
|
151
159
|
}
|
|
152
160
|
function renderReadinessIssueNextSteps(issue) {
|
|
153
|
-
const lines = [
|
|
161
|
+
const lines = [issue.summary];
|
|
154
162
|
if (issue.detail && issue.kind !== "vault-locked") {
|
|
155
|
-
lines.push(`
|
|
163
|
+
lines.push(` ${issue.detail}`);
|
|
156
164
|
}
|
|
157
165
|
issue.actions.forEach((action, index) => {
|
|
158
|
-
lines.push(`
|
|
166
|
+
lines.push(` ${index === 0 ? "next" : "or"}: ${action.command}`);
|
|
159
167
|
});
|
|
160
168
|
return lines;
|
|
161
169
|
}
|