opendevbrowser 0.0.25 → 0.0.26
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/README.md +1 -1
- package/dist/{chunk-Z6ENAZUN.js → chunk-AVQL6WAS.js} +9 -2
- package/dist/chunk-AVQL6WAS.js.map +1 -0
- package/dist/{chunk-7U63PZ4W.js → chunk-GTTYIAI7.js} +369 -175
- package/dist/chunk-GTTYIAI7.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +25 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/serve.d.ts +10 -13
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/daemon-client.d.ts.map +1 -1
- package/dist/cli/daemon-status-policy.d.ts +6 -0
- package/dist/cli/daemon-status-policy.d.ts.map +1 -0
- package/dist/cli/daemon-status.d.ts +1 -0
- package/dist/cli/daemon-status.d.ts.map +1 -1
- package/dist/cli/daemon.d.ts +5 -0
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/index.js +175 -96
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/http.d.ts.map +1 -1
- package/dist/daemon-fingerprint.json +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +109 -28
- package/dist/index.js.map +1 -1
- package/dist/opendevbrowser.d.ts.map +1 -1
- package/dist/opendevbrowser.js +109 -28
- package/dist/opendevbrowser.js.map +1 -1
- package/dist/providers/inspiredesign-capture.d.ts.map +1 -1
- package/dist/providers/workflows.d.ts.map +1 -1
- package/dist/{providers-CYEJZVXB.js → providers-T2FQJCF6.js} +2 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/status.d.ts.map +1 -1
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/dist/chunk-7U63PZ4W.js.map +0 -1
- package/dist/chunk-Z6ENAZUN.js.map +0 -1
- /package/dist/{providers-CYEJZVXB.js.map → providers-T2FQJCF6.js.map} +0 -0
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
runResearchWorkflow,
|
|
48
48
|
runShoppingWorkflow,
|
|
49
49
|
toSnippet
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-AVQL6WAS.js";
|
|
51
51
|
import {
|
|
52
52
|
ProviderRuntimeError
|
|
53
53
|
} from "./chunk-FUSXMW3G.js";
|
|
@@ -35991,12 +35991,129 @@ function createOpenDevBrowserCore(options) {
|
|
|
35991
35991
|
};
|
|
35992
35992
|
}
|
|
35993
35993
|
|
|
35994
|
+
// src/cli/utils/http.ts
|
|
35995
|
+
var DEFAULT_HTTP_TIMEOUT_MS = 5e3;
|
|
35996
|
+
function isAbortError(error) {
|
|
35997
|
+
if (!error || typeof error !== "object") return false;
|
|
35998
|
+
return "name" in error && error.name === "AbortError";
|
|
35999
|
+
}
|
|
36000
|
+
var resolveTimeoutMs = (timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) => {
|
|
36001
|
+
return Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_HTTP_TIMEOUT_MS;
|
|
36002
|
+
};
|
|
36003
|
+
var createTimeoutError = (timeoutMs) => {
|
|
36004
|
+
return new Error(`Request timed out after ${timeoutMs}ms`);
|
|
36005
|
+
};
|
|
36006
|
+
var createTimedSignal = (timeoutMs, upstreamSignal) => {
|
|
36007
|
+
const controller = new AbortController();
|
|
36008
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
36009
|
+
let removeAbortListener;
|
|
36010
|
+
if (upstreamSignal) {
|
|
36011
|
+
if (upstreamSignal.aborted) {
|
|
36012
|
+
controller.abort(upstreamSignal.reason);
|
|
36013
|
+
} else {
|
|
36014
|
+
const onAbort = () => controller.abort(upstreamSignal.reason);
|
|
36015
|
+
upstreamSignal.addEventListener("abort", onAbort, { once: true });
|
|
36016
|
+
removeAbortListener = () => upstreamSignal.removeEventListener("abort", onAbort);
|
|
36017
|
+
}
|
|
36018
|
+
}
|
|
36019
|
+
return {
|
|
36020
|
+
signal: controller.signal,
|
|
36021
|
+
dispose: () => {
|
|
36022
|
+
clearTimeout(timeoutId);
|
|
36023
|
+
removeAbortListener?.();
|
|
36024
|
+
}
|
|
36025
|
+
};
|
|
36026
|
+
};
|
|
36027
|
+
var cancelResponseBody = (response) => {
|
|
36028
|
+
try {
|
|
36029
|
+
const cancelResult = response.body?.cancel?.();
|
|
36030
|
+
if (cancelResult instanceof Promise) {
|
|
36031
|
+
void cancelResult.catch(() => {
|
|
36032
|
+
});
|
|
36033
|
+
}
|
|
36034
|
+
} catch {
|
|
36035
|
+
}
|
|
36036
|
+
};
|
|
36037
|
+
var readResponseBodyWithTimeout = async (response, signal, timeoutMs, reader) => {
|
|
36038
|
+
let bodyCancelled = false;
|
|
36039
|
+
const cancelBody = () => {
|
|
36040
|
+
if (bodyCancelled) {
|
|
36041
|
+
return;
|
|
36042
|
+
}
|
|
36043
|
+
bodyCancelled = true;
|
|
36044
|
+
cancelResponseBody(response);
|
|
36045
|
+
};
|
|
36046
|
+
if (signal.aborted) {
|
|
36047
|
+
cancelBody();
|
|
36048
|
+
throw createTimeoutError(timeoutMs);
|
|
36049
|
+
}
|
|
36050
|
+
let removeAbortListener;
|
|
36051
|
+
const abortPromise = new Promise((_, reject) => {
|
|
36052
|
+
const onAbort = () => {
|
|
36053
|
+
cancelBody();
|
|
36054
|
+
reject(createTimeoutError(timeoutMs));
|
|
36055
|
+
};
|
|
36056
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
36057
|
+
removeAbortListener = () => signal.removeEventListener("abort", onAbort);
|
|
36058
|
+
});
|
|
36059
|
+
try {
|
|
36060
|
+
return await Promise.race([reader(), abortPromise]);
|
|
36061
|
+
} catch (error) {
|
|
36062
|
+
if (signal.aborted || isAbortError(error)) {
|
|
36063
|
+
cancelBody();
|
|
36064
|
+
throw createTimeoutError(timeoutMs);
|
|
36065
|
+
}
|
|
36066
|
+
throw error;
|
|
36067
|
+
} finally {
|
|
36068
|
+
removeAbortListener?.();
|
|
36069
|
+
}
|
|
36070
|
+
};
|
|
36071
|
+
async function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) {
|
|
36072
|
+
const resolvedTimeout = resolveTimeoutMs(timeoutMs);
|
|
36073
|
+
const timedSignal = createTimedSignal(resolvedTimeout, init?.signal ?? void 0);
|
|
36074
|
+
try {
|
|
36075
|
+
return await fetch(input, { ...init, signal: timedSignal.signal });
|
|
36076
|
+
} catch (error) {
|
|
36077
|
+
if (isAbortError(error) || timedSignal.signal.aborted) {
|
|
36078
|
+
throw createTimeoutError(resolvedTimeout);
|
|
36079
|
+
}
|
|
36080
|
+
throw error;
|
|
36081
|
+
} finally {
|
|
36082
|
+
timedSignal.dispose();
|
|
36083
|
+
}
|
|
36084
|
+
}
|
|
36085
|
+
async function fetchWithTimeoutContext(input, init = {}, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) {
|
|
36086
|
+
const resolvedTimeout = resolveTimeoutMs(timeoutMs);
|
|
36087
|
+
const timedSignal = createTimedSignal(resolvedTimeout, init?.signal ?? void 0);
|
|
36088
|
+
try {
|
|
36089
|
+
const response = await fetch(input, { ...init, signal: timedSignal.signal });
|
|
36090
|
+
return {
|
|
36091
|
+
response,
|
|
36092
|
+
signal: timedSignal.signal,
|
|
36093
|
+
timeoutMs: resolvedTimeout,
|
|
36094
|
+
dispose: timedSignal.dispose
|
|
36095
|
+
};
|
|
36096
|
+
} catch (error) {
|
|
36097
|
+
timedSignal.dispose();
|
|
36098
|
+
if (isAbortError(error) || timedSignal.signal.aborted) {
|
|
36099
|
+
throw createTimeoutError(resolvedTimeout);
|
|
36100
|
+
}
|
|
36101
|
+
throw error;
|
|
36102
|
+
}
|
|
36103
|
+
}
|
|
36104
|
+
async function readResponseTextWithTimeout(response, signal, timeoutMs) {
|
|
36105
|
+
return await readResponseBodyWithTimeout(response, signal, timeoutMs, () => response.text());
|
|
36106
|
+
}
|
|
36107
|
+
async function readResponseJsonWithTimeout(response, signal, timeoutMs) {
|
|
36108
|
+
return await readResponseBodyWithTimeout(response, signal, timeoutMs, () => response.json());
|
|
36109
|
+
}
|
|
36110
|
+
|
|
35994
36111
|
// src/cli/daemon.ts
|
|
35995
36112
|
import { createServer as createServer2 } from "http";
|
|
35996
36113
|
import { createHash as createHash6, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
35997
36114
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3, unlinkSync, existsSync as existsSync6 } from "fs";
|
|
35998
36115
|
import { homedir as homedir7 } from "os";
|
|
35999
|
-
import { join as join16, resolve as resolve7 } from "path";
|
|
36116
|
+
import { basename as basename2, dirname as dirname8, join as join16, resolve as resolve7 } from "path";
|
|
36000
36117
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
36001
36118
|
|
|
36002
36119
|
// src/cli/daemon-commands.ts
|
|
@@ -36247,7 +36364,14 @@ var DOM_CAPTURE_EMPTY_MESSAGE = "DOM capture returned empty HTML.";
|
|
|
36247
36364
|
var SKIPPED_AFTER_TRANSPORT_TIMEOUT_SUFFIX = "transport timeout.";
|
|
36248
36365
|
var createRemainingCaptureTimeout = (timeoutMs) => {
|
|
36249
36366
|
const startedAtMs = Date.now();
|
|
36250
|
-
|
|
36367
|
+
let firstRead = true;
|
|
36368
|
+
return () => {
|
|
36369
|
+
if (firstRead) {
|
|
36370
|
+
firstRead = false;
|
|
36371
|
+
return timeoutMs;
|
|
36372
|
+
}
|
|
36373
|
+
return Math.max(1, timeoutMs - Math.max(0, Date.now() - startedAtMs));
|
|
36374
|
+
};
|
|
36251
36375
|
};
|
|
36252
36376
|
var clampInspiredesignCaptureTimeout = (timeoutMs) => {
|
|
36253
36377
|
if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs)) return INSPIREDESIGN_CAPTURE_TIMEOUT_MS;
|
|
@@ -37172,119 +37296,6 @@ var getBindingRenewConfig = () => ({
|
|
|
37172
37296
|
waitMaxMs: WAIT_MAX_MS
|
|
37173
37297
|
});
|
|
37174
37298
|
|
|
37175
|
-
// src/cli/utils/http.ts
|
|
37176
|
-
var DEFAULT_HTTP_TIMEOUT_MS = 5e3;
|
|
37177
|
-
function isAbortError(error) {
|
|
37178
|
-
if (!error || typeof error !== "object") return false;
|
|
37179
|
-
return "name" in error && error.name === "AbortError";
|
|
37180
|
-
}
|
|
37181
|
-
var resolveTimeoutMs = (timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) => {
|
|
37182
|
-
return Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_HTTP_TIMEOUT_MS;
|
|
37183
|
-
};
|
|
37184
|
-
var createTimeoutError = (timeoutMs) => {
|
|
37185
|
-
return new Error(`Request timed out after ${timeoutMs}ms`);
|
|
37186
|
-
};
|
|
37187
|
-
var createTimedSignal = (timeoutMs, upstreamSignal) => {
|
|
37188
|
-
const controller = new AbortController();
|
|
37189
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
37190
|
-
let removeAbortListener;
|
|
37191
|
-
if (upstreamSignal) {
|
|
37192
|
-
if (upstreamSignal.aborted) {
|
|
37193
|
-
controller.abort(upstreamSignal.reason);
|
|
37194
|
-
} else {
|
|
37195
|
-
const onAbort = () => controller.abort(upstreamSignal.reason);
|
|
37196
|
-
upstreamSignal.addEventListener("abort", onAbort, { once: true });
|
|
37197
|
-
removeAbortListener = () => upstreamSignal.removeEventListener("abort", onAbort);
|
|
37198
|
-
}
|
|
37199
|
-
}
|
|
37200
|
-
return {
|
|
37201
|
-
signal: controller.signal,
|
|
37202
|
-
dispose: () => {
|
|
37203
|
-
clearTimeout(timeoutId);
|
|
37204
|
-
removeAbortListener?.();
|
|
37205
|
-
}
|
|
37206
|
-
};
|
|
37207
|
-
};
|
|
37208
|
-
var cancelResponseBody = (response) => {
|
|
37209
|
-
try {
|
|
37210
|
-
void response.body?.cancel?.();
|
|
37211
|
-
} catch {
|
|
37212
|
-
}
|
|
37213
|
-
};
|
|
37214
|
-
var readResponseBodyWithTimeout = async (response, signal, timeoutMs, reader) => {
|
|
37215
|
-
let bodyCancelled = false;
|
|
37216
|
-
const cancelBody = () => {
|
|
37217
|
-
if (bodyCancelled) {
|
|
37218
|
-
return;
|
|
37219
|
-
}
|
|
37220
|
-
bodyCancelled = true;
|
|
37221
|
-
cancelResponseBody(response);
|
|
37222
|
-
};
|
|
37223
|
-
if (signal.aborted) {
|
|
37224
|
-
cancelBody();
|
|
37225
|
-
throw createTimeoutError(timeoutMs);
|
|
37226
|
-
}
|
|
37227
|
-
let removeAbortListener;
|
|
37228
|
-
const abortPromise = new Promise((_, reject) => {
|
|
37229
|
-
const onAbort = () => {
|
|
37230
|
-
cancelBody();
|
|
37231
|
-
reject(createTimeoutError(timeoutMs));
|
|
37232
|
-
};
|
|
37233
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
37234
|
-
removeAbortListener = () => signal.removeEventListener("abort", onAbort);
|
|
37235
|
-
});
|
|
37236
|
-
try {
|
|
37237
|
-
return await Promise.race([reader(), abortPromise]);
|
|
37238
|
-
} catch (error) {
|
|
37239
|
-
if (signal.aborted || isAbortError(error)) {
|
|
37240
|
-
cancelBody();
|
|
37241
|
-
throw createTimeoutError(timeoutMs);
|
|
37242
|
-
}
|
|
37243
|
-
throw error;
|
|
37244
|
-
} finally {
|
|
37245
|
-
removeAbortListener?.();
|
|
37246
|
-
}
|
|
37247
|
-
};
|
|
37248
|
-
async function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) {
|
|
37249
|
-
const resolvedTimeout = resolveTimeoutMs(timeoutMs);
|
|
37250
|
-
const timedSignal = createTimedSignal(resolvedTimeout, init?.signal ?? void 0);
|
|
37251
|
-
try {
|
|
37252
|
-
return await fetch(input, { ...init, signal: timedSignal.signal });
|
|
37253
|
-
} catch (error) {
|
|
37254
|
-
if (isAbortError(error) || timedSignal.signal.aborted) {
|
|
37255
|
-
throw createTimeoutError(resolvedTimeout);
|
|
37256
|
-
}
|
|
37257
|
-
throw error;
|
|
37258
|
-
} finally {
|
|
37259
|
-
timedSignal.dispose();
|
|
37260
|
-
}
|
|
37261
|
-
}
|
|
37262
|
-
async function fetchWithTimeoutContext(input, init = {}, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) {
|
|
37263
|
-
const resolvedTimeout = resolveTimeoutMs(timeoutMs);
|
|
37264
|
-
const timedSignal = createTimedSignal(resolvedTimeout, init?.signal ?? void 0);
|
|
37265
|
-
try {
|
|
37266
|
-
const response = await fetch(input, { ...init, signal: timedSignal.signal });
|
|
37267
|
-
return {
|
|
37268
|
-
response,
|
|
37269
|
-
signal: timedSignal.signal,
|
|
37270
|
-
timeoutMs: resolvedTimeout,
|
|
37271
|
-
dispose: timedSignal.dispose
|
|
37272
|
-
};
|
|
37273
|
-
} catch (error) {
|
|
37274
|
-
timedSignal.dispose();
|
|
37275
|
-
if (isAbortError(error) || timedSignal.signal.aborted) {
|
|
37276
|
-
throw createTimeoutError(resolvedTimeout);
|
|
37277
|
-
}
|
|
37278
|
-
throw error;
|
|
37279
|
-
}
|
|
37280
|
-
}
|
|
37281
|
-
async function readResponseTextWithTimeout(response, signal, timeoutMs) {
|
|
37282
|
-
return await readResponseBodyWithTimeout(response, signal, timeoutMs, () => response.text());
|
|
37283
|
-
}
|
|
37284
|
-
async function readResponseJsonWithTimeout(response, signal, timeoutMs) {
|
|
37285
|
-
return await readResponseBodyWithTimeout(response, signal, timeoutMs, () => response.json());
|
|
37286
|
-
}
|
|
37287
|
-
|
|
37288
37299
|
// src/cli/daemon-commands.ts
|
|
37289
37300
|
var createDaemonWorkflowRuntime = (core, options) => resolveBundledProviderRuntime({
|
|
37290
37301
|
existingRuntime: core.providerRuntime,
|
|
@@ -39020,6 +39031,11 @@ async function resolveMacroExpression(options, config, manager, browserFallbackP
|
|
|
39020
39031
|
|
|
39021
39032
|
// src/cli/daemon.ts
|
|
39022
39033
|
var DEFAULT_DAEMON_PORT2 = 8788;
|
|
39034
|
+
var DAEMON_STOP_DEBUG_ENV = "OPDEVBROWSER_DEBUG_DAEMON_STOP";
|
|
39035
|
+
var DAEMON_FINGERPRINT_FILE = "daemon-fingerprint.json";
|
|
39036
|
+
var DAEMON_STOP_REASON_HEADER = "x-opendevbrowser-stop-reason";
|
|
39037
|
+
var DAEMON_STOP_CLIENT_PID_HEADER = "x-opendevbrowser-stop-client-pid";
|
|
39038
|
+
var DAEMON_STOP_FINGERPRINT_HEADER = "x-opendevbrowser-stop-fingerprint";
|
|
39023
39039
|
var RECOVERABLE_PLAYWRIGHT_TRANSPORT_ERRORS = [
|
|
39024
39040
|
"Cannot find context with specified id",
|
|
39025
39041
|
"Detached while handling command."
|
|
@@ -39076,23 +39092,58 @@ function hashFileContents(entryPath) {
|
|
|
39076
39092
|
return "missing";
|
|
39077
39093
|
}
|
|
39078
39094
|
}
|
|
39095
|
+
function resolveDaemonFingerprintDistRoot(modulePath) {
|
|
39096
|
+
let currentDir = dirname8(modulePath);
|
|
39097
|
+
while (true) {
|
|
39098
|
+
if (basename2(currentDir) === "dist") {
|
|
39099
|
+
return currentDir;
|
|
39100
|
+
}
|
|
39101
|
+
const parentDir = dirname8(currentDir);
|
|
39102
|
+
if (parentDir === currentDir) {
|
|
39103
|
+
break;
|
|
39104
|
+
}
|
|
39105
|
+
currentDir = parentDir;
|
|
39106
|
+
}
|
|
39107
|
+
return null;
|
|
39108
|
+
}
|
|
39109
|
+
function readDaemonFingerprintArtifact(modulePath) {
|
|
39110
|
+
const distRoot = resolveDaemonFingerprintDistRoot(modulePath);
|
|
39111
|
+
if (distRoot === null) {
|
|
39112
|
+
return null;
|
|
39113
|
+
}
|
|
39114
|
+
try {
|
|
39115
|
+
const content = readFileSync5(join16(distRoot, DAEMON_FINGERPRINT_FILE), "utf-8");
|
|
39116
|
+
const payload = JSON.parse(content);
|
|
39117
|
+
if (typeof payload.fingerprint === "string" && payload.fingerprint.trim().length > 0) {
|
|
39118
|
+
return payload.fingerprint.trim();
|
|
39119
|
+
}
|
|
39120
|
+
} catch {
|
|
39121
|
+
}
|
|
39122
|
+
return null;
|
|
39123
|
+
}
|
|
39079
39124
|
function getCurrentDaemonFingerprint(options = {}) {
|
|
39080
|
-
const entryPath = resolveCurrentDaemonEntrypointPath(options);
|
|
39081
39125
|
const modulePath = resolve7(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
39126
|
+
const sharedFingerprint = readDaemonFingerprintArtifact(modulePath);
|
|
39082
39127
|
const fingerprintParts = [
|
|
39083
39128
|
DAEMON_FINGERPRINT_VERSION,
|
|
39084
|
-
|
|
39085
|
-
entryPath,
|
|
39086
|
-
hashFileContents(entryPath)
|
|
39129
|
+
sharedFingerprint ?? hashFileContents(modulePath)
|
|
39087
39130
|
];
|
|
39088
|
-
if (modulePath !== entryPath) {
|
|
39089
|
-
fingerprintParts.push(modulePath, hashFileContents(modulePath));
|
|
39090
|
-
}
|
|
39091
39131
|
return createHash6("sha256").update(fingerprintParts.join("\n")).digest("hex");
|
|
39092
39132
|
}
|
|
39093
39133
|
function isCurrentDaemonFingerprint(fingerprint) {
|
|
39094
39134
|
return typeof fingerprint === "string" && fingerprint === getCurrentDaemonFingerprint();
|
|
39095
39135
|
}
|
|
39136
|
+
function createDaemonStopHeaders(token, reason) {
|
|
39137
|
+
const headers = {
|
|
39138
|
+
Authorization: `Bearer ${token}`,
|
|
39139
|
+
[DAEMON_STOP_FINGERPRINT_HEADER]: getCurrentDaemonFingerprint(),
|
|
39140
|
+
[DAEMON_STOP_REASON_HEADER]: reason
|
|
39141
|
+
};
|
|
39142
|
+
if (process.env[DAEMON_STOP_DEBUG_ENV] === "1") {
|
|
39143
|
+
headers[DAEMON_STOP_CLIENT_PID_HEADER] = String(process.pid);
|
|
39144
|
+
}
|
|
39145
|
+
return headers;
|
|
39146
|
+
}
|
|
39096
39147
|
function resolveDaemonFingerprint(...candidates) {
|
|
39097
39148
|
for (const candidate of candidates) {
|
|
39098
39149
|
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
@@ -39134,6 +39185,20 @@ function sendJson(response, status, payload) {
|
|
|
39134
39185
|
});
|
|
39135
39186
|
response.end(JSON.stringify(payload));
|
|
39136
39187
|
}
|
|
39188
|
+
function logDaemonStopDebug(message, details) {
|
|
39189
|
+
if (process.env[DAEMON_STOP_DEBUG_ENV] !== "1") {
|
|
39190
|
+
return;
|
|
39191
|
+
}
|
|
39192
|
+
const suffix = details ? ` ${JSON.stringify(details)}` : "";
|
|
39193
|
+
console.error(`[daemon-stop-debug] ${message}${suffix}`);
|
|
39194
|
+
}
|
|
39195
|
+
function readSingleHeader(request, name) {
|
|
39196
|
+
const value = request.headers[name];
|
|
39197
|
+
if (typeof value === "string") {
|
|
39198
|
+
return value;
|
|
39199
|
+
}
|
|
39200
|
+
return null;
|
|
39201
|
+
}
|
|
39137
39202
|
var isDaemonCommandRequest = (value) => {
|
|
39138
39203
|
if (typeof value.name !== "string") {
|
|
39139
39204
|
return false;
|
|
@@ -39185,8 +39250,20 @@ async function startDaemon(options = {}) {
|
|
|
39185
39250
|
return;
|
|
39186
39251
|
}
|
|
39187
39252
|
if (request.method === "POST" && url.pathname === "/stop") {
|
|
39253
|
+
const stopFingerprint = readSingleHeader(request, DAEMON_STOP_FINGERPRINT_HEADER);
|
|
39254
|
+
logDaemonStopDebug("http.stop", {
|
|
39255
|
+
remoteAddress: request.socket.remoteAddress ?? null,
|
|
39256
|
+
remotePort: request.socket.remotePort ?? null,
|
|
39257
|
+
reason: readSingleHeader(request, DAEMON_STOP_REASON_HEADER),
|
|
39258
|
+
clientPid: readSingleHeader(request, DAEMON_STOP_CLIENT_PID_HEADER),
|
|
39259
|
+
fingerprintMatches: stopFingerprint === fingerprint
|
|
39260
|
+
});
|
|
39261
|
+
if (stopFingerprint !== fingerprint) {
|
|
39262
|
+
sendJson(response, 409, { ok: false, error: "Stale daemon stop request." });
|
|
39263
|
+
return;
|
|
39264
|
+
}
|
|
39188
39265
|
sendJson(response, 200, { ok: true });
|
|
39189
|
-
await stop();
|
|
39266
|
+
await stop("http.stop");
|
|
39190
39267
|
return;
|
|
39191
39268
|
}
|
|
39192
39269
|
if (request.method === "POST" && url.pathname === "/command") {
|
|
@@ -39240,7 +39317,7 @@ async function startDaemon(options = {}) {
|
|
|
39240
39317
|
return;
|
|
39241
39318
|
}
|
|
39242
39319
|
console.error(error);
|
|
39243
|
-
void stop().finally(() => {
|
|
39320
|
+
void stop("uncaughtException").finally(() => {
|
|
39244
39321
|
process.exitCode = 1;
|
|
39245
39322
|
});
|
|
39246
39323
|
};
|
|
@@ -39249,15 +39326,16 @@ async function startDaemon(options = {}) {
|
|
|
39249
39326
|
return;
|
|
39250
39327
|
}
|
|
39251
39328
|
console.error(reason);
|
|
39252
|
-
void stop().finally(() => {
|
|
39329
|
+
void stop("unhandledRejection").finally(() => {
|
|
39253
39330
|
process.exitCode = 1;
|
|
39254
39331
|
});
|
|
39255
39332
|
};
|
|
39256
|
-
const stop = async () => {
|
|
39333
|
+
const stop = async (reason = "unknown") => {
|
|
39257
39334
|
if (stopping) {
|
|
39258
39335
|
return;
|
|
39259
39336
|
}
|
|
39260
39337
|
stopping = true;
|
|
39338
|
+
logDaemonStopDebug("stop.begin", { reason });
|
|
39261
39339
|
clearDaemonMetadata();
|
|
39262
39340
|
clearBinding();
|
|
39263
39341
|
process.off("SIGINT", sigintHandler);
|
|
@@ -39268,13 +39346,14 @@ async function startDaemon(options = {}) {
|
|
|
39268
39346
|
await new Promise((resolve9) => {
|
|
39269
39347
|
server.close(() => resolve9());
|
|
39270
39348
|
});
|
|
39349
|
+
logDaemonStopDebug("stop.complete", { reason });
|
|
39271
39350
|
};
|
|
39272
39351
|
const sigintHandler = () => {
|
|
39273
|
-
stop().catch(() => {
|
|
39352
|
+
void stop("SIGINT").catch(() => {
|
|
39274
39353
|
});
|
|
39275
39354
|
};
|
|
39276
39355
|
const sigtermHandler = () => {
|
|
39277
|
-
stop().catch(() => {
|
|
39356
|
+
void stop("SIGTERM").catch(() => {
|
|
39278
39357
|
});
|
|
39279
39358
|
};
|
|
39280
39359
|
process.on("SIGINT", sigintHandler);
|
|
@@ -39348,7 +39427,15 @@ function resolveExitCode(result) {
|
|
|
39348
39427
|
return result.success ? EXIT_SUCCESS : EXIT_EXECUTION;
|
|
39349
39428
|
}
|
|
39350
39429
|
|
|
39430
|
+
// src/cli/daemon-status-policy.ts
|
|
39431
|
+
var DEFAULT_DAEMON_STATUS_FETCH_OPTIONS = {
|
|
39432
|
+
timeoutMs: 5e3,
|
|
39433
|
+
retryAttempts: 5,
|
|
39434
|
+
retryDelayMs: 250
|
|
39435
|
+
};
|
|
39436
|
+
|
|
39351
39437
|
// src/cli/daemon-status.ts
|
|
39438
|
+
var DEFAULT_DAEMON_STATUS_TIMEOUT_MS = DEFAULT_DAEMON_STATUS_FETCH_OPTIONS.timeoutMs;
|
|
39352
39439
|
var sleep2 = async (delayMs) => {
|
|
39353
39440
|
if (!(Number.isFinite(delayMs) && delayMs > 0)) {
|
|
39354
39441
|
return;
|
|
@@ -39361,17 +39448,66 @@ var resolveRetryAttempts = (retryAttempts) => {
|
|
|
39361
39448
|
var resolveRetryDelayMs = (retryDelayMs) => {
|
|
39362
39449
|
return typeof retryDelayMs === "number" && Number.isFinite(retryDelayMs) && retryDelayMs > 0 ? retryDelayMs : 0;
|
|
39363
39450
|
};
|
|
39451
|
+
var resolveStatusTimeoutMs = (timeoutMs) => {
|
|
39452
|
+
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_DAEMON_STATUS_TIMEOUT_MS;
|
|
39453
|
+
};
|
|
39454
|
+
var withFingerprintCurrent = (status) => ({
|
|
39455
|
+
...status,
|
|
39456
|
+
fingerprintCurrent: isCurrentDaemonFingerprint(status.fingerprint)
|
|
39457
|
+
});
|
|
39458
|
+
var readRemainingBudgetMs = (deadlineMs) => {
|
|
39459
|
+
return Math.max(0, deadlineMs - Date.now());
|
|
39460
|
+
};
|
|
39461
|
+
var readSeedTimeoutMs = (remainingBudgetMs, remainingSeedCount) => {
|
|
39462
|
+
if (remainingSeedCount <= 1) {
|
|
39463
|
+
return remainingBudgetMs;
|
|
39464
|
+
}
|
|
39465
|
+
return Math.max(1, Math.floor(remainingBudgetMs / remainingSeedCount));
|
|
39466
|
+
};
|
|
39467
|
+
var resolveDaemonStatusSeeds = (metadata, config) => {
|
|
39468
|
+
const seeds = [];
|
|
39469
|
+
const seen = /* @__PURE__ */ new Set();
|
|
39470
|
+
const addSeed = (seed) => {
|
|
39471
|
+
if (!seed) {
|
|
39472
|
+
return;
|
|
39473
|
+
}
|
|
39474
|
+
const key = `${seed.port}:${seed.token}`;
|
|
39475
|
+
if (seen.has(key)) {
|
|
39476
|
+
return;
|
|
39477
|
+
}
|
|
39478
|
+
seen.add(key);
|
|
39479
|
+
seeds.push(seed);
|
|
39480
|
+
};
|
|
39481
|
+
addSeed(
|
|
39482
|
+
config.daemonPort > 0 && config.daemonToken ? {
|
|
39483
|
+
port: config.daemonPort,
|
|
39484
|
+
token: config.daemonToken,
|
|
39485
|
+
relayPort: config.relayPort
|
|
39486
|
+
} : null
|
|
39487
|
+
);
|
|
39488
|
+
addSeed(metadata);
|
|
39489
|
+
return seeds;
|
|
39490
|
+
};
|
|
39364
39491
|
async function fetchDaemonStatus(port, token, options = {}) {
|
|
39365
39492
|
const attempts = resolveRetryAttempts(options.retryAttempts);
|
|
39366
39493
|
const retryDelayMs = resolveRetryDelayMs(options.retryDelayMs);
|
|
39367
39494
|
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
39368
39495
|
try {
|
|
39369
|
-
const
|
|
39496
|
+
const timedResponse = await fetchWithTimeoutContext(`http://127.0.0.1:${port}/status`, {
|
|
39370
39497
|
method: "GET",
|
|
39371
39498
|
headers: { Authorization: `Bearer ${token}` }
|
|
39372
39499
|
}, options.timeoutMs);
|
|
39373
|
-
|
|
39374
|
-
|
|
39500
|
+
try {
|
|
39501
|
+
if (timedResponse.response.ok) {
|
|
39502
|
+
const status = await readResponseJsonWithTimeout(
|
|
39503
|
+
timedResponse.response,
|
|
39504
|
+
timedResponse.signal,
|
|
39505
|
+
timedResponse.timeoutMs
|
|
39506
|
+
);
|
|
39507
|
+
return withFingerprintCurrent(status);
|
|
39508
|
+
}
|
|
39509
|
+
} finally {
|
|
39510
|
+
timedResponse.dispose();
|
|
39375
39511
|
}
|
|
39376
39512
|
} catch {
|
|
39377
39513
|
}
|
|
@@ -39385,32 +39521,34 @@ async function fetchDaemonStatusFromMetadata(config, options = {}) {
|
|
|
39385
39521
|
const resolvedConfig = config ?? loadGlobalConfig();
|
|
39386
39522
|
const attempts = resolveRetryAttempts(options.retryAttempts);
|
|
39387
39523
|
const retryDelayMs = resolveRetryDelayMs(options.retryDelayMs);
|
|
39524
|
+
const deadlineMs = Date.now() + resolveStatusTimeoutMs(options.timeoutMs);
|
|
39388
39525
|
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
39389
39526
|
const metadata = readDaemonMetadata();
|
|
39390
|
-
|
|
39391
|
-
|
|
39392
|
-
|
|
39393
|
-
|
|
39394
|
-
|
|
39527
|
+
const seeds = resolveDaemonStatusSeeds(metadata, resolvedConfig);
|
|
39528
|
+
for (let seedIndex = 0; seedIndex < seeds.length; seedIndex += 1) {
|
|
39529
|
+
const seed = seeds[seedIndex];
|
|
39530
|
+
if (!seed) {
|
|
39531
|
+
continue;
|
|
39395
39532
|
}
|
|
39396
|
-
|
|
39397
|
-
|
|
39398
|
-
|
|
39399
|
-
|
|
39533
|
+
const remainingBudgetMs = readRemainingBudgetMs(deadlineMs);
|
|
39534
|
+
if (remainingBudgetMs <= 0) {
|
|
39535
|
+
return null;
|
|
39536
|
+
}
|
|
39537
|
+
const timeoutMs = readSeedTimeoutMs(remainingBudgetMs, seeds.length - seedIndex);
|
|
39538
|
+
const status = await fetchDaemonStatus(seed.port, seed.token, {
|
|
39539
|
+
timeoutMs
|
|
39400
39540
|
});
|
|
39401
39541
|
if (status?.ok) {
|
|
39402
|
-
persistDaemonStatusMetadata(
|
|
39403
|
-
port: resolvedConfig.daemonPort,
|
|
39404
|
-
token: resolvedConfig.daemonToken,
|
|
39405
|
-
pid: status.pid,
|
|
39406
|
-
relayPort: status.relay.port ?? resolvedConfig.relayPort,
|
|
39407
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39408
|
-
}, status, resolvedConfig);
|
|
39542
|
+
persistDaemonStatusMetadata(seed, status, resolvedConfig);
|
|
39409
39543
|
return status;
|
|
39410
39544
|
}
|
|
39411
39545
|
}
|
|
39412
39546
|
if (attempt < attempts) {
|
|
39413
|
-
|
|
39547
|
+
const remainingBudgetMs = readRemainingBudgetMs(deadlineMs);
|
|
39548
|
+
if (remainingBudgetMs <= 0) {
|
|
39549
|
+
break;
|
|
39550
|
+
}
|
|
39551
|
+
await sleep2(Math.min(retryDelayMs, remainingBudgetMs));
|
|
39414
39552
|
}
|
|
39415
39553
|
}
|
|
39416
39554
|
return null;
|
|
@@ -39456,6 +39594,13 @@ var DAEMON_RECOVERY_READY_TIMEOUT_MS = 5e3;
|
|
|
39456
39594
|
var DAEMON_RESTART_READY_TIMEOUT_MS = 15e3;
|
|
39457
39595
|
var DAEMON_RESTART_POLL_DELAY_MS = 250;
|
|
39458
39596
|
var cachedClientState;
|
|
39597
|
+
var logDaemonStopDebug2 = (message, details) => {
|
|
39598
|
+
if (process.env[DAEMON_STOP_DEBUG_ENV] !== "1") {
|
|
39599
|
+
return;
|
|
39600
|
+
}
|
|
39601
|
+
const suffix = details ? ` ${JSON.stringify(details)}` : "";
|
|
39602
|
+
console.error(`[daemon-stop-debug] ${message}${suffix}`);
|
|
39603
|
+
};
|
|
39459
39604
|
var getClientStateFilePath = () => {
|
|
39460
39605
|
const cacheRoot = getCacheRoot();
|
|
39461
39606
|
return join17(cacheRoot, CLIENT_ID_FILE);
|
|
@@ -39579,7 +39724,7 @@ var DaemonClient = class {
|
|
|
39579
39724
|
this.maybeTrackLease(name, params2, result);
|
|
39580
39725
|
return result;
|
|
39581
39726
|
}
|
|
39582
|
-
if (
|
|
39727
|
+
if (isBindingRequiredError(error)) {
|
|
39583
39728
|
if (this.binding) {
|
|
39584
39729
|
this.clearBinding();
|
|
39585
39730
|
}
|
|
@@ -39703,7 +39848,9 @@ var DaemonClient = class {
|
|
|
39703
39848
|
}
|
|
39704
39849
|
async callRaw(name, params2, timeoutMs) {
|
|
39705
39850
|
const budget = createTimeoutBudget(timeoutMs);
|
|
39706
|
-
const connection = await resolveDaemonConnection(budget
|
|
39851
|
+
const connection = await resolveDaemonConnection(budget, {
|
|
39852
|
+
preferConfiguredRecovery: requiresConfiguredRecovery(name)
|
|
39853
|
+
});
|
|
39707
39854
|
let timedResponse;
|
|
39708
39855
|
try {
|
|
39709
39856
|
timedResponse = await openDaemonCommand(
|
|
@@ -39711,7 +39858,7 @@ var DaemonClient = class {
|
|
|
39711
39858
|
connection.token,
|
|
39712
39859
|
name,
|
|
39713
39860
|
params2,
|
|
39714
|
-
|
|
39861
|
+
readRemainingBudgetMs2(budget)
|
|
39715
39862
|
);
|
|
39716
39863
|
} catch (error) {
|
|
39717
39864
|
if (isTransportTimeoutError2(error)) {
|
|
@@ -39756,7 +39903,7 @@ var createTimeoutBudget = (timeoutMs) => {
|
|
|
39756
39903
|
const resolved = asPositiveNumber(timeoutMs);
|
|
39757
39904
|
return resolved === void 0 ? null : { timeoutMs: resolved, deadlineMs: Date.now() + resolved };
|
|
39758
39905
|
};
|
|
39759
|
-
var
|
|
39906
|
+
var readRemainingBudgetMs2 = (budget) => {
|
|
39760
39907
|
if (!budget) {
|
|
39761
39908
|
return void 0;
|
|
39762
39909
|
}
|
|
@@ -39767,7 +39914,7 @@ var readRemainingBudgetMs = (budget) => {
|
|
|
39767
39914
|
return remainingMs;
|
|
39768
39915
|
};
|
|
39769
39916
|
var capTimeoutToBudget = (timeoutMs, budget) => {
|
|
39770
|
-
const remainingMs =
|
|
39917
|
+
const remainingMs = readRemainingBudgetMs2(budget);
|
|
39771
39918
|
return remainingMs === void 0 ? timeoutMs : Math.max(1, Math.min(timeoutMs, remainingMs));
|
|
39772
39919
|
};
|
|
39773
39920
|
var resolveReadyDeadlineMs = (readyTimeoutMs, budget) => {
|
|
@@ -39864,7 +40011,7 @@ var fetchCurrentDaemonStatus = async (connection, options, budget = null) => {
|
|
|
39864
40011
|
return status;
|
|
39865
40012
|
}
|
|
39866
40013
|
if (attempt < attempts) {
|
|
39867
|
-
await sleep3(Math.min(retryDelayMs,
|
|
40014
|
+
await sleep3(Math.min(retryDelayMs, readRemainingBudgetMs2(budget) ?? retryDelayMs));
|
|
39868
40015
|
}
|
|
39869
40016
|
}
|
|
39870
40017
|
return null;
|
|
@@ -39880,7 +40027,7 @@ var fetchAnyDaemonStatus = async (connection, options, budget = null) => {
|
|
|
39880
40027
|
return status;
|
|
39881
40028
|
}
|
|
39882
40029
|
if (attempt < attempts) {
|
|
39883
|
-
await sleep3(Math.min(retryDelayMs,
|
|
40030
|
+
await sleep3(Math.min(retryDelayMs, readRemainingBudgetMs2(budget) ?? retryDelayMs));
|
|
39884
40031
|
}
|
|
39885
40032
|
}
|
|
39886
40033
|
return null;
|
|
@@ -39891,6 +40038,9 @@ var sleep3 = async (delayMs) => {
|
|
|
39891
40038
|
}
|
|
39892
40039
|
await new Promise((resolve9) => setTimeout(resolve9, delayMs));
|
|
39893
40040
|
};
|
|
40041
|
+
var requiresConfiguredRecovery = (name) => {
|
|
40042
|
+
return name === "canvas.execute";
|
|
40043
|
+
};
|
|
39894
40044
|
var getConfiguredDaemonConnection = () => {
|
|
39895
40045
|
const config = loadGlobalConfig();
|
|
39896
40046
|
if (!(config.daemonPort > 0 && config.daemonToken)) {
|
|
@@ -39912,7 +40062,7 @@ var persistResolvedDaemonStatus = (connection, status) => {
|
|
|
39912
40062
|
};
|
|
39913
40063
|
var persistCurrentConfiguredConnection = async (configuredConnection, status, staleMetadata) => {
|
|
39914
40064
|
if (staleMetadata && !sameDaemonConnection(staleMetadata.connection, configuredConnection)) {
|
|
39915
|
-
void stopDaemonConnection(staleMetadata.connection).catch(() => void 0);
|
|
40065
|
+
void stopDaemonConnection(staleMetadata.connection, null, "persistCurrentConfiguredConnection.staleMetadata").catch(() => void 0);
|
|
39916
40066
|
}
|
|
39917
40067
|
persistResolvedDaemonStatus(configuredConnection, status);
|
|
39918
40068
|
return configuredConnection;
|
|
@@ -39921,7 +40071,7 @@ var resolveConfiguredPreferenceOptions = (budget) => {
|
|
|
39921
40071
|
if (!budget) {
|
|
39922
40072
|
return DAEMON_CONFIG_PREFER_OPTIONS;
|
|
39923
40073
|
}
|
|
39924
|
-
const remainingMs =
|
|
40074
|
+
const remainingMs = readRemainingBudgetMs2(budget);
|
|
39925
40075
|
if (remainingMs === void 0 || remainingMs <= 1) {
|
|
39926
40076
|
return null;
|
|
39927
40077
|
}
|
|
@@ -39943,14 +40093,27 @@ var resolveConfiguredPreferenceOptions = (budget) => {
|
|
|
39943
40093
|
retryDelayMs: retryAttempts > 1 ? retryDelayMs : 0
|
|
39944
40094
|
};
|
|
39945
40095
|
};
|
|
39946
|
-
var stopDaemonConnection = async (connection, budget = null) => {
|
|
40096
|
+
var stopDaemonConnection = async (connection, budget = null, reason = "unknown") => {
|
|
39947
40097
|
const stopTimeoutMs = capTimeoutToBudget(DAEMON_RESTART_STATUS_TIMEOUT_MS, budget);
|
|
40098
|
+
logDaemonStopDebug2("client.stop.request", { reason, port: connection.port });
|
|
39948
40099
|
try {
|
|
39949
|
-
await fetchWithTimeout(`http://127.0.0.1:${connection.port}/stop`, {
|
|
40100
|
+
const response = await fetchWithTimeout(`http://127.0.0.1:${connection.port}/stop`, {
|
|
39950
40101
|
method: "POST",
|
|
39951
|
-
headers:
|
|
40102
|
+
headers: createDaemonStopHeaders(connection.token, reason)
|
|
39952
40103
|
}, stopTimeoutMs);
|
|
40104
|
+
if (response.status === 409) {
|
|
40105
|
+
logDaemonStopDebug2("client.stop.fingerprintRejected", { reason, port: connection.port });
|
|
40106
|
+
return "fingerprint_rejected";
|
|
40107
|
+
}
|
|
40108
|
+
if (!response.ok) {
|
|
40109
|
+
logDaemonStopDebug2("client.stop.rejected", { reason, port: connection.port, status: response.status });
|
|
40110
|
+
return "unreachable";
|
|
40111
|
+
}
|
|
40112
|
+
logDaemonStopDebug2("client.stop.complete", { reason, port: connection.port });
|
|
40113
|
+
return "stopped";
|
|
39953
40114
|
} catch {
|
|
40115
|
+
logDaemonStopDebug2("client.stop.error", { reason, port: connection.port });
|
|
40116
|
+
return "unreachable";
|
|
39954
40117
|
}
|
|
39955
40118
|
};
|
|
39956
40119
|
function resolveDaemonRestartCommand(options = {}) {
|
|
@@ -40056,7 +40219,7 @@ var resolveMetadataConnection = async (metadataConnection, configuredConnection,
|
|
|
40056
40219
|
}
|
|
40057
40220
|
return { connection: metadataConnection, status };
|
|
40058
40221
|
};
|
|
40059
|
-
var resolveFreshDaemonConnection = async (budget = null) => {
|
|
40222
|
+
var resolveFreshDaemonConnection = async (budget = null, options = {}) => {
|
|
40060
40223
|
const configuredConnection = getConfiguredDaemonConnection();
|
|
40061
40224
|
if (!configuredConnection) {
|
|
40062
40225
|
throw createDisconnectedError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
@@ -40069,9 +40232,22 @@ var resolveFreshDaemonConnection = async (budget = null) => {
|
|
|
40069
40232
|
if (currentConfiguredStatus?.ok) {
|
|
40070
40233
|
return await persistCurrentConfiguredConnection(configuredConnection, currentConfiguredStatus, staleMetadata);
|
|
40071
40234
|
}
|
|
40072
|
-
if (
|
|
40235
|
+
if (options.preferConfiguredRecovery && staleMetadata) {
|
|
40236
|
+
currentConfiguredStatus = await waitForCurrentDaemonStatus(
|
|
40237
|
+
configuredConnection,
|
|
40238
|
+
DAEMON_RECOVERY_READY_TIMEOUT_MS,
|
|
40239
|
+
budget
|
|
40240
|
+
);
|
|
40241
|
+
if (currentConfiguredStatus?.ok) {
|
|
40242
|
+
return await persistCurrentConfiguredConnection(configuredConnection, currentConfiguredStatus, staleMetadata);
|
|
40243
|
+
}
|
|
40244
|
+
if (!configuredStatus?.ok) {
|
|
40245
|
+
throw createDisconnectedError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
40246
|
+
}
|
|
40247
|
+
}
|
|
40248
|
+
if (!options.preferConfiguredRecovery && staleMetadata?.status.ok && isCurrentDaemonFingerprint(staleMetadata.status.fingerprint)) {
|
|
40073
40249
|
if (configuredStatus?.ok) {
|
|
40074
|
-
void stopDaemonConnection(configuredConnection, budget).catch(() => void 0);
|
|
40250
|
+
void stopDaemonConnection(configuredConnection, budget, "resolveFreshDaemonConnection.configuredCurrentMetadataPreferred").catch(() => void 0);
|
|
40075
40251
|
}
|
|
40076
40252
|
return staleMetadata.connection;
|
|
40077
40253
|
}
|
|
@@ -40084,13 +40260,11 @@ var resolveFreshDaemonConnection = async (budget = null) => {
|
|
|
40084
40260
|
if (currentConfiguredStatus?.ok) {
|
|
40085
40261
|
return await persistCurrentConfiguredConnection(configuredConnection, currentConfiguredStatus, staleMetadata);
|
|
40086
40262
|
}
|
|
40263
|
+
throw createDisconnectedError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
40087
40264
|
}
|
|
40088
40265
|
const staleConnections = [];
|
|
40089
40266
|
if (configuredStatus?.ok) {
|
|
40090
|
-
staleConnections.push(configuredConnection);
|
|
40091
|
-
}
|
|
40092
|
-
if (staleMetadata && !sameDaemonConnection(staleMetadata.connection, configuredConnection)) {
|
|
40093
|
-
staleConnections.push(staleMetadata.connection);
|
|
40267
|
+
staleConnections.push({ connection: configuredConnection, status: configuredStatus });
|
|
40094
40268
|
}
|
|
40095
40269
|
if (staleConnections.length === 0) {
|
|
40096
40270
|
const recoveringStatus = await waitForCurrentDaemonStatus(
|
|
@@ -40105,7 +40279,16 @@ var resolveFreshDaemonConnection = async (budget = null) => {
|
|
|
40105
40279
|
throw createDisconnectedError("Daemon not running. Start with `opendevbrowser serve`.");
|
|
40106
40280
|
}
|
|
40107
40281
|
for (const staleConnection of staleConnections) {
|
|
40108
|
-
await stopDaemonConnection(
|
|
40282
|
+
const stopOutcome = await stopDaemonConnection(
|
|
40283
|
+
staleConnection.connection,
|
|
40284
|
+
budget,
|
|
40285
|
+
"resolveFreshDaemonConnection.staleConnections"
|
|
40286
|
+
);
|
|
40287
|
+
if (stopOutcome === "fingerprint_rejected") {
|
|
40288
|
+
throw createDisconnectedError(
|
|
40289
|
+
`Daemon on 127.0.0.1:${staleConnection.connection.port} pid=${staleConnection.status.pid} is protected by a different opendevbrowser build. Start with \`opendevbrowser serve\`.`
|
|
40290
|
+
);
|
|
40291
|
+
}
|
|
40109
40292
|
}
|
|
40110
40293
|
if (configuredStatus?.ok) {
|
|
40111
40294
|
const shutdownOutcome = await waitForDaemonShutdown(configuredConnection, DAEMON_RECOVERY_READY_TIMEOUT_MS, budget);
|
|
@@ -40125,7 +40308,7 @@ var resolveFreshDaemonConnection = async (budget = null) => {
|
|
|
40125
40308
|
persistResolvedDaemonStatus(configuredConnection, refreshedStatus);
|
|
40126
40309
|
return configuredConnection;
|
|
40127
40310
|
};
|
|
40128
|
-
var resolveDaemonConnection = async (budget = null) => {
|
|
40311
|
+
var resolveDaemonConnection = async (budget = null, options = {}) => {
|
|
40129
40312
|
const metadata = readDaemonMetadata();
|
|
40130
40313
|
if (metadata && isCurrentDaemonFingerprint(metadata.fingerprint)) {
|
|
40131
40314
|
const metadataConnection = { port: metadata.port, token: metadata.token };
|
|
@@ -40135,6 +40318,9 @@ var resolveDaemonConnection = async (budget = null) => {
|
|
|
40135
40318
|
}
|
|
40136
40319
|
const configuredOptions = resolveConfiguredPreferenceOptions(budget);
|
|
40137
40320
|
if (!configuredOptions) {
|
|
40321
|
+
if (options.preferConfiguredRecovery) {
|
|
40322
|
+
return await resolveFreshDaemonConnection(budget, options);
|
|
40323
|
+
}
|
|
40138
40324
|
return metadataConnection;
|
|
40139
40325
|
}
|
|
40140
40326
|
const configuredStatus = await fetchCurrentDaemonStatus(configuredConnection, configuredOptions, budget);
|
|
@@ -40145,13 +40331,18 @@ var resolveDaemonConnection = async (budget = null) => {
|
|
|
40145
40331
|
{ connection: metadataConnection }
|
|
40146
40332
|
);
|
|
40147
40333
|
}
|
|
40334
|
+
if (options.preferConfiguredRecovery) {
|
|
40335
|
+
return await resolveFreshDaemonConnection(budget, options);
|
|
40336
|
+
}
|
|
40148
40337
|
return metadataConnection;
|
|
40149
40338
|
}
|
|
40150
|
-
return await resolveFreshDaemonConnection(budget);
|
|
40339
|
+
return await resolveFreshDaemonConnection(budget, options);
|
|
40151
40340
|
};
|
|
40152
40341
|
var retryWithRefreshedConnection = async (name, params2, budget) => {
|
|
40153
|
-
const connection = await resolveFreshDaemonConnection(budget
|
|
40154
|
-
|
|
40342
|
+
const connection = await resolveFreshDaemonConnection(budget, {
|
|
40343
|
+
preferConfiguredRecovery: requiresConfiguredRecovery(name)
|
|
40344
|
+
});
|
|
40345
|
+
return await openDaemonCommand(connection.port, connection.token, name, params2, readRemainingBudgetMs2(budget));
|
|
40155
40346
|
};
|
|
40156
40347
|
var openDaemonCommand = async (port, token, name, params2, timeoutMs) => {
|
|
40157
40348
|
return await fetchWithTimeoutContext(`http://127.0.0.1:${port}/command`, {
|
|
@@ -43320,15 +43511,18 @@ export {
|
|
|
43320
43511
|
executeMacroWithRuntime,
|
|
43321
43512
|
fetchWithTimeout,
|
|
43322
43513
|
readDaemonMetadata,
|
|
43323
|
-
|
|
43514
|
+
isCurrentDaemonFingerprint,
|
|
43515
|
+
createDaemonStopHeaders,
|
|
43324
43516
|
startDaemon,
|
|
43325
43517
|
EXIT_USAGE,
|
|
43326
43518
|
EXIT_EXECUTION,
|
|
43327
43519
|
EXIT_DISCONNECTED,
|
|
43328
43520
|
createUsageError,
|
|
43521
|
+
createDisconnectedError,
|
|
43329
43522
|
toCliError,
|
|
43330
43523
|
formatErrorPayload,
|
|
43331
43524
|
resolveExitCode,
|
|
43525
|
+
DEFAULT_DAEMON_STATUS_FETCH_OPTIONS,
|
|
43332
43526
|
fetchDaemonStatus,
|
|
43333
43527
|
fetchDaemonStatusFromMetadata,
|
|
43334
43528
|
DaemonClient,
|
|
@@ -43350,4 +43544,4 @@ export {
|
|
|
43350
43544
|
TOOL_SURFACE_ENTRIES
|
|
43351
43545
|
};
|
|
43352
43546
|
/* v8 ignore next -- @preserve */
|
|
43353
|
-
//# sourceMappingURL=chunk-
|
|
43547
|
+
//# sourceMappingURL=chunk-GTTYIAI7.js.map
|