kibi-cli 2.36.0 → 2.39.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 (224) hide show
  1. package/dist/cli-json-command.d.ts.map +1 -1
  2. package/dist/cli-json-command.js +4 -0
  3. package/dist/cli-operation-metadata.d.ts +1 -1
  4. package/dist/cli-operation-metadata.js +1 -1
  5. package/dist/cli-register-foundation.d.ts.map +1 -1
  6. package/dist/cli-register-foundation.js +2 -1
  7. package/dist/cli-register-maintenance.d.ts.map +1 -1
  8. package/dist/cli-register-maintenance.js +5 -0
  9. package/dist/cli-register-reporting.d.ts.map +1 -1
  10. package/dist/cli-register-reporting.js +1 -0
  11. package/dist/cli-validate.d.ts.map +1 -1
  12. package/dist/cli-validate.js +21 -2
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +19 -1
  15. package/dist/commands/aggregated-checks.d.ts.map +1 -1
  16. package/dist/commands/aggregated-checks.js +89 -16
  17. package/dist/commands/coverage.d.ts +1 -0
  18. package/dist/commands/coverage.d.ts.map +1 -1
  19. package/dist/commands/coverage.js +40 -0
  20. package/dist/commands/doctor.d.ts +5 -0
  21. package/dist/commands/doctor.d.ts.map +1 -1
  22. package/dist/commands/doctor.js +70 -35
  23. package/dist/commands/github-init.d.ts.map +1 -1
  24. package/dist/commands/github-init.js +4 -2
  25. package/dist/commands/hook-managers.d.ts +43 -0
  26. package/dist/commands/hook-managers.d.ts.map +1 -0
  27. package/dist/commands/hook-managers.js +426 -0
  28. package/dist/commands/init.d.ts +1 -0
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +40 -5
  31. package/dist/commands/migrate.d.ts.map +1 -1
  32. package/dist/commands/migrate.js +9 -3
  33. package/dist/commands/sync/persistence.d.ts.map +1 -1
  34. package/dist/commands/sync/persistence.js +49 -1
  35. package/dist/commands/telemetry.d.ts +7 -0
  36. package/dist/commands/telemetry.d.ts.map +1 -0
  37. package/dist/commands/telemetry.js +23 -0
  38. package/dist/decision-firmness.d.ts.map +1 -1
  39. package/dist/decision-firmness.js +11 -14
  40. package/dist/engine-limits.d.ts.map +1 -1
  41. package/dist/engine-limits.js +8 -10
  42. package/dist/entity-body-context.d.ts.map +1 -1
  43. package/dist/entity-body-context.js +39 -36
  44. package/dist/extractors/markdown.d.ts +6 -0
  45. package/dist/extractors/markdown.d.ts.map +1 -1
  46. package/dist/extractors/markdown.js +21 -0
  47. package/dist/extractors/symbol-coordinates.d.ts.map +1 -1
  48. package/dist/extractors/symbol-coordinates.js +23 -4
  49. package/dist/firm-decision-edit.d.ts.map +1 -1
  50. package/dist/firm-decision-edit.js +1 -3
  51. package/dist/intent-search.d.ts +5 -1
  52. package/dist/intent-search.d.ts.map +1 -1
  53. package/dist/intent-search.js +118 -33
  54. package/dist/logic/ir.d.ts.map +1 -1
  55. package/dist/logic/ir.js +82 -108
  56. package/dist/operations/bootstrap/discovery-evidence.d.ts.map +1 -1
  57. package/dist/operations/bootstrap/discovery-evidence.js +44 -2
  58. package/dist/operations/bootstrap/discovery.d.ts.map +1 -1
  59. package/dist/operations/bootstrap/discovery.js +1 -0
  60. package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
  61. package/dist/operations/bootstrap/guidance-actions.js +2 -1
  62. package/dist/operations/bootstrap/plugin-offers.d.ts +11 -2
  63. package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
  64. package/dist/operations/bootstrap/plugin-offers.js +48 -9
  65. package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
  66. package/dist/operations/proof/claim-bindings.js +1 -0
  67. package/dist/operations/proof/code-certificates.d.ts +2 -0
  68. package/dist/operations/proof/code-certificates.d.ts.map +1 -1
  69. package/dist/operations/proof/code-certificates.js +34 -14
  70. package/dist/operations/proof/code-models.d.ts.map +1 -1
  71. package/dist/operations/proof/code-models.js +19 -5
  72. package/dist/operations/proof/code-runner.d.ts +16 -0
  73. package/dist/operations/proof/code-runner.d.ts.map +1 -1
  74. package/dist/operations/proof/code-runner.js +42 -6
  75. package/dist/operations/proof/explain.d.ts +63 -0
  76. package/dist/operations/proof/explain.d.ts.map +1 -1
  77. package/dist/operations/proof/explain.js +162 -0
  78. package/dist/operations/semantic-advisor/analyze-prose.d.ts +9 -1
  79. package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
  80. package/dist/operations/semantic-advisor/analyze-prose.js +21 -0
  81. package/dist/operations/semantic-advisor/case-preview.d.ts +24 -0
  82. package/dist/operations/semantic-advisor/case-preview.d.ts.map +1 -0
  83. package/dist/operations/semantic-advisor/case-preview.js +216 -0
  84. package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
  85. package/dist/operations/semantic-advisor/shared.js +3 -0
  86. package/dist/operations/semantic-advisor/types.d.ts +23 -0
  87. package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
  88. package/dist/plugins/approved-source-analyzers.generated.d.ts +11 -8
  89. package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
  90. package/dist/plugins/approved-source-analyzers.generated.js +11 -8
  91. package/dist/plugins/compose-search-hints.d.ts +29 -0
  92. package/dist/plugins/compose-search-hints.d.ts.map +1 -0
  93. package/dist/plugins/compose-search-hints.js +94 -0
  94. package/dist/plugins/external-allowlist.d.ts +7 -0
  95. package/dist/plugins/external-allowlist.d.ts.map +1 -1
  96. package/dist/plugins/external-allowlist.js +11 -0
  97. package/dist/plugins/registry.d.ts +8 -1
  98. package/dist/plugins/registry.d.ts.map +1 -1
  99. package/dist/plugins/registry.js +22 -3
  100. package/dist/plugins/source-classification.d.ts +2 -2
  101. package/dist/plugins/source-classification.d.ts.map +1 -1
  102. package/dist/plugins/source-classification.js +25 -1
  103. package/dist/prolog/codec.d.ts.map +1 -1
  104. package/dist/prolog/codec.js +10 -20
  105. package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
  106. package/dist/public/impact/coverage-depth-quality.js +32 -16
  107. package/dist/public/impact/full-kb-quality.d.ts +6 -0
  108. package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
  109. package/dist/public/impact/full-kb-quality.js +8 -3
  110. package/dist/public/impact/requirement-quality.d.ts.map +1 -1
  111. package/dist/public/impact/requirement-quality.js +56 -29
  112. package/dist/public/operations/catalog.d.ts +44 -4
  113. package/dist/public/operations/catalog.d.ts.map +1 -1
  114. package/dist/public/operations/check-executor.d.ts +6 -0
  115. package/dist/public/operations/check-executor.d.ts.map +1 -1
  116. package/dist/public/operations/check-executor.js +34 -2
  117. package/dist/public/operations/discovery-executors.d.ts +5 -1
  118. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  119. package/dist/public/operations/discovery-executors.js +65 -4
  120. package/dist/public/operations/evidence-floor.d.ts +8 -1
  121. package/dist/public/operations/evidence-floor.d.ts.map +1 -1
  122. package/dist/public/operations/evidence-floor.js +3 -4
  123. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  124. package/dist/public/operations/migration-plan.js +41 -10
  125. package/dist/public/operations/node-ports.d.ts.map +1 -1
  126. package/dist/public/operations/node-ports.js +3 -1
  127. package/dist/public/operations/repair-plan.d.ts +46 -0
  128. package/dist/public/operations/repair-plan.d.ts.map +1 -1
  129. package/dist/public/operations/repair-plan.js +110 -1
  130. package/dist/public/operations/schema6-check-actions.js +1 -1
  131. package/dist/public/operations/source-analysis-cache.d.ts +22 -0
  132. package/dist/public/operations/source-analysis-cache.d.ts.map +1 -0
  133. package/dist/public/operations/source-analysis-cache.js +157 -0
  134. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  135. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  136. package/dist/public/operations/specs/check-rules.generated.js +2 -1
  137. package/dist/public/operations/specs/check.d.ts +1 -1
  138. package/dist/public/operations/specs/discovery.d.ts +7 -2
  139. package/dist/public/operations/specs/discovery.d.ts.map +1 -1
  140. package/dist/public/operations/specs/discovery.js +7 -2
  141. package/dist/public/operations/specs/mutation-schemas.d.ts +36 -1
  142. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  143. package/dist/public/operations/specs/mutation-schemas.js +30 -0
  144. package/dist/public/operations/specs/upsert.d.ts +36 -1
  145. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  146. package/dist/public/operations/symbol-granularity-check.d.ts +3 -1
  147. package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -1
  148. package/dist/public/operations/symbol-granularity-check.js +21 -7
  149. package/dist/public/proof-protocol.d.ts +6 -1
  150. package/dist/public/proof-protocol.d.ts.map +1 -1
  151. package/dist/public/proof-protocol.js +12 -3
  152. package/dist/public/proof-sources.d.ts +2 -0
  153. package/dist/public/proof-sources.d.ts.map +1 -1
  154. package/dist/public/proof-sources.js +32 -6
  155. package/dist/public/schemas/entity.d.ts.map +1 -1
  156. package/dist/public/schemas/entity.js +59 -0
  157. package/dist/public/skills/kibi-bootstrap/SKILL.md +2 -2
  158. package/dist/public/skills/kibi-commit-review/SKILL.md +6 -2
  159. package/dist/public/skills/kibi-decisions/SKILL.md +7 -2
  160. package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
  161. package/dist/public/skills/kibi-usage/SKILL.md +50 -3
  162. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
  163. package/dist/public/skills/kibi-usage/resources/proof.md +13 -5
  164. package/dist/public/skills/kibi-usage/resources/workflows.md +10 -0
  165. package/dist/relationships/shards.d.ts +2 -0
  166. package/dist/relationships/shards.d.ts.map +1 -1
  167. package/dist/relationships/shards.js +25 -1
  168. package/dist/schemas/entity.schema.json +98 -1
  169. package/dist/search-answer.d.ts +3 -2
  170. package/dist/search-answer.d.ts.map +1 -1
  171. package/dist/search-answer.js +57 -4
  172. package/dist/search-hints.d.ts +58 -0
  173. package/dist/search-hints.d.ts.map +1 -0
  174. package/dist/search-hints.js +187 -0
  175. package/dist/search-ranking.d.ts +7 -0
  176. package/dist/search-ranking.d.ts.map +1 -1
  177. package/dist/search-ranking.js +54 -56
  178. package/dist/search-token-cache.d.ts +30 -0
  179. package/dist/search-token-cache.d.ts.map +1 -0
  180. package/dist/search-token-cache.js +86 -0
  181. package/dist/traceability/impact-knowledge.d.ts.map +1 -1
  182. package/dist/traceability/impact-knowledge.js +2 -0
  183. package/dist/traceability/temp-kb.d.ts.map +1 -1
  184. package/dist/traceability/temp-kb.js +11 -1
  185. package/dist/types/entities.d.ts +12 -0
  186. package/dist/types/entities.d.ts.map +1 -1
  187. package/dist/usage-telemetry.d.ts +20 -0
  188. package/dist/usage-telemetry.d.ts.map +1 -0
  189. package/dist/usage-telemetry.js +93 -0
  190. package/dist/utils/branch-resolver.d.ts.map +1 -1
  191. package/dist/utils/branch-resolver.js +1 -0
  192. package/dist/utils/rule-registry.generated.d.ts +5 -0
  193. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  194. package/dist/utils/rule-registry.generated.js +6 -0
  195. package/package.json +5 -4
  196. package/schema/entities.pl +12 -0
  197. package/src/public/impact/coverage-depth-quality.ts +59 -21
  198. package/src/public/impact/full-kb-quality.ts +15 -1
  199. package/src/public/impact/requirement-quality.ts +95 -38
  200. package/src/public/operations/check-executor.ts +41 -1
  201. package/src/public/operations/discovery-executors.ts +92 -4
  202. package/src/public/operations/evidence-floor.ts +15 -3
  203. package/src/public/operations/migration-plan.ts +41 -9
  204. package/src/public/operations/node-ports.ts +3 -1
  205. package/src/public/operations/repair-plan.ts +152 -1
  206. package/src/public/operations/schema6-check-actions.ts +1 -1
  207. package/src/public/operations/source-analysis-cache.ts +196 -0
  208. package/src/public/operations/specs/check-rules.generated.ts +2 -1
  209. package/src/public/operations/specs/discovery.ts +8 -2
  210. package/src/public/operations/specs/mutation-schemas.ts +34 -0
  211. package/src/public/operations/symbol-granularity-check.ts +25 -5
  212. package/src/public/proof-protocol-types.d.ts +1 -1
  213. package/src/public/proof-protocol.ts +18 -4
  214. package/src/public/proof-sources.ts +37 -6
  215. package/src/public/schemas/entity.ts +65 -0
  216. package/src/public/skills/kibi-bootstrap/SKILL.md +2 -2
  217. package/src/public/skills/kibi-commit-review/SKILL.md +6 -2
  218. package/src/public/skills/kibi-decisions/SKILL.md +7 -2
  219. package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -1
  220. package/src/public/skills/kibi-usage/SKILL.md +50 -3
  221. package/src/public/skills/kibi-usage/resources/fact-lanes.md +34 -0
  222. package/src/public/skills/kibi-usage/resources/proof.md +13 -5
  223. package/src/public/skills/kibi-usage/resources/workflows.md +10 -0
  224. package/src/schemas/entity.schema.json +98 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cli-json-command.d.ts","sourceRoot":"","sources":["../src/cli-json-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAazC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAIpE;AAGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAW7E;AAGD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS;QAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KACpC,EAAE,CAAC;CACL,CAAC;AAkDF,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC,CA+Gf"}
1
+ {"version":3,"file":"cli-json-command.d.ts","sourceRoot":"","sources":["../src/cli-json-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAazC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAIpE;AAGD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAW7E;AAGD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS;QAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KACpC,EAAE,CAAC;CACL,CAAC;AAmDF,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,cAAc,GACzB,OAAO,CAAC,IAAI,CAAC,CAgHf"}
@@ -6,6 +6,7 @@ import { executeOperation as executeProtocolOperation, openFailureResult, } from
6
6
  import { prepareOperationInput } from "./cli-validate.js";
7
7
  import { appendCliDiagnosticUsage, diagnosticEnvOptIn, } from "./public/diagnostic-usage.js";
8
8
  import { createCliRuntime } from "./runtime/cli-runtime.js";
9
+ import { noteCliErrorCategory, noteCliResultError } from "./usage-telemetry.js";
9
10
  export function writeOptionalStderr(stderr) {
10
11
  if (stderr !== undefined) {
11
12
  process.stderr.write(stderr);
@@ -31,6 +32,7 @@ export async function withConsoleOnStderr(fn) {
31
32
  }
32
33
  }
33
34
  function writeInputError(error) {
35
+ noteCliErrorCategory(error.code);
34
36
  process.stderr.write(`Error [${error.code}]: ${error.detail}\n`);
35
37
  process.exitCode = error.exitCode;
36
38
  }
@@ -173,5 +175,7 @@ export async function runJsonInvocation(invocation) {
173
175
  await writeAndWaitForDrain(process.stdout, result.stdout);
174
176
  }
175
177
  writeOptionalStderr(result.stderr);
178
+ if (result.exitCode !== 0)
179
+ noteCliResultError(result.stdout);
176
180
  process.exitCode = result.exitCode;
177
181
  }
@@ -27,7 +27,7 @@ export declare const CLI_OPERATION_METADATA: readonly [{
27
27
  }, {
28
28
  readonly name: "kb_search";
29
29
  readonly cliName: "search";
30
- readonly description: "Ask the KB a question or search it. Default intent-v1 ranking accepts questions, host-agent semantic facets and changed-code source locations, returns evidence, abstains below its confidence threshold and adds an answer layer: the current requirements that govern the topic, what must stay true (linked facts), why (ADRs) and what verifies it (scenarios, tests). Use before changing behavior, then kb_query for exact follow-up. No mutation side effects.";
30
+ readonly description: "Ask the KB a question or search it. Default intent-v1 ranking accepts questions, host-agent semantic facets and changed-code source locations, returns evidence, abstains below its confidence threshold and adds an answer layer: the current requirements that govern the topic, what must stay true (linked facts), why (ADRs) and what verifies it (scenarios, tests). A weak answer may add queryAnalysis.hints from a search-hints plugin: requirements the question may mean, to re-ask with. Use before changing behavior, then kb_query for exact follow-up. No mutation side effects.";
31
31
  }, {
32
32
  readonly name: "kb_status";
33
33
  readonly cliName: "status";
@@ -30,7 +30,7 @@ export const CLI_OPERATION_METADATA = [
30
30
  {
31
31
  name: "kb_search",
32
32
  cliName: "search",
33
- description: "Ask the KB a question or search it. Default intent-v1 ranking accepts questions, host-agent semantic facets and changed-code source locations, returns evidence, abstains below its confidence threshold and adds an answer layer: the current requirements that govern the topic, what must stay true (linked facts), why (ADRs) and what verifies it (scenarios, tests). Use before changing behavior, then kb_query for exact follow-up. No mutation side effects.",
33
+ description: "Ask the KB a question or search it. Default intent-v1 ranking accepts questions, host-agent semantic facets and changed-code source locations, returns evidence, abstains below its confidence threshold and adds an answer layer: the current requirements that govern the topic, what must stay true (linked facts), why (ADRs) and what verifies it (scenarios, tests). A weak answer may add queryAnalysis.hints from a search-hints plugin: requirements the question may mean, to re-ask with. Use before changing behavior, then kb_query for exact follow-up. No mutation side effects.",
34
34
  },
35
35
  {
36
36
  name: "kb_status",
@@ -1 +1 @@
1
- {"version":3,"file":"cli-register-foundation.d.ts","sourceRoot":"","sources":["../src/cli-register-foundation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6JjE"}
1
+ {"version":3,"file":"cli-register-foundation.d.ts","sourceRoot":"","sources":["../src/cli-register-foundation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAezC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiKjE"}
@@ -12,7 +12,8 @@ export function registerFoundationCommands(program) {
12
12
  .option("--no-hooks", "Do not install git hooks (hooks installed by default)")
13
13
  .option("--github", "Scaffold the GitHub Pages badge + requirement-health report workflow")
14
14
  .option("--badge-only", "With --github, publish only the badge (opt out of the full report)")
15
- .option("--print-hook <hook>", "Print a snippet that delegates an existing hook (pre-commit, post-checkout, post-merge, post-rewrite) to kibi, and write nothing")
15
+ .option("--print-hook <hook>", "Print a snippet that delegates an existing hook (pre-commit, post-checkout, post-merge, post-rewrite, or all) to kibi, and write nothing")
16
+ .option("--format <format>", "With --print-hook: shell (default), lefthook, husky or pre-commit")
16
17
  .action(withExitCode(async (options) => (await import("./commands/init.js")).initCommand(options)));
17
18
  program
18
19
  .command("migrate")
@@ -1 +1 @@
1
- {"version":3,"file":"cli-register-maintenance.d.ts","sourceRoot":"","sources":["../src/cli-register-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6KlE"}
1
+ {"version":3,"file":"cli-register-maintenance.d.ts","sourceRoot":"","sources":["../src/cli-register-maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgMlE"}
@@ -68,6 +68,11 @@ export function registerMaintenanceCommands(program) {
68
68
  .option("--format <format>", "Output format: json|table", "table")
69
69
  .option("--limit <n>", "Limit rendered table rows", "50")
70
70
  .action(withExitCode(async (options) => (await import("./commands/usage-remediation.js")).usageRemediationCommand(options)));
71
+ program
72
+ .command("telemetry [action]")
73
+ .description("Show, enable or disable anonymous usage telemetry (status|enable|disable)")
74
+ .option("--format <format>", "Output format: json|text", "text")
75
+ .action(withExitCode(async (action, options) => (await import("./commands/telemetry.js")).telemetryCommand(action, options)));
71
76
  program
72
77
  .command("merge-driver")
73
78
  .description("Git merge driver: three-way merge .kb/symbols.yaml or a relationship shard by record id")
@@ -1 +1 @@
1
- {"version":3,"file":"cli-register-reporting.d.ts","sourceRoot":"","sources":["../src/cli-register-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuRhE"}
1
+ {"version":3,"file":"cli-register-reporting.d.ts","sourceRoot":"","sources":["../src/cli-register-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4RhE"}
@@ -75,6 +75,7 @@ export function registerReportingCommands(program) {
75
75
  .option("--migration-offset <n>", "Skip ready semantic-inventory migration batches", "0")
76
76
  .option("--migration-predicate-limit <n>", "Maximum ranked predicate schemas per proposition", "5")
77
77
  .option("--migration-predicate-min-score <score>", "Minimum predicate schema rank score", "0.35")
78
+ .option("--cases", "Print the edge cases derived from each requirement's typed claims, with their predicted outcome and covering scenarios", false)
78
79
  .option("--format <format>", "Output format: json|table", "table")
79
80
  .action(async (options, command) => {
80
81
  if (options.input !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"cli-validate.d.ts","sourceRoot":"","sources":["../src/cli-validate.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAGpE,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAGlE,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CAC1C,GACD;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAiBlE,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,mBAAmB,CAgCrB;AAGD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,gBAAgB,CAKlB"}
1
+ {"version":3,"file":"cli-validate.d.ts","sourceRoot":"","sources":["../src/cli-validate.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAGpE,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAGlE,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CAC1C,GACD;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAsClE,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,mBAAmB,CA6BrB;AAGD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,GACb,gBAAgB,CAKlB"}
@@ -2,6 +2,26 @@ import Ajv from "ajv";
2
2
  function isObject(value) {
3
3
  return value !== null && typeof value === "object" && !Array.isArray(value);
4
4
  }
5
+ // One validator per operation schema. Building an Ajv instance compiles the
6
+ // JSON Schema meta-schema, and a CLI call validates its input more than once.
7
+ const inputValidator = new Ajv({ allErrors: true, strict: false });
8
+ const compiledInputSchemas = new WeakMap();
9
+ function compileInputSchema(schema) {
10
+ let validator = compiledInputSchemas.get(schema);
11
+ if (validator === undefined) {
12
+ const exact = { ...schema, additionalProperties: false };
13
+ try {
14
+ validator = inputValidator.compile(exact);
15
+ }
16
+ catch {
17
+ // A schema whose $id the shared instance already holds for another
18
+ // schema object compiles on an instance of its own.
19
+ validator = new Ajv({ allErrors: true, strict: false }).compile(exact);
20
+ }
21
+ compiledInputSchemas.set(schema, validator);
22
+ }
23
+ return validator;
24
+ }
5
25
  function formatValidationErrors(errors) {
6
26
  return errors.map((error) => {
7
27
  const location = error.instancePath.length > 0 ? error.instancePath : "/";
@@ -22,8 +42,7 @@ export function prepareOperationInput(input, schema) {
22
42
  };
23
43
  }
24
44
  const businessInput = Object.fromEntries(Object.entries(input).filter(([key]) => key !== "_diagnostic_telemetry"));
25
- const schemaWithExactTopLevel = { ...schema, additionalProperties: false };
26
- const validator = new Ajv({ allErrors: true, strict: false }).compile(schemaWithExactTopLevel);
45
+ const validator = compileInputSchema(schema);
27
46
  if (!validator(businessInput)) {
28
47
  return {
29
48
  valid: false,
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUrD;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM7D;AAGD,wBAAgB,YAAY,IAAI,OAAO,CAiBtC;AAGD,wBAAsB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAqB3C;AAED,wBAAsB,kBAAkB,CACtC,YAAY,UAAoD,EAChE,KAAK,cAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAGf"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUrD;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM7D;AAGD,wBAAgB,YAAY,IAAI,OAAO,CAiBtC;AAGD,wBAAsB,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAqC3C;AAED,wBAAsB,kBAAkB,CACtC,YAAY,UAAoD,EAChE,KAAK,cAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAGf"}
package/dist/cli.js CHANGED
@@ -28,6 +28,7 @@ import { registerProofCommand } from "./cli-register-proof.js";
28
28
  import { registerReportingCommands } from "./cli-register-reporting.js";
29
29
  import { registerSkillsCommands } from "./cli-register-skills.js";
30
30
  import { bootstrapKibiEnvironment } from "./env/bootstrap.js";
31
+ import { finishCliTelemetry, trackCommandPath } from "./usage-telemetry.js";
31
32
  import { resolveWorkspaceCwd } from "./workspace-cwd.js";
32
33
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
33
34
  export function packageVersion(value) {
@@ -70,14 +71,31 @@ export async function main() {
70
71
  if (workspace.cwd !== process.cwd())
71
72
  process.chdir(workspace.cwd);
72
73
  bootstrapKibiEnvironment();
74
+ const startedAt = new Date();
75
+ const program = buildProgram();
76
+ const commandPath = trackCommandPath(program);
73
77
  let exitCode = process.exitCode ?? 0;
78
+ let failure;
74
79
  try {
75
- await buildProgram().parseAsync(workspace.argv);
80
+ await program.parseAsync(workspace.argv);
76
81
  exitCode = process.exitCode ?? 0;
77
82
  }
78
83
  catch (error) {
84
+ failure = error;
79
85
  exitCode = exitCodeFromCliFailure(error);
80
86
  }
87
+ try {
88
+ await finishCliTelemetry({
89
+ commandPath: commandPath(),
90
+ packageVersion: packageVersion(packageJson),
91
+ startedAt,
92
+ exitCode: Number(exitCode),
93
+ error: failure,
94
+ });
95
+ }
96
+ catch {
97
+ // Telemetry is best effort and never changes the exit code.
98
+ }
81
99
  await Promise.all([process.stdout, process.stderr].map((stream) => stream.writableNeedDrain ? once(stream, "drain") : Promise.resolve()));
82
100
  process.exit(exitCode);
83
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"aggregated-checks.d.ts","sourceRoot":"","sources":["../../src/commands/aggregated-checks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,cAAc,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiB5C;;;;;GAKG;AAEH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAYR;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,EACpC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACjC,OAAO,CAAC,SAAS,EAAE,CAAC,CA8DtB"}
1
+ {"version":3,"file":"aggregated-checks.d.ts","sourceRoot":"","sources":["../../src/commands/aggregated-checks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,cAAc,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiB5C;;;;;GAKG;AAEH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAYR;AAsED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,EACpC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACjC,OAAO,CAAC,SAAS,EAAE,CAAC,CAyEtB"}
@@ -1,3 +1,5 @@
1
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
1
3
  import path from "node:path";
2
4
  import { resolveKbPlPath } from "../prolog.js";
3
5
  import { escapeAtom, toPrologAtom } from "../prolog/codec.js";
@@ -25,6 +27,68 @@ export function ontologyQualityOverridesGoal(env = process.env) {
25
27
  ; true
26
28
  )`;
27
29
  }
30
+ /**
31
+ * A private file the engine writes the violations JSON to. A large KB's
32
+ * report can exceed the engine's bounded output capacity, so the answer
33
+ * carries only a transport marker and the JSON travels through this file.
34
+ * A temp folder that cannot be written gives no file, and the engine answers
35
+ * the JSON instead.
36
+ */
37
+ // implements REQ-003
38
+ function checkResultFile() {
39
+ let dir;
40
+ try {
41
+ dir = mkdtempSync(path.join(tmpdir(), "kibi-check-"));
42
+ }
43
+ catch {
44
+ return { path: undefined, dispose: () => { } };
45
+ }
46
+ return {
47
+ path: path.join(dir, "violations.json"),
48
+ // rationale: the directory always exists when disposed, so `force` (which
49
+ // only ignores a missing path) never changes the outcome.
50
+ // Stryker disable next-line BooleanLiteral
51
+ dispose: () => rmSync(dir, { recursive: true, force: true }),
52
+ };
53
+ }
54
+ /**
55
+ * The aggregated checks goal. With a result file it prefers the transport
56
+ * predicate, which falls back to an answer when the engine cannot write the
57
+ * file, then the older file predicates; without one (or with an engine whose
58
+ * core predates both) it asks for the JSON as an answer.
59
+ */
60
+ function aggregatedChecksQuery(checksPlPath, rulesAllowlist, resultPath) {
61
+ const target = resultPath === undefined ? "none" : toPrologAtom(resultPath);
62
+ const rules = rulesAllowlist
63
+ ? `[${[...rulesAllowlist].map(toPrologAtom).join(",")}]`
64
+ : undefined;
65
+ const transport = rules
66
+ ? `predicate_property(checks:check_selected_json_transport(_, _, _, _), _)
67
+ -> call(checks:check_selected_json_transport(${rules}, ${target}, Transport, JsonString))`
68
+ : `predicate_property(checks:check_all_json_transport(_, _, _, _), _)
69
+ -> call(checks:check_all_json_transport(${target}, false, Transport, JsonString))`;
70
+ const fileOnly = resultPath === undefined
71
+ ? ""
72
+ : rules
73
+ ? `predicate_property(checks:check_selected_json_file(_, _), _)
74
+ -> call(checks:check_selected_json_file(${rules}, ${target})), Transport = file
75
+ ; `
76
+ : `predicate_property(checks:check_all_json_file(_, _), _)
77
+ -> call(checks:check_all_json_file(${target}, false)), Transport = file
78
+ ; `;
79
+ const allAnswer = `predicate_property(checks:check_all_json_with_options(_, _), _)
80
+ -> call(checks:check_all_json_with_options(JsonString, false)), Transport = answer
81
+ ; call(checks:check_all_json(JsonString)), Transport = answer`;
82
+ const answer = rules
83
+ ? `predicate_property(checks:check_selected_json(_, _), _)
84
+ -> call(checks:check_selected_json(${rules}, JsonString)), Transport = answer
85
+ ; ${allAnswer}`
86
+ : allAnswer;
87
+ const goal = `( ${transport}
88
+ ; ${fileOnly}${answer}
89
+ )`;
90
+ return `(use_module('${escapeAtom(checksPlPath)}'), ${ontologyQualityOverridesGoal()}, ${goal})`;
91
+ }
28
92
  /**
29
93
  * Run all checks using the aggregated Prolog predicates.
30
94
  * This makes a single Prolog call and parses JSON output, significantly
@@ -36,27 +100,36 @@ export async function runAggregatedChecks(prolog, rulesAllowlist) {
36
100
  // implements REQ-003
37
101
  const violations = [];
38
102
  const checksPlPath = path.join(path.dirname(resolveKbPlPath()), "checks.pl");
39
- const checksPlPathEscaped = escapeAtom(checksPlPath);
40
- const fallbackQuery = `( predicate_property(checks:check_all_json_with_options(_, _), _)
41
- -> call(checks:check_all_json_with_options(JsonString, false))
42
- ; call(checks:check_all_json(JsonString))
43
- )`;
44
- const checksQuery = rulesAllowlist
45
- ? `( predicate_property(checks:check_selected_json(_, _), _)
46
- -> call(checks:check_selected_json([${[...rulesAllowlist]
47
- .map(toPrologAtom)
48
- .join(",")}], JsonString))
49
- ; ${fallbackQuery}
50
- )`
51
- : fallbackQuery;
52
- const query = `(use_module('${checksPlPathEscaped}'), ${ontologyQualityOverridesGoal()}, ${checksQuery})`;
53
- const result = await prolog.query(query);
103
+ const resultFile = checkResultFile();
104
+ let result;
105
+ let jsonString;
106
+ try {
107
+ result = await prolog.query(aggregatedChecksQuery(checksPlPath, rulesAllowlist, resultFile.path));
108
+ // rationale: the engine answers Transport "file" only after a successful
109
+ // query that was given a path, so neither guard changes which answers
110
+ // are read; they only narrow the path for the read.
111
+ // Stryker disable next-line ConditionalExpression,LogicalOperator
112
+ const mayRead = result.success && resultFile.path !== undefined;
113
+ if (mayRead && result.bindings.Transport === "file") {
114
+ try {
115
+ jsonString = readFileSync(resultFile.path, "utf8");
116
+ }
117
+ catch {
118
+ // The engine wrote a file this process cannot read (an engine with
119
+ // another view of the temp folder): ask for the JSON as an answer.
120
+ result = await prolog.query(aggregatedChecksQuery(checksPlPath, rulesAllowlist, undefined));
121
+ }
122
+ }
123
+ }
124
+ finally {
125
+ resultFile.dispose();
126
+ }
54
127
  if (!result.success) {
55
128
  throw new Error(`Aggregated checks query failed: ${result.error || "Unknown error"}`);
56
129
  }
57
130
  let violationsDict;
58
131
  try {
59
- const jsonString = result.bindings.JsonString;
132
+ jsonString ??= result.bindings.JsonString;
60
133
  if (!jsonString) {
61
134
  throw new Error("No JSON string in binding");
62
135
  }
@@ -12,6 +12,7 @@ interface CoverageOptions {
12
12
  migrationPredicateLimit?: string;
13
13
  migrationPredicateMinScore?: string;
14
14
  format?: "json" | "table";
15
+ cases?: boolean;
15
16
  }
16
17
  export declare function coverageCommand(options: CoverageOptions): Promise<void>;
17
18
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAMA,UAAU,eAAe;IACvB,EAAE,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC7E"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAMA,UAAU,eAAe;IACvB,EAAE,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAGD,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC7E"}
@@ -26,5 +26,45 @@ export async function coverageCommand(options) {
26
26
  migrationPredicateLimit: Number.parseInt(options.migrationPredicateLimit || "5", 10),
27
27
  migrationPredicateMinScore: Number.parseFloat(options.migrationPredicateMinScore || "0.35"),
28
28
  });
29
+ if (options.cases === true) {
30
+ printCaseTable(options.format, result.structuredContent);
31
+ return;
32
+ }
29
33
  printDiscoveryResult(options.format, result.structuredContent, result.content[0]?.text ?? "Coverage summary unavailable.");
30
34
  }
35
+ // implements REQ-kibi-case-coverage
36
+ // The edge cases of each returned requirement: one line per case with its
37
+ // predicted outcome and coverage, and the assumption an uncovered rejection
38
+ // case needs. JSON keeps the requirement id with its cases stage.
39
+ function printCaseTable(format, structured) {
40
+ const rows = Array.isArray(structured?.rows)
41
+ ? structured.rows
42
+ : [];
43
+ const withCases = rows.flatMap((row) => {
44
+ const stages = row.proofStages;
45
+ const stage = stages?.cases;
46
+ return stage?.cases?.length ? [{ id: String(row.id), stage }] : [];
47
+ });
48
+ if (format === "json") {
49
+ console.log(JSON.stringify({ rows: withCases.map(({ id, stage }) => ({ id, cases: stage })) }, null, 2));
50
+ return;
51
+ }
52
+ if (withCases.length === 0) {
53
+ console.log("No requirement in this page has derived edge cases.");
54
+ return;
55
+ }
56
+ const lines = [];
57
+ for (const { id, stage } of withCases) {
58
+ const summary = stage.summary ?? {};
59
+ lines.push(`${id}: ${stage.status} (${summary.covered ?? 0} covered, ${summary.uncovered ?? 0} uncovered, ${summary.unspecified ?? 0} unspecified, ${summary.waived ?? 0} waived)`);
60
+ for (const row of stage.cases ?? []) {
61
+ const where = row.coverage === "covered"
62
+ ? ` by ${(row.scenarios ?? []).join(", ")}`
63
+ : "";
64
+ lines.push(` ${row.caseId} ${row.factId} ${row.constraint} -> ${row.predicted}: ${row.coverage}${where}`);
65
+ if (row.coverage === "uncovered" && row.predicted === "rejection")
66
+ lines.push(` assumes ${JSON.stringify(row.assumption ?? {})}`);
67
+ }
68
+ }
69
+ console.log(lines.join("\n"));
70
+ }
@@ -1,6 +1,11 @@
1
1
  export interface DoctorOptions {
2
2
  format?: "json" | "table";
3
3
  }
4
+ /** `doctor:capability_plugins+git_hooks` for the checks that failed. */
5
+ export declare function doctorFailureCategory(results: readonly {
6
+ name: string;
7
+ passed: boolean;
8
+ }[]): string | undefined;
4
9
  export declare function doctorCommand(options?: DoctorOptions): Promise<{
5
10
  exitCode: number;
6
11
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAyGA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,aAAa,CACjC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuH/B;AAED,wBAAsB,4BAA4B,CAChD,IAAI,GAAE,MAAM,OAAO,CAAC;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CACT,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;MAkE3C;AAkGD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAepB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAiHA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wEAAwE;AACxE,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,EAAE,GACpD,MAAM,GAAG,SAAS,CAUpB;AAGD,wBAAsB,aAAa,CACjC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAyH/B;AAED,wBAAsB,4BAA4B,CAChD,IAAI,GAAE,MAAM,OAAO,CAAC;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CACT,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;MAkE3C;AAkGD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAepB"}
@@ -25,6 +25,7 @@ import { kibiPackageVersions } from "../package-versions.js";
25
25
  import { describeConfiguredCapabilityPlugins, readProjectKibiConfig, } from "../plugins/project-config.js";
26
26
  import { SwiplResolutionError, inspectSwiplBundle, probeRequiredLibraries, resolveSwipl, } from "../prolog/swipl-resolver.js";
27
27
  import { buildMigrationPlan, migrationAction, } from "../public/operations/migration-plan.js";
28
+ import { noteCliErrorCategory } from "../usage-telemetry.js";
28
29
  import { resolveBranchAttachment, resolveReadBranchAttachment, } from "../utils/branch-resolver.js";
29
30
  import { branchStoreCompilation, inspectBranchStore, storeLockTakeoverReason, uncompiledBranchStoreReason, } from "../utils/branch-store.js";
30
31
  import { LEGACY_KB_MIGRATION_COMMAND, LEGACY_KB_MIGRATION_NOTE, } from "../utils/config.js";
@@ -32,6 +33,7 @@ import { resolveGitRepository, } from "../utils/git-repository-context.js";
32
33
  import { readKbManifestStatus } from "../utils/kb-manifest.js";
33
34
  import { manifestMergeDriverGaps, mergeDriverSetup, } from "../utils/merge-driver-setup.js";
34
35
  import { LATEST_KB_SCHEMA_VERSION } from "../utils/schema-version.js";
36
+ import { detectHookManager, hookManagerCommands, missingKibiHookCommands, } from "./hook-managers.js";
35
37
  import { KIBI_HOOK_BEGIN, hasManagedHooks, outdatedManagedHooks, } from "./init-helpers.js";
36
38
  import { planLegacyStorageMigration } from "./legacy-storage-migration.js";
37
39
  /**
@@ -45,6 +47,17 @@ const FIRST_PARTY_PLUGIN_SECRETS = {
45
47
  /** Static Jev defaults — must stay aligned with kibi-plugin-jev (no import). */
46
48
  const JEV_DEFAULT_MODEL = "jev-latest";
47
49
  const JEV_MAX_TIMEOUT_MS = 120_000;
50
+ // implements REQ-kibi-anonymous-usage-telemetry
51
+ /** `doctor:capability_plugins+git_hooks` for the checks that failed. */
52
+ export function doctorFailureCategory(results) {
53
+ const failed = results
54
+ .filter((result) => !result.passed)
55
+ .map((result) => result.name
56
+ .toLowerCase()
57
+ .replace(/[^a-z0-9]+/g, "_")
58
+ .replace(/^_|_$/g, ""));
59
+ return failed.length === 0 ? undefined : `doctor:${failed.join("+")}`;
60
+ }
48
61
  // implements REQ-003
49
62
  export async function doctorCommand(options = {}) {
50
63
  // The repository context is per-diagnostic-run state: clearing here keeps
@@ -110,6 +123,8 @@ export async function doctorCommand(options = {}) {
110
123
  results.push({ name, ...(await check()) });
111
124
  }
112
125
  const allPassed = results.every((result) => result.passed);
126
+ // Usage telemetry names the failing checks by their fixed names.
127
+ noteCliErrorCategory(doctorFailureCategory(results));
113
128
  const warnings = results.filter((result) => result.passed && result.warning === true).length;
114
129
  const runtime = await runtimeProvenance();
115
130
  const packageActions = await packageMigrationActions(runtime);
@@ -837,6 +852,47 @@ function hooksPathSuffix() {
837
852
  : "";
838
853
  return ` (core.hooksPath=${context.hooksPathConfig}${origin})`;
839
854
  }
855
+ /**
856
+ * The hook manager (lefthook, husky, pre-commit) that owns this repository's
857
+ * hooks. Its hook files are generated runners, so the commands they run are
858
+ * read from the manager's configuration instead of the files Git executes.
859
+ */
860
+ // implements REQ-git-hook-manager-integration
861
+ function doctorHookManager() {
862
+ const context = doctorRepositoryContext();
863
+ if (!context)
864
+ return null;
865
+ return detectHookManager(context.worktreeRoot, context.effectiveHooksDir, context.hooksPathConfig);
866
+ }
867
+ // implements REQ-git-hook-manager-integration
868
+ function checkHookManagerDelegation(manager, hooks, consequence) {
869
+ const worktreeRoot = doctorRepositoryContext()?.worktreeRoot ?? process.cwd();
870
+ const owner = `Managed by ${manager.name} (${manager.configPath})`;
871
+ const coverage = hooks.map((hook) => ({
872
+ hook,
873
+ missing: missingKibiHookCommands(hook, hookManagerCommands(manager.name, worktreeRoot, hook) ?? []),
874
+ }));
875
+ const gaps = coverage.filter((entry) => entry.missing.length > 0);
876
+ if (gaps.length === 0) {
877
+ const runs = coverage
878
+ .map(({ hook }) => `${hook} runs ${missingKibiHookCommands(hook, [])
879
+ .map((label) => `'${label}'`)
880
+ .join(" and ")}`)
881
+ .join("; ");
882
+ return { passed: true, message: `${owner}; ${runs}` };
883
+ }
884
+ // The manager may reach Kibi through a task runner or script that is not
885
+ // part of its configuration, so an invisible command is a warning only.
886
+ const described = gaps
887
+ .map(({ hook, missing }) => `${hook} does not visibly run ${missing.map((label) => `'${label}'`).join(" and ")}`)
888
+ .join("; ");
889
+ return {
890
+ passed: true,
891
+ warning: true,
892
+ message: `${owner}; ${described}. Kibi reads only the ${manager.name} configuration, not the task runners or scripts it calls; unless they run these commands, ${consequence}`,
893
+ remediation: `Add Kibi's commands to ${manager.configPath}. Print them with: kibi init --print-hook ${gaps.length === 1 ? (gaps[0]?.hook ?? "all") : "all"} --format ${manager.name}`,
894
+ };
895
+ }
840
896
  /**
841
897
  * Kibi-managed hook sections must match what this CLI installs. A section
842
898
  * written by an older CLI keeps running while silently lacking newer gates
@@ -870,6 +926,10 @@ function checkManagedHookSections() {
870
926
  return { passed: true, message: "Current for this Kibi CLI" };
871
927
  }
872
928
  function checkGitHooks() {
929
+ const manager = doctorHookManager();
930
+ if (manager) {
931
+ return checkHookManagerDelegation(manager, ["post-checkout", "post-merge"], "a new branch is not compiled on checkout or after a merge");
932
+ }
873
933
  const postCheckoutPath = path.join(effectiveHooksDir(), "post-checkout");
874
934
  const postMergePath = path.join(effectiveHooksDir(), "post-merge");
875
935
  const preCommitPath = path.join(effectiveHooksDir(), "pre-commit");
@@ -919,42 +979,9 @@ function checkGitHooks() {
919
979
  remediation: "Run: kibi init",
920
980
  };
921
981
  }
922
- /**
923
- * Individual shell commands of a hook script, ignoring comments. Lines are
924
- * split on command separators so `a && b` counts as two commands.
925
- */
926
- // implements REQ-git-hook-effective-install
927
- function hookCommands(content) {
928
- return content
929
- .split("\n")
930
- .filter((line) => !line.trimStart().startsWith("#"))
931
- .flatMap((line) => line.split(/&&|\|\||;|\|/))
932
- .map((command) => command.trim())
933
- .filter((command) => command.length > 0);
934
- }
935
- // Matches `kibi <sub>`, `npx kibi <sub>`, `node_modules/.bin/kibi <sub>` and
936
- // the template's `"$KIBI_BIN" <sub>`.
937
- // implements REQ-git-hook-effective-install
938
- function invokesKibi(command, subcommand) {
939
- return new RegExp(`(?:\\bkibi|\\bKIBI_BIN)["'}]*\\s+${subcommand}(?=\\s|$)`).test(command);
940
- }
941
- /** The pre-commit gate the managed template runs, as a custom hook must. */
942
- const PRE_COMMIT_DELEGATIONS = [
943
- {
944
- label: "kibi check-generated --staged --changed-only",
945
- matches: (command) => invokesKibi(command, "check-generated") &&
946
- /\s--staged(?=\s|$)/.test(command) &&
947
- /\s--changed-only(?=\s|$)/.test(command),
948
- },
949
- {
950
- label: "kibi check --staged",
951
- matches: (command) => invokesKibi(command, "check") && /\s--staged(?=\s|$)/.test(command),
952
- },
953
- ];
954
982
  // implements REQ-git-hook-effective-install
955
983
  function checkCustomPreCommitHook(content, executable) {
956
- const commands = hookCommands(content);
957
- const missing = PRE_COMMIT_DELEGATIONS.filter((delegation) => !commands.some(delegation.matches)).map((delegation) => `'${delegation.label}'`);
984
+ const missing = missingKibiHookCommands("pre-commit", [content]).map((label) => `'${label}'`);
958
985
  if (missing.length > 0) {
959
986
  // An unmarked file that still carries the old template header is a Kibi
960
987
  // hook from before managed sections; removing it lets init reinstall it.
@@ -980,6 +1007,10 @@ function checkCustomPreCommitHook(content, executable) {
980
1007
  };
981
1008
  }
982
1009
  function checkPreCommitHook() {
1010
+ const manager = doctorHookManager();
1011
+ if (manager) {
1012
+ return checkHookManagerDelegation(manager, ["pre-commit"], "commits skip Kibi enforcement");
1013
+ }
983
1014
  const postCheckoutPath = path.join(effectiveHooksDir(), "post-checkout");
984
1015
  const postMergePath = path.join(effectiveHooksDir(), "post-merge");
985
1016
  const preCommitPath = path.join(effectiveHooksDir(), "pre-commit");
@@ -1063,6 +1094,10 @@ function checkPreCommitHook() {
1063
1094
  }
1064
1095
  }
1065
1096
  function checkPostRewriteHook() {
1097
+ const manager = doctorHookManager();
1098
+ if (manager) {
1099
+ return checkHookManagerDelegation(manager, ["post-rewrite"], "a rebased branch keeps a stale KB until the next 'kibi sync'");
1100
+ }
1066
1101
  const postCheckoutPath = path.join(effectiveHooksDir(), "post-checkout");
1067
1102
  const postMergePath = path.join(effectiveHooksDir(), "post-merge");
1068
1103
  const postRewritePath = path.join(effectiveHooksDir(), "post-rewrite");
@@ -1091,7 +1126,7 @@ function checkPostRewriteHook() {
1091
1126
  // A custom hook (no kibi-managed section) is never edited by init.
1092
1127
  // implements REQ-git-hook-effective-install
1093
1128
  if (!content.includes(KIBI_HOOK_BEGIN)) {
1094
- if (!hookCommands(content).some((cmd) => invokesKibi(cmd, "sync"))) {
1129
+ if (missingKibiHookCommands("post-rewrite", [content]).length > 0) {
1095
1130
  return {
1096
1131
  passed: false,
1097
1132
  message: `Custom post-rewrite hook (no kibi-managed section) does not run 'kibi sync'${hooksPathSuffix()}`,
@@ -1 +1 @@
1
- {"version":3,"file":"github-init.d.ts","sourceRoot":"","sources":["../../src/commands/github-init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"github-init.d.ts","sourceRoot":"","sources":["../../src/commands/github-init.ts"],"names":[],"mappings":"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"}
@@ -74,9 +74,11 @@ export function parseGitHubRemote(url) {
74
74
  return undefined;
75
75
  }
76
76
  export function githubPagesUrls(repo) {
77
+ // The *.github.io host is case-insensitive, but the project-site path is
78
+ // case-sensitive, so the repository segment keeps its exact case.
77
79
  const owner = repo.owner.toLowerCase();
78
- const name = repo.repo.toLowerCase();
79
- const isUserSite = name === `${owner}.github.io`;
80
+ const name = repo.repo;
81
+ const isUserSite = name.toLowerCase() === `${owner}.github.io`;
80
82
  const origin = isUserSite
81
83
  ? `https://${owner}.github.io/`
82
84
  : `https://${owner}.github.io/${name}/`;