kibi-cli 0.2.0 → 0.2.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/prolog.d.ts CHANGED
@@ -15,6 +15,7 @@ export declare class PrologProcess {
15
15
  private outputBuffer;
16
16
  private errorBuffer;
17
17
  private cache;
18
+ private interactiveQueryTail;
18
19
  private useOneShotMode;
19
20
  private attachedKbPath;
20
21
  private onProcessExit;
@@ -1 +1 @@
1
- {"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AAuDA,wBAAgB,eAAe,IAAI,MAAM,CAsCxC;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,cAAc,CACyC;IAC/D,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAA6B;gBAEtC,OAAO,GAAE,aAAkB;IAKjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAoCd,YAAY;IAyCpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAsH1D,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,eAAe;YAYT,YAAY;IA0B1B,OAAO,CAAC,WAAW;IA8EnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IA8BtB,SAAS,IAAI,OAAO;IAIpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBjC"}
1
+ {"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AAuDA,wBAAgB,eAAe,IAAI,MAAM,CAsCxC;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,oBAAoB,CAAoC;IAChE,OAAO,CAAC,cAAc,CACyC;IAC/D,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,aAAa,CAA6B;gBAEtC,OAAO,GAAE,aAAkB;IAKjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAoCd,YAAY;IAyCpB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAuJ1D,eAAe,IAAI,IAAI;IAIvB,OAAO,CAAC,eAAe;YAYT,YAAY;IA0B1B,OAAO,CAAC,WAAW;IA8EnB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;IA8BtB,SAAS,IAAI,OAAO;IAIpB,MAAM,IAAI,MAAM;IAIV,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBjC"}
package/dist/prolog.js CHANGED
@@ -85,6 +85,7 @@ export class PrologProcess {
85
85
  outputBuffer = "";
86
86
  errorBuffer = "";
87
87
  cache = new Map();
88
+ interactiveQueryTail = Promise.resolve();
88
89
  useOneShotMode = typeof globalThis.Bun !== "undefined";
89
90
  attachedKbPath = null;
90
91
  onProcessExit = null;
@@ -174,78 +175,101 @@ export class PrologProcess {
174
175
  if (!this.process || !this.process.stdin) {
175
176
  throw new Error("Prolog process not started");
176
177
  }
177
- this.outputBuffer = "";
178
- this.errorBuffer = "";
179
- this.process.stdin.write(`${goal}.
180
- `);
181
- const debug = !!process.env.KIBI_PROLOG_DEBUG;
182
- const normalizedGoal = isSingleGoal
183
- ? this.normalizeGoal(goal)
184
- : undefined;
185
- const start = Date.now();
186
- if (debug && normalizedGoal)
187
- console.error(`[prolog debug] start query: ${normalizedGoal}`);
188
- return new Promise((resolve, reject) => {
189
- const timeoutId = setTimeout(() => {
190
- const msg = `Query timeout after ${this.timeout / 1000}s`;
191
- if (debug) {
192
- const tailOut = this.outputBuffer.slice(-2048);
193
- const tailErr = this.errorBuffer.slice(-2048);
194
- console.error(`[prolog debug] timeout: ${msg}`);
195
- console.error(`[prolog debug] last stdout: ---\n${tailOut}\n---`);
196
- console.error(`[prolog debug] last stderr: ---\n${tailErr}\n---`);
197
- }
198
- reject(new Error(msg));
199
- }, this.timeout);
200
- const checkResult = () => {
201
- if (this.errorBuffer.length > 0 && this.errorBuffer.includes("ERROR")) {
202
- clearTimeout(timeoutId);
203
- if (debug && normalizedGoal)
204
- console.error(`[prolog debug] query error: ${normalizedGoal} error=${this.errorBuffer.split("\n")[0]}`);
205
- resolve({
206
- success: false,
207
- bindings: {},
208
- error: this.translateError(this.errorBuffer),
209
- });
210
- }
211
- else if (this.outputBuffer.includes("true.") ||
212
- this.outputBuffer.match(/^[A-Z_][A-Za-z0-9_]*\s*=\s*.+\./m) ||
213
- // Match multi-line output ending with ] (Prolog list/term output without trailing period)
214
- this.outputBuffer.match(/\]\s*$/m)) {
215
- clearTimeout(timeoutId);
216
- const result = {
217
- success: true,
218
- bindings: this.extractBindings(this.outputBuffer),
219
- };
220
- if (cacheable) {
221
- this.cache.set(goalKey, result);
178
+ const runInteractiveQuery = async () => {
179
+ this.outputBuffer = "";
180
+ this.errorBuffer = "";
181
+ const debug = !!process.env.KIBI_PROLOG_DEBUG;
182
+ const normalizedGoal = this.normalizeGoal(goal);
183
+ const wrappedGoal = /^once\s*\(/.test(normalizedGoal)
184
+ ? normalizedGoal
185
+ : `once((${normalizedGoal}))`;
186
+ const start = Date.now();
187
+ if (debug) {
188
+ console.error(`[prolog debug] start query: ${normalizedGoal}`);
189
+ }
190
+ this.process?.stdin?.write(`${wrappedGoal}.\n`);
191
+ return new Promise((resolve, reject) => {
192
+ const timeoutId = setTimeout(() => {
193
+ const msg = `Query timeout after ${this.timeout / 1000}s (pid=${this.process?.pid ?? 0}, killed=${this.process?.killed ? "yes" : "no"}, exitCode=${this.process?.exitCode ?? "null"}, goal=${JSON.stringify(normalizedGoal.slice(0, 120))})`;
194
+ if (debug) {
195
+ const tailOut = this.outputBuffer.slice(-2048);
196
+ const tailErr = this.errorBuffer.slice(-2048);
197
+ console.error(`[prolog debug] timeout: ${msg}`);
198
+ console.error(`[prolog debug] last stdout: ---\n${tailOut}\n---`);
199
+ console.error(`[prolog debug] last stderr: ---\n${tailErr}\n---`);
200
+ }
201
+ reject(new Error(msg));
202
+ }, this.timeout);
203
+ const checkResult = () => {
204
+ if (this.errorBuffer.length > 0 &&
205
+ this.errorBuffer.includes("ERROR")) {
206
+ clearTimeout(timeoutId);
207
+ if (debug) {
208
+ console.error(`[prolog debug] query error: ${normalizedGoal} error=${this.errorBuffer.split("\n")[0]}`);
209
+ }
210
+ resolve({
211
+ success: false,
212
+ bindings: {},
213
+ error: this.translateError(this.errorBuffer),
214
+ });
215
+ return;
222
216
  }
223
- if (debug && normalizedGoal) {
224
- console.error(`[prolog debug] query success: ${normalizedGoal} elapsed=${(Date.now() - start) / 1000}s`);
217
+ if (this.outputBuffer.includes("true.") ||
218
+ this.outputBuffer.match(/^[A-Z_][A-Za-z0-9_]*\s*=\s*.+\./m) ||
219
+ this.outputBuffer.match(/\]\s*$/m)) {
220
+ clearTimeout(timeoutId);
221
+ const result = {
222
+ success: true,
223
+ bindings: this.extractBindings(this.outputBuffer),
224
+ };
225
+ // Treat any batch/compound goal as non-cacheable to preserve
226
+ // read-after-write consistency. A batch goal is produced when
227
+ // query(string[]) rewrites its inputs into "(goal1, goal2, ...)"
228
+ // which isCacheableGoal() would otherwise mis-classify as cacheable.
229
+ const isBatchGoal = /^\s*\(/.test(normalizedGoal);
230
+ const shouldCache = cacheable && !isBatchGoal;
231
+ if (!shouldCache) {
232
+ this.invalidateCache();
233
+ }
234
+ if (shouldCache) {
235
+ this.cache.set(goalKey, result);
236
+ }
237
+ if (debug) {
238
+ console.error(`[prolog debug] query success: ${normalizedGoal} elapsed=${(Date.now() - start) / 1000}s`);
239
+ }
240
+ resolve(result);
241
+ return;
225
242
  }
226
- resolve(result);
227
- // Send newline to exit Prolog's interactive prompt
228
- if (this.process?.stdin) {
229
- this.process.stdin.write("\n");
243
+ if (this.outputBuffer.includes("false.") ||
244
+ this.outputBuffer.includes("fail.")) {
245
+ clearTimeout(timeoutId);
246
+ if (debug) {
247
+ console.error(`[prolog debug] query failed (false): ${normalizedGoal}`);
248
+ }
249
+ resolve({
250
+ success: false,
251
+ bindings: {},
252
+ error: "Query failed",
253
+ });
254
+ return;
230
255
  }
231
- }
232
- else if (this.outputBuffer.includes("false.") ||
233
- this.outputBuffer.includes("fail.")) {
234
- clearTimeout(timeoutId);
235
- if (debug && normalizedGoal)
236
- console.error(`[prolog debug] query failed (false): ${normalizedGoal}`);
237
- resolve({
238
- success: false,
239
- bindings: {},
240
- error: "Query failed",
241
- });
242
- }
243
- else {
244
256
  setTimeout(checkResult, 50);
245
- }
246
- };
247
- checkResult();
257
+ };
258
+ checkResult();
259
+ });
260
+ };
261
+ const previousQuery = this.interactiveQueryTail;
262
+ let releaseQuery;
263
+ this.interactiveQueryTail = new Promise((resolve) => {
264
+ releaseQuery = resolve;
248
265
  });
266
+ await previousQuery;
267
+ try {
268
+ return await runInteractiveQuery();
269
+ }
270
+ finally {
271
+ releaseQuery();
272
+ }
249
273
  }
250
274
  invalidateCache() {
251
275
  this.cache.clear();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "description": "Kibi CLI for knowledge base management",
6
6
  "engines": {
@@ -11,7 +11,13 @@
11
11
  "bin": {
12
12
  "kibi": "bin/kibi"
13
13
  },
14
- "files": ["dist", "bin", "schema", "src/schemas", "src/public"],
14
+ "files": [
15
+ "dist",
16
+ "bin",
17
+ "schema",
18
+ "src/schemas",
19
+ "src/public"
20
+ ],
15
21
  "scripts": {
16
22
  "build": "tsc -p tsconfig.json",
17
23
  "prepack": "npm run build"
@@ -58,7 +64,7 @@
58
64
  "fast-glob": "^3.2.12",
59
65
  "gray-matter": "^4.0.3",
60
66
  "js-yaml": "^4.1.0",
61
- "kibi-core": "^0.1.6",
67
+ "kibi-core": "^0.1.7",
62
68
  "ts-morph": "^23.0.0"
63
69
  },
64
70
  "license": "AGPL-3.0-or-later",