nodal-agents 0.8.9 → 0.8.10
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/cli.js +1780 -501
- package/migrations/0107_agent_reflection_enabled.sql +13 -0
- package/migrations/meta/_journal.json +7 -0
- package/node_modules/brace-expansion/index.js +78 -22
- package/node_modules/brace-expansion/package.json +1 -1
- package/node_modules/readdir-glob/node_modules/brace-expansion/index.js +78 -22
- package/node_modules/readdir-glob/node_modules/brace-expansion/package.json +1 -1
- package/package.json +2 -2
- package/runner.js +40473 -21854
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +3 -3
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +2 -2
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/code/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/code/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/code/page.js +1 -1
- package/web/.next/server/app/(dashboard)/code/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page.js +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page.js +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/scheduled/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/scheduled/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/scheduled/page.js +1 -1
- package/web/.next/server/app/(dashboard)/scheduled/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/[id]/files/page.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/[id]/files/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/page.js +1 -1
- package/web/.next/server/app/(dashboard)/spaces/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +1 -1
- package/web/.next/server/app/_global-error.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/server/app/_not-found.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/api/auth/[...all]/route.js +1 -1
- package/web/.next/server/app/api/health/route.js +1 -1
- package/web/.next/server/app/api/oauth/[provider]/callback/route.js +1 -1
- package/web/.next/server/app/api/oauth/[provider]/start/route.js +1 -1
- package/web/.next/server/app/login/page.js +1 -1
- package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding/page.js +2 -2
- package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app-paths-manifest.json +3 -3
- package/web/.next/server/chunks/1195.js +1 -1
- package/web/.next/server/chunks/12.js +1 -0
- package/web/.next/server/chunks/210.js +1 -1
- package/web/.next/server/chunks/231.js +7 -7
- package/web/.next/server/chunks/246.js +1 -0
- package/web/.next/server/chunks/3116.js +1 -0
- package/web/.next/server/chunks/353.js +1 -1
- package/web/.next/server/chunks/3598.js +1 -1
- package/web/.next/server/chunks/3660.js +1 -0
- package/web/.next/server/chunks/{5329.js → 3925.js} +1 -1
- package/web/.next/server/chunks/42.js +2 -2
- package/web/.next/server/chunks/4483.js +3 -3
- package/web/.next/server/chunks/4928.js +1 -0
- package/web/.next/server/chunks/5812.js +1 -0
- package/web/.next/server/chunks/6031.js +27 -10
- package/web/.next/server/chunks/6365.js +1 -0
- package/web/.next/server/chunks/6551.js +6 -6
- package/web/.next/server/chunks/7534.js +1 -1
- package/web/.next/server/chunks/{4659.js → 7927.js} +9 -9
- package/web/.next/server/chunks/9128.js +1 -0
- package/web/.next/server/chunks/9348.js +1786 -0
- package/web/.next/server/chunks/{2520.js → 990.js} +87 -87
- package/web/.next/server/chunks/9949.js +69 -34
- package/web/.next/server/middleware-build-manifest.js +1 -1
- package/web/.next/server/middleware.js +23 -23
- package/web/.next/server/pages/404.html +1 -1
- package/web/.next/server/pages/500.html +1 -1
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/static/chunks/1110-99defede02094d03.js +1 -0
- package/web/.next/static/chunks/{3024-0a4647e55c953355.js → 3024-750df22c9a0f5f85.js} +1 -1
- package/web/.next/static/chunks/5034-bffbb6ba9aa605de.js +1 -0
- package/web/.next/static/chunks/6646-3b01d0a39e57a4a3.js +1 -0
- package/web/.next/static/chunks/{7904-f76ecb7fb0ab1b3e.js → 7904-e8c495d3fd5c135e.js} +1 -1
- package/web/.next/static/chunks/{8551-0843f388c81ecc4b.js → 8551-66f5a96f8b5ffdd6.js} +38 -21
- package/web/.next/static/chunks/{8606-679d56e81c4e4550.js → 8606-3b4575644121850b.js} +1 -1
- package/web/.next/static/chunks/9558-ed5cb02a15adeea2.js +1 -0
- package/web/.next/static/chunks/9927-e98e963eb2b7f8ed.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-64aadeb968a4aa5e.js +6 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/page-560e79db5926719a.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-eb63ecada43087fb.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/automations/page-8f27f571bb29513e.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/chat/[id]/page-80be9c2ebf0fcf09.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/chat/page-ee43b81b1aa4f36d.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/code/page-19f2af65e857b0ea.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-c350d2304c92e578.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-7a25f352889a5986.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-c0a871cd968cb52c.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/layout-3f68f447adcef6c5.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-38f024a9ed713e0d.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-cac00d11a48f0521.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/logs/page-0c84de37cfc53542.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/mcp/{page-d38ced6b48036c96.js → page-5d72536a3ea874e5.js} +1 -1
- package/web/.next/static/chunks/app/(dashboard)/memories/page-095d01600502f349.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/page-9b219470f8e9a5cb.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/scheduled/[id]/page-9f77ef5800089d92.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/page-fba1c42c418aea4e.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-eecb34bf4c12d570.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-5b1dcfe6bae606ad.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-716cdb9f6925f3f0.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/page-3c6ed7b04a409801.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/spaces/[id]/files/page-8cafe5c7f9e10cc5.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/spaces/[id]/page-e4f3d4e4fb1bf5b7.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/spaces/page-c4eb76ef7e0abcd8.js +1 -0
- package/web/.next/static/chunks/app/login/page-c0820c56e4376430.js +1 -0
- package/web/.next/static/chunks/app/onboarding/{page-79a89445432931ef.js → page-5d1b037a182b93b2.js} +2 -2
- package/web/.next/static/css/{537b435215d30466.css → 306e66bd437fbf32.css} +1 -1
- package/web/.next/server/chunks/2719.js +0 -1
- package/web/.next/server/chunks/3234.js +0 -1
- package/web/.next/server/chunks/3373.js +0 -1751
- package/web/.next/server/chunks/3483.js +0 -1
- package/web/.next/server/chunks/5020.js +0 -1
- package/web/.next/server/chunks/5042.js +0 -1
- package/web/.next/server/chunks/5767.js +0 -1
- package/web/.next/server/chunks/6143.js +0 -1
- package/web/.next/server/chunks/9717.js +0 -1
- package/web/.next/static/chunks/5034-7816e7ad05216095.js +0 -1
- package/web/.next/static/chunks/5386-f067c56f0ed0afd3.js +0 -1
- package/web/.next/static/chunks/6646-21e7105302193b0e.js +0 -1
- package/web/.next/static/chunks/704-0a3bf99b751ca9ab.js +0 -1
- package/web/.next/static/chunks/9927-c5951099612edcfb.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-0e0a349399606e8b.js +0 -6
- package/web/.next/static/chunks/app/(dashboard)/agents/page-6a8dc12dab1f2874.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/approvals/page-db286cc0a738971b.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/automations/page-c5b1e906f5cb0fe4.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/chat/[id]/page-ddb150b1540988ef.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/chat/page-22788334e4244f90.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/code/page-1571073f95522746.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-949c964856b89951.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-a431b6b1b9f6fea7.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-c2822831e76daf0c.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/layout-ef725b83f773ce1b.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-77a8fdd2d5e31e66.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-a5399e46d3a46a96.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/logs/page-9a887fc28ea3b341.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/memories/page-e8ae3c3c0d80b98f.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/page-c7fe8cb11a48378f.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/scheduled/[id]/page-da3e335c850aac91.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/page-1d22f35fbd41c4c8.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-d2e259fd4c3d09b0.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-6709a7b491ae41fd.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-5d98e96847c72eb5.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/page-c8b3805c9a058b07.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/spaces/[id]/files/page-2f444597fa0abf62.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/spaces/[id]/page-1c2b118f4ef10f7b.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/spaces/page-2d1554b9266429de.js +0 -1
- package/web/.next/static/chunks/app/login/page-d40c57350fe5366f.js +0 -1
- /package/web/.next/static/{vp639cRRGWy7XZlwOEsL8 → C1Q1ncZzMXdFifa-Gr7Wp}/_buildManifest.js +0 -0
- /package/web/.next/static/{vp639cRRGWy7XZlwOEsL8 → C1Q1ncZzMXdFifa-Gr7Wp}/_ssgManifest.js +0 -0
package/cli.js
CHANGED
|
@@ -262,6 +262,214 @@ var init_config = __esm({
|
|
|
262
262
|
}
|
|
263
263
|
});
|
|
264
264
|
|
|
265
|
+
// src/lib/pg-logging.ts
|
|
266
|
+
import {
|
|
267
|
+
existsSync as existsSync3,
|
|
268
|
+
mkdirSync as mkdirSync2,
|
|
269
|
+
readFileSync as readFileSync2,
|
|
270
|
+
renameSync,
|
|
271
|
+
unlinkSync,
|
|
272
|
+
writeFileSync as writeFileSync2
|
|
273
|
+
} from "fs";
|
|
274
|
+
import { join as join3, resolve } from "path";
|
|
275
|
+
import { createHash } from "crypto";
|
|
276
|
+
function postgresLogDirFor(dataDir) {
|
|
277
|
+
const normalised = normaliseDataDir(dataDir);
|
|
278
|
+
const digest = createHash("sha256").update(normalised).digest("hex").slice(0, 8);
|
|
279
|
+
const leaf = normalised.split("/").filter(Boolean).pop() ?? "pg-data";
|
|
280
|
+
return join3(PG_LOG_DIR, `${leaf.replace(/[^A-Za-z0-9._-]/g, "_")}-${digest}`);
|
|
281
|
+
}
|
|
282
|
+
function normaliseDataDir(dataDir) {
|
|
283
|
+
const resolved = toPosixPath(resolve(dataDir)).replace(/\/+$/, "");
|
|
284
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
285
|
+
}
|
|
286
|
+
function toPosixPath(path) {
|
|
287
|
+
return path.split("\\").join("/");
|
|
288
|
+
}
|
|
289
|
+
function postgresLoggingSettings(logDirectory) {
|
|
290
|
+
return {
|
|
291
|
+
logging_collector: "on",
|
|
292
|
+
log_destination: "stderr",
|
|
293
|
+
log_directory: toPosixPath(logDirectory),
|
|
294
|
+
log_filename: "postgresql-%Y-%m-%d.log",
|
|
295
|
+
log_rotation_age: "1d",
|
|
296
|
+
log_rotation_size: `${PG_LOG_ROTATION_SIZE_KB}kB`,
|
|
297
|
+
log_truncate_on_rotation: "on",
|
|
298
|
+
// See the header: this KEEPS the crash lines, it does not drop them.
|
|
299
|
+
log_min_messages: "warning",
|
|
300
|
+
// %m = timestamp with milliseconds, %p = pid of the process writing the
|
|
301
|
+
// line. Both are load-bearing for #111: attributing a crash means matching
|
|
302
|
+
// a pid against what a process table said at a given instant.
|
|
303
|
+
log_line_prefix: "%m [%p] %q%u@%d ",
|
|
304
|
+
// A postmaster that reaps a crashed child names the signal only if it is
|
|
305
|
+
// still around to write the line. On by default; said out loud because the
|
|
306
|
+
// whole diagnosis depends on it.
|
|
307
|
+
restart_after_crash: "on"
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function managedKeys() {
|
|
311
|
+
return new Set(Object.keys(postgresLoggingSettings("x")));
|
|
312
|
+
}
|
|
313
|
+
function quoteGuc(value) {
|
|
314
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
315
|
+
}
|
|
316
|
+
function mergeAutoConf(existing, settings) {
|
|
317
|
+
const managed = managedKeys();
|
|
318
|
+
const kept = [];
|
|
319
|
+
for (const line2 of existing.split(/\r?\n/)) {
|
|
320
|
+
const trimmed = line2.trim();
|
|
321
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
322
|
+
const eq2 = trimmed.indexOf("=");
|
|
323
|
+
if (eq2 < 0) continue;
|
|
324
|
+
const key = trimmed.slice(0, eq2).trim();
|
|
325
|
+
if (managed.has(key)) continue;
|
|
326
|
+
kept.push(trimmed);
|
|
327
|
+
}
|
|
328
|
+
const ours = Object.entries(settings).map(([k, v]) => `${k} = ${quoteGuc(v)}`);
|
|
329
|
+
return "# Do not edit this file manually!\n# It will be overwritten by the ALTER SYSTEM command,\n# and by nodal-agents for the logging_* settings (see apps/cli/src/lib/pg-logging.ts).\n" + [...kept, ...ours].join("\n") + "\n";
|
|
330
|
+
}
|
|
331
|
+
function applyPostgresLoggingConfig(dataDir, logDirectory) {
|
|
332
|
+
mkdirSync2(logDirectory, { recursive: true });
|
|
333
|
+
const target = join3(dataDir, "postgresql.auto.conf");
|
|
334
|
+
let existing = "";
|
|
335
|
+
if (existsSync3(target)) {
|
|
336
|
+
try {
|
|
337
|
+
existing = readFileSync2(target, "utf-8");
|
|
338
|
+
} catch {
|
|
339
|
+
existing = "";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
writeAtomically(target, mergeAutoConf(existing, postgresLoggingSettings(logDirectory)));
|
|
343
|
+
return logDirectory;
|
|
344
|
+
}
|
|
345
|
+
function tempConfPath(target) {
|
|
346
|
+
return `${target}.nodalai.tmp`;
|
|
347
|
+
}
|
|
348
|
+
function writeAtomically(target, contents) {
|
|
349
|
+
const tmp = tempConfPath(target);
|
|
350
|
+
writeFileSync2(tmp, contents, "utf-8");
|
|
351
|
+
try {
|
|
352
|
+
renameSync(tmp, target);
|
|
353
|
+
} catch (err) {
|
|
354
|
+
try {
|
|
355
|
+
unlinkSync(tmp);
|
|
356
|
+
} catch {
|
|
357
|
+
}
|
|
358
|
+
throw err;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
var PG_LOG_DIR, PG_LOG_ROTATION_SIZE_KB;
|
|
362
|
+
var init_pg_logging = __esm({
|
|
363
|
+
"src/lib/pg-logging.ts"() {
|
|
364
|
+
"use strict";
|
|
365
|
+
init_config();
|
|
366
|
+
PG_LOG_DIR = join3(LOG_DIR, "postgres");
|
|
367
|
+
PG_LOG_ROTATION_SIZE_KB = 20 * 1024;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// src/lib/orphans.ts
|
|
372
|
+
function parseProcessRows(stdout) {
|
|
373
|
+
const rows = [];
|
|
374
|
+
for (const line2 of stdout.split(/\r?\n/)) {
|
|
375
|
+
const first = line2.indexOf("|");
|
|
376
|
+
if (first < 0) continue;
|
|
377
|
+
const second = line2.indexOf("|", first + 1);
|
|
378
|
+
if (second < 0) continue;
|
|
379
|
+
const third = line2.indexOf("|", second + 1);
|
|
380
|
+
if (third < 0) continue;
|
|
381
|
+
const pid = Number.parseInt(line2.slice(0, first), 10);
|
|
382
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
383
|
+
const ppid = Number.parseInt(line2.slice(first + 1, second), 10);
|
|
384
|
+
const startedAt = Number.parseInt(line2.slice(second + 1, third), 10);
|
|
385
|
+
rows.push({
|
|
386
|
+
pid,
|
|
387
|
+
ppid: Number.isInteger(ppid) ? ppid : 0,
|
|
388
|
+
commandLine: line2.slice(third + 1),
|
|
389
|
+
...Number.isInteger(startedAt) && startedAt > 0 ? { startedAt } : {}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return rows;
|
|
393
|
+
}
|
|
394
|
+
function isPlausibleParent(parent, child) {
|
|
395
|
+
if (parent.startedAt === void 0 || child.startedAt === void 0) return false;
|
|
396
|
+
return parent.startedAt <= child.startedAt;
|
|
397
|
+
}
|
|
398
|
+
function ownedPostgresPids(input) {
|
|
399
|
+
const owned = [];
|
|
400
|
+
const skipped = [];
|
|
401
|
+
const claim = input.claim;
|
|
402
|
+
if (claim === null) {
|
|
403
|
+
for (const row of input.rows) {
|
|
404
|
+
skipped.push({ pid: row.pid, reason: "no postmaster.pid claims this data dir" });
|
|
405
|
+
}
|
|
406
|
+
return { owned, skipped };
|
|
407
|
+
}
|
|
408
|
+
const byPid = /* @__PURE__ */ new Map();
|
|
409
|
+
for (const row of input.rows) byPid.set(row.pid, row);
|
|
410
|
+
const postmaster = byPid.get(claim.pid);
|
|
411
|
+
if (!input.tableRead) {
|
|
412
|
+
for (const row of input.rows) {
|
|
413
|
+
skipped.push({ pid: row.pid, reason: "the process table could not be read" });
|
|
414
|
+
}
|
|
415
|
+
return { owned, skipped };
|
|
416
|
+
}
|
|
417
|
+
{
|
|
418
|
+
if (postmaster === void 0) {
|
|
419
|
+
for (const row of input.rows) {
|
|
420
|
+
skipped.push({ pid: row.pid, reason: `lockfile pid ${claim.pid} is not a live postgres` });
|
|
421
|
+
}
|
|
422
|
+
return { owned, skipped };
|
|
423
|
+
}
|
|
424
|
+
if (!startMatchesClaim(postmaster, claim)) {
|
|
425
|
+
for (const row of input.rows) {
|
|
426
|
+
skipped.push({
|
|
427
|
+
pid: row.pid,
|
|
428
|
+
reason: `pid ${claim.pid} started at ${String(postmaster.startedAt)}, lockfile says ${String(claim.startedAtSeconds)}`
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
return { owned, skipped };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
owned.push(claim.pid);
|
|
435
|
+
for (const row of input.rows) {
|
|
436
|
+
if (row.pid === claim.pid) continue;
|
|
437
|
+
if (descendsFrom(row, claim.pid, byPid)) owned.push(row.pid);
|
|
438
|
+
else skipped.push({ pid: row.pid, reason: `ancestry=${row.ppid} does not reach ${claim.pid}` });
|
|
439
|
+
}
|
|
440
|
+
return { owned, skipped };
|
|
441
|
+
}
|
|
442
|
+
function startMatchesClaim(process3, claim) {
|
|
443
|
+
if (process3.startedAt === void 0 || claim.startedAtSeconds === null) return false;
|
|
444
|
+
return Math.abs(process3.startedAt - claim.startedAtSeconds * 1e3) <= START_TIME_TOLERANCE_MS;
|
|
445
|
+
}
|
|
446
|
+
function descendsFrom(row, ancestorPid, byPid) {
|
|
447
|
+
const seen = /* @__PURE__ */ new Set([row.pid]);
|
|
448
|
+
let child = row;
|
|
449
|
+
let cursor = byPid.get(row.ppid);
|
|
450
|
+
while (cursor && !seen.has(cursor.pid)) {
|
|
451
|
+
if (!isPlausibleParent(cursor, child)) return false;
|
|
452
|
+
if (cursor.pid === ancestorPid) return true;
|
|
453
|
+
seen.add(cursor.pid);
|
|
454
|
+
child = cursor;
|
|
455
|
+
cursor = byPid.get(cursor.ppid);
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
function measuredPort(pid, listeners) {
|
|
460
|
+
return listeners.find((l) => l.pid === pid)?.port ?? null;
|
|
461
|
+
}
|
|
462
|
+
function formatForeignSkip(entry) {
|
|
463
|
+
return `ORPHAN_PROBE_FOREIGN_POSTGRES_SKIPPED pid=${entry.pid} reason=${entry.reason}`;
|
|
464
|
+
}
|
|
465
|
+
var START_TIME_TOLERANCE_MS;
|
|
466
|
+
var init_orphans = __esm({
|
|
467
|
+
"src/lib/orphans.ts"() {
|
|
468
|
+
"use strict";
|
|
469
|
+
START_TIME_TOLERANCE_MS = 2e3;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
265
473
|
// ../../node_modules/.pnpm/postgres@3.4.9/node_modules/postgres/src/query.js
|
|
266
474
|
function cachedError(xs) {
|
|
267
475
|
if (originCache.has(xs))
|
|
@@ -282,9 +490,9 @@ var init_query = __esm({
|
|
|
282
490
|
CLOSE = {};
|
|
283
491
|
Query = class extends Promise {
|
|
284
492
|
constructor(strings, args, handler, canceller, options = {}) {
|
|
285
|
-
let
|
|
493
|
+
let resolve4, reject;
|
|
286
494
|
super((a, b2) => {
|
|
287
|
-
|
|
495
|
+
resolve4 = a;
|
|
288
496
|
reject = b2;
|
|
289
497
|
});
|
|
290
498
|
this.tagged = Array.isArray(strings.raw);
|
|
@@ -295,7 +503,7 @@ var init_query = __esm({
|
|
|
295
503
|
this.options = options;
|
|
296
504
|
this.state = null;
|
|
297
505
|
this.statement = null;
|
|
298
|
-
this.resolve = (x) => (this.active = false,
|
|
506
|
+
this.resolve = (x) => (this.active = false, resolve4(x));
|
|
299
507
|
this.reject = (x) => (this.active = false, reject(x));
|
|
300
508
|
this.active = false;
|
|
301
509
|
this.cancelled = null;
|
|
@@ -343,12 +551,12 @@ var init_query = __esm({
|
|
|
343
551
|
if (this.executed && !this.active)
|
|
344
552
|
return { done: true };
|
|
345
553
|
prev && prev();
|
|
346
|
-
const promise = new Promise((
|
|
554
|
+
const promise = new Promise((resolve4, reject) => {
|
|
347
555
|
this.cursorFn = (value) => {
|
|
348
|
-
|
|
556
|
+
resolve4({ value, done: false });
|
|
349
557
|
return new Promise((r) => prev = r);
|
|
350
558
|
};
|
|
351
|
-
this.resolve = () => (this.active = false,
|
|
559
|
+
this.resolve = () => (this.active = false, resolve4({ done: true }));
|
|
352
560
|
this.reject = (x) => (this.active = false, reject(x));
|
|
353
561
|
});
|
|
354
562
|
this.execute();
|
|
@@ -946,12 +1154,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
946
1154
|
x.on("drain", drain);
|
|
947
1155
|
return x;
|
|
948
1156
|
}
|
|
949
|
-
async function cancel({ pid, secret },
|
|
1157
|
+
async function cancel({ pid, secret }, resolve4, reject) {
|
|
950
1158
|
try {
|
|
951
1159
|
cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
|
|
952
1160
|
await connect();
|
|
953
1161
|
socket.once("error", reject);
|
|
954
|
-
socket.once("close",
|
|
1162
|
+
socket.once("close", resolve4);
|
|
955
1163
|
} catch (error2) {
|
|
956
1164
|
reject(error2);
|
|
957
1165
|
}
|
|
@@ -1968,7 +2176,7 @@ var init_subscribe = __esm({
|
|
|
1968
2176
|
// ../../node_modules/.pnpm/postgres@3.4.9/node_modules/postgres/src/large.js
|
|
1969
2177
|
import Stream2 from "stream";
|
|
1970
2178
|
function largeObject(sql2, oid, mode = 131072 | 262144) {
|
|
1971
|
-
return new Promise(async (
|
|
2179
|
+
return new Promise(async (resolve4, reject) => {
|
|
1972
2180
|
await sql2.begin(async (sql3) => {
|
|
1973
2181
|
let finish;
|
|
1974
2182
|
!oid && ([{ oid }] = await sql3`select lo_creat(-1) as oid`);
|
|
@@ -1994,7 +2202,7 @@ function largeObject(sql2, oid, mode = 131072 | 262144) {
|
|
|
1994
2202
|
) seek
|
|
1995
2203
|
`
|
|
1996
2204
|
};
|
|
1997
|
-
|
|
2205
|
+
resolve4(lo);
|
|
1998
2206
|
return new Promise(async (r) => finish = r);
|
|
1999
2207
|
async function readable({
|
|
2000
2208
|
highWaterMark = 2048 * 8,
|
|
@@ -2155,8 +2363,8 @@ function Postgres(a, b2) {
|
|
|
2155
2363
|
}
|
|
2156
2364
|
async function reserve() {
|
|
2157
2365
|
const queue = queue_default();
|
|
2158
|
-
const c = open2.length ? open2.shift() : await new Promise((
|
|
2159
|
-
const query = { reserve:
|
|
2366
|
+
const c = open2.length ? open2.shift() : await new Promise((resolve4, reject) => {
|
|
2367
|
+
const query = { reserve: resolve4, reject };
|
|
2160
2368
|
queries.push(query);
|
|
2161
2369
|
closed.length && connect(closed.shift(), query);
|
|
2162
2370
|
});
|
|
@@ -2193,9 +2401,9 @@ function Postgres(a, b2) {
|
|
|
2193
2401
|
let uncaughtError, result;
|
|
2194
2402
|
name && await sql3`savepoint ${sql3(name)}`;
|
|
2195
2403
|
try {
|
|
2196
|
-
result = await new Promise((
|
|
2404
|
+
result = await new Promise((resolve4, reject) => {
|
|
2197
2405
|
const x = fn2(sql3);
|
|
2198
|
-
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(
|
|
2406
|
+
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve4, reject);
|
|
2199
2407
|
});
|
|
2200
2408
|
if (uncaughtError)
|
|
2201
2409
|
throw uncaughtError;
|
|
@@ -2252,8 +2460,8 @@ function Postgres(a, b2) {
|
|
|
2252
2460
|
return c.execute(query) ? move(c, busy) : move(c, full);
|
|
2253
2461
|
}
|
|
2254
2462
|
function cancel(query) {
|
|
2255
|
-
return new Promise((
|
|
2256
|
-
query.state ? query.active ? connection_default(options).cancel(query.state,
|
|
2463
|
+
return new Promise((resolve4, reject) => {
|
|
2464
|
+
query.state ? query.active ? connection_default(options).cancel(query.state, resolve4, reject) : query.cancelled = { resolve: resolve4, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve4());
|
|
2257
2465
|
});
|
|
2258
2466
|
}
|
|
2259
2467
|
async function end({ timeout = null } = {}) {
|
|
@@ -2272,11 +2480,11 @@ function Postgres(a, b2) {
|
|
|
2272
2480
|
async function close() {
|
|
2273
2481
|
await Promise.all(connections.map((c) => c.end()));
|
|
2274
2482
|
}
|
|
2275
|
-
async function destroy(
|
|
2483
|
+
async function destroy(resolve4) {
|
|
2276
2484
|
await Promise.all(connections.map((c) => c.terminate()));
|
|
2277
2485
|
while (queries.length)
|
|
2278
2486
|
queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
|
|
2279
|
-
|
|
2487
|
+
resolve4();
|
|
2280
2488
|
}
|
|
2281
2489
|
function connect(c, query) {
|
|
2282
2490
|
move(c, connecting);
|
|
@@ -3714,7 +3922,7 @@ var init_sql = __esm({
|
|
|
3714
3922
|
return new SQL([new StringChunk(str)]);
|
|
3715
3923
|
}
|
|
3716
3924
|
sql2.raw = raw;
|
|
3717
|
-
function
|
|
3925
|
+
function join14(chunks, separator) {
|
|
3718
3926
|
const result = [];
|
|
3719
3927
|
for (const [i, chunk] of chunks.entries()) {
|
|
3720
3928
|
if (i > 0 && separator !== void 0) {
|
|
@@ -3724,7 +3932,7 @@ var init_sql = __esm({
|
|
|
3724
3932
|
}
|
|
3725
3933
|
return new SQL(result);
|
|
3726
3934
|
}
|
|
3727
|
-
sql2.join =
|
|
3935
|
+
sql2.join = join14;
|
|
3728
3936
|
function identifier(value) {
|
|
3729
3937
|
return new Name(value);
|
|
3730
3938
|
}
|
|
@@ -8047,7 +8255,7 @@ var init_select2 = __esm({
|
|
|
8047
8255
|
const baseTableName = this.tableName;
|
|
8048
8256
|
const tableName = getTableLikeName(table);
|
|
8049
8257
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
8050
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
8258
|
+
if (typeof tableName === "string" && this.config.joins?.some((join14) => join14.alias === tableName)) {
|
|
8051
8259
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
8052
8260
|
}
|
|
8053
8261
|
if (!this.isPartialSelect) {
|
|
@@ -9582,7 +9790,7 @@ var init_update = __esm({
|
|
|
9582
9790
|
createJoin(joinType) {
|
|
9583
9791
|
return (table, on) => {
|
|
9584
9792
|
const tableName = getTableLikeName(table);
|
|
9585
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
9793
|
+
if (typeof tableName === "string" && this.config.joins.some((join14) => join14.alias === tableName)) {
|
|
9586
9794
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
9587
9795
|
}
|
|
9588
9796
|
if (typeof on === "function") {
|
|
@@ -9678,10 +9886,10 @@ var init_update = __esm({
|
|
|
9678
9886
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
9679
9887
|
fields[tableName] = fromFields;
|
|
9680
9888
|
}
|
|
9681
|
-
for (const
|
|
9682
|
-
const tableName2 = getTableLikeName(
|
|
9683
|
-
if (typeof tableName2 === "string" && !is(
|
|
9684
|
-
const fromFields = this.getTableLikeFields(
|
|
9889
|
+
for (const join14 of this.config.joins) {
|
|
9890
|
+
const tableName2 = getTableLikeName(join14.table);
|
|
9891
|
+
if (typeof tableName2 === "string" && !is(join14.table, SQL)) {
|
|
9892
|
+
const fromFields = this.getTableLikeFields(join14.table);
|
|
9685
9893
|
fields[tableName2] = fromFields;
|
|
9686
9894
|
}
|
|
9687
9895
|
}
|
|
@@ -10924,14 +11132,14 @@ __export(migrate_exports, {
|
|
|
10924
11132
|
runMigrations: () => runMigrations
|
|
10925
11133
|
});
|
|
10926
11134
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10927
|
-
import { join as
|
|
11135
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
10928
11136
|
import {
|
|
10929
|
-
existsSync as
|
|
11137
|
+
existsSync as existsSync4,
|
|
10930
11138
|
mkdtempSync,
|
|
10931
11139
|
readdirSync,
|
|
10932
|
-
readFileSync as
|
|
10933
|
-
writeFileSync as
|
|
10934
|
-
mkdirSync as
|
|
11140
|
+
readFileSync as readFileSync3,
|
|
11141
|
+
writeFileSync as writeFileSync3,
|
|
11142
|
+
mkdirSync as mkdirSync3
|
|
10935
11143
|
} from "fs";
|
|
10936
11144
|
import { tmpdir } from "os";
|
|
10937
11145
|
async function runMigrations(connectionString, opts = {}) {
|
|
@@ -10944,26 +11152,26 @@ async function runMigrations(connectionString, opts = {}) {
|
|
|
10944
11152
|
});
|
|
10945
11153
|
const db = drizzle(sql2);
|
|
10946
11154
|
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
10947
|
-
const sibling =
|
|
10948
|
-
const sourceFolder =
|
|
11155
|
+
const sibling = join4(here, "migrations");
|
|
11156
|
+
const sourceFolder = existsSync4(sibling) ? sibling : join4(here, "../migrations");
|
|
10949
11157
|
const migrationsFolder = opts.patchVectorAsText ? patchMigrationsForNoVector(sourceFolder) : sourceFolder;
|
|
10950
11158
|
await migrate(db, { migrationsFolder });
|
|
10951
11159
|
await sql2.end();
|
|
10952
11160
|
}
|
|
10953
11161
|
function patchMigrationsForNoVector(sourceFolder) {
|
|
10954
|
-
const tmpFolder = mkdtempSync(
|
|
10955
|
-
const metaDir =
|
|
10956
|
-
|
|
11162
|
+
const tmpFolder = mkdtempSync(join4(tmpdir(), "nodalai-migrations-"));
|
|
11163
|
+
const metaDir = join4(tmpFolder, "meta");
|
|
11164
|
+
mkdirSync3(metaDir, { recursive: true });
|
|
10957
11165
|
for (const entry of readdirSync(sourceFolder, { withFileTypes: true })) {
|
|
10958
11166
|
if (entry.isDirectory() && entry.name === "meta") {
|
|
10959
|
-
for (const metaFile of readdirSync(
|
|
10960
|
-
const content =
|
|
10961
|
-
|
|
11167
|
+
for (const metaFile of readdirSync(join4(sourceFolder, "meta"))) {
|
|
11168
|
+
const content = readFileSync3(join4(sourceFolder, "meta", metaFile), "utf8");
|
|
11169
|
+
writeFileSync3(join4(metaDir, metaFile), content);
|
|
10962
11170
|
}
|
|
10963
11171
|
} else if (entry.isFile() && entry.name.endsWith(".sql")) {
|
|
10964
|
-
const content =
|
|
11172
|
+
const content = readFileSync3(join4(sourceFolder, entry.name), "utf8");
|
|
10965
11173
|
const patched = content.replace(/\bvector\(\d+\)/g, "text");
|
|
10966
|
-
|
|
11174
|
+
writeFileSync3(join4(tmpFolder, entry.name), patched);
|
|
10967
11175
|
}
|
|
10968
11176
|
}
|
|
10969
11177
|
return tmpFolder;
|
|
@@ -10978,69 +11186,185 @@ var init_migrate = __esm({
|
|
|
10978
11186
|
});
|
|
10979
11187
|
|
|
10980
11188
|
// src/lib/postgres.ts
|
|
10981
|
-
|
|
10982
|
-
|
|
11189
|
+
var postgres_exports = {};
|
|
11190
|
+
__export(postgres_exports, {
|
|
11191
|
+
LEGACY_PG_PASSWORD: () => LEGACY_PG_PASSWORD,
|
|
11192
|
+
PG_DATABASE: () => PG_DATABASE,
|
|
11193
|
+
PG_USER: () => PG_USER,
|
|
11194
|
+
buildPgUrl: () => buildPgUrl,
|
|
11195
|
+
isPostgresAuthFailure: () => isPostgresAuthFailure,
|
|
11196
|
+
livePostmasterPid: () => livePostmasterPid,
|
|
11197
|
+
postgresProcessesForDataDir: () => postgresProcessesForDataDir,
|
|
11198
|
+
processStartedAtMs: () => processStartedAtMs,
|
|
11199
|
+
readPostmasterClaim: () => readPostmasterClaim,
|
|
11200
|
+
readPostmasterPid: () => readPostmasterPid,
|
|
11201
|
+
resolvePgCtl: () => resolvePgCtl,
|
|
11202
|
+
runMigrations: () => runMigrations2,
|
|
11203
|
+
startAndWaitUntilReady: () => startAndWaitUntilReady,
|
|
11204
|
+
startEmbeddedPostgres: () => startEmbeddedPostgres,
|
|
11205
|
+
stopOrphanPostgres: () => stopOrphanPostgres,
|
|
11206
|
+
unconfirmedReading: () => unconfirmedReading
|
|
11207
|
+
});
|
|
11208
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync4, realpathSync, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
11209
|
+
import { join as join5 } from "path";
|
|
10983
11210
|
function readPostmasterPid(dataDir = PG_DATA_DIR) {
|
|
10984
|
-
|
|
10985
|
-
|
|
11211
|
+
return readPostmasterClaim(dataDir)?.pid ?? null;
|
|
11212
|
+
}
|
|
11213
|
+
function readPostmasterClaim(dataDir = PG_DATA_DIR) {
|
|
11214
|
+
const pidFile = join5(dataDir, "postmaster.pid");
|
|
11215
|
+
if (!existsSync5(pidFile)) return null;
|
|
10986
11216
|
try {
|
|
10987
|
-
const
|
|
10988
|
-
const pid = Number.parseInt(
|
|
10989
|
-
|
|
11217
|
+
const lines = readFileSync4(pidFile, "utf-8").split("\n");
|
|
11218
|
+
const pid = Number.parseInt(lines[0]?.trim() ?? "", 10);
|
|
11219
|
+
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
11220
|
+
const recorded = lines[1]?.trim();
|
|
11221
|
+
if (recorded !== void 0 && recorded !== "" && !sameDirectory(recorded, dataDir)) {
|
|
11222
|
+
process.stderr.write(
|
|
11223
|
+
`POSTMASTER_PID_FOREIGN_DATA_DIR pid=${pid} recorded=${recorded} expected=${dataDir}
|
|
11224
|
+
`
|
|
11225
|
+
);
|
|
11226
|
+
return null;
|
|
11227
|
+
}
|
|
11228
|
+
const seconds = Number.parseInt(lines[2]?.trim() ?? "", 10);
|
|
11229
|
+
return { pid, startedAtSeconds: Number.isInteger(seconds) && seconds > 0 ? seconds : null };
|
|
10990
11230
|
} catch {
|
|
10991
11231
|
return null;
|
|
10992
11232
|
}
|
|
10993
11233
|
}
|
|
11234
|
+
function sameDirectory(a, b2) {
|
|
11235
|
+
const clean = (v) => process.platform === "win32" ? v.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase() : (
|
|
11236
|
+
// A backslash is a legal character in a POSIX filename, so turning it
|
|
11237
|
+
// into a separator made `/srv/pg\data` and `/srv/pg/data` — two real,
|
|
11238
|
+
// different directories — compare equal (pass-9 finding R2). Only the
|
|
11239
|
+
// trailing separator is dropped.
|
|
11240
|
+
v.replace(/\/+$/, "")
|
|
11241
|
+
);
|
|
11242
|
+
return clean(a) === clean(b2);
|
|
11243
|
+
}
|
|
10994
11244
|
function livePostmasterPid(dataDir = PG_DATA_DIR) {
|
|
10995
11245
|
const pid = readPostmasterPid(dataDir);
|
|
10996
|
-
|
|
11246
|
+
return pid !== null && isPidRunning(pid) ? pid : null;
|
|
11247
|
+
}
|
|
11248
|
+
function isPidRunning(pid) {
|
|
10997
11249
|
try {
|
|
10998
11250
|
process.kill(pid, 0);
|
|
10999
|
-
return
|
|
11251
|
+
return true;
|
|
11000
11252
|
} catch (err) {
|
|
11001
|
-
return err.code
|
|
11253
|
+
return err.code !== "ESRCH";
|
|
11002
11254
|
}
|
|
11003
11255
|
}
|
|
11004
|
-
async function
|
|
11005
|
-
if (process.platform !== "win32") return
|
|
11256
|
+
async function postgresProcessesForDataDir(dataDir = PG_DATA_DIR) {
|
|
11257
|
+
if (process.platform !== "win32") return unconfirmedReading(dataDir);
|
|
11006
11258
|
const { execa: execa4 } = await import("execa");
|
|
11007
11259
|
try {
|
|
11008
|
-
const { stdout } = await execa4(
|
|
11260
|
+
const { stdout, stderr, exitCode } = await execa4(
|
|
11009
11261
|
"powershell",
|
|
11010
11262
|
[
|
|
11011
11263
|
"-NoProfile",
|
|
11012
11264
|
"-NonInteractive",
|
|
11013
11265
|
"-Command",
|
|
11014
|
-
//
|
|
11015
|
-
//
|
|
11016
|
-
//
|
|
11017
|
-
|
|
11266
|
+
// `CreationDate` is the load-bearing field: it tells one generation of
|
|
11267
|
+
// a pid from the next, which is the only thing that catches a pid the
|
|
11268
|
+
// OS recycled onto a stranger. It goes BEFORE the command line, the one
|
|
11269
|
+
// field that may itself carry a `|`. The command line is kept for the
|
|
11270
|
+
// log line that says what was left alone — never to decide ownership.
|
|
11271
|
+
`Get-CimInstance Win32_Process -Filter "Name='postgres.exe'" | ForEach-Object { $ms = if ($_.CreationDate) { [int64]($_.CreationDate.ToUniversalTime() - (Get-Date '1970-01-01T00:00:00Z').ToUniversalTime()).TotalMilliseconds } else { 0 }; "$($_.ProcessId)|$($_.ParentProcessId)|$ms|$($_.CommandLine)" }`
|
|
11018
11272
|
],
|
|
11019
11273
|
{ reject: false, timeout: 1e4 }
|
|
11020
11274
|
);
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11275
|
+
if (exitCode !== 0) {
|
|
11276
|
+
process.stderr.write(
|
|
11277
|
+
`ORPHAN_PROBE_UNREADABLE exit=${String(exitCode)} stderr=${stderr.trim().slice(0, 200)}
|
|
11278
|
+
`
|
|
11279
|
+
);
|
|
11280
|
+
return unconfirmedReading(dataDir);
|
|
11281
|
+
}
|
|
11282
|
+
const { owned, skipped } = ownedPostgresPids({
|
|
11283
|
+
rows: parseProcessRows(stdout),
|
|
11284
|
+
tableRead: true,
|
|
11285
|
+
// The data directory answers; this table only confirms.
|
|
11286
|
+
claim: readPostmasterClaim(dataDir)
|
|
11287
|
+
});
|
|
11288
|
+
for (const entry of skipped) process.stderr.write(`${formatForeignSkip(entry)}
|
|
11289
|
+
`);
|
|
11290
|
+
return { read: true, owned };
|
|
11291
|
+
} catch (err) {
|
|
11292
|
+
process.stderr.write(
|
|
11293
|
+
`ORPHAN_PROBE_UNREADABLE error=${err instanceof Error ? err.message : String(err)}
|
|
11294
|
+
`
|
|
11295
|
+
);
|
|
11296
|
+
return unconfirmedReading(dataDir);
|
|
11297
|
+
}
|
|
11298
|
+
}
|
|
11299
|
+
function unconfirmedReading(dataDir) {
|
|
11300
|
+
const claim = readPostmasterClaim(dataDir);
|
|
11301
|
+
if (claim === null) {
|
|
11302
|
+
process.stderr.write(`ORPHAN_PROBE_NO_CLAIM dataDir=${dataDir}
|
|
11303
|
+
`);
|
|
11304
|
+
return { read: false, owned: [] };
|
|
11305
|
+
}
|
|
11306
|
+
if (!isPidRunning(claim.pid)) {
|
|
11307
|
+
process.stderr.write(`ORPHAN_PROBE_CLAIMED_PID_NOT_ALIVE pid=${claim.pid}
|
|
11308
|
+
`);
|
|
11309
|
+
return { read: false, owned: [] };
|
|
11310
|
+
}
|
|
11311
|
+
const holdsDataDir = postmasterHoldsDataDir(claim.pid, dataDir);
|
|
11312
|
+
if (holdsDataDir !== true) {
|
|
11313
|
+
process.stderr.write(
|
|
11314
|
+
`ORPHAN_PROBE_NOT_IN_DATA_DIR pid=${claim.pid} holds=${String(holdsDataDir)}
|
|
11315
|
+
`
|
|
11316
|
+
);
|
|
11317
|
+
return { read: false, owned: [] };
|
|
11318
|
+
}
|
|
11319
|
+
const startedAt = processStartedAtMs(claim.pid);
|
|
11320
|
+
if (startedAt === null) {
|
|
11321
|
+
process.stderr.write(
|
|
11322
|
+
`ORPHAN_PROBE_NO_START_TIME pid=${claim.pid} platform=${process.platform}
|
|
11323
|
+
`
|
|
11324
|
+
);
|
|
11325
|
+
return { read: false, owned: [] };
|
|
11326
|
+
}
|
|
11327
|
+
const { owned, skipped } = ownedPostgresPids({
|
|
11328
|
+
rows: [{ pid: claim.pid, ppid: 0, commandLine: "", startedAt }],
|
|
11329
|
+
tableRead: true,
|
|
11330
|
+
claim
|
|
11331
|
+
});
|
|
11332
|
+
for (const entry of skipped) process.stderr.write(`${formatForeignSkip(entry)}
|
|
11333
|
+
`);
|
|
11334
|
+
return { read: false, owned };
|
|
11335
|
+
}
|
|
11336
|
+
function postmasterHoldsDataDir(pid, dataDir) {
|
|
11337
|
+
if (process.platform !== "linux") return null;
|
|
11338
|
+
try {
|
|
11339
|
+
return sameDirectory(realpathSync(`/proc/${pid}/cwd`), realpathSync(dataDir));
|
|
11033
11340
|
} catch {
|
|
11034
|
-
return
|
|
11341
|
+
return null;
|
|
11342
|
+
}
|
|
11343
|
+
}
|
|
11344
|
+
function processStartedAtMs(pid) {
|
|
11345
|
+
if (process.platform !== "linux") return null;
|
|
11346
|
+
try {
|
|
11347
|
+
const stat = readFileSync4(`/proc/${pid}/stat`, "utf-8");
|
|
11348
|
+
const after = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
11349
|
+
const ticksSinceBoot = Number.parseInt(after[19] ?? "", 10);
|
|
11350
|
+
if (!Number.isFinite(ticksSinceBoot)) return null;
|
|
11351
|
+
const uptimeSeconds = Number.parseFloat(
|
|
11352
|
+
readFileSync4("/proc/uptime", "utf-8").split(" ")[0] ?? ""
|
|
11353
|
+
);
|
|
11354
|
+
if (!Number.isFinite(uptimeSeconds)) return null;
|
|
11355
|
+
const elapsedSeconds = uptimeSeconds - ticksSinceBoot / 100;
|
|
11356
|
+
return Date.now() - elapsedSeconds * 1e3;
|
|
11357
|
+
} catch {
|
|
11358
|
+
return null;
|
|
11035
11359
|
}
|
|
11036
11360
|
}
|
|
11037
11361
|
function clearStalePostmasterPid(dataDir) {
|
|
11038
|
-
const pidFile =
|
|
11039
|
-
if (!
|
|
11362
|
+
const pidFile = join5(dataDir, "postmaster.pid");
|
|
11363
|
+
if (!existsSync5(pidFile)) return;
|
|
11040
11364
|
if (readPostmasterPid(dataDir) === null) return;
|
|
11041
11365
|
if (livePostmasterPid(dataDir) !== null) return;
|
|
11042
11366
|
try {
|
|
11043
|
-
|
|
11367
|
+
unlinkSync2(pidFile);
|
|
11044
11368
|
} catch {
|
|
11045
11369
|
}
|
|
11046
11370
|
}
|
|
@@ -11050,32 +11374,128 @@ function buildPgUrl(port, password) {
|
|
|
11050
11374
|
function quotePgLiteral(value) {
|
|
11051
11375
|
return `'${value.replace(/'/g, "''")}'`;
|
|
11052
11376
|
}
|
|
11053
|
-
async function stopOrphanPostgres(dataDir = PG_DATA_DIR) {
|
|
11054
|
-
const
|
|
11055
|
-
if (
|
|
11377
|
+
async function stopOrphanPostgres(decidedPid, dataDir = PG_DATA_DIR) {
|
|
11378
|
+
const claim = readPostmasterClaim(dataDir);
|
|
11379
|
+
if (claim === null || claim.pid !== decidedPid) {
|
|
11380
|
+
process.stderr.write(
|
|
11381
|
+
`PG_CTL_SKIPPED_LOCKFILE_MISMATCH decided=${decidedPid} lockfile=${String(claim?.pid ?? null)}
|
|
11382
|
+
`
|
|
11383
|
+
);
|
|
11384
|
+
return false;
|
|
11385
|
+
}
|
|
11386
|
+
const asRoot = process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0;
|
|
11387
|
+
if (asRoot) {
|
|
11388
|
+
process.stderr.write("PG_CTL_SKIPPED_ROOT \u2014 pg_ctl refuses to run as root\n");
|
|
11389
|
+
return false;
|
|
11390
|
+
}
|
|
11056
11391
|
try {
|
|
11057
|
-
const
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11072
|
-
|
|
11392
|
+
const binary = await resolvePgCtl();
|
|
11393
|
+
if (binary === null) {
|
|
11394
|
+
process.stderr.write(`PG_CTL_NOT_FOUND dataDir=${dataDir}
|
|
11395
|
+
`);
|
|
11396
|
+
return false;
|
|
11397
|
+
}
|
|
11398
|
+
const { execa: execa4 } = await import("execa");
|
|
11399
|
+
const { exitCode, stderr } = await execa4(
|
|
11400
|
+
binary,
|
|
11401
|
+
["stop", "-D", dataDir, "-m", "fast", "-w", "-t", "30"],
|
|
11402
|
+
{ reject: false, timeout: 4e4 }
|
|
11403
|
+
);
|
|
11404
|
+
if (exitCode !== 0) {
|
|
11405
|
+
process.stderr.write(
|
|
11406
|
+
`PG_CTL_STOP_FAILED exit=${String(exitCode)} stderr=${stderr.trim().slice(0, 200)}
|
|
11407
|
+
`
|
|
11408
|
+
);
|
|
11409
|
+
return false;
|
|
11410
|
+
}
|
|
11073
11411
|
return true;
|
|
11074
|
-
} catch {
|
|
11412
|
+
} catch (err) {
|
|
11413
|
+
process.stderr.write(
|
|
11414
|
+
`PG_CTL_STOP_FAILED error=${err instanceof Error ? err.message : String(err)}
|
|
11415
|
+
`
|
|
11416
|
+
);
|
|
11075
11417
|
return false;
|
|
11076
11418
|
}
|
|
11077
11419
|
}
|
|
11078
|
-
async function
|
|
11420
|
+
async function resolvePgCtl() {
|
|
11421
|
+
try {
|
|
11422
|
+
const { createRequire: createRequire2 } = await import("module");
|
|
11423
|
+
const { pathToFileURL } = await import("url");
|
|
11424
|
+
const { dirname: dirname5 } = await import("path");
|
|
11425
|
+
const require2 = createRequire2(import.meta.url);
|
|
11426
|
+
const entry = require2.resolve("embedded-postgres");
|
|
11427
|
+
const module = await import(pathToFileURL(join5(dirname5(entry), "binary.js")).href);
|
|
11428
|
+
const binaries = await module.default?.();
|
|
11429
|
+
const pgCtl = binaries?.pg_ctl;
|
|
11430
|
+
return pgCtl !== void 0 && existsSync5(pgCtl) ? pgCtl : null;
|
|
11431
|
+
} catch {
|
|
11432
|
+
return null;
|
|
11433
|
+
}
|
|
11434
|
+
}
|
|
11435
|
+
function isPostgresAuthFailure(err) {
|
|
11436
|
+
const code = err?.code;
|
|
11437
|
+
return typeof code === "string" && code.length === 5 && code.startsWith("28");
|
|
11438
|
+
}
|
|
11439
|
+
async function stopQuietly(pg) {
|
|
11440
|
+
try {
|
|
11441
|
+
await pg.stop?.();
|
|
11442
|
+
} catch {
|
|
11443
|
+
}
|
|
11444
|
+
}
|
|
11445
|
+
async function startAndWaitUntilReady(pg) {
|
|
11446
|
+
let exitedEarly = null;
|
|
11447
|
+
let resolvedItself = false;
|
|
11448
|
+
const started = pg.start().then(
|
|
11449
|
+
() => {
|
|
11450
|
+
resolvedItself = true;
|
|
11451
|
+
},
|
|
11452
|
+
(err) => {
|
|
11453
|
+
exitedEarly = err ?? new Error("the postmaster exited during startup");
|
|
11454
|
+
}
|
|
11455
|
+
);
|
|
11456
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
11457
|
+
for (; ; ) {
|
|
11458
|
+
if (exitedEarly !== null) throw exitedEarly;
|
|
11459
|
+
const probe = pg.getPgClient("postgres");
|
|
11460
|
+
try {
|
|
11461
|
+
await probe.connect();
|
|
11462
|
+
await probe.end();
|
|
11463
|
+
return;
|
|
11464
|
+
} catch (err) {
|
|
11465
|
+
await probe.end().catch(() => {
|
|
11466
|
+
});
|
|
11467
|
+
if (isPostgresAuthFailure(err)) {
|
|
11468
|
+
await stopQuietly(pg);
|
|
11469
|
+
const code = err.code;
|
|
11470
|
+
throw new Error(
|
|
11471
|
+
`Postgres refused the connection: authentication failed (SQLSTATE ${code}). The cluster started and was stopped again. The password the CLI holds does not match the one this data directory was initialised with.`
|
|
11472
|
+
);
|
|
11473
|
+
}
|
|
11474
|
+
}
|
|
11475
|
+
if (resolvedItself) {
|
|
11476
|
+
await started;
|
|
11477
|
+
return;
|
|
11478
|
+
}
|
|
11479
|
+
if (Date.now() > deadline) {
|
|
11480
|
+
await stopQuietly(pg);
|
|
11481
|
+
throw new Error(
|
|
11482
|
+
`Postgres did not accept a connection within ${READY_TIMEOUT_MS / 1e3}s of starting`
|
|
11483
|
+
);
|
|
11484
|
+
}
|
|
11485
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
11486
|
+
}
|
|
11487
|
+
}
|
|
11488
|
+
function tailLogDirectory(logDirectory, lines = 40) {
|
|
11489
|
+
try {
|
|
11490
|
+
const files = readdirSync2(logDirectory).map((name) => join5(logDirectory, name)).map((path) => ({ path, mtime: statSync(path).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
|
|
11491
|
+
const newest = files[0];
|
|
11492
|
+
if (!newest) return [];
|
|
11493
|
+
return readFileSync4(newest.path, "utf-8").split(/\r?\n/).filter((l) => l.trim() !== "").slice(-lines);
|
|
11494
|
+
} catch {
|
|
11495
|
+
return [];
|
|
11496
|
+
}
|
|
11497
|
+
}
|
|
11498
|
+
async function startEmbeddedPostgres(dataDir = PG_DATA_DIR, port = 25432, password = LEGACY_PG_PASSWORD, logDirectory = postgresLogDirFor(dataDir)) {
|
|
11079
11499
|
const EmbeddedPostgres = (await import("embedded-postgres")).default;
|
|
11080
11500
|
const capturedLogs = [];
|
|
11081
11501
|
const capturedErrors = [];
|
|
@@ -11104,23 +11524,26 @@ async function startEmbeddedPostgres(dataDir = PG_DATA_DIR, port = 25432, passwo
|
|
|
11104
11524
|
if (verboseLog) process.stdout.write("[pg] " + m + "\n");
|
|
11105
11525
|
}
|
|
11106
11526
|
});
|
|
11107
|
-
const alreadyInitialised =
|
|
11527
|
+
const alreadyInitialised = existsSync5(join5(dataDir, "PG_VERSION"));
|
|
11108
11528
|
if (alreadyInitialised) clearStalePostmasterPid(dataDir);
|
|
11109
11529
|
try {
|
|
11110
11530
|
if (!alreadyInitialised) {
|
|
11111
11531
|
await pg.initialise();
|
|
11112
11532
|
}
|
|
11113
|
-
|
|
11533
|
+
applyPostgresLoggingConfig(dataDir, logDirectory);
|
|
11534
|
+
await startAndWaitUntilReady(pg);
|
|
11114
11535
|
} catch (err) {
|
|
11115
11536
|
const errMsg = err instanceof Error && err.message ? err.message : String(err);
|
|
11116
|
-
const fatalLines = capturedLogs
|
|
11537
|
+
const fatalLines = [...capturedLogs, ...tailLogDirectory(logDirectory)].filter(
|
|
11538
|
+
(l) => /\b(FATAL|PANIC|ERROR)\b/.test(l)
|
|
11539
|
+
);
|
|
11117
11540
|
const detail = [
|
|
11118
11541
|
capturedErrors.length ? `Captured Postgres errors:
|
|
11119
11542
|
${capturedErrors.join("\n ")}` : null,
|
|
11120
11543
|
fatalLines.length ? `Postgres log:
|
|
11121
11544
|
${fatalLines.join("\n ")}` : null
|
|
11122
11545
|
].filter(Boolean).join("\n ");
|
|
11123
|
-
const sharedMemHint =
|
|
11546
|
+
const sharedMemHint = fatalLines.some((l) => /pre-existing shared memory block/.test(l)) ? "\n \u2192 A previous Postgres crashed without releasing its Windows shared-memory block. Reboot the machine to clear the orphan kernel object, then retry. No data is lost; pg-data is preserved." : "";
|
|
11124
11547
|
throw new Error(
|
|
11125
11548
|
`Postgres ${alreadyInitialised ? "start" : "init+start"} failed: ${errMsg}` + (detail ? `
|
|
11126
11549
|
${detail}` : "") + sharedMemHint
|
|
@@ -11185,14 +11608,17 @@ async function runMigrations2(databaseUrl, opts = {}) {
|
|
|
11185
11608
|
const { runMigrations: migrate2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
|
|
11186
11609
|
await migrate2(databaseUrl, opts);
|
|
11187
11610
|
}
|
|
11188
|
-
var LEGACY_PG_PASSWORD, PG_USER, PG_DATABASE;
|
|
11611
|
+
var LEGACY_PG_PASSWORD, PG_USER, PG_DATABASE, READY_TIMEOUT_MS;
|
|
11189
11612
|
var init_postgres = __esm({
|
|
11190
11613
|
"src/lib/postgres.ts"() {
|
|
11191
11614
|
"use strict";
|
|
11192
11615
|
init_config();
|
|
11616
|
+
init_pg_logging();
|
|
11617
|
+
init_orphans();
|
|
11193
11618
|
LEGACY_PG_PASSWORD = "nodalai";
|
|
11194
11619
|
PG_USER = "nodalai";
|
|
11195
11620
|
PG_DATABASE = "nodalai";
|
|
11621
|
+
READY_TIMEOUT_MS = 18e4;
|
|
11196
11622
|
}
|
|
11197
11623
|
});
|
|
11198
11624
|
|
|
@@ -14335,6 +14761,22 @@ var init_agents = __esm({
|
|
|
14335
14761
|
// (Memory Sprint 2). Pure char budget — token estimation done at call site
|
|
14336
14762
|
// (length/4). 1500 chars ≈ ~375 tokens, similar to Hermes' 2200+1375 split.
|
|
14337
14763
|
memoryTokenBudget: integer("memory_token_budget").default(1500).notNull(),
|
|
14764
|
+
/**
|
|
14765
|
+
* La réflexion (boucle d'apprentissage de skills) pour CET agent.
|
|
14766
|
+
*
|
|
14767
|
+
* `null` = suivre le réglage du propriétaire (`entities.reflection_enabled`),
|
|
14768
|
+
* qui est le comportement historique et reste le défaut. `false` = jamais,
|
|
14769
|
+
* même quand le propriétaire l'a activée. `true` n'est pas un
|
|
14770
|
+
* contournement : la porte de l'entité s'applique toujours au-dessus.
|
|
14771
|
+
*
|
|
14772
|
+
* Existe parce que la réflexion était TOUT ou RIEN par propriétaire. Sur le
|
|
14773
|
+
* run 20b73ed1 (09/09), un relecteur qui avait rendu « approve » sans le
|
|
14774
|
+
* moindre constat a déclenché trois appels de réflexion à 0,041 $ — 12 % de
|
|
14775
|
+
* la facture du run, pour apprendre d'un travail qui n'avait rien à
|
|
14776
|
+
* apprendre. Un agent dont le métier est de juger n'accumule pas de savoir-
|
|
14777
|
+
* faire réutilisable ; c'est celui qui PRODUIT qui en accumule.
|
|
14778
|
+
*/
|
|
14779
|
+
reflectionEnabled: boolean("reflection_enabled"),
|
|
14338
14780
|
// Daily budget for coding-CLI runs (code_task, étape B of the
|
|
14339
14781
|
// subscription-runtimes plan), in NOTIONAL USD — the cost the claude CLI
|
|
14340
14782
|
// reports even under subscription (codex reports none; its runs count 0
|
|
@@ -14588,6 +15030,19 @@ var init_jobs = __esm({
|
|
|
14588
15030
|
requestId: text("request_id"),
|
|
14589
15031
|
parentJobId: uuid("parent_job_id"),
|
|
14590
15032
|
parentRequestId: text("parent_request_id"),
|
|
15033
|
+
/**
|
|
15034
|
+
* Temps où le job a réellement TOURNÉ, cumulé sur tous ses segments —
|
|
15035
|
+
* suspensions exclues. Un job qui délègue ou attend une approbation sort de
|
|
15036
|
+
* `executeJob` et y rentre plus tard : chaque rentrée ajoute son segment,
|
|
15037
|
+
* elle ne remplace pas le total (apps/runner/src/job/execute.ts,
|
|
15038
|
+
* `dureeCumuleeMs`).
|
|
15039
|
+
*
|
|
15040
|
+
* Ce n'est PAS le temps écoulé de bout en bout. Celui-là se lit
|
|
15041
|
+
* `completed_at − created_at` et ne mérite pas une colonne. La distinction
|
|
15042
|
+
* compte : sur le run 20b73ed1 (09/09/2026), l'orchestrateur a tourné une
|
|
15043
|
+
* trentaine de secondes pour 34 minutes écoulées — le reste était de
|
|
15044
|
+
* l'attente, et les deux chiffres disent des choses différentes.
|
|
15045
|
+
*/
|
|
14591
15046
|
totalDurationMs: integer("total_duration_ms").default(0),
|
|
14592
15047
|
inputTokens: integer("input_tokens").default(0),
|
|
14593
15048
|
outputTokens: integer("output_tokens").default(0),
|
|
@@ -16530,10 +16985,10 @@ var init_transaction = __esm({
|
|
|
16530
16985
|
|
|
16531
16986
|
// ../../packages/secrets/src/index.ts
|
|
16532
16987
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
|
|
16533
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
16988
|
+
import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
16534
16989
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
16535
16990
|
import { homedir as homedir2 } from "os";
|
|
16536
|
-
import { dirname as dirname3, join as
|
|
16991
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
16537
16992
|
function restrictFileToOwner2(path) {
|
|
16538
16993
|
try {
|
|
16539
16994
|
chmodSync2(path, 384);
|
|
@@ -16548,15 +17003,15 @@ function restrictFileToOwner2(path) {
|
|
|
16548
17003
|
}
|
|
16549
17004
|
}
|
|
16550
17005
|
function masterKeyPath() {
|
|
16551
|
-
return
|
|
17006
|
+
return join6(homedir2(), ".nodalai", "secrets.key");
|
|
16552
17007
|
}
|
|
16553
17008
|
function masterKeyFileMissing(path = masterKeyPath()) {
|
|
16554
|
-
return !
|
|
17009
|
+
return !existsSync6(path);
|
|
16555
17010
|
}
|
|
16556
17011
|
function loadOrCreateMasterKey(path = masterKeyPath()) {
|
|
16557
17012
|
if (cachedMasterKey) return cachedMasterKey;
|
|
16558
|
-
if (
|
|
16559
|
-
const raw =
|
|
17013
|
+
if (existsSync6(path)) {
|
|
17014
|
+
const raw = readFileSync5(path, "utf-8").trim();
|
|
16560
17015
|
const buf2 = Buffer.from(raw, "base64");
|
|
16561
17016
|
if (buf2.length !== KEY_BYTES) {
|
|
16562
17017
|
throw new Error(
|
|
@@ -16567,9 +17022,9 @@ function loadOrCreateMasterKey(path = masterKeyPath()) {
|
|
|
16567
17022
|
return buf2;
|
|
16568
17023
|
}
|
|
16569
17024
|
const dir = dirname3(path);
|
|
16570
|
-
if (!
|
|
17025
|
+
if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
|
|
16571
17026
|
const buf = randomBytes2(KEY_BYTES);
|
|
16572
|
-
|
|
17027
|
+
writeFileSync4(path, buf.toString("base64"), { mode: 384 });
|
|
16573
17028
|
restrictFileToOwner2(path);
|
|
16574
17029
|
cachedMasterKey = buf;
|
|
16575
17030
|
return buf;
|
|
@@ -16833,7 +17288,7 @@ var init_master_key_guard = __esm({
|
|
|
16833
17288
|
});
|
|
16834
17289
|
|
|
16835
17290
|
// ../../packages/db/src/queries/channel-identity.ts
|
|
16836
|
-
import { createHash } from "crypto";
|
|
17291
|
+
import { createHash as createHash2 } from "crypto";
|
|
16837
17292
|
async function resolveOwnerConversation(db, agentId, channel) {
|
|
16838
17293
|
if (channel === "telegram") {
|
|
16839
17294
|
const [row2] = await db.select({ chatId: telegramAllowedChats.chatId }).from(telegramAllowedChats).where(
|
|
@@ -16909,7 +17364,7 @@ function credentialsFingerprint(creds) {
|
|
|
16909
17364
|
const canonical = JSON.stringify(
|
|
16910
17365
|
Object.keys(creds).sort().map((k) => [k, creds[k]])
|
|
16911
17366
|
);
|
|
16912
|
-
return
|
|
17367
|
+
return createHash2("sha256").update(canonical).digest("hex");
|
|
16913
17368
|
}
|
|
16914
17369
|
async function getBindingCredentials(db, agentId, channel) {
|
|
16915
17370
|
if (channel === "telegram") {
|
|
@@ -17014,6 +17469,39 @@ var init_telegram_allowed = __esm({
|
|
|
17014
17469
|
}
|
|
17015
17470
|
});
|
|
17016
17471
|
|
|
17472
|
+
// ../../packages/db/src/queries/skill-approval-rules.ts
|
|
17473
|
+
async function dropApprovalRulesForDetachedSkill(db, params) {
|
|
17474
|
+
const [skillRetiree] = await db.select({ requiredBuiltins: agentSkills.requiredBuiltins }).from(agentSkills).where(and(eq(agentSkills.id, params.skillId), eq(agentSkills.entityId, params.entityId))).limit(1);
|
|
17475
|
+
const debloquesParLaSkill = skillRetiree?.requiredBuiltins ?? [];
|
|
17476
|
+
if (debloquesParLaSkill.length === 0) return [];
|
|
17477
|
+
const encoreDebloques = new Set(
|
|
17478
|
+
(await db.select({ requiredBuiltins: agentSkills.requiredBuiltins }).from(agentSkillAssignments).innerJoin(agentSkills, eq(agentSkills.id, agentSkillAssignments.skillId)).where(
|
|
17479
|
+
and(
|
|
17480
|
+
eq(agentSkillAssignments.agentId, params.agentId),
|
|
17481
|
+
eq(agentSkillAssignments.entityId, params.entityId)
|
|
17482
|
+
)
|
|
17483
|
+
)).flatMap((r) => r.requiredBuiltins ?? [])
|
|
17484
|
+
);
|
|
17485
|
+
const candidats = debloquesParLaSkill.filter((t) => !encoreDebloques.has(t));
|
|
17486
|
+
if (candidats.length === 0) return [];
|
|
17487
|
+
const retirees = await db.delete(approvalRules).where(
|
|
17488
|
+
and(
|
|
17489
|
+
eq(approvalRules.entityId, params.entityId),
|
|
17490
|
+
eq(approvalRules.agentId, params.agentId),
|
|
17491
|
+
eq(approvalRules.action, "auto_approve"),
|
|
17492
|
+
inArray(approvalRules.toolName, candidats)
|
|
17493
|
+
)
|
|
17494
|
+
).returning({ toolName: approvalRules.toolName });
|
|
17495
|
+
return retirees.map((r) => r.toolName);
|
|
17496
|
+
}
|
|
17497
|
+
var init_skill_approval_rules = __esm({
|
|
17498
|
+
"../../packages/db/src/queries/skill-approval-rules.ts"() {
|
|
17499
|
+
"use strict";
|
|
17500
|
+
init_drizzle_orm();
|
|
17501
|
+
init_schema2();
|
|
17502
|
+
}
|
|
17503
|
+
});
|
|
17504
|
+
|
|
17017
17505
|
// ../../packages/db/src/queries/mcp-approval-context.ts
|
|
17018
17506
|
function slugToPrefix(slug) {
|
|
17019
17507
|
return slug.replace(/[^a-z0-9]+/gi, "_").toLowerCase();
|
|
@@ -17547,6 +18035,7 @@ __export(src_exports, {
|
|
|
17547
18035
|
decryptChannelSecret: () => decryptChannelSecret,
|
|
17548
18036
|
decryptCredentialForDisplay: () => decryptCredentialForDisplay,
|
|
17549
18037
|
desc: () => desc,
|
|
18038
|
+
dropApprovalRulesForDetachedSkill: () => dropApprovalRulesForDetachedSkill,
|
|
17550
18039
|
encryptChannelCredentials: () => encryptChannelCredentials,
|
|
17551
18040
|
encryptChannelSecret: () => encryptChannelSecret,
|
|
17552
18041
|
entities: () => entities,
|
|
@@ -17628,6 +18117,7 @@ var init_src4 = __esm({
|
|
|
17628
18117
|
init_master_key_guard();
|
|
17629
18118
|
init_telegram_owner();
|
|
17630
18119
|
init_telegram_allowed();
|
|
18120
|
+
init_skill_approval_rules();
|
|
17631
18121
|
init_mcp_approval_context();
|
|
17632
18122
|
init_channel_identity();
|
|
17633
18123
|
init_agents2();
|
|
@@ -17692,7 +18182,7 @@ var init_local_auth = __esm({
|
|
|
17692
18182
|
});
|
|
17693
18183
|
|
|
17694
18184
|
// ../../packages/auth/src/lib/constant-time.ts
|
|
17695
|
-
import { createHash as
|
|
18185
|
+
import { createHash as createHash3, timingSafeEqual } from "crypto";
|
|
17696
18186
|
var init_constant_time = __esm({
|
|
17697
18187
|
"../../packages/auth/src/lib/constant-time.ts"() {
|
|
17698
18188
|
"use strict";
|
|
@@ -17865,22 +18355,44 @@ var init_env = __esm({
|
|
|
17865
18355
|
});
|
|
17866
18356
|
|
|
17867
18357
|
// src/lib/ports.ts
|
|
18358
|
+
var ports_exports = {};
|
|
18359
|
+
__export(ports_exports, {
|
|
18360
|
+
DEFAULT_PORTS: () => DEFAULT_PORTS,
|
|
18361
|
+
findFreePort: () => findFreePort,
|
|
18362
|
+
formatPortRotation: () => formatPortRotation,
|
|
18363
|
+
isPortBindable: () => isPortBindable,
|
|
18364
|
+
pidListeningOnPort: () => pidListeningOnPort
|
|
18365
|
+
});
|
|
17868
18366
|
import { createServer } from "net";
|
|
18367
|
+
async function pidListeningOnPort(port) {
|
|
18368
|
+
const { execa: execa4 } = await import("execa");
|
|
18369
|
+
try {
|
|
18370
|
+
const { stdout } = await execa4("netstat", ["-ano"], { reject: false });
|
|
18371
|
+
for (const line2 of stdout.split(/\r?\n/)) {
|
|
18372
|
+
const m = line2.match(/\s+TCP\s+\S+:(\d+)\s+\S+\s+LISTENING\s+(\d+)/);
|
|
18373
|
+
if (m && m[1] && m[2] && Number.parseInt(m[1], 10) === port) {
|
|
18374
|
+
return Number.parseInt(m[2], 10);
|
|
18375
|
+
}
|
|
18376
|
+
}
|
|
18377
|
+
} catch {
|
|
18378
|
+
}
|
|
18379
|
+
return null;
|
|
18380
|
+
}
|
|
17869
18381
|
function isPortBindable(port) {
|
|
17870
|
-
return new Promise((
|
|
18382
|
+
return new Promise((resolve4) => {
|
|
17871
18383
|
const server = createServer();
|
|
17872
|
-
server.once("error", () =>
|
|
18384
|
+
server.once("error", () => resolve4(false));
|
|
17873
18385
|
try {
|
|
17874
18386
|
server.listen(port, "127.0.0.1", () => {
|
|
17875
|
-
server.close(() =>
|
|
18387
|
+
server.close(() => resolve4(true));
|
|
17876
18388
|
});
|
|
17877
18389
|
} catch {
|
|
17878
|
-
|
|
18390
|
+
resolve4(false);
|
|
17879
18391
|
}
|
|
17880
18392
|
});
|
|
17881
18393
|
}
|
|
17882
18394
|
function findFreePort(preferred, maxAttempts = 20) {
|
|
17883
|
-
return new Promise((
|
|
18395
|
+
return new Promise((resolve4, reject) => {
|
|
17884
18396
|
let attempt = 0;
|
|
17885
18397
|
const tryPort = (port) => {
|
|
17886
18398
|
if (attempt >= maxAttempts) {
|
|
@@ -17896,7 +18408,7 @@ function findFreePort(preferred, maxAttempts = 20) {
|
|
|
17896
18408
|
server.listen(port, "127.0.0.1", () => {
|
|
17897
18409
|
const addr = server.address();
|
|
17898
18410
|
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
17899
|
-
server.close(() =>
|
|
18411
|
+
server.close(() => resolve4(actualPort));
|
|
17900
18412
|
});
|
|
17901
18413
|
server.on("error", () => {
|
|
17902
18414
|
tryPort(port + 1);
|
|
@@ -17905,59 +18417,309 @@ function findFreePort(preferred, maxAttempts = 20) {
|
|
|
17905
18417
|
tryPort(preferred);
|
|
17906
18418
|
});
|
|
17907
18419
|
}
|
|
18420
|
+
function formatPortRotation(changes) {
|
|
18421
|
+
const lines = [];
|
|
18422
|
+
for (const c of changes) {
|
|
18423
|
+
lines.push(` - ${c.name}: ${c.from} \u2192 ${c.to}`);
|
|
18424
|
+
if (c.heldBy === null) continue;
|
|
18425
|
+
lines.push(
|
|
18426
|
+
` :${c.from} is STILL HELD by pid ${c.heldBy}, which was not stopped: nothing here could confirm what it is.`,
|
|
18427
|
+
` It is left running and the port is abandoned, not freed. Check that pid and stop it yourself if it is ours.`
|
|
18428
|
+
);
|
|
18429
|
+
}
|
|
18430
|
+
return lines;
|
|
18431
|
+
}
|
|
18432
|
+
var DEFAULT_PORTS;
|
|
17908
18433
|
var init_ports = __esm({
|
|
17909
18434
|
"src/lib/ports.ts"() {
|
|
17910
18435
|
"use strict";
|
|
18436
|
+
DEFAULT_PORTS = {
|
|
18437
|
+
web: 3e3,
|
|
18438
|
+
runner: 3001,
|
|
18439
|
+
postgres: 25432
|
|
18440
|
+
};
|
|
17911
18441
|
}
|
|
17912
18442
|
});
|
|
17913
18443
|
|
|
17914
|
-
// src/lib/
|
|
17915
|
-
|
|
17916
|
-
|
|
18444
|
+
// src/lib/watchdog.ts
|
|
18445
|
+
var watchdog_exports = {};
|
|
18446
|
+
__export(watchdog_exports, {
|
|
18447
|
+
probeRunnerHealth: () => probeRunnerHealth,
|
|
18448
|
+
startHealthWatchdog: () => startHealthWatchdog
|
|
18449
|
+
});
|
|
18450
|
+
async function probeRunnerHealth(runnerUrl) {
|
|
17917
18451
|
try {
|
|
17918
|
-
|
|
17919
|
-
|
|
17920
|
-
const
|
|
17921
|
-
|
|
17922
|
-
|
|
17923
|
-
|
|
18452
|
+
const controller = new AbortController();
|
|
18453
|
+
const t = setTimeout(() => controller.abort(), 3e3);
|
|
18454
|
+
const res = await fetch(`${runnerUrl}/api/health`, { signal: controller.signal });
|
|
18455
|
+
clearTimeout(t);
|
|
18456
|
+
if (res.status === 200) return { state: "healthy", detail: "" };
|
|
18457
|
+
const body = await res.json().catch(() => null);
|
|
18458
|
+
const detail = body?.db === "error" ? "database unreachable (runner reports db: error)" : `runner is unhealthy (HTTP ${res.status})`;
|
|
18459
|
+
return { state: "degraded", detail };
|
|
17924
18460
|
} catch (err) {
|
|
17925
|
-
|
|
17926
|
-
|
|
17927
|
-
|
|
17928
|
-
|
|
17929
|
-
|
|
17930
|
-
}
|
|
17931
|
-
var LOG_ROTATE_MAX_BYTES;
|
|
17932
|
-
var init_log_rotation = __esm({
|
|
17933
|
-
"src/lib/log-rotation.ts"() {
|
|
17934
|
-
"use strict";
|
|
17935
|
-
LOG_ROTATE_MAX_BYTES = 20 * 1024 * 1024;
|
|
18461
|
+
const aborted = err instanceof Error && err.name === "AbortError";
|
|
18462
|
+
return {
|
|
18463
|
+
state: "unreachable",
|
|
18464
|
+
detail: aborted ? "runner did not answer /api/health within 3s (busy or stalled)" : "runner is not answering /api/health"
|
|
18465
|
+
};
|
|
17936
18466
|
}
|
|
17937
|
-
});
|
|
17938
|
-
|
|
17939
|
-
// src/lib/processes.ts
|
|
17940
|
-
import { execa as execa2 } from "execa";
|
|
17941
|
-
import { createWriteStream, openSync, writeFileSync as writeFileSync4, readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
|
|
17942
|
-
import { join as join6, dirname as dirname4, resolve } from "path";
|
|
17943
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
17944
|
-
async function killProcessTree(child) {
|
|
17945
|
-
const pid = child.pid;
|
|
17946
|
-
if (!pid) return;
|
|
17947
|
-
await killPidTree(pid);
|
|
17948
|
-
}
|
|
17949
|
-
async function descendantPidsWin(root, timeoutMs) {
|
|
17950
|
-
const snapshot2 = await processSnapshotWin(timeoutMs);
|
|
17951
|
-
return walkDescendants(snapshot2, root).map((p) => p.pid);
|
|
17952
18467
|
}
|
|
17953
|
-
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
18468
|
+
function startHealthWatchdog(opts) {
|
|
18469
|
+
const intervalMs = opts.intervalMs ?? 3e4;
|
|
18470
|
+
const failureThreshold = opts.failureThreshold ?? 2;
|
|
18471
|
+
let announced = "healthy";
|
|
18472
|
+
let consecutiveFailures = 0;
|
|
18473
|
+
let stopped = false;
|
|
18474
|
+
let inFlight = false;
|
|
18475
|
+
const tick = async () => {
|
|
18476
|
+
if (stopped || inFlight) return;
|
|
18477
|
+
inFlight = true;
|
|
18478
|
+
try {
|
|
18479
|
+
const result = await opts.probe();
|
|
18480
|
+
if (stopped) return;
|
|
18481
|
+
if (result.state === "healthy") {
|
|
18482
|
+
consecutiveFailures = 0;
|
|
18483
|
+
if (announced !== "healthy") {
|
|
18484
|
+
announced = "healthy";
|
|
18485
|
+
opts.onTransition("healthy", "services are answering again");
|
|
18486
|
+
}
|
|
18487
|
+
return;
|
|
18488
|
+
}
|
|
18489
|
+
consecutiveFailures += 1;
|
|
18490
|
+
if (consecutiveFailures < failureThreshold) return;
|
|
18491
|
+
if (announced !== result.state) {
|
|
18492
|
+
announced = result.state;
|
|
18493
|
+
opts.onTransition(result.state, result.detail);
|
|
18494
|
+
}
|
|
18495
|
+
} finally {
|
|
18496
|
+
inFlight = false;
|
|
18497
|
+
}
|
|
18498
|
+
};
|
|
18499
|
+
const timer2 = setInterval(() => void tick(), intervalMs);
|
|
18500
|
+
timer2.unref?.();
|
|
18501
|
+
return {
|
|
18502
|
+
stop: () => {
|
|
18503
|
+
stopped = true;
|
|
18504
|
+
clearInterval(timer2);
|
|
18505
|
+
}
|
|
18506
|
+
};
|
|
18507
|
+
}
|
|
18508
|
+
var init_watchdog = __esm({
|
|
18509
|
+
"src/lib/watchdog.ts"() {
|
|
18510
|
+
"use strict";
|
|
18511
|
+
}
|
|
18512
|
+
});
|
|
18513
|
+
|
|
18514
|
+
// src/lib/already-running.ts
|
|
18515
|
+
function decideStart(evidence) {
|
|
18516
|
+
if (!evidence.runnerHealthy || evidence.postmasterPid === null) return { proceed: true };
|
|
18517
|
+
return {
|
|
18518
|
+
proceed: false,
|
|
18519
|
+
reason: "ALREADY_RUNNING",
|
|
18520
|
+
message: formatAlreadyRunning(evidence)
|
|
18521
|
+
};
|
|
18522
|
+
}
|
|
18523
|
+
function formatAlreadyRunning(evidence) {
|
|
18524
|
+
const parts = [
|
|
18525
|
+
evidence.runnerPid === null ? null : `runner pid ${evidence.runnerPid}`,
|
|
18526
|
+
evidence.webPid === null ? null : `web pid ${evidence.webPid}`,
|
|
18527
|
+
`postgres pid ${String(evidence.postmasterPid)}`
|
|
18528
|
+
].filter((p) => p !== null);
|
|
18529
|
+
const runnerRef = evidence.runnerPid === null ? "that port" : `pid ${evidence.runnerPid}`;
|
|
18530
|
+
return `Nodal-Agents looks already running (${parts.join(", ")}) \u2014 use \`nodal-agents down\` first.
|
|
18531
|
+
Nothing was stopped, and nothing was signalled.
|
|
18532
|
+
What was observed, and only that: something answered /api/health with 200 on the
|
|
18533
|
+
configured runner port, and postmaster.pid in our data directory names a live
|
|
18534
|
+
postmaster. That is usually this install, up and serving.
|
|
18535
|
+
If it is NOT yours: check ${runnerRef} to see whose server is on that port, free the
|
|
18536
|
+
port or change it in ~/.nodalai/config.json, then run \`up\` again.`;
|
|
18537
|
+
}
|
|
18538
|
+
async function decideStartFromProbes(opts) {
|
|
18539
|
+
const { livePostmasterPid: livePostmasterPid2 } = await Promise.resolve().then(() => (init_postgres(), postgres_exports));
|
|
18540
|
+
const postmasterPid = livePostmasterPid2(opts.dataDir);
|
|
18541
|
+
if (postmasterPid === null) return { proceed: true };
|
|
18542
|
+
const { probeRunnerHealth: probeRunnerHealth2 } = await Promise.resolve().then(() => (init_watchdog(), watchdog_exports));
|
|
18543
|
+
const health = await probeRunnerHealth2(`http://127.0.0.1:${opts.runnerPort}`);
|
|
18544
|
+
if (health.state !== "healthy") return { proceed: true };
|
|
18545
|
+
const { pidListeningOnPort: pidListeningOnPort2 } = await Promise.resolve().then(() => (init_ports(), ports_exports));
|
|
18546
|
+
return decideStart({
|
|
18547
|
+
runnerHealthy: true,
|
|
18548
|
+
postmasterPid,
|
|
18549
|
+
runnerPid: await pidListeningOnPort2(opts.runnerPort),
|
|
18550
|
+
webPid: await pidListeningOnPort2(opts.webPort)
|
|
18551
|
+
});
|
|
18552
|
+
}
|
|
18553
|
+
var AlreadyRunningError;
|
|
18554
|
+
var init_already_running = __esm({
|
|
18555
|
+
"src/lib/already-running.ts"() {
|
|
18556
|
+
"use strict";
|
|
18557
|
+
AlreadyRunningError = class extends Error {
|
|
18558
|
+
reason = "ALREADY_RUNNING";
|
|
18559
|
+
constructor(message) {
|
|
18560
|
+
super(message);
|
|
18561
|
+
this.name = "AlreadyRunningError";
|
|
18562
|
+
}
|
|
18563
|
+
};
|
|
18564
|
+
}
|
|
18565
|
+
});
|
|
18566
|
+
|
|
18567
|
+
// src/lib/pid-confirm.ts
|
|
18568
|
+
function confirmRecordedPid(input) {
|
|
18569
|
+
const { recorded, live, tableRead, ownedPostgresPids: ownedPostgresPids2 } = input;
|
|
18570
|
+
if (!tableRead) {
|
|
18571
|
+
return {
|
|
18572
|
+
killable: false,
|
|
18573
|
+
code: "TABLE_UNREADABLE",
|
|
18574
|
+
detail: `pid ${recorded.pid} could not be confirmed: the process table did not answer`
|
|
18575
|
+
};
|
|
18576
|
+
}
|
|
18577
|
+
if (live === void 0) {
|
|
18578
|
+
return {
|
|
18579
|
+
killable: false,
|
|
18580
|
+
code: "PID_GONE",
|
|
18581
|
+
detail: `pid ${recorded.pid} is no longer running`
|
|
18582
|
+
};
|
|
18583
|
+
}
|
|
18584
|
+
if (isPostgresExe(live.name) && !ownedPostgresPids2.has(live.pid)) {
|
|
18585
|
+
return {
|
|
18586
|
+
killable: false,
|
|
18587
|
+
code: "FOREIGN_POSTGRES",
|
|
18588
|
+
detail: `pid ${recorded.pid} is a ${live.name} that our data dir does not claim`
|
|
18589
|
+
};
|
|
18590
|
+
}
|
|
18591
|
+
if (recorded.name !== void 0 && !sameExe(recorded.name, live.name)) {
|
|
18592
|
+
return {
|
|
18593
|
+
killable: false,
|
|
18594
|
+
code: "BINARY_CHANGED",
|
|
18595
|
+
detail: `pid ${recorded.pid} was recorded as ${recorded.name} and now runs ${live.name}`
|
|
18596
|
+
};
|
|
18597
|
+
}
|
|
18598
|
+
if (recorded.startedAt !== void 0 && recorded.startedAt !== live.startedAt) {
|
|
18599
|
+
return {
|
|
18600
|
+
killable: false,
|
|
18601
|
+
code: "PID_RECYCLED",
|
|
18602
|
+
detail: `pid ${recorded.pid} started at ${live.startedAt}, recorded at ${recorded.startedAt}`
|
|
18603
|
+
};
|
|
18604
|
+
}
|
|
18605
|
+
if (recorded.startedAt === void 0 && recorded.name === void 0) {
|
|
18606
|
+
return {
|
|
18607
|
+
killable: false,
|
|
18608
|
+
code: "IDENTITY_NOT_RECORDED",
|
|
18609
|
+
detail: `pid ${recorded.pid} was recorded as a bare number: nothing identifies it now`
|
|
18610
|
+
};
|
|
18611
|
+
}
|
|
18612
|
+
return OK;
|
|
18613
|
+
}
|
|
18614
|
+
function sameExe(a, b2) {
|
|
18615
|
+
return a.toLowerCase() === b2.toLowerCase();
|
|
18616
|
+
}
|
|
18617
|
+
function isPostgresExe(name) {
|
|
18618
|
+
return sameExe(name, POSTGRES_EXE);
|
|
18619
|
+
}
|
|
18620
|
+
function confirmTree(root, members, ownedPostgresPids2) {
|
|
18621
|
+
const verdict = confirmRecordedPid(root);
|
|
18622
|
+
const foreign = [];
|
|
18623
|
+
const killable = [];
|
|
18624
|
+
for (const member of members) {
|
|
18625
|
+
if (isPostgresExe(member.name) && !ownedPostgresPids2.has(member.pid)) foreign.push(member);
|
|
18626
|
+
else killable.push(member);
|
|
18627
|
+
}
|
|
18628
|
+
return {
|
|
18629
|
+
root: verdict,
|
|
18630
|
+
treeKillAllowed: verdict.killable && foreign.length === 0,
|
|
18631
|
+
foreign,
|
|
18632
|
+
killable
|
|
18633
|
+
};
|
|
18634
|
+
}
|
|
18635
|
+
function formatRefusal(refusal) {
|
|
18636
|
+
return `KILL_REFUSED code=${refusal.code} ${refusal.detail}`;
|
|
18637
|
+
}
|
|
18638
|
+
function unconfirmedIdentityNotice(label, pid) {
|
|
18639
|
+
return `${label} (pid ${pid}) \u2014 no process table on this platform to confirm it with`;
|
|
18640
|
+
}
|
|
18641
|
+
var OK, POSTGRES_EXE;
|
|
18642
|
+
var init_pid_confirm = __esm({
|
|
18643
|
+
"src/lib/pid-confirm.ts"() {
|
|
18644
|
+
"use strict";
|
|
18645
|
+
OK = { killable: true };
|
|
18646
|
+
POSTGRES_EXE = "postgres.exe";
|
|
18647
|
+
}
|
|
18648
|
+
});
|
|
18649
|
+
|
|
18650
|
+
// src/lib/log-rotation.ts
|
|
18651
|
+
import { existsSync as existsSync7, renameSync as renameSync2, rmSync, statSync as statSync2 } from "fs";
|
|
18652
|
+
function rotateLogIfNeeded(logFile, maxBytes = LOG_ROTATE_MAX_BYTES) {
|
|
18653
|
+
try {
|
|
18654
|
+
if (!existsSync7(logFile)) return false;
|
|
18655
|
+
if (statSync2(logFile).size < maxBytes) return false;
|
|
18656
|
+
const archived = `${logFile}.1`;
|
|
18657
|
+
rmSync(archived, { force: true });
|
|
18658
|
+
renameSync2(logFile, archived);
|
|
18659
|
+
return true;
|
|
18660
|
+
} catch (err) {
|
|
18661
|
+
console.warn(
|
|
18662
|
+
`[nodalai] log rotation skipped for ${logFile}: ${err instanceof Error ? err.message : String(err)}`
|
|
18663
|
+
);
|
|
18664
|
+
return false;
|
|
18665
|
+
}
|
|
18666
|
+
}
|
|
18667
|
+
var LOG_ROTATE_MAX_BYTES;
|
|
18668
|
+
var init_log_rotation = __esm({
|
|
18669
|
+
"src/lib/log-rotation.ts"() {
|
|
18670
|
+
"use strict";
|
|
18671
|
+
LOG_ROTATE_MAX_BYTES = 20 * 1024 * 1024;
|
|
18672
|
+
}
|
|
18673
|
+
});
|
|
18674
|
+
|
|
18675
|
+
// src/lib/launcher-log.ts
|
|
18676
|
+
import { appendFileSync } from "fs";
|
|
18677
|
+
import { join as join7 } from "path";
|
|
18678
|
+
function formatLauncherLine(at, event, detail) {
|
|
18679
|
+
return `${at.toISOString()} ${event} ${detail.replace(/\s*\r?\n\s*/g, " ").trim()}
|
|
18680
|
+
`;
|
|
18681
|
+
}
|
|
18682
|
+
function logLauncherEvent(event, detail) {
|
|
18683
|
+
try {
|
|
18684
|
+
rotateLogIfNeeded(LAUNCHER_LOG);
|
|
18685
|
+
appendFileSync(LAUNCHER_LOG, formatLauncherLine(/* @__PURE__ */ new Date(), event, detail), "utf-8");
|
|
18686
|
+
} catch {
|
|
18687
|
+
}
|
|
18688
|
+
}
|
|
18689
|
+
var LAUNCHER_LOG;
|
|
18690
|
+
var init_launcher_log = __esm({
|
|
18691
|
+
"src/lib/launcher-log.ts"() {
|
|
18692
|
+
"use strict";
|
|
18693
|
+
init_config();
|
|
18694
|
+
init_log_rotation();
|
|
18695
|
+
LAUNCHER_LOG = join7(LOG_DIR, "launcher.log");
|
|
18696
|
+
}
|
|
18697
|
+
});
|
|
18698
|
+
|
|
18699
|
+
// src/lib/processes.ts
|
|
18700
|
+
import { execa as execa2 } from "execa";
|
|
18701
|
+
import { createWriteStream, openSync, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
|
|
18702
|
+
import { join as join8, dirname as dirname4, resolve as resolve2 } from "path";
|
|
18703
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
18704
|
+
function asLiveRecord(rec) {
|
|
18705
|
+
return { pid: rec.pid, startedAt: rec.startedAt, name: rec.name ?? "" };
|
|
18706
|
+
}
|
|
18707
|
+
function asLive(rec) {
|
|
18708
|
+
return rec === void 0 ? void 0 : asLiveRecord(rec);
|
|
18709
|
+
}
|
|
18710
|
+
async function killProcessTree(child) {
|
|
18711
|
+
const pid = child.pid;
|
|
18712
|
+
if (!pid) return;
|
|
18713
|
+
await killPidTree(pid);
|
|
18714
|
+
}
|
|
18715
|
+
async function processSnapshotWin(timeoutMs = SNAPSHOT_BUDGET_MS) {
|
|
18716
|
+
if (process.platform !== "win32") return /* @__PURE__ */ new Map();
|
|
18717
|
+
if (!inFlightSnapshot) {
|
|
18718
|
+
inFlightSnapshot = readProcessTableWin(timeoutMs).finally(() => {
|
|
18719
|
+
inFlightSnapshot = null;
|
|
18720
|
+
});
|
|
18721
|
+
}
|
|
18722
|
+
return inFlightSnapshot;
|
|
17961
18723
|
}
|
|
17962
18724
|
async function readProcessTableWin(timeoutMs) {
|
|
17963
18725
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -17997,12 +18759,13 @@ async function readProcessTableWin(timeoutMs) {
|
|
|
17997
18759
|
}
|
|
17998
18760
|
for (const line2 of rows.split(/\r?\n/)) {
|
|
17999
18761
|
const parts = line2.trim().split("|");
|
|
18000
|
-
if (parts.length !==
|
|
18762
|
+
if (parts.length !== 4) continue;
|
|
18001
18763
|
const pid = Number.parseInt(parts[0] ?? "", 10);
|
|
18002
18764
|
const ppid = Number.parseInt(parts[1] ?? "", 10);
|
|
18003
18765
|
const startedAt = (parts[2] ?? "").trim();
|
|
18766
|
+
const name = (parts[3] ?? "").trim();
|
|
18004
18767
|
if (!Number.isInteger(pid) || !Number.isInteger(ppid) || startedAt === "") continue;
|
|
18005
|
-
out.set(pid, { pid, ppid, startedAt });
|
|
18768
|
+
out.set(pid, { pid, ppid, startedAt, name });
|
|
18006
18769
|
}
|
|
18007
18770
|
if (out.size > 0) {
|
|
18008
18771
|
lastSnapshotFailure = null;
|
|
@@ -18036,17 +18799,105 @@ function walkDescendants(snapshot2, root) {
|
|
|
18036
18799
|
}
|
|
18037
18800
|
return out;
|
|
18038
18801
|
}
|
|
18039
|
-
async function
|
|
18802
|
+
async function ownedPostgres() {
|
|
18803
|
+
const { postgresProcessesForDataDir: postgresProcessesForDataDir2 } = await Promise.resolve().then(() => (init_postgres(), postgres_exports));
|
|
18804
|
+
return new Set((await postgresProcessesForDataDir2()).owned);
|
|
18805
|
+
}
|
|
18806
|
+
async function ownedPostgresIfAnyInvolved(candidates) {
|
|
18807
|
+
const EMPTY = /* @__PURE__ */ new Set();
|
|
18808
|
+
const anyPostgres = candidates.some((c) => (c.name ?? "").toLowerCase() === "postgres.exe");
|
|
18809
|
+
return anyPostgres ? await ownedPostgres() : EMPTY;
|
|
18810
|
+
}
|
|
18811
|
+
function vetoesRoot(code, fromRecord) {
|
|
18812
|
+
if (ROOT_KILL_VETO.has(code)) return true;
|
|
18813
|
+
return fromRecord && code === "IDENTITY_NOT_RECORDED";
|
|
18814
|
+
}
|
|
18815
|
+
async function reconfirmMembers(members, rootPid, ownedPostgresPids2) {
|
|
18816
|
+
const fresh = await processSnapshotWin(SHUTDOWN_SNAPSHOT_BUDGET_MS);
|
|
18817
|
+
if (fresh.size === 0) {
|
|
18818
|
+
process.stderr.write(
|
|
18819
|
+
`KILL_UNCONFIRMED code=TABLE_UNREADABLE pid=${rootPid} the tree members are swept on the earlier reading: the table would not answer a second time
|
|
18820
|
+
`
|
|
18821
|
+
);
|
|
18822
|
+
return [...members];
|
|
18823
|
+
}
|
|
18824
|
+
const out = [];
|
|
18825
|
+
for (const member of members) {
|
|
18826
|
+
const verdict = confirmRecordedPid({
|
|
18827
|
+
// An empty name is a row WMI gave us without one; offering it as a
|
|
18828
|
+
// recorded name would read as "it changed" the moment the second reading
|
|
18829
|
+
// has one. One less proof, never a false refusal.
|
|
18830
|
+
recorded: {
|
|
18831
|
+
pid: member.pid,
|
|
18832
|
+
startedAt: member.startedAt,
|
|
18833
|
+
...member.name === "" ? {} : { name: member.name }
|
|
18834
|
+
},
|
|
18835
|
+
live: asLive(fresh.get(member.pid)),
|
|
18836
|
+
tableRead: true,
|
|
18837
|
+
ownedPostgresPids: ownedPostgresPids2
|
|
18838
|
+
});
|
|
18839
|
+
if (verdict.killable) {
|
|
18840
|
+
out.push(member);
|
|
18841
|
+
continue;
|
|
18842
|
+
}
|
|
18843
|
+
if (verdict.code !== "PID_GONE") process.stderr.write(`${formatRefusal(verdict)}
|
|
18844
|
+
`);
|
|
18845
|
+
}
|
|
18846
|
+
return out;
|
|
18847
|
+
}
|
|
18848
|
+
async function killPidTree(pid, ownedPostgresPids2, recorded) {
|
|
18040
18849
|
if (process.platform === "win32") {
|
|
18041
|
-
const
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18850
|
+
const snapshot2 = await processSnapshotWin(SHUTDOWN_SNAPSHOT_BUDGET_MS);
|
|
18851
|
+
const descendants = walkDescendants(snapshot2, pid);
|
|
18852
|
+
const owned = ownedPostgresPids2 ?? await ownedPostgresIfAnyInvolved([...descendants, snapshot2.get(pid) ?? {}]);
|
|
18853
|
+
const fromRecord = recorded !== void 0;
|
|
18854
|
+
const { treeKillAllowed, root, foreign, killable } = confirmTree(
|
|
18855
|
+
{
|
|
18856
|
+
recorded: recorded ?? { pid },
|
|
18857
|
+
live: asLive(snapshot2.get(pid)),
|
|
18858
|
+
tableRead: snapshot2.size > 0,
|
|
18859
|
+
ownedPostgresPids: owned
|
|
18860
|
+
},
|
|
18861
|
+
descendants.map(asLiveRecord),
|
|
18862
|
+
owned
|
|
18863
|
+
);
|
|
18864
|
+
if (!root.killable && root.code === "TABLE_UNREADABLE") {
|
|
18865
|
+
if (fromRecord) {
|
|
18866
|
+
process.stderr.write(`${formatRefusal(root)}
|
|
18867
|
+
`);
|
|
18868
|
+
return;
|
|
18869
|
+
}
|
|
18870
|
+
process.stderr.write(
|
|
18871
|
+
`KILL_UNCONFIRMED code=TABLE_UNREADABLE pid=${pid} is a live handle, not a record: the tree kill proceeds with the identity unconfirmed
|
|
18872
|
+
`
|
|
18873
|
+
);
|
|
18045
18874
|
}
|
|
18046
|
-
|
|
18047
|
-
|
|
18875
|
+
const rootVetoed = !root.killable && vetoesRoot(root.code, fromRecord);
|
|
18876
|
+
if (rootVetoed) process.stderr.write(`${formatRefusal(root)}
|
|
18877
|
+
`);
|
|
18878
|
+
const rootGone = !root.killable && root.code === "PID_GONE";
|
|
18879
|
+
for (const stranger of foreign) {
|
|
18880
|
+
process.stderr.write(
|
|
18881
|
+
`KILL_REFUSED code=FOREIGN_POSTGRES pid=${stranger.pid} is a ${stranger.name} in the tree of pid ${pid} that our data dir does not claim; the tree kill was done pid by pid around it
|
|
18882
|
+
`
|
|
18883
|
+
);
|
|
18884
|
+
}
|
|
18885
|
+
if (treeKillAllowed) {
|
|
18886
|
+
try {
|
|
18887
|
+
await execa2("taskkill", ["/T", "/F", "/PID", String(pid)], { reject: false });
|
|
18888
|
+
} catch {
|
|
18889
|
+
}
|
|
18890
|
+
} else if (!rootVetoed && !rootGone) {
|
|
18891
|
+
try {
|
|
18892
|
+
await execa2("taskkill", ["/F", "/PID", String(pid)], { reject: false });
|
|
18893
|
+
} catch {
|
|
18894
|
+
}
|
|
18895
|
+
}
|
|
18896
|
+
const vouched = killable.length > 0 ? await reconfirmMembers(killable, pid, owned) : [];
|
|
18897
|
+
for (const child of vouched) {
|
|
18898
|
+
if (!isPidAlive(child.pid)) continue;
|
|
18048
18899
|
try {
|
|
18049
|
-
await execa2("taskkill", ["/F", "/PID", String(child)], { reject: false });
|
|
18900
|
+
await execa2("taskkill", ["/F", "/PID", String(child.pid)], { reject: false });
|
|
18050
18901
|
} catch {
|
|
18051
18902
|
}
|
|
18052
18903
|
}
|
|
@@ -18087,14 +18938,14 @@ function resolveAppDir(appName) {
|
|
|
18087
18938
|
const fileDir = dirname4(here);
|
|
18088
18939
|
let cursor = fileDir;
|
|
18089
18940
|
for (let i = 0; i < 8; i++) {
|
|
18090
|
-
if (
|
|
18091
|
-
return
|
|
18941
|
+
if (existsSync8(join8(cursor, "pnpm-workspace.yaml"))) {
|
|
18942
|
+
return join8(cursor, appName);
|
|
18092
18943
|
}
|
|
18093
18944
|
const parent = dirname4(cursor);
|
|
18094
18945
|
if (parent === cursor) break;
|
|
18095
18946
|
cursor = parent;
|
|
18096
18947
|
}
|
|
18097
|
-
return
|
|
18948
|
+
return resolve2(fileDir, "..", "..", "..", "..", appName);
|
|
18098
18949
|
}
|
|
18099
18950
|
function spawnWiring(logFile, detach) {
|
|
18100
18951
|
if (!detach) return { stdin: "ignore", stdout: "pipe", stderr: "pipe", detached: false };
|
|
@@ -18105,7 +18956,7 @@ function spawnWiring(logFile, detach) {
|
|
|
18105
18956
|
};
|
|
18106
18957
|
}
|
|
18107
18958
|
function spawnRunner(env, opts = {}) {
|
|
18108
|
-
const logFile =
|
|
18959
|
+
const logFile = join8(LOG_DIR, "runner.log");
|
|
18109
18960
|
rotateLogIfNeeded(logFile);
|
|
18110
18961
|
const outStream = createWriteStream(logFile, { flags: "a" });
|
|
18111
18962
|
let bin;
|
|
@@ -18113,7 +18964,7 @@ function spawnRunner(env, opts = {}) {
|
|
|
18113
18964
|
let cwd;
|
|
18114
18965
|
if (BUNDLED_ROOT) {
|
|
18115
18966
|
bin = process.execPath;
|
|
18116
|
-
args = [
|
|
18967
|
+
args = [join8(BUNDLED_ROOT, "runner.js")];
|
|
18117
18968
|
cwd = BUNDLED_ROOT;
|
|
18118
18969
|
} else {
|
|
18119
18970
|
const runnerDir = resolveAppDir("apps/runner");
|
|
@@ -18151,7 +19002,7 @@ env keys: ${Object.keys(env).join(",")}
|
|
|
18151
19002
|
return child;
|
|
18152
19003
|
}
|
|
18153
19004
|
function spawnWeb(env, opts = {}) {
|
|
18154
|
-
const logFile =
|
|
19005
|
+
const logFile = join8(LOG_DIR, "web.log");
|
|
18155
19006
|
rotateLogIfNeeded(logFile);
|
|
18156
19007
|
const outStream = createWriteStream(logFile, { flags: "a" });
|
|
18157
19008
|
let bin;
|
|
@@ -18160,8 +19011,8 @@ function spawnWeb(env, opts = {}) {
|
|
|
18160
19011
|
let modeLabel;
|
|
18161
19012
|
if (BUNDLED_ROOT) {
|
|
18162
19013
|
bin = process.execPath;
|
|
18163
|
-
args = [
|
|
18164
|
-
cwd =
|
|
19014
|
+
args = [join8(BUNDLED_ROOT, "web", "server.js")];
|
|
19015
|
+
cwd = join8(BUNDLED_ROOT, "web");
|
|
18165
19016
|
modeLabel = "bundled-standalone";
|
|
18166
19017
|
} else {
|
|
18167
19018
|
const webDir = resolveAppDir("apps/web");
|
|
@@ -18200,33 +19051,52 @@ env keys: ${Object.keys(env).join(",")}
|
|
|
18200
19051
|
}
|
|
18201
19052
|
function resolveLocalBin(packageDir, binName) {
|
|
18202
19053
|
const ext = process.platform === "win32" ? ".CMD" : "";
|
|
18203
|
-
return
|
|
19054
|
+
return join8(packageDir, "node_modules", ".bin", `${binName}${ext}`);
|
|
18204
19055
|
}
|
|
18205
19056
|
async function recordServiceTree(pids) {
|
|
18206
19057
|
if (process.platform !== "win32") return;
|
|
18207
19058
|
const snapshot2 = await processSnapshotWin();
|
|
18208
19059
|
if (snapshot2.size === 0) return;
|
|
18209
19060
|
const children = [];
|
|
19061
|
+
const roots = [];
|
|
18210
19062
|
const seen = /* @__PURE__ */ new Set();
|
|
18211
19063
|
for (const root of [pids.runner, pids.web]) {
|
|
18212
19064
|
if (!root) continue;
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
|
|
19065
|
+
const rec = snapshot2.get(root);
|
|
19066
|
+
if (rec) roots.push(rec);
|
|
19067
|
+
for (const rec2 of walkDescendants(snapshot2, root)) {
|
|
19068
|
+
if (seen.has(rec2.pid)) continue;
|
|
19069
|
+
seen.add(rec2.pid);
|
|
19070
|
+
children.push(rec2);
|
|
18217
19071
|
}
|
|
18218
19072
|
}
|
|
18219
|
-
writePids({ ...pids, children });
|
|
19073
|
+
writePids({ ...pids, children, roots });
|
|
19074
|
+
}
|
|
19075
|
+
function recordedRoot(pids, pid) {
|
|
19076
|
+
const found = pids?.roots?.find((r) => r.pid === pid);
|
|
19077
|
+
if (!found) return { pid };
|
|
19078
|
+
return { pid, startedAt: found.startedAt, ...found.name ? { name: found.name } : {} };
|
|
18220
19079
|
}
|
|
18221
|
-
async function sweepRecordedChildren(children) {
|
|
19080
|
+
async function sweepRecordedChildren(children, ownedPostgresPids2) {
|
|
18222
19081
|
if (process.platform !== "win32" || children.length === 0) return [];
|
|
18223
19082
|
const alive = children.filter((c) => isPidAlive(c.pid));
|
|
18224
19083
|
if (alive.length === 0) return [];
|
|
18225
19084
|
const snapshot2 = await processSnapshotWin();
|
|
19085
|
+
const tableRead = snapshot2.size > 0;
|
|
19086
|
+
const owned = ownedPostgresPids2 ?? await ownedPostgresIfAnyInvolved(alive.flatMap((rec) => [rec, snapshot2.get(rec.pid) ?? {}]));
|
|
18226
19087
|
const killed = [];
|
|
18227
19088
|
for (const rec of alive) {
|
|
18228
|
-
const
|
|
18229
|
-
|
|
19089
|
+
const verdict = confirmRecordedPid({
|
|
19090
|
+
recorded: rec,
|
|
19091
|
+
live: asLive(snapshot2.get(rec.pid)),
|
|
19092
|
+
tableRead,
|
|
19093
|
+
ownedPostgresPids: owned
|
|
19094
|
+
});
|
|
19095
|
+
if (!verdict.killable) {
|
|
19096
|
+
if (verdict.code !== "PID_GONE") process.stderr.write(`${formatRefusal(verdict)}
|
|
19097
|
+
`);
|
|
19098
|
+
continue;
|
|
19099
|
+
}
|
|
18230
19100
|
try {
|
|
18231
19101
|
await execa2("taskkill", ["/F", "/PID", String(rec.pid)], { reject: false });
|
|
18232
19102
|
killed.push(rec.pid);
|
|
@@ -18236,21 +19106,21 @@ async function sweepRecordedChildren(children) {
|
|
|
18236
19106
|
return killed;
|
|
18237
19107
|
}
|
|
18238
19108
|
function writePids(pids) {
|
|
18239
|
-
|
|
19109
|
+
writeFileSync5(join8(PID_DIR, "processes.json"), JSON.stringify(pids, null, 2), "utf-8");
|
|
18240
19110
|
}
|
|
18241
19111
|
function readPids() {
|
|
18242
|
-
const pidFile =
|
|
18243
|
-
if (!
|
|
19112
|
+
const pidFile = join8(PID_DIR, "processes.json");
|
|
19113
|
+
if (!existsSync8(pidFile)) return null;
|
|
18244
19114
|
try {
|
|
18245
|
-
return JSON.parse(
|
|
19115
|
+
return JSON.parse(readFileSync6(pidFile, "utf-8"));
|
|
18246
19116
|
} catch {
|
|
18247
19117
|
return null;
|
|
18248
19118
|
}
|
|
18249
19119
|
}
|
|
18250
19120
|
function clearPids() {
|
|
18251
|
-
const pidFile =
|
|
18252
|
-
if (
|
|
18253
|
-
|
|
19121
|
+
const pidFile = join8(PID_DIR, "processes.json");
|
|
19122
|
+
if (existsSync8(pidFile)) {
|
|
19123
|
+
writeFileSync5(pidFile, JSON.stringify({}), "utf-8");
|
|
18254
19124
|
}
|
|
18255
19125
|
}
|
|
18256
19126
|
async function waitForHealth(url, timeoutMs = 3e4) {
|
|
@@ -18290,12 +19160,13 @@ async function assertWebRenders(url, timeoutMs = 3e5) {
|
|
|
18290
19160
|
function sleep(ms) {
|
|
18291
19161
|
return new Promise((r) => setTimeout(r, ms));
|
|
18292
19162
|
}
|
|
18293
|
-
var SNAPSHOT_BUDGET_MS, SHUTDOWN_SNAPSHOT_BUDGET_MS, inFlightSnapshot, PROCESS_TABLE_QUERIES, lastSnapshotFailure, BUNDLED_ROOT;
|
|
19163
|
+
var SNAPSHOT_BUDGET_MS, SHUTDOWN_SNAPSHOT_BUDGET_MS, inFlightSnapshot, PROCESS_TABLE_QUERIES, lastSnapshotFailure, ROOT_KILL_VETO, BUNDLED_ROOT;
|
|
18294
19164
|
var init_processes = __esm({
|
|
18295
19165
|
"src/lib/processes.ts"() {
|
|
18296
19166
|
"use strict";
|
|
18297
19167
|
init_config();
|
|
18298
19168
|
init_log_rotation();
|
|
19169
|
+
init_pid_confirm();
|
|
18299
19170
|
SNAPSHOT_BUDGET_MS = 2e4;
|
|
18300
19171
|
SHUTDOWN_SNAPSHOT_BUDGET_MS = 6e3;
|
|
18301
19172
|
inFlightSnapshot = null;
|
|
@@ -18303,7 +19174,7 @@ var init_processes = __esm({
|
|
|
18303
19174
|
{
|
|
18304
19175
|
name: "Get-CimInstance",
|
|
18305
19176
|
// -Property keeps WMI from materialising every column of every process.
|
|
18306
|
-
command: 'Get-CimInstance Win32_Process -Property ProcessId,ParentProcessId,CreationDate | ForEach-Object { "$($_.ProcessId)|$($_.ParentProcessId)|$($_.CreationDate.Ticks)" }'
|
|
19177
|
+
command: 'Get-CimInstance Win32_Process -Property ProcessId,ParentProcessId,CreationDate,Name | ForEach-Object { "$($_.ProcessId)|$($_.ParentProcessId)|$($_.CreationDate.Ticks)|$($_.Name)" }'
|
|
18307
19178
|
},
|
|
18308
19179
|
{
|
|
18309
19180
|
name: "Get-WmiObject",
|
|
@@ -18321,82 +19192,22 @@ var init_processes = __esm({
|
|
|
18321
19192
|
// (The obvious alternative, Get-Process | $_.Parent, was tried first and
|
|
18322
19193
|
// does not exist before PowerShell 6. It returned empty parents for every
|
|
18323
19194
|
// row, which the parser correctly discarded.)
|
|
18324
|
-
command: 'Get-WmiObject Win32_Process | ForEach-Object { "$($_.ProcessId)|$($_.ParentProcessId)|$($_.ConvertToDateTime($_.CreationDate).Ticks)" }'
|
|
19195
|
+
command: 'Get-WmiObject Win32_Process | ForEach-Object { "$($_.ProcessId)|$($_.ParentProcessId)|$($_.ConvertToDateTime($_.CreationDate).Ticks)|$($_.Name)" }'
|
|
18325
19196
|
}
|
|
18326
19197
|
];
|
|
18327
19198
|
lastSnapshotFailure = null;
|
|
19199
|
+
ROOT_KILL_VETO = /* @__PURE__ */ new Set([
|
|
19200
|
+
"FOREIGN_POSTGRES",
|
|
19201
|
+
"BINARY_CHANGED",
|
|
19202
|
+
"PID_RECYCLED"
|
|
19203
|
+
]);
|
|
18328
19204
|
BUNDLED_ROOT = (() => {
|
|
18329
19205
|
const here = dirname4(fileURLToPath3(import.meta.url));
|
|
18330
|
-
return
|
|
19206
|
+
return existsSync8(join8(here, "runner.js")) ? here : null;
|
|
18331
19207
|
})();
|
|
18332
19208
|
}
|
|
18333
19209
|
});
|
|
18334
19210
|
|
|
18335
|
-
// src/lib/watchdog.ts
|
|
18336
|
-
async function probeRunnerHealth(runnerUrl) {
|
|
18337
|
-
try {
|
|
18338
|
-
const controller = new AbortController();
|
|
18339
|
-
const t = setTimeout(() => controller.abort(), 3e3);
|
|
18340
|
-
const res = await fetch(`${runnerUrl}/api/health`, { signal: controller.signal });
|
|
18341
|
-
clearTimeout(t);
|
|
18342
|
-
if (res.status === 200) return { state: "healthy", detail: "" };
|
|
18343
|
-
const body = await res.json().catch(() => null);
|
|
18344
|
-
const detail = body?.db === "error" ? "database unreachable (runner reports db: error)" : `runner is unhealthy (HTTP ${res.status})`;
|
|
18345
|
-
return { state: "degraded", detail };
|
|
18346
|
-
} catch (err) {
|
|
18347
|
-
const aborted = err instanceof Error && err.name === "AbortError";
|
|
18348
|
-
return {
|
|
18349
|
-
state: "unreachable",
|
|
18350
|
-
detail: aborted ? "runner did not answer /api/health within 3s (busy or stalled)" : "runner is not answering /api/health"
|
|
18351
|
-
};
|
|
18352
|
-
}
|
|
18353
|
-
}
|
|
18354
|
-
function startHealthWatchdog(opts) {
|
|
18355
|
-
const intervalMs = opts.intervalMs ?? 3e4;
|
|
18356
|
-
const failureThreshold = opts.failureThreshold ?? 2;
|
|
18357
|
-
let announced = "healthy";
|
|
18358
|
-
let consecutiveFailures = 0;
|
|
18359
|
-
let stopped = false;
|
|
18360
|
-
let inFlight = false;
|
|
18361
|
-
const tick = async () => {
|
|
18362
|
-
if (stopped || inFlight) return;
|
|
18363
|
-
inFlight = true;
|
|
18364
|
-
try {
|
|
18365
|
-
const result = await opts.probe();
|
|
18366
|
-
if (stopped) return;
|
|
18367
|
-
if (result.state === "healthy") {
|
|
18368
|
-
consecutiveFailures = 0;
|
|
18369
|
-
if (announced !== "healthy") {
|
|
18370
|
-
announced = "healthy";
|
|
18371
|
-
opts.onTransition("healthy", "services are answering again");
|
|
18372
|
-
}
|
|
18373
|
-
return;
|
|
18374
|
-
}
|
|
18375
|
-
consecutiveFailures += 1;
|
|
18376
|
-
if (consecutiveFailures < failureThreshold) return;
|
|
18377
|
-
if (announced !== result.state) {
|
|
18378
|
-
announced = result.state;
|
|
18379
|
-
opts.onTransition(result.state, result.detail);
|
|
18380
|
-
}
|
|
18381
|
-
} finally {
|
|
18382
|
-
inFlight = false;
|
|
18383
|
-
}
|
|
18384
|
-
};
|
|
18385
|
-
const timer2 = setInterval(() => void tick(), intervalMs);
|
|
18386
|
-
timer2.unref?.();
|
|
18387
|
-
return {
|
|
18388
|
-
stop: () => {
|
|
18389
|
-
stopped = true;
|
|
18390
|
-
clearInterval(timer2);
|
|
18391
|
-
}
|
|
18392
|
-
};
|
|
18393
|
-
}
|
|
18394
|
-
var init_watchdog = __esm({
|
|
18395
|
-
"src/lib/watchdog.ts"() {
|
|
18396
|
-
"use strict";
|
|
18397
|
-
}
|
|
18398
|
-
});
|
|
18399
|
-
|
|
18400
19211
|
// src/commands/up.ts
|
|
18401
19212
|
var up_exports = {};
|
|
18402
19213
|
__export(up_exports, {
|
|
@@ -18406,20 +19217,20 @@ import chalk from "chalk";
|
|
|
18406
19217
|
import ora from "ora";
|
|
18407
19218
|
import open from "open";
|
|
18408
19219
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
18409
|
-
import { existsSync as
|
|
18410
|
-
import { join as
|
|
19220
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
19221
|
+
import { join as join9 } from "path";
|
|
18411
19222
|
async function killSilent(child) {
|
|
18412
19223
|
await killProcessTree(child);
|
|
18413
19224
|
}
|
|
18414
19225
|
function printLogTail(service, lines) {
|
|
18415
|
-
const logFile =
|
|
19226
|
+
const logFile = join9(LOG_DIR, `${service}.log`);
|
|
18416
19227
|
try {
|
|
18417
|
-
if (!
|
|
19228
|
+
if (!existsSync9(logFile)) {
|
|
18418
19229
|
console.error(chalk.gray(`
|
|
18419
19230
|
${service}: no log at ${logFile}`));
|
|
18420
19231
|
return;
|
|
18421
19232
|
}
|
|
18422
|
-
const tail =
|
|
19233
|
+
const tail = readFileSync7(logFile, "utf-8").split(/\r?\n/).filter((l) => l.trim() !== "").slice(-lines);
|
|
18423
19234
|
if (tail.length === 0) {
|
|
18424
19235
|
console.error(chalk.gray(`
|
|
18425
19236
|
${service}: log is empty (${logFile})`));
|
|
@@ -18434,20 +19245,6 @@ function printLogTail(service, lines) {
|
|
|
18434
19245
|
${service}: could not read ${logFile}`));
|
|
18435
19246
|
}
|
|
18436
19247
|
}
|
|
18437
|
-
async function pidListeningOnPort(port) {
|
|
18438
|
-
const { execa: execa4 } = await import("execa");
|
|
18439
|
-
try {
|
|
18440
|
-
const { stdout } = await execa4("netstat", ["-ano"], { reject: false });
|
|
18441
|
-
for (const line2 of stdout.split(/\r?\n/)) {
|
|
18442
|
-
const m = line2.match(/\s+TCP\s+\S+:(\d+)\s+\S+\s+LISTENING\s+(\d+)/);
|
|
18443
|
-
if (m && m[1] && m[2] && Number.parseInt(m[1], 10) === port) {
|
|
18444
|
-
return Number.parseInt(m[2], 10);
|
|
18445
|
-
}
|
|
18446
|
-
}
|
|
18447
|
-
} catch {
|
|
18448
|
-
}
|
|
18449
|
-
return null;
|
|
18450
|
-
}
|
|
18451
19248
|
async function runUp(opts = {}) {
|
|
18452
19249
|
let config = readConfig();
|
|
18453
19250
|
if (!config) {
|
|
@@ -18469,8 +19266,19 @@ async function runUp(opts = {}) {
|
|
|
18469
19266
|
config = defaultConfig;
|
|
18470
19267
|
}
|
|
18471
19268
|
resolveAuthMode(config);
|
|
19269
|
+
const startVerdict = await decideStartFromProbes({
|
|
19270
|
+
runnerPort: config.ports.runner,
|
|
19271
|
+
webPort: config.ports.web,
|
|
19272
|
+
dataDir: PG_DATA_DIR
|
|
19273
|
+
});
|
|
19274
|
+
if (!startVerdict.proceed) {
|
|
19275
|
+
logLauncherEvent("refused-kill", `already-running runner=${config.ports.runner}`);
|
|
19276
|
+
throw new AlreadyRunningError(startVerdict.message);
|
|
19277
|
+
}
|
|
18472
19278
|
const known = readPids();
|
|
18473
|
-
const
|
|
19279
|
+
const pgTable2 = await postgresProcessesForDataDir();
|
|
19280
|
+
const ownedPgPids = new Set(pgTable2.owned);
|
|
19281
|
+
const leftovers = await sweepRecordedChildren(known?.children ?? [], ownedPgPids);
|
|
18474
19282
|
if (leftovers.length > 0) {
|
|
18475
19283
|
console.log(
|
|
18476
19284
|
chalk.gray(` Cleaned up ${leftovers.length} process(es) left by the previous session`)
|
|
@@ -18484,16 +19292,21 @@ async function runUp(opts = {}) {
|
|
|
18484
19292
|
for (const root of [...ourPids]) {
|
|
18485
19293
|
for (const rec of walkDescendants(snapshot2, root)) ourPids.add(rec.pid);
|
|
18486
19294
|
}
|
|
18487
|
-
const
|
|
18488
|
-
const strangers = [];
|
|
19295
|
+
const listeners = [];
|
|
18489
19296
|
for (const [name, port] of [
|
|
18490
19297
|
["web", config.ports.web],
|
|
18491
19298
|
["runner", config.ports.runner],
|
|
18492
19299
|
["postgres", config.ports.postgres]
|
|
18493
19300
|
]) {
|
|
18494
19301
|
const pid = await pidListeningOnPort(port);
|
|
18495
|
-
if (pid
|
|
18496
|
-
|
|
19302
|
+
if (pid !== null) listeners.push({ name, port, pid });
|
|
19303
|
+
}
|
|
19304
|
+
const isOurPostmasterPid = (pid) => ownedPgPids.has(pid);
|
|
19305
|
+
const orphans = [];
|
|
19306
|
+
const strangers = [];
|
|
19307
|
+
for (const { name, port, pid } of listeners) {
|
|
19308
|
+
const ours = name === "postgres" ? isOurPostmasterPid(pid) : ourPids.has(pid);
|
|
19309
|
+
if (ours) orphans.push({ name, port, pid });
|
|
18497
19310
|
else strangers.push({ name, port, pid });
|
|
18498
19311
|
}
|
|
18499
19312
|
if (strangers.length > 0) {
|
|
@@ -18508,14 +19321,25 @@ ${lines}
|
|
|
18508
19321
|
}
|
|
18509
19322
|
if (!orphans.some((o) => o.name === "postgres")) {
|
|
18510
19323
|
const pgPid = livePostmasterPid();
|
|
18511
|
-
if (pgPid !== null) {
|
|
18512
|
-
orphans.push({ name: "postgres", port:
|
|
19324
|
+
if (pgPid !== null && isOurPostmasterPid(pgPid)) {
|
|
19325
|
+
orphans.push({ name: "postgres", port: measuredPort(pgPid, listeners), pid: pgPid });
|
|
19326
|
+
} else if (pgPid !== null) {
|
|
19327
|
+
console.log(
|
|
19328
|
+
chalk.yellow(
|
|
19329
|
+
` - postmaster.pid in ${PG_DATA_DIR} names pid ${pgPid}, which has not been seen
|
|
19330
|
+
to exit. Its identity could NOT be confirmed: its start time differs from
|
|
19331
|
+
the one recorded, or it does not run out of that directory, or at least
|
|
19332
|
+
one of those two could not be read. Nothing was stopped. If Postgres then
|
|
19333
|
+
fails to start, check that pid yourself (its executable, its start time,
|
|
19334
|
+
which cluster it serves) and stop it through its owner rather than killing
|
|
19335
|
+
the number.`
|
|
19336
|
+
)
|
|
19337
|
+
);
|
|
18513
19338
|
}
|
|
18514
19339
|
}
|
|
18515
|
-
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
}
|
|
19340
|
+
for (const pid of ownedPgPids) {
|
|
19341
|
+
if (orphans.some((o) => o.pid === pid)) continue;
|
|
19342
|
+
orphans.push({ name: "postgres", port: measuredPort(pid, listeners), pid });
|
|
18519
19343
|
}
|
|
18520
19344
|
if (orphans.length > 0) {
|
|
18521
19345
|
console.log(
|
|
@@ -18524,13 +19348,33 @@ ${lines}
|
|
|
18524
19348
|
)
|
|
18525
19349
|
);
|
|
18526
19350
|
for (const o of orphans) {
|
|
18527
|
-
console.log(
|
|
19351
|
+
console.log(
|
|
19352
|
+
chalk.gray(
|
|
19353
|
+
o.port === null ? ` - ${o.name} for our data dir (pid ${o.pid}, listening on none of our ports)` : ` - ${o.name} on :${o.port} (pid ${o.pid})`
|
|
19354
|
+
)
|
|
19355
|
+
);
|
|
18528
19356
|
}
|
|
18529
19357
|
console.log(chalk.yellow("Cleaning up before starting\u2026"));
|
|
18530
|
-
const
|
|
18531
|
-
const
|
|
18532
|
-
if (
|
|
18533
|
-
await
|
|
19358
|
+
const pgOrphans = orphans.filter((o) => o.name === "postgres");
|
|
19359
|
+
const postmasterPid = pgOrphans[0]?.pid;
|
|
19360
|
+
if (postmasterPid !== void 0) {
|
|
19361
|
+
const confirmedNow = new Set((await postgresProcessesForDataDir()).owned);
|
|
19362
|
+
if (confirmedNow.has(postmasterPid)) await stopOrphanPostgres(postmasterPid);
|
|
19363
|
+
}
|
|
19364
|
+
const leftAlone = [];
|
|
19365
|
+
const unconfirmed = [];
|
|
19366
|
+
for (const pgOrphan of pgOrphans) {
|
|
19367
|
+
const stillOurs = new Set((await postgresProcessesForDataDir()).owned);
|
|
19368
|
+
if (!stillOurs.has(pgOrphan.pid)) {
|
|
19369
|
+
if (!isPidAlive(pgOrphan.pid)) continue;
|
|
19370
|
+
leftAlone.push(pgOrphan.pid);
|
|
19371
|
+
console.log(
|
|
19372
|
+
chalk.yellow(
|
|
19373
|
+
` - postgres pid ${pgOrphan.pid} is alive but can no longer be confirmed as ours; it was NOT stopped`
|
|
19374
|
+
)
|
|
19375
|
+
);
|
|
19376
|
+
continue;
|
|
19377
|
+
}
|
|
18534
19378
|
if (isPidAlive(pgOrphan.pid)) {
|
|
18535
19379
|
try {
|
|
18536
19380
|
process.kill(pgOrphan.pid, "SIGKILL");
|
|
@@ -18546,12 +19390,31 @@ ${lines}
|
|
|
18546
19390
|
);
|
|
18547
19391
|
}
|
|
18548
19392
|
}
|
|
19393
|
+
const tableAvailable = process.platform === "win32";
|
|
19394
|
+
const table = tableAvailable ? await processSnapshotWin() : /* @__PURE__ */ new Map();
|
|
18549
19395
|
for (const o of orphans) {
|
|
18550
19396
|
if (o.name === "postgres") continue;
|
|
19397
|
+
const live = table.get(o.pid);
|
|
19398
|
+
const verdict = !tableAvailable ? { killable: true } : confirmRecordedPid({
|
|
19399
|
+
recorded: recordedRoot(known, o.pid),
|
|
19400
|
+
live: live === void 0 ? void 0 : { pid: live.pid, startedAt: live.startedAt, name: live.name ?? "" },
|
|
19401
|
+
tableRead: table.size > 0,
|
|
19402
|
+
ownedPostgresPids: ownedPgPids
|
|
19403
|
+
});
|
|
19404
|
+
if (!verdict.killable) {
|
|
19405
|
+
if (verdict.code !== "PID_GONE") {
|
|
19406
|
+
unconfirmed.push(o.pid);
|
|
19407
|
+
console.log(chalk.yellow(` - ${o.name} pid ${o.pid} was NOT killed: ${verdict.detail}`));
|
|
19408
|
+
process.stderr.write(`${formatRefusal(verdict)}
|
|
19409
|
+
`);
|
|
19410
|
+
}
|
|
19411
|
+
continue;
|
|
19412
|
+
}
|
|
18551
19413
|
try {
|
|
18552
19414
|
if (process.platform === "win32") {
|
|
18553
|
-
await
|
|
19415
|
+
await killPidTree(o.pid, ownedPgPids, recordedRoot(known, o.pid));
|
|
18554
19416
|
} else {
|
|
19417
|
+
console.log(chalk.gray(` - ${unconfirmedIdentityNotice(o.name, o.pid)}`));
|
|
18555
19418
|
process.kill(o.pid, "SIGKILL");
|
|
18556
19419
|
}
|
|
18557
19420
|
} catch {
|
|
@@ -18562,6 +19425,7 @@ ${lines}
|
|
|
18562
19425
|
while (Date.now() < deadline) {
|
|
18563
19426
|
stillHeld = [];
|
|
18564
19427
|
for (const o of orphans) {
|
|
19428
|
+
if (o.port === null) continue;
|
|
18565
19429
|
const pid = await pidListeningOnPort(o.port);
|
|
18566
19430
|
if (pid !== null) stillHeld.push({ ...o, pid });
|
|
18567
19431
|
}
|
|
@@ -18571,7 +19435,30 @@ ${lines}
|
|
|
18571
19435
|
if (stillHeld.length > 0) {
|
|
18572
19436
|
const list = stillHeld.map((o) => `${o.name}:${o.port}=${o.pid}`).join(", ");
|
|
18573
19437
|
console.log(chalk.yellow(`Some ports still held (likely Windows ghost sockets): ${list}.`));
|
|
19438
|
+
const alsoLeft = [...leftAlone, ...unconfirmed];
|
|
19439
|
+
if (alsoLeft.length > 0) {
|
|
19440
|
+
console.log(
|
|
19441
|
+
chalk.yellow(`Also left running, unconfirmed as ours: ${alsoLeft.join(", ")}.`)
|
|
19442
|
+
);
|
|
19443
|
+
}
|
|
18574
19444
|
console.log(chalk.gray("Will rotate to free neighbours below.\n"));
|
|
19445
|
+
} else if (leftAlone.length > 0 || unconfirmed.length > 0) {
|
|
19446
|
+
if (leftAlone.length > 0) {
|
|
19447
|
+
console.log(
|
|
19448
|
+
chalk.yellow(
|
|
19449
|
+
`Ports are free, but ${leftAlone.length} postgres process(es) were left running (${leftAlone.join(", ")}): they could not be confirmed as ours.
|
|
19450
|
+
`
|
|
19451
|
+
)
|
|
19452
|
+
);
|
|
19453
|
+
}
|
|
19454
|
+
if (unconfirmed.length > 0) {
|
|
19455
|
+
console.log(
|
|
19456
|
+
chalk.yellow(
|
|
19457
|
+
`${unconfirmed.length} recorded process(es) were left running (${unconfirmed.join(", ")}): the pid no longer identifies what we started.
|
|
19458
|
+
`
|
|
19459
|
+
)
|
|
19460
|
+
);
|
|
19461
|
+
}
|
|
18575
19462
|
} else {
|
|
18576
19463
|
console.log(chalk.green("Orphans cleaned up.\n"));
|
|
18577
19464
|
}
|
|
@@ -18581,13 +19468,18 @@ ${lines}
|
|
|
18581
19468
|
const configured = config.ports[name];
|
|
18582
19469
|
if (await isPortBindable(configured)) continue;
|
|
18583
19470
|
const next = await findFreePort(configured + 1);
|
|
18584
|
-
portChanges.push({
|
|
19471
|
+
portChanges.push({
|
|
19472
|
+
name,
|
|
19473
|
+
from: configured,
|
|
19474
|
+
to: next,
|
|
19475
|
+
heldBy: await pidListeningOnPort(configured)
|
|
19476
|
+
});
|
|
18585
19477
|
config.ports[name] = next;
|
|
18586
19478
|
}
|
|
18587
19479
|
if (portChanges.length > 0) {
|
|
18588
19480
|
console.log(chalk.yellow("Configured ports unavailable \u2014 rotating:"));
|
|
18589
|
-
for (const
|
|
18590
|
-
console.log(
|
|
19481
|
+
for (const line2 of formatPortRotation(portChanges)) {
|
|
19482
|
+
console.log(line2.trimStart().startsWith("-") ? chalk.gray(line2) : chalk.yellow(line2));
|
|
18591
19483
|
}
|
|
18592
19484
|
writeConfig(config);
|
|
18593
19485
|
console.log(chalk.gray(" Updated ~/.nodalai/config.json.\n"));
|
|
@@ -18610,9 +19502,10 @@ ${lines}
|
|
|
18610
19502
|
runner: null,
|
|
18611
19503
|
web: null
|
|
18612
19504
|
};
|
|
18613
|
-
const shutdown = async () => {
|
|
19505
|
+
const shutdown = async (cause = "signal") => {
|
|
18614
19506
|
if (shuttingDown) return;
|
|
18615
19507
|
shuttingDown = true;
|
|
19508
|
+
logLauncherEvent("shutdown", `cause=${cause}`);
|
|
18616
19509
|
console.log("\n" + chalk.yellow(" Stopping Nodal-Agents\u2026"));
|
|
18617
19510
|
const recorded = readPids()?.children ?? [];
|
|
18618
19511
|
await Promise.allSettled(
|
|
@@ -18627,8 +19520,8 @@ ${lines}
|
|
|
18627
19520
|
console.log(chalk.green(" Stopped. Goodbye!"));
|
|
18628
19521
|
process.exit(0);
|
|
18629
19522
|
};
|
|
18630
|
-
process.on("SIGINT", () => void shutdown());
|
|
18631
|
-
process.on("SIGTERM", () => void shutdown());
|
|
19523
|
+
process.on("SIGINT", () => void shutdown("SIGINT"));
|
|
19524
|
+
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
18632
19525
|
let effectivePgPassword = pgPassword;
|
|
18633
19526
|
if (pendingRotation) {
|
|
18634
19527
|
writeConfig({ ...config, postgresPassword: pendingRotation });
|
|
@@ -18748,7 +19641,7 @@ ${lines}
|
|
|
18748
19641
|
const installed = getInstalledVersion2();
|
|
18749
19642
|
const latest = await Promise.race([
|
|
18750
19643
|
getLatestVersion2(),
|
|
18751
|
-
new Promise((
|
|
19644
|
+
new Promise((resolve4) => setTimeout(() => resolve4(null), 3e3))
|
|
18752
19645
|
]);
|
|
18753
19646
|
if (latest !== null && isNewerVersion2(latest, installed)) {
|
|
18754
19647
|
console.log(chalk.cyan(` \u2139 v${latest} available \u2014 run \`nodal-agents update\``));
|
|
@@ -18763,14 +19656,20 @@ ${lines}
|
|
|
18763
19656
|
}
|
|
18764
19657
|
}
|
|
18765
19658
|
console.log("");
|
|
19659
|
+
logLauncherEvent(
|
|
19660
|
+
"started",
|
|
19661
|
+
`web=${webUrl} runner=${runnerUrl} mode=${opts.detach ? "detached" : "foreground"}`
|
|
19662
|
+
);
|
|
18766
19663
|
console.log(chalk.bold.green(` Nodal-Agents ready at ${webUrl}`));
|
|
18767
19664
|
if (config.bind === "lan") {
|
|
18768
19665
|
console.log(chalk.cyan(` LAN mode \u2014 sign up at ${webUrl}/login`));
|
|
18769
19666
|
}
|
|
18770
19667
|
if (opts.detach) {
|
|
19668
|
+
logLauncherEvent("detached", `web=${webUrl} runner=${runnerUrl}`);
|
|
18771
19669
|
console.log(chalk.gray(" Detached \u2014 the terminal is yours again."));
|
|
18772
19670
|
console.log(chalk.gray(" nodal-agents logs runner follow a service"));
|
|
18773
19671
|
console.log(chalk.gray(" nodal-agents down stop everything"));
|
|
19672
|
+
console.log(chalk.gray(` ${LAUNCHER_LOG} what the launcher saw`));
|
|
18774
19673
|
console.log("");
|
|
18775
19674
|
process.exit(0);
|
|
18776
19675
|
}
|
|
@@ -18780,6 +19679,7 @@ ${lines}
|
|
|
18780
19679
|
probe: () => probeRunnerHealth(runnerUrl),
|
|
18781
19680
|
onTransition: (state, detail) => {
|
|
18782
19681
|
const at = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
19682
|
+
logLauncherEvent(state === "healthy" ? "recovered" : "degraded", `state=${state} ${detail}`);
|
|
18783
19683
|
if (state === "healthy") {
|
|
18784
19684
|
console.log(chalk.green(`
|
|
18785
19685
|
[${at}] Recovered \u2014 ${detail}.`));
|
|
@@ -18800,9 +19700,13 @@ ${lines}
|
|
|
18800
19700
|
);
|
|
18801
19701
|
}
|
|
18802
19702
|
});
|
|
18803
|
-
await Promise.race([
|
|
19703
|
+
const exited = await Promise.race([
|
|
19704
|
+
runnerProcess.then(() => "runner").catch(() => "runner"),
|
|
19705
|
+
webProcess.then(() => "web").catch(() => "web")
|
|
19706
|
+
]);
|
|
19707
|
+
logLauncherEvent("child-exited", `service=${exited}`);
|
|
18804
19708
|
watchdog.stop();
|
|
18805
|
-
await shutdown();
|
|
19709
|
+
await shutdown(`${exited} exited`);
|
|
18806
19710
|
}
|
|
18807
19711
|
var init_up = __esm({
|
|
18808
19712
|
"src/commands/up.ts"() {
|
|
@@ -18812,6 +19716,10 @@ var init_up = __esm({
|
|
|
18812
19716
|
init_seed();
|
|
18813
19717
|
init_env();
|
|
18814
19718
|
init_ports();
|
|
19719
|
+
init_orphans();
|
|
19720
|
+
init_already_running();
|
|
19721
|
+
init_pid_confirm();
|
|
19722
|
+
init_launcher_log();
|
|
18815
19723
|
init_processes();
|
|
18816
19724
|
init_src4();
|
|
18817
19725
|
init_watchdog();
|
|
@@ -19099,17 +20007,49 @@ var init_init = __esm({
|
|
|
19099
20007
|
// src/commands/down.ts
|
|
19100
20008
|
var down_exports = {};
|
|
19101
20009
|
__export(down_exports, {
|
|
19102
|
-
runDown: () => runDown
|
|
20010
|
+
runDown: () => runDown,
|
|
20011
|
+
stopWithinBudget: () => stopWithinBudget
|
|
19103
20012
|
});
|
|
19104
20013
|
import chalk3 from "chalk";
|
|
19105
|
-
import { existsSync as
|
|
19106
|
-
import { join as
|
|
19107
|
-
|
|
20014
|
+
import { existsSync as existsSync10 } from "fs";
|
|
20015
|
+
import { join as join10 } from "path";
|
|
20016
|
+
function liveOf(snapshot2, pid) {
|
|
20017
|
+
const rec = snapshot2.get(pid);
|
|
20018
|
+
return rec === void 0 ? void 0 : { pid: rec.pid, startedAt: rec.startedAt, name: rec.name ?? "" };
|
|
20019
|
+
}
|
|
20020
|
+
async function killPid(pid, label, ctx) {
|
|
19108
20021
|
if (!isPidAlive(pid)) {
|
|
19109
20022
|
console.log(chalk3.gray(` ${label} (pid ${pid}) was already stopped`));
|
|
19110
20023
|
return false;
|
|
19111
20024
|
}
|
|
19112
|
-
|
|
20025
|
+
if (!ctx.tableAvailable) {
|
|
20026
|
+
console.log(chalk3.gray(` ${unconfirmedIdentityNotice(label, pid)}`));
|
|
20027
|
+
await killPidTree(pid, ctx.ownedPostgresPids);
|
|
20028
|
+
if (isPidAlive(pid)) {
|
|
20029
|
+
console.log(chalk3.red(` ${label} (pid ${pid}) is STILL RUNNING after SIGTERM then SIGKILL`));
|
|
20030
|
+
return false;
|
|
20031
|
+
}
|
|
20032
|
+
console.log(chalk3.green(` Stopped ${label} (pid ${pid})`));
|
|
20033
|
+
return true;
|
|
20034
|
+
}
|
|
20035
|
+
const verdict = confirmRecordedPid({
|
|
20036
|
+
recorded: recordedRoot(ctx.pids, pid),
|
|
20037
|
+
live: liveOf(ctx.snapshot, pid),
|
|
20038
|
+
tableRead: ctx.snapshot.size > 0,
|
|
20039
|
+
ownedPostgresPids: ctx.ownedPostgresPids
|
|
20040
|
+
});
|
|
20041
|
+
if (!verdict.killable) {
|
|
20042
|
+
console.log(
|
|
20043
|
+
chalk3.yellow(
|
|
20044
|
+
` ${label} (pid ${pid}) was NOT stopped \u2014 ${verdict.detail}.
|
|
20045
|
+
Nodal-Agents does not kill a pid it cannot identify. Nothing was signalled.`
|
|
20046
|
+
)
|
|
20047
|
+
);
|
|
20048
|
+
process.stderr.write(`${formatRefusal(verdict)}
|
|
20049
|
+
`);
|
|
20050
|
+
return false;
|
|
20051
|
+
}
|
|
20052
|
+
await killPidTree(pid, ctx.ownedPostgresPids, recordedRoot(ctx.pids, pid));
|
|
19113
20053
|
if (isPidAlive(pid)) {
|
|
19114
20054
|
console.log(chalk3.red(` ${label} (pid ${pid}) is STILL RUNNING after SIGTERM then SIGKILL`));
|
|
19115
20055
|
return false;
|
|
@@ -19117,10 +20057,30 @@ async function killPid(pid, label) {
|
|
|
19117
20057
|
console.log(chalk3.green(` Stopped ${label} (pid ${pid})`));
|
|
19118
20058
|
return true;
|
|
19119
20059
|
}
|
|
19120
|
-
async function
|
|
19121
|
-
|
|
19122
|
-
|
|
20060
|
+
async function stopWithinBudget(pg, budgetMs) {
|
|
20061
|
+
return await Promise.race([
|
|
20062
|
+
pg.stop().then(() => true).catch(() => true),
|
|
20063
|
+
new Promise((resolve4) => setTimeout(() => resolve4(false), budgetMs))
|
|
20064
|
+
]);
|
|
20065
|
+
}
|
|
20066
|
+
async function stopPostgresGracefully(ctx) {
|
|
20067
|
+
const pidFile = join10(PG_DATA_DIR, "postmaster.pid");
|
|
20068
|
+
if (!existsSync10(pidFile)) return false;
|
|
19123
20069
|
const pgPid = readPostmasterPid(PG_DATA_DIR);
|
|
20070
|
+
const confirmed = pgPid !== null && ctx.ownedPostgresPids.has(pgPid);
|
|
20071
|
+
const refused = pgPid !== null && !confirmed && ctx.postgresReadingWorked;
|
|
20072
|
+
if (refused) {
|
|
20073
|
+
console.log(
|
|
20074
|
+
chalk3.yellow(
|
|
20075
|
+
` postgres (pid ${pgPid}) was NOT stopped \u2014 postmaster.pid names it, but a fresh
|
|
20076
|
+
reading could not confirm it belongs to ${PG_DATA_DIR}.
|
|
20077
|
+
Nothing was signalled. Check that pid yourself before touching it.`
|
|
20078
|
+
)
|
|
20079
|
+
);
|
|
20080
|
+
process.stderr.write(`KILL_REFUSED code=FOREIGN_POSTGRES pid=${pgPid} lockfile=${pidFile}
|
|
20081
|
+
`);
|
|
20082
|
+
return false;
|
|
20083
|
+
}
|
|
19124
20084
|
try {
|
|
19125
20085
|
const EmbeddedPostgres = (await import("embedded-postgres")).default;
|
|
19126
20086
|
const pg = new EmbeddedPostgres({
|
|
@@ -19136,7 +20096,15 @@ async function stopPostgresGracefully() {
|
|
|
19136
20096
|
onLog: () => {
|
|
19137
20097
|
}
|
|
19138
20098
|
});
|
|
19139
|
-
await pg
|
|
20099
|
+
if (!await stopWithinBudget(pg, GRACEFUL_STOP_BUDGET_MS)) {
|
|
20100
|
+
console.log(
|
|
20101
|
+
chalk3.yellow(
|
|
20102
|
+
` postgres (pid ${pgPid ?? "unknown"}) did not finish a graceful stop within ${GRACEFUL_STOP_BUDGET_MS / 1e3}s.
|
|
20103
|
+
A postmaster that is recovering from a crashed backend can take longer than
|
|
20104
|
+
that. Nothing else was signalled; what it is doing now is reported below.`
|
|
20105
|
+
)
|
|
20106
|
+
);
|
|
20107
|
+
}
|
|
19140
20108
|
const pgGone = pgPid === null || await waitForPidDead(pgPid, 15e3);
|
|
19141
20109
|
if (!pgGone) {
|
|
19142
20110
|
const killCmd = process.platform === "win32" ? `powershell Stop-Process -Id ${pgPid} -Force` : `kill -9 ${pgPid}`;
|
|
@@ -19144,7 +20112,9 @@ async function stopPostgresGracefully() {
|
|
|
19144
20112
|
chalk3.red(
|
|
19145
20113
|
` postgres (pid ${pgPid}) is STILL RUNNING after a graceful stop
|
|
19146
20114
|
It holds the shared-memory block for the data dir, so the next \`up\` will fail.
|
|
19147
|
-
Fix: ${killCmd}`
|
|
20115
|
+
` + (confirmed ? ` Fix: ${killCmd}` : ` Its identity could NOT be confirmed, so no kill command is suggested:
|
|
20116
|
+
check that pid yourself (its executable, its start time, which cluster
|
|
20117
|
+
it serves) and stop it through its owner.`)
|
|
19148
20118
|
)
|
|
19149
20119
|
);
|
|
19150
20120
|
return false;
|
|
@@ -19158,15 +20128,23 @@ async function stopPostgresGracefully() {
|
|
|
19158
20128
|
}
|
|
19159
20129
|
async function runDown() {
|
|
19160
20130
|
const pids = readPids();
|
|
20131
|
+
const pgReading = await postgresProcessesForDataDir();
|
|
20132
|
+
const ctx = {
|
|
20133
|
+
pids,
|
|
20134
|
+
tableAvailable: process.platform === "win32",
|
|
20135
|
+
snapshot: await processSnapshotWin(),
|
|
20136
|
+
ownedPostgresPids: new Set(pgReading.owned),
|
|
20137
|
+
postgresReadingWorked: pgReading.read
|
|
20138
|
+
};
|
|
19161
20139
|
let stopped = 0;
|
|
19162
|
-
if (pids?.runner) stopped += await killPid(pids.runner, "runner") ? 1 : 0;
|
|
19163
|
-
if (pids?.web) stopped += await killPid(pids.web, "web") ? 1 : 0;
|
|
19164
|
-
const swept = await sweepRecordedChildren(pids?.children ?? []);
|
|
20140
|
+
if (pids?.runner) stopped += await killPid(pids.runner, "runner", ctx) ? 1 : 0;
|
|
20141
|
+
if (pids?.web) stopped += await killPid(pids.web, "web", ctx) ? 1 : 0;
|
|
20142
|
+
const swept = await sweepRecordedChildren(pids?.children ?? [], ctx.ownedPostgresPids);
|
|
19165
20143
|
if (swept.length > 0) {
|
|
19166
20144
|
console.log(chalk3.green(` Stopped ${swept.length} background worker(s) left behind`));
|
|
19167
20145
|
stopped += swept.length;
|
|
19168
20146
|
}
|
|
19169
|
-
if (await stopPostgresGracefully()) stopped++;
|
|
20147
|
+
if (await stopPostgresGracefully(ctx)) stopped++;
|
|
19170
20148
|
clearPids();
|
|
19171
20149
|
if (stopped === 0) {
|
|
19172
20150
|
console.log(chalk3.yellow("No running Nodal-Agents processes found."));
|
|
@@ -19174,12 +20152,15 @@ async function runDown() {
|
|
|
19174
20152
|
}
|
|
19175
20153
|
console.log(chalk3.green("\n Nodal-Agents stopped."));
|
|
19176
20154
|
}
|
|
20155
|
+
var GRACEFUL_STOP_BUDGET_MS;
|
|
19177
20156
|
var init_down = __esm({
|
|
19178
20157
|
"src/commands/down.ts"() {
|
|
19179
20158
|
"use strict";
|
|
19180
20159
|
init_processes();
|
|
19181
20160
|
init_config();
|
|
19182
20161
|
init_postgres();
|
|
20162
|
+
init_pid_confirm();
|
|
20163
|
+
GRACEFUL_STOP_BUDGET_MS = 6e4;
|
|
19183
20164
|
}
|
|
19184
20165
|
});
|
|
19185
20166
|
|
|
@@ -19189,8 +20170,8 @@ __export(logs_exports, {
|
|
|
19189
20170
|
runLogs: () => runLogs
|
|
19190
20171
|
});
|
|
19191
20172
|
import chalk4 from "chalk";
|
|
19192
|
-
import { existsSync as
|
|
19193
|
-
import { join as
|
|
20173
|
+
import { existsSync as existsSync11, createReadStream, watch, statSync as statSync3 } from "fs";
|
|
20174
|
+
import { join as join11 } from "path";
|
|
19194
20175
|
function isServiceName(s) {
|
|
19195
20176
|
return VALID_SERVICES.includes(s);
|
|
19196
20177
|
}
|
|
@@ -19202,34 +20183,34 @@ async function runLogs(service) {
|
|
|
19202
20183
|
}
|
|
19203
20184
|
const services = target === "all" ? VALID_SERVICES : [target];
|
|
19204
20185
|
for (const svc of services) {
|
|
19205
|
-
const logFile =
|
|
19206
|
-
if (!
|
|
20186
|
+
const logFile = join11(LOG_DIR, `${svc}.log`);
|
|
20187
|
+
if (!existsSync11(logFile)) {
|
|
19207
20188
|
console.log(chalk4.gray(` [${svc}] No log file yet at ${logFile}`));
|
|
19208
20189
|
continue;
|
|
19209
20190
|
}
|
|
19210
20191
|
console.log(chalk4.bold(`
|
|
19211
20192
|
--- ${svc} ---`));
|
|
19212
|
-
await new Promise((
|
|
20193
|
+
await new Promise((resolve4, reject) => {
|
|
19213
20194
|
const stream = createReadStream(logFile, { encoding: "utf-8" });
|
|
19214
20195
|
stream.on("data", (chunk) => process.stdout.write(chunk));
|
|
19215
|
-
stream.on("end",
|
|
20196
|
+
stream.on("end", resolve4);
|
|
19216
20197
|
stream.on("error", reject);
|
|
19217
20198
|
});
|
|
19218
20199
|
}
|
|
19219
20200
|
if (target !== "all") {
|
|
19220
|
-
const logFile =
|
|
19221
|
-
if (!
|
|
20201
|
+
const logFile = join11(LOG_DIR, `${target}.log`);
|
|
20202
|
+
if (!existsSync11(logFile)) {
|
|
19222
20203
|
console.log(chalk4.yellow("Waiting for log file to be created\u2026"));
|
|
19223
20204
|
}
|
|
19224
20205
|
console.log(chalk4.gray("\nFollowing log (Ctrl+C to stop)...\n"));
|
|
19225
20206
|
let fileSize = 0;
|
|
19226
20207
|
try {
|
|
19227
|
-
fileSize =
|
|
20208
|
+
fileSize = statSync3(logFile).size;
|
|
19228
20209
|
} catch {
|
|
19229
20210
|
}
|
|
19230
20211
|
const watcher = watch(logFile, () => {
|
|
19231
20212
|
try {
|
|
19232
|
-
const newSize =
|
|
20213
|
+
const newSize = statSync3(logFile).size;
|
|
19233
20214
|
if (newSize > fileSize) {
|
|
19234
20215
|
const stream = createReadStream(logFile, { start: fileSize, encoding: "utf-8" });
|
|
19235
20216
|
stream.on("data", (chunk) => process.stdout.write(chunk));
|
|
@@ -19254,10 +20235,10 @@ var init_logs = __esm({
|
|
|
19254
20235
|
|
|
19255
20236
|
// ../../packages/checkpoints/src/checkpoints.ts
|
|
19256
20237
|
import { execFile, spawn } from "child_process";
|
|
19257
|
-
import { createHash as
|
|
20238
|
+
import { createHash as createHash4, randomBytes as randomBytes6 } from "crypto";
|
|
19258
20239
|
import { mkdir, rm, writeFile } from "fs/promises";
|
|
19259
|
-
import { existsSync as
|
|
19260
|
-
import { join as
|
|
20240
|
+
import { existsSync as existsSync12 } from "fs";
|
|
20241
|
+
import { join as join12 } from "path";
|
|
19261
20242
|
import { promisify } from "util";
|
|
19262
20243
|
function workspaceKey(workspace) {
|
|
19263
20244
|
let norm = workspace;
|
|
@@ -19265,18 +20246,18 @@ function workspaceKey(workspace) {
|
|
|
19265
20246
|
norm = norm.toLowerCase().replace(/\//g, "\\");
|
|
19266
20247
|
}
|
|
19267
20248
|
norm = norm.replace(/[\\/]+$/, "");
|
|
19268
|
-
return
|
|
20249
|
+
return createHash4("sha256").update(norm).digest("hex").slice(0, 16);
|
|
19269
20250
|
}
|
|
19270
20251
|
function gitEnv(store, workspace, indexFile) {
|
|
19271
20252
|
const key = workspaceKey(workspace);
|
|
19272
20253
|
return {
|
|
19273
20254
|
...process.env,
|
|
19274
|
-
GIT_DIR:
|
|
20255
|
+
GIT_DIR: join12(store, "store"),
|
|
19275
20256
|
GIT_WORK_TREE: workspace,
|
|
19276
20257
|
// A per-workspace index: two workspaces snapshotting at once must not
|
|
19277
20258
|
// stomp on each other's staging area. A READ (diffFile) brings its own
|
|
19278
20259
|
// temporary index instead — see diffFile — so it never touches this one.
|
|
19279
|
-
GIT_INDEX_FILE: indexFile ??
|
|
20260
|
+
GIT_INDEX_FILE: indexFile ?? join12(store, "indexes", key),
|
|
19280
20261
|
// A checkpoint is machinery, not authorship. Identity is fixed so it can
|
|
19281
20262
|
// never depend on — or leak — the owner's git config.
|
|
19282
20263
|
GIT_AUTHOR_NAME: "Nodal checkpoints",
|
|
@@ -19284,8 +20265,8 @@ function gitEnv(store, workspace, indexFile) {
|
|
|
19284
20265
|
GIT_COMMITTER_NAME: "Nodal checkpoints",
|
|
19285
20266
|
GIT_COMMITTER_EMAIL: "checkpoints@nodal.local",
|
|
19286
20267
|
// The owner's global config must not change what we store or how.
|
|
19287
|
-
GIT_CONFIG_GLOBAL:
|
|
19288
|
-
GIT_CONFIG_SYSTEM:
|
|
20268
|
+
GIT_CONFIG_GLOBAL: join12(store, "gitconfig"),
|
|
20269
|
+
GIT_CONFIG_SYSTEM: join12(store, "gitconfig")
|
|
19289
20270
|
};
|
|
19290
20271
|
}
|
|
19291
20272
|
async function git(store, workspace, args, indexFile) {
|
|
@@ -19297,17 +20278,17 @@ async function git(store, workspace, args, indexFile) {
|
|
|
19297
20278
|
return stdout.trim();
|
|
19298
20279
|
}
|
|
19299
20280
|
async function ensureStore(store) {
|
|
19300
|
-
const gitDir =
|
|
19301
|
-
await mkdir(
|
|
19302
|
-
await writeFile(
|
|
19303
|
-
if (!
|
|
20281
|
+
const gitDir = join12(store, "store");
|
|
20282
|
+
await mkdir(join12(store, "indexes"), { recursive: true });
|
|
20283
|
+
await writeFile(join12(store, "gitconfig"), "", { flag: "a" });
|
|
20284
|
+
if (!existsSync12(join12(gitDir, "HEAD"))) {
|
|
19304
20285
|
await mkdir(gitDir, { recursive: true });
|
|
19305
20286
|
await run("git", ["init", "--bare", "--quiet", gitDir], {
|
|
19306
20287
|
timeout: GIT_TIMEOUT_MS,
|
|
19307
20288
|
windowsHide: true
|
|
19308
20289
|
});
|
|
19309
|
-
await mkdir(
|
|
19310
|
-
await writeFile(
|
|
20290
|
+
await mkdir(join12(gitDir, "info"), { recursive: true });
|
|
20291
|
+
await writeFile(join12(gitDir, "info", "exclude"), EXCLUDES.join("\n") + "\n", "utf-8");
|
|
19311
20292
|
}
|
|
19312
20293
|
}
|
|
19313
20294
|
async function snapshot(store, workspace, label) {
|
|
@@ -19333,7 +20314,7 @@ async function snapshot(store, workspace, label) {
|
|
|
19333
20314
|
return { sha, workspace, at, label };
|
|
19334
20315
|
}
|
|
19335
20316
|
async function listCheckpoints(store, workspace, limit = 20) {
|
|
19336
|
-
if (!
|
|
20317
|
+
if (!existsSync12(join12(store, "store", "HEAD"))) return [];
|
|
19337
20318
|
const ref = `refs/nodal/${workspaceKey(workspace)}`;
|
|
19338
20319
|
const out = await git(store, workspace, [
|
|
19339
20320
|
"log",
|
|
@@ -19376,9 +20357,9 @@ var init_checkpoints = __esm({
|
|
|
19376
20357
|
|
|
19377
20358
|
// ../../packages/checkpoints/src/root.ts
|
|
19378
20359
|
import { homedir as homedir3 } from "os";
|
|
19379
|
-
import { join as
|
|
20360
|
+
import { join as join13 } from "path";
|
|
19380
20361
|
function checkpointsRoot() {
|
|
19381
|
-
return process.env["NODALAI_CHECKPOINTS_ROOT"] ??
|
|
20362
|
+
return process.env["NODALAI_CHECKPOINTS_ROOT"] ?? join13(homedir3(), ".nodalai", "checkpoints");
|
|
19382
20363
|
}
|
|
19383
20364
|
var init_root = __esm({
|
|
19384
20365
|
"../../packages/checkpoints/src/root.ts"() {
|
|
@@ -19402,7 +20383,7 @@ __export(checkpoints_exports, {
|
|
|
19402
20383
|
runCheckpointsRestore: () => runCheckpointsRestore
|
|
19403
20384
|
});
|
|
19404
20385
|
import chalk5 from "chalk";
|
|
19405
|
-
import { resolve as
|
|
20386
|
+
import { resolve as resolve3 } from "path";
|
|
19406
20387
|
function ago(iso2) {
|
|
19407
20388
|
const ms = Date.now() - new Date(iso2).getTime();
|
|
19408
20389
|
const min2 = Math.round(ms / 6e4);
|
|
@@ -19413,7 +20394,7 @@ function ago(iso2) {
|
|
|
19413
20394
|
return `${Math.round(h / 24)} d ago`;
|
|
19414
20395
|
}
|
|
19415
20396
|
async function runCheckpointsList(workspace) {
|
|
19416
|
-
const ws =
|
|
20397
|
+
const ws = resolve3(workspace ?? process.cwd());
|
|
19417
20398
|
const list = await listCheckpoints(checkpointsRoot(), ws);
|
|
19418
20399
|
if (list.length === 0) {
|
|
19419
20400
|
console.log(chalk5.yellow(`No checkpoints for ${ws}`));
|
|
@@ -19438,7 +20419,7 @@ Checkpoints for ${ws}
|
|
|
19438
20419
|
`));
|
|
19439
20420
|
}
|
|
19440
20421
|
async function runCheckpointsRestore(sha, workspace) {
|
|
19441
|
-
const ws =
|
|
20422
|
+
const ws = resolve3(workspace ?? process.cwd());
|
|
19442
20423
|
const list = await listCheckpoints(checkpointsRoot(), ws, 200);
|
|
19443
20424
|
const match = list.find((c) => c.sha.startsWith(sha));
|
|
19444
20425
|
if (!match) {
|
|
@@ -23354,7 +24335,7 @@ var init_protocol = __esm({
|
|
|
23354
24335
|
return;
|
|
23355
24336
|
}
|
|
23356
24337
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
23357
|
-
await new Promise((
|
|
24338
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
23358
24339
|
options?.signal?.throwIfAborted();
|
|
23359
24340
|
}
|
|
23360
24341
|
} catch (error) {
|
|
@@ -23371,7 +24352,7 @@ var init_protocol = __esm({
|
|
|
23371
24352
|
*/
|
|
23372
24353
|
request(request, resultSchema, options) {
|
|
23373
24354
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
23374
|
-
return new Promise((
|
|
24355
|
+
return new Promise((resolve4, reject) => {
|
|
23375
24356
|
const earlyReject = (error) => {
|
|
23376
24357
|
reject(error);
|
|
23377
24358
|
};
|
|
@@ -23449,7 +24430,7 @@ var init_protocol = __esm({
|
|
|
23449
24430
|
if (!parseResult.success) {
|
|
23450
24431
|
reject(parseResult.error);
|
|
23451
24432
|
} else {
|
|
23452
|
-
|
|
24433
|
+
resolve4(parseResult.data);
|
|
23453
24434
|
}
|
|
23454
24435
|
} catch (error) {
|
|
23455
24436
|
reject(error);
|
|
@@ -23710,12 +24691,12 @@ var init_protocol = __esm({
|
|
|
23710
24691
|
}
|
|
23711
24692
|
} catch {
|
|
23712
24693
|
}
|
|
23713
|
-
return new Promise((
|
|
24694
|
+
return new Promise((resolve4, reject) => {
|
|
23714
24695
|
if (signal.aborted) {
|
|
23715
24696
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
23716
24697
|
return;
|
|
23717
24698
|
}
|
|
23718
|
-
const timeoutId = setTimeout(
|
|
24699
|
+
const timeoutId = setTimeout(resolve4, interval2);
|
|
23719
24700
|
signal.addEventListener("abort", () => {
|
|
23720
24701
|
clearTimeout(timeoutId);
|
|
23721
24702
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -26742,7 +27723,7 @@ var require_compile = __commonJS({
|
|
|
26742
27723
|
const schOrFunc = root.refs[ref];
|
|
26743
27724
|
if (schOrFunc)
|
|
26744
27725
|
return schOrFunc;
|
|
26745
|
-
let _sch =
|
|
27726
|
+
let _sch = resolve4.call(this, root, ref);
|
|
26746
27727
|
if (_sch === void 0) {
|
|
26747
27728
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
26748
27729
|
const { schemaId } = this.opts;
|
|
@@ -26769,7 +27750,7 @@ var require_compile = __commonJS({
|
|
|
26769
27750
|
function sameSchemaEnv(s1, s2) {
|
|
26770
27751
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
26771
27752
|
}
|
|
26772
|
-
function
|
|
27753
|
+
function resolve4(root, ref) {
|
|
26773
27754
|
let sch;
|
|
26774
27755
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
26775
27756
|
ref = sch;
|
|
@@ -26861,15 +27842,33 @@ var require_data = __commonJS({
|
|
|
26861
27842
|
}
|
|
26862
27843
|
});
|
|
26863
27844
|
|
|
26864
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
27845
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js
|
|
26865
27846
|
var require_utils = __commonJS({
|
|
26866
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
27847
|
+
"../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/utils.js"(exports, module) {
|
|
26867
27848
|
"use strict";
|
|
26868
27849
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
26869
27850
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
26870
27851
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
26871
27852
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
26872
|
-
var isPathCharacter = RegExp.prototype.test.bind(/^[
|
|
27853
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
27854
|
+
var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
|
|
27855
|
+
var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
|
|
27856
|
+
var BYTE_HEX = new Array(256);
|
|
27857
|
+
{
|
|
27858
|
+
const HEX_DIGITS = "0123456789ABCDEF";
|
|
27859
|
+
for (let i = 0; i < 256; i++) {
|
|
27860
|
+
BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
|
|
27861
|
+
}
|
|
27862
|
+
}
|
|
27863
|
+
function percentEncodeNonAscii(cp) {
|
|
27864
|
+
if (cp < 2048) {
|
|
27865
|
+
return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
|
|
27866
|
+
}
|
|
27867
|
+
if (cp < 65536) {
|
|
27868
|
+
return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
27869
|
+
}
|
|
27870
|
+
return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
|
|
27871
|
+
}
|
|
26873
27872
|
function stringArrayToHexStripped(input) {
|
|
26874
27873
|
let acc = "";
|
|
26875
27874
|
let code = 0;
|
|
@@ -26894,91 +27893,105 @@ var require_utils = __commonJS({
|
|
|
26894
27893
|
}
|
|
26895
27894
|
return acc;
|
|
26896
27895
|
}
|
|
27896
|
+
var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
|
|
27897
|
+
var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
|
|
27898
|
+
var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
|
|
26897
27899
|
var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
|
|
26898
|
-
function
|
|
26899
|
-
|
|
26900
|
-
|
|
26901
|
-
|
|
26902
|
-
|
|
26903
|
-
|
|
26904
|
-
|
|
26905
|
-
if (hex !== "") {
|
|
26906
|
-
address.push(hex);
|
|
26907
|
-
} else {
|
|
26908
|
-
output.error = true;
|
|
26909
|
-
return false;
|
|
27900
|
+
function isZoneIdentifier(zone) {
|
|
27901
|
+
if (zone.length === 0) return false;
|
|
27902
|
+
for (let i = 0; i < zone.length; i++) {
|
|
27903
|
+
if (isZoneCharacter(zone[i])) continue;
|
|
27904
|
+
if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
|
|
27905
|
+
i += 2;
|
|
27906
|
+
continue;
|
|
26910
27907
|
}
|
|
26911
|
-
|
|
27908
|
+
return false;
|
|
26912
27909
|
}
|
|
26913
27910
|
return true;
|
|
26914
27911
|
}
|
|
26915
|
-
function
|
|
26916
|
-
let
|
|
26917
|
-
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
let
|
|
26921
|
-
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
|
|
26925
|
-
|
|
26926
|
-
|
|
26927
|
-
}
|
|
26928
|
-
if (cursor === ":") {
|
|
26929
|
-
if (endipv6Encountered === true) {
|
|
26930
|
-
endIpv6 = true;
|
|
26931
|
-
}
|
|
26932
|
-
if (!consume(buffer2, address, output)) {
|
|
26933
|
-
break;
|
|
26934
|
-
}
|
|
26935
|
-
if (++tokenCount > 7) {
|
|
26936
|
-
output.error = true;
|
|
26937
|
-
break;
|
|
26938
|
-
}
|
|
26939
|
-
if (i > 0 && input[i - 1] === ":") {
|
|
26940
|
-
endipv6Encountered = true;
|
|
27912
|
+
function compressIPv6ZeroRun(hextets) {
|
|
27913
|
+
let bestStart = -1;
|
|
27914
|
+
let bestLength = 0;
|
|
27915
|
+
let runStart = -1;
|
|
27916
|
+
let runLength = 0;
|
|
27917
|
+
for (let i = 0; i < hextets.length; i++) {
|
|
27918
|
+
if (hextets[i] === "0") {
|
|
27919
|
+
if (runStart === -1) runStart = i;
|
|
27920
|
+
runLength++;
|
|
27921
|
+
if (runLength > bestLength) {
|
|
27922
|
+
bestLength = runLength;
|
|
27923
|
+
bestStart = runStart;
|
|
26941
27924
|
}
|
|
26942
|
-
address.push(":");
|
|
26943
|
-
continue;
|
|
26944
|
-
} else if (cursor === "%") {
|
|
26945
|
-
if (!consume(buffer2, address, output)) {
|
|
26946
|
-
break;
|
|
26947
|
-
}
|
|
26948
|
-
consume = consumeIsZone;
|
|
26949
27925
|
} else {
|
|
26950
|
-
|
|
27926
|
+
runStart = -1;
|
|
27927
|
+
runLength = 0;
|
|
27928
|
+
}
|
|
27929
|
+
}
|
|
27930
|
+
if (bestLength < 2) return hextets.join(":");
|
|
27931
|
+
const head = hextets.slice(0, bestStart).join(":");
|
|
27932
|
+
const tail = hextets.slice(bestStart + bestLength).join(":");
|
|
27933
|
+
return head + "::" + tail;
|
|
27934
|
+
}
|
|
27935
|
+
function normalizeIPv6Address(input) {
|
|
27936
|
+
const compression = input.indexOf("::");
|
|
27937
|
+
if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
|
|
27938
|
+
const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
|
|
27939
|
+
const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
|
|
27940
|
+
if (compression !== -1) {
|
|
27941
|
+
if (left.length === 1 && left[0] === "") left.length = 0;
|
|
27942
|
+
if (right.length === 1 && right[0] === "") right.length = 0;
|
|
27943
|
+
}
|
|
27944
|
+
const parts = left.concat(right);
|
|
27945
|
+
let hextetCount = 0;
|
|
27946
|
+
for (let i = 0; i < parts.length; i++) {
|
|
27947
|
+
const part = parts[i];
|
|
27948
|
+
if (part === "") return void 0;
|
|
27949
|
+
if (part.indexOf(".") !== -1) {
|
|
27950
|
+
if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
|
|
27951
|
+
hextetCount += 2;
|
|
26951
27952
|
continue;
|
|
26952
27953
|
}
|
|
27954
|
+
if (!isHextet(part)) return void 0;
|
|
27955
|
+
parts[i] = parseInt(part, 16).toString(16);
|
|
27956
|
+
hextetCount++;
|
|
26953
27957
|
}
|
|
26954
|
-
if (
|
|
26955
|
-
if (
|
|
26956
|
-
|
|
26957
|
-
} else if (endIpv6) {
|
|
26958
|
-
address.push(buffer2.join(""));
|
|
26959
|
-
} else {
|
|
26960
|
-
address.push(stringArrayToHexStripped(buffer2));
|
|
26961
|
-
}
|
|
27958
|
+
if (compression === -1) {
|
|
27959
|
+
if (hextetCount !== 8) return void 0;
|
|
27960
|
+
return compressIPv6ZeroRun(parts);
|
|
26962
27961
|
}
|
|
26963
|
-
|
|
26964
|
-
|
|
27962
|
+
if (hextetCount >= 8) return void 0;
|
|
27963
|
+
const expanded = parts.slice(0, left.length);
|
|
27964
|
+
for (let i = hextetCount; i < 8; i++) expanded.push("0");
|
|
27965
|
+
for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
|
|
27966
|
+
return compressIPv6ZeroRun(expanded);
|
|
26965
27967
|
}
|
|
26966
27968
|
function normalizeIPv6(host) {
|
|
26967
|
-
|
|
26968
|
-
|
|
26969
|
-
}
|
|
26970
|
-
|
|
26971
|
-
if (
|
|
26972
|
-
|
|
26973
|
-
|
|
26974
|
-
|
|
26975
|
-
|
|
26976
|
-
|
|
26977
|
-
|
|
26978
|
-
|
|
26979
|
-
|
|
26980
|
-
|
|
26981
|
-
|
|
27969
|
+
const bracketed = host[0] === "[" && host[host.length - 1] === "]";
|
|
27970
|
+
const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
|
|
27971
|
+
if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
|
|
27972
|
+
let input = bracketed ? host.slice(1, -1) : host;
|
|
27973
|
+
if (bracketed && isIPvFuture(input)) {
|
|
27974
|
+
input = input.toLowerCase();
|
|
27975
|
+
return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
|
|
27976
|
+
}
|
|
27977
|
+
if (findToken(input, ":") < 2) {
|
|
27978
|
+
return { host, isIPV6: false, error: bracketed };
|
|
27979
|
+
}
|
|
27980
|
+
let zoneIdentifier = "";
|
|
27981
|
+
const zoneSeparator = input.indexOf("%");
|
|
27982
|
+
if (zoneSeparator !== -1) {
|
|
27983
|
+
const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
|
|
27984
|
+
zoneIdentifier = input.slice(zoneSeparator + separatorLength);
|
|
27985
|
+
if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
|
|
27986
|
+
input = input.slice(0, zoneSeparator);
|
|
27987
|
+
}
|
|
27988
|
+
const address = normalizeIPv6Address(input);
|
|
27989
|
+
if (address === void 0) return { host, isIPV6: false, error: true };
|
|
27990
|
+
return {
|
|
27991
|
+
host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
|
|
27992
|
+
escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
|
|
27993
|
+
isIPV6: true
|
|
27994
|
+
};
|
|
26982
27995
|
}
|
|
26983
27996
|
function findToken(str, token) {
|
|
26984
27997
|
let ind = 0;
|
|
@@ -27097,7 +28110,8 @@ var require_utils = __commonJS({
|
|
|
27097
28110
|
function normalizePathEncoding(input) {
|
|
27098
28111
|
let output = "";
|
|
27099
28112
|
for (let i = 0; i < input.length; i++) {
|
|
27100
|
-
|
|
28113
|
+
const ch = input[i];
|
|
28114
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
27101
28115
|
const hex = input.slice(i + 1, i + 3);
|
|
27102
28116
|
if (isHexPair(hex)) {
|
|
27103
28117
|
const normalizedHex = hex.toUpperCase();
|
|
@@ -27111,10 +28125,152 @@ var require_utils = __commonJS({
|
|
|
27111
28125
|
continue;
|
|
27112
28126
|
}
|
|
27113
28127
|
}
|
|
27114
|
-
if (isPathCharacter(
|
|
27115
|
-
output +=
|
|
28128
|
+
if (isPathCharacter(ch)) {
|
|
28129
|
+
output += ch;
|
|
28130
|
+
} else {
|
|
28131
|
+
const code = input.charCodeAt(i);
|
|
28132
|
+
if (code < 128) {
|
|
28133
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
28134
|
+
} else if (code < 55296 || code > 57343) {
|
|
28135
|
+
output += percentEncodeNonAscii(code);
|
|
28136
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
28137
|
+
const low = input.charCodeAt(i + 1);
|
|
28138
|
+
if (low >= 56320 && low <= 57343) {
|
|
28139
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
28140
|
+
i++;
|
|
28141
|
+
} else {
|
|
28142
|
+
output += percentEncodeNonAscii(65533);
|
|
28143
|
+
}
|
|
28144
|
+
} else {
|
|
28145
|
+
output += percentEncodeNonAscii(65533);
|
|
28146
|
+
}
|
|
28147
|
+
}
|
|
28148
|
+
}
|
|
28149
|
+
return output;
|
|
28150
|
+
}
|
|
28151
|
+
function serializePathEncoding(input, pathNoScheme = false) {
|
|
28152
|
+
let output = "";
|
|
28153
|
+
let firstSegment = pathNoScheme && input[0] !== "/";
|
|
28154
|
+
for (let i = 0; i < input.length; i++) {
|
|
28155
|
+
const ch = input[i];
|
|
28156
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
28157
|
+
const hex = input.slice(i + 1, i + 3);
|
|
28158
|
+
if (isHexPair(hex)) {
|
|
28159
|
+
output += "%" + hex.toUpperCase();
|
|
28160
|
+
i += 2;
|
|
28161
|
+
continue;
|
|
28162
|
+
}
|
|
28163
|
+
}
|
|
28164
|
+
if (ch === "/") {
|
|
28165
|
+
firstSegment = false;
|
|
28166
|
+
}
|
|
28167
|
+
if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
|
|
28168
|
+
output += ch;
|
|
28169
|
+
} else {
|
|
28170
|
+
const code = input.charCodeAt(i);
|
|
28171
|
+
if (code < 128) {
|
|
28172
|
+
output += BYTE_HEX[code];
|
|
28173
|
+
} else if (code < 55296 || code > 57343) {
|
|
28174
|
+
output += percentEncodeNonAscii(code);
|
|
28175
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
28176
|
+
const low = input.charCodeAt(i + 1);
|
|
28177
|
+
if (low >= 56320 && low <= 57343) {
|
|
28178
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
28179
|
+
i++;
|
|
28180
|
+
} else {
|
|
28181
|
+
output += percentEncodeNonAscii(65533);
|
|
28182
|
+
}
|
|
28183
|
+
} else {
|
|
28184
|
+
output += percentEncodeNonAscii(65533);
|
|
28185
|
+
}
|
|
28186
|
+
}
|
|
28187
|
+
}
|
|
28188
|
+
return output;
|
|
28189
|
+
}
|
|
28190
|
+
function encodeComponent(input, isAllowed) {
|
|
28191
|
+
let output = "";
|
|
28192
|
+
for (let i = 0; i < input.length; i++) {
|
|
28193
|
+
const ch = input[i];
|
|
28194
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
28195
|
+
const hex = input.slice(i + 1, i + 3);
|
|
28196
|
+
if (isHexPair(hex)) {
|
|
28197
|
+
output += "%" + hex.toUpperCase();
|
|
28198
|
+
i += 2;
|
|
28199
|
+
continue;
|
|
28200
|
+
}
|
|
28201
|
+
}
|
|
28202
|
+
if (isAllowed(ch)) {
|
|
28203
|
+
output += ch;
|
|
28204
|
+
} else {
|
|
28205
|
+
const code = input.charCodeAt(i);
|
|
28206
|
+
if (code < 128) {
|
|
28207
|
+
output += BYTE_HEX[code];
|
|
28208
|
+
} else if (code < 55296 || code > 57343) {
|
|
28209
|
+
output += percentEncodeNonAscii(code);
|
|
28210
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
28211
|
+
const low = input.charCodeAt(i + 1);
|
|
28212
|
+
if (low >= 56320 && low <= 57343) {
|
|
28213
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
28214
|
+
i++;
|
|
28215
|
+
} else {
|
|
28216
|
+
output += percentEncodeNonAscii(65533);
|
|
28217
|
+
}
|
|
28218
|
+
} else {
|
|
28219
|
+
output += percentEncodeNonAscii(65533);
|
|
28220
|
+
}
|
|
28221
|
+
}
|
|
28222
|
+
}
|
|
28223
|
+
return output;
|
|
28224
|
+
}
|
|
28225
|
+
function encodeUserinfo(input) {
|
|
28226
|
+
return encodeComponent(input, isUserinfoCharacter);
|
|
28227
|
+
}
|
|
28228
|
+
function encodeQuery(input) {
|
|
28229
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
28230
|
+
}
|
|
28231
|
+
function encodeFragment(input) {
|
|
28232
|
+
return encodeComponent(input, isQueryFragmentCharacter);
|
|
28233
|
+
}
|
|
28234
|
+
function isEscapeSafe(cp) {
|
|
28235
|
+
return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
|
|
28236
|
+
}
|
|
28237
|
+
function normalizeQueryFragmentEncoding(input) {
|
|
28238
|
+
let output = "";
|
|
28239
|
+
for (let i = 0; i < input.length; i++) {
|
|
28240
|
+
const ch = input[i];
|
|
28241
|
+
if (ch === "%" && i + 2 < input.length) {
|
|
28242
|
+
const hex = input.slice(i + 1, i + 3);
|
|
28243
|
+
if (isHexPair(hex)) {
|
|
28244
|
+
const normalizedHex = hex.toUpperCase();
|
|
28245
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
28246
|
+
if (isUnreserved(decoded)) {
|
|
28247
|
+
output += decoded;
|
|
28248
|
+
} else {
|
|
28249
|
+
output += "%" + normalizedHex;
|
|
28250
|
+
}
|
|
28251
|
+
i += 2;
|
|
28252
|
+
continue;
|
|
28253
|
+
}
|
|
28254
|
+
}
|
|
28255
|
+
if (isQueryFragmentCharacter(ch)) {
|
|
28256
|
+
output += ch;
|
|
27116
28257
|
} else {
|
|
27117
|
-
|
|
28258
|
+
const code = input.charCodeAt(i);
|
|
28259
|
+
if (code < 128) {
|
|
28260
|
+
output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
|
|
28261
|
+
} else if (code < 55296 || code > 57343) {
|
|
28262
|
+
output += percentEncodeNonAscii(code);
|
|
28263
|
+
} else if (code <= 56319 && i + 1 < input.length) {
|
|
28264
|
+
const low = input.charCodeAt(i + 1);
|
|
28265
|
+
if (low >= 56320 && low <= 57343) {
|
|
28266
|
+
output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
|
|
28267
|
+
i++;
|
|
28268
|
+
} else {
|
|
28269
|
+
output += percentEncodeNonAscii(65533);
|
|
28270
|
+
}
|
|
28271
|
+
} else {
|
|
28272
|
+
output += percentEncodeNonAscii(65533);
|
|
28273
|
+
}
|
|
27118
28274
|
}
|
|
27119
28275
|
}
|
|
27120
28276
|
return output;
|
|
@@ -27137,14 +28293,18 @@ var require_utils = __commonJS({
|
|
|
27137
28293
|
function recomposeAuthority(component) {
|
|
27138
28294
|
const uriTokens = [];
|
|
27139
28295
|
if (component.userinfo !== void 0) {
|
|
27140
|
-
uriTokens.push(component.userinfo);
|
|
28296
|
+
uriTokens.push(encodeUserinfo(component.userinfo));
|
|
27141
28297
|
uriTokens.push("@");
|
|
27142
28298
|
}
|
|
27143
28299
|
if (component.host !== void 0) {
|
|
27144
|
-
let host =
|
|
28300
|
+
let host = component.host;
|
|
27145
28301
|
if (!isIPv4(host)) {
|
|
27146
|
-
|
|
27147
|
-
if (ipV6res.isIPV6
|
|
28302
|
+
let ipV6res = normalizeIPv6(host);
|
|
28303
|
+
if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
|
|
28304
|
+
host = normalizePercentEncoding(host, true);
|
|
28305
|
+
ipV6res = normalizeIPv6(host);
|
|
28306
|
+
}
|
|
28307
|
+
if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
|
|
27148
28308
|
host = `[${ipV6res.escapedHost}]`;
|
|
27149
28309
|
} else {
|
|
27150
28310
|
host = reescapeHostDelimiters(host, false);
|
|
@@ -27164,6 +28324,11 @@ var require_utils = __commonJS({
|
|
|
27164
28324
|
reescapeHostDelimiters,
|
|
27165
28325
|
normalizePercentEncoding,
|
|
27166
28326
|
normalizePathEncoding,
|
|
28327
|
+
serializePathEncoding,
|
|
28328
|
+
normalizeQueryFragmentEncoding,
|
|
28329
|
+
encodeUserinfo,
|
|
28330
|
+
encodeQuery,
|
|
28331
|
+
encodeFragment,
|
|
27167
28332
|
escapePreservingEscapes,
|
|
27168
28333
|
removeDotSegments,
|
|
27169
28334
|
isIPv4,
|
|
@@ -27174,12 +28339,12 @@ var require_utils = __commonJS({
|
|
|
27174
28339
|
}
|
|
27175
28340
|
});
|
|
27176
28341
|
|
|
27177
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
28342
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js
|
|
27178
28343
|
var require_schemes = __commonJS({
|
|
27179
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
28344
|
+
"../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/lib/schemes.js"(exports, module) {
|
|
27180
28345
|
"use strict";
|
|
27181
28346
|
var { isUUID } = require_utils();
|
|
27182
|
-
var URN_REG =
|
|
28347
|
+
var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
|
|
27183
28348
|
var supportedSchemeNames = (
|
|
27184
28349
|
/** @type {const} */
|
|
27185
28350
|
[
|
|
@@ -27240,9 +28405,10 @@ var require_schemes = __commonJS({
|
|
|
27240
28405
|
wsComponent.secure = void 0;
|
|
27241
28406
|
}
|
|
27242
28407
|
if (wsComponent.resourceName) {
|
|
27243
|
-
const
|
|
28408
|
+
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
28409
|
+
const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
27244
28410
|
wsComponent.path = path && path !== "/" ? path : void 0;
|
|
27245
|
-
wsComponent.query =
|
|
28411
|
+
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
27246
28412
|
wsComponent.resourceName = void 0;
|
|
27247
28413
|
}
|
|
27248
28414
|
wsComponent.fragment = void 0;
|
|
@@ -27254,7 +28420,7 @@ var require_schemes = __commonJS({
|
|
|
27254
28420
|
return urnComponent;
|
|
27255
28421
|
}
|
|
27256
28422
|
const matches = urnComponent.path.match(URN_REG);
|
|
27257
|
-
if (matches) {
|
|
28423
|
+
if (matches && matches[0] === urnComponent.path) {
|
|
27258
28424
|
const scheme = options.scheme || urnComponent.scheme || "urn";
|
|
27259
28425
|
urnComponent.nid = matches[1].toLowerCase();
|
|
27260
28426
|
urnComponent.nss = matches[2];
|
|
@@ -27384,12 +28550,21 @@ var require_schemes = __commonJS({
|
|
|
27384
28550
|
}
|
|
27385
28551
|
});
|
|
27386
28552
|
|
|
27387
|
-
// ../../node_modules/.pnpm/fast-uri@3.1.
|
|
28553
|
+
// ../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js
|
|
27388
28554
|
var require_fast_uri = __commonJS({
|
|
27389
|
-
"../../node_modules/.pnpm/fast-uri@3.1.
|
|
28555
|
+
"../../node_modules/.pnpm/fast-uri@3.1.6/node_modules/fast-uri/index.js"(exports, module) {
|
|
27390
28556
|
"use strict";
|
|
27391
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding,
|
|
28557
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
27392
28558
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
28559
|
+
var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
|
|
28560
|
+
var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
|
|
28561
|
+
function decodeValidScheme(scheme) {
|
|
28562
|
+
const decodedScheme = unescape(String(scheme));
|
|
28563
|
+
if (!VALID_SCHEME.test(decodedScheme)) {
|
|
28564
|
+
throw new TypeError(MALFORMED_SCHEME_ERROR);
|
|
28565
|
+
}
|
|
28566
|
+
return decodedScheme;
|
|
28567
|
+
}
|
|
27393
28568
|
function normalize(uri, options) {
|
|
27394
28569
|
if (typeof uri === "string") {
|
|
27395
28570
|
uri = /** @type {T} */
|
|
@@ -27400,9 +28575,36 @@ var require_fast_uri = __commonJS({
|
|
|
27400
28575
|
}
|
|
27401
28576
|
return uri;
|
|
27402
28577
|
}
|
|
27403
|
-
function
|
|
28578
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
27404
28579
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
27405
|
-
const
|
|
28580
|
+
const {
|
|
28581
|
+
parsed: baseParsed,
|
|
28582
|
+
malformedAuthorityOrPort: baseMalformed,
|
|
28583
|
+
malformedPercentEncoding: baseMalformedPercentEncoding,
|
|
28584
|
+
malformedSchemeSpecific: baseMalformedSchemeSpecific,
|
|
28585
|
+
malformedHost: baseMalformedHost,
|
|
28586
|
+
malformedScheme: baseMalformedScheme
|
|
28587
|
+
} = parseWithStatus(baseURI, schemelessOptions);
|
|
28588
|
+
const {
|
|
28589
|
+
parsed: relativeParsed,
|
|
28590
|
+
malformedAuthorityOrPort: relativeMalformed,
|
|
28591
|
+
malformedPercentEncoding: relativeMalformedPercentEncoding,
|
|
28592
|
+
malformedSchemeSpecific: relativeMalformedSchemeSpecific,
|
|
28593
|
+
malformedHost: relativeMalformedHost,
|
|
28594
|
+
malformedScheme: relativeMalformedScheme
|
|
28595
|
+
} = parseWithStatus(relativeURI, schemelessOptions);
|
|
28596
|
+
if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
|
|
28597
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
28598
|
+
}
|
|
28599
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
28600
|
+
const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
|
|
28601
|
+
const resolvedHost = resolved.host;
|
|
28602
|
+
const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
|
|
28603
|
+
canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
|
|
28604
|
+
const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
|
|
28605
|
+
if (resolved.error && !encodedASCIIHost) {
|
|
28606
|
+
throw new Error(resolved.error);
|
|
28607
|
+
}
|
|
27406
28608
|
schemelessOptions.skipEscape = true;
|
|
27407
28609
|
return serialize(resolved, schemelessOptions);
|
|
27408
28610
|
}
|
|
@@ -27462,7 +28664,7 @@ var require_fast_uri = __commonJS({
|
|
|
27462
28664
|
function equal(uriA, uriB, options) {
|
|
27463
28665
|
const normalizedA = normalizeComparableURI(uriA, options);
|
|
27464
28666
|
const normalizedB = normalizeComparableURI(uriB, options);
|
|
27465
|
-
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA
|
|
28667
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
|
|
27466
28668
|
}
|
|
27467
28669
|
function serialize(cmpts, opts) {
|
|
27468
28670
|
const component = {
|
|
@@ -27483,19 +28685,22 @@ var require_fast_uri = __commonJS({
|
|
|
27483
28685
|
};
|
|
27484
28686
|
const options = Object.assign({}, opts);
|
|
27485
28687
|
const uriTokens = [];
|
|
28688
|
+
if (component.scheme) {
|
|
28689
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
28690
|
+
}
|
|
27486
28691
|
const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
|
|
27487
28692
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
28693
|
+
const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
|
|
28694
|
+
const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
|
|
27488
28695
|
if (component.path !== void 0) {
|
|
27489
28696
|
if (!options.skipEscape) {
|
|
27490
|
-
component.path =
|
|
27491
|
-
if (component.scheme !== void 0) {
|
|
27492
|
-
component.path = component.path.split("%3A").join(":");
|
|
27493
|
-
}
|
|
28697
|
+
component.path = serializePathEncoding(component.path, pathNoScheme);
|
|
27494
28698
|
} else {
|
|
27495
28699
|
component.path = normalizePercentEncoding(component.path);
|
|
27496
28700
|
}
|
|
27497
28701
|
}
|
|
27498
28702
|
if (options.reference !== "suffix" && component.scheme) {
|
|
28703
|
+
component.scheme = decodeValidScheme(component.scheme);
|
|
27499
28704
|
uriTokens.push(component.scheme, ":");
|
|
27500
28705
|
}
|
|
27501
28706
|
const authority = recomposeAuthority(component);
|
|
@@ -27513,20 +28718,25 @@ var require_fast_uri = __commonJS({
|
|
|
27513
28718
|
if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
|
|
27514
28719
|
s = removeDotSegments(s);
|
|
27515
28720
|
}
|
|
28721
|
+
if (pathNoScheme) {
|
|
28722
|
+
s = serializePathEncoding(s, true);
|
|
28723
|
+
}
|
|
27516
28724
|
if (authority === void 0 && s[0] === "/" && s[1] === "/") {
|
|
27517
28725
|
s = "/%2F" + s.slice(2);
|
|
27518
28726
|
}
|
|
27519
28727
|
uriTokens.push(s);
|
|
27520
28728
|
}
|
|
27521
28729
|
if (component.query !== void 0) {
|
|
27522
|
-
uriTokens.push("?", component.query);
|
|
28730
|
+
uriTokens.push("?", encodeQuery(component.query));
|
|
27523
28731
|
}
|
|
27524
28732
|
if (component.fragment !== void 0) {
|
|
27525
|
-
uriTokens.push("#", component.fragment);
|
|
28733
|
+
uriTokens.push("#", encodeFragment(component.fragment));
|
|
27526
28734
|
}
|
|
27527
28735
|
return uriTokens.join("");
|
|
27528
28736
|
}
|
|
27529
28737
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
28738
|
+
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
28739
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
27530
28740
|
function getParseError(parsed, matches) {
|
|
27531
28741
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
27532
28742
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -27536,6 +28746,32 @@ var require_fast_uri = __commonJS({
|
|
|
27536
28746
|
}
|
|
27537
28747
|
return void 0;
|
|
27538
28748
|
}
|
|
28749
|
+
function hasMalformedPercentEncoding(component) {
|
|
28750
|
+
if (component === void 0) return false;
|
|
28751
|
+
let percent = component.indexOf("%");
|
|
28752
|
+
while (percent !== -1) {
|
|
28753
|
+
if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
|
|
28754
|
+
return true;
|
|
28755
|
+
}
|
|
28756
|
+
percent = component.indexOf("%", percent + 3);
|
|
28757
|
+
}
|
|
28758
|
+
return false;
|
|
28759
|
+
}
|
|
28760
|
+
function hasMalformedComponentPercentEncoding(matches) {
|
|
28761
|
+
const host = matches[4];
|
|
28762
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host[0] === "[" && host[host.length - 1] === "]") && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
28763
|
+
}
|
|
28764
|
+
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
28765
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host[0] !== "[" && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
28766
|
+
try {
|
|
28767
|
+
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
28768
|
+
} catch (e) {
|
|
28769
|
+
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
28770
|
+
return true;
|
|
28771
|
+
}
|
|
28772
|
+
}
|
|
28773
|
+
return false;
|
|
28774
|
+
}
|
|
27539
28775
|
function parseWithStatus(uri, opts) {
|
|
27540
28776
|
const options = Object.assign({}, opts);
|
|
27541
28777
|
const parsed = {
|
|
@@ -27548,6 +28784,11 @@ var require_fast_uri = __commonJS({
|
|
|
27548
28784
|
fragment: void 0
|
|
27549
28785
|
};
|
|
27550
28786
|
let malformedAuthorityOrPort = false;
|
|
28787
|
+
let malformedPercentEncoding = false;
|
|
28788
|
+
let malformedSchemeSpecific = false;
|
|
28789
|
+
let malformedHost = false;
|
|
28790
|
+
let malformedIPLiteral = false;
|
|
28791
|
+
let malformedScheme = false;
|
|
27551
28792
|
let isIP = false;
|
|
27552
28793
|
if (options.reference === "suffix") {
|
|
27553
28794
|
if (options.scheme) {
|
|
@@ -27556,6 +28797,25 @@ var require_fast_uri = __commonJS({
|
|
|
27556
28797
|
uri = "//" + uri;
|
|
27557
28798
|
}
|
|
27558
28799
|
}
|
|
28800
|
+
const authorityMatch = uri.match(AUTHORITY_PREFIX);
|
|
28801
|
+
if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
|
|
28802
|
+
parsed.error = "URI authority must not contain a literal backslash.";
|
|
28803
|
+
malformedAuthorityOrPort = true;
|
|
28804
|
+
}
|
|
28805
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
28806
|
+
if (introducerMatch !== null) {
|
|
28807
|
+
const region = introducerMatch[1];
|
|
28808
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
28809
|
+
if (normalizedRegion.length >= 2) {
|
|
28810
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
28811
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
28812
|
+
malformedAuthorityOrPort = true;
|
|
28813
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
28814
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
28815
|
+
malformedAuthorityOrPort = true;
|
|
28816
|
+
}
|
|
28817
|
+
}
|
|
28818
|
+
}
|
|
27559
28819
|
const matches = uri.match(URI_PARSE);
|
|
27560
28820
|
if (matches) {
|
|
27561
28821
|
parsed.scheme = matches[1];
|
|
@@ -27565,6 +28825,19 @@ var require_fast_uri = __commonJS({
|
|
|
27565
28825
|
parsed.path = matches[6] || "";
|
|
27566
28826
|
parsed.query = matches[7];
|
|
27567
28827
|
parsed.fragment = matches[8];
|
|
28828
|
+
if (parsed.scheme !== void 0) {
|
|
28829
|
+
const decodedScheme = unescape(parsed.scheme);
|
|
28830
|
+
if (VALID_SCHEME.test(decodedScheme)) {
|
|
28831
|
+
parsed.scheme = decodedScheme.toLowerCase();
|
|
28832
|
+
} else {
|
|
28833
|
+
parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
|
|
28834
|
+
malformedScheme = true;
|
|
28835
|
+
}
|
|
28836
|
+
}
|
|
28837
|
+
malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
|
|
28838
|
+
if (malformedPercentEncoding) {
|
|
28839
|
+
parsed.error = parsed.error || "URI contains malformed percent-encoding.";
|
|
28840
|
+
}
|
|
27568
28841
|
if (isNaN(parsed.port)) {
|
|
27569
28842
|
parsed.port = matches[5];
|
|
27570
28843
|
}
|
|
@@ -27576,9 +28849,15 @@ var require_fast_uri = __commonJS({
|
|
|
27576
28849
|
if (parsed.host) {
|
|
27577
28850
|
const ipv4result = isIPv4(parsed.host);
|
|
27578
28851
|
if (ipv4result === false) {
|
|
28852
|
+
const bracketedIPLiteral = parsed.host[0] === "[" && parsed.host[parsed.host.length - 1] === "]";
|
|
27579
28853
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
27580
|
-
|
|
27581
|
-
|
|
28854
|
+
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
28855
|
+
malformedIPLiteral = bracketedIPLiteral && ipv6result.error === true;
|
|
28856
|
+
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
28857
|
+
if (malformedIPLiteral) {
|
|
28858
|
+
parsed.error = parsed.error || "URI host is malformed.";
|
|
28859
|
+
malformedAuthorityOrPort = true;
|
|
28860
|
+
}
|
|
27582
28861
|
} else {
|
|
27583
28862
|
isIP = true;
|
|
27584
28863
|
}
|
|
@@ -27596,42 +28875,34 @@ var require_fast_uri = __commonJS({
|
|
|
27596
28875
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
27597
28876
|
}
|
|
27598
28877
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
27599
|
-
|
|
27600
|
-
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
27601
|
-
try {
|
|
27602
|
-
parsed.host = URL.domainToASCII(parsed.host.toLowerCase());
|
|
27603
|
-
} catch (e) {
|
|
27604
|
-
parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
|
|
27605
|
-
}
|
|
27606
|
-
}
|
|
27607
|
-
}
|
|
28878
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
27608
28879
|
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
27609
28880
|
if (uri.indexOf("%") !== -1) {
|
|
27610
|
-
if (parsed.
|
|
27611
|
-
parsed.
|
|
27612
|
-
|
|
27613
|
-
if (parsed.host !== void 0) {
|
|
27614
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
28881
|
+
if (parsed.host !== void 0 && !malformedIPLiteral) {
|
|
28882
|
+
const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
28883
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
27615
28884
|
}
|
|
27616
28885
|
}
|
|
27617
28886
|
if (parsed.path) {
|
|
27618
28887
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
27619
28888
|
}
|
|
28889
|
+
if (parsed.query) {
|
|
28890
|
+
parsed.query = normalizeQueryFragmentEncoding(parsed.query);
|
|
28891
|
+
}
|
|
27620
28892
|
if (parsed.fragment) {
|
|
27621
|
-
|
|
27622
|
-
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
27623
|
-
} catch {
|
|
27624
|
-
parsed.error = parsed.error || "URI malformed";
|
|
27625
|
-
}
|
|
28893
|
+
parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
|
|
27626
28894
|
}
|
|
27627
28895
|
}
|
|
27628
28896
|
if (schemeHandler && schemeHandler.parse) {
|
|
27629
28897
|
schemeHandler.parse(parsed, options);
|
|
28898
|
+
if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
|
|
28899
|
+
malformedSchemeSpecific = true;
|
|
28900
|
+
}
|
|
27630
28901
|
}
|
|
27631
28902
|
} else {
|
|
27632
28903
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
27633
28904
|
}
|
|
27634
|
-
return { parsed, malformedAuthorityOrPort };
|
|
28905
|
+
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
27635
28906
|
}
|
|
27636
28907
|
function parse2(uri, opts) {
|
|
27637
28908
|
return parseWithStatus(uri, opts).parsed;
|
|
@@ -27640,25 +28911,33 @@ var require_fast_uri = __commonJS({
|
|
|
27640
28911
|
return normalizeStringWithStatus(uri, opts).normalized;
|
|
27641
28912
|
}
|
|
27642
28913
|
function normalizeStringWithStatus(uri, opts) {
|
|
27643
|
-
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
28914
|
+
const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
|
|
27644
28915
|
return {
|
|
27645
|
-
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
27646
|
-
malformedAuthorityOrPort
|
|
28916
|
+
normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
|
|
28917
|
+
malformedAuthorityOrPort,
|
|
28918
|
+
malformedPercentEncoding,
|
|
28919
|
+
malformedSchemeSpecific,
|
|
28920
|
+
malformedHost,
|
|
28921
|
+
malformedScheme
|
|
27647
28922
|
};
|
|
27648
28923
|
}
|
|
27649
28924
|
function normalizeComparableURI(uri, opts) {
|
|
27650
|
-
if (typeof uri
|
|
27651
|
-
|
|
27652
|
-
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
28925
|
+
if (typeof uri !== "string" && typeof uri !== "object") {
|
|
28926
|
+
return void 0;
|
|
27653
28927
|
}
|
|
27654
|
-
|
|
27655
|
-
|
|
28928
|
+
let value;
|
|
28929
|
+
try {
|
|
28930
|
+
value = typeof uri === "string" ? uri : serialize(uri, opts);
|
|
28931
|
+
} catch {
|
|
28932
|
+
return void 0;
|
|
27656
28933
|
}
|
|
28934
|
+
const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
|
|
28935
|
+
return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
|
|
27657
28936
|
}
|
|
27658
28937
|
var fastUri = {
|
|
27659
28938
|
SCHEMES,
|
|
27660
28939
|
normalize,
|
|
27661
|
-
resolve:
|
|
28940
|
+
resolve: resolve4,
|
|
27662
28941
|
resolveComponent,
|
|
27663
28942
|
equal,
|
|
27664
28943
|
serialize,
|
|
@@ -31786,7 +33065,7 @@ var init_mcp2 = __esm({
|
|
|
31786
33065
|
let task = createTaskResult.task;
|
|
31787
33066
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
31788
33067
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
31789
|
-
await new Promise((
|
|
33068
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollInterval));
|
|
31790
33069
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
31791
33070
|
if (!updatedTask) {
|
|
31792
33071
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -32382,12 +33661,12 @@ var init_stdio2 = __esm({
|
|
|
32382
33661
|
this.onclose?.();
|
|
32383
33662
|
}
|
|
32384
33663
|
send(message) {
|
|
32385
|
-
return new Promise((
|
|
33664
|
+
return new Promise((resolve4) => {
|
|
32386
33665
|
const json2 = serializeMessage(message);
|
|
32387
33666
|
if (this._stdout.write(json2)) {
|
|
32388
|
-
|
|
33667
|
+
resolve4();
|
|
32389
33668
|
} else {
|
|
32390
|
-
this._stdout.once("drain",
|
|
33669
|
+
this._stdout.once("drain", resolve4);
|
|
32391
33670
|
}
|
|
32392
33671
|
});
|
|
32393
33672
|
}
|
|
@@ -32619,10 +33898,10 @@ async function buildNodalMcpServer(opts) {
|
|
|
32619
33898
|
}
|
|
32620
33899
|
async function startNodalMcpServer(opts) {
|
|
32621
33900
|
const server = await buildNodalMcpServer(opts);
|
|
32622
|
-
const closed = new Promise((
|
|
32623
|
-
server.server.onclose =
|
|
32624
|
-
process.stdin.once("end",
|
|
32625
|
-
process.stdin.once("close",
|
|
33901
|
+
const closed = new Promise((resolve4) => {
|
|
33902
|
+
server.server.onclose = resolve4;
|
|
33903
|
+
process.stdin.once("end", resolve4);
|
|
33904
|
+
process.stdin.once("close", resolve4);
|
|
32626
33905
|
});
|
|
32627
33906
|
await server.connect(new StdioServerTransport());
|
|
32628
33907
|
await closed;
|
|
@@ -32723,7 +34002,7 @@ __export(reset_exports, {
|
|
|
32723
34002
|
});
|
|
32724
34003
|
import chalk6 from "chalk";
|
|
32725
34004
|
import prompts2 from "prompts";
|
|
32726
|
-
import { rmSync as rmSync2, existsSync as
|
|
34005
|
+
import { rmSync as rmSync2, existsSync as existsSync13 } from "fs";
|
|
32727
34006
|
async function runReset(options = {}) {
|
|
32728
34007
|
if (!options.yes) {
|
|
32729
34008
|
const { confirm } = await prompts2({
|
|
@@ -32741,7 +34020,7 @@ async function runReset(options = {}) {
|
|
|
32741
34020
|
}
|
|
32742
34021
|
console.log(chalk6.yellow("Stopping any running processes\u2026"));
|
|
32743
34022
|
await runDown();
|
|
32744
|
-
if (
|
|
34023
|
+
if (existsSync13(CONFIG_DIR)) {
|
|
32745
34024
|
rmSync2(CONFIG_DIR, { recursive: true, force: true });
|
|
32746
34025
|
console.log(chalk6.green(` Removed ${CONFIG_DIR}`));
|
|
32747
34026
|
} else {
|