kibi-runtime 2.13.3 → 2.14.0
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 +63 -20
- package/dist/index.js +2990 -2509
- package/dist/skills/kibi-usage/SKILL.md +9 -1
- package/package.json +2 -2
package/dist/engine-daemon.js
CHANGED
|
@@ -102,7 +102,7 @@ function manifestVersion(manifestPath, expectedName) {
|
|
|
102
102
|
}
|
|
103
103
|
function cliVersion() {
|
|
104
104
|
if (true)
|
|
105
|
-
return "2.
|
|
105
|
+
return "2.19.0";
|
|
106
106
|
return manifestVersion(path.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown";
|
|
107
107
|
}
|
|
108
108
|
function coreVersion() {
|
|
@@ -1798,6 +1798,33 @@ function classifyStoreLockHolder(owner) {
|
|
|
1798
1798
|
}
|
|
1799
1799
|
return "alive";
|
|
1800
1800
|
}
|
|
1801
|
+
function readStoreLockOwner(storePath) {
|
|
1802
|
+
const candidates = [
|
|
1803
|
+
join(storePath, ".kibi-lock-owner.json"),
|
|
1804
|
+
join(storePath, "rdf", ".kibi-lock-owner.json")
|
|
1805
|
+
];
|
|
1806
|
+
for (const journalPath of candidates) {
|
|
1807
|
+
if (!existsSync4(journalPath))
|
|
1808
|
+
continue;
|
|
1809
|
+
let parsed;
|
|
1810
|
+
try {
|
|
1811
|
+
parsed = JSON.parse(readFileSync3(journalPath, "utf8"));
|
|
1812
|
+
} catch {
|
|
1813
|
+
continue;
|
|
1814
|
+
}
|
|
1815
|
+
if (parsed === null || typeof parsed !== "object")
|
|
1816
|
+
continue;
|
|
1817
|
+
const record = parsed;
|
|
1818
|
+
const owner = {
|
|
1819
|
+
...typeof record.pid === "number" ? { pid: record.pid } : {},
|
|
1820
|
+
...typeof record.workspaceRoot === "string" ? { workspaceRoot: record.workspaceRoot } : {},
|
|
1821
|
+
...typeof record.bootId === "string" ? { bootId: record.bootId } : {},
|
|
1822
|
+
...typeof record.startedAt === "string" ? { startedAt: record.startedAt } : {}
|
|
1823
|
+
};
|
|
1824
|
+
return { owner, journalPath };
|
|
1825
|
+
}
|
|
1826
|
+
return null;
|
|
1827
|
+
}
|
|
1801
1828
|
function breakStoreLock(rdfDirectory) {
|
|
1802
1829
|
const candidates = [
|
|
1803
1830
|
join(rdfDirectory, "lock"),
|
|
@@ -1818,6 +1845,32 @@ function recordStoreLockTakeover(storePath, brokenPid, reason, at = new Date) {
|
|
|
1818
1845
|
`, { mode: 384 });
|
|
1819
1846
|
} catch {}
|
|
1820
1847
|
}
|
|
1848
|
+
function readRdfLockPid(lockPath) {
|
|
1849
|
+
try {
|
|
1850
|
+
const match = /pid\((\d+)\)/.exec(readFileSync3(lockPath, "utf8"));
|
|
1851
|
+
const pid = Number.parseInt(match?.[1] ?? "", 10);
|
|
1852
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
1853
|
+
} catch {
|
|
1854
|
+
return null;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
function noteDeadHolderBeforeAttach(kbPath) {
|
|
1858
|
+
const lockPath = join(kbPath, "rdf", "lock");
|
|
1859
|
+
if (!existsSync4(lockPath))
|
|
1860
|
+
return () => {
|
|
1861
|
+
return;
|
|
1862
|
+
};
|
|
1863
|
+
const lockPid = readRdfLockPid(lockPath);
|
|
1864
|
+
const journal = readStoreLockOwner(kbPath)?.owner ?? null;
|
|
1865
|
+
const owner = journal !== null && (lockPid === null || journal.pid === lockPid) ? journal : lockPid !== null ? { pid: lockPid } : null;
|
|
1866
|
+
const decision = decideStoreLockTakeover(owner);
|
|
1867
|
+
if (decision.action !== "break")
|
|
1868
|
+
return () => {
|
|
1869
|
+
return;
|
|
1870
|
+
};
|
|
1871
|
+
const brokenPid = owner?.pid ?? null;
|
|
1872
|
+
return () => recordStoreLockTakeover(kbPath, brokenPid, decision.reason);
|
|
1873
|
+
}
|
|
1821
1874
|
function decideStoreLockTakeover(owner) {
|
|
1822
1875
|
const state = classifyStoreLockHolder(owner);
|
|
1823
1876
|
switch (state) {
|
|
@@ -2302,26 +2355,13 @@ function recoverStaleJournalLock(branchPath) {
|
|
|
2302
2355
|
const lockPath = path8.join(branchPath, "rdf", "lock");
|
|
2303
2356
|
if (!existsSync6(lockPath))
|
|
2304
2357
|
return;
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
contents = readFileSync5(lockPath, "utf8");
|
|
2308
|
-
} catch {
|
|
2309
|
-
return;
|
|
2310
|
-
}
|
|
2311
|
-
const match = /pid\((\d+)\)/.exec(contents);
|
|
2312
|
-
if (!match)
|
|
2313
|
-
return;
|
|
2314
|
-
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
2315
|
-
if (!Number.isFinite(pid) || pid <= 0 || pid === process.pid)
|
|
2358
|
+
const pid = readRdfLockPid(lockPath);
|
|
2359
|
+
if (pid === null || pid === process.pid || isProcessAlive(pid))
|
|
2316
2360
|
return;
|
|
2361
|
+
recordStoreLockTakeover(branchPath, pid, decideStoreLockTakeover({ pid }).reason);
|
|
2317
2362
|
try {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
} catch {
|
|
2321
|
-
try {
|
|
2322
|
-
rmSync2(lockPath, { force: true });
|
|
2323
|
-
} catch {}
|
|
2324
|
-
}
|
|
2363
|
+
rmSync2(lockPath, { force: true });
|
|
2364
|
+
} catch {}
|
|
2325
2365
|
}
|
|
2326
2366
|
function connectSocket(socketPath, timeoutMs) {
|
|
2327
2367
|
return new Promise((resolve, reject) => {
|
|
@@ -2541,8 +2581,11 @@ class EngineSession {
|
|
|
2541
2581
|
}
|
|
2542
2582
|
async boot() {
|
|
2543
2583
|
await this.prolog.start();
|
|
2584
|
+
const recordTakeover = noteDeadHolderBeforeAttach(this.branchPath);
|
|
2544
2585
|
const attached = await this.prolog.query(`kb_attach('${quoteProlog(this.branchPath)}')`);
|
|
2545
|
-
if (
|
|
2586
|
+
if (attached.success)
|
|
2587
|
+
recordTakeover();
|
|
2588
|
+
else {
|
|
2546
2589
|
const recovered = await retryAttachAfterBreakingStaleLock(this.prolog, this.branchPath, attached);
|
|
2547
2590
|
if (!recovered.success)
|
|
2548
2591
|
throw new Error(recovered.error ?? "Failed to attach branch KB");
|