@opencodehub/cli 0.1.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 (191) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +85 -0
  3. package/dist/agent-context.d.ts +54 -0
  4. package/dist/agent-context.d.ts.map +1 -0
  5. package/dist/agent-context.js +122 -0
  6. package/dist/agent-context.js.map +1 -0
  7. package/dist/cobol-proleap-setup.d.ts +77 -0
  8. package/dist/cobol-proleap-setup.d.ts.map +1 -0
  9. package/dist/cobol-proleap-setup.js +289 -0
  10. package/dist/cobol-proleap-setup.js.map +1 -0
  11. package/dist/commands/analyze.d.ts +234 -0
  12. package/dist/commands/analyze.d.ts.map +1 -0
  13. package/dist/commands/analyze.js +1096 -0
  14. package/dist/commands/analyze.js.map +1 -0
  15. package/dist/commands/augment.d.ts +48 -0
  16. package/dist/commands/augment.d.ts.map +1 -0
  17. package/dist/commands/augment.js +249 -0
  18. package/dist/commands/augment.js.map +1 -0
  19. package/dist/commands/baseline.d.ts +68 -0
  20. package/dist/commands/baseline.d.ts.map +1 -0
  21. package/dist/commands/baseline.js +110 -0
  22. package/dist/commands/baseline.js.map +1 -0
  23. package/dist/commands/bench.d.ts +54 -0
  24. package/dist/commands/bench.d.ts.map +1 -0
  25. package/dist/commands/bench.js +283 -0
  26. package/dist/commands/bench.js.map +1 -0
  27. package/dist/commands/ci-init.d.ts +37 -0
  28. package/dist/commands/ci-init.d.ts.map +1 -0
  29. package/dist/commands/ci-init.js +115 -0
  30. package/dist/commands/ci-init.js.map +1 -0
  31. package/dist/commands/clean.d.ts +13 -0
  32. package/dist/commands/clean.d.ts.map +1 -0
  33. package/dist/commands/clean.js +38 -0
  34. package/dist/commands/clean.js.map +1 -0
  35. package/dist/commands/code-pack.d.ts +105 -0
  36. package/dist/commands/code-pack.d.ts.map +1 -0
  37. package/dist/commands/code-pack.js +187 -0
  38. package/dist/commands/code-pack.js.map +1 -0
  39. package/dist/commands/context.d.ts +30 -0
  40. package/dist/commands/context.d.ts.map +1 -0
  41. package/dist/commands/context.js +237 -0
  42. package/dist/commands/context.js.map +1 -0
  43. package/dist/commands/detect-changes.d.ts +26 -0
  44. package/dist/commands/detect-changes.d.ts.map +1 -0
  45. package/dist/commands/detect-changes.js +73 -0
  46. package/dist/commands/detect-changes.js.map +1 -0
  47. package/dist/commands/doctor.d.ts +52 -0
  48. package/dist/commands/doctor.d.ts.map +1 -0
  49. package/dist/commands/doctor.js +472 -0
  50. package/dist/commands/doctor.js.map +1 -0
  51. package/dist/commands/find-enclosing-symbol.d.ts +67 -0
  52. package/dist/commands/find-enclosing-symbol.d.ts.map +1 -0
  53. package/dist/commands/find-enclosing-symbol.js +106 -0
  54. package/dist/commands/find-enclosing-symbol.js.map +1 -0
  55. package/dist/commands/group.d.ts +123 -0
  56. package/dist/commands/group.d.ts.map +1 -0
  57. package/dist/commands/group.js +448 -0
  58. package/dist/commands/group.js.map +1 -0
  59. package/dist/commands/impact.d.ts +23 -0
  60. package/dist/commands/impact.d.ts.map +1 -0
  61. package/dist/commands/impact.js +91 -0
  62. package/dist/commands/impact.js.map +1 -0
  63. package/dist/commands/index-repo.d.ts +39 -0
  64. package/dist/commands/index-repo.d.ts.map +1 -0
  65. package/dist/commands/index-repo.js +148 -0
  66. package/dist/commands/index-repo.js.map +1 -0
  67. package/dist/commands/ingest-sarif.d.ts +64 -0
  68. package/dist/commands/ingest-sarif.d.ts.map +1 -0
  69. package/dist/commands/ingest-sarif.js +381 -0
  70. package/dist/commands/ingest-sarif.js.map +1 -0
  71. package/dist/commands/init.d.ts +75 -0
  72. package/dist/commands/init.d.ts.map +1 -0
  73. package/dist/commands/init.js +315 -0
  74. package/dist/commands/init.js.map +1 -0
  75. package/dist/commands/list.d.ts +17 -0
  76. package/dist/commands/list.d.ts.map +1 -0
  77. package/dist/commands/list.js +79 -0
  78. package/dist/commands/list.js.map +1 -0
  79. package/dist/commands/mcp.d.ts +8 -0
  80. package/dist/commands/mcp.d.ts.map +1 -0
  81. package/dist/commands/mcp.js +28 -0
  82. package/dist/commands/mcp.js.map +1 -0
  83. package/dist/commands/open-store.d.ts +25 -0
  84. package/dist/commands/open-store.d.ts.map +1 -0
  85. package/dist/commands/open-store.js +47 -0
  86. package/dist/commands/open-store.js.map +1 -0
  87. package/dist/commands/pack.d.ts +35 -0
  88. package/dist/commands/pack.d.ts.map +1 -0
  89. package/dist/commands/pack.js +83 -0
  90. package/dist/commands/pack.js.map +1 -0
  91. package/dist/commands/query.d.ts +85 -0
  92. package/dist/commands/query.d.ts.map +1 -0
  93. package/dist/commands/query.js +309 -0
  94. package/dist/commands/query.js.map +1 -0
  95. package/dist/commands/scan.d.ts +81 -0
  96. package/dist/commands/scan.d.ts.map +1 -0
  97. package/dist/commands/scan.js +407 -0
  98. package/dist/commands/scan.js.map +1 -0
  99. package/dist/commands/setup.d.ts +178 -0
  100. package/dist/commands/setup.d.ts.map +1 -0
  101. package/dist/commands/setup.js +370 -0
  102. package/dist/commands/setup.js.map +1 -0
  103. package/dist/commands/sql.d.ts +19 -0
  104. package/dist/commands/sql.d.ts.map +1 -0
  105. package/dist/commands/sql.js +51 -0
  106. package/dist/commands/sql.js.map +1 -0
  107. package/dist/commands/status.d.ts +13 -0
  108. package/dist/commands/status.d.ts.map +1 -0
  109. package/dist/commands/status.js +66 -0
  110. package/dist/commands/status.js.map +1 -0
  111. package/dist/commands/verdict-render.d.ts +33 -0
  112. package/dist/commands/verdict-render.d.ts.map +1 -0
  113. package/dist/commands/verdict-render.js +123 -0
  114. package/dist/commands/verdict-render.js.map +1 -0
  115. package/dist/commands/verdict.d.ts +61 -0
  116. package/dist/commands/verdict.d.ts.map +1 -0
  117. package/dist/commands/verdict.js +146 -0
  118. package/dist/commands/verdict.js.map +1 -0
  119. package/dist/commands/wiki.d.ts +26 -0
  120. package/dist/commands/wiki.d.ts.map +1 -0
  121. package/dist/commands/wiki.js +74 -0
  122. package/dist/commands/wiki.js.map +1 -0
  123. package/dist/editors/claude-code.d.ts +23 -0
  124. package/dist/editors/claude-code.d.ts.map +1 -0
  125. package/dist/editors/claude-code.js +58 -0
  126. package/dist/editors/claude-code.js.map +1 -0
  127. package/dist/editors/codex.d.ts +22 -0
  128. package/dist/editors/codex.d.ts.map +1 -0
  129. package/dist/editors/codex.js +59 -0
  130. package/dist/editors/codex.js.map +1 -0
  131. package/dist/editors/cursor.d.ts +13 -0
  132. package/dist/editors/cursor.d.ts.map +1 -0
  133. package/dist/editors/cursor.js +21 -0
  134. package/dist/editors/cursor.js.map +1 -0
  135. package/dist/editors/index.d.ts +12 -0
  136. package/dist/editors/index.d.ts.map +1 -0
  137. package/dist/editors/index.js +11 -0
  138. package/dist/editors/index.js.map +1 -0
  139. package/dist/editors/opencode.d.ts +23 -0
  140. package/dist/editors/opencode.d.ts.map +1 -0
  141. package/dist/editors/opencode.js +61 -0
  142. package/dist/editors/opencode.js.map +1 -0
  143. package/dist/editors/types.d.ts +33 -0
  144. package/dist/editors/types.d.ts.map +1 -0
  145. package/dist/editors/types.js +19 -0
  146. package/dist/editors/types.js.map +1 -0
  147. package/dist/editors/windows-wrap.d.ts +19 -0
  148. package/dist/editors/windows-wrap.d.ts.map +1 -0
  149. package/dist/editors/windows-wrap.js +28 -0
  150. package/dist/editors/windows-wrap.js.map +1 -0
  151. package/dist/editors/windsurf.d.ts +12 -0
  152. package/dist/editors/windsurf.d.ts.map +1 -0
  153. package/dist/editors/windsurf.js +21 -0
  154. package/dist/editors/windsurf.js.map +1 -0
  155. package/dist/embedder-downloader.d.ts +87 -0
  156. package/dist/embedder-downloader.d.ts.map +1 -0
  157. package/dist/embedder-downloader.js +261 -0
  158. package/dist/embedder-downloader.js.map +1 -0
  159. package/dist/fs-atomic.d.ts +22 -0
  160. package/dist/fs-atomic.d.ts.map +1 -0
  161. package/dist/fs-atomic.js +28 -0
  162. package/dist/fs-atomic.js.map +1 -0
  163. package/dist/groups.d.ts +64 -0
  164. package/dist/groups.d.ts.map +1 -0
  165. package/dist/groups.js +172 -0
  166. package/dist/groups.js.map +1 -0
  167. package/dist/index.d.ts +11 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +703 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/lib/is-indexed.d.ts +20 -0
  172. package/dist/lib/is-indexed.d.ts.map +1 -0
  173. package/dist/lib/is-indexed.js +35 -0
  174. package/dist/lib/is-indexed.js.map +1 -0
  175. package/dist/registry.d.ts +64 -0
  176. package/dist/registry.d.ts.map +1 -0
  177. package/dist/registry.js +145 -0
  178. package/dist/registry.js.map +1 -0
  179. package/dist/scip-downloader.d.ts +138 -0
  180. package/dist/scip-downloader.d.ts.map +1 -0
  181. package/dist/scip-downloader.js +372 -0
  182. package/dist/scip-downloader.js.map +1 -0
  183. package/dist/scip-pins.d.ts +99 -0
  184. package/dist/scip-pins.d.ts.map +1 -0
  185. package/dist/scip-pins.js +195 -0
  186. package/dist/scip-pins.js.map +1 -0
  187. package/dist/skills-gen.d.ts +47 -0
  188. package/dist/skills-gen.d.ts.map +1 -0
  189. package/dist/skills-gen.js +292 -0
  190. package/dist/skills-gen.js.map +1 -0
  191. package/package.json +81 -0
@@ -0,0 +1,381 @@
1
+ /**
2
+ * `codehub ingest-sarif <sarif-file>` — import a SARIF v2.1.0 log into
3
+ * the code graph as `Finding` nodes + `FOUND_IN` edges.
4
+ *
5
+ * Flow:
6
+ * 1. Read + parse + validate the SARIF file via `@opencodehub/sarif`.
7
+ * 2. Resolve the target repo (either `--repo <name>` or CWD).
8
+ * 3. Open the DuckDB store and pull a per-file, line-sorted symbol
9
+ * index over the SARIF's referenced URIs (used to resolve Finding
10
+ * → Symbol edges).
11
+ * 4. For every Result across every Run, build a Finding node keyed by
12
+ * `Finding:<scannerId>:<ruleId>:<uri>:<startLine>`. Emit FOUND_IN
13
+ * edges to the target File node (matched by `artifactLocation.uri`
14
+ * against `file_path`) plus a second FOUND_IN edge to the tightest
15
+ * enclosing symbol at `(uri, startLine)` when the graph contains
16
+ * one. A scanner-provided `opencodehub.symbolId` hint wins over the
17
+ * enclosing lookup when set.
18
+ * 5. UPSERT into DuckDB via `store.bulkLoad({ mode: "upsert" })`.
19
+ *
20
+ * The command is idempotent — re-running with the same SARIF produces
21
+ * the same nodes and edges. Results without a parsable location (no
22
+ * physicalLocation.artifactLocation.uri) are skipped with a warning.
23
+ */
24
+ import { readFile } from "node:fs/promises";
25
+ import { resolve } from "node:path";
26
+ import { KnowledgeGraph, makeNodeId } from "@opencodehub/core-types";
27
+ import { applyBaselineState, enrichWithFingerprints, SarifLogSchema, } from "@opencodehub/sarif";
28
+ import { openStore, resolveDbPath, resolveRepoMetaDir, } from "@opencodehub/storage";
29
+ import { readRegistry } from "../registry.js";
30
+ import { ENCLOSING_SYMBOL_KINDS, findEnclosingSymbolId, indexNodesByFile, } from "./find-enclosing-symbol.js";
31
+ export async function runIngestSarif(sarifFile, opts = {}) {
32
+ const sarifPath = resolve(sarifFile);
33
+ const raw = await readFile(sarifPath, "utf8");
34
+ const parsed = JSON.parse(raw);
35
+ const validation = SarifLogSchema.safeParse(parsed);
36
+ if (!validation.success) {
37
+ throw new Error(`codehub ingest-sarif: ${sarifPath} is not a valid SARIF 2.1.0 log: ${validation.error.message}`);
38
+ }
39
+ let log = validation.data;
40
+ const repoPath = await resolveRepoPath(opts);
41
+ // Stamp `opencodehub/v1` + `primaryLocationLineHash` partial fingerprints
42
+ // onto every result. The call is idempotent: an already-enriched input
43
+ // produces the same fingerprints, so re-ingesting a SARIF file leaves the
44
+ // column stable.
45
+ log = enrichWithFingerprints(log);
46
+ // Optional baseline overlay. When `<repo>/.codehub/baseline.sarif` exists
47
+ // we tag every result with SARIF 2.1.0 `baselineState` so the
48
+ // `baseline_state` column is populated; missing baseline leaves it NULL
49
+ // (consumers treat NULL as "new" by convention).
50
+ const baselineLog = await loadRepoBaseline(repoPath);
51
+ if (baselineLog !== undefined) {
52
+ log = applyBaselineState(log, baselineLog);
53
+ }
54
+ const dbPath = resolveDbPath(repoPath);
55
+ const composed = await openStore({ path: dbPath, backend: "auto" });
56
+ let graph;
57
+ let summary;
58
+ try {
59
+ await composed.graph.open();
60
+ await composed.graph.createSchema();
61
+ // Pull the per-file symbol index out of the store once so every
62
+ // SARIF result can resolve its enclosing symbol without a round
63
+ // trip. Restricts to URIs that actually appear in the SARIF log
64
+ // and to the code-kind allow set shared with `buildFindingsGraph`.
65
+ const nodesByFile = await loadNodesByFileForSarif(composed.graph, log.runs);
66
+ ({ graph, summary } = buildFindingsGraph(log.runs, nodesByFile));
67
+ await composed.graph.bulkLoad(graph, { mode: "upsert" });
68
+ }
69
+ finally {
70
+ await composed.close();
71
+ }
72
+ const out = {
73
+ sarifFile: sarifPath,
74
+ repoPath,
75
+ findingsEmitted: summary.findingsEmitted,
76
+ edgesEmitted: summary.edgesEmitted,
77
+ resultsSkipped: summary.resultsSkipped,
78
+ warnings: summary.warnings,
79
+ };
80
+ for (const w of summary.warnings) {
81
+ console.warn(`codehub ingest-sarif: ${w}`);
82
+ }
83
+ console.warn(`codehub ingest-sarif: ${out.findingsEmitted} findings, ${out.edgesEmitted} edges from ${sarifPath} → ${repoPath}`);
84
+ return out;
85
+ }
86
+ /**
87
+ * Pure builder over SARIF runs. Exposed for unit tests so we can exercise
88
+ * the node/edge emission logic without touching DuckDB.
89
+ *
90
+ * `nodesByFile` is the per-file, line-sorted symbol index (produced by
91
+ * {@link indexNodesByFile}) used to resolve each SARIF result back to the
92
+ * tightest-enclosing code symbol when the scanner did not populate
93
+ * `result.properties["opencodehub.symbolId"]` itself. Callers that only
94
+ * want the File-level edge (e.g. unit tests) can omit it — an empty map
95
+ * means every symbol lookup misses and only the File edge is emitted.
96
+ */
97
+ export function buildFindingsGraph(runs, nodesByFile = new Map()) {
98
+ const graph = new KnowledgeGraph();
99
+ const warnings = [];
100
+ let findingsEmitted = 0;
101
+ let edgesEmitted = 0;
102
+ let resultsSkipped = 0;
103
+ for (const run of runs) {
104
+ const scannerId = run.tool.driver.name;
105
+ const results = run.results ?? [];
106
+ for (const result of results) {
107
+ const finding = buildFindingNode(scannerId, result);
108
+ if (!finding) {
109
+ resultsSkipped += 1;
110
+ continue;
111
+ }
112
+ graph.addNode(finding.node);
113
+ findingsEmitted += 1;
114
+ // FOUND_IN edge Finding → File (matched by URI). We always emit
115
+ // this edge — if the target File node does not exist in the graph
116
+ // (ingest-sarif runs independently of analyze), the relation is
117
+ // still recorded; downstream queries can left-join.
118
+ const fileId = makeNodeId("File", finding.uri, finding.uri);
119
+ graph.addEdge({
120
+ from: finding.node.id,
121
+ to: fileId,
122
+ type: "FOUND_IN",
123
+ confidence: 1,
124
+ reason: finding.reason,
125
+ });
126
+ edgesEmitted += 1;
127
+ // Resolve the Finding → Symbol edge. Priority order:
128
+ // 1. `opencodehub.symbolId` in the result properties bag — the
129
+ // explicit scanner-provided hint wins (e.g. semgrep rules that
130
+ // resolve to a specific function already).
131
+ // 2. Tightest-enclosing symbol at (uri, startLine) from the graph
132
+ // index. This is the common path for third-party SARIF tools
133
+ // that emit raw file+line locations.
134
+ // If neither resolves we keep the File-only edge.
135
+ const hintedSymbolId = extractSymbolId(result);
136
+ const symbolId = hintedSymbolId !== undefined
137
+ ? hintedSymbolId
138
+ : findEnclosingSymbolId(nodesByFile, finding.uri, finding.node.startLine ?? 1);
139
+ if (symbolId !== undefined) {
140
+ graph.addEdge({
141
+ from: finding.node.id,
142
+ to: symbolId,
143
+ type: "FOUND_IN",
144
+ confidence: 1,
145
+ reason: finding.reason,
146
+ step: 1,
147
+ });
148
+ edgesEmitted += 1;
149
+ }
150
+ }
151
+ }
152
+ return {
153
+ graph,
154
+ summary: { findingsEmitted, edgesEmitted, resultsSkipped, warnings },
155
+ };
156
+ }
157
+ /**
158
+ * Convert a single SARIF Result into a FindingNode. Returns `undefined`
159
+ * when the result is missing a location we can key on — we need
160
+ * (ruleId, uri, startLine) to produce a stable id.
161
+ */
162
+ function buildFindingNode(scannerId, result) {
163
+ const ruleId = result.ruleId;
164
+ if (typeof ruleId !== "string" || ruleId.length === 0)
165
+ return undefined;
166
+ const loc = result.locations?.[0]?.physicalLocation;
167
+ const uri = loc?.artifactLocation?.uri;
168
+ if (typeof uri !== "string" || uri.length === 0)
169
+ return undefined;
170
+ const region = loc?.region;
171
+ const startLine = region?.startLine ?? 1;
172
+ const endLine = region?.endLine;
173
+ // Severity: map SARIF level → Finding.severity. Default "note" when
174
+ // the scanner omits `level` (GHAS treats missing level as "warning",
175
+ // but we stay conservative).
176
+ const severity = mapSeverity(result.level);
177
+ const message = result.message?.text ?? "";
178
+ const id = makeNodeId("Finding", uri, `${scannerId}:${ruleId}:${startLine}`);
179
+ const propertiesBag = {};
180
+ if (result.properties) {
181
+ for (const [k, v] of Object.entries(result.properties)) {
182
+ propertiesBag[k] = v;
183
+ }
184
+ }
185
+ const suppressedJson = extractSuppressedJson(result);
186
+ const partialFingerprint = extractOpenCodeHubFingerprint(result);
187
+ const baselineState = extractBaselineState(result);
188
+ const node = {
189
+ id,
190
+ kind: "Finding",
191
+ name: `${scannerId}:${ruleId}`,
192
+ filePath: uri,
193
+ ruleId,
194
+ severity,
195
+ scannerId,
196
+ message,
197
+ propertiesBag,
198
+ startLine,
199
+ ...(endLine !== undefined ? { endLine } : {}),
200
+ ...(suppressedJson !== undefined ? { suppressedJson } : {}),
201
+ ...(partialFingerprint !== undefined ? { partialFingerprint } : {}),
202
+ ...(baselineState !== undefined ? { baselineState } : {}),
203
+ };
204
+ const reason = endLine !== undefined ? `startLine=${startLine};endLine=${endLine}` : `startLine=${startLine}`;
205
+ return { node, uri, reason };
206
+ }
207
+ function mapSeverity(level) {
208
+ switch (level) {
209
+ case "error":
210
+ case "warning":
211
+ case "note":
212
+ case "none":
213
+ return level;
214
+ default:
215
+ return "note";
216
+ }
217
+ }
218
+ /**
219
+ * Persist SARIF `suppressions[]` into the FindingNode's `suppressedJson`
220
+ * column. We keep every entry (external + inSource) so
221
+ * downstream consumers can distinguish waiver provenance; missing or
222
+ * empty arrays resolve to undefined so the column stays null and verdict
223
+ * treats the finding as un-suppressed.
224
+ */
225
+ function extractSuppressedJson(result) {
226
+ const arr = result.suppressions;
227
+ if (!Array.isArray(arr) || arr.length === 0)
228
+ return undefined;
229
+ const entries = [];
230
+ for (const entry of arr) {
231
+ if (entry === null || typeof entry !== "object")
232
+ continue;
233
+ const record = entry;
234
+ const kind = record["kind"];
235
+ const justification = record["justification"];
236
+ if (typeof kind !== "string" || typeof justification !== "string")
237
+ continue;
238
+ const expiresAt = record["expiresAt"];
239
+ const out = {
240
+ kind,
241
+ justification,
242
+ };
243
+ if (typeof expiresAt === "string" && expiresAt.length > 0)
244
+ out.expiresAt = expiresAt;
245
+ entries.push(out);
246
+ }
247
+ return entries.length > 0 ? JSON.stringify(entries) : undefined;
248
+ }
249
+ function extractSymbolId(result) {
250
+ const props = result.properties;
251
+ if (!props || typeof props !== "object")
252
+ return undefined;
253
+ const record = props;
254
+ // Primary key scanners put inside their result properties bag.
255
+ const v = record["opencodehub.symbolId"];
256
+ if (typeof v === "string" && v.length > 0)
257
+ return v;
258
+ return undefined;
259
+ }
260
+ /**
261
+ * Pull the `opencodehub/v1` entry out of `result.partialFingerprints` and
262
+ * persist it on the FindingNode. Enrichment runs before ingest so this
263
+ * lookup always succeeds for well-formed inputs — if it doesn't, the
264
+ * column stays NULL (e.g. SARIF files that predate enrichment).
265
+ */
266
+ function extractOpenCodeHubFingerprint(result) {
267
+ const pf = result.partialFingerprints;
268
+ if (pf === null || pf === undefined || typeof pf !== "object")
269
+ return undefined;
270
+ const v = pf["opencodehub/v1"];
271
+ return typeof v === "string" && v.length > 0 ? v : undefined;
272
+ }
273
+ /**
274
+ * Read `result.baselineState` as a typed literal. `applyBaselineState`
275
+ * only writes `"new" | "unchanged" | "updated"` (baseline-only findings
276
+ * stay outside the current log); `"absent"` can arrive via third-party
277
+ * tooling so we accept it for completeness.
278
+ */
279
+ function extractBaselineState(result) {
280
+ const v = result.baselineState;
281
+ if (v === "new" || v === "unchanged" || v === "updated" || v === "absent") {
282
+ return v;
283
+ }
284
+ return undefined;
285
+ }
286
+ /**
287
+ * Load `<repo>/.codehub/baseline.sarif` if present. Missing file resolves
288
+ * to undefined; malformed file raises so the caller can surface the
289
+ * validation error instead of silently dropping baselineState.
290
+ */
291
+ async function loadRepoBaseline(repoPath) {
292
+ const candidate = resolve(`${resolveRepoMetaDir(repoPath)}/baseline.sarif`);
293
+ let raw;
294
+ try {
295
+ raw = await readFile(candidate, "utf8");
296
+ }
297
+ catch (err) {
298
+ if (err.code === "ENOENT")
299
+ return undefined;
300
+ throw err;
301
+ }
302
+ const parsed = JSON.parse(raw);
303
+ const result = SarifLogSchema.safeParse(parsed);
304
+ if (!result.success) {
305
+ throw new Error(`codehub ingest-sarif: baseline at ${candidate} is not a valid SARIF 2.1.0 log: ${result.error.message}`);
306
+ }
307
+ return result.data;
308
+ }
309
+ /**
310
+ * Collect every distinct `artifactLocation.uri` across every Result in
311
+ * every Run. Results without a parsable URI (or with an empty one) are
312
+ * silently skipped — downstream emission logic already discards them.
313
+ */
314
+ function collectSarifUris(runs) {
315
+ const seen = new Set();
316
+ for (const run of runs) {
317
+ for (const result of run.results ?? []) {
318
+ const uri = result.locations?.[0]?.physicalLocation?.artifactLocation?.uri;
319
+ if (typeof uri === "string" && uri.length > 0)
320
+ seen.add(uri);
321
+ }
322
+ }
323
+ return [...seen];
324
+ }
325
+ /**
326
+ * Query the graph store for every code-kind node whose `file_path`
327
+ * matches a URI that appears in the SARIF log, then build the per-file,
328
+ * line-sorted symbol index used by {@link findEnclosingSymbolId}.
329
+ *
330
+ * Scoping by the SARIF URIs keeps the query bounded even on large
331
+ * repos: a SARIF log typically references a few hundred files, not the
332
+ * whole codebase. Empty URI list short-circuits to an empty index — the
333
+ * caller will emit only File-level edges, which matches the v0 behavior
334
+ * before symbol-level linkage existed.
335
+ */
336
+ async function loadNodesByFileForSarif(graph, runs) {
337
+ const uris = collectSarifUris(runs);
338
+ if (uris.length === 0)
339
+ return new Map();
340
+ // Fan one round-trip per code kind in the allow-set, narrowed by
341
+ // `filePath` set. `listNodesByKind` returns the typed node shape
342
+ // (`NodeOfKind<K>`) — the row projection only needs id / filePath /
343
+ // startLine / endLine / kind, all of which are present on every
344
+ // ENCLOSING_SYMBOL_KINDS member (LocatedNode subset).
345
+ const uriSet = new Set(uris);
346
+ const projected = [];
347
+ for (const kind of ENCLOSING_SYMBOL_KINDS) {
348
+ const nodes = await graph.listNodesByKind(kind);
349
+ for (const n of nodes) {
350
+ if (!uriSet.has(n.filePath))
351
+ continue;
352
+ const startLine = n.startLine;
353
+ const endLine = n.endLine;
354
+ if (typeof startLine !== "number" || !Number.isFinite(startLine))
355
+ continue;
356
+ if (typeof endLine !== "number" || !Number.isFinite(endLine))
357
+ continue;
358
+ projected.push({
359
+ id: n.id,
360
+ filePath: n.filePath,
361
+ startLine,
362
+ endLine,
363
+ kind: n.kind,
364
+ });
365
+ }
366
+ }
367
+ return indexNodesByFile(projected);
368
+ }
369
+ async function resolveRepoPath(opts) {
370
+ if (opts.repo !== undefined) {
371
+ const registryOpts = opts.home !== undefined ? { home: opts.home } : {};
372
+ const registry = await readRegistry(registryOpts);
373
+ const hit = registry[opts.repo];
374
+ if (hit)
375
+ return resolve(hit.path);
376
+ // Treat as raw path fallback for ergonomics (same convention as query CLI).
377
+ return resolve(opts.repo);
378
+ }
379
+ return resolve(process.cwd());
380
+ }
381
+ //# sourceMappingURL=ingest-sarif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest-sarif.js","sourceRoot":"","sources":["../../src/commands/ingest-sarif.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * `codehub init` — bootstrap a repository for OpenCodeHub in one command.
3
+ *
4
+ * Project-scope installer. Copies plugin assets (skills/agents/commands/hooks)
5
+ * into `<repo>/.claude/`, writes `.mcp.json` so Claude Code launches the
6
+ * `codehub` MCP server, appends `.codehub/` to `.gitignore`, and seeds a
7
+ * starter `opencodehub.policy.yaml` (commented out; rules ship in spec 002).
8
+ *
9
+ * Why project scope:
10
+ * - Checking `.claude/` into git means every teammate's Claude Code
11
+ * auto-discovers the plugin on clone. No per-machine install.
12
+ * - Keeps the plugin pinned to the repo's graph schema; upgrades are
13
+ * explicit (`codehub init --upgrade`) rather than ambient.
14
+ *
15
+ * Hook rewrite note:
16
+ * The plugin's `hooks.json` uses `${CLAUDE_PLUGIN_ROOT}` which is only
17
+ * bound for user-scope plugins. Project-scope hooks must use
18
+ * `${CLAUDE_PROJECT_DIR}/.claude` for Claude Code to find the shell
19
+ * scripts. We rewrite the token at install time and write the result
20
+ * to `.claude/settings.json` (the project-scope equivalent of
21
+ * `hooks.json`).
22
+ *
23
+ * Idempotence: re-running with identical args produces byte-identical
24
+ * output. Re-running against an existing `.claude/` refuses unless
25
+ * `--force` is set, and the error lists every conflicting file.
26
+ *
27
+ * Filesystem access goes through the same `FsApi` seam used by
28
+ * `commands/setup.ts` so tests run against an in-memory implementation.
29
+ */
30
+ import { type FsApi, type SetupResult } from "./setup.js";
31
+ export interface InitOptions {
32
+ /** Target repo. Defaults to `process.cwd()`. */
33
+ readonly repo?: string;
34
+ /** Plugin source dir. Defaults to the bundled `dist/plugin-assets/`. */
35
+ readonly sourceDir?: string;
36
+ /**
37
+ * Overwrite `.claude/` on re-run. Without `--force`, conflicting files cause
38
+ * a refusal listing each one.
39
+ */
40
+ readonly force?: boolean;
41
+ /**
42
+ * Skip the `.mcp.json` edit. Useful for teams that manage MCP config
43
+ * elsewhere (e.g., via Claude Code user-scope config).
44
+ */
45
+ readonly skipMcp?: boolean;
46
+ /**
47
+ * Skip seeding `opencodehub.policy.yaml`. The starter file is commented out
48
+ * and purely informational; some repos may prefer to author their own.
49
+ */
50
+ readonly skipPolicy?: boolean;
51
+ /** FS seam. Defaults to real filesystem. */
52
+ readonly fs?: FsApi;
53
+ /** Structured logger. Defaults to `console.warn`. */
54
+ readonly log?: (message: string) => void;
55
+ readonly warn?: (message: string) => void;
56
+ /** Override home dir (forwarded to `runSetup` for claude-code MCP write). */
57
+ readonly home?: string;
58
+ }
59
+ export interface InitResult {
60
+ readonly repoRoot: string;
61
+ readonly sourceDir: string;
62
+ readonly claudeDir: string;
63
+ readonly filesCopied: number;
64
+ readonly hooksWrittenTo: string | null;
65
+ readonly mcpResult: SetupResult | null;
66
+ readonly gitignoreUpdated: boolean;
67
+ readonly policySeeded: boolean;
68
+ }
69
+ /**
70
+ * Entry point for `codehub init`. Returns a structured result; throws on
71
+ * unrecoverable error (e.g., plugin source missing, conflicts without
72
+ * `--force`).
73
+ */
74
+ export declare function runInit(opts?: InitOptions): Promise<InitResult>;
75
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAgBH,OAAO,EAAE,KAAK,KAAK,EAA+B,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AA0CvF,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;IACpB,qDAAqD;IACrD,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA6EzE"}