@ouro.bot/cli 0.1.0-alpha.443 → 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
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
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
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.443",
|
|
6
14
|
"changes": [
|
|
@@ -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;
|
|
@@ -629,7 +655,7 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
629
655
|
// The daemon writes structured events to daemon.ndjson in the first
|
|
630
656
|
// agent bundle's state/daemon/logs/ directory. Read the last line to
|
|
631
657
|
// surface what it's currently doing (e.g., "starting auto-start agents").
|
|
632
|
-
const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
|
|
658
|
+
const bundlesRoot = deps.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
633
659
|
if (!fs.existsSync(bundlesRoot))
|
|
634
660
|
return null;
|
|
635
661
|
const agents = fs.readdirSync(bundlesRoot).filter((d) => d.endsWith(".ouro"));
|
|
@@ -706,9 +732,27 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
706
732
|
startDaemonProcess: deps.startDaemonProcess,
|
|
707
733
|
checkSocketAlive: deps.checkSocketAlive,
|
|
708
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
|
+
},
|
|
709
746
|
});
|
|
710
|
-
if (!runtimeResult.
|
|
711
|
-
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
|
+
};
|
|
712
756
|
}
|
|
713
757
|
const stability = await (0, startup_tui_1.pollDaemonStartup)({
|
|
714
758
|
sendCommand: deps.sendCommand,
|
|
@@ -729,8 +773,12 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
729
773
|
render: !deps.reportDaemonStartupPhase,
|
|
730
774
|
});
|
|
731
775
|
return {
|
|
776
|
+
ok: true,
|
|
732
777
|
alreadyRunning: runtimeResult.alreadyRunning,
|
|
733
778
|
message: runtimeResult.message,
|
|
779
|
+
verifyStartupStatus: runtimeResult.verifyStartupStatus,
|
|
780
|
+
startedPid: runtimeResult.startedPid,
|
|
781
|
+
startupFailureReason: null,
|
|
734
782
|
stability,
|
|
735
783
|
};
|
|
736
784
|
}
|
|
@@ -750,6 +798,8 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
750
798
|
const startupFailure = await waitForDaemonStartup(deps, {
|
|
751
799
|
bootStartedAtMs,
|
|
752
800
|
pid: lastPid,
|
|
801
|
+
serviceLabel: "new background service",
|
|
802
|
+
readLatestDaemonEvent: readLatestDaemonStartupEvent,
|
|
753
803
|
});
|
|
754
804
|
if (!startupFailure) {
|
|
755
805
|
const stability = await (0, startup_tui_1.pollDaemonStartup)({
|
|
@@ -771,8 +821,10 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
771
821
|
render: !deps.reportDaemonStartupPhase,
|
|
772
822
|
});
|
|
773
823
|
return {
|
|
824
|
+
ok: true,
|
|
774
825
|
alreadyRunning: false,
|
|
775
826
|
message: `daemon started (pid ${lastPid ?? "unknown"})`,
|
|
827
|
+
startupFailureReason: null,
|
|
776
828
|
stability,
|
|
777
829
|
};
|
|
778
830
|
}
|
|
@@ -783,8 +835,10 @@ async function ensureDaemonRunning(deps, options = {}) {
|
|
|
783
835
|
deps.reportDaemonStartupPhase?.("background service startup went sideways once; trying one more time");
|
|
784
836
|
}
|
|
785
837
|
return {
|
|
838
|
+
ok: false,
|
|
786
839
|
alreadyRunning: false,
|
|
787
840
|
message: formatDaemonStartupFailureMessage(lastPid, lastFailure, deps),
|
|
841
|
+
startupFailureReason: lastFailure.reason,
|
|
788
842
|
};
|
|
789
843
|
}
|
|
790
844
|
function hasStartupHealthMonitor(deps) {
|
|
@@ -809,14 +863,14 @@ function hasFreshCurrentBootHealthSignal(deps, bootStartedAtMs, pid) {
|
|
|
809
863
|
}
|
|
810
864
|
function formatDaemonStartupFailureMessage(pid, failure, deps) {
|
|
811
865
|
const lines = [
|
|
812
|
-
`
|
|
866
|
+
`background service started (pid ${pid ?? "unknown"}) but did not finish booting: ${failure.reason}`,
|
|
813
867
|
];
|
|
814
868
|
const recentLogLines = deps.readRecentDaemonLogLines?.(DEFAULT_DAEMON_STARTUP_LOG_LINES) ?? [];
|
|
815
869
|
if (recentLogLines.length > 0) {
|
|
816
870
|
lines.push("recent daemon logs:");
|
|
817
871
|
lines.push(...recentLogLines.map((line) => ` ${line}`));
|
|
818
872
|
}
|
|
819
|
-
lines.push("
|
|
873
|
+
lines.push("Run `ouro logs` to watch live startup logs or `ouro doctor` for a deeper diagnosis.");
|
|
820
874
|
return lines.join("\n");
|
|
821
875
|
}
|
|
822
876
|
async function waitForDaemonStartup(deps, options) {
|
|
@@ -830,13 +884,17 @@ async function waitForDaemonStartup(deps, options) {
|
|
|
830
884
|
let stableSinceMs = null;
|
|
831
885
|
let sawSocket = false;
|
|
832
886
|
if (!useHealthMonitor) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
+
};
|
|
840
898
|
}
|
|
841
899
|
while (now() < deadline) {
|
|
842
900
|
await sleep(pollIntervalMs);
|
|
@@ -844,40 +902,37 @@ async function waitForDaemonStartup(deps, options) {
|
|
|
844
902
|
if (!aliveNow) {
|
|
845
903
|
if (sawSocket) {
|
|
846
904
|
return {
|
|
847
|
-
reason:
|
|
905
|
+
reason: `${options.serviceLabel} answered once and then disappeared during startup`,
|
|
848
906
|
retryable: true,
|
|
849
907
|
};
|
|
850
908
|
}
|
|
909
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
910
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "waiting", latestEvent));
|
|
851
911
|
continue;
|
|
852
912
|
}
|
|
853
913
|
if (!sawSocket) {
|
|
854
914
|
sawSocket = true;
|
|
855
915
|
stableSinceMs = now();
|
|
856
|
-
|
|
916
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
917
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "answering", latestEvent));
|
|
857
918
|
}
|
|
858
919
|
if (!hasFreshCurrentBootHealthSignal(deps, options.bootStartedAtMs, options.pid)) {
|
|
920
|
+
const latestEvent = options.readLatestDaemonEvent?.() ?? null;
|
|
921
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "answering", latestEvent));
|
|
859
922
|
continue;
|
|
860
923
|
}
|
|
924
|
+
deps.reportDaemonStartupPhase?.(formatDaemonStartupProgressLine(options.serviceLabel, "stabilizing"));
|
|
861
925
|
if (stableSinceMs !== null && now() - stableSinceMs >= stabilityWindowMs) {
|
|
862
926
|
return null;
|
|
863
927
|
}
|
|
864
928
|
}
|
|
865
929
|
return {
|
|
866
930
|
reason: sawSocket
|
|
867
|
-
?
|
|
868
|
-
:
|
|
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`,
|
|
869
933
|
retryable: sawSocket,
|
|
870
934
|
};
|
|
871
935
|
}
|
|
872
|
-
async function verifyDaemonAlive(checkSocketAlive, socketPath, maxWaitMs = 10_000, pollIntervalMs = 500, sleep = defaultSleep, now = Date.now) {
|
|
873
|
-
const deadline = now() + maxWaitMs;
|
|
874
|
-
while (now() < deadline) {
|
|
875
|
-
await sleep(pollIntervalMs);
|
|
876
|
-
if (await checkSocketAlive(socketPath))
|
|
877
|
-
return true;
|
|
878
|
-
}
|
|
879
|
-
return false;
|
|
880
|
-
}
|
|
881
936
|
function defaultSleep(ms) {
|
|
882
937
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
883
938
|
}
|
|
@@ -4144,22 +4199,19 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4144
4199
|
if (command.noRepair) {
|
|
4145
4200
|
writeProviderRepairSummary(deps, "Provider checks need attention", preflightProviderDegraded);
|
|
4146
4201
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
4147
|
-
deps
|
|
4148
|
-
return message;
|
|
4202
|
+
return returnCliFailure(deps, message);
|
|
4149
4203
|
}
|
|
4150
4204
|
const repairResult = await runReadinessRepairForDegraded(preflightProviderDegraded, deps);
|
|
4151
4205
|
if (!repairResult.repairsAttempted) {
|
|
4152
4206
|
writeProviderRepairSummary(deps, "Provider checks still need attention", repairResult.remainingDegraded);
|
|
4153
4207
|
const message = "daemon not started: provider checks need repair. Run `ouro repair` or rerun `ouro up` to choose a repair path.";
|
|
4154
|
-
deps
|
|
4155
|
-
return message;
|
|
4208
|
+
return returnCliFailure(deps, message);
|
|
4156
4209
|
}
|
|
4157
4210
|
const remainingDegraded = repairResult.remainingDegraded;
|
|
4158
4211
|
if (remainingDegraded.length > 0) {
|
|
4159
4212
|
writeProviderRepairSummary(deps, "Still needs attention", remainingDegraded);
|
|
4160
4213
|
const message = "daemon not started: provider checks still need repair.";
|
|
4161
|
-
deps
|
|
4162
|
-
return message;
|
|
4214
|
+
return returnCliFailure(deps, message);
|
|
4163
4215
|
}
|
|
4164
4216
|
deps.writeStdout("All set. Provider checks recovered after repair.");
|
|
4165
4217
|
}
|
|
@@ -4172,12 +4224,11 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4172
4224
|
progress.announceStep?.(label);
|
|
4173
4225
|
},
|
|
4174
4226
|
}, { initialAlive: daemonAliveBeforeStart });
|
|
4175
|
-
if (daemonResult.
|
|
4227
|
+
if (!daemonResult.ok) {
|
|
4176
4228
|
;
|
|
4177
|
-
progress.
|
|
4229
|
+
progress.failPhase?.("starting daemon", summarizeDaemonStartupFailure(daemonResult));
|
|
4178
4230
|
progress.end();
|
|
4179
|
-
deps
|
|
4180
|
-
return daemonResult.message;
|
|
4231
|
+
return returnCliFailure(deps, daemonResult.message);
|
|
4181
4232
|
}
|
|
4182
4233
|
progress.completePhase("starting daemon", daemonProgressSummary(daemonResult));
|
|
4183
4234
|
if (!providerChecksAlreadyRun || daemonResult.alreadyRunning) {
|
|
@@ -4193,8 +4244,7 @@ async function runOuroCli(args, deps = (0, cli_defaults_1.createDefaultOuroCliDe
|
|
|
4193
4244
|
progress.failPhase?.("final daemon check", finalDaemonCheck.summary);
|
|
4194
4245
|
progress.end();
|
|
4195
4246
|
const message = finalDaemonCheck.message ?? "background service stopped before boot finished";
|
|
4196
|
-
deps
|
|
4197
|
-
return message;
|
|
4247
|
+
return returnCliFailure(deps, message);
|
|
4198
4248
|
}
|
|
4199
4249
|
progress.completePhase("final daemon check", finalDaemonCheck.summary);
|
|
4200
4250
|
progress.end();
|
|
@@ -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",
|