kibi-cli 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/commands/doctor.js +11 -5
- package/dist/commands/sync/manifest.d.ts +10 -0
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +27 -0
- package/dist/commands/sync/untracked-targets.d.ts +17 -0
- package/dist/commands/sync/untracked-targets.d.ts.map +1 -1
- package/dist/commands/sync/untracked-targets.js +43 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +16 -23
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +5 -12
- package/dist/prolog/store-lock.d.ts +19 -0
- package/dist/prolog/store-lock.d.ts.map +1 -1
- package/dist/prolog/store-lock.js +46 -0
- package/dist/proof/inspect.d.ts +1 -1
- package/dist/proof/inspect.d.ts.map +1 -1
- package/dist/proof/inspect.js +9 -2
- package/dist/public/operations/catalog.d.ts +50 -1
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +1 -4
- package/dist/public/operations/discovery-executors.d.ts +36 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +361 -1
- package/dist/public/operations/specs/discovery.d.ts +50 -1
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +56 -1
- package/dist/public/skills/kibi-usage/SKILL.md +9 -1
- package/dist/runtime/cli-runtime.d.ts.map +1 -1
- package/dist/runtime/cli-runtime.js +7 -2
- package/dist/search-answer.d.ts +12 -3
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +51 -4
- package/dist/utils/content-freshness.d.ts.map +1 -1
- package/dist/utils/content-freshness.js +12 -2
- package/dist/utils/symbol-manifest-layout.d.ts +9 -0
- package/dist/utils/symbol-manifest-layout.d.ts.map +1 -0
- package/dist/utils/symbol-manifest-layout.js +18 -0
- package/package.json +2 -2
- package/src/public/operations/contracts.ts +4 -4
- package/src/public/operations/discovery-executors.ts +472 -0
- package/src/public/operations/specs/discovery.ts +67 -1
- package/src/public/skills/kibi-usage/SKILL.md +9 -1
|
@@ -23,7 +23,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
|
|
|
23
23
|
}, {
|
|
24
24
|
readonly name: "kb_query";
|
|
25
25
|
readonly cliName: "query";
|
|
26
|
-
readonly description: "Read entities from the KB with filters. Use for
|
|
26
|
+
readonly description: "Read entities from the KB with exact filters, or ask typed fact questions. Use for lookup by id, type, tags or sourceFile, and for precise questions about modeled facts: predicate facts by name with named arguments (predicate + where), property facts of a subject (subjectKey + propertyKey), or the catalog of facts of one kind (factKind; 'predicate_schema' lists the predicates you can ask about with their argument names and constants). Typed answers return matching fact rows plus factQuery: the schema used, distinct counts, values that do exist when nothing matched, warnings about the question and the next call to make. Read-only. Tags filter by metadata tags only, not entity IDs.";
|
|
27
27
|
}, {
|
|
28
28
|
readonly name: "kb_search";
|
|
29
29
|
readonly cliName: "search";
|
|
@@ -25,7 +25,7 @@ export const CLI_OPERATION_METADATA = [
|
|
|
25
25
|
{
|
|
26
26
|
name: "kb_query",
|
|
27
27
|
cliName: "query",
|
|
28
|
-
description: "Read entities from the KB with filters. Use for
|
|
28
|
+
description: "Read entities from the KB with exact filters, or ask typed fact questions. Use for lookup by id, type, tags or sourceFile, and for precise questions about modeled facts: predicate facts by name with named arguments (predicate + where), property facts of a subject (subjectKey + propertyKey), or the catalog of facts of one kind (factKind; 'predicate_schema' lists the predicates you can ask about with their argument names and constants). Typed answers return matching fact rows plus factQuery: the schema used, distinct counts, values that do exist when nothing matched, warnings about the question and the next call to make. Read-only. Tags filter by metadata tags only, not entity IDs.",
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
name: "kb_search",
|
package/dist/commands/doctor.js
CHANGED
|
@@ -694,14 +694,19 @@ function checkBranchStore() {
|
|
|
694
694
|
const compilation = branchStoreCompilation(store);
|
|
695
695
|
// implements REQ-core-journaled-engine-persistence
|
|
696
696
|
const takeover = storeLockTakeoverReason(store.path);
|
|
697
|
+
// A takeover is reported whether or not the store holds a compilation yet.
|
|
698
|
+
const withTakeover = (message) => takeover
|
|
699
|
+
? `${message}${message.endsWith(".") ? "" : "."} ${String(takeover.detail)}`
|
|
700
|
+
: message;
|
|
701
|
+
const takeoverDetails = takeover ? { lockTakeover: takeover } : {};
|
|
697
702
|
if (compilation.compiled) {
|
|
698
703
|
return {
|
|
699
704
|
passed: true,
|
|
700
|
-
message: `Compiled for ${branch}${compilation.generation ? ` (${compilation.generation})` : ""}
|
|
705
|
+
message: withTakeover(`Compiled for ${branch}${compilation.generation ? ` (${compilation.generation})` : ""}`),
|
|
701
706
|
details: {
|
|
702
707
|
...details,
|
|
703
708
|
generation: compilation.generation,
|
|
704
|
-
...
|
|
709
|
+
...takeoverDetails,
|
|
705
710
|
},
|
|
706
711
|
};
|
|
707
712
|
}
|
|
@@ -709,18 +714,19 @@ function checkBranchStore() {
|
|
|
709
714
|
if (reason === null) {
|
|
710
715
|
return {
|
|
711
716
|
passed: true,
|
|
712
|
-
message: `Not compiled yet for ${branch}; .kb/ holds no authored sources
|
|
713
|
-
details,
|
|
717
|
+
message: withTakeover(`Not compiled yet for ${branch}; .kb/ holds no authored sources`),
|
|
718
|
+
details: { ...details, ...takeoverDetails },
|
|
714
719
|
};
|
|
715
720
|
}
|
|
716
721
|
return {
|
|
717
722
|
passed: false,
|
|
718
|
-
message: String(reason.detail),
|
|
723
|
+
message: withTakeover(String(reason.detail)),
|
|
719
724
|
remediation: "Run: kibi sync",
|
|
720
725
|
details: {
|
|
721
726
|
...details,
|
|
722
727
|
generation: compilation.generation,
|
|
723
728
|
authoredSources: reason.authoredSources,
|
|
729
|
+
...takeoverDetails,
|
|
724
730
|
},
|
|
725
731
|
};
|
|
726
732
|
}
|
|
@@ -33,6 +33,16 @@ export declare function refreshManifestCoordinates(manifestPath: string, workspa
|
|
|
33
33
|
refreshSymbolCoordinates?: boolean;
|
|
34
34
|
quiet?: boolean;
|
|
35
35
|
}): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Rewrite a symbol manifest whose `symbols` sequence is in YAML flow layout
|
|
38
|
+
* (`symbols: [ { id: … }, … ]`) as block YAML, keeping comments and entry
|
|
39
|
+
* order. kibi-cli before 2.18.0 appended to the `symbols: []` that
|
|
40
|
+
* `kibi init` writes and kept every symbol on that one line; the hook
|
|
41
|
+
* scanners of older adapters cannot read it and diffs of it are unreviewable,
|
|
42
|
+
* so plain `kibi sync` normalises it once. Returns the number of symbols
|
|
43
|
+
* when the file was rewritten, otherwise null.
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeManifestLayout(manifestPath: string, deps?: Partial<ManifestDeps>): number | null;
|
|
36
46
|
export declare function hasAllGeneratedCoordinates(entry: ManifestSymbolEntry): boolean;
|
|
37
47
|
export declare function isEligibleForCoordinateRefresh(sourceFile: string | undefined, workspaceRoot: string, deps?: Partial<ManifestDeps>): boolean;
|
|
38
48
|
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/manifest.ts"],"names":[],"mappings":"AAkBA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,UAAU,EACV,UAAU,EACV,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAE9D,OAAO,EAML,uBAAuB,EACxB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,KAAK,mBAAmB,EACxB,uBAAuB,EACxB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,0BAA0B,EAG3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAG5E,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,QAAQ,CAAC;IAC1B,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,2BAA2B,EAAE,OAAO,2BAA2B,CAAC;CACjE;AAkBD,eAAO,MAAM,8BAA8B,QAc1C,CAAC;AAaF;;;;;;;;;GASG;AACH,OAAO,EAAE,0BAA0B,EAAE,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAG7E;AAoHD,wBAAsB,0BAA0B,CAE9C,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACA,OAAO,CAAC,IAAI,CAAC,CA0Mf;AAED;;;;;;;;GAQG;AAEH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,MAAM,GAAG,IAAI,CAWf;AAED,wBAAgB,0BAA0B,CAExC,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAOT;AAED,wBAAgB,8BAA8B,CAE5C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC3B,OAAO,CAUT"}
|
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
19
19
|
import * as path from "node:path";
|
|
20
20
|
import { dump as dumpYAML, load as parseYAML } from "js-yaml";
|
|
21
|
+
import { isSeq, parseDocument } from "yaml";
|
|
21
22
|
import { coarseCoordinateSpan, coordinateIdentityHash, coordinateSourceHash, parseCoordinateArtifact, writeCoordinateArtifact, } from "../../extractors/symbol-coordinates.js";
|
|
22
23
|
import { enrichSymbolCoordinates, } from "../../extractors/symbols-coordinator.js";
|
|
23
24
|
import { COARSE_GRANULARITY_REASONS, COARSE_GRANULARITY_REASONS_PARENTHESIZED, isCoarseGranularityReason, } from "../../public/symbol-granularity.js";
|
|
24
25
|
import { resolveSymbolsManifestPaths } from "../../utils/manifest-paths.js";
|
|
26
|
+
import { blockifySymbolManifest } from "../../utils/symbol-manifest-layout.js";
|
|
25
27
|
function resolveDeps(overrides) {
|
|
26
28
|
return {
|
|
27
29
|
dumpYAML,
|
|
@@ -307,6 +309,31 @@ manifestPath, workspaceRoot, deps) {
|
|
|
307
309
|
}
|
|
308
310
|
}
|
|
309
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Rewrite a symbol manifest whose `symbols` sequence is in YAML flow layout
|
|
314
|
+
* (`symbols: [ { id: … }, … ]`) as block YAML, keeping comments and entry
|
|
315
|
+
* order. kibi-cli before 2.18.0 appended to the `symbols: []` that
|
|
316
|
+
* `kibi init` writes and kept every symbol on that one line; the hook
|
|
317
|
+
* scanners of older adapters cannot read it and diffs of it are unreviewable,
|
|
318
|
+
* so plain `kibi sync` normalises it once. Returns the number of symbols
|
|
319
|
+
* when the file was rewritten, otherwise null.
|
|
320
|
+
*/
|
|
321
|
+
// implements REQ-kibi-hooks-flow-manifest
|
|
322
|
+
export function normalizeManifestLayout(manifestPath, deps) {
|
|
323
|
+
const resolved = resolveDeps(deps);
|
|
324
|
+
const rawContent = String(resolved.readFileSync(manifestPath, "utf8"));
|
|
325
|
+
const doc = parseDocument(rawContent);
|
|
326
|
+
const symbols = doc.get("symbols", true);
|
|
327
|
+
if (!isSeq(symbols) || symbols.items.length === 0)
|
|
328
|
+
return null;
|
|
329
|
+
if (!blockifySymbolManifest(doc))
|
|
330
|
+
return null;
|
|
331
|
+
const nextContent = doc.toString({ lineWidth: 0 });
|
|
332
|
+
if (nextContent === rawContent)
|
|
333
|
+
return null;
|
|
334
|
+
publishAtomically(manifestPath, nextContent, resolved);
|
|
335
|
+
return symbols.items.length;
|
|
336
|
+
}
|
|
310
337
|
export function hasAllGeneratedCoordinates(
|
|
311
338
|
// implements REQ-003
|
|
312
339
|
entry) {
|
|
@@ -20,5 +20,22 @@ interface UntrackedTargetsDeps {
|
|
|
20
20
|
* the diagnostic can never break a sync run.
|
|
21
21
|
*/
|
|
22
22
|
export declare function findUntrackedDocumentMatches(workspaceRoot: string, missingIds: readonly string[], deps?: Partial<UntrackedTargetsDeps>): Map<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Give an upsert-only symbol manifest the pending-source receipt kb_upsert
|
|
25
|
+
* writes since it learned to (`writeSourceForUpsert`).
|
|
26
|
+
*
|
|
27
|
+
* Older Kibi appended symbols to the untracked `.kb/symbols.yaml` that
|
|
28
|
+
* `kibi init` creates without a receipt. The upsert wrote those symbols into
|
|
29
|
+
* the store directly, but sync never saw the manifest, so the store recorded
|
|
30
|
+
* no content hash for it and every source its symbols reference stayed
|
|
31
|
+
* "newer" after a clone or checkout, however many times sync ran.
|
|
32
|
+
*
|
|
33
|
+
* The manifest is adopted only when Git does not track it, no receipt covers
|
|
34
|
+
* it, and at least one symbol it declares is already in the compiled store
|
|
35
|
+
* (`isStored`): Kibi wrote it. A hand-written untracked manifest whose
|
|
36
|
+
* symbols the store never saw keeps the tracked-only boundary and sync's
|
|
37
|
+
* "stage this file" note. Returns whether a receipt was written.
|
|
38
|
+
*/
|
|
39
|
+
export declare function adoptUpsertOnlySymbolManifest(workspaceRoot: string, isStored: (ids: readonly string[]) => Promise<boolean>): Promise<boolean>;
|
|
23
40
|
export {};
|
|
24
41
|
//# sourceMappingURL=untracked-targets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"untracked-targets.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/untracked-targets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"untracked-targets.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/untracked-targets.ts"],"names":[],"mappings":"AA6BA,UAAU,oBAAoB;IAC5B,YAAY,EAAE,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAC5D,MAAM,CAAC;IACZ,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1D;AAQD;;;;;;;;;;;GAWG;AAEH,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,IAAI,GAAE,OAAO,CAAC,oBAAoB,CAAM,GACvC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAsDrB;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAsB,6BAA6B,CACjD,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GACrD,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
|
|
@@ -20,7 +20,8 @@ import { createHash } from "node:crypto";
|
|
|
20
20
|
import { existsSync, readFileSync } from "node:fs";
|
|
21
21
|
import * as path from "node:path";
|
|
22
22
|
import { load as parseYAML } from "js-yaml";
|
|
23
|
-
import {
|
|
23
|
+
import { isUntrackedByGit, writePendingSourceReceipt, } from "../../operations/mutation/source-authoring.js";
|
|
24
|
+
import { KB_PATHS, isSymbolsManifestPath } from "../../utils/kb-paths.js";
|
|
24
25
|
const defaultDeps = {
|
|
25
26
|
execFileSync: (file, args, options) => execFileSync(file, args, options),
|
|
26
27
|
existsSync,
|
|
@@ -96,6 +97,47 @@ export function findUntrackedDocumentMatches(workspaceRoot, missingIds, deps = {
|
|
|
96
97
|
}
|
|
97
98
|
return matches;
|
|
98
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Give an upsert-only symbol manifest the pending-source receipt kb_upsert
|
|
102
|
+
* writes since it learned to (`writeSourceForUpsert`).
|
|
103
|
+
*
|
|
104
|
+
* Older Kibi appended symbols to the untracked `.kb/symbols.yaml` that
|
|
105
|
+
* `kibi init` creates without a receipt. The upsert wrote those symbols into
|
|
106
|
+
* the store directly, but sync never saw the manifest, so the store recorded
|
|
107
|
+
* no content hash for it and every source its symbols reference stayed
|
|
108
|
+
* "newer" after a clone or checkout, however many times sync ran.
|
|
109
|
+
*
|
|
110
|
+
* The manifest is adopted only when Git does not track it, no receipt covers
|
|
111
|
+
* it, and at least one symbol it declares is already in the compiled store
|
|
112
|
+
* (`isStored`): Kibi wrote it. A hand-written untracked manifest whose
|
|
113
|
+
* symbols the store never saw keeps the tracked-only boundary and sync's
|
|
114
|
+
* "stage this file" note. Returns whether a receipt was written.
|
|
115
|
+
*/
|
|
116
|
+
// implements REQ-cli-status-pre-first-sync, REQ-core-persistence
|
|
117
|
+
export async function adoptUpsertOnlySymbolManifest(workspaceRoot, isStored) {
|
|
118
|
+
const relative = KB_PATHS.symbolsManifest;
|
|
119
|
+
const absolute = path.resolve(workspaceRoot, relative);
|
|
120
|
+
if (!existsSync(absolute))
|
|
121
|
+
return false;
|
|
122
|
+
if (existsSync(pendingReceiptFor(workspaceRoot, relative)))
|
|
123
|
+
return false;
|
|
124
|
+
let bytes;
|
|
125
|
+
try {
|
|
126
|
+
bytes = readFileSync(absolute);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const ids = manifestIds(bytes.toString("utf8"));
|
|
132
|
+
if (ids.length === 0)
|
|
133
|
+
return false;
|
|
134
|
+
if (!isUntrackedByGit(workspaceRoot, relative))
|
|
135
|
+
return false;
|
|
136
|
+
if (!(await isStored(ids)))
|
|
137
|
+
return false;
|
|
138
|
+
writePendingSourceReceipt(workspaceRoot, relative, createHash("sha256").update(bytes).digest("hex"));
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
99
141
|
/** Where kb_upsert records the pending-source receipt of `relative`. */
|
|
100
142
|
function pendingReceiptFor(workspaceRoot, relative) {
|
|
101
143
|
return path.join(workspaceRoot, ".kb", "recovery", "pending-sources", `${createHash("sha256").update(relative).digest("hex")}.json`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6BjE,OAAO,EAEL,yBAAyB,EAE1B,MAAM,gDAAgD,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,6BAA6B,CAAC;AAyBrC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6BjE,OAAO,EAEL,yBAAyB,EAE1B,MAAM,gDAAgD,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,6BAA6B,CAAC;AAyBrC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAkCxE,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAmCD,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,4BAA4B,UAAQ,EACpC,4BAA4B,GAAE,4BAA4B,EAAO,GAChE,MAAM,EAAE,CAuGV;AAiFD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,yBAAyB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,yBAAyB,GAAG;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,KACzD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,aAAa,CAAC;IAC/D,yBAAyB,CAAC,EAAE,OAAO,yBAAyB,CAAC;CAC9D;AA+FD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGvE;AAGD,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,IAAI,GAChB,IAAI,CAMN;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAMP;AAED,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,UAAU,EAAE,EACzB,oBAAoB,EAAE,OAAO,EAC7B,iBAAiB,EAAE,MAAM,EACzB,WAAW,EAAE,MAAM,GAClB,IAAI,CAUN;AAGD,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IACP,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;CACZ,EACN,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA+qCrB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -33,10 +33,10 @@ import { loadEntityPaths } from "../utils/config.js";
|
|
|
33
33
|
import { SYNC_CACHE_TTL_MS, SYNC_CACHE_VERSION, SYNC_COMPILER_FINGERPRINT, hashFile, hashManifestWithCoordinates, hashNormalized, readSyncCache, toCacheKey, writeSyncCache, } from "./sync/cache.js";
|
|
34
34
|
import { clearRecoveredPendingSourceReceipts, discoverSourceFiles, } from "./sync/discovery.js";
|
|
35
35
|
import { normalizeExtractionSources, processExtractions, } from "./sync/extraction.js";
|
|
36
|
-
import { refreshManifestCoordinates } from "./sync/manifest.js";
|
|
36
|
+
import { normalizeManifestLayout, refreshManifestCoordinates, } from "./sync/manifest.js";
|
|
37
37
|
import { persistEntities, persistRelationships, retractEntitiesById, retractEntitiesForSources, retractEntityRelationshipsById, retractRelationships, } from "./sync/persistence.js";
|
|
38
38
|
import { atomicPublish, atomicPublishGeneration, cleanupStaging, createUniqueStagingPath, prepareStagingEnvironment, } from "./sync/staging.js";
|
|
39
|
-
import { findUntrackedDocumentMatches } from "./sync/untracked-targets.js";
|
|
39
|
+
import { adoptUpsertOnlySymbolManifest, findUntrackedDocumentMatches, } from "./sync/untracked-targets.js";
|
|
40
40
|
// Manual deletion of a written-but-unstaged source leaves a recovery receipt
|
|
41
41
|
// behind; sync refuses to guess, so the error must name the way out.
|
|
42
42
|
const PENDING_SOURCE_RECOVERY_HINT = " If the file was deleted on purpose, run 'kibi branch recover --apply' to rebuild the branch KB from the sources that remain.";
|
|
@@ -202,6 +202,32 @@ async function checkpointNoopSync(workspaceRoot, branch) {
|
|
|
202
202
|
await engine.terminate();
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
+
/** Whether the branch's compiled store already holds any of `ids`. */
|
|
206
|
+
// implements REQ-cli-status-pre-first-sync
|
|
207
|
+
async function storeHoldsAnyEntity(workspaceRoot, branch, ids) {
|
|
208
|
+
const engine = new EngineClient({
|
|
209
|
+
workspaceRoot,
|
|
210
|
+
branch,
|
|
211
|
+
timeout: 120_000,
|
|
212
|
+
});
|
|
213
|
+
try {
|
|
214
|
+
await engine.start();
|
|
215
|
+
for (const id of ids) {
|
|
216
|
+
const found = await engine.queryEntities({ id, limit: 1, offset: 0 });
|
|
217
|
+
if (found.count > 0 || found.entities.length > 0)
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Adoption is best effort: an unreadable store adopts nothing and the
|
|
224
|
+
// compile below reports the store itself.
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
await engine.terminate();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
205
231
|
function compilerCacheHasEntityDelta(cache) {
|
|
206
232
|
return (cache.entityHashes !== undefined && cache.sourceEntityIds !== undefined);
|
|
207
233
|
}
|
|
@@ -354,6 +380,18 @@ export async function syncCommand(options = {}, runtime = {}) {
|
|
|
354
380
|
ensureBranchStoreManifest(workspaceRoot, currentBranch);
|
|
355
381
|
await ensureJournaledBranchStoreAsync(livePathForEngine);
|
|
356
382
|
}
|
|
383
|
+
// implements REQ-cli-status-pre-first-sync
|
|
384
|
+
// An untracked symbol manifest that only kb_upsert ever wrote (older Kibi
|
|
385
|
+
// left it without a pending-source receipt) gets the receipt here, so
|
|
386
|
+
// this sync compiles it and records its content hash. Without it the
|
|
387
|
+
// sources its symbols reference read as newer after every clone.
|
|
388
|
+
if (!validateOnly &&
|
|
389
|
+
recoveryBackupPath === undefined &&
|
|
390
|
+
options.detachedSnapshot === undefined &&
|
|
391
|
+
runtime.createProlog === undefined) {
|
|
392
|
+
const branch = currentBranch;
|
|
393
|
+
await adoptUpsertOnlySymbolManifest(workspaceRoot, (ids) => storeHoldsAnyEntity(workspaceRoot, branch, ids));
|
|
394
|
+
}
|
|
357
395
|
const needsExclusiveGenerationPublish = !validateOnly && (rebuild || recoveryBackupPath !== undefined);
|
|
358
396
|
if (needsExclusiveGenerationPublish) {
|
|
359
397
|
// Recovery intentionally avoids attaching the broken live store. The
|
|
@@ -413,6 +451,17 @@ export async function syncCommand(options = {}, runtime = {}) {
|
|
|
413
451
|
const relationshipShardFiles = existsSync(relationshipsDir)
|
|
414
452
|
? trackedRelationshipFiles(workspaceRoot, relationshipsDir, recoveryBackupPath !== undefined, recoveredPendingReceiptPaths)
|
|
415
453
|
: [];
|
|
454
|
+
// A manifest an older writer left in flow layout is rewritten as block
|
|
455
|
+
// YAML before anything hashes it, ahead of the no-op fast path below, so
|
|
456
|
+
// a project whose cache is already fresh still gets it on the next sync.
|
|
457
|
+
if (!validateOnly) {
|
|
458
|
+
for (const file of manifestFiles) {
|
|
459
|
+
const normalized = normalizeManifestLayout(file);
|
|
460
|
+
if (normalized !== null) {
|
|
461
|
+
console.log(`\u2713 Rewrote ${path.relative(workspaceRoot, file)} in block layout (${normalized} symbol${normalized === 1 ? "" : "s"})`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
416
465
|
// No-op is a first-class compiler result. Hashing the configured inputs is
|
|
417
466
|
// sufficient when normalized entity/shard inventories are already fresh;
|
|
418
467
|
// avoid rebuilding maps and rediscovering RDF state for the common path.
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAgCA,OAAO,EAEL,KAAK,iBAAiB,EAMvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACV,wBAAwB,EACxB,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -18,7 +18,7 @@ import { kibiPackageVersions } from "./package-versions.js";
|
|
|
18
18
|
import { writePerformanceTraceEvent } from "./performance-trace.js";
|
|
19
19
|
import { PrologProcess, resolveKbPlPath } from "./prolog.js";
|
|
20
20
|
import { parseEntityFromList, parseListOfLists } from "./prolog/codec.js";
|
|
21
|
-
import { retryAttachAfterBreakingStaleLock } from "./prolog/store-lock.js";
|
|
21
|
+
import { decideStoreLockTakeover, isProcessAlive, noteDeadHolderBeforeAttach, readRdfLockPid, recordStoreLockTakeover, retryAttachAfterBreakingStaleLock, } from "./prolog/store-lock.js";
|
|
22
22
|
import { resolveSwipl, swiplIdentity } from "./prolog/swipl-resolver.js";
|
|
23
23
|
import { queryEntityChunks } from "./public/operations/discovery-entities.js";
|
|
24
24
|
import { isValidBranchName } from "./utils/branch-resolver.js";
|
|
@@ -636,31 +636,19 @@ function recoverStaleJournalLock(branchPath) {
|
|
|
636
636
|
const lockPath = path.join(branchPath, "rdf", "lock");
|
|
637
637
|
if (!existsSync(lockPath))
|
|
638
638
|
return;
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
contents = readFileSync(lockPath, "utf8");
|
|
642
|
-
}
|
|
643
|
-
catch {
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
const match = /pid\((\d+)\)/.exec(contents);
|
|
647
|
-
if (!match)
|
|
648
|
-
return;
|
|
649
|
-
const pid = Number.parseInt(match[1] ?? "", 10);
|
|
650
|
-
if (!Number.isFinite(pid) || pid <= 0 || pid === process.pid)
|
|
639
|
+
const pid = readRdfLockPid(lockPath);
|
|
640
|
+
if (pid === null || pid === process.pid || isProcessAlive(pid))
|
|
651
641
|
return;
|
|
642
|
+
// implements REQ-core-journaled-engine-persistence
|
|
643
|
+
// Breaking a dead holder's lock is a takeover; record it for kb_status and
|
|
644
|
+
// kibi doctor instead of healing silently.
|
|
645
|
+
recordStoreLockTakeover(branchPath, pid, decideStoreLockTakeover({ pid }).reason);
|
|
652
646
|
try {
|
|
653
|
-
|
|
654
|
-
return;
|
|
647
|
+
rmSync(lockPath, { force: true });
|
|
655
648
|
}
|
|
656
649
|
catch {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
660
|
-
catch {
|
|
661
|
-
// Let rdf_attach_db report the lock error if another process wins the
|
|
662
|
-
// race between the liveness probe and removal.
|
|
663
|
-
}
|
|
650
|
+
// Let rdf_attach_db report the lock error if another process wins the
|
|
651
|
+
// race between the liveness probe and removal.
|
|
664
652
|
}
|
|
665
653
|
}
|
|
666
654
|
function daemonEntry() {
|
|
@@ -1565,8 +1553,13 @@ export class EngineSession {
|
|
|
1565
1553
|
}
|
|
1566
1554
|
async boot() {
|
|
1567
1555
|
await this.prolog.start();
|
|
1556
|
+
// A killed holder never makes kb_attach fail (its OS lock died with it),
|
|
1557
|
+
// so a dead-holder takeover must be noted before the attach succeeds.
|
|
1558
|
+
const recordTakeover = noteDeadHolderBeforeAttach(this.branchPath);
|
|
1568
1559
|
const attached = await this.prolog.query(`kb_attach('${quoteProlog(this.branchPath)}')`);
|
|
1569
|
-
if (
|
|
1560
|
+
if (attached.success)
|
|
1561
|
+
recordTakeover();
|
|
1562
|
+
else {
|
|
1570
1563
|
// The daemon hosts the branch store for every later request, so a
|
|
1571
1564
|
// store-locked startup with a provably dead holder is auto-healed here
|
|
1572
1565
|
// exactly like the CLI runtime path; live holders abort the startup
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@ import { OperationError } from "../../cli-errors.js";
|
|
|
10
10
|
import { requirementSemanticText } from "../../extractors/markdown.js";
|
|
11
11
|
import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
12
12
|
import { CANONICAL_ENTITY_PATHS, isDerivedKbPath, } from "../../utils/kb-paths.js";
|
|
13
|
+
import { blockifySymbolManifest } from "../../utils/symbol-manifest-layout.js";
|
|
13
14
|
function digest(value) {
|
|
14
15
|
return createHash("sha256").update(value).digest("hex");
|
|
15
16
|
}
|
|
@@ -464,18 +465,10 @@ function renderSymbolManifest(entity, relationships, existingContent) {
|
|
|
464
465
|
throw new OperationError("SOURCE_FORMAT_INVALID", "Symbol manifest must contain a symbols array");
|
|
465
466
|
}
|
|
466
467
|
// implements REQ-core-persistence
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
|
|
470
|
-
const
|
|
471
|
-
if (sequence.flow === true) {
|
|
472
|
-
sequence.flow = false;
|
|
473
|
-
for (const item of sequence.items) {
|
|
474
|
-
if (item && typeof item === "object" && "flow" in item)
|
|
475
|
-
item.flow = false;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
const items = sequence.items;
|
|
468
|
+
// Render the list (and the entries that were written inside it) as block
|
|
469
|
+
// YAML so diffs stay reviewable.
|
|
470
|
+
blockifySymbolManifest(doc);
|
|
471
|
+
const items = symbols.items;
|
|
479
472
|
const id = String(entity.id);
|
|
480
473
|
const indices = items.flatMap((item, index) => {
|
|
481
474
|
if (!item || typeof item !== "object" || !("get" in item))
|
|
@@ -43,6 +43,25 @@ export type StoreLockTakeoverRecord = Readonly<{
|
|
|
43
43
|
export declare function recordStoreLockTakeover(storePath: string, brokenPid: number | null, reason: string, at?: Date): void;
|
|
44
44
|
/** The last takeover record of a branch store, or null when none is readable. */
|
|
45
45
|
export declare function readStoreLockTakeover(storePath: string): StoreLockTakeoverRecord | null;
|
|
46
|
+
/** The holder pid an rdf_persistency `lock` file records, or null. */
|
|
47
|
+
export declare function readRdfLockPid(lockPath: string): number | null;
|
|
48
|
+
/**
|
|
49
|
+
* Note, before `kb_attach`, whether a dead holder left this branch store
|
|
50
|
+
* locked, and return the step that records the takeover once the attach has
|
|
51
|
+
* succeeded.
|
|
52
|
+
*
|
|
53
|
+
* rdf_persistency locks the store with an OS advisory lock that the kernel
|
|
54
|
+
* releases when its holder dies, so a killed engine never makes the next
|
|
55
|
+
* attach fail with `store_locked`: the attach simply takes the store over.
|
|
56
|
+
* The only trace is the `rdf/lock` file, which SWI deletes on every detach
|
|
57
|
+
* and halt; one that is still present was left by a holder that crashed or
|
|
58
|
+
* was killed. Its holder (the ownership journal when it names the same
|
|
59
|
+
* process, which adds the boot id, else the lock file's pid) is classified
|
|
60
|
+
* the same way a `store_locked` failure is. The returned step is a no-op
|
|
61
|
+
* unless that holder is provably dead; callers run it only after a
|
|
62
|
+
* successful attach, which proves the holder no longer held the lock.
|
|
63
|
+
*/
|
|
64
|
+
export declare function noteDeadHolderBeforeAttach(kbPath: string): () => void;
|
|
46
65
|
export interface StoreLockTakeoverDecision {
|
|
47
66
|
readonly action: "break" | "surface";
|
|
48
67
|
readonly reason: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAqB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgBhF,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,oBAAoB,CAYtB;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAWzD;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAsB,CAAC;AAElE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,GAAE,IAAiB,GACpB,IAAI,CAUN;AAED,iFAAiF;AAEjF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAmBhC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,yBAAyB,CAoB3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AAEH,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAiCtB"}
|
|
1
|
+
{"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAqB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgBhF,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,oBAAoB,CAYtB;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAWzD;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAsB,CAAC;AAElE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,GAAE,IAAiB,GACpB,IAAI,CAUN;AAED,iFAAiF;AAEjF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAmBhC;AAED,sEAAsE;AAEtE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAerE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,yBAAyB,CAoB3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AAEH,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAiCtB"}
|
|
@@ -176,6 +176,52 @@ export function readStoreLockTakeover(storePath) {
|
|
|
176
176
|
return null;
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
|
+
/** The holder pid an rdf_persistency `lock` file records, or null. */
|
|
180
|
+
// implements REQ-core-journaled-engine-persistence
|
|
181
|
+
export function readRdfLockPid(lockPath) {
|
|
182
|
+
try {
|
|
183
|
+
const match = /pid\((\d+)\)/.exec(readFileSync(lockPath, "utf8"));
|
|
184
|
+
const pid = Number.parseInt(match?.[1] ?? "", 10);
|
|
185
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Note, before `kb_attach`, whether a dead holder left this branch store
|
|
193
|
+
* locked, and return the step that records the takeover once the attach has
|
|
194
|
+
* succeeded.
|
|
195
|
+
*
|
|
196
|
+
* rdf_persistency locks the store with an OS advisory lock that the kernel
|
|
197
|
+
* releases when its holder dies, so a killed engine never makes the next
|
|
198
|
+
* attach fail with `store_locked`: the attach simply takes the store over.
|
|
199
|
+
* The only trace is the `rdf/lock` file, which SWI deletes on every detach
|
|
200
|
+
* and halt; one that is still present was left by a holder that crashed or
|
|
201
|
+
* was killed. Its holder (the ownership journal when it names the same
|
|
202
|
+
* process, which adds the boot id, else the lock file's pid) is classified
|
|
203
|
+
* the same way a `store_locked` failure is. The returned step is a no-op
|
|
204
|
+
* unless that holder is provably dead; callers run it only after a
|
|
205
|
+
* successful attach, which proves the holder no longer held the lock.
|
|
206
|
+
*/
|
|
207
|
+
// implements REQ-core-journaled-engine-persistence
|
|
208
|
+
export function noteDeadHolderBeforeAttach(kbPath) {
|
|
209
|
+
const lockPath = join(kbPath, "rdf", "lock");
|
|
210
|
+
if (!existsSync(lockPath))
|
|
211
|
+
return () => undefined;
|
|
212
|
+
const lockPid = readRdfLockPid(lockPath);
|
|
213
|
+
const journal = readStoreLockOwner(kbPath)?.owner ?? null;
|
|
214
|
+
const owner = journal !== null && (lockPid === null || journal.pid === lockPid)
|
|
215
|
+
? journal
|
|
216
|
+
: lockPid !== null
|
|
217
|
+
? { pid: lockPid }
|
|
218
|
+
: null;
|
|
219
|
+
const decision = decideStoreLockTakeover(owner);
|
|
220
|
+
if (decision.action !== "break")
|
|
221
|
+
return () => undefined;
|
|
222
|
+
const brokenPid = owner?.pid ?? null;
|
|
223
|
+
return () => recordStoreLockTakeover(kbPath, brokenPid, decision.reason);
|
|
224
|
+
}
|
|
179
225
|
/**
|
|
180
226
|
* Decide whether a store-locked failure may be auto-healed. Only a provably
|
|
181
227
|
* dead holder (or a holder from a previous boot) is broken; live or unknown
|
package/dist/proof/inspect.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type ProofInspection = Readonly<{
|
|
|
28
28
|
integrationPlanReason: string;
|
|
29
29
|
}>;
|
|
30
30
|
export type ProofInspectionOptions = Readonly<{
|
|
31
|
-
/** Plan
|
|
31
|
+
/** Plan adding this integration id, or replacing it when it exists. */
|
|
32
32
|
update?: string;
|
|
33
33
|
/** Command (argv) the proposed integration runs instead of the detected one. */
|
|
34
34
|
command?: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/proof/inspect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAC;AAM/B,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,gFAAgF;IAChF,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yEAAyE;IACzE,mBAAmB,EAAE,SAAS,QAAQ,CAAC;QACrC,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;KAC5B,CAAC,EAAE,CAAC;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,qEAAqE;IACrE,mBAAmB,EAAE,mBAAmB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC/D,6EAA6E;IAC7E,gBAAgB,EAAE,mBAAmB,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC;IACjE;;;OAGG;IACH,eAAe,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,sDAAsD;IACtD,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/proof/inspect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,uBAAuB,CAAC;AAM/B,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,gFAAgF;IAChF,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yEAAyE;IACzE,mBAAmB,EAAE,SAAS,QAAQ,CAAC;QACrC,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;KAC5B,CAAC,EAAE,CAAC;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,qEAAqE;IACrE,mBAAmB,EAAE,mBAAmB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC/D,6EAA6E;IAC7E,gBAAgB,EAAE,mBAAmB,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC;IACjE;;;OAGG;IACH,eAAe,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,sDAAsD;IACtD,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC,CAAC;AAwIH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAMT;AA2BD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,sBAA2B,GACnC,eAAe,CAiHjB"}
|
package/dist/proof/inspect.js
CHANGED
|
@@ -219,9 +219,16 @@ export function inspectProofEnvironment(root, options = {}) {
|
|
|
219
219
|
: [];
|
|
220
220
|
const planned = buildProofIntegrationPlan(root, options);
|
|
221
221
|
const applyHint = "review integrationPlan, then apply it with kb_apply_plan (or `kibi apply-plan --input -`) passing plan, approvedPlanHash = plan.planHash and approvedActionIds";
|
|
222
|
+
const updateId = options.update?.trim() || undefined;
|
|
222
223
|
let recommendation;
|
|
223
|
-
if (planned.plan !== null &&
|
|
224
|
-
|
|
224
|
+
if (planned.plan !== null && updateId !== undefined) {
|
|
225
|
+
// implements REQ-kibi-verification-evidence-contract
|
|
226
|
+
// The plan adds an id the file does not have yet; only an existing one is
|
|
227
|
+
// replaced.
|
|
228
|
+
const verb = currentIntegrations.some((entry) => entry.id === updateId)
|
|
229
|
+
? "replace"
|
|
230
|
+
: "add";
|
|
231
|
+
recommendation = `To ${verb} integration '${updateId}', ${applyHint}.`;
|
|
225
232
|
}
|
|
226
233
|
else if (!integrations.available) {
|
|
227
234
|
if (planned.plan === null) {
|