kibi-runtime 2.0.2 → 2.1.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.
@@ -4,36 +4,161 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // ../cli/src/engine-daemon.ts
6
6
  import { writeFileSync as writeFileSync3 } from "node:fs";
7
- import path5 from "node:path";
7
+ import path8 from "node:path";
8
8
  import { pathToFileURL } from "node:url";
9
9
 
10
10
  // ../cli/src/engine.ts
11
- import { createHash as createHash2 } from "node:crypto";
11
+ import { createHash as createHash2, randomUUID } from "node:crypto";
12
12
  import {
13
13
  chmodSync,
14
- closeSync,
15
- existsSync as existsSync4,
14
+ closeSync as closeSync2,
15
+ existsSync as existsSync6,
16
16
  fsyncSync,
17
+ lstatSync as lstatSync3,
17
18
  mkdirSync as mkdirSync2,
18
- openSync,
19
- readFileSync as readFileSync3,
19
+ openSync as openSync2,
20
+ readFileSync as readFileSync4,
20
21
  readdirSync as readdirSync2,
21
- realpathSync,
22
+ realpathSync as realpathSync3,
22
23
  renameSync,
23
24
  rmSync as rmSync2,
24
- statSync as statSync2,
25
+ statSync as statSync4,
25
26
  unlinkSync,
26
27
  writeFileSync as writeFileSync2
27
28
  } from "node:fs";
28
29
  import * as net from "node:net";
29
30
  import * as os from "node:os";
30
- import * as path4 from "node:path";
31
+ import * as path7 from "node:path";
32
+ import { performance as performance2 } from "node:perf_hooks";
33
+
34
+ // ../cli/src/performance-trace.ts
35
+ import { constants } from "node:fs";
36
+ import {
37
+ closeSync,
38
+ existsSync,
39
+ lstatSync,
40
+ openSync,
41
+ realpathSync,
42
+ statSync,
43
+ writeSync
44
+ } from "node:fs";
45
+ import path from "node:path";
46
+ var KIBI_PERF_TRACE_DIR_ENV = "KIBI_PERF_TRACE_DIR";
47
+ var KIBI_PERF_TIMINGS_ENV = "KIBI_PERF_TIMINGS";
48
+ var KIBI_PERF_TRACE_MAX_EVENTS = 5000;
49
+ var KIBI_PERF_TRACE_MAX_BYTES = 512 * 1024;
50
+ var states = new Map;
51
+ var MAX_DURATION_MS = 60000;
52
+ var TRACE_LIMIT_RESERVE_BYTES = 96;
53
+ function isWithin(parent, candidate) {
54
+ const relative = path.relative(parent, candidate);
55
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
56
+ }
57
+ function privateTraceFile() {
58
+ if (process.env[KIBI_PERF_TIMINGS_ENV] !== "1")
59
+ return null;
60
+ const configuredDirectory = process.env[KIBI_PERF_TRACE_DIR_ENV];
61
+ if (!configuredDirectory || !path.isAbsolute(configuredDirectory))
62
+ return null;
63
+ try {
64
+ const directoryInfo = lstatSync(configuredDirectory);
65
+ if (!directoryInfo.isDirectory() || directoryInfo.isSymbolicLink()) {
66
+ return null;
67
+ }
68
+ const directory = realpathSync(configuredDirectory);
69
+ if (path.resolve(configuredDirectory) !== directory)
70
+ return null;
71
+ const directoryStats = statSync(directory);
72
+ if (typeof process.getuid !== "function" || directoryStats.uid !== process.getuid()) {
73
+ return null;
74
+ }
75
+ if ((directoryStats.mode & 63) !== 0) {
76
+ return null;
77
+ }
78
+ const currentDirectory = realpathSync(process.cwd());
79
+ if (isWithin(currentDirectory, directory))
80
+ return null;
81
+ const file = path.join(directory, `kibi-performance-${process.pid}.jsonl`);
82
+ let state = states.get(file);
83
+ if (!state) {
84
+ if (existsSync(file))
85
+ return null;
86
+ state = { bytes: 0, events: 0, disabled: false };
87
+ states.set(file, state);
88
+ }
89
+ if (state.disabled)
90
+ return null;
91
+ return { file, state };
92
+ } catch {
93
+ return null;
94
+ }
95
+ }
96
+ function writeAll(fd, bytes) {
97
+ let offset = 0;
98
+ while (offset < bytes.length) {
99
+ const written = writeSync(fd, bytes, offset, bytes.length - offset);
100
+ if (written <= 0)
101
+ throw new Error("Performance trace write made no progress");
102
+ offset += written;
103
+ }
104
+ }
105
+ function appendLine(file, state, line, exclusive) {
106
+ const fileInfo = existsSync(file) ? lstatSync(file) : null;
107
+ if (exclusive && fileInfo !== null || !exclusive && (!fileInfo?.isFile() || fileInfo.isSymbolicLink() || fileInfo.size !== state.bytes)) {
108
+ throw new Error("Performance trace file changed unexpectedly");
109
+ }
110
+ const flags = constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND | (constants.O_NOFOLLOW ?? 0) | (exclusive ? constants.O_EXCL : 0);
111
+ const fd = openSync(file, flags, 384);
112
+ try {
113
+ const bytes = Buffer.from(line, "utf8");
114
+ writeAll(fd, bytes);
115
+ state.bytes += bytes.length;
116
+ } finally {
117
+ closeSync(fd);
118
+ }
119
+ }
120
+ function appendLimitMarker(file, state, limit) {
121
+ const marker = `${JSON.stringify({ kind: "trace-limit", pid: process.pid, limit })}
122
+ `;
123
+ const byteLength = Buffer.byteLength(marker, "utf8");
124
+ if (state.bytes + byteLength <= KIBI_PERF_TRACE_MAX_BYTES) {
125
+ appendLine(file, state, marker, state.events === 0);
126
+ }
127
+ state.disabled = true;
128
+ }
129
+ function writePerformanceTraceEvent(event) {
130
+ if (!Number.isFinite(event.durationMs) || event.durationMs < 0 || event.durationMs > MAX_DURATION_MS) {
131
+ return;
132
+ }
133
+ const trace = privateTraceFile();
134
+ if (!trace)
135
+ return;
136
+ const durationMs = Math.round(event.durationMs * 1000) / 1000;
137
+ const line = `${JSON.stringify({
138
+ kind: event.kind,
139
+ durationMs,
140
+ pid: process.pid
141
+ })}
142
+ `;
143
+ const byteLength = Buffer.byteLength(line, "utf8");
144
+ try {
145
+ if (trace.state.events >= KIBI_PERF_TRACE_MAX_EVENTS || trace.state.bytes + byteLength > KIBI_PERF_TRACE_MAX_BYTES - TRACE_LIMIT_RESERVE_BYTES) {
146
+ appendLimitMarker(trace.file, trace.state, trace.state.events >= KIBI_PERF_TRACE_MAX_EVENTS ? "events" : "bytes");
147
+ return;
148
+ }
149
+ appendLine(trace.file, trace.state, line, trace.state.events === 0);
150
+ trace.state.events += 1;
151
+ } catch {
152
+ trace.state.disabled = true;
153
+ }
154
+ }
31
155
 
32
156
  // ../cli/src/prolog.ts
33
157
  import { spawn } from "node:child_process";
34
- import { existsSync } from "node:fs";
158
+ import { existsSync as existsSync3 } from "node:fs";
35
159
  import { createRequire as createRequire2 } from "node:module";
36
- import path from "node:path";
160
+ import path3 from "node:path";
161
+ import { performance } from "node:perf_hooks";
37
162
  import { fileURLToPath } from "node:url";
38
163
 
39
164
  // ../cli/src/env.ts
@@ -383,8 +508,336 @@ function unquoteAtom(value) {
383
508
  return trimmed;
384
509
  }
385
510
 
511
+ // ../cli/src/prolog/swipl-resolver.ts
512
+ import { execFileSync, spawnSync } from "node:child_process";
513
+ import {
514
+ constants as constants2,
515
+ accessSync,
516
+ existsSync as existsSync2,
517
+ readFileSync,
518
+ statSync as statSync2
519
+ } from "node:fs";
520
+ import path2 from "node:path";
521
+ import {
522
+ BUNDLED_BINARY_PATH,
523
+ MANIFEST_FILE,
524
+ PLATFORM_PACKAGES,
525
+ locatePlatformPackage,
526
+ platformKey,
527
+ sha256File,
528
+ validateBuildManifest
529
+ } from "kibi-swipl";
530
+ var MINIMUM_SWIPL_MAJOR = 9;
531
+
532
+ class SwiplResolutionError extends Error {
533
+ code;
534
+ platform;
535
+ packageName;
536
+ constructor(code, message, platform, packageName) {
537
+ super(message);
538
+ this.name = "SwiplResolutionError";
539
+ this.code = code;
540
+ this.platform = platform;
541
+ this.packageName = packageName;
542
+ }
543
+ }
544
+ function detectGlibc() {
545
+ if (process.platform !== "linux")
546
+ return;
547
+ try {
548
+ const report = process.report?.getReport?.();
549
+ if (report !== undefined) {
550
+ return typeof report.header?.glibcVersionRuntime === "string";
551
+ }
552
+ } catch {}
553
+ return !["/lib/ld-musl-x86_64.so.1", "/lib/ld-musl-aarch64.so.1"].some((loader) => existsSync2(loader));
554
+ }
555
+ function defaultRunVersion(bin) {
556
+ return execFileSync(bin, ["--version"], {
557
+ encoding: "utf8",
558
+ timeout: 1e4,
559
+ stdio: ["ignore", "pipe", "pipe"]
560
+ });
561
+ }
562
+ function defaultDeps() {
563
+ return {
564
+ platform: process.platform,
565
+ arch: process.arch,
566
+ glibc: detectGlibc(),
567
+ locatePackage: (name) => locatePlatformPackage(name),
568
+ runVersion: defaultRunVersion
569
+ };
570
+ }
571
+ function parseSwiplVersion(output) {
572
+ const match = /version\s+(\d+)\.(\d+)(?:\.(\d+))?/i.exec(output);
573
+ if (match === null)
574
+ return;
575
+ const [, major, minor, patch] = match;
576
+ return {
577
+ version: `${major}.${minor}${patch === undefined ? "" : `.${patch}`}`,
578
+ major: Number.parseInt(major ?? "0", 10)
579
+ };
580
+ }
581
+ function installCommand(platform) {
582
+ if (platform === "linux") {
583
+ return "sudo apt-add-repository ppa:swi-prolog/stable && sudo apt-get update && sudo apt-get install swi-prolog";
584
+ }
585
+ if (platform === "darwin")
586
+ return "brew install swi-prolog";
587
+ return "download the installer from https://www.swi-prolog.org/download/stable and add swipl to PATH";
588
+ }
589
+ function hostLabel(deps) {
590
+ const libc = deps.platform === "linux" && deps.glibc !== undefined ? ` (${deps.glibc ? "glibc" : "musl"})` : "";
591
+ return `${deps.platform}-${deps.arch}${libc}`;
592
+ }
593
+ function isExecutableFile(candidate) {
594
+ try {
595
+ if (!statSync2(candidate).isFile())
596
+ return false;
597
+ accessSync(candidate, constants2.X_OK);
598
+ return true;
599
+ } catch {
600
+ return false;
601
+ }
602
+ }
603
+ function inspectBundle(deps) {
604
+ const key = platformKey({
605
+ platform: deps.platform,
606
+ arch: deps.arch,
607
+ glibc: deps.glibc
608
+ });
609
+ if (key === undefined)
610
+ return { kind: "unsupported" };
611
+ const packageName = PLATFORM_PACKAGES[key].package;
612
+ const packageDir = deps.locatePackage(packageName);
613
+ if (packageDir === undefined)
614
+ return { kind: "missing", key, packageName };
615
+ const manifestPath = path2.join(packageDir, MANIFEST_FILE);
616
+ const binary = path2.join(packageDir, BUNDLED_BINARY_PATH);
617
+ if (!existsSync2(manifestPath)) {
618
+ if (!existsSync2(binary))
619
+ return { kind: "empty", key, packageName };
620
+ return {
621
+ kind: "corrupt",
622
+ key,
623
+ packageName,
624
+ reason: `${MANIFEST_FILE} is missing next to ${BUNDLED_BINARY_PATH}`
625
+ };
626
+ }
627
+ const corrupt = (reason) => ({
628
+ kind: "corrupt",
629
+ key,
630
+ packageName,
631
+ reason
632
+ });
633
+ let manifest;
634
+ let packageJson;
635
+ try {
636
+ manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
637
+ } catch (error) {
638
+ return corrupt(`${MANIFEST_FILE} is not valid JSON (${error instanceof Error ? error.message : String(error)})`);
639
+ }
640
+ try {
641
+ packageJson = JSON.parse(readFileSync(path2.join(packageDir, "package.json"), "utf8"));
642
+ } catch (error) {
643
+ return corrupt(`package.json is unreadable (${error instanceof Error ? error.message : String(error)})`);
644
+ }
645
+ const packageVersion = packageJson.kibi?.swiplVersion;
646
+ const checked = validateBuildManifest(manifest, {
647
+ target: key,
648
+ swiplVersion: typeof packageVersion === "string" ? packageVersion : undefined
649
+ });
650
+ if (!checked.ok)
651
+ return corrupt(checked.reason);
652
+ if (!isExecutableFile(binary)) {
653
+ return corrupt(`${BUNDLED_BINARY_PATH} is missing or not executable`);
654
+ }
655
+ let actual;
656
+ try {
657
+ actual = sha256File(binary);
658
+ } catch (error) {
659
+ return corrupt(`${BUNDLED_BINARY_PATH} is unreadable (${error instanceof Error ? error.message : String(error)})`);
660
+ }
661
+ if (actual !== checked.binarySha256) {
662
+ return corrupt(`${BUNDLED_BINARY_PATH} SHA-256 ${actual} does not match the manifest (${checked.binarySha256})`);
663
+ }
664
+ const home = path2.join(packageDir, checked.home);
665
+ let homeIsDirectory = false;
666
+ try {
667
+ homeIsDirectory = statSync2(home).isDirectory();
668
+ } catch {}
669
+ if (!homeIsDirectory)
670
+ return corrupt(`${checked.home} is missing`);
671
+ return {
672
+ kind: "ok",
673
+ key,
674
+ packageName,
675
+ resolved: {
676
+ bin: binary,
677
+ home,
678
+ version: checked.swiplVersion,
679
+ source: "bundled"
680
+ }
681
+ };
682
+ }
683
+ function probeVersion(bin, deps) {
684
+ let output;
685
+ try {
686
+ output = deps.runVersion(bin);
687
+ } catch (error) {
688
+ return {
689
+ kind: "unusable",
690
+ detail: error instanceof Error ? error.message : String(error)
691
+ };
692
+ }
693
+ const parsed = parseSwiplVersion(output);
694
+ if (parsed === undefined) {
695
+ return {
696
+ kind: "unusable",
697
+ detail: `unrecognized --version output ${JSON.stringify(output.trim().slice(0, 80))}`
698
+ };
699
+ }
700
+ if (parsed.major < MINIMUM_SWIPL_MAJOR) {
701
+ return { kind: "too-old", version: parsed.version };
702
+ }
703
+ return { kind: "ok", version: parsed.version };
704
+ }
705
+ function findOnPath(env, deps) {
706
+ for (const directory of (env.PATH ?? "").split(path2.delimiter)) {
707
+ if (directory === "" || !path2.isAbsolute(directory))
708
+ continue;
709
+ const candidate = path2.join(directory, "swipl");
710
+ if (!isExecutableFile(candidate))
711
+ continue;
712
+ const probe = probeVersion(candidate, deps);
713
+ if (probe.kind === "ok") {
714
+ return {
715
+ kind: "ok",
716
+ resolved: { bin: candidate, version: probe.version, source: "path" }
717
+ };
718
+ }
719
+ return probe.kind === "too-old" ? { kind: "too-old", bin: candidate, version: probe.version } : { kind: "unusable", bin: candidate, detail: probe.detail };
720
+ }
721
+ return { kind: "absent" };
722
+ }
723
+ function resolveFromEnv(override, deps) {
724
+ const platform = hostLabel(deps);
725
+ const key = platformKey({
726
+ platform: deps.platform,
727
+ arch: deps.arch,
728
+ glibc: deps.glibc
729
+ });
730
+ const packageName = key === undefined ? undefined : PLATFORM_PACKAGES[key].package;
731
+ const invalid = (detail) => new SwiplResolutionError("swipl_env_invalid", `KIBI_SWIPL=${override} ${detail}. Set KIBI_SWIPL to the absolute path of a SWI-Prolog ${MINIMUM_SWIPL_MAJOR}.0+ executable, to "system" to use swipl from PATH, or unset it to use the bundled runtime.`, platform, packageName);
732
+ if (!path2.isAbsolute(override))
733
+ return fail(invalid("is not an absolute path"));
734
+ if (!isExecutableFile(override)) {
735
+ return fail(invalid("is not an executable file"));
736
+ }
737
+ const probe = probeVersion(override, deps);
738
+ if (probe.kind === "unusable") {
739
+ return fail(invalid(`could not report its version (${probe.detail})`));
740
+ }
741
+ if (probe.kind === "too-old") {
742
+ return fail(invalid(`is SWI-Prolog ${probe.version}, but ${MINIMUM_SWIPL_MAJOR}.0 or newer is required`));
743
+ }
744
+ return { bin: override, version: probe.version, source: "env" };
745
+ }
746
+ function fail(error) {
747
+ throw error;
748
+ }
749
+ function notFoundError(deps, bundle, lookup) {
750
+ const platform = hostLabel(deps);
751
+ const command = installCommand(deps.platform);
752
+ const lines = [
753
+ `Kibi could not find a usable SWI-Prolog (${MINIMUM_SWIPL_MAJOR}.0 or newer is required).`,
754
+ `Detected platform: ${platform}.`
755
+ ];
756
+ let packageName;
757
+ if (bundle === "skipped") {
758
+ lines.push("Bundled SWI-Prolog: skipped because KIBI_SWIPL=system.");
759
+ const key = platformKey({
760
+ platform: deps.platform,
761
+ arch: deps.arch,
762
+ glibc: deps.glibc
763
+ });
764
+ if (key !== undefined)
765
+ packageName = PLATFORM_PACKAGES[key].package;
766
+ } else if (bundle.kind === "unsupported") {
767
+ lines.push(`Bundled SWI-Prolog: no bundled build exists for ${platform} (supported: ${Object.keys(PLATFORM_PACKAGES).join(", ")}).`);
768
+ } else {
769
+ packageName = bundle.packageName;
770
+ if (bundle.kind === "empty") {
771
+ lines.push(`Bundled SWI-Prolog: package ${bundle.packageName} is installed but carries no runtime (a source checkout that was not populated from a release build).`);
772
+ } else {
773
+ lines.push(`Bundled SWI-Prolog: package ${bundle.packageName} would cover this platform but is not installed. It is skipped by installs that omit optional dependencies (npm --omit=optional, --no-optional) and by pnpm supportedArchitectures settings that exclude this platform.`);
774
+ lines.push(` Add it with: npm install --save-dev ${bundle.packageName}`);
775
+ }
776
+ }
777
+ if (bundle === "skipped" && packageName !== undefined) {
778
+ lines.push(` To use it, unset KIBI_SWIPL and install ${packageName}.`);
779
+ }
780
+ switch (lookup.kind) {
781
+ case "absent":
782
+ lines.push("System SWI-Prolog: swipl was not found on PATH.");
783
+ break;
784
+ case "too-old":
785
+ lines.push(`System SWI-Prolog: swipl on PATH (${lookup.bin}) is version ${lookup.version}, older than ${MINIMUM_SWIPL_MAJOR}.0.`);
786
+ break;
787
+ case "unusable":
788
+ lines.push(`System SWI-Prolog: swipl on PATH (${lookup.bin}) could not report its version (${lookup.detail}).`);
789
+ break;
790
+ case "ok":
791
+ break;
792
+ }
793
+ lines.push(` Install it with: ${command}`);
794
+ lines.push(`Or set KIBI_SWIPL to the absolute path of a SWI-Prolog ${MINIMUM_SWIPL_MAJOR}.0+ executable.`);
795
+ return new SwiplResolutionError("swipl_not_found", lines.join(`
796
+ `), platform, packageName);
797
+ }
798
+ function resolveSwiplWith(env, deps) {
799
+ const override = env.KIBI_SWIPL?.trim() ?? "";
800
+ if (override !== "" && override !== "system") {
801
+ return resolveFromEnv(override, deps);
802
+ }
803
+ let bundle = "skipped";
804
+ if (override === "") {
805
+ bundle = inspectBundle(deps);
806
+ if (bundle.kind === "ok")
807
+ return bundle.resolved;
808
+ if (bundle.kind === "corrupt") {
809
+ throw new SwiplResolutionError("swipl_bundle_corrupt", [
810
+ `The bundled SWI-Prolog package ${bundle.packageName} is damaged: ${bundle.reason}.`,
811
+ `Detected platform: ${hostLabel(deps)}.`,
812
+ `Reinstall it (for example: npm install --save-dev ${bundle.packageName}), or set KIBI_SWIPL=system to use swipl from PATH instead.`
813
+ ].join(`
814
+ `), hostLabel(deps), bundle.packageName);
815
+ }
816
+ }
817
+ const lookup = findOnPath(env, deps);
818
+ if (lookup.kind === "ok")
819
+ return lookup.resolved;
820
+ throw notFoundError(deps, bundle, lookup);
821
+ }
822
+ var cache = new Map;
823
+ function resolveSwipl(env = process.env) {
824
+ const key = `${env.KIBI_SWIPL ?? ""}\x00${env.PATH ?? ""}`;
825
+ const cached = cache.get(key);
826
+ if (cached !== undefined)
827
+ return cached;
828
+ const resolved = resolveSwiplWith(env, defaultDeps());
829
+ cache.set(key, resolved);
830
+ return resolved;
831
+ }
832
+ function swiplIdentity(resolved) {
833
+ return `${resolved.bin}@${resolved.version}`;
834
+ }
835
+ function swiplChildEnv(resolved) {
836
+ return resolved.home === undefined ? {} : { SWI_HOME_DIR: resolved.home };
837
+ }
838
+
386
839
  // ../cli/src/prolog.ts
387
- var importMetaDir = path.dirname(fileURLToPath(import.meta.url));
840
+ var importMetaDir = path3.dirname(fileURLToPath(import.meta.url));
388
841
  var DEFAULT_PROLOG_OUTPUT_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
389
842
  var PROLOG_OUTPUT_OVERFLOW_ERROR = "Query exceeded bounded Prolog output capacity (ENOBUFS); narrow the operation or reduce stored entity size";
390
843
  var INTERACTIVE_QUERY_FRAME_END = "__KIBI_QUERY_FRAME_END__";
@@ -398,9 +851,9 @@ function packageVersion(packagePath) {
398
851
  }
399
852
  }
400
853
  var KIBI_PACKAGE_VERSIONS = [
401
- `kibi-cli@${packageVersion(path.join(importMetaDir, "..", "package.json"))}`,
402
- `kibi-core@${packageVersion(path.join(importMetaDir, "..", "..", "core", "package.json"))}`,
403
- `kibi-mcp@${packageVersion(path.join(importMetaDir, "..", "..", "mcp", "package.json"))}`
854
+ `kibi-cli@${packageVersion(path3.join(importMetaDir, "..", "package.json"))}`,
855
+ `kibi-core@${packageVersion(path3.join(importMetaDir, "..", "..", "core", "package.json"))}`,
856
+ `kibi-mcp@${packageVersion(path3.join(importMetaDir, "..", "..", "mcp", "package.json"))}`
404
857
  ].join(",");
405
858
  function resolveKbPlPath() {
406
859
  const overrideKbPath = getKbPlPathOverride();
@@ -412,17 +865,17 @@ function resolveKbPlPath() {
412
865
  return require2.resolve("kibi-core/src/kb.pl");
413
866
  } catch {
414
867
  const coreMain = require2.resolve("kibi-core");
415
- const coreDir = path.dirname(coreMain);
416
- return path.join(coreDir, "src", "kb.pl");
868
+ const coreDir = path3.dirname(coreMain);
869
+ return path3.join(coreDir, "src", "kb.pl");
417
870
  }
418
871
  } catch {}
419
872
  let currentDir = importMetaDir;
420
- while (currentDir !== path.dirname(currentDir)) {
421
- const candidate = path.join(currentDir, "packages", "core", "src", "kb.pl");
422
- if (existsSync(candidate)) {
873
+ while (currentDir !== path3.dirname(currentDir)) {
874
+ const candidate = path3.join(currentDir, "packages", "core", "src", "kb.pl");
875
+ if (existsSync3(candidate)) {
423
876
  return candidate;
424
877
  }
425
- currentDir = path.dirname(currentDir);
878
+ currentDir = path3.dirname(currentDir);
426
879
  }
427
880
  throw new Error("Unable to resolve kb.pl. Expected kibi-core to be installed (node_modules) " + "or to be running inside the monorepo checkout.");
428
881
  }
@@ -450,7 +903,8 @@ function bindProcessExitHandler(current, terminate, on = (event, listener) => pr
450
903
 
451
904
  class PrologProcess {
452
905
  process = null;
453
- swiplPath;
906
+ explicitSwiplPath;
907
+ swiplResolver;
454
908
  timeout;
455
909
  outputBuffer = "";
456
910
  outputBufferBytes = 0;
@@ -468,7 +922,8 @@ class PrologProcess {
468
922
  interactiveStarted = false;
469
923
  terminationReason = null;
470
924
  constructor(options = {}) {
471
- this.swiplPath = options.swiplPath || "swipl";
925
+ this.explicitSwiplPath = options.swiplPath || undefined;
926
+ this.swiplResolver = options.swiplResolver ?? (() => resolveSwipl());
472
927
  this.timeout = options.timeout || 30000;
473
928
  this.maxOutputBytes = options.maxOutputBytes !== undefined && Number.isInteger(options.maxOutputBytes) && options.maxOutputBytes > 0 ? options.maxOutputBytes : DEFAULT_PROLOG_OUTPUT_MAX_BUFFER_BYTES;
474
929
  this.useOneShotMode = options.oneShot ?? false;
@@ -482,15 +937,24 @@ class PrologProcess {
482
937
  needsRestart() {
483
938
  return this.interactiveStarted && !this.isProcessUsable();
484
939
  }
940
+ launchTarget() {
941
+ const explicit = this.explicitSwiplPath;
942
+ if (explicit !== undefined)
943
+ return { bin: explicit, env: {} };
944
+ const resolved = this.swiplResolver();
945
+ return { bin: resolved.bin, env: swiplChildEnv(resolved) };
946
+ }
485
947
  async start() {
486
- if (!existsSync(this.swiplPath) && this.swiplPath !== "swipl") {
487
- throw new Error(`SWI-Prolog not found at ${this.swiplPath}. Please install SWI-Prolog or check your PATH.`);
948
+ const explicit = this.explicitSwiplPath;
949
+ if (explicit !== undefined && !existsSync3(explicit) && explicit !== "swipl") {
950
+ throw new Error(`SWI-Prolog not found at ${explicit}. Please install SWI-Prolog or check your PATH.`);
488
951
  }
952
+ const launch = this.launchTarget();
489
953
  const kbPath = resolveKbPlPath();
490
954
  this.interactiveStarted = true;
491
955
  this.terminationReason = null;
492
956
  this.invalidateCache();
493
- this.process = spawn(this.swiplPath, [
957
+ this.process = spawn(launch.bin, [
494
958
  "-g",
495
959
  `use_module('${kbPath}'), use_module(library(semweb/rdf_db)), set_prolog_flag(answer_write_options, [max_depth(0), quoted(true)])`,
496
960
  "--quiet"
@@ -498,6 +962,7 @@ class PrologProcess {
498
962
  detached: process.platform !== "win32",
499
963
  env: {
500
964
  ...process.env,
965
+ ...launch.env,
501
966
  KIBI_RUNTIME_NAME: process.versions.bun !== undefined ? "bun" : "node",
502
967
  KIBI_RUNTIME_VERSION: process.versions.bun ?? process.versions.node ?? "unknown",
503
968
  KIBI_PACKAGE_VERSIONS: process.env.KIBI_PACKAGE_VERSIONS ?? KIBI_PACKAGE_VERSIONS
@@ -546,12 +1011,22 @@ class PrologProcess {
546
1011
  this.clearQueryBuffers();
547
1012
  }
548
1013
  async query(goal) {
1014
+ if (!this.useOneShotMode && this.needsRestart()) {
1015
+ throw this.lostProcessError();
1016
+ }
549
1017
  const isSingleGoal = typeof goal === "string";
550
1018
  const goalKey = isSingleGoal ? goal : null;
551
1019
  const cacheable = goalKey !== null && this.isCacheableGoal(goalKey);
552
1020
  if (cacheable) {
1021
+ const cacheLookupStartedAt = process.env.KIBI_PERF_TIMINGS === "1" ? performance.now() : null;
553
1022
  const cachedResult = this.cache.get(goalKey);
554
1023
  if (cachedResult) {
1024
+ if (cacheLookupStartedAt !== null) {
1025
+ writePerformanceTraceEvent({
1026
+ kind: "prolog-process-cache-hit",
1027
+ durationMs: performance.now() - cacheLookupStartedAt
1028
+ });
1029
+ }
555
1030
  return cachedResult;
556
1031
  }
557
1032
  }
@@ -696,12 +1171,22 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
696
1171
  releaseQuery = resolve;
697
1172
  });
698
1173
  await previousQuery;
1174
+ const tracingEnabled = process.env.KIBI_PERF_TIMINGS === "1";
1175
+ let roundTripStartedAt = null;
699
1176
  try {
700
1177
  if (!this.isProcessUsable()) {
701
1178
  throw this.lostProcessError();
702
1179
  }
1180
+ if (tracingEnabled)
1181
+ roundTripStartedAt = performance.now();
703
1182
  return await runInteractiveQuery();
704
1183
  } finally {
1184
+ if (roundTripStartedAt !== null) {
1185
+ writePerformanceTraceEvent({
1186
+ kind: "prolog-round-trip",
1187
+ durationMs: performance.now() - roundTripStartedAt
1188
+ });
1189
+ }
705
1190
  releaseQuery();
706
1191
  }
707
1192
  }
@@ -783,10 +1268,12 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
783
1268
  const packageVersions = process.env.KIBI_PACKAGE_VERSIONS ?? KIBI_PACKAGE_VERSIONS;
784
1269
  let child;
785
1270
  try {
786
- child = spawn(this.swiplPath, ["-q", "-g", prologGoal, "-t", "halt"], {
1271
+ const launch = this.launchTarget();
1272
+ child = spawn(launch.bin, ["-q", "-g", prologGoal, "-t", "halt"], {
787
1273
  detached: process.platform !== "win32",
788
1274
  env: {
789
1275
  ...process.env,
1276
+ ...launch.env,
790
1277
  KIBI_GOAL: combinedGoal,
791
1278
  KIBI_RUNTIME_NAME: runtimeName,
792
1279
  KIBI_RUNTIME_VERSION: runtimeVersion,
@@ -1042,6 +1529,18 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
1042
1529
  return { message: this.translateError(errorText) };
1043
1530
  }
1044
1531
  translateError(errorText) {
1532
+ const existence = errorText.match(/^__KIBI_ERROR__:error\(existence_error\((key|procedure),([^,()\r\n]+)(?:,|\),)/m);
1533
+ const identifier = existence?.[2]?.trim().replace(/^'([^']+)'$/, "$1");
1534
+ if (existence?.[1] === "key" && identifier !== undefined) {
1535
+ if (/^[A-Za-z][A-Za-z0-9_-]{0,95}$/.test(identifier)) {
1536
+ return `Predicate or file not found (missing dictionary key: ${identifier})`;
1537
+ }
1538
+ }
1539
+ if (existence?.[1] === "procedure" && identifier !== undefined) {
1540
+ if (/^(?:[A-Za-z][A-Za-z0-9_]{0,95}:)?[A-Za-z][A-Za-z0-9_]{0,95}\/[0-9]{1,3}$/.test(identifier)) {
1541
+ return `Predicate or file not found (missing procedure: ${identifier})`;
1542
+ }
1543
+ }
1045
1544
  const cleanError = errorText.replace(/^__KIBI_(?:STAGE|RUNTIME|ERROR)__:[^\r\n]*\r?\n?/gm, "");
1046
1545
  if (cleanError.includes("stale_snapshot")) {
1047
1546
  return "KB snapshot is stale; reattach or refresh the runtime before retrying (stale_snapshot)";
@@ -1072,6 +1571,8 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
1072
1571
  if (cleanError.includes("existence_error") || cleanError.includes("Unknown procedure")) {
1073
1572
  return "Predicate or file not found";
1074
1573
  }
1574
+ if (existence !== null)
1575
+ return "Predicate or file not found";
1075
1576
  if (cleanError.includes("permission_error")) {
1076
1577
  return "Access denied or KB locked";
1077
1578
  }
@@ -1131,8 +1632,8 @@ writeln('${INTERACTIVE_QUERY_FRAME_END}').
1131
1632
  }
1132
1633
 
1133
1634
  // ../cli/src/prolog/store-lock.ts
1134
- import { existsSync as existsSync2, rmSync } from "node:fs";
1135
- import { readFileSync } from "node:fs";
1635
+ import { existsSync as existsSync4, rmSync } from "node:fs";
1636
+ import { readFileSync as readFileSync2 } from "node:fs";
1136
1637
  import { dirname, join } from "node:path";
1137
1638
  var cachedBootId;
1138
1639
  function currentBootId() {
@@ -1143,7 +1644,7 @@ function currentBootId() {
1143
1644
  return cachedBootId;
1144
1645
  }
1145
1646
  try {
1146
- const raw = readFileSync("/proc/sys/kernel/random/boot_id", "utf8");
1647
+ const raw = readFileSync2("/proc/sys/kernel/random/boot_id", "utf8");
1147
1648
  cachedBootId = raw.trim();
1148
1649
  } catch {
1149
1650
  cachedBootId = null;
@@ -1182,7 +1683,7 @@ function breakStoreLock(rdfDirectory) {
1182
1683
  join(dirname(rdfDirectory), ".kibi-lock-owner.json")
1183
1684
  ];
1184
1685
  for (const candidate of candidates) {
1185
- if (existsSync2(candidate)) {
1686
+ if (existsSync4(candidate)) {
1186
1687
  rmSync(candidate, { force: true });
1187
1688
  }
1188
1689
  }
@@ -1236,31 +1737,31 @@ import {
1236
1737
  execFileSync as rawExecFileSync,
1237
1738
  execSync as rawExecSync
1238
1739
  } from "node:child_process";
1239
- import * as path3 from "node:path";
1740
+ import * as path5 from "node:path";
1240
1741
 
1241
1742
  // ../cli/src/utils/branch-store-locator.ts
1242
1743
  import { createHash } from "node:crypto";
1243
1744
  import {
1244
- existsSync as existsSync3,
1745
+ existsSync as existsSync5,
1245
1746
  mkdirSync,
1246
- readFileSync as readFileSync2,
1747
+ readFileSync as readFileSync3,
1247
1748
  readdirSync,
1248
- statSync,
1749
+ statSync as statSync3,
1249
1750
  writeFileSync
1250
1751
  } from "node:fs";
1251
- import path2 from "node:path";
1752
+ import path4 from "node:path";
1252
1753
  var BRANCH_STORE_MANIFEST_VERSION = 1;
1253
1754
  function branchStoreKey(branch) {
1254
1755
  return createHash("sha256").update(branch, "utf8").digest("hex");
1255
1756
  }
1256
1757
  function branchStoresRoot(workspaceRoot) {
1257
- return path2.join(path2.resolve(workspaceRoot), ".kb", "branches");
1758
+ return path4.join(path4.resolve(workspaceRoot), ".kb", "branches");
1258
1759
  }
1259
1760
  function branchStorePath(workspaceRoot, branch) {
1260
- return path2.join(branchStoresRoot(workspaceRoot), branchStoreKey(branch));
1761
+ return path4.join(branchStoresRoot(workspaceRoot), branchStoreKey(branch));
1261
1762
  }
1262
1763
  function branchStoreManifestPath(storePath) {
1263
- return path2.join(storePath, "branch.json");
1764
+ return path4.join(storePath, "branch.json");
1264
1765
  }
1265
1766
  function expectedBranchStoreManifest(branch) {
1266
1767
  return {
@@ -1271,10 +1772,10 @@ function expectedBranchStoreManifest(branch) {
1271
1772
  }
1272
1773
  function readBranchStoreManifest(storePath) {
1273
1774
  const manifestPath = branchStoreManifestPath(storePath);
1274
- if (!existsSync3(manifestPath))
1775
+ if (!existsSync5(manifestPath))
1275
1776
  return null;
1276
1777
  try {
1277
- const parsed = JSON.parse(readFileSync2(manifestPath, "utf8"));
1778
+ const parsed = JSON.parse(readFileSync3(manifestPath, "utf8"));
1278
1779
  if (parsed.version !== BRANCH_STORE_MANIFEST_VERSION || typeof parsed.branch !== "string" || typeof parsed.key !== "string") {
1279
1780
  return null;
1280
1781
  }
@@ -1290,7 +1791,7 @@ function readBranchStoreManifest(storePath) {
1290
1791
  function branchStoreManifestMatches(storePath, branch) {
1291
1792
  const manifest = readBranchStoreManifest(storePath);
1292
1793
  const expected = expectedBranchStoreManifest(branch);
1293
- return manifest !== null && manifest.version === expected.version && manifest.branch === expected.branch && manifest.key === expected.key && path2.basename(storePath) === expected.key;
1794
+ return manifest !== null && manifest.version === expected.version && manifest.branch === expected.branch && manifest.key === expected.key && path4.basename(storePath) === expected.key;
1294
1795
  }
1295
1796
  function ensureBranchStoreManifest(workspaceRoot, branch) {
1296
1797
  const storePath = branchStorePath(workspaceRoot, branch);
@@ -1301,7 +1802,7 @@ function ensureBranchStoreManifest(workspaceRoot, branch) {
1301
1802
  throw new Error(`Branch store identity mismatch at ${storePath}; refusing to attach it to '${branch}'.`);
1302
1803
  }
1303
1804
  if (existing === null) {
1304
- if (existsSync3(manifestPath)) {
1805
+ if (existsSync5(manifestPath)) {
1305
1806
  throw new Error(`Branch store manifest is invalid at ${manifestPath}; refusing to overwrite it.`);
1306
1807
  }
1307
1808
  const entries = readdirSync(storePath);
@@ -1315,7 +1816,7 @@ function ensureBranchStoreManifest(workspaceRoot, branch) {
1315
1816
  }
1316
1817
 
1317
1818
  // ../cli/src/utils/branch-resolver.ts
1318
- var defaultDeps = {
1819
+ var defaultDeps2 = {
1319
1820
  execSync: rawExecSync,
1320
1821
  execFileSync: rawExecFileSync
1321
1822
  };
@@ -1335,7 +1836,7 @@ function isValidBranchName(name) {
1335
1836
  const codePoint = character.codePointAt(0) ?? 0;
1336
1837
  return codePoint <= 32 || codePoint === 127;
1337
1838
  });
1338
- if (name.includes("..") || path3.isAbsolute(name) || name.startsWith("/")) {
1839
+ if (name.includes("..") || path5.isAbsolute(name) || name.startsWith("/")) {
1339
1840
  return false;
1340
1841
  }
1341
1842
  if (name.includes("//") || name.endsWith("/") || name.endsWith(".") || name.includes("\\") || name.startsWith("-") || name.includes("@{") || name.includes("..") || hasControlCharacter || /[~^:?*\[\]]/.test(name)) {
@@ -1346,7 +1847,7 @@ function isValidBranchName(name) {
1346
1847
  return false;
1347
1848
  }
1348
1849
  try {
1349
- defaultDeps.execFileSync("git", ["check-ref-format", "--branch", name], {
1850
+ defaultDeps2.execFileSync("git", ["check-ref-format", "--branch", name], {
1350
1851
  stdio: ["ignore", "ignore", "ignore"],
1351
1852
  timeout: 5000
1352
1853
  });
@@ -1356,10 +1857,43 @@ function isValidBranchName(name) {
1356
1857
  }
1357
1858
  }
1358
1859
 
1860
+ // ../cli/src/utils/canonical-path.ts
1861
+ import { lstatSync as lstatSync2, realpathSync as realpathSync2 } from "node:fs";
1862
+ import path6 from "node:path";
1863
+ function canonicalFilesystemPath(candidate) {
1864
+ let existing = path6.resolve(candidate);
1865
+ const missing = [];
1866
+ for (;; ) {
1867
+ try {
1868
+ return path6.resolve(realpathSync2.native(existing), ...missing);
1869
+ } catch (error) {
1870
+ if (error.code !== "ENOENT")
1871
+ throw error;
1872
+ let entry;
1873
+ try {
1874
+ entry = lstatSync2(existing);
1875
+ } catch (statError) {
1876
+ if (statError.code !== "ENOENT")
1877
+ throw statError;
1878
+ }
1879
+ if (entry !== undefined)
1880
+ throw error;
1881
+ const parent = path6.dirname(existing);
1882
+ if (parent === existing)
1883
+ throw error;
1884
+ missing.unshift(path6.basename(existing));
1885
+ existing = parent;
1886
+ }
1887
+ }
1888
+ }
1889
+
1359
1890
  // ../cli/src/engine.ts
1360
1891
  var ENGINE_PROTOCOL_VERSION = 1;
1361
1892
  var ENGINE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
1362
1893
  var ENGINE_PACKAGE_VERSIONS = process.env.KIBI_PACKAGE_VERSIONS ?? "unknown";
1894
+ function engineSwiplIdentity() {
1895
+ return swiplIdentity(resolveSwipl());
1896
+ }
1363
1897
  var ENGINE_QUERY_CACHE_MAX_ENTRIES = 128;
1364
1898
  var ENGINE_QUERY_CACHE_MAX_RESULT_BYTES = 8 * 1024 * 1024;
1365
1899
  var ENGINE_FRESHNESS_CACHE_MS = 100;
@@ -1370,18 +1904,18 @@ function requestEngineSignalShutdown(shutdown) {
1370
1904
  };
1371
1905
  }
1372
1906
  function readJournalGeneration(branchPath) {
1373
- const currentPath = path4.join(branchPath, "CURRENT");
1374
- if (!existsSync4(currentPath))
1907
+ const currentPath = path7.join(branchPath, "CURRENT");
1908
+ if (!existsSync6(currentPath))
1375
1909
  return "";
1376
- return readFileSync3(currentPath, "utf8").trim();
1910
+ return readFileSync4(currentPath, "utf8").trim();
1377
1911
  }
1378
1912
  function readEngineAttachmentIdentity(branchPath) {
1379
- if (!existsSync4(branchPath))
1913
+ if (!existsSync6(branchPath))
1380
1914
  return null;
1381
- const stats = statSync2(branchPath);
1382
- let resolved = path4.resolve(branchPath);
1915
+ const stats = statSync4(branchPath);
1916
+ let resolved = path7.resolve(branchPath);
1383
1917
  try {
1384
- resolved = realpathSync(branchPath);
1918
+ resolved = realpathSync3(branchPath);
1385
1919
  } catch {}
1386
1920
  return {
1387
1921
  path: resolved,
@@ -1513,42 +2047,85 @@ function parseFrames(buffer, onFrame) {
1513
2047
  return buffer.subarray(cursor);
1514
2048
  }
1515
2049
  function runtimeDirectory() {
1516
- const configured = process.env.KIBI_RUNTIME_DIR ?? process.env.XDG_RUNTIME_DIR ?? path4.join(os.tmpdir(), "kibi-runtime");
1517
- const candidates = [configured, path4.join(os.tmpdir(), "kibi-runtime")];
2050
+ const configured = process.env.KIBI_RUNTIME_DIR ?? process.env.XDG_RUNTIME_DIR ?? path7.join(os.tmpdir(), "kibi-runtime");
2051
+ if (process.platform === "win32") {
2052
+ for (const candidate of [
2053
+ configured,
2054
+ path7.join(os.tmpdir(), "kibi-runtime")
2055
+ ]) {
2056
+ try {
2057
+ mkdirSync2(candidate, { recursive: true, mode: 448 });
2058
+ const probe = path7.join(candidate, `.kibi-write-${process.pid}`);
2059
+ writeFileSync2(probe, "", { mode: 384 });
2060
+ unlinkSync(probe);
2061
+ return candidate;
2062
+ } catch {}
2063
+ }
2064
+ throw new Error("Unable to create a writable Kibi engine runtime directory");
2065
+ }
2066
+ const euid = process.geteuid?.();
2067
+ if (euid === undefined)
2068
+ throw new Error("Kibi engine runtime euid unavailable");
2069
+ let configuredIdentity;
2070
+ try {
2071
+ configuredIdentity = canonicalFilesystemPath(configured);
2072
+ } catch {
2073
+ configuredIdentity = path7.resolve(configured);
2074
+ }
2075
+ const configuredKey = createHash2("sha256").update(configuredIdentity).digest("hex").slice(0, 32);
2076
+ const candidates = [
2077
+ configured,
2078
+ path7.join("/tmp", `kb-${euid}-${configuredKey}`)
2079
+ ];
2080
+ const maximumBytes = process.platform === "linux" ? 107 : 103;
2081
+ const socketName = `kibi-${"0".repeat(32)}.sock`;
1518
2082
  for (const candidate of candidates) {
1519
2083
  try {
2084
+ try {
2085
+ if (lstatSync3(candidate).isSymbolicLink())
2086
+ continue;
2087
+ } catch (error) {
2088
+ if (error.code !== "ENOENT")
2089
+ throw error;
2090
+ }
1520
2091
  mkdirSync2(candidate, { recursive: true, mode: 448 });
1521
- const probe = path4.join(candidate, `.kibi-write-${process.pid}`);
1522
- writeFileSync2(probe, "", { mode: 384 });
2092
+ const directory = lstatSync3(candidate);
2093
+ if (!directory.isDirectory() || directory.uid !== euid || (directory.mode & 63) !== 0)
2094
+ continue;
2095
+ const canonical = canonicalFilesystemPath(candidate);
2096
+ if (Buffer.byteLength(path7.join(canonical, socketName), "utf8") > maximumBytes)
2097
+ continue;
2098
+ const probe = path7.join(canonical, `.kibi-write-${randomUUID()}`);
2099
+ writeFileSync2(probe, "", { mode: 384, flag: "wx" });
1523
2100
  unlinkSync(probe);
1524
- return candidate;
2101
+ return canonical;
1525
2102
  } catch {}
1526
2103
  }
1527
2104
  throw new Error("Unable to create a writable Kibi engine runtime directory");
1528
2105
  }
1529
2106
  function fsyncPath(filePath) {
1530
- if (!existsSync4(filePath))
2107
+ if (!existsSync6(filePath))
1531
2108
  return;
1532
2109
  let descriptor = null;
1533
2110
  try {
1534
- descriptor = openSync(filePath, "r");
2111
+ descriptor = openSync2(filePath, "r");
1535
2112
  fsyncSync(descriptor);
1536
2113
  } finally {
1537
2114
  if (descriptor !== null)
1538
- closeSync(descriptor);
2115
+ closeSync2(descriptor);
1539
2116
  }
1540
2117
  }
1541
2118
  function fsyncJournaledBranchStore(branchPath) {
1542
- const rdfRoot = path4.join(branchPath, "rdf");
2119
+ const rdfRoot = path7.join(branchPath, "rdf");
1543
2120
  const directories = [];
1544
- const pending = existsSync4(rdfRoot) ? [rdfRoot] : [];
2121
+ const pending = existsSync6(rdfRoot) ? [rdfRoot] : [];
1545
2122
  while (pending.length > 0) {
1546
2123
  const directory = pending.pop();
1547
2124
  if (directory === undefined)
1548
2125
  break;
1549
2126
  directories.push(directory);
1550
2127
  for (const entry of readdirSync2(directory, { withFileTypes: true })) {
1551
- const entryPath = path4.join(directory, entry.name);
2128
+ const entryPath = path7.join(directory, entry.name);
1552
2129
  if (entry.isDirectory())
1553
2130
  pending.push(entryPath);
1554
2131
  else if (entry.isFile() && entry.name !== "lock")
@@ -1556,7 +2133,7 @@ function fsyncJournaledBranchStore(branchPath) {
1556
2133
  }
1557
2134
  }
1558
2135
  for (const metadata of ["CURRENT", "storage.json", "kb.rdf"]) {
1559
- fsyncPath(path4.join(branchPath, metadata));
2136
+ fsyncPath(path7.join(branchPath, metadata));
1560
2137
  }
1561
2138
  if (process.platform !== "win32") {
1562
2139
  for (const directory of directories.reverse())
@@ -1565,33 +2142,27 @@ function fsyncJournaledBranchStore(branchPath) {
1565
2142
  }
1566
2143
  }
1567
2144
  function engineSocketPath(workspaceRoot, branch) {
1568
- const canonicalRoot = (() => {
1569
- try {
1570
- return realpathSync(workspaceRoot);
1571
- } catch {
1572
- return path4.resolve(workspaceRoot);
1573
- }
1574
- })();
2145
+ const canonicalRoot = canonicalFilesystemPath(workspaceRoot);
1575
2146
  const key = createHash2("sha256").update(`${canonicalRoot}\x00${branch}`).digest("hex").slice(0, 32);
1576
2147
  if (process.platform === "win32") {
1577
2148
  return `\\\\.\\pipe\\kibi-${key}`;
1578
2149
  }
1579
- return path4.join(runtimeDirectory(), `kibi-${key}.sock`);
2150
+ return path7.join(runtimeDirectory(), `kibi-${key}.sock`);
1580
2151
  }
1581
2152
  function enginePidPath(workspaceRoot, branch) {
1582
2153
  const socket = engineSocketPath(workspaceRoot, branch);
1583
2154
  if (process.platform === "win32") {
1584
- return path4.join(runtimeDirectory(), `kibi-${createHash2("sha256").update(`${path4.resolve(workspaceRoot)}\x00${branch}`).digest("hex")}.pid`);
2155
+ return path7.join(runtimeDirectory(), `kibi-${createHash2("sha256").update(`${path7.resolve(workspaceRoot)}\x00${branch}`).digest("hex")}.pid`);
1585
2156
  }
1586
2157
  return `${socket}.pid`;
1587
2158
  }
1588
2159
  function recoverStaleJournalLock(branchPath) {
1589
- const lockPath = path4.join(branchPath, "rdf", "lock");
1590
- if (!existsSync4(lockPath))
2160
+ const lockPath = path7.join(branchPath, "rdf", "lock");
2161
+ if (!existsSync6(lockPath))
1591
2162
  return;
1592
2163
  let contents = "";
1593
2164
  try {
1594
- contents = readFileSync3(lockPath, "utf8");
2165
+ contents = readFileSync4(lockPath, "utf8");
1595
2166
  } catch {
1596
2167
  return;
1597
2168
  }
@@ -1639,27 +2210,27 @@ function connectSocket(socketPath, timeoutMs) {
1639
2210
  }
1640
2211
  async function ensureJournaledBranchStoreAsync(branchPath) {
1641
2212
  mkdirSync2(branchPath, { recursive: true });
1642
- const markerPath = path4.join(branchPath, "storage.json");
1643
- const marker = existsSync4(markerPath) ? readFileSync3(markerPath, "utf8") : "";
2213
+ const markerPath = path7.join(branchPath, "storage.json");
2214
+ const marker = existsSync6(markerPath) ? readFileSync4(markerPath, "utf8") : "";
1644
2215
  if (marker.includes("kibi.rdf-journal.v1")) {
1645
- const rdfDirectory = path4.join(branchPath, "rdf");
1646
- const currentPath = path4.join(branchPath, "CURRENT");
1647
- const sentinelPath = path4.join(branchPath, "kb.rdf");
1648
- if (!existsSync4(rdfDirectory) || !existsSync4(currentPath)) {
2216
+ const rdfDirectory = path7.join(branchPath, "rdf");
2217
+ const currentPath = path7.join(branchPath, "CURRENT");
2218
+ const sentinelPath = path7.join(branchPath, "kb.rdf");
2219
+ if (!existsSync6(rdfDirectory) || !existsSync6(currentPath)) {
1649
2220
  recoverInterruptedGeneration(branchPath);
1650
- if (existsSync4(rdfDirectory) && existsSync4(currentPath)) {
2221
+ if (existsSync6(rdfDirectory) && existsSync6(currentPath)) {
1651
2222
  recoverStaleJournalLock(branchPath);
1652
2223
  archiveLegacyFiles(branchPath);
1653
- if (!existsSync4(sentinelPath)) {
2224
+ if (!existsSync6(sentinelPath)) {
1654
2225
  writeFileSync2(sentinelPath, `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
1655
2226
  `, { mode: 384 });
1656
2227
  }
1657
2228
  return;
1658
2229
  }
1659
- const legacyRdf = path4.join(branchPath, "kb.rdf");
1660
- const legacyAudit = path4.join(branchPath, "audit.log");
1661
- const legacyContents = existsSync4(legacyRdf) ? readFileSync3(legacyRdf, "utf8") : "";
1662
- if (existsSync4(legacyAudit) || existsSync4(legacyRdf) && !legacyContents.includes("kibi.rdf-journal.v1")) {
2230
+ const legacyRdf = path7.join(branchPath, "kb.rdf");
2231
+ const legacyAudit = path7.join(branchPath, "audit.log");
2232
+ const legacyContents = existsSync6(legacyRdf) ? readFileSync4(legacyRdf, "utf8") : "";
2233
+ if (existsSync6(legacyAudit) || existsSync6(legacyRdf) && !legacyContents.includes("kibi.rdf-journal.v1")) {
1663
2234
  rmSync2(rdfDirectory, { recursive: true, force: true });
1664
2235
  rmSync2(currentPath, { force: true });
1665
2236
  rmSync2(markerPath, { force: true });
@@ -1669,36 +2240,36 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
1669
2240
  } else {
1670
2241
  recoverStaleJournalLock(branchPath);
1671
2242
  archiveLegacyFiles(branchPath);
1672
- if (!existsSync4(sentinelPath)) {
2243
+ if (!existsSync6(sentinelPath)) {
1673
2244
  writeFileSync2(sentinelPath, `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
1674
2245
  `, { mode: 384 });
1675
2246
  }
1676
2247
  return;
1677
2248
  }
1678
2249
  }
1679
- const legacyRdf = path4.join(branchPath, "kb.rdf");
1680
- const legacyAudit = path4.join(branchPath, "audit.log");
1681
- if (!existsSync4(legacyRdf) && !existsSync4(legacyAudit)) {
1682
- mkdirSync2(path4.join(branchPath, "rdf"), { recursive: true });
2250
+ const legacyRdf = path7.join(branchPath, "kb.rdf");
2251
+ const legacyAudit = path7.join(branchPath, "audit.log");
2252
+ if (!existsSync6(legacyRdf) && !existsSync6(legacyAudit)) {
2253
+ mkdirSync2(path7.join(branchPath, "rdf"), { recursive: true });
1683
2254
  writeFileSync2(markerPath, `{"format":"kibi.rdf-journal.v1","schemaVersion":1}
1684
2255
  `, { mode: 384 });
1685
- writeFileSync2(path4.join(branchPath, "CURRENT"), `generation-1:0
2256
+ writeFileSync2(path7.join(branchPath, "CURRENT"), `generation-1:0
1686
2257
  `, {
1687
2258
  mode: 384
1688
2259
  });
1689
- writeFileSync2(path4.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
2260
+ writeFileSync2(path7.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
1690
2261
  `, { mode: 384 });
1691
2262
  return;
1692
2263
  }
1693
- if (existsSync4(legacyRdf)) {
1694
- const legacyContents = readFileSync3(legacyRdf, "utf8");
2264
+ if (existsSync6(legacyRdf)) {
2265
+ const legacyContents = readFileSync4(legacyRdf, "utf8");
1695
2266
  if (!/<rdf:RDF(?:\s|>)/.test(legacyContents)) {
1696
2267
  throw new Error(`Legacy Kibi store is corrupt at ${legacyRdf}: expected RDF/XML root`);
1697
2268
  }
1698
2269
  }
1699
- const parent = path4.dirname(branchPath);
1700
- const migrationKey = createHash2("sha256").update(path4.resolve(branchPath)).digest("hex").slice(0, 16);
1701
- const staging = path4.join(parent, `.${migrationKey}.migration.${process.pid}.${Date.now()}`);
2270
+ const parent = path7.dirname(branchPath);
2271
+ const migrationKey = createHash2("sha256").update(path7.resolve(branchPath)).digest("hex").slice(0, 16);
2272
+ const staging = path7.join(parent, `.${migrationKey}.migration.${process.pid}.${Date.now()}`);
1702
2273
  mkdirSync2(staging, { recursive: true, mode: 448 });
1703
2274
  const testOneShot = false;
1704
2275
  const migrator = new PrologProcess({
@@ -1726,35 +2297,35 @@ async function ensureJournaledBranchStoreAsync(branchPath) {
1726
2297
  await migrator.terminate();
1727
2298
  }
1728
2299
  for (const file of ["rdf", "storage.json", "CURRENT"]) {
1729
- const source = path4.join(staging, file);
1730
- if (!existsSync4(source))
2300
+ const source = path7.join(staging, file);
2301
+ if (!existsSync6(source))
1731
2302
  continue;
1732
- const target = path4.join(branchPath, file);
1733
- if (existsSync4(target))
2303
+ const target = path7.join(branchPath, file);
2304
+ if (existsSync6(target))
1734
2305
  rmSync2(target, { recursive: true, force: true });
1735
2306
  renameSync(source, target);
1736
2307
  }
1737
2308
  archiveLegacyFiles(branchPath);
1738
- writeFileSync2(path4.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
2309
+ writeFileSync2(path7.join(branchPath, "kb.rdf"), `KIBI_STORAGE_FORMAT=kibi.rdf-journal.v1
1739
2310
  `, { mode: 384 });
1740
2311
  fsyncJournaledBranchStore(branchPath);
1741
2312
  rmSync2(staging, { recursive: true, force: true });
1742
2313
  }
1743
2314
  function archiveLegacyFiles(branchPath) {
1744
- const legacyDir = path4.join(branchPath, "legacy");
2315
+ const legacyDir = path7.join(branchPath, "legacy");
1745
2316
  mkdirSync2(legacyDir, { recursive: true, mode: 448 });
1746
2317
  for (const file of ["kb.rdf", "audit.log"]) {
1747
- const source = path4.join(branchPath, file);
1748
- if (!existsSync4(source))
2318
+ const source = path7.join(branchPath, file);
2319
+ if (!existsSync6(source))
1749
2320
  continue;
1750
2321
  if (file === "kb.rdf") {
1751
- const contents = readFileSync3(source, "utf8");
2322
+ const contents = readFileSync4(source, "utf8");
1752
2323
  if (contents.includes("kibi.rdf-journal.v1"))
1753
2324
  continue;
1754
2325
  }
1755
- const destination = path4.join(legacyDir, file);
1756
- if (existsSync4(destination)) {
1757
- renameSync(source, path4.join(legacyDir, `${file}.recovery.${Date.now()}`));
2326
+ const destination = path7.join(legacyDir, file);
2327
+ if (existsSync6(destination)) {
2328
+ renameSync(source, path7.join(legacyDir, `${file}.recovery.${Date.now()}`));
1758
2329
  } else {
1759
2330
  renameSync(source, destination);
1760
2331
  }
@@ -1770,36 +2341,36 @@ function recoverInterruptedGeneration(branchPath) {
1770
2341
  const newest = (prefix) => {
1771
2342
  const candidates = entries.filter((entry) => entry.startsWith(prefix)).sort().reverse();
1772
2343
  const candidate = candidates[0];
1773
- return candidate === undefined ? null : path4.join(branchPath, candidate);
2344
+ return candidate === undefined ? null : path7.join(branchPath, candidate);
1774
2345
  };
1775
2346
  const oldRdf = newest("rdf.old.");
1776
2347
  const oldCurrent = newest("CURRENT.old.");
1777
- const rdfPath = path4.join(branchPath, "rdf");
1778
- const currentPath = path4.join(branchPath, "CURRENT");
1779
- if ((!existsSync4(rdfPath) || !existsSync4(currentPath)) && oldRdf && oldCurrent) {
2348
+ const rdfPath = path7.join(branchPath, "rdf");
2349
+ const currentPath = path7.join(branchPath, "CURRENT");
2350
+ if ((!existsSync6(rdfPath) || !existsSync6(currentPath)) && oldRdf && oldCurrent) {
1780
2351
  try {
1781
- if (existsSync4(rdfPath))
2352
+ if (existsSync6(rdfPath))
1782
2353
  rmSync2(rdfPath, { recursive: true, force: true });
1783
- if (existsSync4(currentPath))
2354
+ if (existsSync6(currentPath))
1784
2355
  rmSync2(currentPath, { force: true });
1785
2356
  renameSync(oldRdf, rdfPath);
1786
2357
  renameSync(oldCurrent, currentPath);
1787
2358
  return;
1788
2359
  } catch {}
1789
2360
  }
1790
- if (!existsSync4(rdfPath) && oldRdf) {
2361
+ if (!existsSync6(rdfPath) && oldRdf) {
1791
2362
  try {
1792
2363
  renameSync(oldRdf, rdfPath);
1793
2364
  } catch {}
1794
2365
  }
1795
- if (!existsSync4(currentPath) && oldCurrent) {
2366
+ if (!existsSync6(currentPath) && oldCurrent) {
1796
2367
  try {
1797
2368
  renameSync(oldCurrent, currentPath);
1798
2369
  } catch {}
1799
2370
  }
1800
2371
  }
1801
2372
  function isEngineLifecycleRequest(request) {
1802
- if (request.method === "stop" || request.method === "cancel")
2373
+ if (request.method === "stop" || request.method === "cancel" || request.method === "handshake")
1803
2374
  return true;
1804
2375
  const kind = request.command?.kind;
1805
2376
  return request.method === "command" && (kind === "stop" || kind === "cancel" || kind === "lifecycle");
@@ -1817,9 +2388,9 @@ class EngineSession {
1817
2388
  constructor(prolog, branchPath) {
1818
2389
  this.prolog = prolog;
1819
2390
  this.branchPath = branchPath;
1820
- const coreModuleDir = path4.dirname(resolveKbPlPath());
2391
+ const coreModuleDir = path7.dirname(resolveKbPlPath());
1821
2392
  for (const [fileName, label] of ENGINE_PRELOADED_MODULES) {
1822
- const modulePath = path4.join(coreModuleDir, fileName);
2393
+ const modulePath = path7.join(coreModuleDir, fileName);
1823
2394
  this.modules.push({
1824
2395
  goal: `use_module('${quoteProlog(modulePath.replaceAll("\\", "/"))}')`,
1825
2396
  label
@@ -1866,10 +2437,14 @@ class EngineSession {
1866
2437
  return true;
1867
2438
  }
1868
2439
  }
1869
- async function runEngineDaemon(options) {
1870
- if (!isValidBranchName(options.branch)) {
1871
- throw new Error(`Invalid Kibi engine branch name: ${options.branch}`);
2440
+ async function runEngineDaemon(requestedOptions) {
2441
+ if (!isValidBranchName(requestedOptions.branch)) {
2442
+ throw new Error(`Invalid Kibi engine branch name: ${requestedOptions.branch}`);
1872
2443
  }
2444
+ const options = {
2445
+ ...requestedOptions,
2446
+ workspaceRoot: canonicalFilesystemPath(requestedOptions.workspaceRoot)
2447
+ };
1873
2448
  const branchPath = ensureBranchStoreManifest(options.workspaceRoot, options.branch);
1874
2449
  await ensureJournaledBranchStoreAsync(branchPath);
1875
2450
  const prolog = new PrologProcess({
@@ -1880,8 +2455,9 @@ async function runEngineDaemon(options) {
1880
2455
  const session = new EngineSession(prolog, branchPath);
1881
2456
  await session.boot();
1882
2457
  let attachedIdentity = readEngineAttachmentIdentity(branchPath);
1883
- mkdirSync2(path4.dirname(options.socketPath), { recursive: true, mode: 448 });
1884
- if (existsSync4(options.socketPath)) {
2458
+ const serverPrologIdentity = engineSwiplIdentity();
2459
+ mkdirSync2(path7.dirname(options.socketPath), { recursive: true, mode: 448 });
2460
+ if (existsSync6(options.socketPath)) {
1885
2461
  const isLivePeerSignal = (error) => {
1886
2462
  if (error && typeof error === "object") {
1887
2463
  const code = "code" in error ? String(error.code) : "";
@@ -1933,6 +2509,10 @@ async function runEngineDaemon(options) {
1933
2509
  let freshnessCache = null;
1934
2510
  const clients = new Set;
1935
2511
  let shuttingDown = false;
2512
+ let finishShutdown;
2513
+ const shutdownFinished = new Promise((resolve) => {
2514
+ finishShutdown = resolve;
2515
+ });
1936
2516
  const exactBranchStatus = (result) => {
1937
2517
  if (!result.success || typeof result.bindings.JsonString !== "string") {
1938
2518
  return result;
@@ -1961,7 +2541,7 @@ async function runEngineDaemon(options) {
1961
2541
  const workspaceWatchdog = setInterval(() => {
1962
2542
  if (shuttingDown)
1963
2543
  return;
1964
- if (!existsSync4(options.workspaceRoot)) {
2544
+ if (!existsSync6(options.workspaceRoot)) {
1965
2545
  workspaceMissingStreak += 1;
1966
2546
  if (workspaceMissingStreak < 2)
1967
2547
  return;
@@ -1973,7 +2553,7 @@ async function runEngineDaemon(options) {
1973
2553
  }, engineWorkspaceWatchdogMs());
1974
2554
  workspaceWatchdog.unref();
1975
2555
  const scheduleIdleExit = () => {
1976
- if (activeClients > 0)
2556
+ if (shuttingDown || activeClients > 0)
1977
2557
  return;
1978
2558
  if (!idleCompactionQueued) {
1979
2559
  idleCompactionQueued = true;
@@ -2002,9 +2582,12 @@ async function runEngineDaemon(options) {
2002
2582
  if (expectedPackages !== undefined && request.packageVersions !== expectedPackages) {
2003
2583
  throw new Error(`Kibi engine package-version mismatch: client=${request.packageVersions ?? "missing"}, server=${expectedPackages}`);
2004
2584
  }
2005
- if (path4.resolve(request.workspaceRoot ?? "") !== path4.resolve(options.workspaceRoot) || request.branch !== options.branch) {
2585
+ if (canonicalFilesystemPath(request.workspaceRoot ?? "") !== options.workspaceRoot || request.branch !== options.branch) {
2006
2586
  throw new Error("Kibi engine workspace identity mismatch");
2007
2587
  }
2588
+ if (request.method !== "handshake" && request.method !== "stop" && request.prologIdentity !== serverPrologIdentity) {
2589
+ throw new Error(`Kibi engine SWI-Prolog mismatch: client=${request.prologIdentity ?? "missing"}, server=${serverPrologIdentity}`);
2590
+ }
2008
2591
  if (!isEngineLifecycleRequest(request) && await session.ensureLive()) {
2009
2592
  queryCache.clear();
2010
2593
  freshnessCache = null;
@@ -2145,7 +2728,14 @@ async function runEngineDaemon(options) {
2145
2728
  }
2146
2729
  }
2147
2730
  case "kbStatus": {
2731
+ const freshnessCacheLookupStartedAt = process.env.KIBI_PERF_TIMINGS === "1" ? performance2.now() : null;
2148
2732
  if (freshnessCache !== null && Date.now() - freshnessCache.capturedAt <= ENGINE_FRESHNESS_CACHE_MS) {
2733
+ if (freshnessCacheLookupStartedAt !== null) {
2734
+ writePerformanceTraceEvent({
2735
+ kind: "engine-freshness-cache-hit",
2736
+ durationMs: performance2.now() - freshnessCacheLookupStartedAt
2737
+ });
2738
+ }
2149
2739
  return freshnessCache.result;
2150
2740
  }
2151
2741
  const result = exactBranchStatus(await prolog.query("status:kb_status_json(JsonString)"));
@@ -2165,9 +2755,17 @@ async function runEngineDaemon(options) {
2165
2755
  freshnessCache = null;
2166
2756
  }
2167
2757
  if (cacheableEngineGoal(request.goal)) {
2758
+ const queryCacheLookupStartedAt = process.env.KIBI_PERF_TIMINGS === "1" ? performance2.now() : null;
2168
2759
  const cached = queryCache.get(request.goal);
2169
- if (cached !== undefined)
2760
+ if (cached !== undefined) {
2761
+ if (queryCacheLookupStartedAt !== null) {
2762
+ writePerformanceTraceEvent({
2763
+ kind: "engine-query-cache-hit",
2764
+ durationMs: performance2.now() - queryCacheLookupStartedAt
2765
+ });
2766
+ }
2170
2767
  return cached;
2768
+ }
2171
2769
  }
2172
2770
  const result = await prolog.query(request.goal);
2173
2771
  session.recordModuleLoad(request.goal, result);
@@ -2204,6 +2802,8 @@ async function runEngineDaemon(options) {
2204
2802
  if (typeof request.targetDirectory !== "string")
2205
2803
  throw new Error("export.targetDirectory is required");
2206
2804
  return prolog.query(`kb_storage_export('${quoteProlog(request.targetDirectory)}')`);
2805
+ case "handshake":
2806
+ return { prologIdentity: serverPrologIdentity };
2207
2807
  case "stop":
2208
2808
  setImmediate(() => void shutdown());
2209
2809
  return { stopped: true };
@@ -2223,6 +2823,10 @@ async function runEngineDaemon(options) {
2223
2823
  if (idleTimer)
2224
2824
  clearTimeout(idleTimer);
2225
2825
  clearInterval(workspaceWatchdog);
2826
+ server.close();
2827
+ await queue.catch(() => {
2828
+ return;
2829
+ });
2226
2830
  const saved = session.needsRecycle() ? null : await prolog.query("kb_save").catch(() => null);
2227
2831
  if (saved?.success) {
2228
2832
  try {
@@ -2234,22 +2838,29 @@ async function runEngineDaemon(options) {
2234
2838
  });
2235
2839
  for (const client of clients)
2236
2840
  client.destroy();
2237
- server.close();
2238
2841
  server.unref();
2239
2842
  try {
2240
- if (existsSync4(options.socketPath))
2843
+ if (existsSync6(options.socketPath))
2241
2844
  rmSync2(options.socketPath, { force: true });
2242
- if (existsSync4(enginePidPath(options.workspaceRoot, options.branch)))
2845
+ if (existsSync6(enginePidPath(options.workspaceRoot, options.branch)))
2243
2846
  rmSync2(enginePidPath(options.workspaceRoot, options.branch), {
2244
2847
  force: true
2245
2848
  });
2246
2849
  } catch {}
2247
2850
  setTimeout(() => process.exit(0), 50).unref();
2851
+ finishShutdown();
2248
2852
  };
2249
2853
  const requestSignalShutdown = requestEngineSignalShutdown(shutdown);
2250
2854
  process.once("SIGTERM", requestSignalShutdown);
2251
2855
  process.once("SIGINT", requestSignalShutdown);
2252
2856
  server.on("connection", (socket) => {
2857
+ socket.on("error", () => {
2858
+ return;
2859
+ });
2860
+ if (shuttingDown) {
2861
+ socket.destroy();
2862
+ return;
2863
+ }
2253
2864
  clients.add(socket);
2254
2865
  activeClients += 1;
2255
2866
  const cancelledRequests = new Set;
@@ -2259,6 +2870,15 @@ async function runEngineDaemon(options) {
2259
2870
  const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
2260
2871
  buffer = parseFrames(Buffer.concat([buffer, bytes]), (value) => {
2261
2872
  const request = value;
2873
+ if (shuttingDown) {
2874
+ writeSocketFrame(socket, {
2875
+ id: request.id,
2876
+ ok: false,
2877
+ error: "Kibi engine is shutting down; request was not executed",
2878
+ serverPackageVersions: ENGINE_PACKAGE_VERSIONS
2879
+ });
2880
+ return;
2881
+ }
2262
2882
  if (request.method === "cancel" && typeof request.cancelOf === "number") {
2263
2883
  cancelledRequests.add(request.cancelOf);
2264
2884
  }
@@ -2317,6 +2937,7 @@ async function runEngineDaemon(options) {
2317
2937
  await new Promise((resolve) => {
2318
2938
  server.once("close", resolve);
2319
2939
  });
2940
+ await shutdownFinished;
2320
2941
  }
2321
2942
 
2322
2943
  // ../cli/src/engine-daemon.ts
@@ -2328,7 +2949,7 @@ function isEngineDaemonEntrypoint(argv = process.argv, moduleUrl = import.meta.u
2328
2949
  if (typeof entry !== "string" || entry.length === 0)
2329
2950
  return false;
2330
2951
  try {
2331
- return moduleUrl === pathToFileURL(path5.resolve(entry)).href;
2952
+ return moduleUrl === pathToFileURL(path8.resolve(entry)).href;
2332
2953
  } catch {
2333
2954
  return false;
2334
2955
  }