kibi-runtime 2.13.1 → 2.13.3
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/dist/engine-daemon.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
4
4
|
|
|
5
5
|
// ../cli/src/engine-daemon.ts
|
|
6
|
-
import { writeFileSync as
|
|
6
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
7
7
|
import path9 from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
9
|
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
rmSync as rmSync2,
|
|
25
25
|
statSync as statSync4,
|
|
26
26
|
unlinkSync,
|
|
27
|
-
writeFileSync as
|
|
27
|
+
writeFileSync as writeFileSync3
|
|
28
28
|
} from "node:fs";
|
|
29
29
|
import * as net from "node:net";
|
|
30
30
|
import * as os from "node:os";
|
|
@@ -102,7 +102,7 @@ function manifestVersion(manifestPath, expectedName) {
|
|
|
102
102
|
}
|
|
103
103
|
function cliVersion() {
|
|
104
104
|
if (true)
|
|
105
|
-
return "2.
|
|
105
|
+
return "2.18.0";
|
|
106
106
|
return manifestVersion(path.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown";
|
|
107
107
|
}
|
|
108
108
|
function coreVersion() {
|
|
@@ -1576,7 +1576,7 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
|
|
|
1576
1576
|
child.kill(signal);
|
|
1577
1577
|
} catch {}
|
|
1578
1578
|
}
|
|
1579
|
-
async terminateProcessTree(child) {
|
|
1579
|
+
async terminateProcessTree(child, graceMs = 0) {
|
|
1580
1580
|
let closed = false;
|
|
1581
1581
|
const exited = new Promise((resolve) => {
|
|
1582
1582
|
const markExited = () => {
|
|
@@ -1586,6 +1586,19 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
|
|
|
1586
1586
|
child.once("close", markExited);
|
|
1587
1587
|
child.once("error", markExited);
|
|
1588
1588
|
});
|
|
1589
|
+
if (graceMs > 0 && child.exitCode === null && child.signalCode === null) {
|
|
1590
|
+
let graceTimer;
|
|
1591
|
+
await Promise.race([
|
|
1592
|
+
exited,
|
|
1593
|
+
new Promise((resolve) => {
|
|
1594
|
+
graceTimer = setTimeout(resolve, graceMs);
|
|
1595
|
+
})
|
|
1596
|
+
]);
|
|
1597
|
+
if (graceTimer)
|
|
1598
|
+
clearTimeout(graceTimer);
|
|
1599
|
+
if (closed)
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1589
1602
|
if (child.exitCode === null)
|
|
1590
1603
|
this.signalProcessTree(child, "SIGTERM");
|
|
1591
1604
|
await Promise.race([
|
|
@@ -1707,7 +1720,7 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
|
|
|
1707
1720
|
}
|
|
1708
1721
|
return new PrologProcessTerminatedError(this.terminationReason ?? "process exited");
|
|
1709
1722
|
}
|
|
1710
|
-
async terminate() {
|
|
1723
|
+
async terminate(options = {}) {
|
|
1711
1724
|
if (this.interactiveStarted) {
|
|
1712
1725
|
this.terminationReason ??= "terminated";
|
|
1713
1726
|
}
|
|
@@ -1727,7 +1740,7 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
|
|
|
1727
1740
|
this.terminationPromise = (async () => {
|
|
1728
1741
|
if (current) {
|
|
1729
1742
|
current.stdin?.end();
|
|
1730
|
-
await this.terminateProcessTree(current);
|
|
1743
|
+
await this.terminateProcessTree(current, options.graceMs ?? 0);
|
|
1731
1744
|
}
|
|
1732
1745
|
await Promise.all(oneShots.map((child) => this.terminateProcessTree(child)));
|
|
1733
1746
|
})();
|
|
@@ -1741,7 +1754,7 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
|
|
|
1741
1754
|
}
|
|
1742
1755
|
|
|
1743
1756
|
// ../cli/src/prolog/store-lock.ts
|
|
1744
|
-
import { existsSync as existsSync4, rmSync } from "node:fs";
|
|
1757
|
+
import { existsSync as existsSync4, rmSync, writeFileSync } from "node:fs";
|
|
1745
1758
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1746
1759
|
import { dirname, join } from "node:path";
|
|
1747
1760
|
var cachedBootId;
|
|
@@ -1797,6 +1810,14 @@ function breakStoreLock(rdfDirectory) {
|
|
|
1797
1810
|
}
|
|
1798
1811
|
}
|
|
1799
1812
|
}
|
|
1813
|
+
var STORE_LOCK_TAKEOVER_FILE = ".kibi-lock-takeover.json";
|
|
1814
|
+
var STORE_LOCK_TAKEOVER_VISIBLE_MS = 24 * 60 * 60 * 1000;
|
|
1815
|
+
function recordStoreLockTakeover(storePath, brokenPid, reason, at = new Date) {
|
|
1816
|
+
try {
|
|
1817
|
+
writeFileSync(join(storePath, STORE_LOCK_TAKEOVER_FILE), `${JSON.stringify({ brokenPid, reason, at: at.toISOString() })}
|
|
1818
|
+
`, { mode: 384 });
|
|
1819
|
+
} catch {}
|
|
1820
|
+
}
|
|
1800
1821
|
function decideStoreLockTakeover(owner) {
|
|
1801
1822
|
const state = classifyStoreLockHolder(owner);
|
|
1802
1823
|
switch (state) {
|
|
@@ -1833,6 +1854,7 @@ Store lock holder: ${holderSummary}. Close that session, or run 'kibi engine sto
|
|
|
1833
1854
|
};
|
|
1834
1855
|
}
|
|
1835
1856
|
const lockDirectory = storeLocked.lockDirectory !== "" ? storeLocked.lockDirectory : join(kbPath, "rdf");
|
|
1857
|
+
recordStoreLockTakeover(kbPath, storeLocked.owner?.pid ?? null, decision.reason);
|
|
1836
1858
|
breakStoreLock(lockDirectory);
|
|
1837
1859
|
const retried = await prolog.query(`kb_attach('${escapeAtom(kbPath)}')`);
|
|
1838
1860
|
if (retried.success) {
|
|
@@ -1856,7 +1878,7 @@ import {
|
|
|
1856
1878
|
readFileSync as readFileSync4,
|
|
1857
1879
|
readdirSync,
|
|
1858
1880
|
statSync as statSync3,
|
|
1859
|
-
writeFileSync
|
|
1881
|
+
writeFileSync as writeFileSync2
|
|
1860
1882
|
} from "node:fs";
|
|
1861
1883
|
import path5 from "node:path";
|
|
1862
1884
|
var BRANCH_STORE_MANIFEST_VERSION = 1;
|
|
@@ -1918,7 +1940,7 @@ function ensureBranchStoreManifest(workspaceRoot, branch) {
|
|
|
1918
1940
|
if (entries.length > 0) {
|
|
1919
1941
|
throw new Error(`Branch store at ${storePath} has compiled data but no valid identity manifest; refusing to adopt it.`);
|
|
1920
1942
|
}
|
|
1921
|
-
|
|
1943
|
+
writeFileSync2(manifestPath, `${JSON.stringify(expectedBranchStoreManifest(branch), null, 2)}
|
|
1922
1944
|
`, { mode: 384 });
|
|
1923
1945
|
}
|
|
1924
1946
|
return storePath;
|
|
@@ -2005,6 +2027,8 @@ var READ_LIMITED_METHODS = new Set([
|
|
|
2005
2027
|
]);
|
|
2006
2028
|
var ENGINE_PROTOCOL_VERSION = 1;
|
|
2007
2029
|
var ENGINE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
2030
|
+
var ENGINE_IDLE_CHECK_INTERVAL_MS = 30 * 1000;
|
|
2031
|
+
var ENGINE_PROLOG_EXIT_GRACE_MS = 1000;
|
|
2008
2032
|
function enginePackageVersions() {
|
|
2009
2033
|
return kibiPackageVersions();
|
|
2010
2034
|
}
|
|
@@ -2174,7 +2198,7 @@ function runtimeDirectory() {
|
|
|
2174
2198
|
try {
|
|
2175
2199
|
mkdirSync2(candidate, { recursive: true, mode: 448 });
|
|
2176
2200
|
const probe = path8.join(candidate, `.kibi-write-${process.pid}`);
|
|
2177
|
-
|
|
2201
|
+
writeFileSync3(probe, "", { mode: 384 });
|
|
2178
2202
|
unlinkSync(probe);
|
|
2179
2203
|
return candidate;
|
|
2180
2204
|
} catch {}
|
|
@@ -2214,7 +2238,7 @@ function runtimeDirectory() {
|
|
|
2214
2238
|
if (Buffer.byteLength(path8.join(canonical, socketName), "utf8") > maximumBytes)
|
|
2215
2239
|
continue;
|
|
2216
2240
|
const probe = path8.join(canonical, `.kibi-write-${randomUUID()}`);
|
|
2217
|
-
|
|
2241
|
+
writeFileSync3(probe, "", { mode: 384, flag: "wx" });
|
|
2218
2242
|
unlinkSync(probe);
|
|
2219
2243
|
return canonical;
|
|
2220
2244
|
} catch {}
|
|
@@ -2340,7 +2364,7 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
|
|
|
2340
2364
|
recoverStaleJournalLock(branchPath);
|
|
2341
2365
|
archiveLegacyFiles(branchPath);
|
|
2342
2366
|
if (!existsSync6(sentinelPath)) {
|
|
2343
|
-
|
|
2367
|
+
writeFileSync3(sentinelPath, `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
|
|
2344
2368
|
`, { mode: 384 });
|
|
2345
2369
|
}
|
|
2346
2370
|
return;
|
|
@@ -2359,7 +2383,7 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
|
|
|
2359
2383
|
recoverStaleJournalLock(branchPath);
|
|
2360
2384
|
archiveLegacyFiles(branchPath);
|
|
2361
2385
|
if (!existsSync6(sentinelPath)) {
|
|
2362
|
-
|
|
2386
|
+
writeFileSync3(sentinelPath, `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
|
|
2363
2387
|
`, { mode: 384 });
|
|
2364
2388
|
}
|
|
2365
2389
|
return;
|
|
@@ -2369,13 +2393,13 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
|
|
|
2369
2393
|
const legacyAudit = path8.join(branchPath, "audit.log");
|
|
2370
2394
|
if (!existsSync6(legacyRdf) && !existsSync6(legacyAudit)) {
|
|
2371
2395
|
mkdirSync2(path8.join(branchPath, "rdf"), { recursive: true });
|
|
2372
|
-
|
|
2396
|
+
writeFileSync3(markerPath, `{"format":"kibi.rdf-journal.v1","schemaVersion":1}
|
|
2373
2397
|
`, { mode: 384 });
|
|
2374
|
-
|
|
2398
|
+
writeFileSync3(path8.join(branchPath, "CURRENT"), `generation-1:0
|
|
2375
2399
|
`, {
|
|
2376
2400
|
mode: 384
|
|
2377
2401
|
});
|
|
2378
|
-
|
|
2402
|
+
writeFileSync3(path8.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
|
|
2379
2403
|
`, { mode: 384 });
|
|
2380
2404
|
return;
|
|
2381
2405
|
}
|
|
@@ -2424,7 +2448,7 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
|
|
|
2424
2448
|
renameSync(source, target);
|
|
2425
2449
|
}
|
|
2426
2450
|
archiveLegacyFiles(branchPath);
|
|
2427
|
-
|
|
2451
|
+
writeFileSync3(path8.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
|
|
2428
2452
|
`, { mode: 384 });
|
|
2429
2453
|
fsyncJournaledBranchStore(branchPath);
|
|
2430
2454
|
rmSync2(staging, { recursive: true, force: true });
|
|
@@ -2617,11 +2641,12 @@ async function runEngineDaemon(requestedOptions) {
|
|
|
2617
2641
|
rmSync2(options.socketPath, { force: true });
|
|
2618
2642
|
} catch {}
|
|
2619
2643
|
}
|
|
2620
|
-
|
|
2644
|
+
writeFileSync3(enginePidPath(options.workspaceRoot, options.branch), `${process.pid}
|
|
2621
2645
|
`, { mode: 384 });
|
|
2622
2646
|
const server = net.createServer();
|
|
2623
2647
|
let activeClients = 0;
|
|
2624
|
-
let
|
|
2648
|
+
let lastActivityAt = Date.now();
|
|
2649
|
+
let idleWatch = null;
|
|
2625
2650
|
let queue = Promise.resolve();
|
|
2626
2651
|
let idleCompactionQueued = false;
|
|
2627
2652
|
const queryCache = new Map;
|
|
@@ -2698,12 +2723,15 @@ async function runEngineDaemon(requestedOptions) {
|
|
|
2698
2723
|
idleCompactionQueued = false;
|
|
2699
2724
|
});
|
|
2700
2725
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2726
|
+
lastActivityAt = Date.now();
|
|
2727
|
+
if (idleWatch)
|
|
2728
|
+
return;
|
|
2729
|
+
const idleMs = engineIdleTimeoutMs();
|
|
2730
|
+
idleWatch = setInterval(() => {
|
|
2731
|
+
if (!shuttingDown && activeClients === 0 && Date.now() - lastActivityAt >= idleMs)
|
|
2705
2732
|
shutdown();
|
|
2706
|
-
},
|
|
2733
|
+
}, Math.min(idleMs, ENGINE_IDLE_CHECK_INTERVAL_MS));
|
|
2734
|
+
idleWatch.unref();
|
|
2707
2735
|
};
|
|
2708
2736
|
const handle = async (request, cancelledRequests) => {
|
|
2709
2737
|
if (request.protocolVersion !== ENGINE_PROTOCOL_VERSION) {
|
|
@@ -2958,20 +2986,22 @@ async function runEngineDaemon(requestedOptions) {
|
|
|
2958
2986
|
shuttingDown = true;
|
|
2959
2987
|
process.off("SIGTERM", requestSignalShutdown);
|
|
2960
2988
|
process.off("SIGINT", requestSignalShutdown);
|
|
2961
|
-
if (
|
|
2962
|
-
|
|
2989
|
+
if (idleWatch)
|
|
2990
|
+
clearInterval(idleWatch);
|
|
2963
2991
|
clearInterval(workspaceWatchdog);
|
|
2964
2992
|
server.close();
|
|
2965
2993
|
await queue.catch(() => {
|
|
2966
2994
|
return;
|
|
2967
2995
|
});
|
|
2968
2996
|
const saved = session.needsRecycle() ? null : await prolog.query("kb_save").catch(() => null);
|
|
2997
|
+
let detached = false;
|
|
2969
2998
|
if (saved?.success) {
|
|
2970
2999
|
try {
|
|
2971
3000
|
fsyncJournaledBranchStore(branchPath);
|
|
2972
3001
|
} catch {}
|
|
3002
|
+
detached = await prolog.query("kb_detach").then((result) => result.success).catch(() => false);
|
|
2973
3003
|
}
|
|
2974
|
-
await prolog.terminate().catch(() => {
|
|
3004
|
+
await prolog.terminate({ graceMs: detached ? 0 : ENGINE_PROLOG_EXIT_GRACE_MS }).catch(() => {
|
|
2975
3005
|
return;
|
|
2976
3006
|
});
|
|
2977
3007
|
for (const client of clients)
|
|
@@ -3008,6 +3038,7 @@ async function runEngineDaemon(requestedOptions) {
|
|
|
3008
3038
|
const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
3009
3039
|
buffer = parseFrames(Buffer.concat([buffer, bytes]), (value) => {
|
|
3010
3040
|
const request = value;
|
|
3041
|
+
lastActivityAt = Date.now();
|
|
3011
3042
|
if (shuttingDown) {
|
|
3012
3043
|
writeSocketFrame(socket, {
|
|
3013
3044
|
id: request.id,
|
|
@@ -3114,7 +3145,7 @@ async function runEngineDaemonCli(args = process.argv.slice(2)) {
|
|
|
3114
3145
|
const socketPath = socketIndex >= 0 ? args[socketIndex + 1] : undefined;
|
|
3115
3146
|
if (socketPath) {
|
|
3116
3147
|
try {
|
|
3117
|
-
|
|
3148
|
+
writeFileSync4(`${socketPath}.error`, `${message}
|
|
3118
3149
|
`, { mode: 384 });
|
|
3119
3150
|
} catch {}
|
|
3120
3151
|
}
|