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.
Files changed (46) hide show
  1. package/dist/cli-operation-metadata.d.ts +1 -1
  2. package/dist/cli-operation-metadata.js +1 -1
  3. package/dist/commands/doctor.js +11 -5
  4. package/dist/commands/sync/manifest.d.ts +10 -0
  5. package/dist/commands/sync/manifest.d.ts.map +1 -1
  6. package/dist/commands/sync/manifest.js +27 -0
  7. package/dist/commands/sync/untracked-targets.d.ts +17 -0
  8. package/dist/commands/sync/untracked-targets.d.ts.map +1 -1
  9. package/dist/commands/sync/untracked-targets.js +43 -1
  10. package/dist/commands/sync.d.ts.map +1 -1
  11. package/dist/commands/sync.js +51 -2
  12. package/dist/engine.d.ts.map +1 -1
  13. package/dist/engine.js +16 -23
  14. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  15. package/dist/operations/mutation/source-authoring.js +5 -12
  16. package/dist/prolog/store-lock.d.ts +19 -0
  17. package/dist/prolog/store-lock.d.ts.map +1 -1
  18. package/dist/prolog/store-lock.js +46 -0
  19. package/dist/proof/inspect.d.ts +1 -1
  20. package/dist/proof/inspect.d.ts.map +1 -1
  21. package/dist/proof/inspect.js +9 -2
  22. package/dist/public/operations/catalog.d.ts +50 -1
  23. package/dist/public/operations/catalog.d.ts.map +1 -1
  24. package/dist/public/operations/contracts.js +1 -4
  25. package/dist/public/operations/discovery-executors.d.ts +36 -0
  26. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  27. package/dist/public/operations/discovery-executors.js +361 -1
  28. package/dist/public/operations/specs/discovery.d.ts +50 -1
  29. package/dist/public/operations/specs/discovery.d.ts.map +1 -1
  30. package/dist/public/operations/specs/discovery.js +56 -1
  31. package/dist/public/skills/kibi-usage/SKILL.md +9 -1
  32. package/dist/runtime/cli-runtime.d.ts.map +1 -1
  33. package/dist/runtime/cli-runtime.js +7 -2
  34. package/dist/search-answer.d.ts +12 -3
  35. package/dist/search-answer.d.ts.map +1 -1
  36. package/dist/search-answer.js +51 -4
  37. package/dist/utils/content-freshness.d.ts.map +1 -1
  38. package/dist/utils/content-freshness.js +12 -2
  39. package/dist/utils/symbol-manifest-layout.d.ts +9 -0
  40. package/dist/utils/symbol-manifest-layout.d.ts.map +1 -0
  41. package/dist/utils/symbol-manifest-layout.js +18 -0
  42. package/package.json +2 -2
  43. package/src/public/operations/contracts.ts +4 -4
  44. package/src/public/operations/discovery-executors.ts +472 -0
  45. package/src/public/operations/specs/discovery.ts +67 -1
  46. 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 discovery and lookup before edits. Do not use for writes. No mutation side effects. Tags filter by metadata tags only, not entity IDs.";
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 discovery and lookup before edits. Do not use for writes. No mutation side effects. Tags filter by metadata tags only, not entity IDs.",
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",
@@ -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})` : ""}${takeover ? `. ${String(takeover.detail)}` : ""}`,
705
+ message: withTakeover(`Compiled for ${branch}${compilation.generation ? ` (${compilation.generation})` : ""}`),
701
706
  details: {
702
707
  ...details,
703
708
  generation: compilation.generation,
704
- ...(takeover ? { lockTakeover: takeover } : {}),
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;AAC9D,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;AAE5E,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,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"}
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":"AAyBA,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"}
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 { isSymbolsManifestPath } from "../../utils/kb-paths.js";
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;AA4BxE,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;AAqDD,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,CAipCrB;AAED,OAAO,EAAE,qBAAqB,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"}
@@ -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.
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
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
- let contents = "";
640
- try {
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
- process.kill(pid, 0);
654
- return;
647
+ rmSync(lockPath, { force: true });
655
648
  }
656
649
  catch {
657
- try {
658
- rmSync(lockPath, { force: true });
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 (!attached.success) {
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;AAMjF,OAAO,KAAK,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAmBH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAiBN;AAED,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAExD,8EAA8E;AAE9E,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOpE;AAED;;;;GAIG;AAEH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS,GAAG,IAAI,GACtB,IAAI,CAON;AAeD;;;;GAIG;AAEH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,IAAI,CAMN;AAgBD,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqCR;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR;AAsBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAET;AAkGD,uFAAuF;AAEvF,eAAO,MAAM,uBAAuB,uGAM1B,CAAC;AA8BX,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,GACZ,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCzC;AAgSD,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB;IAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CA6C7C;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4DpC;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAiEpC;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GACnB,MAAM,CAsBR;AAED;;;;;;;GAOG;AAEH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAaT;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC5C,OAAO,CAAC,EAAE,gBAAgB,EAC1B,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC;IACT,OAAO,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,GAAG,IAAI,CAAC,CA+IR;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC3C,MAAM,CAOR"}
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;AAOjF,OAAO,KAAK,EAAqB,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC,CAAC;AAmBH,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAiBN;AAED,KAAK,SAAS,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAExD,8EAA8E;AAE9E,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOpE;AAED;;;;GAIG;AAEH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS,GAAG,IAAI,GACtB,IAAI,CAON;AAeD;;;;GAIG;AAEH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,IAAI,CAMN;AAgBD,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqCR;AAED,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,MAAM,CAoBR;AAsBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAET;AAkGD,uFAAuF;AAEvF,eAAO,MAAM,uBAAuB,uGAM1B,CAAC;AA8BX,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,GACZ,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCzC;AAwRD,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB;IAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CA6C7C;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA4DpC;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAiEpC;AAED;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,YAAY,EAAE,MAAM,GACnB,MAAM,CAsBR;AAED;;;;;;;GAOG;AAEH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAaT;AAED,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC5C,OAAO,CAAC,EAAE,gBAAgB,EAC1B,sBAAsB,CAAC,EAAE,MAAM,GAC9B,OAAO,CAAC;IACT,OAAO,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,GAAG,IAAI,CAAC,CA+IR;AAED,uEAAuE;AACvE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC3C,MAAM,CAOR"}
@@ -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
- // `kibi init` writes `symbols: []`, a flow sequence; appending to it kept
468
- // every symbol on one line. Render the list (and the entries that were
469
- // written inside it) as block YAML so diffs stay reviewable.
470
- const sequence = symbols;
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
@@ -28,7 +28,7 @@ export type ProofInspection = Readonly<{
28
28
  integrationPlanReason: string;
29
29
  }>;
30
30
  export type ProofInspectionOptions = Readonly<{
31
- /** Plan a replacement of this existing integration id. */
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,0DAA0D;IAC1D,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,CA0GjB"}
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"}
@@ -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 && options.update !== undefined) {
224
- recommendation = `To replace integration '${options.update}', ${applyHint}.`;
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) {