agent-remnote 1.5.0 → 1.5.1
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.md +13 -0
- package/dist/main.js +1412 -1242
- package/package.json +1 -1
- package/plugin-artifacts/PluginZip.zip +0 -0
- package/plugin-artifacts/dist/build-info.json +3 -3
- package/plugin-artifacts/dist/index-sandbox.js +1 -1
- package/plugin-artifacts/dist/index.js +1 -1
- package/plugin-artifacts/dist/{indexPlugin-B6yR4-RE.js → indexPlugin-Cx5F4LoS.js} +1 -1
package/dist/main.js
CHANGED
|
@@ -92343,29 +92343,235 @@ var WsClientLive = succeed10(WsClient, {
|
|
|
92343
92343
|
})
|
|
92344
92344
|
});
|
|
92345
92345
|
|
|
92346
|
-
// src/lib/
|
|
92347
|
-
|
|
92348
|
-
|
|
92349
|
-
|
|
92350
|
-
|
|
92351
|
-
const
|
|
92352
|
-
|
|
92353
|
-
|
|
92346
|
+
// src/lib/apiUrls.ts
|
|
92347
|
+
function normalizeApiBasePath2(basePath) {
|
|
92348
|
+
const trimmed2 = basePath.trim();
|
|
92349
|
+
if (!trimmed2)
|
|
92350
|
+
return "/v1";
|
|
92351
|
+
const normalized = trimmed2.startsWith("/") ? trimmed2 : `/${trimmed2}`;
|
|
92352
|
+
const withoutTrailing = normalized.replace(/\/+$/, "");
|
|
92353
|
+
return withoutTrailing && withoutTrailing !== "/" ? withoutTrailing : "/";
|
|
92354
|
+
}
|
|
92355
|
+
function normalizeBaseUrl(baseUrl) {
|
|
92356
|
+
return baseUrl.trim().replace(/\/+$/, "");
|
|
92357
|
+
}
|
|
92358
|
+
function resolveBasePrefix(baseUrl, fallbackBasePath) {
|
|
92359
|
+
const parsed = new URL(normalizeBaseUrl(baseUrl));
|
|
92360
|
+
const pathname = normalizeApiBasePath2(parsed.pathname);
|
|
92361
|
+
if (pathname && pathname !== "/")
|
|
92362
|
+
return normalizeApiBasePath2(pathname);
|
|
92363
|
+
return normalizeApiBasePath2(fallbackBasePath);
|
|
92364
|
+
}
|
|
92365
|
+
function normalizeRoutePath(routePath) {
|
|
92366
|
+
const trimmed2 = routePath.trim();
|
|
92367
|
+
if (!trimmed2)
|
|
92368
|
+
return "";
|
|
92369
|
+
return `/${trimmed2.replace(/^\/+/, "")}`;
|
|
92370
|
+
}
|
|
92371
|
+
function buildApiBaseUrl(baseUrl, fallbackBasePath = "/v1") {
|
|
92372
|
+
const parsed = new URL(normalizeBaseUrl(baseUrl));
|
|
92373
|
+
const prefix2 = resolveBasePrefix(baseUrl, fallbackBasePath);
|
|
92374
|
+
return prefix2 === "/" ? parsed.origin : `${parsed.origin}${prefix2}`;
|
|
92375
|
+
}
|
|
92376
|
+
function apiLocalBaseUrl(port3, basePath = "/v1") {
|
|
92377
|
+
return buildApiBaseUrl(`http://127.0.0.1:${port3}`, basePath);
|
|
92378
|
+
}
|
|
92379
|
+
function apiContainerBaseUrl(port3, basePath = "/v1") {
|
|
92380
|
+
return buildApiBaseUrl(`http://host.docker.internal:${port3}`, basePath);
|
|
92381
|
+
}
|
|
92382
|
+
function joinApiUrl(baseUrl, routePath, fallbackBasePath = "/v1") {
|
|
92383
|
+
return `${buildApiBaseUrl(baseUrl, fallbackBasePath)}${normalizeRoutePath(routePath)}`;
|
|
92384
|
+
}
|
|
92385
|
+
|
|
92386
|
+
// src/services/HostApiClient.ts
|
|
92387
|
+
function normalizeBaseUrl2(baseUrl) {
|
|
92388
|
+
return baseUrl.trim().replace(/\/+$/, "");
|
|
92389
|
+
}
|
|
92390
|
+
function apiTimeoutError(params3) {
|
|
92391
|
+
return new CliError({
|
|
92392
|
+
code: "API_TIMEOUT",
|
|
92393
|
+
message: `API timeout after ${params3.timeoutMs}ms`,
|
|
92394
|
+
exitCode: 1,
|
|
92395
|
+
details: { base_url: params3.baseUrl, path: params3.path, timeout_ms: params3.timeoutMs }
|
|
92396
|
+
});
|
|
92397
|
+
}
|
|
92398
|
+
function apiUnavailableError(params3) {
|
|
92399
|
+
return new CliError({
|
|
92400
|
+
code: "API_UNAVAILABLE",
|
|
92401
|
+
message: String(params3.error?.message || params3.error || "API request failed"),
|
|
92402
|
+
exitCode: 1,
|
|
92403
|
+
details: { base_url: params3.baseUrl, path: params3.path }
|
|
92404
|
+
});
|
|
92405
|
+
}
|
|
92406
|
+
function exitCodeFromRemoteCode(code2) {
|
|
92407
|
+
return code2 === "INVALID_ARGS" || code2 === "INVALID_PAYLOAD" || code2 === "PAYLOAD_TOO_LARGE" ? 2 : 1;
|
|
92408
|
+
}
|
|
92409
|
+
function parseEnvelope(raw4) {
|
|
92410
|
+
if (!raw4 || typeof raw4 !== "object") {
|
|
92411
|
+
return { ok: false, error: { code: "INTERNAL", message: "Invalid API response envelope" } };
|
|
92354
92412
|
}
|
|
92355
|
-
|
|
92356
|
-
|
|
92357
|
-
|
|
92358
|
-
|
|
92359
|
-
const
|
|
92360
|
-
|
|
92361
|
-
|
|
92362
|
-
|
|
92413
|
+
return raw4;
|
|
92414
|
+
}
|
|
92415
|
+
function buildQuery(params3) {
|
|
92416
|
+
const sp = new URLSearchParams;
|
|
92417
|
+
for (const [key, value8] of Object.entries(params3)) {
|
|
92418
|
+
if (value8 === undefined || value8 === null)
|
|
92419
|
+
continue;
|
|
92420
|
+
if (typeof value8 === "string") {
|
|
92421
|
+
if (!value8.trim())
|
|
92422
|
+
continue;
|
|
92423
|
+
sp.set(key, value8);
|
|
92424
|
+
continue;
|
|
92425
|
+
}
|
|
92426
|
+
if (typeof value8 === "number" || typeof value8 === "boolean") {
|
|
92427
|
+
sp.set(key, String(value8));
|
|
92428
|
+
}
|
|
92363
92429
|
}
|
|
92364
|
-
|
|
92430
|
+
const query = sp.toString();
|
|
92431
|
+
return query ? `?${query}` : "";
|
|
92432
|
+
}
|
|
92433
|
+
function requestJson(params3) {
|
|
92434
|
+
const timeoutMs = Math.max(1, params3.timeoutMs ?? 15000);
|
|
92435
|
+
const baseUrl = normalizeBaseUrl2(params3.baseUrl);
|
|
92436
|
+
const url2 = joinApiUrl(baseUrl, params3.path, params3.basePath);
|
|
92437
|
+
return async((resume2) => {
|
|
92438
|
+
const controller = new AbortController;
|
|
92439
|
+
const timer2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
92440
|
+
fetch(url2, {
|
|
92441
|
+
method: params3.method,
|
|
92442
|
+
headers: params3.method === "POST" ? { "content-type": "application/json" } : undefined,
|
|
92443
|
+
body: params3.body === undefined ? undefined : JSON.stringify(params3.body),
|
|
92444
|
+
signal: controller.signal
|
|
92445
|
+
}).then(async (response) => {
|
|
92446
|
+
clearTimeout(timer2);
|
|
92447
|
+
let parsed;
|
|
92448
|
+
try {
|
|
92449
|
+
parsed = parseEnvelope(await response.json());
|
|
92450
|
+
} catch (error4) {
|
|
92451
|
+
resume2(fail8(new CliError({
|
|
92452
|
+
code: "API_UNAVAILABLE",
|
|
92453
|
+
message: "API returned a non-JSON response",
|
|
92454
|
+
exitCode: 1,
|
|
92455
|
+
details: { url: url2, status: response.status, error: String(error4?.message || error4) }
|
|
92456
|
+
})));
|
|
92457
|
+
return;
|
|
92458
|
+
}
|
|
92459
|
+
if (parsed.ok === true) {
|
|
92460
|
+
resume2(succeed8(parsed.data));
|
|
92461
|
+
return;
|
|
92462
|
+
}
|
|
92463
|
+
const code2 = typeof parsed.error?.code === "string" ? parsed.error.code : "INTERNAL";
|
|
92464
|
+
const message2 = typeof parsed.error?.message === "string" ? parsed.error.message : "API request failed";
|
|
92465
|
+
const hint = Array.isArray(parsed.hint) ? parsed.hint.map(String) : undefined;
|
|
92466
|
+
resume2(fail8(new CliError({
|
|
92467
|
+
code: code2,
|
|
92468
|
+
message: message2,
|
|
92469
|
+
exitCode: exitCodeFromRemoteCode(code2),
|
|
92470
|
+
details: parsed.error?.details,
|
|
92471
|
+
hint
|
|
92472
|
+
})));
|
|
92473
|
+
}).catch((error4) => {
|
|
92474
|
+
clearTimeout(timer2);
|
|
92475
|
+
if (error4?.name === "AbortError") {
|
|
92476
|
+
resume2(fail8(apiTimeoutError({ baseUrl, path: params3.path, timeoutMs })));
|
|
92477
|
+
return;
|
|
92478
|
+
}
|
|
92479
|
+
resume2(fail8(apiUnavailableError({ baseUrl, path: params3.path, error: error4 })));
|
|
92480
|
+
});
|
|
92481
|
+
return sync3(() => {
|
|
92482
|
+
clearTimeout(timer2);
|
|
92483
|
+
controller.abort();
|
|
92484
|
+
});
|
|
92485
|
+
});
|
|
92365
92486
|
}
|
|
92366
92487
|
|
|
92488
|
+
class HostApiClient extends Tag2("HostApiClient")() {
|
|
92489
|
+
}
|
|
92490
|
+
var HostApiClientLive = effect(HostApiClient, gen2(function* () {
|
|
92491
|
+
const cfg = yield* AppConfig;
|
|
92492
|
+
const basePath = cfg.apiBasePath ?? "/v1";
|
|
92493
|
+
const request = (params3) => requestJson({ ...params3, basePath });
|
|
92494
|
+
return {
|
|
92495
|
+
resolveRefValue: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/ref/resolve", method: "POST", body, timeoutMs }),
|
|
92496
|
+
resolvePlacement: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/placement/resolve", method: "POST", body, timeoutMs }),
|
|
92497
|
+
resolveStableSiblingRange: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/selection/stable-sibling-range", method: "POST", body, timeoutMs }),
|
|
92498
|
+
health: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/health", method: "GET", timeoutMs }),
|
|
92499
|
+
status: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/status", method: "GET", timeoutMs }),
|
|
92500
|
+
uiContextSnapshot: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92501
|
+
baseUrl,
|
|
92502
|
+
path: `/plugin/ui-context/snapshot${buildQuery({ stateFile, staleMs })}`,
|
|
92503
|
+
method: "GET",
|
|
92504
|
+
timeoutMs
|
|
92505
|
+
}),
|
|
92506
|
+
uiContextPage: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92507
|
+
baseUrl,
|
|
92508
|
+
path: `/plugin/ui-context/page${buildQuery({ stateFile, staleMs })}`,
|
|
92509
|
+
method: "GET",
|
|
92510
|
+
timeoutMs
|
|
92511
|
+
}),
|
|
92512
|
+
uiContextFocusedRem: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92513
|
+
baseUrl,
|
|
92514
|
+
path: `/plugin/ui-context/focused-rem${buildQuery({ stateFile, staleMs })}`,
|
|
92515
|
+
method: "GET",
|
|
92516
|
+
timeoutMs
|
|
92517
|
+
}),
|
|
92518
|
+
uiContextDescribe: ({ baseUrl, stateFile, staleMs, selectionLimit, timeoutMs }) => request({
|
|
92519
|
+
baseUrl,
|
|
92520
|
+
path: `/plugin/ui-context/describe${buildQuery({ stateFile, staleMs, selectionLimit })}`,
|
|
92521
|
+
method: "GET",
|
|
92522
|
+
timeoutMs
|
|
92523
|
+
}),
|
|
92524
|
+
selectionSnapshot: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92525
|
+
baseUrl,
|
|
92526
|
+
path: `/plugin/selection/snapshot${buildQuery({ stateFile, staleMs })}`,
|
|
92527
|
+
method: "GET",
|
|
92528
|
+
timeoutMs
|
|
92529
|
+
}),
|
|
92530
|
+
selectionRoots: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92531
|
+
baseUrl,
|
|
92532
|
+
path: `/plugin/selection/roots${buildQuery({ stateFile, staleMs })}`,
|
|
92533
|
+
method: "GET",
|
|
92534
|
+
timeoutMs
|
|
92535
|
+
}),
|
|
92536
|
+
selectionCurrent: ({ baseUrl, stateFile, staleMs, timeoutMs }) => request({
|
|
92537
|
+
baseUrl,
|
|
92538
|
+
path: `/plugin/selection/current${buildQuery({ stateFile, staleMs })}`,
|
|
92539
|
+
method: "GET",
|
|
92540
|
+
timeoutMs
|
|
92541
|
+
}),
|
|
92542
|
+
pluginCurrent: ({ baseUrl, stateFile, staleMs, selectionLimit, timeoutMs }) => request({
|
|
92543
|
+
baseUrl,
|
|
92544
|
+
path: `/plugin/current${buildQuery({ stateFile, staleMs, selectionLimit })}`,
|
|
92545
|
+
method: "GET",
|
|
92546
|
+
timeoutMs
|
|
92547
|
+
}),
|
|
92548
|
+
selectionOutline: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/plugin/selection/outline", method: "POST", body, timeoutMs }),
|
|
92549
|
+
uiContext: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/ui-context", method: "GET", timeoutMs }),
|
|
92550
|
+
selection: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/selection", method: "GET", timeoutMs }),
|
|
92551
|
+
searchDb: ({ baseUrl, ...body }) => request({ baseUrl, path: "/search/db", method: "POST", body }),
|
|
92552
|
+
searchPlugin: ({ baseUrl, ...body }) => request({ baseUrl, path: "/search/plugin", method: "POST", body }),
|
|
92553
|
+
writeApply: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/write/apply", method: "POST", body, timeoutMs }),
|
|
92554
|
+
readOutline: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/outline", method: "POST", body, timeoutMs }),
|
|
92555
|
+
readPageId: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/page-id", method: "POST", body, timeoutMs }),
|
|
92556
|
+
resolveRef: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/resolve-ref", method: "POST", body, timeoutMs }),
|
|
92557
|
+
byReference: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/by-reference", method: "POST", body, timeoutMs }),
|
|
92558
|
+
references: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/references", method: "POST", body, timeoutMs }),
|
|
92559
|
+
resolveQueryPowerup: ({ baseUrl, powerup, timeoutMs }) => request({ baseUrl, path: "/internal/query/resolve-powerup", method: "POST", body: { powerup }, timeoutMs }),
|
|
92560
|
+
query: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/query", method: "POST", body, timeoutMs }),
|
|
92561
|
+
dailyRemId: ({ baseUrl, date: date6, offsetDays, timeoutMs }) => request({
|
|
92562
|
+
baseUrl,
|
|
92563
|
+
path: `/daily/rem-id${buildQuery({ date: date6, offsetDays })}`,
|
|
92564
|
+
method: "GET",
|
|
92565
|
+
timeoutMs
|
|
92566
|
+
}),
|
|
92567
|
+
queueWait: ({ baseUrl, txnId, timeoutMs, pollMs }) => request({ baseUrl, path: "/queue/wait", method: "POST", body: { txnId, timeoutMs, pollMs } }),
|
|
92568
|
+
queueTxn: ({ baseUrl, txnId, timeoutMs }) => request({ baseUrl, path: `/queue/txns/${encodeURIComponent(txnId)}`, method: "GET", timeoutMs }),
|
|
92569
|
+
triggerSync: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/actions/trigger-sync", method: "POST", timeoutMs })
|
|
92570
|
+
};
|
|
92571
|
+
}));
|
|
92572
|
+
|
|
92367
92573
|
// src/lib/pidTrust.ts
|
|
92368
|
-
import
|
|
92574
|
+
import path19 from "node:path";
|
|
92369
92575
|
function normalizeToken(value8) {
|
|
92370
92576
|
return value8.trim().replace(/\\/g, "/").toLowerCase();
|
|
92371
92577
|
}
|
|
@@ -92376,7 +92582,7 @@ function collectCommandTokens(raw4) {
|
|
|
92376
92582
|
if (!normalized)
|
|
92377
92583
|
continue;
|
|
92378
92584
|
const unquoted = normalized.replace(/^['"]|['"]$/g, "");
|
|
92379
|
-
const base =
|
|
92585
|
+
const base = path19.basename(unquoted);
|
|
92380
92586
|
if (unquoted.includes("agent-remnote") || base.includes("agent-remnote")) {
|
|
92381
92587
|
out.add("agent-remnote");
|
|
92382
92588
|
}
|
|
@@ -92434,32 +92640,870 @@ function requireTrustedPidRecord(params3) {
|
|
|
92434
92640
|
});
|
|
92435
92641
|
}
|
|
92436
92642
|
|
|
92437
|
-
// src/lib/
|
|
92438
|
-
import {
|
|
92439
|
-
|
|
92440
|
-
|
|
92441
|
-
import {
|
|
92442
|
-
|
|
92443
|
-
class StatusLineFile extends Tag2("StatusLineFile")() {
|
|
92444
|
-
}
|
|
92445
|
-
function defaultTextFile() {
|
|
92446
|
-
return path21.join(homeDir(), ".agent-remnote", "status-line.txt");
|
|
92447
|
-
}
|
|
92448
|
-
function defaultJsonFile() {
|
|
92449
|
-
return path21.join(homeDir(), ".agent-remnote", "status-line.json");
|
|
92450
|
-
}
|
|
92451
|
-
function ensureDir8(p3) {
|
|
92452
|
-
return fs14.mkdir(path21.dirname(p3), { recursive: true }).then(() => {
|
|
92453
|
-
return;
|
|
92454
|
-
});
|
|
92455
|
-
}
|
|
92456
|
-
async function readFileOrEmpty(filePath) {
|
|
92643
|
+
// src/lib/runtimeBuildInfo.ts
|
|
92644
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
92645
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
|
|
92646
|
+
import path20 from "node:path";
|
|
92647
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
92648
|
+
function packageInfo() {
|
|
92457
92649
|
try {
|
|
92458
|
-
|
|
92459
|
-
|
|
92460
|
-
|
|
92461
|
-
|
|
92462
|
-
|
|
92650
|
+
const raw4 = readFileSync2(new URL("../../package.json", import.meta.url), "utf8");
|
|
92651
|
+
const parsed = JSON.parse(raw4);
|
|
92652
|
+
const name = typeof parsed?.name === "string" && parsed.name.trim() ? parsed.name.trim() : "agent-remnote";
|
|
92653
|
+
const version = typeof parsed?.version === "string" && parsed.version.trim() ? parsed.version.trim() : "0.0.0";
|
|
92654
|
+
return { name, version };
|
|
92655
|
+
} catch {
|
|
92656
|
+
return { name: "agent-remnote", version: "0.0.0" };
|
|
92657
|
+
}
|
|
92658
|
+
}
|
|
92659
|
+
function fileMtimeMs(targetPath) {
|
|
92660
|
+
try {
|
|
92661
|
+
return Math.floor(statSync(targetPath).mtimeMs);
|
|
92662
|
+
} catch {
|
|
92663
|
+
return 0;
|
|
92664
|
+
}
|
|
92665
|
+
}
|
|
92666
|
+
function latestMtimeMs(dirPath) {
|
|
92667
|
+
if (!existsSync2(dirPath))
|
|
92668
|
+
return 0;
|
|
92669
|
+
let max7 = 0;
|
|
92670
|
+
const stack = [dirPath];
|
|
92671
|
+
while (stack.length > 0) {
|
|
92672
|
+
const current2 = stack.pop();
|
|
92673
|
+
let entries2 = [];
|
|
92674
|
+
try {
|
|
92675
|
+
entries2 = readdirSync(current2);
|
|
92676
|
+
} catch {
|
|
92677
|
+
continue;
|
|
92678
|
+
}
|
|
92679
|
+
for (const entry of entries2) {
|
|
92680
|
+
const full = path20.join(current2, entry);
|
|
92681
|
+
let st;
|
|
92682
|
+
try {
|
|
92683
|
+
st = statSync(full);
|
|
92684
|
+
} catch {
|
|
92685
|
+
continue;
|
|
92686
|
+
}
|
|
92687
|
+
if (st.isDirectory()) {
|
|
92688
|
+
stack.push(full);
|
|
92689
|
+
} else if (st.isFile()) {
|
|
92690
|
+
max7 = Math.max(max7, Math.floor(st.mtimeMs));
|
|
92691
|
+
}
|
|
92692
|
+
}
|
|
92693
|
+
}
|
|
92694
|
+
return max7;
|
|
92695
|
+
}
|
|
92696
|
+
function detectMode() {
|
|
92697
|
+
const url2 = import.meta.url;
|
|
92698
|
+
if (url2.includes("/src/"))
|
|
92699
|
+
return "src";
|
|
92700
|
+
if (url2.includes("/dist/"))
|
|
92701
|
+
return "dist";
|
|
92702
|
+
return "unknown";
|
|
92703
|
+
}
|
|
92704
|
+
function computeDefaultBuildInfo() {
|
|
92705
|
+
const pkg = packageInfo();
|
|
92706
|
+
const mode = detectMode();
|
|
92707
|
+
const srcDir = new URL("../", import.meta.url);
|
|
92708
|
+
const packageJson = new URL("../../package.json", import.meta.url);
|
|
92709
|
+
const sourceStamp = Math.max(latestMtimeMs(fileURLToPath3(srcDir)), fileMtimeMs(fileURLToPath3(packageJson)));
|
|
92710
|
+
const buildIdInput = `${pkg.name}
|
|
92711
|
+
${pkg.version}
|
|
92712
|
+
${mode}
|
|
92713
|
+
${sourceStamp}`;
|
|
92714
|
+
const buildId = createHash3("sha256").update(buildIdInput).digest("hex").slice(0, 12);
|
|
92715
|
+
return {
|
|
92716
|
+
name: pkg.name,
|
|
92717
|
+
version: pkg.version,
|
|
92718
|
+
build_id: `${pkg.version}:${buildId}`,
|
|
92719
|
+
built_at: sourceStamp || Date.now(),
|
|
92720
|
+
source_stamp: sourceStamp || Date.now(),
|
|
92721
|
+
mode
|
|
92722
|
+
};
|
|
92723
|
+
}
|
|
92724
|
+
var cached4;
|
|
92725
|
+
function parseEnvNumber(raw4, fallback) {
|
|
92726
|
+
const parsed = Number(raw4);
|
|
92727
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
92728
|
+
}
|
|
92729
|
+
function currentRuntimeBuildInfo() {
|
|
92730
|
+
if (cached4)
|
|
92731
|
+
return cached4;
|
|
92732
|
+
const defaultInfo = computeDefaultBuildInfo();
|
|
92733
|
+
cached4 = {
|
|
92734
|
+
name: process.env.AGENT_REMNOTE_NAME?.trim() || defaultInfo.name,
|
|
92735
|
+
version: process.env.AGENT_REMNOTE_VERSION?.trim() || defaultInfo.version,
|
|
92736
|
+
build_id: process.env.AGENT_REMNOTE_BUILD_ID?.trim() || defaultInfo.build_id,
|
|
92737
|
+
built_at: parseEnvNumber(process.env.AGENT_REMNOTE_BUILD_AT, defaultInfo.built_at),
|
|
92738
|
+
source_stamp: parseEnvNumber(process.env.AGENT_REMNOTE_SOURCE_STAMP, defaultInfo.source_stamp),
|
|
92739
|
+
mode: process.env.AGENT_REMNOTE_BUILD_MODE === "src" || process.env.AGENT_REMNOTE_BUILD_MODE === "dist" || process.env.AGENT_REMNOTE_BUILD_MODE === "unknown" ? process.env.AGENT_REMNOTE_BUILD_MODE : defaultInfo.mode
|
|
92740
|
+
};
|
|
92741
|
+
return cached4;
|
|
92742
|
+
}
|
|
92743
|
+
function runtimeVersionWarnings(params3) {
|
|
92744
|
+
const warnings = [];
|
|
92745
|
+
const compare2 = (label, other) => {
|
|
92746
|
+
if (!other)
|
|
92747
|
+
return;
|
|
92748
|
+
if (other.build_id !== params3.current.build_id) {
|
|
92749
|
+
warnings.push(`${label} build mismatch: current=${params3.current.build_id} live=${other.build_id}`);
|
|
92750
|
+
}
|
|
92751
|
+
};
|
|
92752
|
+
compare2("daemon", params3.daemon);
|
|
92753
|
+
compare2("plugin", params3.plugin);
|
|
92754
|
+
compare2("api", params3.api);
|
|
92755
|
+
return warnings;
|
|
92756
|
+
}
|
|
92757
|
+
|
|
92758
|
+
// src/commands/api/_shared.ts
|
|
92759
|
+
var API_HEALTH_TIMEOUT_MS = 2000;
|
|
92760
|
+
var API_START_WAIT_DEFAULT_MS = 15000;
|
|
92761
|
+
var API_STOP_WAIT_DEFAULT_MS = 5000;
|
|
92762
|
+
function childCommandLine(params3) {
|
|
92763
|
+
const command = process.argv[0];
|
|
92764
|
+
const script = process.argv[1];
|
|
92765
|
+
if (!command || !script) {
|
|
92766
|
+
throw new CliError({
|
|
92767
|
+
code: "INTERNAL",
|
|
92768
|
+
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
92769
|
+
exitCode: 1,
|
|
92770
|
+
details: { argv: process.argv }
|
|
92771
|
+
});
|
|
92772
|
+
}
|
|
92773
|
+
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
92774
|
+
const args2 = [...execArgv, script, "--daemon-url", params3.wsUrl, "--store-db", params3.storeDb];
|
|
92775
|
+
if (params3.remnoteDb)
|
|
92776
|
+
args2.push("--remnote-db", params3.remnoteDb);
|
|
92777
|
+
args2.push("--api-base-path", params3.basePath);
|
|
92778
|
+
args2.push("api", "serve", "--host", params3.host, "--port", String(params3.port), "--state-file", params3.stateFile);
|
|
92779
|
+
return { command, args: args2 };
|
|
92780
|
+
}
|
|
92781
|
+
function toPidFileValue(params3) {
|
|
92782
|
+
return {
|
|
92783
|
+
pid: params3.pid,
|
|
92784
|
+
build: currentRuntimeBuildInfo(),
|
|
92785
|
+
started_at: params3.startedAt,
|
|
92786
|
+
host: params3.host,
|
|
92787
|
+
port: params3.port,
|
|
92788
|
+
base_path: params3.basePath,
|
|
92789
|
+
log_file: params3.logFile,
|
|
92790
|
+
state_file: params3.stateFile,
|
|
92791
|
+
cmd: params3.cmd
|
|
92792
|
+
};
|
|
92793
|
+
}
|
|
92794
|
+
function waitForApiHealth(baseUrl, waitMs) {
|
|
92795
|
+
return gen2(function* () {
|
|
92796
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
92797
|
+
return yield* fail8(new CliError({
|
|
92798
|
+
code: "INVALID_ARGS",
|
|
92799
|
+
message: "--wait must be a non-negative integer (ms)",
|
|
92800
|
+
exitCode: 2,
|
|
92801
|
+
details: { wait_ms: waitMs }
|
|
92802
|
+
}));
|
|
92803
|
+
}
|
|
92804
|
+
if (waitMs === 0)
|
|
92805
|
+
return;
|
|
92806
|
+
const api = yield* HostApiClient;
|
|
92807
|
+
const deadline = Date.now() + waitMs;
|
|
92808
|
+
while (Date.now() < deadline) {
|
|
92809
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
92810
|
+
const res = yield* api.health({ baseUrl, timeoutMs: Math.min(API_HEALTH_TIMEOUT_MS, Math.max(1, remaining)) }).pipe(either3);
|
|
92811
|
+
if (isRight2(res))
|
|
92812
|
+
return;
|
|
92813
|
+
yield* sleep4(millis(300));
|
|
92814
|
+
}
|
|
92815
|
+
return yield* fail8(new CliError({
|
|
92816
|
+
code: "API_TIMEOUT",
|
|
92817
|
+
message: `Timed out waiting for host API to become available (${waitMs}ms)`,
|
|
92818
|
+
exitCode: 1,
|
|
92819
|
+
details: { base_url: baseUrl, wait_ms: waitMs },
|
|
92820
|
+
hint: ["agent-remnote api status --json", "agent-remnote api logs", "agent-remnote stack status --json"]
|
|
92821
|
+
}));
|
|
92822
|
+
});
|
|
92823
|
+
}
|
|
92824
|
+
function startApiDaemon(params3) {
|
|
92825
|
+
return gen2(function* () {
|
|
92826
|
+
const cfg = yield* AppConfig;
|
|
92827
|
+
const api = yield* HostApiClient;
|
|
92828
|
+
const apiFiles = yield* ApiDaemonFiles;
|
|
92829
|
+
const proc = yield* Process;
|
|
92830
|
+
const host = params3.host ?? cfg.apiHost ?? "0.0.0.0";
|
|
92831
|
+
const port3 = params3.port ?? cfg.apiPort ?? 3000;
|
|
92832
|
+
const basePath = params3.basePath ?? cfg.apiBasePath ?? "/v1";
|
|
92833
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? apiFiles.defaultPidFile());
|
|
92834
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? apiFiles.defaultLogFile());
|
|
92835
|
+
const stateFilePath = resolveUserFilePath(params3.stateFile ?? apiFiles.defaultStateFile());
|
|
92836
|
+
const localBaseUrl = apiLocalBaseUrl(port3, basePath);
|
|
92837
|
+
const existing = yield* apiFiles.readPidFile(pidFilePath);
|
|
92838
|
+
if (existing) {
|
|
92839
|
+
const alive = yield* proc.isPidRunning(existing.pid);
|
|
92840
|
+
if (!alive) {
|
|
92841
|
+
yield* apiFiles.deletePidFile(pidFilePath);
|
|
92842
|
+
} else {
|
|
92843
|
+
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
92844
|
+
return {
|
|
92845
|
+
started: false,
|
|
92846
|
+
pid: existing.pid,
|
|
92847
|
+
pid_file: pidFilePath,
|
|
92848
|
+
log_file: logFilePath,
|
|
92849
|
+
state_file: stateFilePath,
|
|
92850
|
+
base_url: localBaseUrl
|
|
92851
|
+
};
|
|
92852
|
+
}
|
|
92853
|
+
}
|
|
92854
|
+
const pre = yield* api.health({ baseUrl: localBaseUrl, timeoutMs: API_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
92855
|
+
if (isRight2(pre)) {
|
|
92856
|
+
return {
|
|
92857
|
+
started: false,
|
|
92858
|
+
pid_file: pidFilePath,
|
|
92859
|
+
log_file: logFilePath,
|
|
92860
|
+
state_file: stateFilePath,
|
|
92861
|
+
base_url: localBaseUrl
|
|
92862
|
+
};
|
|
92863
|
+
}
|
|
92864
|
+
const cmd = yield* try_3({
|
|
92865
|
+
try: () => childCommandLine({
|
|
92866
|
+
wsUrl: cfg.wsUrl,
|
|
92867
|
+
storeDb: cfg.storeDb,
|
|
92868
|
+
remnoteDb: cfg.remnoteDb,
|
|
92869
|
+
host,
|
|
92870
|
+
port: port3,
|
|
92871
|
+
basePath,
|
|
92872
|
+
stateFile: stateFilePath
|
|
92873
|
+
}),
|
|
92874
|
+
catch: (e) => isCliError(e) ? e : new CliError({
|
|
92875
|
+
code: "INTERNAL",
|
|
92876
|
+
message: "Failed to start host api",
|
|
92877
|
+
exitCode: 1,
|
|
92878
|
+
details: { error: String(e?.message || e) }
|
|
92879
|
+
})
|
|
92880
|
+
});
|
|
92881
|
+
const pid = yield* proc.spawnDetached({ command: cmd.command, args: cmd.args, logFile: logFilePath });
|
|
92882
|
+
yield* apiFiles.writePidFile(pidFilePath, toPidFileValue({
|
|
92883
|
+
pid,
|
|
92884
|
+
startedAt: Date.now(),
|
|
92885
|
+
host,
|
|
92886
|
+
port: port3,
|
|
92887
|
+
basePath,
|
|
92888
|
+
logFile: logFilePath,
|
|
92889
|
+
stateFile: stateFilePath,
|
|
92890
|
+
cmd: [cmd.command, ...cmd.args]
|
|
92891
|
+
}));
|
|
92892
|
+
yield* waitForApiHealth(localBaseUrl, params3.waitMs);
|
|
92893
|
+
return {
|
|
92894
|
+
started: true,
|
|
92895
|
+
pid,
|
|
92896
|
+
pid_file: pidFilePath,
|
|
92897
|
+
log_file: logFilePath,
|
|
92898
|
+
state_file: stateFilePath,
|
|
92899
|
+
base_url: localBaseUrl
|
|
92900
|
+
};
|
|
92901
|
+
});
|
|
92902
|
+
}
|
|
92903
|
+
function ensureApiDaemon(params3) {
|
|
92904
|
+
return gen2(function* () {
|
|
92905
|
+
const cfg = yield* AppConfig;
|
|
92906
|
+
const api = yield* HostApiClient;
|
|
92907
|
+
const apiFiles = yield* ApiDaemonFiles;
|
|
92908
|
+
const proc = yield* Process;
|
|
92909
|
+
const port3 = params3.port ?? cfg.apiPort ?? 3000;
|
|
92910
|
+
const basePath = cfg.apiBasePath ?? "/v1";
|
|
92911
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? apiFiles.defaultPidFile());
|
|
92912
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? apiFiles.defaultLogFile());
|
|
92913
|
+
const stateFilePath = resolveUserFilePath(params3.stateFile ?? apiFiles.defaultStateFile());
|
|
92914
|
+
const localBaseUrl = apiLocalBaseUrl(port3, basePath);
|
|
92915
|
+
const pre = yield* api.health({ baseUrl: localBaseUrl, timeoutMs: API_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
92916
|
+
if (isRight2(pre)) {
|
|
92917
|
+
const existing = yield* apiFiles.readPidFile(pidFilePath);
|
|
92918
|
+
if (existing) {
|
|
92919
|
+
const alive = yield* proc.isPidRunning(existing.pid);
|
|
92920
|
+
if (alive) {
|
|
92921
|
+
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
92922
|
+
return {
|
|
92923
|
+
started: false,
|
|
92924
|
+
pid: existing.pid,
|
|
92925
|
+
pid_file: pidFilePath,
|
|
92926
|
+
log_file: existing.log_file ?? logFilePath,
|
|
92927
|
+
state_file: existing.state_file ?? stateFilePath,
|
|
92928
|
+
base_url: localBaseUrl
|
|
92929
|
+
};
|
|
92930
|
+
}
|
|
92931
|
+
}
|
|
92932
|
+
return {
|
|
92933
|
+
started: false,
|
|
92934
|
+
pid_file: pidFilePath,
|
|
92935
|
+
log_file: logFilePath,
|
|
92936
|
+
state_file: stateFilePath,
|
|
92937
|
+
base_url: localBaseUrl
|
|
92938
|
+
};
|
|
92939
|
+
}
|
|
92940
|
+
return yield* startApiDaemon(params3);
|
|
92941
|
+
});
|
|
92942
|
+
}
|
|
92943
|
+
|
|
92944
|
+
// src/lib/pluginServerHealth.ts
|
|
92945
|
+
function checkPluginServerHealth(baseUrl, timeoutMs) {
|
|
92946
|
+
return tryPromise2({
|
|
92947
|
+
try: async () => {
|
|
92948
|
+
const controller = new AbortController;
|
|
92949
|
+
const timer2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
92950
|
+
try {
|
|
92951
|
+
const res = await fetch(`${baseUrl}/manifest.json`, { signal: controller.signal });
|
|
92952
|
+
if (!res.ok) {
|
|
92953
|
+
throw new Error(`Unexpected response status: ${res.status}`);
|
|
92954
|
+
}
|
|
92955
|
+
return { base_url: baseUrl };
|
|
92956
|
+
} finally {
|
|
92957
|
+
clearTimeout(timer2);
|
|
92958
|
+
}
|
|
92959
|
+
},
|
|
92960
|
+
catch: (error4) => new CliError({
|
|
92961
|
+
code: "PLUGIN_UNAVAILABLE",
|
|
92962
|
+
message: "Plugin server is unavailable",
|
|
92963
|
+
exitCode: 1,
|
|
92964
|
+
details: { base_url: baseUrl, error: String(error4?.message || error4) }
|
|
92965
|
+
})
|
|
92966
|
+
});
|
|
92967
|
+
}
|
|
92968
|
+
function waitForPluginServerHealth(baseUrl, waitMs, timeoutMs) {
|
|
92969
|
+
return gen2(function* () {
|
|
92970
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
92971
|
+
return yield* fail8(new CliError({
|
|
92972
|
+
code: "INVALID_ARGS",
|
|
92973
|
+
message: "--wait must be a non-negative integer (ms)",
|
|
92974
|
+
exitCode: 2,
|
|
92975
|
+
details: { wait_ms: waitMs }
|
|
92976
|
+
}));
|
|
92977
|
+
}
|
|
92978
|
+
if (waitMs === 0)
|
|
92979
|
+
return;
|
|
92980
|
+
const deadline = Date.now() + waitMs;
|
|
92981
|
+
while (Date.now() < deadline) {
|
|
92982
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
92983
|
+
const res = yield* checkPluginServerHealth(baseUrl, Math.min(timeoutMs, Math.max(1, remaining))).pipe(either3);
|
|
92984
|
+
if (isRight2(res))
|
|
92985
|
+
return;
|
|
92986
|
+
yield* sleep4(millis(300));
|
|
92987
|
+
}
|
|
92988
|
+
return yield* fail8(new CliError({
|
|
92989
|
+
code: "PLUGIN_UNAVAILABLE",
|
|
92990
|
+
message: `Timed out waiting for plugin server to become available (${waitMs}ms)`,
|
|
92991
|
+
exitCode: 1,
|
|
92992
|
+
details: { base_url: baseUrl, wait_ms: waitMs },
|
|
92993
|
+
hint: ["agent-remnote plugin status --json", "agent-remnote plugin logs --lines 200"]
|
|
92994
|
+
}));
|
|
92995
|
+
});
|
|
92996
|
+
}
|
|
92997
|
+
|
|
92998
|
+
// src/commands/plugin/_shared.ts
|
|
92999
|
+
var PLUGIN_SERVER_HEALTH_TIMEOUT_MS = 2000;
|
|
93000
|
+
var PLUGIN_SERVER_START_WAIT_DEFAULT_MS = 15000;
|
|
93001
|
+
var PLUGIN_SERVER_STOP_WAIT_DEFAULT_MS = 5000;
|
|
93002
|
+
var PLUGIN_SERVER_DEFAULT_HOST = "127.0.0.1";
|
|
93003
|
+
var PLUGIN_SERVER_DEFAULT_PORT = 8080;
|
|
93004
|
+
function pluginServerLocalBaseUrl(host, port3) {
|
|
93005
|
+
const normalizedHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
|
|
93006
|
+
return `http://${normalizedHost}:${port3}`;
|
|
93007
|
+
}
|
|
93008
|
+
function childCommandLine2(params3) {
|
|
93009
|
+
const command = process.argv[0];
|
|
93010
|
+
const script = process.argv[1];
|
|
93011
|
+
if (!command || !script) {
|
|
93012
|
+
throw new CliError({
|
|
93013
|
+
code: "INTERNAL",
|
|
93014
|
+
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
93015
|
+
exitCode: 1,
|
|
93016
|
+
details: { argv: process.argv }
|
|
93017
|
+
});
|
|
93018
|
+
}
|
|
93019
|
+
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
93020
|
+
const args2 = [...execArgv, script, "plugin", "serve", "--host", params3.host, "--port", String(params3.port), "--state-file", params3.stateFile];
|
|
93021
|
+
return { command, args: args2 };
|
|
93022
|
+
}
|
|
93023
|
+
function toPidFileValue2(params3) {
|
|
93024
|
+
return {
|
|
93025
|
+
pid: params3.pid,
|
|
93026
|
+
build: currentRuntimeBuildInfo(),
|
|
93027
|
+
started_at: params3.startedAt,
|
|
93028
|
+
host: params3.host,
|
|
93029
|
+
port: params3.port,
|
|
93030
|
+
log_file: params3.logFile,
|
|
93031
|
+
state_file: params3.stateFile,
|
|
93032
|
+
cmd: params3.cmd
|
|
93033
|
+
};
|
|
93034
|
+
}
|
|
93035
|
+
function startPluginServer(params3) {
|
|
93036
|
+
return gen2(function* () {
|
|
93037
|
+
const files = yield* PluginServerFiles;
|
|
93038
|
+
const proc = yield* Process;
|
|
93039
|
+
const host = params3.host ?? PLUGIN_SERVER_DEFAULT_HOST;
|
|
93040
|
+
const port3 = params3.port ?? PLUGIN_SERVER_DEFAULT_PORT;
|
|
93041
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? files.defaultPidFile());
|
|
93042
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? files.defaultLogFile());
|
|
93043
|
+
const stateFilePath = resolveUserFilePath(params3.stateFile ?? files.defaultStateFile());
|
|
93044
|
+
const baseUrl = pluginServerLocalBaseUrl(host, port3);
|
|
93045
|
+
const existing = yield* files.readPidFile(pidFilePath);
|
|
93046
|
+
if (existing) {
|
|
93047
|
+
const alive = yield* proc.isPidRunning(existing.pid);
|
|
93048
|
+
if (!alive) {
|
|
93049
|
+
yield* files.deletePidFile(pidFilePath);
|
|
93050
|
+
} else {
|
|
93051
|
+
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
93052
|
+
return {
|
|
93053
|
+
started: false,
|
|
93054
|
+
pid: existing.pid,
|
|
93055
|
+
pid_file: pidFilePath,
|
|
93056
|
+
log_file: existing.log_file ?? logFilePath,
|
|
93057
|
+
state_file: existing.state_file ?? stateFilePath,
|
|
93058
|
+
base_url: baseUrl
|
|
93059
|
+
};
|
|
93060
|
+
}
|
|
93061
|
+
}
|
|
93062
|
+
const pre = yield* checkPluginServerHealth(baseUrl, PLUGIN_SERVER_HEALTH_TIMEOUT_MS).pipe(either3);
|
|
93063
|
+
if (isRight2(pre)) {
|
|
93064
|
+
return {
|
|
93065
|
+
started: false,
|
|
93066
|
+
pid_file: pidFilePath,
|
|
93067
|
+
log_file: logFilePath,
|
|
93068
|
+
state_file: stateFilePath,
|
|
93069
|
+
base_url: baseUrl
|
|
93070
|
+
};
|
|
93071
|
+
}
|
|
93072
|
+
const cmd = yield* try_3({
|
|
93073
|
+
try: () => childCommandLine2({ host, port: port3, stateFile: stateFilePath }),
|
|
93074
|
+
catch: (error4) => isCliError(error4) ? error4 : new CliError({
|
|
93075
|
+
code: "INTERNAL",
|
|
93076
|
+
message: "Failed to start plugin server",
|
|
93077
|
+
exitCode: 1,
|
|
93078
|
+
details: { error: String(error4?.message || error4) }
|
|
93079
|
+
})
|
|
93080
|
+
});
|
|
93081
|
+
const pid = yield* proc.spawnDetached({ command: cmd.command, args: cmd.args, logFile: logFilePath });
|
|
93082
|
+
yield* files.writePidFile(pidFilePath, toPidFileValue2({
|
|
93083
|
+
pid,
|
|
93084
|
+
startedAt: Date.now(),
|
|
93085
|
+
host,
|
|
93086
|
+
port: port3,
|
|
93087
|
+
logFile: logFilePath,
|
|
93088
|
+
stateFile: stateFilePath,
|
|
93089
|
+
cmd: [cmd.command, ...cmd.args]
|
|
93090
|
+
}));
|
|
93091
|
+
yield* waitForPluginServerHealth(baseUrl, params3.waitMs, PLUGIN_SERVER_HEALTH_TIMEOUT_MS);
|
|
93092
|
+
return {
|
|
93093
|
+
started: true,
|
|
93094
|
+
pid,
|
|
93095
|
+
pid_file: pidFilePath,
|
|
93096
|
+
log_file: logFilePath,
|
|
93097
|
+
state_file: stateFilePath,
|
|
93098
|
+
base_url: baseUrl
|
|
93099
|
+
};
|
|
93100
|
+
});
|
|
93101
|
+
}
|
|
93102
|
+
function ensurePluginServer(params3) {
|
|
93103
|
+
return gen2(function* () {
|
|
93104
|
+
const files = yield* PluginServerFiles;
|
|
93105
|
+
const proc = yield* Process;
|
|
93106
|
+
const host = params3.host ?? PLUGIN_SERVER_DEFAULT_HOST;
|
|
93107
|
+
const port3 = params3.port ?? PLUGIN_SERVER_DEFAULT_PORT;
|
|
93108
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? files.defaultPidFile());
|
|
93109
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? files.defaultLogFile());
|
|
93110
|
+
const stateFilePath = resolveUserFilePath(params3.stateFile ?? files.defaultStateFile());
|
|
93111
|
+
const baseUrl = pluginServerLocalBaseUrl(host, port3);
|
|
93112
|
+
const pre = yield* checkPluginServerHealth(baseUrl, PLUGIN_SERVER_HEALTH_TIMEOUT_MS).pipe(either3);
|
|
93113
|
+
if (isRight2(pre)) {
|
|
93114
|
+
const existing = yield* files.readPidFile(pidFilePath);
|
|
93115
|
+
if (existing) {
|
|
93116
|
+
const alive = yield* proc.isPidRunning(existing.pid);
|
|
93117
|
+
if (alive) {
|
|
93118
|
+
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
93119
|
+
return {
|
|
93120
|
+
started: false,
|
|
93121
|
+
pid: existing.pid,
|
|
93122
|
+
pid_file: pidFilePath,
|
|
93123
|
+
log_file: existing.log_file ?? logFilePath,
|
|
93124
|
+
state_file: existing.state_file ?? stateFilePath,
|
|
93125
|
+
base_url: baseUrl
|
|
93126
|
+
};
|
|
93127
|
+
}
|
|
93128
|
+
}
|
|
93129
|
+
return {
|
|
93130
|
+
started: false,
|
|
93131
|
+
pid_file: pidFilePath,
|
|
93132
|
+
log_file: logFilePath,
|
|
93133
|
+
state_file: stateFilePath,
|
|
93134
|
+
base_url: baseUrl
|
|
93135
|
+
};
|
|
93136
|
+
}
|
|
93137
|
+
return yield* startPluginServer(params3);
|
|
93138
|
+
});
|
|
93139
|
+
}
|
|
93140
|
+
|
|
93141
|
+
// src/commands/ws/_shared.ts
|
|
93142
|
+
import path21 from "node:path";
|
|
93143
|
+
var WS_HEALTH_TIMEOUT_MS = 2000;
|
|
93144
|
+
var WS_START_WAIT_DEFAULT_MS = 15000;
|
|
93145
|
+
var WS_STOP_WAIT_DEFAULT_MS = 5000;
|
|
93146
|
+
function supervisorCommandLine(params3) {
|
|
93147
|
+
const command = process.argv[0];
|
|
93148
|
+
const script = process.argv[1];
|
|
93149
|
+
if (!command || !script) {
|
|
93150
|
+
throw new CliError({
|
|
93151
|
+
code: "INTERNAL",
|
|
93152
|
+
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
93153
|
+
exitCode: 1,
|
|
93154
|
+
details: { argv: process.argv }
|
|
93155
|
+
});
|
|
93156
|
+
}
|
|
93157
|
+
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
93158
|
+
return {
|
|
93159
|
+
command,
|
|
93160
|
+
args: [
|
|
93161
|
+
...execArgv,
|
|
93162
|
+
script,
|
|
93163
|
+
"--daemon-url",
|
|
93164
|
+
params3.wsUrl,
|
|
93165
|
+
"--store-db",
|
|
93166
|
+
params3.storeDb,
|
|
93167
|
+
"daemon",
|
|
93168
|
+
"supervisor",
|
|
93169
|
+
"--pid-file",
|
|
93170
|
+
params3.pidFile,
|
|
93171
|
+
"--log-file",
|
|
93172
|
+
params3.logFile,
|
|
93173
|
+
"--state-file",
|
|
93174
|
+
params3.stateFile
|
|
93175
|
+
]
|
|
93176
|
+
};
|
|
93177
|
+
}
|
|
93178
|
+
function toPidFileValue3(params3) {
|
|
93179
|
+
return {
|
|
93180
|
+
pid: params3.pid,
|
|
93181
|
+
build: currentRuntimeBuildInfo(),
|
|
93182
|
+
started_at: params3.startedAt,
|
|
93183
|
+
ws_url: params3.wsUrl,
|
|
93184
|
+
log_file: params3.logFile,
|
|
93185
|
+
cmd: params3.cmd,
|
|
93186
|
+
ws_bridge_state_file: params3.wsBridgeStateFile,
|
|
93187
|
+
status_line_file: params3.statusLineFile,
|
|
93188
|
+
status_line_json_file: params3.statusLineJsonFile
|
|
93189
|
+
};
|
|
93190
|
+
}
|
|
93191
|
+
function waitForHealth(url2, waitMs) {
|
|
93192
|
+
return gen2(function* () {
|
|
93193
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
93194
|
+
return yield* fail8(new CliError({
|
|
93195
|
+
code: "INVALID_ARGS",
|
|
93196
|
+
message: "--wait must be a non-negative integer (ms)",
|
|
93197
|
+
exitCode: 2,
|
|
93198
|
+
details: { wait_ms: waitMs }
|
|
93199
|
+
}));
|
|
93200
|
+
}
|
|
93201
|
+
if (waitMs === 0)
|
|
93202
|
+
return;
|
|
93203
|
+
const ws = yield* WsClient;
|
|
93204
|
+
const deadline = Date.now() + waitMs;
|
|
93205
|
+
while (Date.now() < deadline) {
|
|
93206
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
93207
|
+
const res = yield* ws.health({ url: url2, timeoutMs: Math.min(WS_HEALTH_TIMEOUT_MS, Math.max(1, remaining)) }).pipe(either3);
|
|
93208
|
+
if (isRight2(res))
|
|
93209
|
+
return;
|
|
93210
|
+
yield* sleep4(millis(300));
|
|
93211
|
+
}
|
|
93212
|
+
return yield* fail8(new CliError({
|
|
93213
|
+
code: "WS_TIMEOUT",
|
|
93214
|
+
message: `Timed out waiting for WS to become available (${waitMs}ms)`,
|
|
93215
|
+
exitCode: 1,
|
|
93216
|
+
details: { url: url2, wait_ms: waitMs },
|
|
93217
|
+
hint: ["agent-remnote daemon status", "agent-remnote daemon logs", "agent-remnote daemon health --json"]
|
|
93218
|
+
}));
|
|
93219
|
+
});
|
|
93220
|
+
}
|
|
93221
|
+
function toInitialSupervisorState(now2) {
|
|
93222
|
+
return {
|
|
93223
|
+
status: "running",
|
|
93224
|
+
restart_count: 0,
|
|
93225
|
+
restart_window_started_at: now2,
|
|
93226
|
+
backoff_until: null,
|
|
93227
|
+
last_exit: null,
|
|
93228
|
+
failed_reason: null
|
|
93229
|
+
};
|
|
93230
|
+
}
|
|
93231
|
+
function defaultStateFilePathFromPidFile(pidFilePath) {
|
|
93232
|
+
return path21.join(path21.dirname(pidFilePath), "ws.state.json");
|
|
93233
|
+
}
|
|
93234
|
+
function startWsSupervisor(params3) {
|
|
93235
|
+
return gen2(function* () {
|
|
93236
|
+
const cfg = yield* AppConfig;
|
|
93237
|
+
const daemonFiles = yield* DaemonFiles;
|
|
93238
|
+
const supervisorState = yield* SupervisorState;
|
|
93239
|
+
const proc = yield* Process;
|
|
93240
|
+
const ws = yield* WsClient;
|
|
93241
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? daemonFiles.defaultPidFile());
|
|
93242
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? daemonFiles.defaultLogFile());
|
|
93243
|
+
const stateFilePath = defaultStateFilePathFromPidFile(pidFilePath);
|
|
93244
|
+
const existingPidFile = yield* daemonFiles.readPidFile(pidFilePath);
|
|
93245
|
+
if (existingPidFile) {
|
|
93246
|
+
const alive = yield* proc.isPidRunning(existingPidFile.pid);
|
|
93247
|
+
if (!alive) {
|
|
93248
|
+
yield* daemonFiles.deletePidFile(pidFilePath);
|
|
93249
|
+
yield* supervisorState.deleteStateFile(stateFilePath);
|
|
93250
|
+
} else {
|
|
93251
|
+
yield* requireTrustedPidRecord({ record: existingPidFile, pidFilePath });
|
|
93252
|
+
return {
|
|
93253
|
+
started: false,
|
|
93254
|
+
pid: existingPidFile.pid,
|
|
93255
|
+
pid_file: pidFilePath,
|
|
93256
|
+
log_file: existingPidFile.log_file ?? logFilePath
|
|
93257
|
+
};
|
|
93258
|
+
}
|
|
93259
|
+
}
|
|
93260
|
+
const pre = yield* ws.health({ url: cfg.wsUrl, timeoutMs: WS_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
93261
|
+
if (isRight2(pre)) {
|
|
93262
|
+
return { started: false, pid_file: pidFilePath, log_file: logFilePath };
|
|
93263
|
+
}
|
|
93264
|
+
const cmd = yield* try_3({
|
|
93265
|
+
try: () => supervisorCommandLine({
|
|
93266
|
+
wsUrl: cfg.wsUrl,
|
|
93267
|
+
storeDb: cfg.storeDb,
|
|
93268
|
+
pidFile: pidFilePath,
|
|
93269
|
+
logFile: logFilePath,
|
|
93270
|
+
stateFile: stateFilePath
|
|
93271
|
+
}),
|
|
93272
|
+
catch: (e) => isCliError(e) ? e : new CliError({
|
|
93273
|
+
code: "INTERNAL",
|
|
93274
|
+
message: "Failed to start supervisor",
|
|
93275
|
+
exitCode: 1,
|
|
93276
|
+
details: { error: String(e?.message || e) }
|
|
93277
|
+
})
|
|
93278
|
+
});
|
|
93279
|
+
const pid = yield* proc.spawnDetached({ command: cmd.command, args: cmd.args, logFile: logFilePath });
|
|
93280
|
+
const now2 = Date.now();
|
|
93281
|
+
yield* daemonFiles.writePidFile(pidFilePath, {
|
|
93282
|
+
...toPidFileValue3({
|
|
93283
|
+
pid,
|
|
93284
|
+
startedAt: now2,
|
|
93285
|
+
wsUrl: cfg.wsUrl,
|
|
93286
|
+
logFile: logFilePath,
|
|
93287
|
+
cmd: [cmd.command, ...cmd.args],
|
|
93288
|
+
wsBridgeStateFile: cfg.wsStateFile.path,
|
|
93289
|
+
statusLineFile: cfg.statusLineFile,
|
|
93290
|
+
statusLineJsonFile: cfg.statusLineJsonFile
|
|
93291
|
+
}),
|
|
93292
|
+
mode: "supervisor",
|
|
93293
|
+
child_pid: null,
|
|
93294
|
+
state_file: stateFilePath
|
|
93295
|
+
});
|
|
93296
|
+
yield* supervisorState.writeStateFile(stateFilePath, toInitialSupervisorState(now2));
|
|
93297
|
+
yield* waitForHealth(cfg.wsUrl, params3.waitMs);
|
|
93298
|
+
return { started: true, pid, pid_file: pidFilePath, log_file: logFilePath };
|
|
93299
|
+
});
|
|
93300
|
+
}
|
|
93301
|
+
function ensureWsSupervisor(params3) {
|
|
93302
|
+
return gen2(function* () {
|
|
93303
|
+
const cfg = yield* AppConfig;
|
|
93304
|
+
const ws = yield* WsClient;
|
|
93305
|
+
const pre = yield* ws.health({ url: cfg.wsUrl, timeoutMs: WS_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
93306
|
+
if (isRight2(pre)) {
|
|
93307
|
+
const daemonFiles = yield* DaemonFiles;
|
|
93308
|
+
const proc = yield* Process;
|
|
93309
|
+
const pidFilePath = resolveUserFilePath(params3.pidFile ?? daemonFiles.defaultPidFile());
|
|
93310
|
+
const logFilePath = resolveUserFilePath(params3.logFile ?? daemonFiles.defaultLogFile());
|
|
93311
|
+
const existingPidFile = yield* daemonFiles.readPidFile(pidFilePath);
|
|
93312
|
+
if (existingPidFile) {
|
|
93313
|
+
const alive = yield* proc.isPidRunning(existingPidFile.pid);
|
|
93314
|
+
if (alive) {
|
|
93315
|
+
yield* requireTrustedPidRecord({ record: existingPidFile, pidFilePath });
|
|
93316
|
+
return {
|
|
93317
|
+
started: false,
|
|
93318
|
+
pid: existingPidFile.pid,
|
|
93319
|
+
pid_file: pidFilePath,
|
|
93320
|
+
log_file: existingPidFile.log_file ?? logFilePath
|
|
93321
|
+
};
|
|
93322
|
+
}
|
|
93323
|
+
}
|
|
93324
|
+
return {
|
|
93325
|
+
started: false,
|
|
93326
|
+
pid_file: pidFilePath,
|
|
93327
|
+
log_file: logFilePath
|
|
93328
|
+
};
|
|
93329
|
+
}
|
|
93330
|
+
return yield* startWsSupervisor(params3);
|
|
93331
|
+
});
|
|
93332
|
+
}
|
|
93333
|
+
|
|
93334
|
+
// src/lib/managedRuntimePaths.ts
|
|
93335
|
+
import path22 from "node:path";
|
|
93336
|
+
function resolveManagedStateFile(params3) {
|
|
93337
|
+
const defaultPath = resolveUserFilePath(params3.defaultStateFilePath);
|
|
93338
|
+
const explicitPath = params3.explicitStateFilePath ? resolveUserFilePath(params3.explicitStateFilePath) : undefined;
|
|
93339
|
+
const candidatePath = params3.candidate ? resolveUserFilePath(params3.candidate) : undefined;
|
|
93340
|
+
if (!candidatePath) {
|
|
93341
|
+
return explicitPath ?? defaultPath;
|
|
93342
|
+
}
|
|
93343
|
+
if (candidatePath === defaultPath)
|
|
93344
|
+
return candidatePath;
|
|
93345
|
+
if (explicitPath && candidatePath === explicitPath)
|
|
93346
|
+
return candidatePath;
|
|
93347
|
+
const pidRoot = path22.dirname(params3.pidFilePath);
|
|
93348
|
+
const rel = path22.relative(pidRoot, candidatePath);
|
|
93349
|
+
if (rel === "" || !rel.startsWith("..") && !path22.isAbsolute(rel)) {
|
|
93350
|
+
return candidatePath;
|
|
93351
|
+
}
|
|
93352
|
+
return explicitPath ?? defaultPath;
|
|
93353
|
+
}
|
|
93354
|
+
|
|
93355
|
+
// src/lib/pluginBuildInfo.ts
|
|
93356
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
93357
|
+
import path24 from "node:path";
|
|
93358
|
+
|
|
93359
|
+
// src/lib/pluginArtifacts.ts
|
|
93360
|
+
import { existsSync as existsSync3, statSync as statSync2 } from "node:fs";
|
|
93361
|
+
import path23 from "node:path";
|
|
93362
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
93363
|
+
function currentDir(moduleUrl) {
|
|
93364
|
+
return path23.dirname(fileURLToPath4(moduleUrl));
|
|
93365
|
+
}
|
|
93366
|
+
function isDirectory(targetPath) {
|
|
93367
|
+
try {
|
|
93368
|
+
return statSync2(targetPath).isDirectory();
|
|
93369
|
+
} catch {
|
|
93370
|
+
return false;
|
|
93371
|
+
}
|
|
93372
|
+
}
|
|
93373
|
+
function isFile(targetPath) {
|
|
93374
|
+
try {
|
|
93375
|
+
return statSync2(targetPath).isFile();
|
|
93376
|
+
} catch {
|
|
93377
|
+
return false;
|
|
93378
|
+
}
|
|
93379
|
+
}
|
|
93380
|
+
function distCandidates(moduleUrl) {
|
|
93381
|
+
const dir2 = currentDir(moduleUrl);
|
|
93382
|
+
return [
|
|
93383
|
+
path23.resolve(dir2, "../../plugin-artifacts/dist"),
|
|
93384
|
+
path23.resolve(dir2, "../plugin-artifacts/dist"),
|
|
93385
|
+
path23.resolve(dir2, "../../../plugin/dist"),
|
|
93386
|
+
path23.resolve(dir2, "../../plugin/dist")
|
|
93387
|
+
];
|
|
93388
|
+
}
|
|
93389
|
+
function zipCandidates(moduleUrl) {
|
|
93390
|
+
const dir2 = currentDir(moduleUrl);
|
|
93391
|
+
return [
|
|
93392
|
+
path23.resolve(dir2, "../../plugin-artifacts/PluginZip.zip"),
|
|
93393
|
+
path23.resolve(dir2, "../plugin-artifacts/PluginZip.zip"),
|
|
93394
|
+
path23.resolve(dir2, "../../../plugin/PluginZip.zip"),
|
|
93395
|
+
path23.resolve(dir2, "../../plugin/PluginZip.zip")
|
|
93396
|
+
];
|
|
93397
|
+
}
|
|
93398
|
+
function validateDistPath(targetPath) {
|
|
93399
|
+
return isDirectory(targetPath) && existsSync3(path23.join(targetPath, "manifest.json"));
|
|
93400
|
+
}
|
|
93401
|
+
function hasBuildInfo(targetPath) {
|
|
93402
|
+
return isFile(path23.join(targetPath, "build-info.json"));
|
|
93403
|
+
}
|
|
93404
|
+
function resolvePluginDistPath(moduleUrl = import.meta.url) {
|
|
93405
|
+
for (const candidate of distCandidates(moduleUrl)) {
|
|
93406
|
+
if (validateDistPath(candidate) && hasBuildInfo(candidate))
|
|
93407
|
+
return candidate;
|
|
93408
|
+
}
|
|
93409
|
+
for (const candidate of distCandidates(moduleUrl)) {
|
|
93410
|
+
if (validateDistPath(candidate))
|
|
93411
|
+
return candidate;
|
|
93412
|
+
}
|
|
93413
|
+
throw new CliError({
|
|
93414
|
+
code: "DEPENDENCY_MISSING",
|
|
93415
|
+
message: "Plugin build artifacts are unavailable",
|
|
93416
|
+
exitCode: 1,
|
|
93417
|
+
details: { candidates: distCandidates(moduleUrl) },
|
|
93418
|
+
hint: [
|
|
93419
|
+
"Run npm run build --workspace @remnote/plugin in the repository checkout",
|
|
93420
|
+
"Or install a packaged agent-remnote release that includes plugin artifacts"
|
|
93421
|
+
]
|
|
93422
|
+
});
|
|
93423
|
+
}
|
|
93424
|
+
function resolvePluginZipPath(moduleUrl = import.meta.url) {
|
|
93425
|
+
for (const candidate of zipCandidates(moduleUrl)) {
|
|
93426
|
+
if (isFile(candidate))
|
|
93427
|
+
return candidate;
|
|
93428
|
+
}
|
|
93429
|
+
throw new CliError({
|
|
93430
|
+
code: "DEPENDENCY_MISSING",
|
|
93431
|
+
message: "Plugin zip artifact is unavailable",
|
|
93432
|
+
exitCode: 1,
|
|
93433
|
+
details: { candidates: zipCandidates(moduleUrl) },
|
|
93434
|
+
hint: [
|
|
93435
|
+
"Run npm run build --workspace @remnote/plugin in the repository checkout",
|
|
93436
|
+
"Or install a packaged agent-remnote release that includes plugin artifacts"
|
|
93437
|
+
]
|
|
93438
|
+
});
|
|
93439
|
+
}
|
|
93440
|
+
|
|
93441
|
+
// src/lib/pluginBuildInfo.ts
|
|
93442
|
+
function readPluginDistBuildInfo(distPath) {
|
|
93443
|
+
const normalized = typeof distPath === "string" ? distPath.trim() : "";
|
|
93444
|
+
if (!normalized)
|
|
93445
|
+
return null;
|
|
93446
|
+
const target2 = path24.join(normalized, "build-info.json");
|
|
93447
|
+
try {
|
|
93448
|
+
const raw4 = readFileSync3(target2, "utf8");
|
|
93449
|
+
const parsed = JSON.parse(raw4);
|
|
93450
|
+
if (typeof parsed?.name === "string" && typeof parsed?.version === "string" && typeof parsed?.build_id === "string" && typeof parsed?.built_at === "number" && typeof parsed?.source_stamp === "number") {
|
|
93451
|
+
return {
|
|
93452
|
+
name: parsed.name,
|
|
93453
|
+
version: parsed.version,
|
|
93454
|
+
build_id: parsed.build_id,
|
|
93455
|
+
built_at: parsed.built_at,
|
|
93456
|
+
source_stamp: parsed.source_stamp,
|
|
93457
|
+
mode: parsed.mode === "src" || parsed.mode === "dist" || parsed.mode === "unknown" ? parsed.mode : "dist"
|
|
93458
|
+
};
|
|
93459
|
+
}
|
|
93460
|
+
} catch {}
|
|
93461
|
+
return null;
|
|
93462
|
+
}
|
|
93463
|
+
function currentExpectedPluginBuildInfo() {
|
|
93464
|
+
try {
|
|
93465
|
+
const dist = resolvePluginDistPath();
|
|
93466
|
+
return readPluginDistBuildInfo(dist);
|
|
93467
|
+
} catch {
|
|
93468
|
+
return null;
|
|
93469
|
+
}
|
|
93470
|
+
}
|
|
93471
|
+
function pluginBuildWarnings(params3) {
|
|
93472
|
+
if (!params3.expected || !params3.live)
|
|
93473
|
+
return [];
|
|
93474
|
+
if (params3.expected.build_id === params3.live.build_id)
|
|
93475
|
+
return [];
|
|
93476
|
+
return [
|
|
93477
|
+
`plugin build mismatch: expected=${params3.expected.build_id} live=${params3.live.build_id}`
|
|
93478
|
+
];
|
|
93479
|
+
}
|
|
93480
|
+
|
|
93481
|
+
// src/lib/statuslineArtifacts.ts
|
|
93482
|
+
import { promises as fs15 } from "node:fs";
|
|
93483
|
+
|
|
93484
|
+
// src/services/StatusLineFile.ts
|
|
93485
|
+
import { promises as fs14 } from "node:fs";
|
|
93486
|
+
import path25 from "node:path";
|
|
93487
|
+
class StatusLineFile extends Tag2("StatusLineFile")() {
|
|
93488
|
+
}
|
|
93489
|
+
function defaultTextFile() {
|
|
93490
|
+
return path25.join(homeDir(), ".agent-remnote", "status-line.txt");
|
|
93491
|
+
}
|
|
93492
|
+
function defaultJsonFile() {
|
|
93493
|
+
return path25.join(homeDir(), ".agent-remnote", "status-line.json");
|
|
93494
|
+
}
|
|
93495
|
+
function ensureDir8(p3) {
|
|
93496
|
+
return fs14.mkdir(path25.dirname(p3), { recursive: true }).then(() => {
|
|
93497
|
+
return;
|
|
93498
|
+
});
|
|
93499
|
+
}
|
|
93500
|
+
async function readFileOrEmpty(filePath) {
|
|
93501
|
+
try {
|
|
93502
|
+
return await fs14.readFile(filePath, "utf8");
|
|
93503
|
+
} catch (e) {
|
|
93504
|
+
if (e?.code === "ENOENT")
|
|
93505
|
+
return "";
|
|
93506
|
+
throw e;
|
|
92463
93507
|
}
|
|
92464
93508
|
}
|
|
92465
93509
|
async function writeTextAtomic(filePath, content) {
|
|
@@ -92544,6 +93588,26 @@ function cleanupStatuslineArtifacts(paths) {
|
|
|
92544
93588
|
}
|
|
92545
93589
|
|
|
92546
93590
|
// src/lib/doctor/fixes.ts
|
|
93591
|
+
function stopTrustedRuntime(params3) {
|
|
93592
|
+
return gen2(function* () {
|
|
93593
|
+
const proc = yield* Process;
|
|
93594
|
+
yield* proc.kill(params3.pid, "SIGTERM");
|
|
93595
|
+
const exited = yield* proc.waitForExit({ pid: params3.pid, timeoutMs: params3.stopWaitMs });
|
|
93596
|
+
if (!exited) {
|
|
93597
|
+
yield* proc.kill(params3.pid, "SIGKILL");
|
|
93598
|
+
const killed = yield* proc.waitForExit({ pid: params3.pid, timeoutMs: params3.stopWaitMs });
|
|
93599
|
+
if (!killed) {
|
|
93600
|
+
return yield* fail8(new CliError({
|
|
93601
|
+
code: "INTERNAL",
|
|
93602
|
+
message: `Failed to stop mismatched ${params3.service} runtime`,
|
|
93603
|
+
exitCode: 1,
|
|
93604
|
+
details: { pid: params3.pid, pid_file: params3.pidFilePath, state_file: params3.stateFilePath }
|
|
93605
|
+
}));
|
|
93606
|
+
}
|
|
93607
|
+
}
|
|
93608
|
+
yield* params3.cleanup;
|
|
93609
|
+
});
|
|
93610
|
+
}
|
|
92547
93611
|
function applyDoctorFixes() {
|
|
92548
93612
|
return gen2(function* () {
|
|
92549
93613
|
const cfg = yield* AppConfig;
|
|
@@ -92557,6 +93621,7 @@ function applyDoctorFixes() {
|
|
|
92557
93621
|
const fixes = [];
|
|
92558
93622
|
const cleaned = [];
|
|
92559
93623
|
const cleanupFailures = [];
|
|
93624
|
+
const current2 = currentRuntimeBuildInfo();
|
|
92560
93625
|
const daemonPidFile = daemonFiles.defaultPidFile();
|
|
92561
93626
|
const daemonPidInfo = yield* daemonFiles.readPidFile(daemonPidFile).pipe(orElseSucceed2(() => {
|
|
92562
93627
|
return;
|
|
@@ -92639,6 +93704,14 @@ function applyDoctorFixes() {
|
|
|
92639
93704
|
});
|
|
92640
93705
|
}
|
|
92641
93706
|
}
|
|
93707
|
+
const resolvedPluginStateFile = resolveManagedStateFile({
|
|
93708
|
+
pidFilePath: pluginPidFile,
|
|
93709
|
+
defaultStateFilePath: pluginFiles.defaultStateFile(),
|
|
93710
|
+
candidate: pluginPidInfo?.state_file
|
|
93711
|
+
});
|
|
93712
|
+
const pluginStateInfo = yield* pluginFiles.readStateFile(resolvedPluginStateFile).pipe(orElseSucceed2(() => {
|
|
93713
|
+
return;
|
|
93714
|
+
}));
|
|
92642
93715
|
fixes.push({
|
|
92643
93716
|
id: "runtime.cleanup_stale_artifacts",
|
|
92644
93717
|
ok: cleanupFailures.length === 0,
|
|
@@ -92673,17 +93746,155 @@ function applyDoctorFixes() {
|
|
|
92673
93746
|
details: { error: configRepair.left.message }
|
|
92674
93747
|
});
|
|
92675
93748
|
}
|
|
93749
|
+
const restartAttempted = [];
|
|
93750
|
+
const restartRestarted = [];
|
|
93751
|
+
const restartSkipped = [];
|
|
93752
|
+
const restartFailed = [];
|
|
93753
|
+
const expectedPlugin = currentExpectedPluginBuildInfo();
|
|
93754
|
+
const daemonNeedsRestart = daemonPidInfo?.pid && daemonPidInfo.build?.build_id && daemonPidInfo.build.build_id !== current2.build_id && daemonPidInfo.mode === "supervisor" && (yield* isTrustedPidRecord(daemonPidInfo));
|
|
93755
|
+
if (daemonNeedsRestart) {
|
|
93756
|
+
const daemonStateFile = resolveManagedStateFile({
|
|
93757
|
+
pidFilePath: daemonPidFile,
|
|
93758
|
+
defaultStateFilePath: supervisorState.defaultStateFile(),
|
|
93759
|
+
candidate: daemonPidInfo.state_file
|
|
93760
|
+
});
|
|
93761
|
+
restartAttempted.push("daemon");
|
|
93762
|
+
const stopped = yield* stopTrustedRuntime({
|
|
93763
|
+
service: "daemon",
|
|
93764
|
+
pid: daemonPidInfo.pid,
|
|
93765
|
+
pidFilePath: daemonPidFile,
|
|
93766
|
+
stateFilePath: daemonStateFile,
|
|
93767
|
+
stopWaitMs: WS_STOP_WAIT_DEFAULT_MS,
|
|
93768
|
+
cleanup: gen2(function* () {
|
|
93769
|
+
yield* daemonFiles.deletePidFile(daemonPidFile);
|
|
93770
|
+
yield* supervisorState.deleteStateFile(daemonStateFile);
|
|
93771
|
+
yield* cleanupStatuslineArtifacts(resolveStatuslineArtifactPaths({ cfg, pidInfo: daemonPidInfo }));
|
|
93772
|
+
})
|
|
93773
|
+
}).pipe(either3);
|
|
93774
|
+
if (stopped._tag === "Right") {
|
|
93775
|
+
changed = true;
|
|
93776
|
+
const started = yield* startWsSupervisor({
|
|
93777
|
+
waitMs: WS_START_WAIT_DEFAULT_MS,
|
|
93778
|
+
pidFile: daemonPidFile,
|
|
93779
|
+
logFile: daemonPidInfo.log_file
|
|
93780
|
+
}).pipe(either3);
|
|
93781
|
+
if (started._tag === "Right") {
|
|
93782
|
+
if (started.right.started) {
|
|
93783
|
+
restartRestarted.push("daemon");
|
|
93784
|
+
} else {
|
|
93785
|
+
restartSkipped.push("daemon_already_healthy_after_restart_attempt");
|
|
93786
|
+
}
|
|
93787
|
+
} else {
|
|
93788
|
+
restartFailed.push({ service: "daemon", error: started.left.message });
|
|
93789
|
+
}
|
|
93790
|
+
} else {
|
|
93791
|
+
restartFailed.push({ service: "daemon", error: stopped.left.message });
|
|
93792
|
+
}
|
|
93793
|
+
} else if (daemonPidInfo?.build?.build_id && daemonPidInfo.build.build_id !== current2.build_id) {
|
|
93794
|
+
restartSkipped.push("daemon_restart_not_safe");
|
|
93795
|
+
}
|
|
93796
|
+
const apiNeedsRestart = apiPidInfo?.pid && apiPidInfo.build?.build_id && apiPidInfo.build.build_id !== current2.build_id && (yield* isTrustedPidRecord(apiPidInfo));
|
|
93797
|
+
if (apiNeedsRestart) {
|
|
93798
|
+
const apiStateFile = resolveManagedStateFile({
|
|
93799
|
+
pidFilePath: apiPidFile,
|
|
93800
|
+
defaultStateFilePath: apiFiles.defaultStateFile(),
|
|
93801
|
+
candidate: apiPidInfo.state_file
|
|
93802
|
+
});
|
|
93803
|
+
restartAttempted.push("api");
|
|
93804
|
+
const stopped = yield* stopTrustedRuntime({
|
|
93805
|
+
service: "api",
|
|
93806
|
+
pid: apiPidInfo.pid,
|
|
93807
|
+
pidFilePath: apiPidFile,
|
|
93808
|
+
stateFilePath: apiStateFile,
|
|
93809
|
+
stopWaitMs: API_STOP_WAIT_DEFAULT_MS,
|
|
93810
|
+
cleanup: gen2(function* () {
|
|
93811
|
+
yield* apiFiles.deletePidFile(apiPidFile);
|
|
93812
|
+
yield* apiFiles.deleteStateFile(apiStateFile);
|
|
93813
|
+
})
|
|
93814
|
+
}).pipe(either3);
|
|
93815
|
+
if (stopped._tag === "Right") {
|
|
93816
|
+
changed = true;
|
|
93817
|
+
const started = yield* startApiDaemon({
|
|
93818
|
+
host: apiPidInfo.host,
|
|
93819
|
+
port: apiPidInfo.port,
|
|
93820
|
+
basePath: apiPidInfo.base_path,
|
|
93821
|
+
waitMs: API_START_WAIT_DEFAULT_MS,
|
|
93822
|
+
pidFile: apiPidFile,
|
|
93823
|
+
logFile: apiPidInfo.log_file,
|
|
93824
|
+
stateFile: apiStateFile
|
|
93825
|
+
}).pipe(either3);
|
|
93826
|
+
if (started._tag === "Right") {
|
|
93827
|
+
if (started.right.started) {
|
|
93828
|
+
restartRestarted.push("api");
|
|
93829
|
+
} else {
|
|
93830
|
+
restartSkipped.push("api_already_healthy_after_restart_attempt");
|
|
93831
|
+
}
|
|
93832
|
+
} else {
|
|
93833
|
+
restartFailed.push({ service: "api", error: started.left.message });
|
|
93834
|
+
}
|
|
93835
|
+
} else {
|
|
93836
|
+
restartFailed.push({ service: "api", error: stopped.left.message });
|
|
93837
|
+
}
|
|
93838
|
+
} else if (apiPidInfo?.build?.build_id && apiPidInfo.build.build_id !== current2.build_id) {
|
|
93839
|
+
restartSkipped.push("api_restart_not_safe");
|
|
93840
|
+
}
|
|
93841
|
+
const pluginArtifactMismatch = expectedPlugin && pluginStateInfo?.plugin_build?.build_id && pluginStateInfo.plugin_build.build_id !== expectedPlugin.build_id;
|
|
93842
|
+
const pluginRuntimeMismatch = pluginPidInfo?.build?.build_id && pluginPidInfo.build.build_id !== current2.build_id;
|
|
93843
|
+
const pluginNeedsRestart = pluginPidInfo?.pid && (pluginRuntimeMismatch || pluginArtifactMismatch) && (yield* isTrustedPidRecord(pluginPidInfo));
|
|
93844
|
+
if (pluginNeedsRestart) {
|
|
93845
|
+
const pluginStateFile = resolveManagedStateFile({
|
|
93846
|
+
pidFilePath: pluginPidFile,
|
|
93847
|
+
defaultStateFilePath: pluginFiles.defaultStateFile(),
|
|
93848
|
+
candidate: pluginPidInfo.state_file
|
|
93849
|
+
});
|
|
93850
|
+
restartAttempted.push("plugin");
|
|
93851
|
+
const stopped = yield* stopTrustedRuntime({
|
|
93852
|
+
service: "plugin",
|
|
93853
|
+
pid: pluginPidInfo.pid,
|
|
93854
|
+
pidFilePath: pluginPidFile,
|
|
93855
|
+
stateFilePath: pluginStateFile,
|
|
93856
|
+
stopWaitMs: PLUGIN_SERVER_STOP_WAIT_DEFAULT_MS,
|
|
93857
|
+
cleanup: gen2(function* () {
|
|
93858
|
+
yield* pluginFiles.deletePidFile(pluginPidFile);
|
|
93859
|
+
yield* pluginFiles.deleteStateFile(pluginStateFile);
|
|
93860
|
+
})
|
|
93861
|
+
}).pipe(either3);
|
|
93862
|
+
if (stopped._tag === "Right") {
|
|
93863
|
+
changed = true;
|
|
93864
|
+
const started = yield* startPluginServer({
|
|
93865
|
+
host: pluginPidInfo.host,
|
|
93866
|
+
port: pluginPidInfo.port,
|
|
93867
|
+
waitMs: PLUGIN_SERVER_START_WAIT_DEFAULT_MS,
|
|
93868
|
+
pidFile: pluginPidFile,
|
|
93869
|
+
logFile: pluginPidInfo.log_file,
|
|
93870
|
+
stateFile: pluginStateFile
|
|
93871
|
+
}).pipe(either3);
|
|
93872
|
+
if (started._tag === "Right") {
|
|
93873
|
+
if (started.right.started) {
|
|
93874
|
+
restartRestarted.push("plugin");
|
|
93875
|
+
} else {
|
|
93876
|
+
restartSkipped.push("plugin_already_healthy_after_restart_attempt");
|
|
93877
|
+
}
|
|
93878
|
+
} else {
|
|
93879
|
+
restartFailed.push({ service: "plugin", error: started.left.message });
|
|
93880
|
+
}
|
|
93881
|
+
} else {
|
|
93882
|
+
restartFailed.push({ service: "plugin", error: stopped.left.message });
|
|
93883
|
+
}
|
|
93884
|
+
} else if (pluginRuntimeMismatch || pluginArtifactMismatch) {
|
|
93885
|
+
restartSkipped.push("plugin_restart_not_safe");
|
|
93886
|
+
}
|
|
92676
93887
|
const restartSummary = {
|
|
92677
|
-
attempted:
|
|
92678
|
-
restarted:
|
|
92679
|
-
skipped:
|
|
92680
|
-
failed:
|
|
93888
|
+
attempted: restartAttempted,
|
|
93889
|
+
restarted: restartRestarted,
|
|
93890
|
+
skipped: restartSkipped,
|
|
93891
|
+
failed: restartFailed
|
|
92681
93892
|
};
|
|
92682
93893
|
fixes.push({
|
|
92683
93894
|
id: "runtime.restart_mismatched_services",
|
|
92684
|
-
ok:
|
|
92685
|
-
changed:
|
|
92686
|
-
summary: "
|
|
93895
|
+
ok: restartFailed.length === 0,
|
|
93896
|
+
changed: restartRestarted.length > 0,
|
|
93897
|
+
summary: restartAttempted.length === 0 ? "No trusted runtime build mismatches required automatic restart" : restartFailed.length === 0 ? `Restarted ${restartRestarted.length} mismatched runtime service(s)` : `Restarted ${restartRestarted.length} mismatched runtime service(s); ${restartFailed.length} restart(s) failed`,
|
|
92687
93898
|
details: restartSummary
|
|
92688
93899
|
});
|
|
92689
93900
|
return { fixes, changed, restartSummary };
|
|
@@ -92691,40 +93902,40 @@ function applyDoctorFixes() {
|
|
|
92691
93902
|
}
|
|
92692
93903
|
|
|
92693
93904
|
// src/lib/doctor/checks.ts
|
|
92694
|
-
import
|
|
93905
|
+
import path27 from "node:path";
|
|
92695
93906
|
|
|
92696
93907
|
// src/lib/builtin-scenarios/index.ts
|
|
92697
|
-
import { existsSync as
|
|
92698
|
-
import
|
|
92699
|
-
import { fileURLToPath as
|
|
92700
|
-
var MODULE_DIR =
|
|
93908
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
93909
|
+
import path26 from "node:path";
|
|
93910
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
93911
|
+
var MODULE_DIR = path26.dirname(fileURLToPath5(import.meta.url));
|
|
92701
93912
|
function locateBuiltinSourceRoot() {
|
|
92702
93913
|
const packageRootCandidates = [
|
|
92703
|
-
|
|
92704
|
-
|
|
93914
|
+
path26.resolve(MODULE_DIR, "../../../"),
|
|
93915
|
+
path26.resolve(MODULE_DIR, "..")
|
|
92705
93916
|
];
|
|
92706
93917
|
for (const packageRoot of packageRootCandidates) {
|
|
92707
|
-
const builtinSourceRoot =
|
|
92708
|
-
if (
|
|
93918
|
+
const builtinSourceRoot = path26.join(packageRoot, "builtin-scenarios");
|
|
93919
|
+
if (existsSync4(path26.join(builtinSourceRoot, "catalog.json"))) {
|
|
92709
93920
|
return { packageRoot, builtinSourceRoot };
|
|
92710
93921
|
}
|
|
92711
93922
|
}
|
|
92712
93923
|
throw new Error(`Unable to locate builtin-scenarios catalog from ${MODULE_DIR}`);
|
|
92713
93924
|
}
|
|
92714
93925
|
var { packageRoot: PACKAGE_ROOT, builtinSourceRoot: BUILTIN_SOURCE_ROOT } = locateBuiltinSourceRoot();
|
|
92715
|
-
var REPO_ROOT =
|
|
92716
|
-
var BUILTIN_CATALOG_PATH =
|
|
93926
|
+
var REPO_ROOT = path26.resolve(PACKAGE_ROOT, "../..");
|
|
93927
|
+
var BUILTIN_CATALOG_PATH = path26.join(BUILTIN_SOURCE_ROOT, "catalog.json");
|
|
92717
93928
|
var BUILTIN_SOURCE_PREFIX = "packages/agent-remnote/builtin-scenarios/";
|
|
92718
93929
|
function readJsonFile(filePath) {
|
|
92719
|
-
return JSON.parse(
|
|
93930
|
+
return JSON.parse(readFileSync4(filePath, "utf8"));
|
|
92720
93931
|
}
|
|
92721
93932
|
function resolveRepoPath(relPath) {
|
|
92722
|
-
return
|
|
93933
|
+
return path26.resolve(REPO_ROOT, relPath);
|
|
92723
93934
|
}
|
|
92724
93935
|
function resolveBuiltinPackagePath(relPath) {
|
|
92725
93936
|
const normalized = relPath.replaceAll("\\", "/");
|
|
92726
93937
|
if (normalized.startsWith(BUILTIN_SOURCE_PREFIX)) {
|
|
92727
|
-
return
|
|
93938
|
+
return path26.resolve(BUILTIN_SOURCE_ROOT, normalized.slice(BUILTIN_SOURCE_PREFIX.length));
|
|
92728
93939
|
}
|
|
92729
93940
|
return resolveRepoPath(relPath);
|
|
92730
93941
|
}
|
|
@@ -92732,275 +93943,34 @@ var builtinScenarioCatalog = readJsonFile(BUILTIN_CATALOG_PATH);
|
|
|
92732
93943
|
var builtinScenarioPackageCache = new Map;
|
|
92733
93944
|
var builtinScenarioPackagesTarget = {};
|
|
92734
93945
|
function loadBuiltinScenarioPackage(entry) {
|
|
92735
|
-
const
|
|
92736
|
-
if (
|
|
92737
|
-
return
|
|
93946
|
+
const cached5 = builtinScenarioPackageCache.get(entry.package_id);
|
|
93947
|
+
if (cached5)
|
|
93948
|
+
return cached5;
|
|
92738
93949
|
const loaded = readJsonFile(resolveBuiltinPackagePath(entry.package_path));
|
|
92739
93950
|
builtinScenarioPackageCache.set(entry.package_id, loaded);
|
|
92740
93951
|
return loaded;
|
|
92741
93952
|
}
|
|
92742
|
-
for (const entry of builtinScenarioCatalog) {
|
|
92743
|
-
Object.defineProperty(builtinScenarioPackagesTarget, entry.package_id, {
|
|
92744
|
-
enumerable: true,
|
|
92745
|
-
configurable: false,
|
|
92746
|
-
get: () => loadBuiltinScenarioPackage(entry)
|
|
92747
|
-
});
|
|
92748
|
-
}
|
|
92749
|
-
var builtinScenarioPackages = Object.freeze(builtinScenarioPackagesTarget);
|
|
92750
|
-
function getBuiltinScenarioPackage(id2) {
|
|
92751
|
-
const entry = builtinScenarioCatalog.find((item) => item.package_id === id2);
|
|
92752
|
-
if (!entry) {
|
|
92753
|
-
throw new Error(`Unknown builtin scenario package: ${id2}`);
|
|
92754
|
-
}
|
|
92755
|
-
return loadBuiltinScenarioPackage(entry);
|
|
92756
|
-
}
|
|
92757
|
-
function getBuiltinScenarioPackageSourcePath(id2) {
|
|
92758
|
-
const entry = builtinScenarioCatalog.find((item) => item.package_id === id2);
|
|
92759
|
-
if (!entry) {
|
|
92760
|
-
throw new Error(`Unknown builtin scenario source: ${id2}`);
|
|
92761
|
-
}
|
|
92762
|
-
return resolveBuiltinPackagePath(entry.package_path);
|
|
92763
|
-
}
|
|
92764
|
-
|
|
92765
|
-
// src/lib/pluginBuildInfo.ts
|
|
92766
|
-
import { readFileSync as readFileSync3 } from "node:fs";
|
|
92767
|
-
import path24 from "node:path";
|
|
92768
|
-
|
|
92769
|
-
// src/lib/pluginArtifacts.ts
|
|
92770
|
-
import { existsSync as existsSync3, statSync } from "node:fs";
|
|
92771
|
-
import path23 from "node:path";
|
|
92772
|
-
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
92773
|
-
function currentDir(moduleUrl) {
|
|
92774
|
-
return path23.dirname(fileURLToPath4(moduleUrl));
|
|
92775
|
-
}
|
|
92776
|
-
function isDirectory(targetPath) {
|
|
92777
|
-
try {
|
|
92778
|
-
return statSync(targetPath).isDirectory();
|
|
92779
|
-
} catch {
|
|
92780
|
-
return false;
|
|
92781
|
-
}
|
|
92782
|
-
}
|
|
92783
|
-
function isFile(targetPath) {
|
|
92784
|
-
try {
|
|
92785
|
-
return statSync(targetPath).isFile();
|
|
92786
|
-
} catch {
|
|
92787
|
-
return false;
|
|
92788
|
-
}
|
|
92789
|
-
}
|
|
92790
|
-
function distCandidates(moduleUrl) {
|
|
92791
|
-
const dir2 = currentDir(moduleUrl);
|
|
92792
|
-
return [
|
|
92793
|
-
path23.resolve(dir2, "../../plugin-artifacts/dist"),
|
|
92794
|
-
path23.resolve(dir2, "../plugin-artifacts/dist"),
|
|
92795
|
-
path23.resolve(dir2, "../../../plugin/dist"),
|
|
92796
|
-
path23.resolve(dir2, "../../plugin/dist")
|
|
92797
|
-
];
|
|
92798
|
-
}
|
|
92799
|
-
function zipCandidates(moduleUrl) {
|
|
92800
|
-
const dir2 = currentDir(moduleUrl);
|
|
92801
|
-
return [
|
|
92802
|
-
path23.resolve(dir2, "../../plugin-artifacts/PluginZip.zip"),
|
|
92803
|
-
path23.resolve(dir2, "../plugin-artifacts/PluginZip.zip"),
|
|
92804
|
-
path23.resolve(dir2, "../../../plugin/PluginZip.zip"),
|
|
92805
|
-
path23.resolve(dir2, "../../plugin/PluginZip.zip")
|
|
92806
|
-
];
|
|
92807
|
-
}
|
|
92808
|
-
function validateDistPath(targetPath) {
|
|
92809
|
-
return isDirectory(targetPath) && existsSync3(path23.join(targetPath, "manifest.json"));
|
|
92810
|
-
}
|
|
92811
|
-
function hasBuildInfo(targetPath) {
|
|
92812
|
-
return isFile(path23.join(targetPath, "build-info.json"));
|
|
92813
|
-
}
|
|
92814
|
-
function resolvePluginDistPath(moduleUrl = import.meta.url) {
|
|
92815
|
-
for (const candidate of distCandidates(moduleUrl)) {
|
|
92816
|
-
if (validateDistPath(candidate) && hasBuildInfo(candidate))
|
|
92817
|
-
return candidate;
|
|
92818
|
-
}
|
|
92819
|
-
for (const candidate of distCandidates(moduleUrl)) {
|
|
92820
|
-
if (validateDistPath(candidate))
|
|
92821
|
-
return candidate;
|
|
92822
|
-
}
|
|
92823
|
-
throw new CliError({
|
|
92824
|
-
code: "DEPENDENCY_MISSING",
|
|
92825
|
-
message: "Plugin build artifacts are unavailable",
|
|
92826
|
-
exitCode: 1,
|
|
92827
|
-
details: { candidates: distCandidates(moduleUrl) },
|
|
92828
|
-
hint: [
|
|
92829
|
-
"Run npm run build --workspace @remnote/plugin in the repository checkout",
|
|
92830
|
-
"Or install a packaged agent-remnote release that includes plugin artifacts"
|
|
92831
|
-
]
|
|
92832
|
-
});
|
|
92833
|
-
}
|
|
92834
|
-
function resolvePluginZipPath(moduleUrl = import.meta.url) {
|
|
92835
|
-
for (const candidate of zipCandidates(moduleUrl)) {
|
|
92836
|
-
if (isFile(candidate))
|
|
92837
|
-
return candidate;
|
|
92838
|
-
}
|
|
92839
|
-
throw new CliError({
|
|
92840
|
-
code: "DEPENDENCY_MISSING",
|
|
92841
|
-
message: "Plugin zip artifact is unavailable",
|
|
92842
|
-
exitCode: 1,
|
|
92843
|
-
details: { candidates: zipCandidates(moduleUrl) },
|
|
92844
|
-
hint: [
|
|
92845
|
-
"Run npm run build --workspace @remnote/plugin in the repository checkout",
|
|
92846
|
-
"Or install a packaged agent-remnote release that includes plugin artifacts"
|
|
92847
|
-
]
|
|
92848
|
-
});
|
|
92849
|
-
}
|
|
92850
|
-
|
|
92851
|
-
// src/lib/pluginBuildInfo.ts
|
|
92852
|
-
function readPluginDistBuildInfo(distPath) {
|
|
92853
|
-
const normalized = typeof distPath === "string" ? distPath.trim() : "";
|
|
92854
|
-
if (!normalized)
|
|
92855
|
-
return null;
|
|
92856
|
-
const target2 = path24.join(normalized, "build-info.json");
|
|
92857
|
-
try {
|
|
92858
|
-
const raw4 = readFileSync3(target2, "utf8");
|
|
92859
|
-
const parsed = JSON.parse(raw4);
|
|
92860
|
-
if (typeof parsed?.name === "string" && typeof parsed?.version === "string" && typeof parsed?.build_id === "string" && typeof parsed?.built_at === "number" && typeof parsed?.source_stamp === "number") {
|
|
92861
|
-
return {
|
|
92862
|
-
name: parsed.name,
|
|
92863
|
-
version: parsed.version,
|
|
92864
|
-
build_id: parsed.build_id,
|
|
92865
|
-
built_at: parsed.built_at,
|
|
92866
|
-
source_stamp: parsed.source_stamp,
|
|
92867
|
-
mode: parsed.mode === "src" || parsed.mode === "dist" || parsed.mode === "unknown" ? parsed.mode : "dist"
|
|
92868
|
-
};
|
|
92869
|
-
}
|
|
92870
|
-
} catch {}
|
|
92871
|
-
return null;
|
|
92872
|
-
}
|
|
92873
|
-
function currentExpectedPluginBuildInfo() {
|
|
92874
|
-
try {
|
|
92875
|
-
const dist = resolvePluginDistPath();
|
|
92876
|
-
return readPluginDistBuildInfo(dist);
|
|
92877
|
-
} catch {
|
|
92878
|
-
return null;
|
|
92879
|
-
}
|
|
92880
|
-
}
|
|
92881
|
-
function pluginBuildWarnings(params3) {
|
|
92882
|
-
if (!params3.expected || !params3.live)
|
|
92883
|
-
return [];
|
|
92884
|
-
if (params3.expected.build_id === params3.live.build_id)
|
|
92885
|
-
return [];
|
|
92886
|
-
return [
|
|
92887
|
-
`plugin build mismatch: expected=${params3.expected.build_id} live=${params3.live.build_id}`
|
|
92888
|
-
];
|
|
92889
|
-
}
|
|
92890
|
-
|
|
92891
|
-
// src/lib/runtimeBuildInfo.ts
|
|
92892
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
92893
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync, statSync as statSync2 } from "node:fs";
|
|
92894
|
-
import path25 from "node:path";
|
|
92895
|
-
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
92896
|
-
function packageInfo() {
|
|
92897
|
-
try {
|
|
92898
|
-
const raw4 = readFileSync4(new URL("../../package.json", import.meta.url), "utf8");
|
|
92899
|
-
const parsed = JSON.parse(raw4);
|
|
92900
|
-
const name = typeof parsed?.name === "string" && parsed.name.trim() ? parsed.name.trim() : "agent-remnote";
|
|
92901
|
-
const version = typeof parsed?.version === "string" && parsed.version.trim() ? parsed.version.trim() : "0.0.0";
|
|
92902
|
-
return { name, version };
|
|
92903
|
-
} catch {
|
|
92904
|
-
return { name: "agent-remnote", version: "0.0.0" };
|
|
92905
|
-
}
|
|
92906
|
-
}
|
|
92907
|
-
function fileMtimeMs(targetPath) {
|
|
92908
|
-
try {
|
|
92909
|
-
return Math.floor(statSync2(targetPath).mtimeMs);
|
|
92910
|
-
} catch {
|
|
92911
|
-
return 0;
|
|
92912
|
-
}
|
|
92913
|
-
}
|
|
92914
|
-
function latestMtimeMs(dirPath) {
|
|
92915
|
-
if (!existsSync4(dirPath))
|
|
92916
|
-
return 0;
|
|
92917
|
-
let max7 = 0;
|
|
92918
|
-
const stack = [dirPath];
|
|
92919
|
-
while (stack.length > 0) {
|
|
92920
|
-
const current2 = stack.pop();
|
|
92921
|
-
let entries2 = [];
|
|
92922
|
-
try {
|
|
92923
|
-
entries2 = readdirSync(current2);
|
|
92924
|
-
} catch {
|
|
92925
|
-
continue;
|
|
92926
|
-
}
|
|
92927
|
-
for (const entry of entries2) {
|
|
92928
|
-
const full = path25.join(current2, entry);
|
|
92929
|
-
let st;
|
|
92930
|
-
try {
|
|
92931
|
-
st = statSync2(full);
|
|
92932
|
-
} catch {
|
|
92933
|
-
continue;
|
|
92934
|
-
}
|
|
92935
|
-
if (st.isDirectory()) {
|
|
92936
|
-
stack.push(full);
|
|
92937
|
-
} else if (st.isFile()) {
|
|
92938
|
-
max7 = Math.max(max7, Math.floor(st.mtimeMs));
|
|
92939
|
-
}
|
|
92940
|
-
}
|
|
92941
|
-
}
|
|
92942
|
-
return max7;
|
|
92943
|
-
}
|
|
92944
|
-
function detectMode() {
|
|
92945
|
-
const url2 = import.meta.url;
|
|
92946
|
-
if (url2.includes("/src/"))
|
|
92947
|
-
return "src";
|
|
92948
|
-
if (url2.includes("/dist/"))
|
|
92949
|
-
return "dist";
|
|
92950
|
-
return "unknown";
|
|
92951
|
-
}
|
|
92952
|
-
function computeDefaultBuildInfo() {
|
|
92953
|
-
const pkg = packageInfo();
|
|
92954
|
-
const mode = detectMode();
|
|
92955
|
-
const srcDir = new URL("../", import.meta.url);
|
|
92956
|
-
const packageJson = new URL("../../package.json", import.meta.url);
|
|
92957
|
-
const sourceStamp = Math.max(latestMtimeMs(fileURLToPath5(srcDir)), fileMtimeMs(fileURLToPath5(packageJson)));
|
|
92958
|
-
const buildIdInput = `${pkg.name}
|
|
92959
|
-
${pkg.version}
|
|
92960
|
-
${mode}
|
|
92961
|
-
${sourceStamp}`;
|
|
92962
|
-
const buildId = createHash3("sha256").update(buildIdInput).digest("hex").slice(0, 12);
|
|
92963
|
-
return {
|
|
92964
|
-
name: pkg.name,
|
|
92965
|
-
version: pkg.version,
|
|
92966
|
-
build_id: `${pkg.version}:${buildId}`,
|
|
92967
|
-
built_at: sourceStamp || Date.now(),
|
|
92968
|
-
source_stamp: sourceStamp || Date.now(),
|
|
92969
|
-
mode
|
|
92970
|
-
};
|
|
92971
|
-
}
|
|
92972
|
-
var cached4;
|
|
92973
|
-
function parseEnvNumber(raw4, fallback) {
|
|
92974
|
-
const parsed = Number(raw4);
|
|
92975
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
93953
|
+
for (const entry of builtinScenarioCatalog) {
|
|
93954
|
+
Object.defineProperty(builtinScenarioPackagesTarget, entry.package_id, {
|
|
93955
|
+
enumerable: true,
|
|
93956
|
+
configurable: false,
|
|
93957
|
+
get: () => loadBuiltinScenarioPackage(entry)
|
|
93958
|
+
});
|
|
92976
93959
|
}
|
|
92977
|
-
|
|
92978
|
-
|
|
92979
|
-
|
|
92980
|
-
|
|
92981
|
-
|
|
92982
|
-
|
|
92983
|
-
|
|
92984
|
-
build_id: process.env.AGENT_REMNOTE_BUILD_ID?.trim() || defaultInfo.build_id,
|
|
92985
|
-
built_at: parseEnvNumber(process.env.AGENT_REMNOTE_BUILD_AT, defaultInfo.built_at),
|
|
92986
|
-
source_stamp: parseEnvNumber(process.env.AGENT_REMNOTE_SOURCE_STAMP, defaultInfo.source_stamp),
|
|
92987
|
-
mode: process.env.AGENT_REMNOTE_BUILD_MODE === "src" || process.env.AGENT_REMNOTE_BUILD_MODE === "dist" || process.env.AGENT_REMNOTE_BUILD_MODE === "unknown" ? process.env.AGENT_REMNOTE_BUILD_MODE : defaultInfo.mode
|
|
92988
|
-
};
|
|
92989
|
-
return cached4;
|
|
93960
|
+
var builtinScenarioPackages = Object.freeze(builtinScenarioPackagesTarget);
|
|
93961
|
+
function getBuiltinScenarioPackage(id2) {
|
|
93962
|
+
const entry = builtinScenarioCatalog.find((item) => item.package_id === id2);
|
|
93963
|
+
if (!entry) {
|
|
93964
|
+
throw new Error(`Unknown builtin scenario package: ${id2}`);
|
|
93965
|
+
}
|
|
93966
|
+
return loadBuiltinScenarioPackage(entry);
|
|
92990
93967
|
}
|
|
92991
|
-
function
|
|
92992
|
-
const
|
|
92993
|
-
|
|
92994
|
-
|
|
92995
|
-
|
|
92996
|
-
|
|
92997
|
-
warnings.push(`${label} build mismatch: current=${params3.current.build_id} live=${other.build_id}`);
|
|
92998
|
-
}
|
|
92999
|
-
};
|
|
93000
|
-
compare2("daemon", params3.daemon);
|
|
93001
|
-
compare2("plugin", params3.plugin);
|
|
93002
|
-
compare2("api", params3.api);
|
|
93003
|
-
return warnings;
|
|
93968
|
+
function getBuiltinScenarioPackageSourcePath(id2) {
|
|
93969
|
+
const entry = builtinScenarioCatalog.find((item) => item.package_id === id2);
|
|
93970
|
+
if (!entry) {
|
|
93971
|
+
throw new Error(`Unknown builtin scenario source: ${id2}`);
|
|
93972
|
+
}
|
|
93973
|
+
return resolveBuiltinPackagePath(entry.package_path);
|
|
93004
93974
|
}
|
|
93005
93975
|
|
|
93006
93976
|
// src/lib/doctor/checks.ts
|
|
@@ -93021,7 +93991,7 @@ function collectDoctorChecks() {
|
|
|
93021
93991
|
staleArtifacts.push({
|
|
93022
93992
|
service: "daemon",
|
|
93023
93993
|
pidFile: daemonPidFile,
|
|
93024
|
-
stateFile: daemonPidInfo.state_file ??
|
|
93994
|
+
stateFile: daemonPidInfo.state_file ?? path27.join(path27.dirname(daemonPidFile), "ws.state.json"),
|
|
93025
93995
|
pid: daemonPidInfo.pid
|
|
93026
93996
|
});
|
|
93027
93997
|
}
|
|
@@ -93049,13 +94019,16 @@ function collectDoctorChecks() {
|
|
|
93049
94019
|
pid: pluginPidInfo.pid
|
|
93050
94020
|
});
|
|
93051
94021
|
}
|
|
94022
|
+
const pluginStateInfo = yield* pluginFiles.readStateFile(pluginPidInfo?.state_file ?? pluginFiles.defaultStateFile()).pipe(orElseSucceed2(() => {
|
|
94023
|
+
return;
|
|
94024
|
+
}));
|
|
93052
94025
|
const current2 = currentRuntimeBuildInfo();
|
|
93053
94026
|
const expectedPlugin = currentExpectedPluginBuildInfo();
|
|
93054
94027
|
const mismatches = [
|
|
93055
94028
|
daemonPidInfo?.build?.build_id && daemonPidInfo.build.build_id !== current2.build_id ? { service: "daemon", live: daemonPidInfo.build.build_id } : null,
|
|
93056
94029
|
apiPidInfo?.build?.build_id && apiPidInfo.build.build_id !== current2.build_id ? { service: "api", live: apiPidInfo.build.build_id } : null,
|
|
93057
94030
|
pluginPidInfo?.build?.build_id && pluginPidInfo.build.build_id !== current2.build_id ? { service: "plugin", live: pluginPidInfo.build.build_id } : null,
|
|
93058
|
-
expectedPlugin &&
|
|
94031
|
+
expectedPlugin && pluginStateInfo?.plugin_build?.build_id && pluginStateInfo.plugin_build.build_id !== expectedPlugin.build_id ? { service: "plugin-artifact", live: pluginStateInfo.plugin_build.build_id, expected: expectedPlugin.build_id } : null
|
|
93059
94032
|
].filter(Boolean);
|
|
93060
94033
|
const configPreview = yield* userConfig.previewRepair().pipe(either3);
|
|
93061
94034
|
const configChanged = configPreview._tag === "Right" ? configPreview.right.changed : false;
|
|
@@ -93069,269 +94042,76 @@ function collectDoctorChecks() {
|
|
|
93069
94042
|
return { ok: true, details: undefined };
|
|
93070
94043
|
} catch (error4) {
|
|
93071
94044
|
return { ok: false, details: { error: String(error4?.message || error4) } };
|
|
93072
|
-
}
|
|
93073
|
-
});
|
|
93074
|
-
const pluginArtifactsCheck = yield* sync3(() => {
|
|
93075
|
-
try {
|
|
93076
|
-
return { ok: true, details: { distPath: resolvePluginDistPath(), zipPath: resolvePluginZipPath() } };
|
|
93077
|
-
} catch (error4) {
|
|
93078
|
-
return { ok: false, details: { error: String(error4?.message || error4) } };
|
|
93079
|
-
}
|
|
93080
|
-
});
|
|
93081
|
-
const pidWritable = yield* fsAccess.canWritePath(daemonPidFile);
|
|
93082
|
-
const logWritable = yield* fsAccess.canWritePath(daemonFiles.defaultLogFile());
|
|
93083
|
-
const storeWritable = yield* fsAccess.checkWritableFile(cfg.storeDb);
|
|
93084
|
-
const pathOk = pidWritable && logWritable && storeWritable.ok;
|
|
93085
|
-
return [
|
|
93086
|
-
{
|
|
93087
|
-
id: "runtime.stale_pid_or_state",
|
|
93088
|
-
ok: staleArtifacts.length === 0,
|
|
93089
|
-
severity: staleArtifacts.length === 0 ? "info" : "warning",
|
|
93090
|
-
summary: staleArtifacts.length === 0 ? "No stale runtime pid/state artifacts" : `Found ${staleArtifacts.length} stale runtime artifact set(s)`,
|
|
93091
|
-
details: staleArtifacts,
|
|
93092
|
-
repairable: staleArtifacts.length > 0
|
|
93093
|
-
},
|
|
93094
|
-
{
|
|
93095
|
-
id: "runtime.version_mismatch",
|
|
93096
|
-
ok: mismatches.length === 0,
|
|
93097
|
-
severity: mismatches.length === 0 ? "info" : "warning",
|
|
93098
|
-
summary: mismatches.length === 0 ? "No runtime build mismatch detected" : `Found ${mismatches.length} runtime build mismatch(es)`,
|
|
93099
|
-
details: mismatches,
|
|
93100
|
-
repairable: mismatches.length > 0
|
|
93101
|
-
},
|
|
93102
|
-
{
|
|
93103
|
-
id: "config.migration_needed",
|
|
93104
|
-
ok: configValid && !configChanged,
|
|
93105
|
-
severity: !configValid ? "error" : configChanged ? "warning" : "info",
|
|
93106
|
-
summary: !configValid ? "User config is invalid or conflicting" : configChanged ? "User config can be canonicalized" : "User config already canonical",
|
|
93107
|
-
details: configDetails,
|
|
93108
|
-
repairable: configRepairable
|
|
93109
|
-
},
|
|
93110
|
-
{
|
|
93111
|
-
id: "package.builtin_scenarios_broken",
|
|
93112
|
-
ok: packageCheck.ok,
|
|
93113
|
-
severity: packageCheck.ok ? "info" : "error",
|
|
93114
|
-
summary: packageCheck.ok ? "Builtin scenarios are loadable" : "Builtin scenario package loading failed",
|
|
93115
|
-
details: packageCheck.details,
|
|
93116
|
-
repairable: !packageCheck.ok
|
|
93117
|
-
},
|
|
93118
|
-
{
|
|
93119
|
-
id: "package.plugin_artifacts_unavailable",
|
|
93120
|
-
ok: pluginArtifactsCheck.ok,
|
|
93121
|
-
severity: pluginArtifactsCheck.ok ? "info" : "error",
|
|
93122
|
-
summary: pluginArtifactsCheck.ok ? "Plugin artifacts are available" : "Plugin artifacts are unavailable",
|
|
93123
|
-
details: pluginArtifactsCheck.details,
|
|
93124
|
-
repairable: false
|
|
93125
|
-
},
|
|
93126
|
-
{
|
|
93127
|
-
id: "env.path_or_permission_problem",
|
|
93128
|
-
ok: pathOk,
|
|
93129
|
-
severity: pathOk ? "info" : "error",
|
|
93130
|
-
summary: pathOk ? "Required writable paths are available" : "One or more required paths are not writable",
|
|
93131
|
-
details: {
|
|
93132
|
-
daemon_pid_file: daemonPidFile,
|
|
93133
|
-
daemon_log_file: daemonFiles.defaultLogFile(),
|
|
93134
|
-
pid_writable: pidWritable,
|
|
93135
|
-
log_writable: logWritable,
|
|
93136
|
-
store_db: cfg.storeDb,
|
|
93137
|
-
store_writable: storeWritable
|
|
93138
|
-
},
|
|
93139
|
-
repairable: false
|
|
93140
|
-
}
|
|
93141
|
-
];
|
|
93142
|
-
});
|
|
93143
|
-
}
|
|
93144
|
-
|
|
93145
|
-
// src/commands/ws/_shared.ts
|
|
93146
|
-
import path27 from "node:path";
|
|
93147
|
-
var WS_HEALTH_TIMEOUT_MS = 2000;
|
|
93148
|
-
var WS_START_WAIT_DEFAULT_MS = 15000;
|
|
93149
|
-
var WS_STOP_WAIT_DEFAULT_MS = 5000;
|
|
93150
|
-
function supervisorCommandLine(params3) {
|
|
93151
|
-
const command = process.argv[0];
|
|
93152
|
-
const script = process.argv[1];
|
|
93153
|
-
if (!command || !script) {
|
|
93154
|
-
throw new CliError({
|
|
93155
|
-
code: "INTERNAL",
|
|
93156
|
-
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
93157
|
-
exitCode: 1,
|
|
93158
|
-
details: { argv: process.argv }
|
|
93159
|
-
});
|
|
93160
|
-
}
|
|
93161
|
-
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
93162
|
-
return {
|
|
93163
|
-
command,
|
|
93164
|
-
args: [
|
|
93165
|
-
...execArgv,
|
|
93166
|
-
script,
|
|
93167
|
-
"--daemon-url",
|
|
93168
|
-
params3.wsUrl,
|
|
93169
|
-
"--store-db",
|
|
93170
|
-
params3.storeDb,
|
|
93171
|
-
"daemon",
|
|
93172
|
-
"supervisor",
|
|
93173
|
-
"--pid-file",
|
|
93174
|
-
params3.pidFile,
|
|
93175
|
-
"--log-file",
|
|
93176
|
-
params3.logFile,
|
|
93177
|
-
"--state-file",
|
|
93178
|
-
params3.stateFile
|
|
93179
|
-
]
|
|
93180
|
-
};
|
|
93181
|
-
}
|
|
93182
|
-
function toPidFileValue(params3) {
|
|
93183
|
-
return {
|
|
93184
|
-
pid: params3.pid,
|
|
93185
|
-
build: currentRuntimeBuildInfo(),
|
|
93186
|
-
started_at: params3.startedAt,
|
|
93187
|
-
ws_url: params3.wsUrl,
|
|
93188
|
-
log_file: params3.logFile,
|
|
93189
|
-
cmd: params3.cmd,
|
|
93190
|
-
ws_bridge_state_file: params3.wsBridgeStateFile,
|
|
93191
|
-
status_line_file: params3.statusLineFile,
|
|
93192
|
-
status_line_json_file: params3.statusLineJsonFile
|
|
93193
|
-
};
|
|
93194
|
-
}
|
|
93195
|
-
function waitForHealth(url2, waitMs) {
|
|
93196
|
-
return gen2(function* () {
|
|
93197
|
-
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
93198
|
-
return yield* fail8(new CliError({
|
|
93199
|
-
code: "INVALID_ARGS",
|
|
93200
|
-
message: "--wait must be a non-negative integer (ms)",
|
|
93201
|
-
exitCode: 2,
|
|
93202
|
-
details: { wait_ms: waitMs }
|
|
93203
|
-
}));
|
|
93204
|
-
}
|
|
93205
|
-
if (waitMs === 0)
|
|
93206
|
-
return;
|
|
93207
|
-
const ws = yield* WsClient;
|
|
93208
|
-
const deadline = Date.now() + waitMs;
|
|
93209
|
-
while (Date.now() < deadline) {
|
|
93210
|
-
const remaining = Math.max(0, deadline - Date.now());
|
|
93211
|
-
const res = yield* ws.health({ url: url2, timeoutMs: Math.min(WS_HEALTH_TIMEOUT_MS, Math.max(1, remaining)) }).pipe(either3);
|
|
93212
|
-
if (isRight2(res))
|
|
93213
|
-
return;
|
|
93214
|
-
yield* sleep4(millis(300));
|
|
93215
|
-
}
|
|
93216
|
-
return yield* fail8(new CliError({
|
|
93217
|
-
code: "WS_TIMEOUT",
|
|
93218
|
-
message: `Timed out waiting for WS to become available (${waitMs}ms)`,
|
|
93219
|
-
exitCode: 1,
|
|
93220
|
-
details: { url: url2, wait_ms: waitMs },
|
|
93221
|
-
hint: ["agent-remnote daemon status", "agent-remnote daemon logs", "agent-remnote daemon health --json"]
|
|
93222
|
-
}));
|
|
93223
|
-
});
|
|
93224
|
-
}
|
|
93225
|
-
function toInitialSupervisorState(now2) {
|
|
93226
|
-
return {
|
|
93227
|
-
status: "running",
|
|
93228
|
-
restart_count: 0,
|
|
93229
|
-
restart_window_started_at: now2,
|
|
93230
|
-
backoff_until: null,
|
|
93231
|
-
last_exit: null,
|
|
93232
|
-
failed_reason: null
|
|
93233
|
-
};
|
|
93234
|
-
}
|
|
93235
|
-
function defaultStateFilePathFromPidFile(pidFilePath) {
|
|
93236
|
-
return path27.join(path27.dirname(pidFilePath), "ws.state.json");
|
|
93237
|
-
}
|
|
93238
|
-
function startWsSupervisor(params3) {
|
|
93239
|
-
return gen2(function* () {
|
|
93240
|
-
const cfg = yield* AppConfig;
|
|
93241
|
-
const daemonFiles = yield* DaemonFiles;
|
|
93242
|
-
const supervisorState = yield* SupervisorState;
|
|
93243
|
-
const proc = yield* Process;
|
|
93244
|
-
const ws = yield* WsClient;
|
|
93245
|
-
const pidFilePath = resolveUserFilePath(params3.pidFile ?? daemonFiles.defaultPidFile());
|
|
93246
|
-
const logFilePath = resolveUserFilePath(params3.logFile ?? daemonFiles.defaultLogFile());
|
|
93247
|
-
const stateFilePath = defaultStateFilePathFromPidFile(pidFilePath);
|
|
93248
|
-
const existingPidFile = yield* daemonFiles.readPidFile(pidFilePath);
|
|
93249
|
-
if (existingPidFile) {
|
|
93250
|
-
const alive = yield* proc.isPidRunning(existingPidFile.pid);
|
|
93251
|
-
if (!alive) {
|
|
93252
|
-
yield* daemonFiles.deletePidFile(pidFilePath);
|
|
93253
|
-
yield* supervisorState.deleteStateFile(stateFilePath);
|
|
93254
|
-
} else {
|
|
93255
|
-
yield* requireTrustedPidRecord({ record: existingPidFile, pidFilePath });
|
|
93256
|
-
return {
|
|
93257
|
-
started: false,
|
|
93258
|
-
pid: existingPidFile.pid,
|
|
93259
|
-
pid_file: pidFilePath,
|
|
93260
|
-
log_file: existingPidFile.log_file ?? logFilePath
|
|
93261
|
-
};
|
|
93262
|
-
}
|
|
93263
|
-
}
|
|
93264
|
-
const pre = yield* ws.health({ url: cfg.wsUrl, timeoutMs: WS_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
93265
|
-
if (isRight2(pre)) {
|
|
93266
|
-
return { started: false, pid_file: pidFilePath, log_file: logFilePath };
|
|
93267
|
-
}
|
|
93268
|
-
const cmd = yield* try_3({
|
|
93269
|
-
try: () => supervisorCommandLine({
|
|
93270
|
-
wsUrl: cfg.wsUrl,
|
|
93271
|
-
storeDb: cfg.storeDb,
|
|
93272
|
-
pidFile: pidFilePath,
|
|
93273
|
-
logFile: logFilePath,
|
|
93274
|
-
stateFile: stateFilePath
|
|
93275
|
-
}),
|
|
93276
|
-
catch: (e) => isCliError(e) ? e : new CliError({
|
|
93277
|
-
code: "INTERNAL",
|
|
93278
|
-
message: "Failed to start supervisor",
|
|
93279
|
-
exitCode: 1,
|
|
93280
|
-
details: { error: String(e?.message || e) }
|
|
93281
|
-
})
|
|
94045
|
+
}
|
|
93282
94046
|
});
|
|
93283
|
-
const
|
|
93284
|
-
|
|
93285
|
-
|
|
93286
|
-
|
|
93287
|
-
|
|
93288
|
-
|
|
93289
|
-
wsUrl: cfg.wsUrl,
|
|
93290
|
-
logFile: logFilePath,
|
|
93291
|
-
cmd: [cmd.command, ...cmd.args],
|
|
93292
|
-
wsBridgeStateFile: cfg.wsStateFile.path,
|
|
93293
|
-
statusLineFile: cfg.statusLineFile,
|
|
93294
|
-
statusLineJsonFile: cfg.statusLineJsonFile
|
|
93295
|
-
}),
|
|
93296
|
-
mode: "supervisor",
|
|
93297
|
-
child_pid: null,
|
|
93298
|
-
state_file: stateFilePath
|
|
94047
|
+
const pluginArtifactsCheck = yield* sync3(() => {
|
|
94048
|
+
try {
|
|
94049
|
+
return { ok: true, details: { distPath: resolvePluginDistPath(), zipPath: resolvePluginZipPath() } };
|
|
94050
|
+
} catch (error4) {
|
|
94051
|
+
return { ok: false, details: { error: String(error4?.message || error4) } };
|
|
94052
|
+
}
|
|
93299
94053
|
});
|
|
93300
|
-
yield*
|
|
93301
|
-
yield*
|
|
93302
|
-
|
|
93303
|
-
|
|
93304
|
-
|
|
93305
|
-
|
|
93306
|
-
|
|
93307
|
-
|
|
93308
|
-
|
|
93309
|
-
|
|
93310
|
-
|
|
93311
|
-
|
|
93312
|
-
|
|
93313
|
-
|
|
93314
|
-
|
|
93315
|
-
|
|
93316
|
-
|
|
93317
|
-
|
|
93318
|
-
|
|
93319
|
-
|
|
93320
|
-
|
|
93321
|
-
|
|
93322
|
-
|
|
93323
|
-
|
|
93324
|
-
|
|
93325
|
-
|
|
93326
|
-
|
|
94054
|
+
const pidWritable = yield* fsAccess.canWritePath(daemonPidFile);
|
|
94055
|
+
const logWritable = yield* fsAccess.canWritePath(daemonFiles.defaultLogFile());
|
|
94056
|
+
const storeWritable = yield* fsAccess.checkWritableFile(cfg.storeDb);
|
|
94057
|
+
const pathOk = pidWritable && logWritable && storeWritable.ok;
|
|
94058
|
+
return [
|
|
94059
|
+
{
|
|
94060
|
+
id: "runtime.stale_pid_or_state",
|
|
94061
|
+
ok: staleArtifacts.length === 0,
|
|
94062
|
+
severity: staleArtifacts.length === 0 ? "info" : "warning",
|
|
94063
|
+
summary: staleArtifacts.length === 0 ? "No stale runtime pid/state artifacts" : `Found ${staleArtifacts.length} stale runtime artifact set(s)`,
|
|
94064
|
+
details: staleArtifacts,
|
|
94065
|
+
repairable: staleArtifacts.length > 0
|
|
94066
|
+
},
|
|
94067
|
+
{
|
|
94068
|
+
id: "runtime.version_mismatch",
|
|
94069
|
+
ok: mismatches.length === 0,
|
|
94070
|
+
severity: mismatches.length === 0 ? "info" : "warning",
|
|
94071
|
+
summary: mismatches.length === 0 ? "No runtime build mismatch detected" : `Found ${mismatches.length} runtime build mismatch(es)`,
|
|
94072
|
+
details: mismatches,
|
|
94073
|
+
repairable: mismatches.length > 0
|
|
94074
|
+
},
|
|
94075
|
+
{
|
|
94076
|
+
id: "config.migration_needed",
|
|
94077
|
+
ok: configValid && !configChanged,
|
|
94078
|
+
severity: !configValid ? "error" : configChanged ? "warning" : "info",
|
|
94079
|
+
summary: !configValid ? "User config is invalid or conflicting" : configChanged ? "User config can be canonicalized" : "User config already canonical",
|
|
94080
|
+
details: configDetails,
|
|
94081
|
+
repairable: configRepairable
|
|
94082
|
+
},
|
|
94083
|
+
{
|
|
94084
|
+
id: "package.builtin_scenarios_broken",
|
|
94085
|
+
ok: packageCheck.ok,
|
|
94086
|
+
severity: packageCheck.ok ? "info" : "error",
|
|
94087
|
+
summary: packageCheck.ok ? "Builtin scenarios are loadable" : "Builtin scenario package loading failed",
|
|
94088
|
+
details: packageCheck.details,
|
|
94089
|
+
repairable: !packageCheck.ok
|
|
94090
|
+
},
|
|
94091
|
+
{
|
|
94092
|
+
id: "package.plugin_artifacts_unavailable",
|
|
94093
|
+
ok: pluginArtifactsCheck.ok,
|
|
94094
|
+
severity: pluginArtifactsCheck.ok ? "info" : "error",
|
|
94095
|
+
summary: pluginArtifactsCheck.ok ? "Plugin artifacts are available" : "Plugin artifacts are unavailable",
|
|
94096
|
+
details: pluginArtifactsCheck.details,
|
|
94097
|
+
repairable: false
|
|
94098
|
+
},
|
|
94099
|
+
{
|
|
94100
|
+
id: "env.path_or_permission_problem",
|
|
94101
|
+
ok: pathOk,
|
|
94102
|
+
severity: pathOk ? "info" : "error",
|
|
94103
|
+
summary: pathOk ? "Required writable paths are available" : "One or more required paths are not writable",
|
|
94104
|
+
details: {
|
|
94105
|
+
daemon_pid_file: daemonPidFile,
|
|
94106
|
+
daemon_log_file: daemonFiles.defaultLogFile(),
|
|
94107
|
+
pid_writable: pidWritable,
|
|
94108
|
+
log_writable: logWritable,
|
|
94109
|
+
store_db: cfg.storeDb,
|
|
94110
|
+
store_writable: storeWritable
|
|
94111
|
+
},
|
|
94112
|
+
repairable: false
|
|
93327
94113
|
}
|
|
93328
|
-
|
|
93329
|
-
started: false,
|
|
93330
|
-
pid_file: pidFilePath,
|
|
93331
|
-
log_file: logFilePath
|
|
93332
|
-
};
|
|
93333
|
-
}
|
|
93334
|
-
return yield* startWsSupervisor(params3);
|
|
94114
|
+
];
|
|
93335
94115
|
});
|
|
93336
94116
|
}
|
|
93337
94117
|
|
|
@@ -95429,7 +96209,7 @@ var baseBackoffMs = integer7("backoff-ms").pipe(withDefault5(500));
|
|
|
95429
96209
|
var maxBackoffMs = integer7("max-backoff-ms").pipe(withDefault5(1e4));
|
|
95430
96210
|
var logMaxBytes = integer7("log-max-bytes").pipe(withDefault5(0));
|
|
95431
96211
|
var logKeep = integer7("log-keep").pipe(withDefault5(5));
|
|
95432
|
-
function
|
|
96212
|
+
function childCommandLine3(params3) {
|
|
95433
96213
|
const command = process.argv[0];
|
|
95434
96214
|
const script = process.argv[1];
|
|
95435
96215
|
if (!command || !script) {
|
|
@@ -95454,7 +96234,7 @@ var wsSupervisorCommand = exports_Command.make("supervisor", { pidFile: pidFile7
|
|
|
95454
96234
|
const logFilePath = resolveUserFilePath(logFile5 ?? daemonFiles.defaultLogFile());
|
|
95455
96235
|
const stateFilePath = resolveUserFilePath(stateFile3 ?? supervisorState.defaultStateFile());
|
|
95456
96236
|
const childCmd = yield* try_3({
|
|
95457
|
-
try: () =>
|
|
96237
|
+
try: () => childCommandLine3({ wsUrl: cfg.wsUrl, storeDb: cfg.storeDb }),
|
|
95458
96238
|
catch: (e) => isCliError(e) ? e : new CliError({
|
|
95459
96239
|
code: "INTERNAL",
|
|
95460
96240
|
message: "Failed to build child command line",
|
|
@@ -95770,238 +96550,11 @@ function waitForTxn(params3) {
|
|
|
95770
96550
|
]
|
|
95771
96551
|
}));
|
|
95772
96552
|
}
|
|
95773
|
-
yield* sleep4(millis(resolvedPollMs));
|
|
95774
|
-
}
|
|
95775
|
-
});
|
|
95776
|
-
}
|
|
95777
|
-
|
|
95778
|
-
// src/lib/apiUrls.ts
|
|
95779
|
-
function normalizeApiBasePath2(basePath) {
|
|
95780
|
-
const trimmed2 = basePath.trim();
|
|
95781
|
-
if (!trimmed2)
|
|
95782
|
-
return "/v1";
|
|
95783
|
-
const normalized = trimmed2.startsWith("/") ? trimmed2 : `/${trimmed2}`;
|
|
95784
|
-
const withoutTrailing = normalized.replace(/\/+$/, "");
|
|
95785
|
-
return withoutTrailing && withoutTrailing !== "/" ? withoutTrailing : "/";
|
|
95786
|
-
}
|
|
95787
|
-
function normalizeBaseUrl(baseUrl) {
|
|
95788
|
-
return baseUrl.trim().replace(/\/+$/, "");
|
|
95789
|
-
}
|
|
95790
|
-
function resolveBasePrefix(baseUrl, fallbackBasePath) {
|
|
95791
|
-
const parsed = new URL(normalizeBaseUrl(baseUrl));
|
|
95792
|
-
const pathname = normalizeApiBasePath2(parsed.pathname);
|
|
95793
|
-
if (pathname && pathname !== "/")
|
|
95794
|
-
return normalizeApiBasePath2(pathname);
|
|
95795
|
-
return normalizeApiBasePath2(fallbackBasePath);
|
|
95796
|
-
}
|
|
95797
|
-
function normalizeRoutePath(routePath) {
|
|
95798
|
-
const trimmed2 = routePath.trim();
|
|
95799
|
-
if (!trimmed2)
|
|
95800
|
-
return "";
|
|
95801
|
-
return `/${trimmed2.replace(/^\/+/, "")}`;
|
|
95802
|
-
}
|
|
95803
|
-
function buildApiBaseUrl(baseUrl, fallbackBasePath = "/v1") {
|
|
95804
|
-
const parsed = new URL(normalizeBaseUrl(baseUrl));
|
|
95805
|
-
const prefix2 = resolveBasePrefix(baseUrl, fallbackBasePath);
|
|
95806
|
-
return prefix2 === "/" ? parsed.origin : `${parsed.origin}${prefix2}`;
|
|
95807
|
-
}
|
|
95808
|
-
function apiLocalBaseUrl(port3, basePath = "/v1") {
|
|
95809
|
-
return buildApiBaseUrl(`http://127.0.0.1:${port3}`, basePath);
|
|
95810
|
-
}
|
|
95811
|
-
function apiContainerBaseUrl(port3, basePath = "/v1") {
|
|
95812
|
-
return buildApiBaseUrl(`http://host.docker.internal:${port3}`, basePath);
|
|
95813
|
-
}
|
|
95814
|
-
function joinApiUrl(baseUrl, routePath, fallbackBasePath = "/v1") {
|
|
95815
|
-
return `${buildApiBaseUrl(baseUrl, fallbackBasePath)}${normalizeRoutePath(routePath)}`;
|
|
95816
|
-
}
|
|
95817
|
-
|
|
95818
|
-
// src/services/HostApiClient.ts
|
|
95819
|
-
function normalizeBaseUrl2(baseUrl) {
|
|
95820
|
-
return baseUrl.trim().replace(/\/+$/, "");
|
|
95821
|
-
}
|
|
95822
|
-
function apiTimeoutError(params3) {
|
|
95823
|
-
return new CliError({
|
|
95824
|
-
code: "API_TIMEOUT",
|
|
95825
|
-
message: `API timeout after ${params3.timeoutMs}ms`,
|
|
95826
|
-
exitCode: 1,
|
|
95827
|
-
details: { base_url: params3.baseUrl, path: params3.path, timeout_ms: params3.timeoutMs }
|
|
95828
|
-
});
|
|
95829
|
-
}
|
|
95830
|
-
function apiUnavailableError(params3) {
|
|
95831
|
-
return new CliError({
|
|
95832
|
-
code: "API_UNAVAILABLE",
|
|
95833
|
-
message: String(params3.error?.message || params3.error || "API request failed"),
|
|
95834
|
-
exitCode: 1,
|
|
95835
|
-
details: { base_url: params3.baseUrl, path: params3.path }
|
|
95836
|
-
});
|
|
95837
|
-
}
|
|
95838
|
-
function exitCodeFromRemoteCode(code2) {
|
|
95839
|
-
return code2 === "INVALID_ARGS" || code2 === "INVALID_PAYLOAD" || code2 === "PAYLOAD_TOO_LARGE" ? 2 : 1;
|
|
95840
|
-
}
|
|
95841
|
-
function parseEnvelope(raw4) {
|
|
95842
|
-
if (!raw4 || typeof raw4 !== "object") {
|
|
95843
|
-
return { ok: false, error: { code: "INTERNAL", message: "Invalid API response envelope" } };
|
|
95844
|
-
}
|
|
95845
|
-
return raw4;
|
|
95846
|
-
}
|
|
95847
|
-
function buildQuery(params3) {
|
|
95848
|
-
const sp = new URLSearchParams;
|
|
95849
|
-
for (const [key, value8] of Object.entries(params3)) {
|
|
95850
|
-
if (value8 === undefined || value8 === null)
|
|
95851
|
-
continue;
|
|
95852
|
-
if (typeof value8 === "string") {
|
|
95853
|
-
if (!value8.trim())
|
|
95854
|
-
continue;
|
|
95855
|
-
sp.set(key, value8);
|
|
95856
|
-
continue;
|
|
95857
|
-
}
|
|
95858
|
-
if (typeof value8 === "number" || typeof value8 === "boolean") {
|
|
95859
|
-
sp.set(key, String(value8));
|
|
95860
|
-
}
|
|
95861
|
-
}
|
|
95862
|
-
const query = sp.toString();
|
|
95863
|
-
return query ? `?${query}` : "";
|
|
95864
|
-
}
|
|
95865
|
-
function requestJson(params3) {
|
|
95866
|
-
const timeoutMs = Math.max(1, params3.timeoutMs ?? 15000);
|
|
95867
|
-
const baseUrl = normalizeBaseUrl2(params3.baseUrl);
|
|
95868
|
-
const url2 = joinApiUrl(baseUrl, params3.path, params3.basePath);
|
|
95869
|
-
return async((resume2) => {
|
|
95870
|
-
const controller = new AbortController;
|
|
95871
|
-
const timer2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
95872
|
-
fetch(url2, {
|
|
95873
|
-
method: params3.method,
|
|
95874
|
-
headers: params3.method === "POST" ? { "content-type": "application/json" } : undefined,
|
|
95875
|
-
body: params3.body === undefined ? undefined : JSON.stringify(params3.body),
|
|
95876
|
-
signal: controller.signal
|
|
95877
|
-
}).then(async (response) => {
|
|
95878
|
-
clearTimeout(timer2);
|
|
95879
|
-
let parsed;
|
|
95880
|
-
try {
|
|
95881
|
-
parsed = parseEnvelope(await response.json());
|
|
95882
|
-
} catch (error4) {
|
|
95883
|
-
resume2(fail8(new CliError({
|
|
95884
|
-
code: "API_UNAVAILABLE",
|
|
95885
|
-
message: "API returned a non-JSON response",
|
|
95886
|
-
exitCode: 1,
|
|
95887
|
-
details: { url: url2, status: response.status, error: String(error4?.message || error4) }
|
|
95888
|
-
})));
|
|
95889
|
-
return;
|
|
95890
|
-
}
|
|
95891
|
-
if (parsed.ok === true) {
|
|
95892
|
-
resume2(succeed8(parsed.data));
|
|
95893
|
-
return;
|
|
95894
|
-
}
|
|
95895
|
-
const code2 = typeof parsed.error?.code === "string" ? parsed.error.code : "INTERNAL";
|
|
95896
|
-
const message2 = typeof parsed.error?.message === "string" ? parsed.error.message : "API request failed";
|
|
95897
|
-
const hint = Array.isArray(parsed.hint) ? parsed.hint.map(String) : undefined;
|
|
95898
|
-
resume2(fail8(new CliError({
|
|
95899
|
-
code: code2,
|
|
95900
|
-
message: message2,
|
|
95901
|
-
exitCode: exitCodeFromRemoteCode(code2),
|
|
95902
|
-
details: parsed.error?.details,
|
|
95903
|
-
hint
|
|
95904
|
-
})));
|
|
95905
|
-
}).catch((error4) => {
|
|
95906
|
-
clearTimeout(timer2);
|
|
95907
|
-
if (error4?.name === "AbortError") {
|
|
95908
|
-
resume2(fail8(apiTimeoutError({ baseUrl, path: params3.path, timeoutMs })));
|
|
95909
|
-
return;
|
|
95910
|
-
}
|
|
95911
|
-
resume2(fail8(apiUnavailableError({ baseUrl, path: params3.path, error: error4 })));
|
|
95912
|
-
});
|
|
95913
|
-
return sync3(() => {
|
|
95914
|
-
clearTimeout(timer2);
|
|
95915
|
-
controller.abort();
|
|
95916
|
-
});
|
|
96553
|
+
yield* sleep4(millis(resolvedPollMs));
|
|
96554
|
+
}
|
|
95917
96555
|
});
|
|
95918
96556
|
}
|
|
95919
96557
|
|
|
95920
|
-
class HostApiClient extends Tag2("HostApiClient")() {
|
|
95921
|
-
}
|
|
95922
|
-
var HostApiClientLive = effect(HostApiClient, gen2(function* () {
|
|
95923
|
-
const cfg = yield* AppConfig;
|
|
95924
|
-
const basePath = cfg.apiBasePath ?? "/v1";
|
|
95925
|
-
const request = (params3) => requestJson({ ...params3, basePath });
|
|
95926
|
-
return {
|
|
95927
|
-
resolveRefValue: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/ref/resolve", method: "POST", body, timeoutMs }),
|
|
95928
|
-
resolvePlacement: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/placement/resolve", method: "POST", body, timeoutMs }),
|
|
95929
|
-
resolveStableSiblingRange: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/selection/stable-sibling-range", method: "POST", body, timeoutMs }),
|
|
95930
|
-
health: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/health", method: "GET", timeoutMs }),
|
|
95931
|
-
status: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/status", method: "GET", timeoutMs }),
|
|
95932
|
-
uiContextSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95933
|
-
baseUrl,
|
|
95934
|
-
path: `/plugin/ui-context/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95935
|
-
method: "GET",
|
|
95936
|
-
timeoutMs
|
|
95937
|
-
}),
|
|
95938
|
-
uiContextPage: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95939
|
-
baseUrl,
|
|
95940
|
-
path: `/plugin/ui-context/page${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95941
|
-
method: "GET",
|
|
95942
|
-
timeoutMs
|
|
95943
|
-
}),
|
|
95944
|
-
uiContextFocusedRem: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95945
|
-
baseUrl,
|
|
95946
|
-
path: `/plugin/ui-context/focused-rem${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95947
|
-
method: "GET",
|
|
95948
|
-
timeoutMs
|
|
95949
|
-
}),
|
|
95950
|
-
uiContextDescribe: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs }) => request({
|
|
95951
|
-
baseUrl,
|
|
95952
|
-
path: `/plugin/ui-context/describe${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
|
|
95953
|
-
method: "GET",
|
|
95954
|
-
timeoutMs
|
|
95955
|
-
}),
|
|
95956
|
-
selectionSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95957
|
-
baseUrl,
|
|
95958
|
-
path: `/plugin/selection/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95959
|
-
method: "GET",
|
|
95960
|
-
timeoutMs
|
|
95961
|
-
}),
|
|
95962
|
-
selectionRoots: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95963
|
-
baseUrl,
|
|
95964
|
-
path: `/plugin/selection/roots${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95965
|
-
method: "GET",
|
|
95966
|
-
timeoutMs
|
|
95967
|
-
}),
|
|
95968
|
-
selectionCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => request({
|
|
95969
|
-
baseUrl,
|
|
95970
|
-
path: `/plugin/selection/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
|
|
95971
|
-
method: "GET",
|
|
95972
|
-
timeoutMs
|
|
95973
|
-
}),
|
|
95974
|
-
pluginCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs }) => request({
|
|
95975
|
-
baseUrl,
|
|
95976
|
-
path: `/plugin/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
|
|
95977
|
-
method: "GET",
|
|
95978
|
-
timeoutMs
|
|
95979
|
-
}),
|
|
95980
|
-
selectionOutline: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/plugin/selection/outline", method: "POST", body, timeoutMs }),
|
|
95981
|
-
uiContext: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/ui-context", method: "GET", timeoutMs }),
|
|
95982
|
-
selection: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/selection", method: "GET", timeoutMs }),
|
|
95983
|
-
searchDb: ({ baseUrl, ...body }) => request({ baseUrl, path: "/search/db", method: "POST", body }),
|
|
95984
|
-
searchPlugin: ({ baseUrl, ...body }) => request({ baseUrl, path: "/search/plugin", method: "POST", body }),
|
|
95985
|
-
writeApply: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/write/apply", method: "POST", body, timeoutMs }),
|
|
95986
|
-
readOutline: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/outline", method: "POST", body, timeoutMs }),
|
|
95987
|
-
readPageId: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/page-id", method: "POST", body, timeoutMs }),
|
|
95988
|
-
resolveRef: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/resolve-ref", method: "POST", body, timeoutMs }),
|
|
95989
|
-
byReference: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/by-reference", method: "POST", body, timeoutMs }),
|
|
95990
|
-
references: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/references", method: "POST", body, timeoutMs }),
|
|
95991
|
-
resolveQueryPowerup: ({ baseUrl, powerup, timeoutMs }) => request({ baseUrl, path: "/internal/query/resolve-powerup", method: "POST", body: { powerup }, timeoutMs }),
|
|
95992
|
-
query: ({ baseUrl, body, timeoutMs }) => request({ baseUrl, path: "/read/query", method: "POST", body, timeoutMs }),
|
|
95993
|
-
dailyRemId: ({ baseUrl, date: date6, offsetDays, timeoutMs }) => request({
|
|
95994
|
-
baseUrl,
|
|
95995
|
-
path: `/daily/rem-id${buildQuery({ date: date6, offsetDays })}`,
|
|
95996
|
-
method: "GET",
|
|
95997
|
-
timeoutMs
|
|
95998
|
-
}),
|
|
95999
|
-
queueWait: ({ baseUrl, txnId, timeoutMs, pollMs }) => request({ baseUrl, path: "/queue/wait", method: "POST", body: { txnId, timeoutMs, pollMs } }),
|
|
96000
|
-
queueTxn: ({ baseUrl, txnId, timeoutMs }) => request({ baseUrl, path: `/queue/txns/${encodeURIComponent(txnId)}`, method: "GET", timeoutMs }),
|
|
96001
|
-
triggerSync: ({ baseUrl, timeoutMs }) => request({ baseUrl, path: "/actions/trigger-sync", method: "POST", timeoutMs })
|
|
96002
|
-
};
|
|
96003
|
-
}));
|
|
96004
|
-
|
|
96005
96558
|
// src/lib/workspaceResolver.ts
|
|
96006
96559
|
import fs19 from "node:fs";
|
|
96007
96560
|
|
|
@@ -101420,232 +101973,46 @@ var applyCommand = exports_Command.make("apply", {
|
|
|
101420
101973
|
const resolvedIdempotencyKey = idempotencyKey3 ?? compiled.idempotencyKey;
|
|
101421
101974
|
if (dryRun) {
|
|
101422
101975
|
yield* writeSuccess({
|
|
101423
|
-
data: {
|
|
101424
|
-
dry_run: true,
|
|
101425
|
-
kind: compiled.kind,
|
|
101426
|
-
ops: compiled.ops,
|
|
101427
|
-
alias_map: compiled.aliasMap,
|
|
101428
|
-
meta: metaValue ? payloadSvc.normalizeKeys(metaValue) : undefined
|
|
101429
|
-
},
|
|
101430
|
-
md: `- dry_run: true
|
|
101431
|
-
- kind: ${compiled.kind}
|
|
101432
|
-
- ops: ${compiled.ops.length}
|
|
101433
|
-
`
|
|
101434
|
-
});
|
|
101435
|
-
return;
|
|
101436
|
-
}
|
|
101437
|
-
yield* validateOptionMutationOps({ scopeLabel: "generic", ops: compiled.ops });
|
|
101438
|
-
const data = yield* invokeWave1Capability("write.apply", {
|
|
101439
|
-
body: {
|
|
101440
|
-
...expanded,
|
|
101441
|
-
priority: resolvedPriority,
|
|
101442
|
-
clientId: resolvedClientId,
|
|
101443
|
-
idempotencyKey: resolvedIdempotencyKey,
|
|
101444
|
-
meta: metaValue,
|
|
101445
|
-
notify: notify3 ?? compiled.notify ?? true,
|
|
101446
|
-
ensureDaemon: ensureDaemon4 ?? compiled.ensureDaemon ?? true
|
|
101447
|
-
},
|
|
101448
|
-
wait: wait3,
|
|
101449
|
-
timeoutMs: timeoutMs3,
|
|
101450
|
-
pollMs: pollMs3
|
|
101451
|
-
});
|
|
101452
|
-
const out = compiled.kind === "actions" ? { ...data, alias_map: data?.alias_map ?? compiled.aliasMap } : data;
|
|
101453
|
-
yield* writeSuccess({
|
|
101454
|
-
data: out,
|
|
101455
|
-
ids: [data.txn_id, ...data.op_ids],
|
|
101456
|
-
md: `- txn_id: ${data.txn_id}
|
|
101457
|
-
- op_ids: ${data.op_ids.length}
|
|
101458
|
-
- notified: ${data.notified}
|
|
101459
|
-
- sent: ${data.sent ?? ""}
|
|
101460
|
-
`
|
|
101461
|
-
});
|
|
101462
|
-
}).pipe(catchAll2(writeFailure)));
|
|
101463
|
-
|
|
101464
|
-
// src/commands/api/_shared.ts
|
|
101465
|
-
var API_HEALTH_TIMEOUT_MS = 2000;
|
|
101466
|
-
var API_START_WAIT_DEFAULT_MS = 15000;
|
|
101467
|
-
var API_STOP_WAIT_DEFAULT_MS = 5000;
|
|
101468
|
-
function childCommandLine2(params3) {
|
|
101469
|
-
const command = process.argv[0];
|
|
101470
|
-
const script = process.argv[1];
|
|
101471
|
-
if (!command || !script) {
|
|
101472
|
-
throw new CliError({
|
|
101473
|
-
code: "INTERNAL",
|
|
101474
|
-
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
101475
|
-
exitCode: 1,
|
|
101476
|
-
details: { argv: process.argv }
|
|
101477
|
-
});
|
|
101478
|
-
}
|
|
101479
|
-
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
101480
|
-
const args2 = [...execArgv, script, "--daemon-url", params3.wsUrl, "--store-db", params3.storeDb];
|
|
101481
|
-
if (params3.remnoteDb)
|
|
101482
|
-
args2.push("--remnote-db", params3.remnoteDb);
|
|
101483
|
-
args2.push("--api-base-path", params3.basePath);
|
|
101484
|
-
args2.push("api", "serve", "--host", params3.host, "--port", String(params3.port), "--state-file", params3.stateFile);
|
|
101485
|
-
return { command, args: args2 };
|
|
101486
|
-
}
|
|
101487
|
-
function toPidFileValue2(params3) {
|
|
101488
|
-
return {
|
|
101489
|
-
pid: params3.pid,
|
|
101490
|
-
build: currentRuntimeBuildInfo(),
|
|
101491
|
-
started_at: params3.startedAt,
|
|
101492
|
-
host: params3.host,
|
|
101493
|
-
port: params3.port,
|
|
101494
|
-
base_path: params3.basePath,
|
|
101495
|
-
log_file: params3.logFile,
|
|
101496
|
-
state_file: params3.stateFile,
|
|
101497
|
-
cmd: params3.cmd
|
|
101498
|
-
};
|
|
101499
|
-
}
|
|
101500
|
-
function waitForApiHealth(baseUrl, waitMs) {
|
|
101501
|
-
return gen2(function* () {
|
|
101502
|
-
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
101503
|
-
return yield* fail8(new CliError({
|
|
101504
|
-
code: "INVALID_ARGS",
|
|
101505
|
-
message: "--wait must be a non-negative integer (ms)",
|
|
101506
|
-
exitCode: 2,
|
|
101507
|
-
details: { wait_ms: waitMs }
|
|
101508
|
-
}));
|
|
101509
|
-
}
|
|
101510
|
-
if (waitMs === 0)
|
|
101511
|
-
return;
|
|
101512
|
-
const api = yield* HostApiClient;
|
|
101513
|
-
const deadline = Date.now() + waitMs;
|
|
101514
|
-
while (Date.now() < deadline) {
|
|
101515
|
-
const remaining = Math.max(0, deadline - Date.now());
|
|
101516
|
-
const res = yield* api.health({ baseUrl, timeoutMs: Math.min(API_HEALTH_TIMEOUT_MS, Math.max(1, remaining)) }).pipe(either3);
|
|
101517
|
-
if (isRight2(res))
|
|
101518
|
-
return;
|
|
101519
|
-
yield* sleep4(millis(300));
|
|
101520
|
-
}
|
|
101521
|
-
return yield* fail8(new CliError({
|
|
101522
|
-
code: "API_TIMEOUT",
|
|
101523
|
-
message: `Timed out waiting for host API to become available (${waitMs}ms)`,
|
|
101524
|
-
exitCode: 1,
|
|
101525
|
-
details: { base_url: baseUrl, wait_ms: waitMs },
|
|
101526
|
-
hint: ["agent-remnote api status --json", "agent-remnote api logs", "agent-remnote stack status --json"]
|
|
101527
|
-
}));
|
|
101528
|
-
});
|
|
101529
|
-
}
|
|
101530
|
-
function startApiDaemon(params3) {
|
|
101531
|
-
return gen2(function* () {
|
|
101532
|
-
const cfg = yield* AppConfig;
|
|
101533
|
-
const api = yield* HostApiClient;
|
|
101534
|
-
const apiFiles = yield* ApiDaemonFiles;
|
|
101535
|
-
const proc = yield* Process;
|
|
101536
|
-
const host = params3.host ?? cfg.apiHost ?? "0.0.0.0";
|
|
101537
|
-
const port3 = params3.port ?? cfg.apiPort ?? 3000;
|
|
101538
|
-
const basePath2 = cfg.apiBasePath ?? "/v1";
|
|
101539
|
-
const pidFilePath = resolveUserFilePath(params3.pidFile ?? apiFiles.defaultPidFile());
|
|
101540
|
-
const logFilePath = resolveUserFilePath(params3.logFile ?? apiFiles.defaultLogFile());
|
|
101541
|
-
const stateFilePath = resolveUserFilePath(params3.stateFile ?? apiFiles.defaultStateFile());
|
|
101542
|
-
const localBaseUrl = apiLocalBaseUrl(port3, basePath2);
|
|
101543
|
-
const existing = yield* apiFiles.readPidFile(pidFilePath);
|
|
101544
|
-
if (existing) {
|
|
101545
|
-
const alive = yield* proc.isPidRunning(existing.pid);
|
|
101546
|
-
if (!alive) {
|
|
101547
|
-
yield* apiFiles.deletePidFile(pidFilePath);
|
|
101548
|
-
} else {
|
|
101549
|
-
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
101550
|
-
return {
|
|
101551
|
-
started: false,
|
|
101552
|
-
pid: existing.pid,
|
|
101553
|
-
pid_file: pidFilePath,
|
|
101554
|
-
log_file: logFilePath,
|
|
101555
|
-
state_file: stateFilePath,
|
|
101556
|
-
base_url: localBaseUrl
|
|
101557
|
-
};
|
|
101558
|
-
}
|
|
101559
|
-
}
|
|
101560
|
-
const pre = yield* api.health({ baseUrl: localBaseUrl, timeoutMs: API_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
101561
|
-
if (isRight2(pre)) {
|
|
101562
|
-
return {
|
|
101563
|
-
started: false,
|
|
101564
|
-
pid_file: pidFilePath,
|
|
101565
|
-
log_file: logFilePath,
|
|
101566
|
-
state_file: stateFilePath,
|
|
101567
|
-
base_url: localBaseUrl
|
|
101568
|
-
};
|
|
101569
|
-
}
|
|
101570
|
-
const cmd = yield* try_3({
|
|
101571
|
-
try: () => childCommandLine2({
|
|
101572
|
-
wsUrl: cfg.wsUrl,
|
|
101573
|
-
storeDb: cfg.storeDb,
|
|
101574
|
-
remnoteDb: cfg.remnoteDb,
|
|
101575
|
-
host,
|
|
101576
|
-
port: port3,
|
|
101577
|
-
basePath: basePath2,
|
|
101578
|
-
stateFile: stateFilePath
|
|
101579
|
-
}),
|
|
101580
|
-
catch: (e) => isCliError(e) ? e : new CliError({
|
|
101581
|
-
code: "INTERNAL",
|
|
101582
|
-
message: "Failed to start host api",
|
|
101583
|
-
exitCode: 1,
|
|
101584
|
-
details: { error: String(e?.message || e) }
|
|
101585
|
-
})
|
|
101586
|
-
});
|
|
101587
|
-
const pid = yield* proc.spawnDetached({ command: cmd.command, args: cmd.args, logFile: logFilePath });
|
|
101588
|
-
yield* apiFiles.writePidFile(pidFilePath, toPidFileValue2({
|
|
101589
|
-
pid,
|
|
101590
|
-
startedAt: Date.now(),
|
|
101591
|
-
host,
|
|
101592
|
-
port: port3,
|
|
101593
|
-
basePath: basePath2,
|
|
101594
|
-
logFile: logFilePath,
|
|
101595
|
-
stateFile: stateFilePath,
|
|
101596
|
-
cmd: [cmd.command, ...cmd.args]
|
|
101597
|
-
}));
|
|
101598
|
-
yield* waitForApiHealth(localBaseUrl, params3.waitMs);
|
|
101599
|
-
return {
|
|
101600
|
-
started: true,
|
|
101601
|
-
pid,
|
|
101602
|
-
pid_file: pidFilePath,
|
|
101603
|
-
log_file: logFilePath,
|
|
101604
|
-
state_file: stateFilePath,
|
|
101605
|
-
base_url: localBaseUrl
|
|
101606
|
-
};
|
|
101976
|
+
data: {
|
|
101977
|
+
dry_run: true,
|
|
101978
|
+
kind: compiled.kind,
|
|
101979
|
+
ops: compiled.ops,
|
|
101980
|
+
alias_map: compiled.aliasMap,
|
|
101981
|
+
meta: metaValue ? payloadSvc.normalizeKeys(metaValue) : undefined
|
|
101982
|
+
},
|
|
101983
|
+
md: `- dry_run: true
|
|
101984
|
+
- kind: ${compiled.kind}
|
|
101985
|
+
- ops: ${compiled.ops.length}
|
|
101986
|
+
`
|
|
101987
|
+
});
|
|
101988
|
+
return;
|
|
101989
|
+
}
|
|
101990
|
+
yield* validateOptionMutationOps({ scopeLabel: "generic", ops: compiled.ops });
|
|
101991
|
+
const data = yield* invokeWave1Capability("write.apply", {
|
|
101992
|
+
body: {
|
|
101993
|
+
...expanded,
|
|
101994
|
+
priority: resolvedPriority,
|
|
101995
|
+
clientId: resolvedClientId,
|
|
101996
|
+
idempotencyKey: resolvedIdempotencyKey,
|
|
101997
|
+
meta: metaValue,
|
|
101998
|
+
notify: notify3 ?? compiled.notify ?? true,
|
|
101999
|
+
ensureDaemon: ensureDaemon4 ?? compiled.ensureDaemon ?? true
|
|
102000
|
+
},
|
|
102001
|
+
wait: wait3,
|
|
102002
|
+
timeoutMs: timeoutMs3,
|
|
102003
|
+
pollMs: pollMs3
|
|
101607
102004
|
});
|
|
101608
|
-
}
|
|
101609
|
-
|
|
101610
|
-
|
|
101611
|
-
|
|
101612
|
-
|
|
101613
|
-
|
|
101614
|
-
|
|
101615
|
-
|
|
101616
|
-
|
|
101617
|
-
const pidFilePath = resolveUserFilePath(params3.pidFile ?? apiFiles.defaultPidFile());
|
|
101618
|
-
const logFilePath = resolveUserFilePath(params3.logFile ?? apiFiles.defaultLogFile());
|
|
101619
|
-
const stateFilePath = resolveUserFilePath(params3.stateFile ?? apiFiles.defaultStateFile());
|
|
101620
|
-
const localBaseUrl = apiLocalBaseUrl(port3, basePath2);
|
|
101621
|
-
const pre = yield* api.health({ baseUrl: localBaseUrl, timeoutMs: API_HEALTH_TIMEOUT_MS }).pipe(either3);
|
|
101622
|
-
if (isRight2(pre)) {
|
|
101623
|
-
const existing = yield* apiFiles.readPidFile(pidFilePath);
|
|
101624
|
-
if (existing) {
|
|
101625
|
-
const alive = yield* proc.isPidRunning(existing.pid);
|
|
101626
|
-
if (alive) {
|
|
101627
|
-
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
101628
|
-
return {
|
|
101629
|
-
started: false,
|
|
101630
|
-
pid: existing.pid,
|
|
101631
|
-
pid_file: pidFilePath,
|
|
101632
|
-
log_file: existing.log_file ?? logFilePath,
|
|
101633
|
-
state_file: existing.state_file ?? stateFilePath,
|
|
101634
|
-
base_url: localBaseUrl
|
|
101635
|
-
};
|
|
101636
|
-
}
|
|
101637
|
-
}
|
|
101638
|
-
return {
|
|
101639
|
-
started: false,
|
|
101640
|
-
pid_file: pidFilePath,
|
|
101641
|
-
log_file: logFilePath,
|
|
101642
|
-
state_file: stateFilePath,
|
|
101643
|
-
base_url: localBaseUrl
|
|
101644
|
-
};
|
|
101645
|
-
}
|
|
101646
|
-
return yield* startApiDaemon(params3);
|
|
102005
|
+
const out = compiled.kind === "actions" ? { ...data, alias_map: data?.alias_map ?? compiled.aliasMap } : data;
|
|
102006
|
+
yield* writeSuccess({
|
|
102007
|
+
data: out,
|
|
102008
|
+
ids: [data.txn_id, ...data.op_ids],
|
|
102009
|
+
md: `- txn_id: ${data.txn_id}
|
|
102010
|
+
- op_ids: ${data.op_ids.length}
|
|
102011
|
+
- notified: ${data.notified}
|
|
102012
|
+
- sent: ${data.sent ?? ""}
|
|
102013
|
+
`
|
|
101647
102014
|
});
|
|
101648
|
-
}
|
|
102015
|
+
}).pipe(catchAll2(writeFailure)));
|
|
101649
102016
|
|
|
101650
102017
|
// src/commands/api/ensure.ts
|
|
101651
102018
|
function optionToUndefined17(opt) {
|
|
@@ -103017,203 +103384,6 @@ var pluginCurrentCommand = exports_Command.make("current", { stateFile: stateFil
|
|
|
103017
103384
|
yield* writeSuccess({ data: out, ids: ids3, md });
|
|
103018
103385
|
}).pipe(catchAll2(writeFailure)));
|
|
103019
103386
|
|
|
103020
|
-
// src/lib/pluginServerHealth.ts
|
|
103021
|
-
function checkPluginServerHealth(baseUrl, timeoutMs3) {
|
|
103022
|
-
return tryPromise2({
|
|
103023
|
-
try: async () => {
|
|
103024
|
-
const controller = new AbortController;
|
|
103025
|
-
const timer2 = setTimeout(() => controller.abort(), timeoutMs3);
|
|
103026
|
-
try {
|
|
103027
|
-
const res = await fetch(`${baseUrl}/manifest.json`, { signal: controller.signal });
|
|
103028
|
-
if (!res.ok) {
|
|
103029
|
-
throw new Error(`Unexpected response status: ${res.status}`);
|
|
103030
|
-
}
|
|
103031
|
-
return { base_url: baseUrl };
|
|
103032
|
-
} finally {
|
|
103033
|
-
clearTimeout(timer2);
|
|
103034
|
-
}
|
|
103035
|
-
},
|
|
103036
|
-
catch: (error4) => new CliError({
|
|
103037
|
-
code: "PLUGIN_UNAVAILABLE",
|
|
103038
|
-
message: "Plugin server is unavailable",
|
|
103039
|
-
exitCode: 1,
|
|
103040
|
-
details: { base_url: baseUrl, error: String(error4?.message || error4) }
|
|
103041
|
-
})
|
|
103042
|
-
});
|
|
103043
|
-
}
|
|
103044
|
-
function waitForPluginServerHealth(baseUrl, waitMs, timeoutMs3) {
|
|
103045
|
-
return gen2(function* () {
|
|
103046
|
-
if (!Number.isFinite(waitMs) || waitMs < 0) {
|
|
103047
|
-
return yield* fail8(new CliError({
|
|
103048
|
-
code: "INVALID_ARGS",
|
|
103049
|
-
message: "--wait must be a non-negative integer (ms)",
|
|
103050
|
-
exitCode: 2,
|
|
103051
|
-
details: { wait_ms: waitMs }
|
|
103052
|
-
}));
|
|
103053
|
-
}
|
|
103054
|
-
if (waitMs === 0)
|
|
103055
|
-
return;
|
|
103056
|
-
const deadline = Date.now() + waitMs;
|
|
103057
|
-
while (Date.now() < deadline) {
|
|
103058
|
-
const remaining = Math.max(0, deadline - Date.now());
|
|
103059
|
-
const res = yield* checkPluginServerHealth(baseUrl, Math.min(timeoutMs3, Math.max(1, remaining))).pipe(either3);
|
|
103060
|
-
if (isRight2(res))
|
|
103061
|
-
return;
|
|
103062
|
-
yield* sleep4(millis(300));
|
|
103063
|
-
}
|
|
103064
|
-
return yield* fail8(new CliError({
|
|
103065
|
-
code: "PLUGIN_UNAVAILABLE",
|
|
103066
|
-
message: `Timed out waiting for plugin server to become available (${waitMs}ms)`,
|
|
103067
|
-
exitCode: 1,
|
|
103068
|
-
details: { base_url: baseUrl, wait_ms: waitMs },
|
|
103069
|
-
hint: ["agent-remnote plugin status --json", "agent-remnote plugin logs --lines 200"]
|
|
103070
|
-
}));
|
|
103071
|
-
});
|
|
103072
|
-
}
|
|
103073
|
-
|
|
103074
|
-
// src/commands/plugin/_shared.ts
|
|
103075
|
-
var PLUGIN_SERVER_HEALTH_TIMEOUT_MS = 2000;
|
|
103076
|
-
var PLUGIN_SERVER_START_WAIT_DEFAULT_MS = 15000;
|
|
103077
|
-
var PLUGIN_SERVER_STOP_WAIT_DEFAULT_MS = 5000;
|
|
103078
|
-
var PLUGIN_SERVER_DEFAULT_HOST = "127.0.0.1";
|
|
103079
|
-
var PLUGIN_SERVER_DEFAULT_PORT = 8080;
|
|
103080
|
-
function pluginServerLocalBaseUrl(host5, port7) {
|
|
103081
|
-
const normalizedHost = host5 === "0.0.0.0" || host5 === "::" ? "127.0.0.1" : host5;
|
|
103082
|
-
return `http://${normalizedHost}:${port7}`;
|
|
103083
|
-
}
|
|
103084
|
-
function childCommandLine3(params3) {
|
|
103085
|
-
const command = process.argv[0];
|
|
103086
|
-
const script = process.argv[1];
|
|
103087
|
-
if (!command || !script) {
|
|
103088
|
-
throw new CliError({
|
|
103089
|
-
code: "INTERNAL",
|
|
103090
|
-
message: "Unable to determine the current executable entrypoint (process.argv is incomplete)",
|
|
103091
|
-
exitCode: 1,
|
|
103092
|
-
details: { argv: process.argv }
|
|
103093
|
-
});
|
|
103094
|
-
}
|
|
103095
|
-
const execArgv = Array.isArray(process.execArgv) ? process.execArgv : [];
|
|
103096
|
-
const args2 = [...execArgv, script, "plugin", "serve", "--host", params3.host, "--port", String(params3.port), "--state-file", params3.stateFile];
|
|
103097
|
-
return { command, args: args2 };
|
|
103098
|
-
}
|
|
103099
|
-
function toPidFileValue3(params3) {
|
|
103100
|
-
return {
|
|
103101
|
-
pid: params3.pid,
|
|
103102
|
-
build: currentRuntimeBuildInfo(),
|
|
103103
|
-
started_at: params3.startedAt,
|
|
103104
|
-
host: params3.host,
|
|
103105
|
-
port: params3.port,
|
|
103106
|
-
log_file: params3.logFile,
|
|
103107
|
-
state_file: params3.stateFile,
|
|
103108
|
-
cmd: params3.cmd
|
|
103109
|
-
};
|
|
103110
|
-
}
|
|
103111
|
-
function startPluginServer(params3) {
|
|
103112
|
-
return gen2(function* () {
|
|
103113
|
-
const files = yield* PluginServerFiles;
|
|
103114
|
-
const proc = yield* Process;
|
|
103115
|
-
const host5 = params3.host ?? PLUGIN_SERVER_DEFAULT_HOST;
|
|
103116
|
-
const port7 = params3.port ?? PLUGIN_SERVER_DEFAULT_PORT;
|
|
103117
|
-
const pidFilePath = resolveUserFilePath(params3.pidFile ?? files.defaultPidFile());
|
|
103118
|
-
const logFilePath = resolveUserFilePath(params3.logFile ?? files.defaultLogFile());
|
|
103119
|
-
const stateFilePath = resolveUserFilePath(params3.stateFile ?? files.defaultStateFile());
|
|
103120
|
-
const baseUrl = pluginServerLocalBaseUrl(host5, port7);
|
|
103121
|
-
const existing = yield* files.readPidFile(pidFilePath);
|
|
103122
|
-
if (existing) {
|
|
103123
|
-
const alive = yield* proc.isPidRunning(existing.pid);
|
|
103124
|
-
if (!alive) {
|
|
103125
|
-
yield* files.deletePidFile(pidFilePath);
|
|
103126
|
-
} else {
|
|
103127
|
-
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
103128
|
-
return {
|
|
103129
|
-
started: false,
|
|
103130
|
-
pid: existing.pid,
|
|
103131
|
-
pid_file: pidFilePath,
|
|
103132
|
-
log_file: existing.log_file ?? logFilePath,
|
|
103133
|
-
state_file: existing.state_file ?? stateFilePath,
|
|
103134
|
-
base_url: baseUrl
|
|
103135
|
-
};
|
|
103136
|
-
}
|
|
103137
|
-
}
|
|
103138
|
-
const pre = yield* checkPluginServerHealth(baseUrl, PLUGIN_SERVER_HEALTH_TIMEOUT_MS).pipe(either3);
|
|
103139
|
-
if (isRight2(pre)) {
|
|
103140
|
-
return {
|
|
103141
|
-
started: false,
|
|
103142
|
-
pid_file: pidFilePath,
|
|
103143
|
-
log_file: logFilePath,
|
|
103144
|
-
state_file: stateFilePath,
|
|
103145
|
-
base_url: baseUrl
|
|
103146
|
-
};
|
|
103147
|
-
}
|
|
103148
|
-
const cmd = yield* try_3({
|
|
103149
|
-
try: () => childCommandLine3({ host: host5, port: port7, stateFile: stateFilePath }),
|
|
103150
|
-
catch: (error4) => isCliError(error4) ? error4 : new CliError({
|
|
103151
|
-
code: "INTERNAL",
|
|
103152
|
-
message: "Failed to start plugin server",
|
|
103153
|
-
exitCode: 1,
|
|
103154
|
-
details: { error: String(error4?.message || error4) }
|
|
103155
|
-
})
|
|
103156
|
-
});
|
|
103157
|
-
const pid = yield* proc.spawnDetached({ command: cmd.command, args: cmd.args, logFile: logFilePath });
|
|
103158
|
-
yield* files.writePidFile(pidFilePath, toPidFileValue3({
|
|
103159
|
-
pid,
|
|
103160
|
-
startedAt: Date.now(),
|
|
103161
|
-
host: host5,
|
|
103162
|
-
port: port7,
|
|
103163
|
-
logFile: logFilePath,
|
|
103164
|
-
stateFile: stateFilePath,
|
|
103165
|
-
cmd: [cmd.command, ...cmd.args]
|
|
103166
|
-
}));
|
|
103167
|
-
yield* waitForPluginServerHealth(baseUrl, params3.waitMs, PLUGIN_SERVER_HEALTH_TIMEOUT_MS);
|
|
103168
|
-
return {
|
|
103169
|
-
started: true,
|
|
103170
|
-
pid,
|
|
103171
|
-
pid_file: pidFilePath,
|
|
103172
|
-
log_file: logFilePath,
|
|
103173
|
-
state_file: stateFilePath,
|
|
103174
|
-
base_url: baseUrl
|
|
103175
|
-
};
|
|
103176
|
-
});
|
|
103177
|
-
}
|
|
103178
|
-
function ensurePluginServer(params3) {
|
|
103179
|
-
return gen2(function* () {
|
|
103180
|
-
const files = yield* PluginServerFiles;
|
|
103181
|
-
const proc = yield* Process;
|
|
103182
|
-
const host5 = params3.host ?? PLUGIN_SERVER_DEFAULT_HOST;
|
|
103183
|
-
const port7 = params3.port ?? PLUGIN_SERVER_DEFAULT_PORT;
|
|
103184
|
-
const pidFilePath = resolveUserFilePath(params3.pidFile ?? files.defaultPidFile());
|
|
103185
|
-
const logFilePath = resolveUserFilePath(params3.logFile ?? files.defaultLogFile());
|
|
103186
|
-
const stateFilePath = resolveUserFilePath(params3.stateFile ?? files.defaultStateFile());
|
|
103187
|
-
const baseUrl = pluginServerLocalBaseUrl(host5, port7);
|
|
103188
|
-
const pre = yield* checkPluginServerHealth(baseUrl, PLUGIN_SERVER_HEALTH_TIMEOUT_MS).pipe(either3);
|
|
103189
|
-
if (isRight2(pre)) {
|
|
103190
|
-
const existing = yield* files.readPidFile(pidFilePath);
|
|
103191
|
-
if (existing) {
|
|
103192
|
-
const alive = yield* proc.isPidRunning(existing.pid);
|
|
103193
|
-
if (alive) {
|
|
103194
|
-
yield* requireTrustedPidRecord({ record: existing, pidFilePath });
|
|
103195
|
-
return {
|
|
103196
|
-
started: false,
|
|
103197
|
-
pid: existing.pid,
|
|
103198
|
-
pid_file: pidFilePath,
|
|
103199
|
-
log_file: existing.log_file ?? logFilePath,
|
|
103200
|
-
state_file: existing.state_file ?? stateFilePath,
|
|
103201
|
-
base_url: baseUrl
|
|
103202
|
-
};
|
|
103203
|
-
}
|
|
103204
|
-
}
|
|
103205
|
-
return {
|
|
103206
|
-
started: false,
|
|
103207
|
-
pid_file: pidFilePath,
|
|
103208
|
-
log_file: logFilePath,
|
|
103209
|
-
state_file: stateFilePath,
|
|
103210
|
-
base_url: baseUrl
|
|
103211
|
-
};
|
|
103212
|
-
}
|
|
103213
|
-
return yield* startPluginServer(params3);
|
|
103214
|
-
});
|
|
103215
|
-
}
|
|
103216
|
-
|
|
103217
103387
|
// src/commands/plugin/ensure.ts
|
|
103218
103388
|
function optionToUndefined33(opt) {
|
|
103219
103389
|
return isSome2(opt) ? opt.value : undefined;
|