@ouro.bot/cli 0.1.0-alpha.442 → 0.1.0-alpha.444
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 +16 -0
- package/dist/heart/daemon/agent-config-check.js +34 -2
- package/dist/heart/daemon/cli-defaults.js +6 -1
- package/dist/heart/daemon/cli-exec.js +167 -40
- package/dist/heart/daemon/daemon-cli.js +2 -1
- package/dist/heart/daemon/daemon-runtime-sync.js +17 -2
- package/dist/heart/daemon/provider-ping-progress.js +9 -4
- package/dist/heart/daemon/terminal-ui.js +2 -2
- package/dist/heart/daemon/up-progress.js +57 -11
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
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.444",
|
|
6
|
+
"changes": [
|
|
7
|
+
"`ouro up` now treats daemon startup as one truthful boot story across fresh starts and daemon replacement: both paths wait on the same current-boot readiness check, keep narrating real progress while the background service warms up, and stop calling startup done just because one quick socket probe answered.",
|
|
8
|
+
"Slow real-world boots now get more patience and better visibility. The default startup timeout was extended to 60 seconds, the boot checklist keeps printing live startup detail instead of stalling on a blinking cursor, and replacement boot failures now land as a failed `starting daemon` step with plain-language diagnosis.",
|
|
9
|
+
"Startup failures now behave like failures to the shell as well as to the human: `ouro up` sets a non-zero exit code when daemon boot does not finish, and `ouro logs` is wired into the installed CLI again so the recovery path it points to actually opens the live daemon/agent log tail."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"version": "0.1.0-alpha.443",
|
|
14
|
+
"changes": [
|
|
15
|
+
"`ouro up` now renders as a real boot checklist instead of a loose progress wall: the screen shows the full startup path up front, marks what is running now, and keeps pending steps visible so humans can see where Ouro is in the bring-up flow.",
|
|
16
|
+
"Provider checks during startup now narrate the providers each selected lane is actually using, translate noisy vault chatter into plain language, and keep the live-check copy truthful instead of implying that every configured provider was checked.",
|
|
17
|
+
"`ouro up` no longer reports success just because the daemon answered once during startup. Before handing control back, Ouro now performs one final daemon-status handoff check and fails with a clear diagnosis if the background service stopped before boot actually finished."
|
|
18
|
+
]
|
|
19
|
+
},
|
|
4
20
|
{
|
|
5
21
|
"version": "0.1.0-alpha.442",
|
|
6
22
|
"changes": [
|
|
@@ -318,6 +318,33 @@ function failedPingResult(agentName, lane, provider, model, result) {
|
|
|
318
318
|
function credentialRecordForLane(pool, provider) {
|
|
319
319
|
return pool.providers[provider];
|
|
320
320
|
}
|
|
321
|
+
function laneAudienceLabel(lane) {
|
|
322
|
+
return lane === "outward" ? "chat" : "inner dialog";
|
|
323
|
+
}
|
|
324
|
+
function bindingLabel(binding) {
|
|
325
|
+
return `${binding.provider} / ${binding.model}`;
|
|
326
|
+
}
|
|
327
|
+
function selectedProviderPlan(agentName, state) {
|
|
328
|
+
return [
|
|
329
|
+
`${agentName}: checking the providers this agent uses right now`,
|
|
330
|
+
...["outward", "inner"].map((lane) => `- ${laneAudienceLabel(lane)}: ${bindingLabel(state.lanes[lane])}`),
|
|
331
|
+
].join("\n");
|
|
332
|
+
}
|
|
333
|
+
function mapVaultRefreshProgress(agentName, onProgress) {
|
|
334
|
+
return (message) => {
|
|
335
|
+
if (message.startsWith("reading vault items for ")) {
|
|
336
|
+
onProgress(`${agentName}: opening saved provider credentials in the vault`);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (message === "parsing provider credentials...") {
|
|
340
|
+
onProgress(`${agentName}: organizing saved provider credentials`);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function providerPingSubject(agentName, lanes) {
|
|
345
|
+
const laneList = lanes.map((lane) => laneAudienceLabel(lane)).join(" + ");
|
|
346
|
+
return `${agentName} (${laneList})`;
|
|
347
|
+
}
|
|
321
348
|
/**
|
|
322
349
|
* Structural validation only. Live provider credential validation belongs to
|
|
323
350
|
* checkAgentConfigWithProviderHealth(), which reads the agent vault and pings.
|
|
@@ -352,8 +379,9 @@ async function checkAgentConfigWithProviderHealth(agentName, bundlesRoot, deps =
|
|
|
352
379
|
return stateResult.result;
|
|
353
380
|
if (stateResult.disabled)
|
|
354
381
|
return { ok: true };
|
|
382
|
+
deps.onProgress?.(selectedProviderPlan(agentName, stateResult.state));
|
|
355
383
|
const ping = deps.pingProvider ?? (await Promise.resolve().then(() => __importStar(require("../provider-ping")))).pingProvider;
|
|
356
|
-
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(agentName, deps.onProgress ? { onProgress: deps.onProgress } : undefined);
|
|
384
|
+
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(agentName, deps.onProgress ? { onProgress: mapVaultRefreshProgress(agentName, deps.onProgress) } : undefined);
|
|
357
385
|
const pingGroups = new Map();
|
|
358
386
|
const lanes = ["outward", "inner"];
|
|
359
387
|
for (const lane of lanes) {
|
|
@@ -390,7 +418,11 @@ async function checkAgentConfigWithProviderHealth(agentName, bundlesRoot, deps =
|
|
|
390
418
|
const result = await ping(group.provider, providerCredentialConfig(group.record), {
|
|
391
419
|
model: group.model,
|
|
392
420
|
...(deps.onProgress
|
|
393
|
-
? (0, provider_ping_progress_1.createProviderPingProgressReporter)({
|
|
421
|
+
? (0, provider_ping_progress_1.createProviderPingProgressReporter)({
|
|
422
|
+
provider: group.provider,
|
|
423
|
+
model: group.model,
|
|
424
|
+
subject: providerPingSubject(agentName, group.lanes),
|
|
425
|
+
}, deps.onProgress)
|
|
394
426
|
: {}),
|
|
395
427
|
});
|
|
396
428
|
return { group, result };
|
|
@@ -514,11 +514,16 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
|
|
|
514
514
|
sendCommand: socket_client_1.sendDaemonCommand,
|
|
515
515
|
startDaemonProcess: defaultStartDaemonProcess,
|
|
516
516
|
writeStdout: defaultWriteStdout,
|
|
517
|
+
setExitCode: (code) => {
|
|
518
|
+
const current = typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
519
|
+
process.exitCode = Math.max(current, code);
|
|
520
|
+
},
|
|
517
521
|
writeRaw: defaultWriteRaw,
|
|
518
522
|
isTTY: process.stdout.isTTY === true,
|
|
519
523
|
checkSocketAlive: socket_client_1.checkDaemonSocketAlive,
|
|
520
524
|
cleanupStaleSocket: defaultCleanupStaleSocket,
|
|
521
525
|
fallbackPendingMessage: defaultFallbackPendingMessage,
|
|
526
|
+
tailLogs: (options) => (0, log_tailer_1.tailLogs)(options),
|
|
522
527
|
healthFilePath: (0, daemon_health_1.getDefaultHealthPath)(),
|
|
523
528
|
readHealthState: daemon_health_1.readHealth,
|
|
524
529
|
readHealthUpdatedAt: defaultReadHealthUpdatedAt,
|
|
@@ -528,7 +533,7 @@ function createDefaultOuroCliDeps(socketPath = socket_client_1.DEFAULT_DAEMON_SO
|
|
|
528
533
|
updateCheckTimeoutMs: update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS,
|
|
529
534
|
startupPollIntervalMs: 250,
|
|
530
535
|
startupStabilityWindowMs: 1_500,
|
|
531
|
-
startupTimeoutMs:
|
|
536
|
+
startupTimeoutMs: 60_000,
|
|
532
537
|
startupRetryLimit: 1,
|
|
533
538
|
listDiscoveredAgents: defaultListDiscoveredAgents,
|
|
534
539
|
runHatchFlow: hatch_flow_1.runHatchFlow,
|
|
@@ -39,6 +39,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.summarizeDaemonStartupFailure = summarizeDaemonStartupFailure;
|
|
42
43
|
exports.mergeStartupStability = mergeStartupStability;
|
|
43
44
|
exports.ensureDaemonRunning = ensureDaemonRunning;
|
|
44
45
|
exports.listGithubCopilotModels = listGithubCopilotModels;
|
|
@@ -100,7 +101,7 @@ const agent_discovery_1 = require("./agent-discovery");
|
|
|
100
101
|
const connect_bay_1 = require("./connect-bay");
|
|
101
102
|
const runtime_capability_check_1 = require("../runtime-capability-check");
|
|
102
103
|
// ── ensureDaemonRunning ──
|
|
103
|
-
const DEFAULT_DAEMON_STARTUP_TIMEOUT_MS =
|
|
104
|
+
const DEFAULT_DAEMON_STARTUP_TIMEOUT_MS = 60_000;
|
|
104
105
|
const DEFAULT_DAEMON_STARTUP_POLL_INTERVAL_MS = 500;
|
|
105
106
|
const DEFAULT_DAEMON_STARTUP_STABILITY_WINDOW_MS = 1_500;
|
|
106
107
|
const DEFAULT_DAEMON_STARTUP_RETRY_LIMIT = 1;
|
|
@@ -122,6 +123,31 @@ function summarizeCliUpdateCheckStatus(error, timedOut = false) {
|
|
|
122
123
|
}
|
|
123
124
|
return "skipped; update check unavailable";
|
|
124
125
|
}
|
|
126
|
+
function returnCliFailure(deps, message, exitCode = 1) {
|
|
127
|
+
deps.setExitCode?.(exitCode);
|
|
128
|
+
deps.writeStdout(message);
|
|
129
|
+
return message;
|
|
130
|
+
}
|
|
131
|
+
function summarizeDaemonStartupFailure(result) {
|
|
132
|
+
if (result.startupFailureReason && result.startupFailureReason.trim().length > 0) {
|
|
133
|
+
return result.startupFailureReason;
|
|
134
|
+
}
|
|
135
|
+
const firstLine = result.message.split(/\r?\n/, 1)[0]?.trim();
|
|
136
|
+
return firstLine && firstLine.length > 0
|
|
137
|
+
? firstLine
|
|
138
|
+
: "background service failed to finish booting";
|
|
139
|
+
}
|
|
140
|
+
function formatDaemonStartupProgressLine(serviceLabel, status, latestEvent) {
|
|
141
|
+
const base = status === "waiting"
|
|
142
|
+
? `waiting for the ${serviceLabel} to answer`
|
|
143
|
+
: status === "answering"
|
|
144
|
+
? `${serviceLabel} answered\n- waiting for this boot to publish its ready signal`
|
|
145
|
+
: `${serviceLabel} answered\n- ready signal received; making sure it holds`;
|
|
146
|
+
const trimmedEvent = latestEvent?.trim();
|
|
147
|
+
return trimmedEvent && status !== "stabilizing"
|
|
148
|
+
? `${base}\n- latest daemon event: ${trimmedEvent}`
|
|
149
|
+
: base;
|
|
150
|
+
}
|
|
125
151
|
async function runCliUpdateCheckWithTimeout(checkForCliUpdate, timeoutMs = update_checker_1.CLI_UPDATE_CHECK_TIMEOUT_MS) {
|
|
126
152
|
return await new Promise((resolve, reject) => {
|
|
127
153
|
let settled = false;
|
|
@@ -160,7 +186,6 @@ async function checkAgentProviders(deps, agentsOverride, onProgress) {
|
|
|
160
186
|
const degraded = [];
|
|
161
187
|
for (const agent of [...new Set(agents)]) {
|
|
162
188
|
try {
|
|
163
|
-
onProgress?.(`${agent}: checking providers...`);
|
|
164
189
|
const result = await checkAgentProviderHealth(agent, bundlesRoot, deps, onProgress);
|
|
165
190
|
if (result.ok)
|
|
166
191
|
continue;
|
|
@@ -358,9 +383,14 @@ function writeProviderRepairSummary(deps, title, degraded) {
|
|
|
358
383
|
}
|
|
359
384
|
function providerRepairCountSummary(count) {
|
|
360
385
|
if (count === 0)
|
|
361
|
-
return "
|
|
386
|
+
return "selected providers answered live checks";
|
|
362
387
|
return `${count} ${count === 1 ? "needs" : "need"} attention`;
|
|
363
388
|
}
|
|
389
|
+
function bootPhasePlan(daemonAlive) {
|
|
390
|
+
return daemonAlive
|
|
391
|
+
? ["update check", "system setup", "starting daemon", "provider checks", "final daemon check"]
|
|
392
|
+
: ["update check", "system setup", "provider checks", "starting daemon", "final daemon check"];
|
|
393
|
+
}
|
|
364
394
|
function createHumanCommandProgress(deps, commandName) {
|
|
365
395
|
return new up_progress_1.CommandProgress({
|
|
366
396
|
write: deps.writeRaw ?? deps.writeStdout,
|
|
@@ -387,8 +417,67 @@ function daemonProgressSummary(result) {
|
|
|
387
417
|
if (result.alreadyRunning)
|
|
388
418
|
return "already running";
|
|
389
419
|
if (result.message.includes("replaced"))
|
|
390
|
-
return "replacement
|
|
391
|
-
return "
|
|
420
|
+
return "replacement answered";
|
|
421
|
+
return "background service answered";
|
|
422
|
+
}
|
|
423
|
+
function finalDaemonFailureMessage(deps, reason) {
|
|
424
|
+
const lines = [`background service stopped before boot finished: ${reason}`];
|
|
425
|
+
const recentLogLines = deps.readRecentDaemonLogLines?.(DEFAULT_DAEMON_STARTUP_LOG_LINES) ?? [];
|
|
426
|
+
if (recentLogLines.length > 0) {
|
|
427
|
+
lines.push("recent daemon logs:");
|
|
428
|
+
lines.push(...recentLogLines.map((line) => ` ${line}`));
|
|
429
|
+
}
|
|
430
|
+
lines.push("Run `ouro up` again or `ouro doctor` for a deeper diagnosis.");
|
|
431
|
+
return lines.join("\n");
|
|
432
|
+
}
|
|
433
|
+
async function verifyDaemonReadyForHandoff(deps) {
|
|
434
|
+
const socketAlive = await deps.checkSocketAlive(deps.socketPath);
|
|
435
|
+
if (!socketAlive) {
|
|
436
|
+
return {
|
|
437
|
+
ok: false,
|
|
438
|
+
summary: "background service stopped",
|
|
439
|
+
message: finalDaemonFailureMessage(deps, "the daemon socket is no longer answering"),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const response = await deps.sendCommand(deps.socketPath, { kind: "daemon.status" });
|
|
444
|
+
if (!response.ok) {
|
|
445
|
+
const reason = response.error ?? response.message ?? "daemon status did not answer cleanly";
|
|
446
|
+
return {
|
|
447
|
+
ok: false,
|
|
448
|
+
summary: "daemon status did not answer",
|
|
449
|
+
message: finalDaemonFailureMessage(deps, reason),
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const payload = (0, cli_render_1.parseStatusPayload)(response.data);
|
|
453
|
+
if (!payload) {
|
|
454
|
+
return {
|
|
455
|
+
ok: true,
|
|
456
|
+
summary: "daemon answered",
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
if (payload.overview.daemon !== "running") {
|
|
460
|
+
return {
|
|
461
|
+
ok: false,
|
|
462
|
+
summary: `daemon reported ${payload.overview.daemon}`,
|
|
463
|
+
message: finalDaemonFailureMessage(deps, `the daemon reported state ${payload.overview.daemon}`),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const workerCount = payload.workers.length;
|
|
467
|
+
return {
|
|
468
|
+
ok: true,
|
|
469
|
+
summary: workerCount === 0
|
|
470
|
+
? "daemon answered"
|
|
471
|
+
: `${workerCount} worker${workerCount === 1 ? "" : "s"} still answering`,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
return {
|
|
476
|
+
ok: false,
|
|
477
|
+
summary: "daemon status did not answer",
|
|
478
|
+
message: finalDaemonFailureMessage(deps, error instanceof Error ? error.message : String(error)),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
392
481
|
}
|
|
393
482
|
async function reportPostRepairProviderHealth(deps, repairedAgents, onProgress) {
|
|
394
483
|
const remainingDegraded = await checkAgentProviders(deps, repairedAgents, onProgress);
|
|
@@ -566,7 +655,7 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
566
655
|
// The daemon writes structured events to daemon.ndjson in the first
|
|
567
656
|
// agent bundle's state/daemon/logs/ directory. Read the last line to
|
|
568
657
|
// surface what it's currently doing (e.g., "starting auto-start agents").
|
|
569
|
-
const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
|
|
658
|
+
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
570
659
|
if (!fs.existsSync(bundlesRoot))
|
|
571
660
|
return null;
|
|
572
661
|
const agents = fs.readdirSync(bundlesRoot).filter((d) => d.endsWith(".ouro"));
|
|
@@ -643,9 +732,27 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
643
732
|
startDaemonProcess: deps.startDaemonProcess,
|
|
644
733
|
checkSocketAlive: deps.checkSocketAlive,
|
|
645
734
|
onProgress: deps.reportDaemonStartupPhase,
|
|
735
|
+
waitForDaemonStartup: async ({ pid }) => {
|
|
736
|
+
const startupFailure = await waitForDaemonStartup(deps, {
|
|
737
|
+
bootStartedAtMs: (deps.now ?? Date.now)(),
|
|
738
|
+
pid,
|
|
739
|
+
serviceLabel: "replacement background service",
|
|
740
|
+
readLatestDaemonEvent: readLatestDaemonStartupEvent,
|
|
741
|
+
});
|
|
742
|
+
return startupFailure
|
|
743
|
+
? { ok: false, reason: startupFailure.reason }
|
|
744
|
+
: { ok: true };
|
|
745
|
+
},
|
|
646
746
|
});
|
|
647
|
-
if (!runtimeResult.
|
|
648
|
-
return
|
|
747
|
+
if (!runtimeResult.ok) {
|
|
748
|
+
return {
|
|
749
|
+
ok: false,
|
|
750
|
+
alreadyRunning: runtimeResult.alreadyRunning,
|
|
751
|
+
message: runtimeResult.message,
|
|
752
|
+
verifyStartupStatus: runtimeResult.verifyStartupStatus,
|
|
753
|
+
startedPid: runtimeResult.startedPid,
|
|
754
|
+
startupFailureReason: runtimeResult.startupFailureReason ?? null,
|
|
755
|
+
};
|
|
649
756
|
}
|
|
650
757
|
const stability = await (0, startup_tui_1.pollDaemonStartup)({
|
|
651
758
|
sendCommand: deps.sendCommand,
|
|
@@ -666,8 +773,12 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
666
773
|
render: !deps.reportDaemonStartupPhase,
|
|
667
774
|
});
|
|
668
775
|
return {
|
|
776
|
+
ok: true,
|
|
669
777
|
alreadyRunning: runtimeResult.alreadyRunning,
|
|
670
778
|
message: runtimeResult.message,
|
|
779
|
+
verifyStartupStatus: runtimeResult.verifyStartupStatus,
|
|
780
|
+
startedPid: runtimeResult.startedPid,
|
|
781
|
+
startupFailureReason: null,
|
|
671
782
|
stability,
|
|
672
783
|
};
|
|
673
784
|
}
|
|
@@ -687,6 +798,8 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
687
798
|
const startupFailure = await waitForDaemonStartup(deps, {
|
|
688
799
|
bootStartedAtMs,
|
|
689
800
|
pid: lastPid,
|
|
801
|
+
serviceLabel: "new background service",
|
|
802
|
+
readLatestDaemonEvent: readLatestDaemonStartupEvent,
|
|
690
803
|
});
|
|
691
804
|
if (!startupFailure) {
|
|
692
805
|
const stability = await (0, startup_tui_1.pollDaemonStartup)({
|
|
@@ -708,8 +821,10 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
708
821
|
render: !deps.reportDaemonStartupPhase,
|
|
709
822
|
});
|
|
710
823
|
return {
|
|
824
|
+
ok: true,
|
|
711
825
|
alreadyRunning: false,
|
|
712
826
|
message: `daemon started (pid ${lastPid ?? "unknown"})`,
|
|
827
|
+
startupFailureReason: null,
|
|
713
828
|
stability,
|
|
714
829
|
};
|
|
715
830
|
}
|
|
@@ -720,8 +835,10 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
720
835
|
deps.reportDaemonStartupPhase?.("background service startup went sideways once; trying one more time");
|
|
721
836
|
}
|
|
722
837
|
return {
|
|
838
|
+
ok: false,
|
|
723
839
|
alreadyRunning: false,
|
|
724
840
|
message: formatDaemonStartupFailureMessage(lastPid, lastFailure, deps),
|
|
841
|
+
startupFailureReason: lastFailure.reason,
|
|
725
842
|
};
|
|
726
843
|
}
|
|
727
844
|
function hasStartupHealthMonitor(deps) {
|
|
@@ -746,14 +863,14 @@ function hasFreshCurrentBootHealthSignal(deps, bootStartedAtMs, pid) {
|
|
|
746
863
|
}
|
|
747
864
|
function formatDaemonStartupFailureMessage(pid, failure, deps) {
|
|
748
865
|
const lines = [
|
|
749
|
-
`
|
|
866
|
+
`background service started (pid ${pid ?? "unknown"}) but did not finish booting: ${failure.reason}`,
|
|
750
867
|
];
|
|
751
868
|
const recentLogLines = deps.readRecentDaemonLogLines?.(DEFAULT_DAEMON_STARTUP_LOG_LINES) ?? [];
|
|
752
869
|
if (recentLogLines.length > 0) {
|
|
753
870
|
lines.push("recent daemon logs:");
|
|
754
871
|
lines.push(...recentLogLines.map((line) => ` ${line}`));
|
|
755
872
|
}
|
|
756
|
-
lines.push("
|
|
873
|
+
lines.push("Run `ouro logs` to watch live startup logs or `ouro doctor` for a deeper diagnosis.");
|
|
757
874
|
return lines.join("\n");
|
|
758
875
|
}
|
|
759
876
|
async function waitForDaemonStartup(deps, options) {
|
|
@@ -767,13 +884,17 @@ async function waitForDaemonStartup(deps, options) {
|
|
|
767
884
|
let stableSinceMs = null;
|
|
768
885
|
let sawSocket = false;
|
|
769
886
|
if (!useHealthMonitor) {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
887
|
+
while (now() < deadline) {
|
|
888
|
+
await sleep(pollIntervalMs);
|
|
889
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
890
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "waiting", latestEvent));
|
|
891
|
+
if (await deps.checkSocketAlive(deps.socketPath))
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
return {
|
|
895
|
+
reason: `${options.serviceLabel} did not answer within ${Math.ceil(timeoutMs / 1000)}s`,
|
|
896
|
+
retryable: false,
|
|
897
|
+
};
|
|
777
898
|
}
|
|
778
899
|
while (now() < deadline) {
|
|
779
900
|
await sleep(pollIntervalMs);
|
|
@@ -781,40 +902,37 @@ async function waitForDaemonStartup(deps, options) {
|
|
|
781
902
|
if (!aliveNow) {
|
|
782
903
|
if (sawSocket) {
|
|
783
904
|
return {
|
|
784
|
-
reason:
|
|
905
|
+
reason: `${options.serviceLabel} answered once and then disappeared during startup`,
|
|
785
906
|
retryable: true,
|
|
786
907
|
};
|
|
787
908
|
}
|
|
909
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
910
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "waiting", latestEvent));
|
|
788
911
|
continue;
|
|
789
912
|
}
|
|
790
913
|
if (!sawSocket) {
|
|
791
914
|
sawSocket = true;
|
|
792
915
|
stableSinceMs = now();
|
|
793
|
-
|
|
916
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
917
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "answering", latestEvent));
|
|
794
918
|
}
|
|
795
919
|
if (!hasFreshCurrentBootHealthSignal(deps, options.bootStartedAtMs, options.pid)) {
|
|
920
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
921
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "answering", latestEvent));
|
|
796
922
|
continue;
|
|
797
923
|
}
|
|
924
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "stabilizing"));
|
|
798
925
|
if (stableSinceMs !== null && now() - stableSinceMs >= stabilityWindowMs) {
|
|
799
926
|
return null;
|
|
800
927
|
}
|
|
801
928
|
}
|
|
802
929
|
return {
|
|
803
930
|
reason: sawSocket
|
|
804
|
-
?
|
|
805
|
-
:
|
|
931
|
+
? `${options.serviceLabel} answered but this boot never published a ready signal within ${Math.ceil(timeoutMs / 1000)}s`
|
|
932
|
+
: `${options.serviceLabel} did not answer within ${Math.ceil(timeoutMs / 1000)}s`,
|
|
806
933
|
retryable: sawSocket,
|
|
807
934
|
};
|
|
808
935
|
}
|
|
809
|
-
async function verifyDaemonAlive(checkSocketAlive, socketPath, maxWaitMs = 10_000, pollIntervalMs = 500, sleep = defaultSleep, now = Date.now) {
|
|
810
|
-
const deadline = now() + maxWaitMs;
|
|
811
|
-
while (now() < deadline) {
|
|
812
|
-
await sleep(pollIntervalMs);
|
|
813
|
-
if (await checkSocketAlive(socketPath))
|
|
814
|
-
return true;
|
|
815
|
-
}
|
|
816
|
-
return false;
|
|
817
|
-
}
|
|
818
936
|
function defaultSleep(ms) {
|
|
819
937
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
820
938
|
}
|
|
@@ -3939,6 +4057,8 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
3939
4057
|
now: deps.now ?? (() => Date.now()),
|
|
3940
4058
|
autoRender: true,
|
|
3941
4059
|
});
|
|
4060
|
+
const daemonAliveAtBootStart = await deps.checkSocketAlive(deps.socketPath);
|
|
4061
|
+
progress.setPhasePlan?.(bootPhasePlan(daemonAliveAtBootStart));
|
|
3942
4062
|
// ── versioned CLI update check ──
|
|
3943
4063
|
if (deps.checkForCliUpdate) {
|
|
3944
4064
|
progress.startPhase("update check");
|
|
@@ -4067,6 +4187,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4067
4187
|
promptInput: deps.promptInput,
|
|
4068
4188
|
});
|
|
4069
4189
|
const daemonAliveBeforeStart = await deps.checkSocketAlive(deps.socketPath);
|
|
4190
|
+
progress.setPhasePlan?.(bootPhasePlan(daemonAliveBeforeStart));
|
|
4070
4191
|
let providerChecksAlreadyRun = false;
|
|
4071
4192
|
if (!daemonAliveBeforeStart) {
|
|
4072
4193
|
progress.startPhase("provider checks");
|
|
@@ -4078,22 +4199,19 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4078
4199
|
if (command.noRepair) {
|
|
4079
4200
|
writeProviderRepairSummary(deps, "Provider checks need attention", preflightProviderDegraded);
|
|
4080
4201
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
4081
|
-
deps
|
|
4082
|
-
return message;
|
|
4202
|
+
return returnCliFailure(deps, message);
|
|
4083
4203
|
}
|
|
4084
4204
|
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
4085
4205
|
if (!repairResult.repairsAttempted) {
|
|
4086
4206
|
writeProviderRepairSummary(deps, "Provider checks still need attention", repairResult.remainingDegraded);
|
|
4087
4207
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
4088
|
-
deps
|
|
4089
|
-
return message;
|
|
4208
|
+
return returnCliFailure(deps, message);
|
|
4090
4209
|
}
|
|
4091
4210
|
const remainingDegraded = repairResult.remainingDegraded;
|
|
4092
4211
|
if (remainingDegraded.length > 0) {
|
|
4093
4212
|
writeProviderRepairSummary(deps, "Still needs attention", remainingDegraded);
|
|
4094
4213
|
const message = "daemon not started: provider checks still need repair.";
|
|
4095
|
-
deps
|
|
4096
|
-
return message;
|
|
4214
|
+
return returnCliFailure(deps, message);
|
|
4097
4215
|
}
|
|
4098
4216
|
deps.writeStdout("All set. Provider checks recovered after repair.");
|
|
4099
4217
|
}
|
|
@@ -4106,12 +4224,11 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4106
4224
|
progress.announceStep?.(label);
|
|
4107
4225
|
},
|
|
4108
4226
|
}, { initialAlive: daemonAliveBeforeStart });
|
|
4109
|
-
if (daemonResult.
|
|
4227
|
+
if (!daemonResult.ok) {
|
|
4110
4228
|
;
|
|
4111
|
-
progress.
|
|
4229
|
+
progress.failPhase?.("starting daemon", summarizeDaemonStartupFailure(daemonResult));
|
|
4112
4230
|
progress.end();
|
|
4113
|
-
deps
|
|
4114
|
-
return daemonResult.message;
|
|
4231
|
+
return returnCliFailure(deps, daemonResult.message);
|
|
4115
4232
|
}
|
|
4116
4233
|
progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
|
|
4117
4234
|
if (!providerChecksAlreadyRun || daemonResult.alreadyRunning) {
|
|
@@ -4120,6 +4237,16 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4120
4237
|
daemonResult.stability = mergeStartupStability(daemonResult.stability, providerDegraded);
|
|
4121
4238
|
progress.completePhase("provider checks", providerRepairCountSummary(providerDegraded.length));
|
|
4122
4239
|
}
|
|
4240
|
+
progress.startPhase("final daemon check");
|
|
4241
|
+
const finalDaemonCheck = await verifyDaemonReadyForHandoff(deps);
|
|
4242
|
+
if (!finalDaemonCheck.ok) {
|
|
4243
|
+
;
|
|
4244
|
+
progress.failPhase?.("final daemon check", finalDaemonCheck.summary);
|
|
4245
|
+
progress.end();
|
|
4246
|
+
const message = finalDaemonCheck.message ?? "background service stopped before boot finished";
|
|
4247
|
+
return returnCliFailure(deps, message);
|
|
4248
|
+
}
|
|
4249
|
+
progress.completePhase("final daemon check", finalDaemonCheck.summary);
|
|
4123
4250
|
progress.end();
|
|
4124
4251
|
// Interactive repair for degraded agents (Unit 5) — skipped by --no-repair (Unit 6)
|
|
4125
4252
|
if (daemonResult.stability?.degraded && daemonResult.stability.degraded.length > 0) {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ouro-entry.ts, ouro-bot-wrapper.ts) continue to work unchanged.
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.readFirstBundleMetaVersion = exports.createDefaultOuroCliDeps = exports.pingGithubCopilotModel = exports.listGithubCopilotModels = exports.ensureDaemonRunning = exports.runOuroCli = exports.parseOuroCommand = void 0;
|
|
17
|
+
exports.readFirstBundleMetaVersion = exports.createDefaultOuroCliDeps = exports.pingGithubCopilotModel = exports.summarizeDaemonStartupFailure = exports.listGithubCopilotModels = exports.ensureDaemonRunning = exports.runOuroCli = exports.parseOuroCommand = void 0;
|
|
18
18
|
// ── Parsing ──
|
|
19
19
|
var cli_parse_1 = require("./cli-parse");
|
|
20
20
|
Object.defineProperty(exports, "parseOuroCommand", { enumerable: true, get: function () { return cli_parse_1.parseOuroCommand; } });
|
|
@@ -23,6 +23,7 @@ var cli_exec_1 = require("./cli-exec");
|
|
|
23
23
|
Object.defineProperty(exports, "runOuroCli", { enumerable: true, get: function () { return cli_exec_1.runOuroCli; } });
|
|
24
24
|
Object.defineProperty(exports, "ensureDaemonRunning", { enumerable: true, get: function () { return cli_exec_1.ensureDaemonRunning; } });
|
|
25
25
|
Object.defineProperty(exports, "listGithubCopilotModels", { enumerable: true, get: function () { return cli_exec_1.listGithubCopilotModels; } });
|
|
26
|
+
Object.defineProperty(exports, "summarizeDaemonStartupFailure", { enumerable: true, get: function () { return cli_exec_1.summarizeDaemonStartupFailure; } });
|
|
26
27
|
var provider_ping_1 = require("../provider-ping");
|
|
27
28
|
Object.defineProperty(exports, "pingGithubCopilotModel", { enumerable: true, get: function () { return provider_ping_1.pingGithubCopilotModel; } });
|
|
28
29
|
// ── Defaults ──
|
|
@@ -111,10 +111,14 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
111
111
|
catch (error) {
|
|
112
112
|
const reason = formatErrorReason(error);
|
|
113
113
|
result = {
|
|
114
|
+
ok: false,
|
|
114
115
|
alreadyRunning: true,
|
|
115
116
|
message: includesVersionDrift
|
|
116
117
|
? `daemon already running (${deps.socketPath}; could not replace the older background service ${runningVersion} -> ${deps.localVersion}: ${reason})`
|
|
117
118
|
: `daemon already running (${deps.socketPath}; could not replace the older background service after runtime drift ${publicDriftSummary}: ${reason})`,
|
|
119
|
+
startupFailureReason: includesVersionDrift
|
|
120
|
+
? "could not replace the older background service"
|
|
121
|
+
: "could not replace the older background service after runtime drift",
|
|
118
122
|
};
|
|
119
123
|
(0, runtime_1.emitNervesEvent)({
|
|
120
124
|
level: "warn",
|
|
@@ -144,16 +148,23 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
144
148
|
deps.onProgress?.("starting the replacement background service");
|
|
145
149
|
const started = await deps.startDaemonProcess(deps.socketPath);
|
|
146
150
|
const pid = started.pid ?? "unknown";
|
|
147
|
-
const
|
|
151
|
+
const startupCheck = deps.waitForDaemonStartup
|
|
152
|
+
? await deps.waitForDaemonStartup({ pid: started.pid ?? null })
|
|
153
|
+
: { ok: await verifyDaemonStarted(deps) };
|
|
154
|
+
const verified = startupCheck.ok;
|
|
148
155
|
/* v8 ignore next -- daemon liveness failure: requires real daemon crash timing @preserve */
|
|
149
|
-
const suffix = verified
|
|
156
|
+
const suffix = verified
|
|
157
|
+
? ""
|
|
158
|
+
: `\n${startupCheck.reason ?? "replacement background service did not answer in time"}; check logs with \`ouro logs\` or run \`ouro doctor\`.`;
|
|
150
159
|
result = {
|
|
160
|
+
ok: verified,
|
|
151
161
|
alreadyRunning: false,
|
|
152
162
|
message: includesVersionDrift
|
|
153
163
|
? `replaced an older background service ${runningVersion} -> ${deps.localVersion} (pid ${pid})${suffix}`
|
|
154
164
|
: `replaced an older background service after runtime drift: ${publicDriftSummary} (pid ${pid})${suffix}`,
|
|
155
165
|
verifyStartupStatus: verified,
|
|
156
166
|
startedPid: started.pid ?? null,
|
|
167
|
+
startupFailureReason: verified ? null : (startupCheck.reason ?? "replacement background service did not answer in time"),
|
|
157
168
|
};
|
|
158
169
|
(0, runtime_1.emitNervesEvent)({
|
|
159
170
|
component: "daemon",
|
|
@@ -180,6 +191,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
180
191
|
}
|
|
181
192
|
if (!isKnownVersion(localRuntime.version) || !isKnownVersion(runningVersion)) {
|
|
182
193
|
result = {
|
|
194
|
+
ok: true,
|
|
183
195
|
alreadyRunning: true,
|
|
184
196
|
message: `daemon already running (${deps.socketPath}; unable to verify version)`,
|
|
185
197
|
};
|
|
@@ -208,6 +220,7 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
208
220
|
catch (error) {
|
|
209
221
|
const reason = formatErrorReason(error);
|
|
210
222
|
const result = {
|
|
223
|
+
ok: true,
|
|
211
224
|
alreadyRunning: true,
|
|
212
225
|
message: `daemon already running (${deps.socketPath}; unable to verify version: ${reason})`,
|
|
213
226
|
};
|
|
@@ -230,10 +243,12 @@ async function ensureCurrentDaemonRuntime(deps) {
|
|
|
230
243
|
return result;
|
|
231
244
|
}
|
|
232
245
|
const result = {
|
|
246
|
+
ok: true,
|
|
233
247
|
alreadyRunning: true,
|
|
234
248
|
message: `daemon already running (${deps.socketPath})`,
|
|
235
249
|
verifyStartupStatus: true,
|
|
236
250
|
startedPid: null,
|
|
251
|
+
startupFailureReason: null,
|
|
237
252
|
};
|
|
238
253
|
(0, runtime_1.emitNervesEvent)({
|
|
239
254
|
component: "daemon",
|
|
@@ -33,11 +33,16 @@ function providerRetryTiming(delayMs) {
|
|
|
33
33
|
return `in ${rounded}`;
|
|
34
34
|
}
|
|
35
35
|
function formatProviderAttemptProgress(context, attempt, maxAttempts) {
|
|
36
|
-
|
|
36
|
+
const prefix = context.subject ? `${context.subject}: ` : "";
|
|
37
|
+
return `${prefix}checking ${formatProviderPingLabel(context)} (attempt ${attempt} of ${maxAttempts})...`;
|
|
37
38
|
}
|
|
38
|
-
function formatProviderRetryProgress(record, maxAttempts) {
|
|
39
|
+
function formatProviderRetryProgress(context, record, maxAttempts) {
|
|
39
40
|
const nextAttempt = Math.min(record.attempt + 1, maxAttempts);
|
|
40
|
-
|
|
41
|
+
const retryDetail = `${providerRetryReason(record)}; retrying ${providerRetryTiming(record.delayMs)} (attempt ${nextAttempt} of ${maxAttempts})`;
|
|
42
|
+
if (context.subject) {
|
|
43
|
+
return `${context.subject}: ${retryDetail} while checking ${formatProviderPingLabel(context)}`;
|
|
44
|
+
}
|
|
45
|
+
return `${formatProviderPingLabel(record)}: ${retryDetail}`;
|
|
41
46
|
}
|
|
42
47
|
function createProviderPingProgressReporter(context, onProgress) {
|
|
43
48
|
return {
|
|
@@ -70,7 +75,7 @@ function createProviderPingProgressReporter(context, onProgress) {
|
|
|
70
75
|
classification: record.classification ?? "unknown",
|
|
71
76
|
},
|
|
72
77
|
});
|
|
73
|
-
onProgress(formatProviderRetryProgress(record, maxAttempts));
|
|
78
|
+
onProgress(formatProviderRetryProgress(context, record, maxAttempts));
|
|
74
79
|
},
|
|
75
80
|
};
|
|
76
81
|
}
|
|
@@ -201,11 +201,11 @@ function renderTerminalOperation(options) {
|
|
|
201
201
|
summary: options.summary,
|
|
202
202
|
sections: [
|
|
203
203
|
{
|
|
204
|
-
title: "Right now",
|
|
204
|
+
title: options.currentTitle ?? "Right now",
|
|
205
205
|
lines: currentLines,
|
|
206
206
|
},
|
|
207
207
|
{
|
|
208
|
-
title: "Progress",
|
|
208
|
+
title: options.stepsTitle ?? "Progress",
|
|
209
209
|
lines: progressLines,
|
|
210
210
|
},
|
|
211
211
|
],
|
|
@@ -22,6 +22,22 @@ const BOLD = "\x1b[1m";
|
|
|
22
22
|
const DIM = "\x1b[2m";
|
|
23
23
|
const GREEN = "\x1b[38;2;46;204;64m";
|
|
24
24
|
const RED = "\x1b[38;2;255;106;106m";
|
|
25
|
+
const BASE_UP_PHASE_PLAN = [
|
|
26
|
+
"update check",
|
|
27
|
+
"system setup",
|
|
28
|
+
"provider checks",
|
|
29
|
+
"starting daemon",
|
|
30
|
+
"final daemon check",
|
|
31
|
+
];
|
|
32
|
+
const FRIENDLY_UP_PHASE_LABELS = {
|
|
33
|
+
"update check": "Check for updates",
|
|
34
|
+
"system setup": "Prepare this machine",
|
|
35
|
+
"agent updates": "Update installed agents",
|
|
36
|
+
"bundle cleanup": "Clean up stale bundles",
|
|
37
|
+
"provider checks": "Check the providers your agents use right now",
|
|
38
|
+
"starting daemon": "Start the background service",
|
|
39
|
+
"final daemon check": "Confirm the background service stayed up",
|
|
40
|
+
};
|
|
25
41
|
function splitDetailLines(detail) {
|
|
26
42
|
if (!detail)
|
|
27
43
|
return [];
|
|
@@ -45,6 +61,7 @@ class UpProgress {
|
|
|
45
61
|
completed = [];
|
|
46
62
|
currentPhase = null;
|
|
47
63
|
currentDetail = null;
|
|
64
|
+
upPhasePlan = BASE_UP_PHASE_PLAN;
|
|
48
65
|
prevLineCount = 0;
|
|
49
66
|
ended = false;
|
|
50
67
|
renderTimer = null;
|
|
@@ -96,6 +113,13 @@ class UpProgress {
|
|
|
96
113
|
return;
|
|
97
114
|
this.write(` ${label}\n`);
|
|
98
115
|
}
|
|
116
|
+
setPhasePlan(labels) {
|
|
117
|
+
const nextPlan = [...new Set(labels.map((label) => label.trim()).filter((label) => label.length > 0))];
|
|
118
|
+
this.upPhasePlan = nextPlan.length > 0 ? nextPlan : BASE_UP_PHASE_PLAN;
|
|
119
|
+
if (this.isTTY && this.eventScope === "up") {
|
|
120
|
+
this.flushRender();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
99
123
|
/**
|
|
100
124
|
* Update the sub-step detail on the current spinner phase. Rendered as
|
|
101
125
|
* "label (Xs) -- detail" in TTY mode. In non-TTY mode, writes changed
|
|
@@ -272,39 +296,61 @@ class UpProgress {
|
|
|
272
296
|
}
|
|
273
297
|
return lines;
|
|
274
298
|
}
|
|
299
|
+
renderUpStepLabel(label) {
|
|
300
|
+
return FRIENDLY_UP_PHASE_LABELS[label] ?? label;
|
|
301
|
+
}
|
|
275
302
|
renderUpScreen(now) {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
303
|
+
const seenLabels = new Set();
|
|
304
|
+
const steps = this.completed.map((phase) => {
|
|
305
|
+
seenLabels.add(phase.label);
|
|
306
|
+
return {
|
|
307
|
+
label: this.renderUpStepLabel(phase.label),
|
|
308
|
+
status: phase.status === "failure" ? "failed" : "done",
|
|
309
|
+
detail: phase.detail,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
let currentStepLabel = this.completed.some((phase) => phase.status === "failure")
|
|
313
|
+
? "Boot paused."
|
|
314
|
+
: this.completed.length > 0
|
|
315
|
+
? "Boot checklist complete."
|
|
316
|
+
: "Waiting to begin.";
|
|
282
317
|
let currentStepDetails = [];
|
|
283
318
|
if (this.currentPhase) {
|
|
284
319
|
const elapsed = now - this.currentPhase.startedAt;
|
|
285
320
|
const elapsedSec = (elapsed / 1000).toFixed(1);
|
|
286
321
|
const frameIndex = Math.floor(elapsed / 80) % SPINNER_FRAMES.length;
|
|
287
322
|
const spinner = SPINNER_FRAMES[frameIndex];
|
|
288
|
-
currentStepLabel = `${spinner} ${this.currentPhase.label} (${elapsedSec}s)`;
|
|
323
|
+
currentStepLabel = `${spinner} ${this.renderUpStepLabel(this.currentPhase.label)} (${elapsedSec}s)`;
|
|
289
324
|
currentStepDetails = splitDetailLines(this.currentPhase.detail);
|
|
290
325
|
steps.push({
|
|
291
|
-
label: this.currentPhase.label,
|
|
326
|
+
label: this.renderUpStepLabel(this.currentPhase.label),
|
|
292
327
|
status: "active",
|
|
293
328
|
});
|
|
329
|
+
seenLabels.add(this.currentPhase.label);
|
|
330
|
+
}
|
|
331
|
+
for (const label of this.upPhasePlan) {
|
|
332
|
+
if (!seenLabels.has(label)) {
|
|
333
|
+
steps.push({
|
|
334
|
+
label: this.renderUpStepLabel(label),
|
|
335
|
+
status: "pending",
|
|
336
|
+
});
|
|
337
|
+
}
|
|
294
338
|
}
|
|
295
339
|
return (0, terminal_ui_1.renderTerminalOperation)({
|
|
296
340
|
isTTY: true,
|
|
297
341
|
columns: this.columns,
|
|
298
342
|
masthead: {
|
|
299
|
-
subtitle: "
|
|
343
|
+
subtitle: "Booting the local agent runtime.",
|
|
300
344
|
},
|
|
301
|
-
title: "
|
|
302
|
-
summary: "Ouro
|
|
345
|
+
title: "Ouro boot checklist",
|
|
346
|
+
summary: "Ouro will check for updates, prepare this machine, verify the providers your agents use right now, start the background service, and make sure it stays up.",
|
|
303
347
|
currentStep: {
|
|
304
348
|
label: currentStepLabel,
|
|
305
349
|
detailLines: currentStepDetails,
|
|
306
350
|
},
|
|
307
351
|
steps,
|
|
352
|
+
currentTitle: "Doing now",
|
|
353
|
+
stepsTitle: "Boot checklist",
|
|
308
354
|
suppressEvent: true,
|
|
309
355
|
}).trimEnd().split("\n");
|
|
310
356
|
}
|