kibi-cli 0.2.6 → 0.2.7
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/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +29 -6
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +44 -20
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +22 -14
- package/dist/prolog.d.ts +2 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +45 -12
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0QvE"}
|
package/dist/commands/check.js
CHANGED
|
@@ -27,7 +27,10 @@ import { loadConfig } from "../utils/config.js";
|
|
|
27
27
|
import { RULES, getEffectiveRules, } from "../utils/rule-registry.js";
|
|
28
28
|
import { runAggregatedChecks } from "./aggregated-checks.js";
|
|
29
29
|
import { getCurrentBranch } from "./init-helpers.js";
|
|
30
|
+
// implements REQ-006
|
|
30
31
|
export async function checkCommand(options) {
|
|
32
|
+
let prolog = null;
|
|
33
|
+
let attached = false;
|
|
31
34
|
try {
|
|
32
35
|
// Resolve KB path with priority:
|
|
33
36
|
// --kb-path > git branch --show-current > KIBI_BRANCH env > develop > main
|
|
@@ -139,7 +142,7 @@ export async function checkCommand(options) {
|
|
|
139
142
|
process.exit(1);
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
|
-
|
|
145
|
+
prolog = new PrologProcess({ timeout: 120000 });
|
|
143
146
|
await prolog.start();
|
|
144
147
|
const kbPathEscaped = escapeAtom(resolvedKbPath);
|
|
145
148
|
const attachResult = await prolog.query(`kb_attach('${kbPathEscaped}')`);
|
|
@@ -148,6 +151,7 @@ export async function checkCommand(options) {
|
|
|
148
151
|
console.error(`Error: Failed to attach KB: ${attachResult.error}`);
|
|
149
152
|
process.exit(1);
|
|
150
153
|
}
|
|
154
|
+
attached = true;
|
|
151
155
|
const violations = [];
|
|
152
156
|
// Load config to get rule enablement settings
|
|
153
157
|
const config = loadConfig(process.cwd());
|
|
@@ -161,10 +165,17 @@ export async function checkCommand(options) {
|
|
|
161
165
|
async function runCheck(name, fn, ...args) {
|
|
162
166
|
if (!effectiveRules.has(name))
|
|
163
167
|
return;
|
|
168
|
+
if (!prolog) {
|
|
169
|
+
throw new Error("Prolog process not initialized");
|
|
170
|
+
}
|
|
164
171
|
const res = await fn(prolog, ...args);
|
|
165
172
|
if (res?.length)
|
|
166
173
|
violations.push(...res);
|
|
167
174
|
}
|
|
175
|
+
if (!prolog) {
|
|
176
|
+
throw new Error("Prolog process not initialized");
|
|
177
|
+
}
|
|
178
|
+
const activeProlog = prolog;
|
|
168
179
|
// Use aggregated checks (single Prolog call) when possible for better performance
|
|
169
180
|
// This is significantly faster in Bun/Docker environments where one-shot mode
|
|
170
181
|
// spawns a new Prolog process for each query
|
|
@@ -182,7 +193,7 @@ export async function checkCommand(options) {
|
|
|
182
193
|
if (canUseAggregated) {
|
|
183
194
|
// Fast path: single Prolog call returning all violations
|
|
184
195
|
// Pass the requireAdr option for symbol-traceability
|
|
185
|
-
const aggregatedViolations = await runAggregatedChecks(
|
|
196
|
+
const aggregatedViolations = await runAggregatedChecks(activeProlog, effectiveRules, checksConfig.symbolTraceability?.requireAdr ?? false);
|
|
186
197
|
violations.push(...aggregatedViolations);
|
|
187
198
|
}
|
|
188
199
|
else {
|
|
@@ -192,16 +203,14 @@ export async function checkCommand(options) {
|
|
|
192
203
|
await runCheck("symbol-traceability", (p) => checkSymbolTraceability(p, checksConfig.symbolTraceability?.requireAdr ?? false));
|
|
193
204
|
await runCheck("no-dangling-refs", checkNoDanglingRefs);
|
|
194
205
|
await runCheck("no-cycles", checkNoCycles);
|
|
195
|
-
const allEntityIds = await getAllEntityIds(
|
|
206
|
+
const allEntityIds = await getAllEntityIds(activeProlog);
|
|
196
207
|
if (effectiveRules.has("required-fields")) {
|
|
197
|
-
const requiredViolations = await checkRequiredFields(
|
|
208
|
+
const requiredViolations = await checkRequiredFields(activeProlog, allEntityIds);
|
|
198
209
|
violations.push(...requiredViolations);
|
|
199
210
|
}
|
|
200
211
|
await runCheck("deprecated-adr-no-successor", checkDeprecatedAdrs);
|
|
201
212
|
await runCheck("domain-contradictions", checkDomainContradictions);
|
|
202
213
|
}
|
|
203
|
-
await prolog.query("kb_detach");
|
|
204
|
-
await prolog.terminate();
|
|
205
214
|
if (violations.length === 0) {
|
|
206
215
|
console.log("✓ No violations found. KB is valid.");
|
|
207
216
|
process.exit(0);
|
|
@@ -224,6 +233,20 @@ export async function checkCommand(options) {
|
|
|
224
233
|
console.error(`Error: ${message}`);
|
|
225
234
|
process.exit(1);
|
|
226
235
|
}
|
|
236
|
+
finally {
|
|
237
|
+
if (prolog) {
|
|
238
|
+
if (attached) {
|
|
239
|
+
try {
|
|
240
|
+
await prolog.query("kb_detach");
|
|
241
|
+
}
|
|
242
|
+
catch { }
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
await prolog.terminate();
|
|
246
|
+
}
|
|
247
|
+
catch { }
|
|
248
|
+
}
|
|
249
|
+
}
|
|
227
250
|
}
|
|
228
251
|
async function checkMustPriorityCoverage(prolog) {
|
|
229
252
|
const violations = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AA2CA,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAgLf"}
|
package/dist/commands/query.js
CHANGED
|
@@ -23,9 +23,12 @@ import relationshipSchema from "../public/schemas/relationship.js";
|
|
|
23
23
|
import { VALID_ENTITY_TYPES } from "../query/service.js";
|
|
24
24
|
import { resolveActiveBranch } from "../utils/branch-resolver.js";
|
|
25
25
|
const REL_TYPES = relationshipSchema.properties.type.enum;
|
|
26
|
+
// implements REQ-003
|
|
26
27
|
export async function queryCommand(type, options) {
|
|
28
|
+
let prolog = null;
|
|
29
|
+
let attached = false;
|
|
27
30
|
try {
|
|
28
|
-
|
|
31
|
+
prolog = new PrologProcess({ timeout: 120000 });
|
|
29
32
|
await prolog.start();
|
|
30
33
|
await prolog.query("set_prolog_flag(answer_write_options, [max_depth(0), spacing(next_argument)])");
|
|
31
34
|
// Resolve branch: allow non-git repos to use default "main" for query
|
|
@@ -56,6 +59,7 @@ export async function queryCommand(type, options) {
|
|
|
56
59
|
console.error(`Error: Failed to attach KB: ${attachResult.error || "Unknown error"}`);
|
|
57
60
|
process.exit(1);
|
|
58
61
|
}
|
|
62
|
+
attached = true;
|
|
59
63
|
let results = [];
|
|
60
64
|
// Query relationships mode
|
|
61
65
|
if (options.relationships) {
|
|
@@ -85,10 +89,9 @@ export async function queryCommand(type, options) {
|
|
|
85
89
|
else if (type || options.source) {
|
|
86
90
|
// Validate type if provided
|
|
87
91
|
if (type && !VALID_ENTITY_TYPES.includes(type)) {
|
|
88
|
-
await prolog.query("kb_detach");
|
|
89
|
-
await prolog.terminate();
|
|
90
92
|
console.error(`Error: Invalid type '${type}'. Valid types: ${VALID_ENTITY_TYPES.join(", ")}`);
|
|
91
|
-
process.
|
|
93
|
+
process.exitCode = 1;
|
|
94
|
+
return;
|
|
92
95
|
}
|
|
93
96
|
let goal;
|
|
94
97
|
if (options.source) {
|
|
@@ -134,13 +137,10 @@ export async function queryCommand(type, options) {
|
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
else {
|
|
137
|
-
await prolog.query("kb_detach");
|
|
138
|
-
await prolog.terminate();
|
|
139
140
|
console.error("Error: Must specify entity type, --source, or --relationships option");
|
|
140
|
-
process.
|
|
141
|
+
process.exitCode = 1;
|
|
142
|
+
return;
|
|
141
143
|
}
|
|
142
|
-
await prolog.query("kb_detach");
|
|
143
|
-
await prolog.terminate();
|
|
144
144
|
// Apply pagination
|
|
145
145
|
const limit = Number.parseInt(options.limit || "100");
|
|
146
146
|
const offset = Number.parseInt(options.offset || "0");
|
|
@@ -152,7 +152,7 @@ export async function queryCommand(type, options) {
|
|
|
152
152
|
else {
|
|
153
153
|
console.log("No entities found");
|
|
154
154
|
}
|
|
155
|
-
|
|
155
|
+
return;
|
|
156
156
|
}
|
|
157
157
|
// Format output
|
|
158
158
|
if (options.format === "table") {
|
|
@@ -161,12 +161,25 @@ export async function queryCommand(type, options) {
|
|
|
161
161
|
else {
|
|
162
162
|
console.log(JSON.stringify(paginated, null, 2));
|
|
163
163
|
}
|
|
164
|
-
process.exit(0);
|
|
165
164
|
}
|
|
166
165
|
catch (error) {
|
|
167
166
|
const message = error instanceof Error ? error.message : String(error);
|
|
168
167
|
console.error(`Error: ${message}`);
|
|
169
|
-
process.
|
|
168
|
+
process.exitCode = 1;
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
if (prolog) {
|
|
172
|
+
if (attached) {
|
|
173
|
+
try {
|
|
174
|
+
await prolog.query("kb_detach");
|
|
175
|
+
}
|
|
176
|
+
catch { }
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
await prolog.terminate();
|
|
180
|
+
}
|
|
181
|
+
catch { }
|
|
182
|
+
}
|
|
170
183
|
}
|
|
171
184
|
}
|
|
172
185
|
/**
|
|
@@ -183,10 +196,11 @@ function outputTable(items, isRelationships) {
|
|
|
183
196
|
colWidths: [20, 18, 18],
|
|
184
197
|
});
|
|
185
198
|
for (const item of items) {
|
|
199
|
+
const rel = item;
|
|
186
200
|
table.push([
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
201
|
+
rel.type || "N/A",
|
|
202
|
+
rel.from.substring(0, 16) || "N/A",
|
|
203
|
+
rel.to.substring(0, 16) || "N/A",
|
|
190
204
|
]);
|
|
191
205
|
}
|
|
192
206
|
console.log(table.toString());
|
|
@@ -197,12 +211,22 @@ function outputTable(items, isRelationships) {
|
|
|
197
211
|
colWidths: [18, 10, 40, 12, 30],
|
|
198
212
|
});
|
|
199
213
|
for (const entity of items) {
|
|
214
|
+
const record = entity;
|
|
215
|
+
const id = typeof record.id === "string" ? record.id : "N/A";
|
|
216
|
+
const entityType = typeof record.type === "string" ? record.type : "N/A";
|
|
217
|
+
const title = typeof record.title === "string" ? record.title : "N/A";
|
|
218
|
+
const status = typeof record.status === "string" ? record.status : "N/A";
|
|
219
|
+
const tags = Array.isArray(record.tags)
|
|
220
|
+
? record.tags
|
|
221
|
+
.filter((tag) => typeof tag === "string")
|
|
222
|
+
.join(", ")
|
|
223
|
+
: "";
|
|
200
224
|
table.push([
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
225
|
+
id.substring(0, 16),
|
|
226
|
+
entityType,
|
|
227
|
+
title.substring(0, 38),
|
|
228
|
+
status,
|
|
229
|
+
tags.substring(0, 28),
|
|
206
230
|
]);
|
|
207
231
|
}
|
|
208
232
|
console.log(table.toString());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyCjE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyCjE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GACL,OAAO,CAAC,WAAW,CAAC,CA0WtB;AAGD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -35,6 +35,7 @@ export class SyncError extends Error {
|
|
|
35
35
|
this.name = "SyncError";
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
// implements REQ-003, REQ-007
|
|
38
39
|
export async function syncCommand(options = {}) {
|
|
39
40
|
const validateOnly = options.validateOnly ?? false;
|
|
40
41
|
const rebuild = options.rebuild ?? false;
|
|
@@ -106,9 +107,9 @@ export async function syncCommand(options = {}) {
|
|
|
106
107
|
const hash = hashFile(file);
|
|
107
108
|
const lastSeen = syncCache.seenAt[key];
|
|
108
109
|
const lastSeenMs = lastSeen ? Date.parse(lastSeen) : Number.NaN;
|
|
109
|
-
const expired =
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const expired = !lastSeen ||
|
|
111
|
+
Number.isNaN(lastSeenMs) ||
|
|
112
|
+
nowMs - lastSeenMs > SYNC_CACHE_TTL_MS;
|
|
112
113
|
nextHashes[key] = hash;
|
|
113
114
|
nextSeenAt[key] = nowIso;
|
|
114
115
|
const isChanged = expired || syncCache.hashes[key] !== hash || validateOnly || rebuild;
|
|
@@ -126,6 +127,8 @@ export async function syncCommand(options = {}) {
|
|
|
126
127
|
console.warn(`Warning: Failed to hash ${file}: ${message}`);
|
|
127
128
|
}
|
|
128
129
|
}
|
|
130
|
+
const performedFullReindex = changedMarkdownFiles.length === markdownFiles.length &&
|
|
131
|
+
changedManifestFiles.length === manifestFiles.length;
|
|
129
132
|
// Content extraction
|
|
130
133
|
const { results, failedCacheKeys, errors } = await processExtractions(changedMarkdownFiles, changedManifestFiles, validateOnly);
|
|
131
134
|
// Collect INVALID_AUTHORING diagnostics
|
|
@@ -176,7 +179,7 @@ export async function syncCommand(options = {}) {
|
|
|
176
179
|
continue;
|
|
177
180
|
}
|
|
178
181
|
evictedHashes[key] = hash;
|
|
179
|
-
evictedSeenAt[key] =
|
|
182
|
+
evictedSeenAt[key] = nextSeenAt[key] ?? nowIso;
|
|
180
183
|
}
|
|
181
184
|
writeSyncCache(cachePath, {
|
|
182
185
|
version: SYNC_CACHE_VERSION,
|
|
@@ -204,7 +207,13 @@ export async function syncCommand(options = {}) {
|
|
|
204
207
|
throw new SyncError(`Failed to attach to staging KB: ${attachResult.error || "Unknown error"}`);
|
|
205
208
|
}
|
|
206
209
|
const entityIds = new Set();
|
|
207
|
-
//
|
|
210
|
+
// Track entity counts by type
|
|
211
|
+
for (const { entity } of results) {
|
|
212
|
+
entityCounts[entity.type] = (entityCounts[entity.type] || 0) + 1;
|
|
213
|
+
}
|
|
214
|
+
// Persist entities
|
|
215
|
+
const { entityCount, kbModified: entitiesModified } = await persistEntities(prolog, results, entityIds);
|
|
216
|
+
// Validate and filter dangling relationships after entity IDs are known.
|
|
208
217
|
const validationErrors = validateRelationships(allRelationships, entityIds);
|
|
209
218
|
if (validationErrors.length > 0) {
|
|
210
219
|
console.warn(`Warning: ${validationErrors.length} dangling relationship(s) found`);
|
|
@@ -214,19 +223,16 @@ export async function syncCommand(options = {}) {
|
|
|
214
223
|
}
|
|
215
224
|
const danglingKeys = new Set(validationErrors.map(({ relationship: r }) => `${r.type}|${r.from}|${r.to}`));
|
|
216
225
|
const validRelationships = allRelationships.filter((r) => !danglingKeys.has(`${r.type}|${r.from}|${r.to}`));
|
|
217
|
-
// Track entity counts by type
|
|
218
|
-
for (const { entity } of results) {
|
|
219
|
-
entityCounts[entity.type] = (entityCounts[entity.type] || 0) + 1;
|
|
220
|
-
}
|
|
221
|
-
// Persist entities
|
|
222
|
-
const { entityCount, kbModified: entitiesModified } = await persistEntities(prolog, results, entityIds);
|
|
223
226
|
// Persist relationships
|
|
224
227
|
const { relationshipCount, kbModified: relationshipsModified } = await persistRelationships(prolog, results, validRelationships);
|
|
225
228
|
const kbModified = entitiesModified || relationshipsModified;
|
|
226
229
|
if (kbModified) {
|
|
227
230
|
prolog.invalidateCache();
|
|
228
231
|
}
|
|
229
|
-
await prolog.query("kb_save");
|
|
232
|
+
const saveResult = await prolog.query("kb_save");
|
|
233
|
+
if (!saveResult.success) {
|
|
234
|
+
throw new SyncError(`Failed to save staging KB: ${saveResult.error || "Unknown error"}`);
|
|
235
|
+
}
|
|
230
236
|
await prolog.query("kb_detach");
|
|
231
237
|
await prolog.terminate();
|
|
232
238
|
// Publish staging to live
|
|
@@ -239,7 +245,7 @@ export async function syncCommand(options = {}) {
|
|
|
239
245
|
continue;
|
|
240
246
|
}
|
|
241
247
|
evictedHashes[key] = hash;
|
|
242
|
-
evictedSeenAt[key] =
|
|
248
|
+
evictedSeenAt[key] = nextSeenAt[key] ?? nowIso;
|
|
243
249
|
}
|
|
244
250
|
const liveCachePath = path.join(livePath, "sync-cache.json");
|
|
245
251
|
writeSyncCache(liveCachePath, {
|
|
@@ -248,7 +254,9 @@ export async function syncCommand(options = {}) {
|
|
|
248
254
|
seenAt: evictedSeenAt,
|
|
249
255
|
});
|
|
250
256
|
published = true;
|
|
251
|
-
if (
|
|
257
|
+
if (performedFullReindex &&
|
|
258
|
+
markdownFiles.length > 0 &&
|
|
259
|
+
entityCount < markdownFiles.length) {
|
|
252
260
|
diagnostics.push(createDocsNotIndexedDiagnostic(markdownFiles.length, entityCount));
|
|
253
261
|
}
|
|
254
262
|
console.log(`✓ Imported ${entityCount} entities, ${relationshipCount} relationships`);
|
package/dist/prolog.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare class PrologProcess {
|
|
|
25
25
|
query(goal: string | string[]): Promise<QueryResult>;
|
|
26
26
|
invalidateCache(): void;
|
|
27
27
|
private isCacheableGoal;
|
|
28
|
+
private isMutatingGoal;
|
|
29
|
+
private isExplicitSaveGoal;
|
|
28
30
|
private queryOneShot;
|
|
29
31
|
private execOneShot;
|
|
30
32
|
private normalizeGoal;
|
package/dist/prolog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AA4BA,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;
|
|
1
|
+
{"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"AA4BA,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;IAavB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,kBAAkB;YAIZ,YAAY;IAkC1B,OAAO,CAAC,WAAW;IA8FnB,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
|
@@ -73,7 +73,7 @@ export class PrologProcess {
|
|
|
73
73
|
const kbPath = resolveKbPlPath();
|
|
74
74
|
this.process = spawn(this.swiplPath, [
|
|
75
75
|
"-g",
|
|
76
|
-
`use_module('${kbPath}'), set_prolog_flag(answer_write_options, [max_depth(0), quoted(true)])`,
|
|
76
|
+
`use_module('${kbPath}'), use_module(library(semweb/rdf_db)), set_prolog_flag(answer_write_options, [max_depth(0), quoted(true)])`,
|
|
77
77
|
"--quiet",
|
|
78
78
|
]);
|
|
79
79
|
if (!this.process.stdout || !this.process.stderr || !this.process.stdin) {
|
|
@@ -256,6 +256,16 @@ export class PrologProcess {
|
|
|
256
256
|
trimmed.startsWith("kb_delete_") ||
|
|
257
257
|
trimmed.startsWith("kb_retract_"));
|
|
258
258
|
}
|
|
259
|
+
// implements REQ-009
|
|
260
|
+
isMutatingGoal(goal) {
|
|
261
|
+
return (goal.includes("kb_assert_") ||
|
|
262
|
+
goal.includes("kb_delete_") ||
|
|
263
|
+
goal.includes("kb_retract_"));
|
|
264
|
+
}
|
|
265
|
+
// implements REQ-009
|
|
266
|
+
isExplicitSaveGoal(goal) {
|
|
267
|
+
return goal.trim().startsWith("kb_save");
|
|
268
|
+
}
|
|
259
269
|
async queryOneShot(goal) {
|
|
260
270
|
if (Array.isArray(goal)) {
|
|
261
271
|
return this.execOneShot(goal, this.attachedKbPath);
|
|
@@ -269,6 +279,13 @@ export class PrologProcess {
|
|
|
269
279
|
}
|
|
270
280
|
const attachMatch = trimmedGoal.match(/^kb_attach\('(.+)'\)$/);
|
|
271
281
|
if (attachMatch) {
|
|
282
|
+
if (this.attachedKbPath !== null) {
|
|
283
|
+
return {
|
|
284
|
+
success: false,
|
|
285
|
+
bindings: {},
|
|
286
|
+
error: "KB already attached",
|
|
287
|
+
};
|
|
288
|
+
}
|
|
272
289
|
const attachResult = this.execOneShot(trimmedGoal, null);
|
|
273
290
|
if (attachResult.success) {
|
|
274
291
|
this.attachedKbPath = attachMatch[1];
|
|
@@ -278,11 +295,21 @@ export class PrologProcess {
|
|
|
278
295
|
return this.execOneShot(trimmedGoal, this.attachedKbPath);
|
|
279
296
|
}
|
|
280
297
|
execOneShot(goal, kbPath) {
|
|
281
|
-
const
|
|
298
|
+
const originalGoalList = Array.isArray(goal)
|
|
282
299
|
? goal.map((item) => this.normalizeGoal(item))
|
|
283
300
|
: [this.normalizeGoal(goal)];
|
|
301
|
+
const explicitSaveRequested = Array.isArray(goal)
|
|
302
|
+
? originalGoalList.some((item) => this.isExplicitSaveGoal(item))
|
|
303
|
+
: false;
|
|
304
|
+
const goalList = explicitSaveRequested
|
|
305
|
+
? originalGoalList.filter((item) => !this.isExplicitSaveGoal(item))
|
|
306
|
+
: originalGoalList;
|
|
284
307
|
const isBatch = goalList.length > 1;
|
|
285
|
-
const combinedGoal = goalList.length ===
|
|
308
|
+
const combinedGoal = goalList.length === 0
|
|
309
|
+
? "true"
|
|
310
|
+
: goalList.length === 1
|
|
311
|
+
? goalList[0]
|
|
312
|
+
: `(${goalList.join(", ")})`;
|
|
286
313
|
const kbModulePath = resolveKbPlPath();
|
|
287
314
|
const prologGoal = [
|
|
288
315
|
`use_module('${kbModulePath}')`,
|
|
@@ -292,8 +319,14 @@ export class PrologProcess {
|
|
|
292
319
|
"read_term_from_atom(GoalAtom, Goal, [variable_names(Vars)])",
|
|
293
320
|
kbPath ? "getenv('KIBI_KB_PATH', KBPath), kb_attach(KBPath)" : "true",
|
|
294
321
|
isBatch ? "WrappedGoal = rdf_transaction(Goal)" : "WrappedGoal = Goal",
|
|
295
|
-
"(catch(call(WrappedGoal), E, (print_message(error, E), fail)) ->
|
|
296
|
-
kbPath
|
|
322
|
+
"(catch(call(WrappedGoal), E, (print_message(error, E), fail)) -> QuerySucceeded = true ; QuerySucceeded = false)",
|
|
323
|
+
kbPath &&
|
|
324
|
+
(explicitSaveRequested ||
|
|
325
|
+
goalList.some((item) => this.isMutatingGoal(item)))
|
|
326
|
+
? "(QuerySucceeded == true -> kb_save ; true)"
|
|
327
|
+
: "true",
|
|
328
|
+
kbPath ? "kb_detach" : "true",
|
|
329
|
+
"(QuerySucceeded == true -> (forall(member(Name=Value, Vars), (write(Name), write('='), write_term(Value, [quoted(true), max_depth(0)]), writeln('.'))), writeln('__KIBI_TRUE__.')) ; writeln('__KIBI_FALSE__.'))",
|
|
297
330
|
].join(", ");
|
|
298
331
|
const result = spawnSync(this.swiplPath, ["-q", "-g", prologGoal, "-t", "halt"], {
|
|
299
332
|
encoding: "utf8",
|
|
@@ -313,6 +346,13 @@ export class PrologProcess {
|
|
|
313
346
|
}
|
|
314
347
|
const stdout = result.stdout ?? "";
|
|
315
348
|
const stderr = result.stderr ?? "";
|
|
349
|
+
if (stderr.includes("ERROR")) {
|
|
350
|
+
return {
|
|
351
|
+
success: false,
|
|
352
|
+
bindings: {},
|
|
353
|
+
error: this.translateError(stderr),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
316
356
|
if (stdout.includes("__KIBI_TRUE__")) {
|
|
317
357
|
const clean = stdout
|
|
318
358
|
.split("\n")
|
|
@@ -323,13 +363,6 @@ export class PrologProcess {
|
|
|
323
363
|
bindings: this.extractBindings(clean),
|
|
324
364
|
};
|
|
325
365
|
}
|
|
326
|
-
if (stderr.includes("ERROR")) {
|
|
327
|
-
return {
|
|
328
|
-
success: false,
|
|
329
|
-
bindings: {},
|
|
330
|
-
error: this.translateError(stderr),
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
366
|
return {
|
|
334
367
|
success: false,
|
|
335
368
|
bindings: {},
|