kibi-cli 2.1.0 → 2.2.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 (246) hide show
  1. package/dist/cli-protocol.d.ts.map +1 -1
  2. package/dist/cli-protocol.js +3 -2
  3. package/dist/commands/aggregated-checks.d.ts +7 -0
  4. package/dist/commands/aggregated-checks.d.ts.map +1 -1
  5. package/dist/commands/aggregated-checks.js +25 -1
  6. package/dist/commands/check.d.ts.map +1 -1
  7. package/dist/commands/check.js +21 -13
  8. package/dist/commands/doctor.d.ts.map +1 -1
  9. package/dist/commands/doctor.js +105 -24
  10. package/dist/commands/github-init.d.ts +1 -1
  11. package/dist/commands/github-init.d.ts.map +1 -1
  12. package/dist/commands/github-init.js +1 -1
  13. package/dist/commands/init-helpers.d.ts +17 -2
  14. package/dist/commands/init-helpers.d.ts.map +1 -1
  15. package/dist/commands/init-helpers.js +123 -23
  16. package/dist/commands/init.d.ts.map +1 -1
  17. package/dist/commands/init.js +110 -15
  18. package/dist/commands/prove.d.ts.map +1 -1
  19. package/dist/commands/prove.js +10 -18
  20. package/dist/commands/sync/cache.d.ts +20 -1
  21. package/dist/commands/sync/cache.d.ts.map +1 -1
  22. package/dist/commands/sync/cache.js +51 -2
  23. package/dist/commands/sync/discovery.d.ts.map +1 -1
  24. package/dist/commands/sync/discovery.js +1 -1
  25. package/dist/commands/sync/persistence.d.ts.map +1 -1
  26. package/dist/commands/sync/persistence.js +8 -0
  27. package/dist/commands/sync.d.ts.map +1 -1
  28. package/dist/commands/sync.js +11 -3
  29. package/dist/engine.d.ts +26 -0
  30. package/dist/engine.d.ts.map +1 -1
  31. package/dist/engine.js +126 -29
  32. package/dist/extractors/manifest.d.ts.map +1 -1
  33. package/dist/extractors/manifest.js +66 -28
  34. package/dist/extractors/markdown.d.ts +2 -0
  35. package/dist/extractors/markdown.d.ts.map +1 -1
  36. package/dist/extractors/markdown.js +14 -3
  37. package/dist/extractors/relationships.d.ts.map +1 -1
  38. package/dist/extractors/relationships.js +1 -0
  39. package/dist/intent-search.d.ts.map +1 -1
  40. package/dist/intent-search.js +68 -29
  41. package/dist/operations/bootstrap/generate.d.ts.map +1 -1
  42. package/dist/operations/bootstrap/generate.js +4 -3
  43. package/dist/operations/modeling/model-requirement.d.ts +1 -1
  44. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  45. package/dist/operations/modeling/model-requirement.js +176 -10
  46. package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
  47. package/dist/operations/modeling/predicate-applyplan.js +14 -2
  48. package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
  49. package/dist/operations/modeling/predicate-loader.js +24 -0
  50. package/dist/operations/modeling/predicate-types.d.ts +4 -0
  51. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  52. package/dist/operations/modeling/predicate-vocabulary.d.ts +54 -0
  53. package/dist/operations/modeling/predicate-vocabulary.d.ts.map +1 -0
  54. package/dist/operations/modeling/predicate-vocabulary.js +169 -0
  55. package/dist/operations/modeling/requirement-types.d.ts +5 -0
  56. package/dist/operations/modeling/requirement-types.d.ts.map +1 -1
  57. package/dist/operations/modeling/vocabulary-alignment.d.ts +60 -0
  58. package/dist/operations/modeling/vocabulary-alignment.d.ts.map +1 -0
  59. package/dist/operations/modeling/vocabulary-alignment.js +178 -0
  60. package/dist/operations/mutation/contradictions.d.ts +3 -0
  61. package/dist/operations/mutation/contradictions.d.ts.map +1 -1
  62. package/dist/operations/mutation/contradictions.js +29 -0
  63. package/dist/operations/mutation/delete.d.ts.map +1 -1
  64. package/dist/operations/mutation/delete.js +33 -1
  65. package/dist/operations/mutation/predicate-vocabulary-guard.d.ts +8 -0
  66. package/dist/operations/mutation/predicate-vocabulary-guard.d.ts.map +1 -0
  67. package/dist/operations/mutation/predicate-vocabulary-guard.js +64 -0
  68. package/dist/operations/mutation/relationships.d.ts +1 -1
  69. package/dist/operations/mutation/relationships.d.ts.map +1 -1
  70. package/dist/operations/mutation/relationships.js +1 -0
  71. package/dist/operations/mutation/saga.d.ts +5 -0
  72. package/dist/operations/mutation/saga.d.ts.map +1 -1
  73. package/dist/operations/mutation/saga.js +10 -0
  74. package/dist/operations/mutation/serialization.d.ts.map +1 -1
  75. package/dist/operations/mutation/serialization.js +2 -0
  76. package/dist/operations/mutation/source-authoring.d.ts +6 -0
  77. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  78. package/dist/operations/mutation/source-authoring.js +65 -26
  79. package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
  80. package/dist/operations/mutation/strict-fact.js +5 -0
  81. package/dist/operations/mutation/types.d.ts +17 -0
  82. package/dist/operations/mutation/types.d.ts.map +1 -1
  83. package/dist/operations/mutation/upsert.d.ts +6 -0
  84. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  85. package/dist/operations/mutation/upsert.js +72 -4
  86. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  87. package/dist/operations/mutation/validate-upsert.js +24 -1
  88. package/dist/operations/mutation/validation.d.ts.map +1 -1
  89. package/dist/operations/mutation/validation.js +16 -3
  90. package/dist/operations/planning/apply-plan.d.ts.map +1 -1
  91. package/dist/operations/planning/apply-plan.js +61 -17
  92. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  93. package/dist/operations/planning/compile-intent.js +3 -1
  94. package/dist/operations/proof/code-scope.d.ts +17 -0
  95. package/dist/operations/proof/code-scope.d.ts.map +1 -0
  96. package/dist/operations/proof/code-scope.js +60 -0
  97. package/dist/operations/proof/ingest-proof.d.ts +4 -2
  98. package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
  99. package/dist/operations/proof/ingest-proof.js +207 -74
  100. package/dist/operations/proof/migrate-legacy-receipts.d.ts.map +1 -1
  101. package/dist/operations/proof/migrate-legacy-receipts.js +7 -5
  102. package/dist/operations/proof/prune-receipts.d.ts.map +1 -1
  103. package/dist/operations/proof/prune-receipts.js +7 -5
  104. package/dist/plugins/compose-semantic-classifier.d.ts +6 -1
  105. package/dist/plugins/compose-semantic-classifier.d.ts.map +1 -1
  106. package/dist/plugins/compose-semantic-classifier.js +8 -3
  107. package/dist/plugins/compose-vocabulary-alignment.d.ts +23 -0
  108. package/dist/plugins/compose-vocabulary-alignment.d.ts.map +1 -0
  109. package/dist/plugins/compose-vocabulary-alignment.js +141 -0
  110. package/dist/plugins/external-allowlist.d.ts +7 -0
  111. package/dist/plugins/external-allowlist.d.ts.map +1 -1
  112. package/dist/plugins/external-allowlist.js +13 -0
  113. package/dist/plugins/index.d.ts +2 -0
  114. package/dist/plugins/index.d.ts.map +1 -1
  115. package/dist/plugins/index.js +4 -0
  116. package/dist/plugins/registry.d.ts +2 -1
  117. package/dist/plugins/registry.d.ts.map +1 -1
  118. package/dist/plugins/registry.js +22 -1
  119. package/dist/prolog/codec.d.ts.map +1 -1
  120. package/dist/prolog/codec.js +2 -0
  121. package/dist/prolog.d.ts +36 -0
  122. package/dist/prolog.d.ts.map +1 -1
  123. package/dist/prolog.js +78 -9
  124. package/dist/public/diagnostic-usage.d.ts.map +1 -1
  125. package/dist/public/diagnostic-usage.js +7 -25
  126. package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
  127. package/dist/public/impact/full-kb-quality.js +4 -12
  128. package/dist/public/operations/catalog.d.ts +36 -7
  129. package/dist/public/operations/catalog.d.ts.map +1 -1
  130. package/dist/public/operations/check-executor.d.ts.map +1 -1
  131. package/dist/public/operations/check-executor.js +10 -2
  132. package/dist/public/operations/check-helpers.d.ts +6 -0
  133. package/dist/public/operations/check-helpers.d.ts.map +1 -1
  134. package/dist/public/operations/check-helpers.js +21 -1
  135. package/dist/public/operations/contracts.d.ts.map +1 -1
  136. package/dist/public/operations/contracts.js +16 -0
  137. package/dist/public/operations/discovery-entities.d.ts +42 -2
  138. package/dist/public/operations/discovery-entities.d.ts.map +1 -1
  139. package/dist/public/operations/discovery-entities.js +195 -22
  140. package/dist/public/operations/discovery-executors.d.ts +1 -0
  141. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  142. package/dist/public/operations/discovery-executors.js +75 -46
  143. package/dist/public/operations/migration-plan.d.ts +2 -0
  144. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  145. package/dist/public/operations/migration-plan.js +50 -0
  146. package/dist/public/operations/predicate-schema-conformance.d.ts +41 -0
  147. package/dist/public/operations/predicate-schema-conformance.d.ts.map +1 -0
  148. package/dist/public/operations/predicate-schema-conformance.js +242 -0
  149. package/dist/public/operations/prolog-json.d.ts.map +1 -1
  150. package/dist/public/operations/prolog-json.js +9 -3
  151. package/dist/public/operations/result-envelope.d.ts +34 -1
  152. package/dist/public/operations/result-envelope.d.ts.map +1 -1
  153. package/dist/public/operations/result-envelope.js +78 -2
  154. package/dist/public/operations/runtime-types.d.ts +1 -1
  155. package/dist/public/operations/runtime-types.d.ts.map +1 -1
  156. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  157. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  158. package/dist/public/operations/specs/check-rules.generated.js +8 -1
  159. package/dist/public/operations/specs/check.d.ts +1 -1
  160. package/dist/public/operations/specs/discovery.d.ts +7 -1
  161. package/dist/public/operations/specs/discovery.d.ts.map +1 -1
  162. package/dist/public/operations/specs/discovery.js +7 -1
  163. package/dist/public/operations/specs/mutation-schemas.d.ts +27 -4
  164. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  165. package/dist/public/operations/specs/mutation-schemas.js +21 -3
  166. package/dist/public/operations/specs/reporting.d.ts +8 -0
  167. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  168. package/dist/public/operations/specs/reporting.js +46 -15
  169. package/dist/public/operations/specs/upsert.d.ts +28 -5
  170. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  171. package/dist/public/operations/specs/upsert.js +1 -1
  172. package/dist/public/operations/symbol-repair-plan.d.ts.map +1 -1
  173. package/dist/public/operations/symbol-repair-plan.js +8 -3
  174. package/dist/public/schemas/entity.d.ts.map +1 -1
  175. package/dist/public/schemas/entity.js +22 -0
  176. package/dist/public/schemas/relationship.d.ts.map +1 -1
  177. package/dist/public/schemas/relationship.js +1 -0
  178. package/dist/public/skills/kibi-usage/SKILL.md +7 -3
  179. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +4 -0
  180. package/dist/public/skills/kibi-usage/resources/relationship-directions.md +35 -17
  181. package/dist/public/skills/kibi-usage/resources/source-authoring.md +36 -0
  182. package/dist/public/skills/kibi-usage/resources/workflows.md +52 -1
  183. package/dist/public/telemetry-acceptance.d.ts.map +1 -1
  184. package/dist/public/telemetry-acceptance.js +21 -5
  185. package/dist/relationships/shards.d.ts +6 -0
  186. package/dist/relationships/shards.d.ts.map +1 -1
  187. package/dist/relationships/shards.js +26 -19
  188. package/dist/schemas/entity.schema.json +32 -0
  189. package/dist/traceability/staged-diagnostics.d.ts +1 -1
  190. package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
  191. package/dist/traceability/staged-entity-id-style.d.ts +12 -0
  192. package/dist/traceability/staged-entity-id-style.d.ts.map +1 -0
  193. package/dist/traceability/staged-entity-id-style.js +68 -0
  194. package/dist/traceability/temp-kb.d.ts.map +1 -1
  195. package/dist/traceability/temp-kb.js +8 -0
  196. package/dist/traceability/validate.js +1 -1
  197. package/dist/types/entities.d.ts +2 -0
  198. package/dist/types/entities.d.ts.map +1 -1
  199. package/dist/types/relationships.d.ts +1 -1
  200. package/dist/types/relationships.d.ts.map +1 -1
  201. package/dist/utils/entity-id-style.d.ts +27 -0
  202. package/dist/utils/entity-id-style.d.ts.map +1 -0
  203. package/dist/utils/entity-id-style.js +81 -0
  204. package/dist/utils/git-repository-context.d.ts +50 -0
  205. package/dist/utils/git-repository-context.d.ts.map +1 -0
  206. package/dist/utils/git-repository-context.js +259 -0
  207. package/dist/utils/rule-registry.d.ts +5 -0
  208. package/dist/utils/rule-registry.d.ts.map +1 -1
  209. package/dist/utils/rule-registry.generated.d.ts +37 -0
  210. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  211. package/dist/utils/rule-registry.generated.js +44 -0
  212. package/dist/utils/strict-modeling.d.ts +7 -0
  213. package/dist/utils/strict-modeling.d.ts.map +1 -1
  214. package/dist/utils/strict-modeling.js +11 -0
  215. package/package.json +4 -4
  216. package/schema/entities.pl +60 -1
  217. package/schema/relationships.pl +17 -4
  218. package/schema/validation.pl +118 -20
  219. package/src/public/diagnostic-usage.ts +16 -24
  220. package/src/public/impact/full-kb-quality.ts +4 -16
  221. package/src/public/operations/check-executor.ts +12 -1
  222. package/src/public/operations/check-helpers.ts +27 -1
  223. package/src/public/operations/contracts.ts +19 -0
  224. package/src/public/operations/discovery-entities.ts +292 -23
  225. package/src/public/operations/discovery-executors.ts +91 -55
  226. package/src/public/operations/migration-plan.ts +57 -0
  227. package/src/public/operations/predicate-schema-conformance.ts +362 -0
  228. package/src/public/operations/prolog-json.ts +9 -3
  229. package/src/public/operations/result-envelope.ts +114 -2
  230. package/src/public/operations/runtime-types.ts +1 -1
  231. package/src/public/operations/specs/check-rules.generated.ts +8 -1
  232. package/src/public/operations/specs/discovery.ts +8 -1
  233. package/src/public/operations/specs/mutation-schemas.ts +23 -3
  234. package/src/public/operations/specs/reporting.ts +69 -22
  235. package/src/public/operations/specs/upsert.ts +1 -1
  236. package/src/public/operations/symbol-repair-plan.ts +13 -3
  237. package/src/public/schemas/entity.ts +22 -0
  238. package/src/public/schemas/relationship.ts +1 -0
  239. package/src/public/skills/kibi-usage/SKILL.md +7 -3
  240. package/src/public/skills/kibi-usage/resources/fact-lanes.md +4 -0
  241. package/src/public/skills/kibi-usage/resources/relationship-directions.md +35 -17
  242. package/src/public/skills/kibi-usage/resources/source-authoring.md +36 -0
  243. package/src/public/skills/kibi-usage/resources/workflows.md +52 -1
  244. package/src/public/telemetry-acceptance.ts +37 -6
  245. package/src/schemas/entity.schema.json +32 -0
  246. package/src/schemas/relationship.schema.json +1 -0
@@ -15,7 +15,7 @@
15
15
  You should have received a copy of the GNU Affero General Public License
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
- import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
18
+ import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import fg from "fast-glob";
21
21
  import { getBranchDiagnostic, resolveActiveBranch, } from "../utils/branch-resolver.js";
@@ -236,41 +236,141 @@ const KIBI_HOOK_END = "# END kibi-managed";
236
236
  function escapeRegex(s) {
237
237
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
238
238
  }
239
+ function hookIntegrationRecipe(hook) {
240
+ // Recipes must reproduce the exact checks the Kibi template runs for that
241
+ // hook, with failure propagation, or the delegation is weaker than the
242
+ // template it replaces.
243
+ switch (hook) {
244
+ case "pre-commit":
245
+ return "delegate from that hook with 'kibi check-generated --staged --changed-only && kibi check --staged' (both commands must succeed; '&&' propagates the first failure)";
246
+ case "post-checkout":
247
+ return "delegate from that hook to 'kibi sync' on branch checkouts (the template skips file checkouts)";
248
+ case "post-merge":
249
+ return "delegate from that hook to 'kibi sync'";
250
+ case "post-rewrite":
251
+ return "delegate from that hook to 'kibi sync' after rebase/amend rewrites";
252
+ default:
253
+ return "delegate to the matching Kibi template command";
254
+ }
255
+ }
239
256
  export function installHook(hookPath, content) {
240
257
  // implements REQ-008
258
+ // implements REQ-git-hook-effective-install
241
259
  const kibiSection = `${KIBI_HOOK_BEGIN}\n${content}\n${KIBI_HOOK_END}`;
242
- if (existsSync(hookPath)) {
260
+ let hookStats;
261
+ try {
262
+ hookStats = lstatSync(hookPath);
263
+ }
264
+ catch (error) {
265
+ if (error.code === "ENOENT" ||
266
+ error.code === "ENOTDIR") {
267
+ // Missing hook: create it through the parent directory. Refuse when an
268
+ // ancestor is itself a symlink whose target leaves the resolved path
269
+ // (realpath is checked by the caller's hooks-dir guard).
270
+ writeFileSync(hookPath, `#!/bin/sh\n${kibiSection}\n`, { mode: 0o755 });
271
+ chmodSync(hookPath, 0o755);
272
+ return "installed";
273
+ }
274
+ console.error(`! Unable to inspect ${hookPath}: ${error.message}; leaving it untouched.`);
275
+ return "skipped-unsupported";
276
+ }
277
+ if (hookStats.isSymbolicLink()) {
278
+ // Never follow a symlinked hook: read/write/chmod would modify an
279
+ // arbitrary target outside our guard. Dangling symlinks are treated the
280
+ // same (the intended target must not be auto-created either).
281
+ return "skipped-symlink";
282
+ }
283
+ if (!hookStats.isFile()) {
284
+ return "skipped-unsupported";
285
+ }
286
+ try {
243
287
  const existing = readFileSync(hookPath, "utf8");
244
288
  if (existing.includes(KIBI_HOOK_BEGIN) &&
245
289
  existing.includes(KIBI_HOOK_END)) {
246
290
  // Replace only the kibi-managed section, preserving any user-authored content
247
291
  const updated = existing.replace(new RegExp(`${escapeRegex(KIBI_HOOK_BEGIN)}[\\s\\S]*?${escapeRegex(KIBI_HOOK_END)}`), kibiSection);
248
292
  writeFileSync(hookPath, updated, { mode: 0o755 });
293
+ chmodSync(hookPath, 0o755);
294
+ return "updated";
249
295
  }
250
- else if (existing.trim().length > 0) {
251
- return;
252
- }
253
- else {
254
- const shebang = existing.startsWith("#!/") ? "" : "#!/bin/sh\n";
255
- writeFileSync(hookPath, `${shebang}${existing.trimEnd()}\n${kibiSection}\n`, { mode: 0o755 });
296
+ if (existing.trim().length > 0) {
297
+ // A hook we did not write: never overwrite foreign enforcement.
298
+ return "skipped-foreign";
256
299
  }
300
+ const shebang = existing.startsWith("#!/") ? "" : "#!/bin/sh\n";
301
+ writeFileSync(hookPath, `${shebang}${existing.trimEnd()}\n${kibiSection}\n`, { mode: 0o755 });
302
+ chmodSync(hookPath, 0o755);
303
+ return "installed";
257
304
  }
258
- else {
259
- writeFileSync(hookPath, `#!/bin/sh\n${kibiSection}\n`, { mode: 0o755 });
305
+ catch (error) {
306
+ console.error(`! Unable to read ${hookPath}: ${error.message}; leaving it untouched.`);
307
+ return "skipped-unsupported";
260
308
  }
261
- // Explicitly ensure hook is executable
262
- chmodSync(hookPath, 0o755);
263
309
  }
264
- export function installGitHooks(gitDir) {
265
- const hooksDir = path.join(gitDir, "hooks");
310
+ /** Kibi-managed hooks in install order, with the template each one installs. */
311
+ const MANAGED_HOOK_TEMPLATES = [
312
+ ["post-checkout", POST_CHECKOUT_HOOK],
313
+ ["post-merge", POST_MERGE_HOOK],
314
+ ["post-rewrite", POST_REWRITE_HOOK],
315
+ ["pre-commit", PRE_COMMIT_HOOK],
316
+ ];
317
+ function managedHookBody(template) {
318
+ return template.replace("#!/bin/sh\n", "");
319
+ }
320
+ /**
321
+ * Installed kibi-managed hooks whose managed section differs from what this
322
+ * CLI installs, such as a pre-commit gate written before `check-generated`
323
+ * joined it. User-authored hooks without kibi markers are not reported.
324
+ */
325
+ // implements REQ-cli-doctor
326
+ export function outdatedManagedHooks(hooksDir) {
327
+ const managed = new RegExp(`${escapeRegex(KIBI_HOOK_BEGIN)}\\n([\\s\\S]*?)\\n${escapeRegex(KIBI_HOOK_END)}`);
328
+ return MANAGED_HOOK_TEMPLATES.filter(([hook, template]) => {
329
+ const hookPath = path.join(hooksDir, hook);
330
+ if (!existsSync(hookPath))
331
+ return false;
332
+ const section = managed.exec(readFileSync(hookPath, "utf8"));
333
+ return section !== null && section[1] !== managedHookBody(template);
334
+ }).map(([hook]) => hook);
335
+ }
336
+ /** Whether any hook in the directory carries a kibi-managed section. */
337
+ // implements REQ-cli-doctor
338
+ export function hasManagedHooks(hooksDir) {
339
+ return MANAGED_HOOK_TEMPLATES.some(([hook]) => {
340
+ const hookPath = path.join(hooksDir, hook);
341
+ return (existsSync(hookPath) &&
342
+ readFileSync(hookPath, "utf8").includes(KIBI_HOOK_BEGIN));
343
+ });
344
+ }
345
+ export function installGitHooks(hooksDir, options = {}) {
346
+ // implements REQ-git-hook-effective-install
266
347
  mkdirSync(hooksDir, { recursive: true });
267
- const postCheckoutPath = path.join(hooksDir, "post-checkout");
268
- const postMergePath = path.join(hooksDir, "post-merge");
269
- const postRewritePath = path.join(hooksDir, "post-rewrite");
270
- const preCommitPath = path.join(hooksDir, "pre-commit");
271
- installHook(postCheckoutPath, POST_CHECKOUT_HOOK.replace("#!/bin/sh\n", ""));
272
- installHook(postMergePath, POST_MERGE_HOOK.replace("#!/bin/sh\n", ""));
273
- installHook(postRewritePath, POST_REWRITE_HOOK.replace("#!/bin/sh\n", ""));
274
- installHook(preCommitPath, PRE_COMMIT_HOOK.replace("#!/bin/sh\n", ""));
275
- console.log("✓ Installed git hooks (pre-commit, post-checkout, post-merge, post-rewrite)");
348
+ const results = MANAGED_HOOK_TEMPLATES.map(([hook, template]) => ({
349
+ hook,
350
+ result: installHook(path.join(hooksDir, hook), managedHookBody(template)),
351
+ }));
352
+ for (const { hook, result } of results) {
353
+ if (result === "skipped-foreign") {
354
+ console.log(`! ${hook}: existing non-Kibi hook left untouched; Kibi enforcement is NOT installed for this hook. To integrate: ${hookIntegrationRecipe(hook)}.`);
355
+ }
356
+ else if (result === "skipped-symlink") {
357
+ console.log(`! ${hook}: hook is a symlink; Kibi never edits symlink targets. Manage the target manually (${hookIntegrationRecipe(hook)}).`);
358
+ }
359
+ else if (result === "skipped-unsupported") {
360
+ console.log(`! ${hook}: hook path is not a regular file; left untouched.`);
361
+ }
362
+ }
363
+ const installedOrUpdated = results.filter((entry) => entry.result === "installed" || entry.result === "updated");
364
+ if (installedOrUpdated.length > 0) {
365
+ console.log(`✓ Installed/updated Kibi git hooks at ${hooksDir} (${installedOrUpdated.map((entry) => entry.hook).join(", ")})`);
366
+ }
367
+ else {
368
+ console.log(`! No Kibi git hooks installed at ${hooksDir} (all hooks were skipped).`);
369
+ }
370
+ if (options.hooksPathOrigin) {
371
+ // Configuration/location reporting stays neutral about what happened:
372
+ // the per-hook lines and the aggregate above carry the install verdict.
373
+ console.log(`! core.hooksPath is configured (${options.hooksPathOrigin}); the effective hooks directory for THIS checkout is ${hooksDir}. Git resolves a relative hooks path separately under every worktree, so coverage of other worktrees is INCOMPLETE/UNVERIFIED: commit a versioned launcher that delegates to kibi, or run 'kibi init' in each checkout. Kibi will not change core.hooksPath.`);
374
+ }
375
+ return results;
276
376
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAqCA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAoDD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA2F/B"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAmGA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAoDD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAwI/B"}
@@ -15,17 +15,74 @@
15
15
  You should have received a copy of the GNU Affero General Public License
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
- import { existsSync } from "node:fs";
18
+ import { existsSync, lstatSync, realpathSync } from "node:fs";
19
19
  import * as path from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { classifyActivation } from "../operations/bootstrap/activation.js";
22
22
  import { nodeFilesystem } from "../public/operations/node-ports.js";
23
23
  import { resolveBranchAttachment } from "../utils/branch-resolver.js";
24
+ import { resolveGitRepository, } from "../utils/git-repository-context.js";
24
25
  import { scaffoldGitHubIntegration } from "./github-init.js";
25
26
  import { copySchemaFiles, createKbDirectoryStructure, createManifestFile, ensureSymbolsManifestFile, installGitHooks, updateGitIgnore, } from "./init-helpers.js";
26
27
  const __filename = fileURLToPath(import.meta.url);
27
28
  const __dirname = path.dirname(__filename);
28
- async function initNextAction() {
29
+ /**
30
+ * A hooks directory may be auto-managed only when Git resolves it inside this
31
+ * repository: under the common Git directory (the default hooks location) or
32
+ * under the current worktree root (repository-local relative core.hooksPath).
33
+ * Anything else — global configs, other repositories, external directories —
34
+ * must never receive auto-installed hooks.
35
+ * implements REQ-git-hook-effective-install
36
+ */
37
+ function isRepositoryManagedHooksDir(context) {
38
+ const realpathAllowMissingTail = (candidate) => {
39
+ let current = path.resolve(candidate);
40
+ const missingSegments = [];
41
+ while (true) {
42
+ try {
43
+ return path.resolve(realpathSync.native(current), ...missingSegments);
44
+ }
45
+ catch (error) {
46
+ const code = error.code;
47
+ if (code !== "ENOENT" && code !== "ENOTDIR")
48
+ return null;
49
+ // A dangling symlink cannot be canonicalized. Do not treat it as an
50
+ // ordinary missing suffix: mkdir could follow it into an external
51
+ // directory when Git's hooks path is created.
52
+ try {
53
+ if (lstatSync(current).isSymbolicLink())
54
+ return null;
55
+ }
56
+ catch (statError) {
57
+ const statCode = statError.code;
58
+ if (statCode !== "ENOENT" && statCode !== "ENOTDIR")
59
+ return null;
60
+ }
61
+ const parent = path.dirname(current);
62
+ if (parent === current)
63
+ return null;
64
+ missingSegments.unshift(path.basename(current));
65
+ current = parent;
66
+ }
67
+ }
68
+ };
69
+ const isWithin = (candidate, root) => {
70
+ const relative = path.relative(root, candidate);
71
+ return (relative === "" ||
72
+ (relative !== ".." &&
73
+ !relative.startsWith(`..${path.sep}`) &&
74
+ !path.isAbsolute(relative)));
75
+ };
76
+ const hooksDir = realpathAllowMissingTail(context.effectiveHooksDir);
77
+ const commonGitDir = realpathAllowMissingTail(context.commonGitDir);
78
+ const worktreeRoot = realpathAllowMissingTail(context.worktreeRoot);
79
+ if (!hooksDir || !commonGitDir || !worktreeRoot)
80
+ return false;
81
+ // The default hooks dir in a linked worktree is shared under the common Git
82
+ // directory, which can sit outside the current worktree root.
83
+ return isWithin(hooksDir, commonGitDir) || isWithin(hooksDir, worktreeRoot);
84
+ }
85
+ async function initNextAction(projectRoot) {
29
86
  const sourceFiles = await nodeFilesystem.glob([
30
87
  ".kb/requirements/**/*.md",
31
88
  ".kb/scenarios/**/*.md",
@@ -35,9 +92,9 @@ async function initNextAction() {
35
92
  ".kb/flags/**/*.md",
36
93
  ".kb/events/**/*.md",
37
94
  ".kb/facts/**/*.md",
38
- ], { cwd: process.cwd() });
95
+ ], { cwd: projectRoot });
39
96
  const activation = await classifyActivation({
40
- workspaceRoot: process.cwd(),
97
+ workspaceRoot: projectRoot,
41
98
  signal: new AbortController().signal,
42
99
  clock: () => new Date(),
43
100
  fs: nodeFilesystem,
@@ -67,12 +124,35 @@ export async function initCommand(options) {
67
124
  console.error("Error: --badge-only requires --github. The recommended integration is `kibi init --github` (badge + full report).");
68
125
  return { exitCode: 1 };
69
126
  }
70
- const kbDir = path.join(process.cwd(), ".kb");
127
+ // Resolve the repository once and derive every project path from Git's own
128
+ // answer, so init works from linked worktrees (.git is a file there) and
129
+ // from subdirectories (cwd has no .kb or .git at all). Bare repositories,
130
+ // unreadable contexts, and operational Git refusals are rejected before any
131
+ // workspace write — even when KIBI_BRANCH makes a standalone fallback
132
+ // available for genuinely non-repository directories.
133
+ // implements REQ-git-hook-effective-install
134
+ const resolution = resolveGitRepository(process.cwd());
135
+ if (resolution.status === "git-refused") {
136
+ console.error(`Error: ${resolution.reason}`);
137
+ console.error("Kibi cannot verify this directory's Git context; refusing to create workspace state.");
138
+ return { exitCode: 1 };
139
+ }
140
+ if (resolution.status === "unsupported") {
141
+ console.error(`Error: ${resolution.reason}`);
142
+ console.error("Kibi requires a working-tree checkout; refusing to create workspace state.");
143
+ return { exitCode: 1 };
144
+ }
145
+ const repoContext = resolution.status === "ok" ? resolution.context : null;
146
+ const projectRoot = repoContext?.worktreeRoot ?? process.cwd();
147
+ const kbDir = path.join(projectRoot, ".kb");
71
148
  const kbExists = existsSync(kbDir);
72
- // Resolve the exact active Git branch. Standalone use must be explicit via
73
- // KIBI_BRANCH; there is no implicit default branch.
149
+ // Resolve the exact active Git branch against the project root (not cwd):
150
+ // recovery journals, legacy stores, and identity manifests are read from
151
+ // the same .kb tree init is about to write.
152
+ // Standalone use must be explicit via KIBI_BRANCH; there is no implicit
153
+ // default branch.
74
154
  let currentBranch;
75
- const result = resolveBranchAttachment();
155
+ const result = resolveBranchAttachment(projectRoot);
76
156
  if ("error" in result) {
77
157
  const isNonGitError = result.code === "NOT_A_GIT_REPO" || result.code === "GIT_NOT_AVAILABLE";
78
158
  console.error("Error: Failed to resolve the active git branch.");
@@ -90,7 +170,7 @@ export async function initCommand(options) {
90
170
  if (!kbExists) {
91
171
  createKbDirectoryStructure(kbDir, currentBranch);
92
172
  createManifestFile(kbDir);
93
- updateGitIgnore(process.cwd());
173
+ updateGitIgnore(projectRoot);
94
174
  const schemaSourceDir = path.resolve(__dirname, "..", "..", "schema");
95
175
  await copySchemaFiles(kbDir, schemaSourceDir);
96
176
  }
@@ -104,14 +184,29 @@ export async function initCommand(options) {
104
184
  createManifestFile(kbDir);
105
185
  }
106
186
  }
107
- ensureSymbolsManifestFile(process.cwd());
187
+ ensureSymbolsManifestFile(projectRoot);
108
188
  if (options.hooks) {
109
- const gitDir = path.join(process.cwd(), ".git");
110
- if (!existsSync(gitDir)) {
189
+ if (!repoContext) {
111
190
  console.error("Warning: No git repository found, skipping hooks");
112
191
  }
192
+ else if (!isRepositoryManagedHooksDir(repoContext)) {
193
+ // core.hooksPath is only the culprit when it is configured; the
194
+ // default hooks directory can also escape the repository through a
195
+ // symlink, and blaming a setting the operator never made misleads.
196
+ const cause = repoContext.hooksPathConfig
197
+ ? "core.hooksPath points outside this repository"
198
+ : "The Git hooks directory resolves outside this repository (for example through a symlink)";
199
+ console.error(`Warning: ${cause} (${repoContext.effectiveHooksDir}); refusing to install hooks into unrelated directories. Kibi enforcement stays OFF for this repository until the hooks path is repository-managed.`);
200
+ }
113
201
  else {
114
- installGitHooks(gitDir);
202
+ installGitHooks(repoContext.effectiveHooksDir, {
203
+ hooksPathOrigin: repoContext.hooksPathOrigin,
204
+ });
205
+ if (repoContext.isLinkedWorktree && !repoContext.hooksPathConfig) {
206
+ // Only the default common hooks directory is shared by Git across
207
+ // worktrees; a configured hooksPath resolves per checkout.
208
+ console.log(`✓ Repository-common hooks directory shared with all worktrees (${repoContext.effectiveHooksDir})`);
209
+ }
115
210
  }
116
211
  }
117
212
  console.log("\n✓ Kibi initialized. Kibi infrastructure is ready for this repository.");
@@ -119,11 +214,11 @@ export async function initCommand(options) {
119
214
  if (kbExists) {
120
215
  console.log(" Existing Kibi source knowledge was preserved.");
121
216
  }
122
- console.log((await initNextAction()).message);
217
+ console.log((await initNextAction(projectRoot)).message);
123
218
  console.log(" Optional diagnostic: run 'kibi doctor' if setup appears degraded.");
124
219
  if (options.github === true) {
125
220
  scaffoldGitHubIntegration({
126
- cwd: process.cwd(),
221
+ cwd: projectRoot,
127
222
  badgeOnly: options.badgeOnly === true,
128
223
  });
129
224
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prove.d.ts","sourceRoot":"","sources":["../../src/commands/prove.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AASjE,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAYnF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAGH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACzC,CAAC,CAAC;AAEH,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C;;;;;GAKG;AAEH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,GAC1D,MAAM,CAiBR;AAED;;;;GAIG;AAEH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,CAAC,CAUb;AAQD,wBAAgB,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEjD;AAkCD,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,gBAAgB,EAC7B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,UAAU,CAWnB;AA4KD,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgL/B"}
1
+ {"version":3,"file":"prove.d.ts","sourceRoot":"","sources":["../../src/commands/prove.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AASjE,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAYnF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAGH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACzC,CAAC,CAAC;AAEH,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE5C;;;;;GAKG;AAEH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,GAC1D,MAAM,CAiBR;AAED;;;;GAIG;AAEH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,CAAC,CAUb;AAQD,wBAAgB,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEjD;AAkCD,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,gBAAgB,EAC7B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,UAAU,CAWnB;AAsKD,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgL/B"}
@@ -151,33 +151,25 @@ function markAggregateFailure(results) {
151
151
  return results.map((result) => ({ ...result, outcome: "failed" }));
152
152
  }
153
153
  async function selectTests(context, options) {
154
- // Paginated: loading every test entity with full props in one query can
155
- // exceed the Prolog output buffer once receipt histories grow.
156
- const loadAll = async () => {
157
- const pageSize = 25;
158
- const all = [];
159
- for (let offset = 0;; offset += pageSize) {
160
- const page = await loadEntities(context.prolog, {
161
- type: "test",
162
- limit: pageSize,
163
- offset,
164
- });
165
- all.push(...page);
166
- if (page.length < pageSize)
167
- return all;
168
- }
169
- };
154
+ // Contract plus bindings only. Receipt histories are loaded again at ingest
155
+ // and blow the Prolog output buffer when selected up front. JUnit and TAP
156
+ // conversion needs the bindings before that reload.
157
+ const loadAll = async () => loadEntities(context.prolog, {
158
+ type: "test",
159
+ projection: "proof_contract",
160
+ });
170
161
  let candidates = [];
171
162
  if (options.testId) {
172
163
  const found = await loadEntities(context.prolog, {
173
164
  id: options.testId,
174
165
  type: "test",
166
+ projection: "proof_contract",
175
167
  });
176
168
  candidates = found.map(withId);
177
169
  }
178
170
  else if (options.requirement) {
179
171
  const requirementId = options.requirement;
180
- const scenarioResult = await context.prolog?.query(`findall([S,T], (kb_relationship(specified_by, '${requirementId}', S), (kb_relationship(verified_by, S, T) ; kb_relationship(validates, T, S)), kb_entity(T, test, _)), Rows)`);
172
+ const scenarioResult = await context.prolog?.query(`findall([S,T], (kb_relationship(specified_by, '${requirementId}', S), (kb_relationship(verified_by, S, T) ; kb_relationship(validates, T, S))), Rows)`);
181
173
  const rowsRaw = scenarioResult?.success
182
174
  ? scenarioResult.bindings.Rows
183
175
  : undefined;
@@ -189,7 +181,7 @@ async function selectTests(context, options) {
189
181
  ids.add(test.trim());
190
182
  }
191
183
  }
192
- const directResult = await context.prolog?.query(`findall(T, (kb_relationship(validates, T, '${requirementId}'), kb_entity(T, test, _)), Rows)`);
184
+ const directResult = await context.prolog?.query(`findall(T, kb_relationship(validates, T, '${requirementId}'), Rows)`);
193
185
  const directRaw = directResult?.success
194
186
  ? directResult.bindings.Rows
195
187
  : undefined;
@@ -21,6 +21,8 @@ export type SyncCache = {
21
21
  seenAt: Record<string, string>;
22
22
  semanticHashes: Record<string, string>;
23
23
  semanticContracts: Record<string, boolean>;
24
+ /** Compiler contract that produced the cached compilation; see below. */
25
+ compilerFingerprint?: string;
24
26
  };
25
27
  /**
26
28
  * v2: cache identities are workspace-root relative instead of process-cwd
@@ -30,6 +32,20 @@ export type SyncCache = {
30
32
  */
31
33
  export declare const SYNC_CACHE_VERSION = 2;
32
34
  export declare const SYNC_CACHE_TTL_MS: number;
35
+ /**
36
+ * Identity of the entity property contract this CLI compiles against. Sync
37
+ * skips unchanged sources by content hash, so a store compiled by a CLI with a
38
+ * different contract (an older build that drops properties it does not know)
39
+ * would otherwise keep that lossy compilation forever. A cache stamped with a
40
+ * different fingerprint is discarded, which re-imports every source once.
41
+ */
42
+ export declare const SYNC_COMPILER_FINGERPRINT: string;
43
+ /**
44
+ * Stale reason for a branch store whose last compilation used a different
45
+ * compiler contract than the running CLI. Status reports it so a lossy store is
46
+ * visible before the next sync repairs it.
47
+ */
48
+ export declare function compilerFingerprintReason(storePath: string, deps?: Partial<SyncCacheDeps>): Record<string, unknown> | null;
33
49
  export declare function toCacheKey(workspaceRoot: string, filePath: string): string;
34
50
  export declare function hashFile(workspaceRoot: string, filePath: string, deps?: Partial<SyncCacheDeps>): string;
35
51
  /** Deterministically hash a JSON-compatible compiler payload. */
@@ -41,7 +57,10 @@ export declare function hashNormalized(value: unknown): string;
41
57
  * source hash even though the authored YAML bytes stay identical.
42
58
  */
43
59
  export declare function hashManifestWithCoordinates(workspaceRoot: string, manifestPath: string, coordinatesPath: string | null, deps?: Partial<SyncCacheDeps>): string;
44
- export declare function readSyncCache(cachePath: string, deps?: Partial<SyncCacheDeps>): SyncCache;
60
+ export declare function readSyncCache(cachePath: string, deps?: Partial<SyncCacheDeps>, options?: {
61
+ /** Discard a cache produced under a different compiler contract. */
62
+ readonly compilerFingerprint?: string;
63
+ }): SyncCache;
45
64
  export declare function writeSyncCache(cachePath: string, cache: SyncCache, deps?: Partial<SyncCacheDeps>): void;
46
65
  export declare function copySyncCache(livePath: string, stagingPath: string, deps?: Partial<SyncCacheDeps>): void;
47
66
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/cache.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7E,UAAU,aAAa;IACrB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC;AAaD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAE1D,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED,wBAAgB,QAAQ,CAEtB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,MAAM,CAIR;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAerD;AAED;;;;;GAKG;AAEH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,MAAM,CA4FR;AAED,wBAAgB,aAAa,CAE3B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,SAAS,CAuDX;AAED,wBAAgB,cAAc,CAE5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,IAAI,CAaN;AAED,wBAAgB,aAAa,CAE3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,IAAI,CASN"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/cache.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAO7E,UAAU,aAAa;IACrB,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,aAAa,EAAE,OAAO,aAAa,CAAC;CACrC;AAaD,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAE1D;;;;;;GAMG;AAEH,eAAO,MAAM,yBAAyB,QAEtB,CAAC;AAEjB;;;;GAIG;AAEH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAyBhC;AAED,wBAAgB,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED,wBAAgB,QAAQ,CAEtB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,MAAM,CAIR;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAerD;AAED;;;;;GAKG;AAEH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,MAAM,CA4FR;AAED,wBAAgB,aAAa,CAE3B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,EAC7B,OAAO,GAAE;IACP,oEAAoE;IACpE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAClC,GACL,SAAS,CA8DX;AAED,wBAAgB,cAAc,CAE5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,EAChB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,IAAI,CAaN;AAED,wBAAgB,aAAa,CAE3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC5B,IAAI,CASN"}
@@ -19,6 +19,9 @@ import { createHash } from "node:crypto";
19
19
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
20
20
  import * as path from "node:path";
21
21
  import { load as parseYAML } from "js-yaml";
22
+ import entitySchema from "../../schemas/entity.schema.json" with {
23
+ type: "json"
24
+ };
22
25
  function resolveDeps(overrides) {
23
26
  return {
24
27
  createHash,
@@ -37,6 +40,47 @@ function resolveDeps(overrides) {
37
40
  */
38
41
  export const SYNC_CACHE_VERSION = 2;
39
42
  export const SYNC_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
43
+ /**
44
+ * Identity of the entity property contract this CLI compiles against. Sync
45
+ * skips unchanged sources by content hash, so a store compiled by a CLI with a
46
+ * different contract (an older build that drops properties it does not know)
47
+ * would otherwise keep that lossy compilation forever. A cache stamped with a
48
+ * different fingerprint is discarded, which re-imports every source once.
49
+ */
50
+ // implements REQ-cli-canonical-runtime
51
+ export const SYNC_COMPILER_FINGERPRINT = createHash("sha256")
52
+ .update(JSON.stringify(entitySchema))
53
+ .digest("hex");
54
+ /**
55
+ * Stale reason for a branch store whose last compilation used a different
56
+ * compiler contract than the running CLI. Status reports it so a lossy store is
57
+ * visible before the next sync repairs it.
58
+ */
59
+ // implements REQ-cli-canonical-runtime
60
+ export function compilerFingerprintReason(storePath, deps) {
61
+ const resolved = resolveDeps(deps);
62
+ const cachePath = path.join(storePath, "sync-cache.json");
63
+ if (!resolved.existsSync(cachePath))
64
+ return null;
65
+ let recorded;
66
+ try {
67
+ recorded = JSON.parse(resolved.readFileSync(cachePath, "utf8")).compilerFingerprint;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ if (recorded === SYNC_COMPILER_FINGERPRINT)
73
+ return null;
74
+ return {
75
+ code: "compiler_changed",
76
+ path: cachePath,
77
+ entityIds: [],
78
+ detail: typeof recorded === "string"
79
+ ? "The branch KB was compiled by a Kibi CLI with a different entity property contract, so unchanged sources may lack properties this CLI keeps. The next kibi sync re-imports every source."
80
+ : "The branch KB was compiled by a Kibi CLI that did not record its entity property contract, so unchanged sources may lack properties this CLI keeps. The next kibi sync re-imports every source.",
81
+ remediation: { command_argv: ["kibi", "sync"], applyRequired: false },
82
+ };
83
+ }
40
84
  export function toCacheKey(workspaceRoot, filePath) {
41
85
  const root = path.resolve(workspaceRoot);
42
86
  const target = path.isAbsolute(filePath)
@@ -165,7 +209,7 @@ export function hashManifestWithCoordinates(workspaceRoot, manifestPath, coordin
165
209
  }
166
210
  export function readSyncCache(
167
211
  // implements REQ-003
168
- cachePath, deps) {
212
+ cachePath, deps, options = {}) {
169
213
  const resolved = resolveDeps(deps);
170
214
  if (!resolved.existsSync(cachePath)) {
171
215
  return {
@@ -178,7 +222,9 @@ cachePath, deps) {
178
222
  }
179
223
  try {
180
224
  const parsed = JSON.parse(resolved.readFileSync(cachePath, "utf8"));
181
- if (parsed.version !== SYNC_CACHE_VERSION) {
225
+ if (parsed.version !== SYNC_CACHE_VERSION ||
226
+ (options.compilerFingerprint !== undefined &&
227
+ parsed.compilerFingerprint !== options.compilerFingerprint)) {
182
228
  return {
183
229
  version: SYNC_CACHE_VERSION,
184
230
  hashes: {},
@@ -206,6 +252,9 @@ cachePath, deps) {
206
252
  if (parsed.shardRelationships !== undefined) {
207
253
  cache.shardRelationships = parsed.shardRelationships;
208
254
  }
255
+ if (parsed.compilerFingerprint !== undefined) {
256
+ cache.compilerFingerprint = parsed.compilerFingerprint;
257
+ }
209
258
  return cache;
210
259
  }
211
260
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/discovery.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,+EAA+E;IAC/E,6BAA6B,CAAC,EAAE,OAAO,CAAC;CACzC,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAyFH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOlD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAShE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUxD;AAED,wBAAgB,mCAAmC,CACjD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,4BAA4B,EAAE,GAChD,IAAI,CA6CN;AAsBD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,MAAM,GAAG,IAAI,CAIf;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC;IACT,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B,EAAE,4BAA4B,EAAE,CAAC;CAC9D,CAAC,CA+FD"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/discovery.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,+EAA+E;IAC/E,6BAA6B,CAAC,EAAE,OAAO,CAAC;CACzC,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AA2FH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOlD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAShE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUxD;AAED,wBAAgB,mCAAmC,CACjD,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,4BAA4B,EAAE,GAChD,IAAI,CA6CN;AAsBD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,MAAM,GAAG,IAAI,CAIf;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC;IACT,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B,EAAE,4BAA4B,EAAE,CAAC;CAC9D,CAAC,CA+FD"}
@@ -67,7 +67,7 @@ function pendingSourcePaths(cwd, recoverMissing) {
67
67
  });
68
68
  continue;
69
69
  }
70
- throw new Error(`Pending source is missing: ${relative}`);
70
+ throw new Error(`Pending source is missing: ${relative}. If the file was deleted on purpose, run 'kibi branch recover --apply' to rebuild the branch KB from the sources that remain.`);
71
71
  }
72
72
  const actual = createHash("sha256")
73
73
  .update(readFileSync(absolute))
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAiHrD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AA8CD,iFAAiF;AACjF,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,MAAM,CAAC,CAkCjB;AAED,0EAA0E;AAC1E,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,8EAA8E;AAC9E,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,SAAS,qBAAqB,EAAE,GAC9C,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAmCD,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,OAAO,GAAE;IAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GAChD,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAyPvD;AA4BD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,MAAM,CAER;AAGD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,EAC3C,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAmO7D"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/persistence.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA0HrD,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AA8CD,iFAAiF;AACjF,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,MAAM,CAAC,CAkCjB;AAED,0EAA0E;AAC1E,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED,8EAA8E;AAC9E,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,SAAS,qBAAqB,EAAE,GAC9C,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAmCD,wBAAsB,eAAe,CAEnC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,OAAO,GAAE;IAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GAChD,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAyPvD;AA4BD,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,MAAM,CAER;AAGD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,kBAAkB,EAAE,qBAAqB,EAAE,EAC3C,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAmO7D"}
@@ -83,6 +83,14 @@ function serializeTypedFactFields(entity) {
83
83
  if (ruleIr !== undefined && ruleIr !== null) {
84
84
  fields.push(`rule_ir=${toPrologString(JSON.stringify(ruleIr))}`);
85
85
  }
86
+ // Predicate-schema vocabularies are objects; like rule_ir they travel as
87
+ // JSON strings and are decoded again at the public boundary.
88
+ for (const field of ["argument_constants", "argument_aliases"]) {
89
+ const value = getEntityField(entity, field);
90
+ if (value !== undefined && value !== null) {
91
+ fields.push(`${field}=${toPrologString(JSON.stringify(value))}`);
92
+ }
93
+ }
86
94
  // Atom fields (possibly unquoted if simple)
87
95
  for (const field of ATOM_FIELDS) {
88
96
  const value = getEntityField(entity, field);
@@ -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;AAyB7C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAsBxE,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,CAqGV;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;AA6DD,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;CACnB,EACN,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAwnCrB;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;AA0B7C,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AA2BxE,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;AA6DD,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;CACnB,EACN,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA6nCrB;AAED,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}