kibi-cli 2.39.0 → 2.40.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 (163) hide show
  1. package/dist/cli-register-foundation.js +2 -2
  2. package/dist/commands/check.d.ts.map +1 -1
  3. package/dist/commands/check.js +33 -9
  4. package/dist/commands/doctor.d.ts.map +1 -1
  5. package/dist/commands/doctor.js +15 -0
  6. package/dist/commands/init.d.ts.map +1 -1
  7. package/dist/commands/init.js +4 -0
  8. package/dist/commands/migrate-plan-record.d.ts +18 -0
  9. package/dist/commands/migrate-plan-record.d.ts.map +1 -0
  10. package/dist/commands/migrate-plan-record.js +112 -0
  11. package/dist/commands/migrate.d.ts +11 -2
  12. package/dist/commands/migrate.d.ts.map +1 -1
  13. package/dist/commands/migrate.js +53 -7
  14. package/dist/commands/prove.d.ts.map +1 -1
  15. package/dist/commands/prove.js +18 -3
  16. package/dist/commands/sync/manifest.d.ts.map +1 -1
  17. package/dist/commands/sync/manifest.js +17 -4
  18. package/dist/commands/sync.d.ts.map +1 -1
  19. package/dist/commands/sync.js +8 -0
  20. package/dist/commands/telemetry.d.ts.map +1 -1
  21. package/dist/commands/telemetry.js +12 -2
  22. package/dist/extractors/symbol-title-match.d.ts +31 -0
  23. package/dist/extractors/symbol-title-match.d.ts.map +1 -0
  24. package/dist/extractors/symbol-title-match.js +133 -0
  25. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  26. package/dist/extractors/symbols-coordinator.js +81 -12
  27. package/dist/operations/bootstrap/discovery-evidence.js +2 -2
  28. package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
  29. package/dist/operations/bootstrap/guidance-actions.js +12 -1
  30. package/dist/operations/bootstrap/plugin-offers.d.ts +7 -1
  31. package/dist/operations/bootstrap/plugin-offers.d.ts.map +1 -1
  32. package/dist/operations/bootstrap/plugin-offers.js +73 -3
  33. package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
  34. package/dist/operations/modeling/logic-modeling.js +2 -1
  35. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  36. package/dist/operations/modeling/model-requirement.js +2 -1
  37. package/dist/operations/mutation/symbol-refresh.d.ts +2 -0
  38. package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
  39. package/dist/operations/mutation/symbol-refresh.js +6 -1
  40. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  41. package/dist/operations/mutation/upsert.js +7 -0
  42. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  43. package/dist/operations/planning/compile-intent.js +2 -1
  44. package/dist/operations/proof/claim-bindings.d.ts +11 -0
  45. package/dist/operations/proof/claim-bindings.d.ts.map +1 -1
  46. package/dist/operations/proof/claim-bindings.js +144 -1
  47. package/dist/operations/proof/code-certificates.d.ts +10 -3
  48. package/dist/operations/proof/code-certificates.d.ts.map +1 -1
  49. package/dist/operations/proof/code-certificates.js +65 -13
  50. package/dist/operations/proof/code-languages.d.ts +104 -0
  51. package/dist/operations/proof/code-languages.d.ts.map +1 -0
  52. package/dist/operations/proof/code-languages.js +119 -0
  53. package/dist/operations/proof/code-models.d.ts +2 -0
  54. package/dist/operations/proof/code-models.d.ts.map +1 -1
  55. package/dist/operations/proof/code-models.js +11 -5
  56. package/dist/operations/proof/code-runner.d.ts +12 -9
  57. package/dist/operations/proof/code-runner.d.ts.map +1 -1
  58. package/dist/operations/proof/code-runner.js +81 -38
  59. package/dist/operations/proof/code-scope.d.ts +8 -0
  60. package/dist/operations/proof/code-scope.d.ts.map +1 -1
  61. package/dist/operations/proof/code-scope.js +30 -1
  62. package/dist/operations/proof/explain.d.ts +13 -0
  63. package/dist/operations/proof/explain.d.ts.map +1 -1
  64. package/dist/operations/proof/explain.js +66 -0
  65. package/dist/operations/proof/ingest-proof.d.ts +2 -0
  66. package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
  67. package/dist/operations/proof/ingest-proof.js +1 -0
  68. package/dist/operations/proof/java-package-shadow.d.ts +14 -0
  69. package/dist/operations/proof/java-package-shadow.d.ts.map +1 -0
  70. package/dist/operations/proof/java-package-shadow.js +389 -0
  71. package/dist/operations/proof/prolog-evaluator.d.ts +14 -0
  72. package/dist/operations/proof/prolog-evaluator.d.ts.map +1 -0
  73. package/dist/operations/proof/prolog-evaluator.js +247 -0
  74. package/dist/operations/proof/prolog-source-reader.d.ts +20 -0
  75. package/dist/operations/proof/prolog-source-reader.d.ts.map +1 -0
  76. package/dist/operations/proof/prolog-source-reader.js +1123 -0
  77. package/dist/operations/proof/source-code-readers.d.ts +6 -0
  78. package/dist/operations/proof/source-code-readers.d.ts.map +1 -1
  79. package/dist/operations/proof/source-code-readers.js +879 -75
  80. package/dist/plugins/approved-source-analyzers.generated.d.ts +13 -35
  81. package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -1
  82. package/dist/plugins/approved-source-analyzers.generated.js +13 -35
  83. package/dist/plugins/plugin-install-check.d.ts +21 -0
  84. package/dist/plugins/plugin-install-check.d.ts.map +1 -0
  85. package/dist/plugins/plugin-install-check.js +62 -0
  86. package/dist/plugins/proof-reference-extractors.d.ts +20 -0
  87. package/dist/plugins/proof-reference-extractors.d.ts.map +1 -0
  88. package/dist/plugins/proof-reference-extractors.js +104 -0
  89. package/dist/plugins/reference-language-suggestion.d.ts +51 -0
  90. package/dist/plugins/reference-language-suggestion.d.ts.map +1 -0
  91. package/dist/plugins/reference-language-suggestion.js +277 -0
  92. package/dist/plugins/registry.d.ts.map +1 -1
  93. package/dist/plugins/registry.js +3 -1
  94. package/dist/plugins/source-analysis-service.d.ts.map +1 -1
  95. package/dist/plugins/source-analysis-service.js +4 -0
  96. package/dist/plugins/source-change-analysis.d.ts +26 -1
  97. package/dist/plugins/source-change-analysis.d.ts.map +1 -1
  98. package/dist/plugins/source-change-analysis.js +77 -5
  99. package/dist/plugins/source-classification.d.ts.map +1 -1
  100. package/dist/plugins/source-classification.js +23 -3
  101. package/dist/public/operations/catalog.d.ts +32 -7
  102. package/dist/public/operations/catalog.d.ts.map +1 -1
  103. package/dist/public/operations/check-executor.d.ts.map +1 -1
  104. package/dist/public/operations/check-executor.js +3 -0
  105. package/dist/public/operations/evidence-floor.d.ts +8 -0
  106. package/dist/public/operations/evidence-floor.d.ts.map +1 -1
  107. package/dist/public/operations/evidence-floor.js +19 -1
  108. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  109. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  110. package/dist/public/operations/specs/check-rules.generated.js +2 -1
  111. package/dist/public/operations/specs/check.d.ts +1 -1
  112. package/dist/public/operations/specs/mutation-schemas.d.ts +31 -6
  113. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  114. package/dist/public/operations/specs/reporting.d.ts +8 -0
  115. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  116. package/dist/public/operations/specs/reporting.js +26 -3
  117. package/dist/public/operations/specs/semantic.d.ts.map +1 -1
  118. package/dist/public/operations/specs/semantic.js +2 -1
  119. package/dist/public/operations/specs/upsert.d.ts +31 -6
  120. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  121. package/dist/public/operations/symbol-coordinates-check.d.ts +11 -0
  122. package/dist/public/operations/symbol-coordinates-check.d.ts.map +1 -0
  123. package/dist/public/operations/symbol-coordinates-check.js +66 -0
  124. package/dist/public/proof-protocol.d.ts +31 -6
  125. package/dist/public/proof-protocol.d.ts.map +1 -1
  126. package/dist/public/proof-protocol.js +45 -15
  127. package/dist/public/proof-sources.d.ts +4 -2
  128. package/dist/public/proof-sources.d.ts.map +1 -1
  129. package/dist/public/proof-sources.js +43 -4
  130. package/dist/public/skills/kibi-usage/SKILL.md +6 -3
  131. package/dist/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
  132. package/dist/public/skills/kibi-usage/resources/proof.md +44 -3
  133. package/dist/schemas/entity.schema.json +34 -6
  134. package/dist/traceability/analysis-gate.d.ts +3 -1
  135. package/dist/traceability/analysis-gate.d.ts.map +1 -1
  136. package/dist/traceability/analysis-gate.js +9 -1
  137. package/dist/traceability/staged-file-coverage.d.ts.map +1 -1
  138. package/dist/traceability/staged-file-coverage.js +7 -2
  139. package/dist/traceability/symbol-extract.d.ts +17 -0
  140. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  141. package/dist/traceability/symbol-extract.js +69 -15
  142. package/dist/traceability/validate.d.ts.map +1 -1
  143. package/dist/traceability/validate.js +5 -7
  144. package/dist/utils/first-sentence.d.ts +9 -0
  145. package/dist/utils/first-sentence.d.ts.map +1 -0
  146. package/dist/utils/first-sentence.js +52 -0
  147. package/dist/utils/rule-registry.generated.d.ts +6 -0
  148. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  149. package/dist/utils/rule-registry.generated.js +7 -0
  150. package/package.json +5 -5
  151. package/src/public/operations/check-executor.ts +8 -0
  152. package/src/public/operations/evidence-floor.ts +29 -1
  153. package/src/public/operations/specs/check-rules.generated.ts +2 -1
  154. package/src/public/operations/specs/reporting.ts +38 -3
  155. package/src/public/operations/specs/semantic.ts +2 -1
  156. package/src/public/operations/symbol-coordinates-check.ts +79 -0
  157. package/src/public/proof-protocol-types.d.ts +22 -5
  158. package/src/public/proof-protocol.ts +78 -19
  159. package/src/public/proof-sources.ts +51 -3
  160. package/src/public/skills/kibi-usage/SKILL.md +6 -3
  161. package/src/public/skills/kibi-usage/resources/prolog-proofs.md +207 -0
  162. package/src/public/skills/kibi-usage/resources/proof.md +44 -3
  163. package/src/schemas/entity.schema.json +34 -6
@@ -0,0 +1,277 @@
1
+ /*
2
+ Kibi — repo-local, per-branch, queryable long-term memory for software projects
3
+ Copyright (C) 2026 Piotr Franczyk
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Affero General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Affero General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Affero General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ import { execFileSync } from "node:child_process";
19
+ import { createHash } from "node:crypto";
20
+ import { existsSync, readFileSync } from "node:fs";
21
+ import { createRequire } from "node:module";
22
+ import { dirname, join } from "node:path";
23
+ import { REFERENCE_EXTRACTOR_CAPABILITY_ID, SYMBOL_EXTRACTOR_V2_CAPABILITY_ID, } from "kibi-plugin-sdk";
24
+ import { PLUGIN_LANGUAGE_PACKS, PLUGIN_REFERENCE_LANGUAGES, } from "../operations/proof/code-languages.js";
25
+ import { readProjectKibiConfig } from "./project-config.js";
26
+ import { REFERENCE_PLUGIN_PACKAGE } from "./proof-reference-extractors.js";
27
+ const NOT_PRODUCTION = /(?:^|\/)(?:node_modules|dist|build|target|bin|obj|vendor|coverage|tests?|__tests__|e2e|fixtures?)\/|^\.kb\/|(?:_test\.go|Tests?\.(?:java|cs)|\.(?:test|spec)\.[^/]+)$/i;
28
+ /** Whether a package.json lists a package in any dependency field. */
29
+ export function manifestDeclares(manifest, packageName) {
30
+ if (typeof manifest !== "object" || manifest === null)
31
+ return false;
32
+ return ["dependencies", "devDependencies", "optionalDependencies"].some((field) => {
33
+ const dependencies = manifest[field];
34
+ return (typeof dependencies === "object" &&
35
+ dependencies !== null &&
36
+ Object.hasOwn(dependencies, packageName));
37
+ });
38
+ }
39
+ /** The version of a package installed for the workspace, or null. */
40
+ export function workspaceInstalledVersion(workspaceRoot) {
41
+ const resolve = createRequire(join(workspaceRoot, "package.json")).resolve;
42
+ return (packageName) => {
43
+ // A package whose exports omit ./package.json (kibi-plugin-treesitter)
44
+ // is found through the node_modules lookup directories instead.
45
+ const manifests = [
46
+ () => resolve(`${packageName}/package.json`),
47
+ ...(resolve.paths(packageName) ?? []).map((directory) => () => join(directory, packageName, "package.json")),
48
+ ];
49
+ for (const manifestPath of manifests) {
50
+ try {
51
+ const manifest = JSON.parse(readFileSync(manifestPath(), "utf8"));
52
+ return typeof manifest.version === "string" ? manifest.version : null;
53
+ }
54
+ catch {
55
+ // Try the next lookup directory.
56
+ }
57
+ }
58
+ return null;
59
+ };
60
+ }
61
+ /** The pack versions the installed kibi-plugin-treesitter pins. */
62
+ export function pinnedPackVersions(workspaceRoot) {
63
+ if (workspaceRoot === undefined)
64
+ return new Map();
65
+ try {
66
+ const catalogPath = createRequire(join(workspaceRoot, "package.json")).resolve(`${REFERENCE_PLUGIN_PACKAGE}/catalog.json`);
67
+ const catalog = JSON.parse(readFileSync(catalogPath, "utf8"));
68
+ return new Map((catalog.languages ?? []).flatMap((language) => typeof language.pack === "string" &&
69
+ typeof language.packVersion === "string"
70
+ ? [[language.pack, language.packVersion]]
71
+ : []));
72
+ }
73
+ catch {
74
+ return new Map();
75
+ }
76
+ }
77
+ /**
78
+ * The installed kibi-lang-* packs, at the version the installed plugin pins,
79
+ * whose grammar file does not hash to the SHA-256 the plugin pins. Doctor
80
+ * names them so a changed grammar is not shown as healthy.
81
+ */
82
+ // implements REQ-kibi-tree-sitter-language-packs
83
+ export function modifiedPacks(workspaceRoot) {
84
+ if (workspaceRoot === undefined)
85
+ return new Set();
86
+ const resolve = createRequire(join(workspaceRoot, "package.json")).resolve;
87
+ let languages;
88
+ try {
89
+ languages =
90
+ JSON.parse(readFileSync(resolve(`${REFERENCE_PLUGIN_PACKAGE}/catalog.json`), "utf8")).languages ?? [];
91
+ }
92
+ catch {
93
+ return new Set();
94
+ }
95
+ const modified = new Set();
96
+ for (const language of languages) {
97
+ const { pack, packVersion, asset, assetSha256 } = language;
98
+ if (typeof pack !== "string" ||
99
+ typeof asset !== "string" ||
100
+ typeof assetSha256 !== "string")
101
+ continue;
102
+ let manifestPath;
103
+ try {
104
+ manifestPath = resolve(`${pack}/package.json`);
105
+ }
106
+ catch {
107
+ continue;
108
+ }
109
+ try {
110
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
111
+ if (manifest.version !== packVersion)
112
+ continue;
113
+ const digest = createHash("sha256")
114
+ .update(readFileSync(join(dirname(manifestPath), asset)))
115
+ .digest("hex");
116
+ if (digest !== assetSha256)
117
+ modified.add(pack);
118
+ }
119
+ catch {
120
+ modified.add(pack);
121
+ }
122
+ }
123
+ return modified;
124
+ }
125
+ /**
126
+ * Whether the project has sources kibi-plugin-treesitter must read for it:
127
+ * Go, Java, C# or Rust files whose references source proofs read only
128
+ * through the plugin while it is not activated for that, or files of a
129
+ * language whose kibi-lang-* pack is not installed (at the version the
130
+ * installed plugin pins) while the plugin is listed or being suggested.
131
+ * Reads file names and package manifests only; never imports a plugin.
132
+ */
133
+ // implements REQ-kibi-tree-sitter-references, REQ-kibi-tree-sitter-language-packs
134
+ export function referenceLanguageSuggestion(files, config, installedVersion = () => null, pinned = new Map(), modified = new Set(), pluginDeclared = true) {
135
+ const production = files.filter((file) => !NOT_PRODUCTION.test(file));
136
+ const references = PLUGIN_REFERENCE_LANGUAGES.map((language) => ({
137
+ name: language.name,
138
+ found: production.filter((file) => language.pattern.test(file)),
139
+ })).filter((language) => language.found.length > 0);
140
+ const entry = (config.plugins ?? []).find((plugin) => plugin.package === REFERENCE_PLUGIN_PACKAGE);
141
+ if ((config.declinedPlugins ?? []).includes(REFERENCE_PLUGIN_PACKAGE))
142
+ return null;
143
+ const activate = references.length > 0 &&
144
+ entry?.capabilities[REFERENCE_EXTRACTOR_CAPABILITY_ID] === undefined;
145
+ const packLanguages = PLUGIN_LANGUAGE_PACKS.map((language) => ({
146
+ ...language,
147
+ found: production.filter((file) => language.pattern.test(file)),
148
+ })).filter((language) => language.found.length > 0);
149
+ // Without the plugin, any language it reads is a reason to suggest it for
150
+ // symbols. `.pl` alone is shared with Perl, so Prolog counts only with a
151
+ // `.plt` file or a `pack.pl`.
152
+ const confirmed = packLanguages.filter((language) => language.pack !== "kibi-lang-prolog" ||
153
+ language.found.some((file) => /(?:\.plt|(?:^|\/)pack\.pl)$/i.test(file)));
154
+ const symbolLanguages = confirmed;
155
+ const suggestSymbols = entry === undefined && symbolLanguages.length > 0;
156
+ if (entry === undefined && !activate && !suggestSymbols)
157
+ return null;
158
+ const missing = confirmed.filter((language) => {
159
+ const installed = installedVersion(language.pack);
160
+ const wanted = pinned.get(language.pack);
161
+ return (installed === null ||
162
+ (wanted !== undefined && installed !== wanted) ||
163
+ modified.has(language.pack));
164
+ });
165
+ if (!activate && !suggestSymbols && missing.length === 0)
166
+ return null;
167
+ const shown = activate
168
+ ? references
169
+ : suggestSymbols
170
+ ? symbolLanguages
171
+ : missing;
172
+ return {
173
+ package: REFERENCE_PLUGIN_PACKAGE,
174
+ capabilities: [
175
+ ...(activate ? [REFERENCE_EXTRACTOR_CAPABILITY_ID] : []),
176
+ ...(entry === undefined ? [SYMBOL_EXTRACTOR_V2_CAPABILITY_ID] : []),
177
+ ],
178
+ languages: shown.map((language) => ({
179
+ name: language.name,
180
+ files: language.found.length,
181
+ })),
182
+ evidence: shown.flatMap((language) => language.found).slice(0, 5),
183
+ activeForSymbolsOnly: entry !== undefined,
184
+ pluginInstalled: pluginDeclared && installedVersion(REFERENCE_PLUGIN_PACKAGE) !== null,
185
+ packs: missing.map((language) => {
186
+ const version = pinned.get(language.pack);
187
+ return version === undefined
188
+ ? language.pack
189
+ : `${language.pack}@${version}`;
190
+ }),
191
+ modified: missing
192
+ .filter((language) => modified.has(language.pack))
193
+ .map((language) => language.pack),
194
+ };
195
+ }
196
+ /** One line naming the languages and what to install or activate. */
197
+ export function describeReferenceLanguageSuggestion(suggestion) {
198
+ const found = suggestion.languages
199
+ .map((language) => `${language.files} ${language.name}`)
200
+ .join(", ");
201
+ const activation = suggestion.capabilities
202
+ .map((capability) => `"${capability}": { "mode": "augment" }`)
203
+ .join(", ");
204
+ const packs = suggestion.packs.length === 0
205
+ ? ""
206
+ : ` and the grammar pack(s) ${suggestion.packs.join(", ")}`;
207
+ if (suggestion.capabilities.length === 0)
208
+ return `${found} source file(s); ${suggestion.package} reads them only with${packs.slice(4)} installed: npm install --save-dev ${suggestion.packs.join(" ")}`;
209
+ if (suggestion.activeForSymbolsOnly)
210
+ return `${found} source file(s); ${suggestion.package} is active for symbols but not for source proofs: add ${activation} to its package.json kibi.plugins entry${packs === "" ? "" : `, and install${packs.slice(4)}`}`;
211
+ const what = suggestion.capabilities.includes(REFERENCE_EXTRACTOR_CAPABILITY_ID)
212
+ ? "source proofs and symbols"
213
+ : "symbols";
214
+ const entry = JSON.stringify({
215
+ package: suggestion.package,
216
+ capabilities: Object.fromEntries(suggestion.capabilities.map((capability) => [
217
+ capability,
218
+ { mode: "augment" },
219
+ ])),
220
+ });
221
+ const activate = `add this entry to package.json "kibi": { "plugins": [ ${entry} ] }`;
222
+ // An installed plugin only lacks its kibi.plugins entry.
223
+ const install = [
224
+ ...(suggestion.pluginInstalled ? [] : [suggestion.package]),
225
+ ...suggestion.packs,
226
+ ];
227
+ const needs = suggestion.pluginInstalled
228
+ ? `${suggestion.package}, which is installed but not activated${packs === "" ? "" : `,${packs}`}`
229
+ : `${suggestion.package}${packs}`;
230
+ return install.length === 0
231
+ ? `${found} source file(s); ${what} for them need ${needs}: ${activate}`
232
+ : `${found} source file(s); ${what} for them need ${needs}: npm install --save-dev ${install.join(" ")}, then ${activate}`;
233
+ }
234
+ function readManifestOrNull(workspaceRoot) {
235
+ try {
236
+ return JSON.parse(readFileSync(join(workspaceRoot, "package.json"), "utf8"));
237
+ }
238
+ catch {
239
+ return null;
240
+ }
241
+ }
242
+ /**
243
+ * The suggestion for a workspace, from its tracked files, as one line for
244
+ * `kibi init` and `kibi doctor`, or null when nothing is missing. A project
245
+ * without a package.json is told to create a minimal one first.
246
+ */
247
+ // implements REQ-kibi-tree-sitter-references, REQ-kibi-tree-sitter-language-packs
248
+ export function workspaceReferenceLanguageNote(workspaceRoot) {
249
+ let files;
250
+ let config;
251
+ try {
252
+ files = execFileSync("git", ["ls-files", "-z"], {
253
+ cwd: workspaceRoot,
254
+ encoding: "utf8",
255
+ stdio: ["ignore", "pipe", "ignore"],
256
+ maxBuffer: 64 * 1024 * 1024,
257
+ })
258
+ .split("\0")
259
+ .filter((file) => file.length > 0);
260
+ config = readProjectKibiConfig(workspaceRoot);
261
+ }
262
+ catch {
263
+ return null;
264
+ }
265
+ const suggestion = referenceLanguageSuggestion(files, config, workspaceInstalledVersion(workspaceRoot), pinnedPackVersions(workspaceRoot), modifiedPacks(workspaceRoot), manifestDeclares(readManifestOrNull(workspaceRoot), REFERENCE_PLUGIN_PACKAGE));
266
+ if (suggestion === null)
267
+ return null;
268
+ const noManifest = !existsSync(join(workspaceRoot, "package.json"));
269
+ const changed = suggestion.modified.length === 0
270
+ ? ""
271
+ : ` The installed grammar of ${suggestion.modified.join(", ")} does not match the SHA-256 ${suggestion.package} pins; reinstall it.`;
272
+ return `${describeReferenceLanguageSuggestion(suggestion)}.${changed}${noManifest
273
+ ? " This project has no package.json: run npm init -y first to create a minimal one (Kibi reads only its devDependencies and kibi.plugins), then run the install and add the kibi.plugins entry above, and add node_modules/ to .gitignore."
274
+ : ""} ${suggestion.capabilities.includes(REFERENCE_EXTRACTOR_CAPABILITY_ID)
275
+ ? "Without it, references proofs on those files are refused."
276
+ : "Until then, symbols in those files are placed by text match and are approximate."}`;
277
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/plugins/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/plugins/registry.ts"],"names":[],"mappings":"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"}
@@ -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 { CHECK_POLICY_CAPABILITY_ID, CHECK_POLICY_CONTRACT_VERSION, KIBI_PLUGIN_API_VERSION, ONTOLOGY_PACK_CAPABILITY_ID, SEARCH_HINTS_CAPABILITY_ID, SEMANTIC_CLASSIFIER_CAPABILITY_ID, SYMBOL_EXTRACTOR_CAPABILITY_ID, SYMBOL_EXTRACTOR_V2_CAPABILITY_ID, VOCABULARY_ALIGNMENT_CAPABILITY_ID, defineKibiPlugin, validateKibiPlugin, } from "kibi-plugin-sdk";
18
+ import { CHECK_POLICY_CAPABILITY_ID, CHECK_POLICY_CONTRACT_VERSION, KIBI_PLUGIN_API_VERSION, ONTOLOGY_PACK_CAPABILITY_ID, REFERENCE_EXTRACTOR_CAPABILITY_ID, SEARCH_HINTS_CAPABILITY_ID, SEMANTIC_CLASSIFIER_CAPABILITY_ID, SYMBOL_EXTRACTOR_CAPABILITY_ID, SYMBOL_EXTRACTOR_V2_CAPABILITY_ID, VOCABULARY_ALIGNMENT_CAPABILITY_ID, defineKibiPlugin, validateKibiPlugin, } from "kibi-plugin-sdk";
19
19
  import { loadPluginPackage } from "./load-plugin.js";
20
20
  import { readProjectKibiConfig } from "./project-config.js";
21
21
  import { PluginResolutionError } from "./resolve-package.js";
@@ -27,6 +27,8 @@ const CAPABILITY_SLOT = {
27
27
  [VOCABULARY_ALIGNMENT_CAPABILITY_ID]: "vocabularyAlignment",
28
28
  [CHECK_POLICY_CAPABILITY_ID]: "checkPolicy",
29
29
  [SEARCH_HINTS_CAPABILITY_ID]: "searchHints",
30
+ // Read only by source proofs, through the qualified loader.
31
+ [REFERENCE_EXTRACTOR_CAPABILITY_ID]: "referenceExtractor",
30
32
  };
31
33
  /**
32
34
  * Search hints have no builtin answer: without a configured provider there
@@ -1 +1 @@
1
- {"version":3,"file":"source-analysis-service.d.ts","sourceRoot":"","sources":["../../src/plugins/source-analysis-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"source-analysis-service.d.ts","sourceRoot":"","sources":["../../src/plugins/source-analysis-service.ts"],"names":[],"mappings":"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"}
@@ -159,6 +159,10 @@ export class SourceAnalysisService {
159
159
  async analyzeTextV2(filePath, content, explicitLanguageHint) {
160
160
  const request = createV2Request(filePath, content, explicitLanguageHint);
161
161
  const { classification } = request;
162
+ // Kibi's own knowledge-base files (its Prolog schema included) are not
163
+ // project source, so they never ask for a grammar pack.
164
+ if (/^(?:\.\/)?\.kb\//.test(filePath.replaceAll("\\", "/")))
165
+ return request.fallback("unsupported", "kibi_knowledge_base_file", "Kibi's own knowledge-base files are not analyzed as project source.");
162
166
  if (content.length > SOURCE_ANALYSIS_V2_MAX_INPUT_CODE_UNITS ||
163
167
  Buffer.byteLength(content, "utf8") > 8 * 1024 * 1024)
164
168
  return request.fallback("failed", "input_limit", `Source input exceeds the ${SOURCE_ANALYSIS_V2_MAX_INPUT_CODE_UNITS} UTF-16 code unit or 8 MiB UTF-8 analysis limit`);
@@ -10,6 +10,31 @@ export interface SourceChangeAnalysis {
10
10
  export declare function analyzeSourceChanges(inventory: readonly StagedPath[], service: SourceAnalysisService): Promise<Map<string, SourceChangeAnalysis>>;
11
11
  /** Adapt a host result to the shared analysis gate. */
12
12
  export declare function gateAnalysis(result: HostSourceAnalysisResultV2 | null): GateAnalysis<HostSourceAnalysisResultV2["uncoveredRanges"][number]> | null;
13
- /** Enforce the shared analysis gate when no impact policy accepts reviews. */
13
+ /** Staged lines of a partially analyzed file that need a file-level review. */
14
+ export interface PartialAnalysisReview {
15
+ path: string;
16
+ /** Staged lines inside the gaps and outside every placed declaration. */
17
+ lines: {
18
+ startLine: number;
19
+ endLine: number;
20
+ }[];
21
+ ranges: {
22
+ startLine: number;
23
+ endLine: number;
24
+ reason: string;
25
+ }[];
26
+ detail: string;
27
+ }
28
+ /**
29
+ * The after-side gaps a staged change touches outside every declaration the
30
+ * analyzer placed. A changed line inside a placed declaration is validated
31
+ * against that symbol instead.
32
+ */
33
+ export declare function partialAnalysisReviews(inventory: readonly StagedPath[], analyses: ReadonlyMap<string, SourceChangeAnalysis>): PartialAnalysisReview[];
34
+ /**
35
+ * Enforce the shared analysis gate when no impact policy accepts reviews:
36
+ * failed analysis and non-local gaps block; a local gap is left to
37
+ * {@link partialAnalysisReviews}.
38
+ */
14
39
  export declare function assertSourceAnalysisGate(inventory: readonly StagedPath[], analyses: ReadonlyMap<string, SourceChangeAnalysis>): void;
15
40
  //# sourceMappingURL=source-change-analysis.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-change-analysis.d.ts","sourceRoot":"","sources":["../../src/plugins/source-change-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EAElB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EACV,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,8BAA8B,CAAC;AAGtC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,0BAA0B,GAAG,IAAI,CAAC;CAC1C;AAKD,wFAAwF;AAExF,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAgC5C;AAED,uDAAuD;AAEvD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,0BAA0B,GAAG,IAAI,GACxC,YAAY,CAAC,0BAA0B,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAQ5E;AAED,8EAA8E;AAE9E,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAClD,IAAI,CAkBN"}
1
+ {"version":3,"file":"source-change-analysis.d.ts","sourceRoot":"","sources":["../../src/plugins/source-change-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EAElB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,OAAO,KAAK,EACV,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,8BAA8B,CAAC;AAGtC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,0BAA0B,GAAG,IAAI,CAAC;CAC1C;AAKD,wFAAwF;AAExF,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAgC5C;AAED,uDAAuD;AAEvD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,0BAA0B,GAAG,IAAI,GACxC,YAAY,CAAC,0BAA0B,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAQ5E;AAED,+EAA+E;AAE/E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChD,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AAEH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAClD,qBAAqB,EAAE,CA8DzB;AA4CD;;;;GAIG;AAEH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,UAAU,EAAE,EAChC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAClD,IAAI,CAeN"}
@@ -1,4 +1,5 @@
1
1
  import { analysisObligation, } from "../traceability/analysis-gate.js";
2
+ import { partialAnalysisSymbolsUsable } from "../traceability/symbol-extract.js";
2
3
  /** Files analyzed at once; pooled providers bound their own worker count. */
3
4
  const SOURCE_ANALYSIS_CONCURRENCY = 4;
4
5
  /** Analyze both versions without changing the complete inventory or assigning proof. */
@@ -37,18 +38,89 @@ export function gateAnalysis(result) {
37
38
  }
38
39
  : null;
39
40
  }
40
- /** Enforce the shared analysis gate when no impact policy accepts reviews. */
41
+ /**
42
+ * The after-side gaps a staged change touches outside every declaration the
43
+ * analyzer placed. A changed line inside a placed declaration is validated
44
+ * against that symbol instead.
45
+ */
46
+ // implements REQ-source-analysis-v2
47
+ export function partialAnalysisReviews(inventory, analyses) {
48
+ const reviews = [];
49
+ for (const file of inventory) {
50
+ const after = analyses.get(file.path)?.after ?? null;
51
+ const obligation = analysisObligation("after", gateAnalysis(after), file.hunkRanges);
52
+ if (obligation.kind !== "partial_review" || !after)
53
+ continue;
54
+ const placed = partialAnalysisSymbolsUsable(after) ? after.symbols : [];
55
+ const ranges = obligation.ranges.filter((range) => file.hunkRanges.some((hunk) => linesOutside(Math.max(range.startLine, hunk.start), Math.min(range.endLine, hunk.end), placed).length > 0));
56
+ if (ranges.length === 0)
57
+ continue;
58
+ const lines = mergeLineRanges(ranges.flatMap((range) => file.hunkRanges.flatMap((hunk) => linesOutside(Math.max(range.startLine, hunk.start), Math.min(range.endLine, hunk.end), placed))));
59
+ const detail = [
60
+ ...new Set(after.diagnostics
61
+ .filter((item) => item.range === undefined ||
62
+ ranges.some((range) => item.range !== undefined &&
63
+ item.range.startLine <= range.endLine &&
64
+ range.startLine <= item.range.endLine))
65
+ .map((item) => item.message)),
66
+ ].join(" ");
67
+ reviews.push({
68
+ path: file.path,
69
+ lines,
70
+ ranges: ranges.map((range) => ({
71
+ startLine: range.startLine,
72
+ endLine: range.endLine,
73
+ reason: range.reason,
74
+ })),
75
+ detail: detail || [...new Set(ranges.map((range) => range.reason))].join(", "),
76
+ });
77
+ }
78
+ return reviews;
79
+ }
80
+ /** The parts of the lines [start, end] that no span contains. */
81
+ function linesOutside(start, end, spans) {
82
+ const out = [];
83
+ let line = start;
84
+ while (line <= end) {
85
+ const cover = spans.find((span) => span.startLine <= line && line <= span.endLine);
86
+ if (cover) {
87
+ line = cover.endLine + 1;
88
+ continue;
89
+ }
90
+ const next = Math.min(end + 1, ...spans
91
+ .filter((span) => span.startLine > line)
92
+ .map((span) => span.startLine));
93
+ out.push({ startLine: line, endLine: next - 1 });
94
+ line = next;
95
+ }
96
+ return out;
97
+ }
98
+ function mergeLineRanges(ranges) {
99
+ const sorted = [...ranges].sort((a, b) => a.startLine - b.startLine);
100
+ const merged = [];
101
+ for (const range of sorted) {
102
+ const last = merged.at(-1);
103
+ if (last && range.startLine <= last.endLine + 1)
104
+ last.endLine = Math.max(last.endLine, range.endLine);
105
+ else
106
+ merged.push({ ...range });
107
+ }
108
+ return merged;
109
+ }
110
+ /**
111
+ * Enforce the shared analysis gate when no impact policy accepts reviews:
112
+ * failed analysis and non-local gaps block; a local gap is left to
113
+ * {@link partialAnalysisReviews}.
114
+ */
41
115
  // implements REQ-source-analysis-v2
42
116
  export function assertSourceAnalysisGate(inventory, analyses) {
43
117
  for (const file of inventory) {
44
118
  const analysis = analyses.get(file.path);
45
119
  const after = analysis?.after ?? null;
46
120
  const obligation = analysisObligation("after", gateAnalysis(after), file.hunkRanges);
47
- if (obligation.kind !== "blocked" && obligation.kind !== "partial_review")
121
+ if (obligation.kind !== "blocked")
48
122
  continue;
49
123
  const detail = after?.diagnostics.map((d) => d.message).join("; ") ?? "";
50
- throw new Error(obligation.kind === "blocked"
51
- ? `Source analysis ${after?.status} for ${file.path}: ${detail}`
52
- : `Source analysis partial for ${file.path} where the staged change touches uncovered lines (${obligation.ranges.map((range) => `${range.startLine}-${range.endLine}`).join(", ")}): ${detail}`);
124
+ throw new Error(`Source analysis ${after?.status} for ${file.path}: ${detail}`);
53
125
  }
54
126
  }
@@ -1 +1 @@
1
- {"version":3,"file":"source-classification.d.ts","sourceRoot":"","sources":["../../src/plugins/source-classification.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CAAC;IACP,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1D,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IACzD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAwGP;;;;GAIG;AAEH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,6EAA6E;AAE7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED,wEAAwE;AAExE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAM/D;AAED,+EAA+E;AAE/E,wBAAgB,oBAAoB,IAAI,SAAS,MAAM,EAAE,CAExD;AA2RD,qGAAqG;AACrG,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,oBAAoB,CAAC,EAAE,MAAM,GAC5B,oBAAoB,CAiKtB"}
1
+ {"version":3,"file":"source-classification.d.ts","sourceRoot":"","sources":["../../src/plugins/source-classification.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CAAC;IACP,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1D,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IACzD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAwGP;;;;GAIG;AAEH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,6EAA6E;AAE7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED,wEAAwE;AAExE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAM/D;AAED,+EAA+E;AAE/E,wBAAgB,oBAAoB,IAAI,SAAS,MAAM,EAAE,CAExD;AA8SD,qGAAqG;AACrG,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,oBAAoB,CAAC,EAAE,MAAM,GAC5B,oBAAoB,CAqKtB"}
@@ -360,6 +360,22 @@ function perlOrPrologByContent(content) {
360
360
  return undefined;
361
361
  return prolog ? "prolog" : "perl";
362
362
  }
363
+ // C++-only constructs; `extern "C"` guards and C23 attributes are not among them.
364
+ const CPP_ONLY = /^\s*(?:class|namespace|template\s*<|using\s+namespace)\b|^\s*(?:public|private|protected)\s*:|\b(?:virtual|constexpr|nullptr|operator\s*[^\w\s]|static_cast|dynamic_cast|reinterpret_cast|noexcept)\b|\bstd::|[A-Za-z_]\w*::[A-Za-z_~]/m;
365
+ /**
366
+ * Resolves a `.h` header without a shebang: C++ when its code uses a
367
+ * construct only C++ has, otherwise C (a C header also parses as C++, but
368
+ * the reverse does not hold, so C is the reading that stays exact).
369
+ */
370
+ // implements REQ-multilingual-language-catalog
371
+ function cOrCppByContent(content) {
372
+ const code = content
373
+ .slice(0, MAX_CONTENT_SNIFF_LENGTH)
374
+ .replace(/\/\*[\s\S]*?\*\//g, " ")
375
+ .replace(/\/\/[^\n]*/g, " ")
376
+ .replace(/"(?:[^"\\\n]|\\.)*"/g, '""');
377
+ return CPP_ONLY.test(code) ? "cpp" : "c";
378
+ }
363
379
  function classificationForLanguage(language, source) {
364
380
  if (FILE_LEVEL_LANGUAGES.has(language)) {
365
381
  return {
@@ -417,9 +433,13 @@ export function classifySource(filePath, content, explicitLanguageHint) {
417
433
  return classificationForLanguage(explicit, "explicit");
418
434
  }
419
435
  if (extension?.kind === "ambiguous") {
420
- const contentLanguage = shebang === undefined && extension.language === "perl-or-prolog"
421
- ? perlOrPrologByContent(content)
422
- : undefined;
436
+ const contentLanguage = shebang !== undefined
437
+ ? undefined
438
+ : extension.language === "perl-or-prolog"
439
+ ? perlOrPrologByContent(content)
440
+ : extension.language === "c-or-cpp"
441
+ ? cOrCppByContent(content)
442
+ : undefined;
423
443
  if (contentLanguage !== undefined)
424
444
  return classificationForLanguage(contentLanguage, "content");
425
445
  if (shebang === undefined) {