kibi-runtime 2.14.0 → 2.14.2

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.
@@ -19,10 +19,10 @@ import {
19
19
  openSync as openSync2,
20
20
  readFileSync as readFileSync5,
21
21
  readdirSync as readdirSync2,
22
- realpathSync as realpathSync3,
22
+ realpathSync as realpathSync4,
23
23
  renameSync,
24
24
  rmSync as rmSync2,
25
- statSync as statSync4,
25
+ statSync as statSync5,
26
26
  unlinkSync,
27
27
  writeFileSync as writeFileSync3
28
28
  } from "node:fs";
@@ -102,7 +102,7 @@ function manifestVersion(manifestPath, expectedName) {
102
102
  }
103
103
  function cliVersion() {
104
104
  if (true)
105
- return "2.19.0";
105
+ return "2.21.0";
106
106
  return manifestVersion(path.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown";
107
107
  }
108
108
  function coreVersion() {
@@ -1754,9 +1754,15 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
1754
1754
  }
1755
1755
 
1756
1756
  // ../cli/src/prolog/store-lock.ts
1757
- import { existsSync as existsSync4, rmSync, writeFileSync } from "node:fs";
1757
+ import {
1758
+ existsSync as existsSync4,
1759
+ realpathSync as realpathSync2,
1760
+ rmSync,
1761
+ statSync as statSync3,
1762
+ writeFileSync
1763
+ } from "node:fs";
1758
1764
  import { readFileSync as readFileSync3 } from "node:fs";
1759
- import { dirname, join } from "node:path";
1765
+ import { basename, dirname, join } from "node:path";
1760
1766
  var cachedBootId;
1761
1767
  function currentBootId() {
1762
1768
  if (cachedBootId !== undefined)
@@ -1863,7 +1869,7 @@ function noteDeadHolderBeforeAttach(kbPath) {
1863
1869
  const lockPid = readRdfLockPid(lockPath);
1864
1870
  const journal = readStoreLockOwner(kbPath)?.owner ?? null;
1865
1871
  const owner = journal !== null && (lockPid === null || journal.pid === lockPid) ? journal : lockPid !== null ? { pid: lockPid } : null;
1866
- const decision = decideStoreLockTakeover(owner);
1872
+ const decision = decideStoreLockTakeover(owner, { storePath: kbPath });
1867
1873
  if (decision.action !== "break")
1868
1874
  return () => {
1869
1875
  return;
@@ -1871,14 +1877,71 @@ function noteDeadHolderBeforeAttach(kbPath) {
1871
1877
  const brokenPid = owner?.pid ?? null;
1872
1878
  return () => recordStoreLockTakeover(kbPath, brokenPid, decision.reason);
1873
1879
  }
1874
- function decideStoreLockTakeover(owner) {
1880
+ var FOREIGN_STORE_LOCK_REASON_PREFIX = "journal belongs to another workspace";
1881
+ function existingRealPath(pathname) {
1882
+ try {
1883
+ return realpathSync2(pathname);
1884
+ } catch {
1885
+ return null;
1886
+ }
1887
+ }
1888
+ function sameDirectory(left, right) {
1889
+ try {
1890
+ const a = statSync3(left);
1891
+ const b = statSync3(right);
1892
+ return a.dev === b.dev && a.ino === b.ino;
1893
+ } catch {
1894
+ return false;
1895
+ }
1896
+ }
1897
+ function owningWorkspaceRoot(storePath) {
1898
+ let current = storePath;
1899
+ for (;; ) {
1900
+ const parent = dirname(current);
1901
+ if (parent === current)
1902
+ return null;
1903
+ if (basename(parent) === "branches" && basename(dirname(parent)) === ".kb")
1904
+ return dirname(dirname(parent));
1905
+ current = parent;
1906
+ }
1907
+ }
1908
+ function foreignStoreLockJournalRoot(owner, storePath) {
1909
+ const recorded = owner?.workspaceRoot;
1910
+ if (recorded === undefined || recorded === "")
1911
+ return null;
1912
+ const store = existingRealPath(storePath);
1913
+ if (store === null)
1914
+ return null;
1915
+ const ownWorkspace = owningWorkspaceRoot(store);
1916
+ if (ownWorkspace === null)
1917
+ return null;
1918
+ const lockPid = readRdfLockPid(join(storePath, "rdf", "lock"));
1919
+ if (lockPid !== null && lockPid !== owner?.pid)
1920
+ return null;
1921
+ const recordedPath = existingRealPath(recorded);
1922
+ if (recordedPath === null || recordedPath === store)
1923
+ return null;
1924
+ if (sameDirectory(recordedPath, store))
1925
+ return null;
1926
+ const recordedWorkspace = owningWorkspaceRoot(recordedPath) ?? recordedPath;
1927
+ return recordedWorkspace === ownWorkspace ? null : recorded;
1928
+ }
1929
+ function decideStoreLockTakeover(owner, options = {}) {
1875
1930
  const state = classifyStoreLockHolder(owner);
1931
+ if (state === "dead") {
1932
+ return {
1933
+ action: "break",
1934
+ reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`
1935
+ };
1936
+ }
1937
+ const foreignRoot = options.storePath === undefined ? null : foreignStoreLockJournalRoot(owner, options.storePath);
1938
+ if (foreignRoot !== null) {
1939
+ return {
1940
+ action: "break",
1941
+ reason: `${FOREIGN_STORE_LOCK_REASON_PREFIX} ${foreignRoot}`
1942
+ };
1943
+ }
1876
1944
  switch (state) {
1877
- case "dead":
1878
- return {
1879
- action: "break",
1880
- reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`
1881
- };
1882
1945
  case "unknown":
1883
1946
  return {
1884
1947
  action: "surface",
@@ -1897,7 +1960,9 @@ async function retryAttachAfterBreakingStaleLock(prolog, kbPath, failed) {
1897
1960
  const storeLocked = record?.storeLocked;
1898
1961
  if (storeLocked === undefined)
1899
1962
  return failed;
1900
- const decision = decideStoreLockTakeover(storeLocked.owner);
1963
+ const decision = decideStoreLockTakeover(storeLocked.owner, {
1964
+ storePath: kbPath
1965
+ });
1901
1966
  if (decision.action !== "break") {
1902
1967
  const holderSummary = storeLocked.owner === null ? decision.reason : `pid ${storeLocked.owner.pid ?? "?"} (${decision.reason})`;
1903
1968
  return {
@@ -1930,7 +1995,7 @@ import {
1930
1995
  mkdirSync,
1931
1996
  readFileSync as readFileSync4,
1932
1997
  readdirSync,
1933
- statSync as statSync3,
1998
+ statSync as statSync4,
1934
1999
  writeFileSync as writeFileSync2
1935
2000
  } from "node:fs";
1936
2001
  import path5 from "node:path";
@@ -2042,14 +2107,14 @@ function isValidBranchName(name) {
2042
2107
  }
2043
2108
 
2044
2109
  // ../cli/src/utils/canonical-path.ts
2045
- import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
2110
+ import { lstatSync as lstatSync2, realpathSync as realpathSync3 } from "node:fs";
2046
2111
  import path7 from "node:path";
2047
2112
  function canonicalFilesystemPath(candidate) {
2048
2113
  let existing = path7.resolve(candidate);
2049
2114
  const missing = [];
2050
2115
  for (;; ) {
2051
2116
  try {
2052
- return path7.resolve(realpathSync2.native(existing), ...missing);
2117
+ return path7.resolve(realpathSync3.native(existing), ...missing);
2053
2118
  } catch (error) {
2054
2119
  if (error.code !== "ENOENT")
2055
2120
  throw error;
@@ -2107,10 +2172,10 @@ function readJournalGeneration(branchPath) {
2107
2172
  function readEngineAttachmentIdentity(branchPath) {
2108
2173
  if (!existsSync6(branchPath))
2109
2174
  return null;
2110
- const stats = statSync4(branchPath);
2175
+ const stats = statSync5(branchPath);
2111
2176
  let resolved = path8.resolve(branchPath);
2112
2177
  try {
2113
- resolved = realpathSync3(branchPath);
2178
+ resolved = realpathSync4(branchPath);
2114
2179
  } catch {}
2115
2180
  return {
2116
2181
  path: resolved,
@@ -2356,9 +2421,23 @@ function recoverStaleJournalLock(branchPath) {
2356
2421
  if (!existsSync6(lockPath))
2357
2422
  return;
2358
2423
  const pid = readRdfLockPid(lockPath);
2359
- if (pid === null || pid === process.pid || isProcessAlive(pid))
2424
+ if (pid === null || pid === process.pid)
2360
2425
  return;
2361
- recordStoreLockTakeover(branchPath, pid, decideStoreLockTakeover({ pid }).reason);
2426
+ let reason;
2427
+ if (!isProcessAlive(pid)) {
2428
+ reason = decideStoreLockTakeover({ pid }).reason;
2429
+ } else {
2430
+ const journal = readStoreLockOwner(branchPath)?.owner ?? null;
2431
+ if (journal === null || journal.pid !== pid)
2432
+ return;
2433
+ const decision = decideStoreLockTakeover(journal, {
2434
+ storePath: branchPath
2435
+ });
2436
+ if (decision.action !== "break")
2437
+ return;
2438
+ reason = decision.reason;
2439
+ }
2440
+ recordStoreLockTakeover(branchPath, pid, reason);
2362
2441
  try {
2363
2442
  rmSync2(lockPath, { force: true });
2364
2443
  } catch {}