@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"} repair`;
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("provider checks recovered after repair");
183
+ deps.writeStdout("All set. Provider checks recovered after repair.");
184
184
  return remainingDegraded;
185
185
  }
186
- writeProviderRepairSummary(deps, "Still blocked:", remainingDegraded);
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 repair:", preflightProviderDegraded);
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 repair:", repairResult.remainingDegraded);
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 blocked:", remainingDegraded);
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("provider checks recovered after repair");
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 repair:", daemonResult.stability.degraded);
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 ? "" : " but daemon failed to respond, check logs";
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 from ${runningVersion} to ${deps.localVersion} (pid ${pid})${suffix}`
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 writeDeclinedRepair(degraded, command, deps) {
68
- deps.writeStdout(`repair skipped for ${degraded.agent}; run \`${command}\` later.`);
69
- if (degraded.fixHint.includes("ouro vault replace") || degraded.fixHint.includes("ouro vault recover")) {
70
- deps.writeStdout(`repair options for ${degraded.agent}: ${degraded.fixHint}`);
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 repairable = degraded
110
- .map((entry) => ({ entry, action: runnableRepairActionFor(entry) }))
111
- .filter((item) => item.action !== undefined);
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
- const answer = await deps.promptInput(`run \`${action.command}\` now? Only say yes if you have the saved unlock secret. [y/n] `);
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(`fix hint for ${entry.agent}: ${entry.fixHint}`);
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(`vault unlock error for ${entry.agent}: ${msg}`);
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
- const answer = await deps.promptInput(`run \`${action.command}\` now? [y/n] `);
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(`auth flow error for ${entry.agent}: ${msg}`);
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(`fix hint for ${entry.agent}: ${entry.fixHint}`);
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(`${entry.agent}: ${entry.errorReason}`);
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 = [` ${issue.summary}`];
161
+ const lines = [issue.summary];
154
162
  if (issue.detail && issue.kind !== "vault-locked") {
155
- lines.push(` ${issue.detail}`);
163
+ lines.push(` ${issue.detail}`);
156
164
  }
157
165
  issue.actions.forEach((action, index) => {
158
- lines.push(` ${index === 0 ? "next" : "or"}: ${action.command}`);
166
+ lines.push(` ${index === 0 ? "next" : "or"}: ${action.command}`);
159
167
  });
160
168
  return lines;
161
169
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.408",
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",