@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.
- package/LICENSE +202 -0
- package/README.md +85 -0
- package/dist/agent-context.d.ts +54 -0
- package/dist/agent-context.d.ts.map +1 -0
- package/dist/agent-context.js +122 -0
- package/dist/agent-context.js.map +1 -0
- package/dist/cobol-proleap-setup.d.ts +77 -0
- package/dist/cobol-proleap-setup.d.ts.map +1 -0
- package/dist/cobol-proleap-setup.js +289 -0
- package/dist/cobol-proleap-setup.js.map +1 -0
- package/dist/commands/analyze.d.ts +234 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +1096 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/augment.d.ts +48 -0
- package/dist/commands/augment.d.ts.map +1 -0
- package/dist/commands/augment.js +249 -0
- package/dist/commands/augment.js.map +1 -0
- package/dist/commands/baseline.d.ts +68 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +110 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/bench.d.ts +54 -0
- package/dist/commands/bench.d.ts.map +1 -0
- package/dist/commands/bench.js +283 -0
- package/dist/commands/bench.js.map +1 -0
- package/dist/commands/ci-init.d.ts +37 -0
- package/dist/commands/ci-init.d.ts.map +1 -0
- package/dist/commands/ci-init.js +115 -0
- package/dist/commands/ci-init.js.map +1 -0
- package/dist/commands/clean.d.ts +13 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +38 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/code-pack.d.ts +105 -0
- package/dist/commands/code-pack.d.ts.map +1 -0
- package/dist/commands/code-pack.js +187 -0
- package/dist/commands/code-pack.js.map +1 -0
- package/dist/commands/context.d.ts +30 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +237 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/detect-changes.d.ts +26 -0
- package/dist/commands/detect-changes.d.ts.map +1 -0
- package/dist/commands/detect-changes.js +73 -0
- package/dist/commands/detect-changes.js.map +1 -0
- package/dist/commands/doctor.d.ts +52 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +472 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/find-enclosing-symbol.d.ts +67 -0
- package/dist/commands/find-enclosing-symbol.d.ts.map +1 -0
- package/dist/commands/find-enclosing-symbol.js +106 -0
- package/dist/commands/find-enclosing-symbol.js.map +1 -0
- package/dist/commands/group.d.ts +123 -0
- package/dist/commands/group.d.ts.map +1 -0
- package/dist/commands/group.js +448 -0
- package/dist/commands/group.js.map +1 -0
- package/dist/commands/impact.d.ts +23 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +91 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/index-repo.d.ts +39 -0
- package/dist/commands/index-repo.d.ts.map +1 -0
- package/dist/commands/index-repo.js +148 -0
- package/dist/commands/index-repo.js.map +1 -0
- package/dist/commands/ingest-sarif.d.ts +64 -0
- package/dist/commands/ingest-sarif.d.ts.map +1 -0
- package/dist/commands/ingest-sarif.js +381 -0
- package/dist/commands/ingest-sarif.js.map +1 -0
- package/dist/commands/init.d.ts +75 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +315 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +17 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +79 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +28 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/open-store.d.ts +25 -0
- package/dist/commands/open-store.d.ts.map +1 -0
- package/dist/commands/open-store.js +47 -0
- package/dist/commands/open-store.js.map +1 -0
- package/dist/commands/pack.d.ts +35 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +83 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/query.d.ts +85 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +309 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/scan.d.ts +81 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +407 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/setup.d.ts +178 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +370 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/sql.d.ts +19 -0
- package/dist/commands/sql.d.ts.map +1 -0
- package/dist/commands/sql.js +51 -0
- package/dist/commands/sql.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +66 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/verdict-render.d.ts +33 -0
- package/dist/commands/verdict-render.d.ts.map +1 -0
- package/dist/commands/verdict-render.js +123 -0
- package/dist/commands/verdict-render.js.map +1 -0
- package/dist/commands/verdict.d.ts +61 -0
- package/dist/commands/verdict.d.ts.map +1 -0
- package/dist/commands/verdict.js +146 -0
- package/dist/commands/verdict.js.map +1 -0
- package/dist/commands/wiki.d.ts +26 -0
- package/dist/commands/wiki.d.ts.map +1 -0
- package/dist/commands/wiki.js +74 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/editors/claude-code.d.ts +23 -0
- package/dist/editors/claude-code.d.ts.map +1 -0
- package/dist/editors/claude-code.js +58 -0
- package/dist/editors/claude-code.js.map +1 -0
- package/dist/editors/codex.d.ts +22 -0
- package/dist/editors/codex.d.ts.map +1 -0
- package/dist/editors/codex.js +59 -0
- package/dist/editors/codex.js.map +1 -0
- package/dist/editors/cursor.d.ts +13 -0
- package/dist/editors/cursor.d.ts.map +1 -0
- package/dist/editors/cursor.js +21 -0
- package/dist/editors/cursor.js.map +1 -0
- package/dist/editors/index.d.ts +12 -0
- package/dist/editors/index.d.ts.map +1 -0
- package/dist/editors/index.js +11 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/editors/opencode.d.ts +23 -0
- package/dist/editors/opencode.d.ts.map +1 -0
- package/dist/editors/opencode.js +61 -0
- package/dist/editors/opencode.js.map +1 -0
- package/dist/editors/types.d.ts +33 -0
- package/dist/editors/types.d.ts.map +1 -0
- package/dist/editors/types.js +19 -0
- package/dist/editors/types.js.map +1 -0
- package/dist/editors/windows-wrap.d.ts +19 -0
- package/dist/editors/windows-wrap.d.ts.map +1 -0
- package/dist/editors/windows-wrap.js +28 -0
- package/dist/editors/windows-wrap.js.map +1 -0
- package/dist/editors/windsurf.d.ts +12 -0
- package/dist/editors/windsurf.d.ts.map +1 -0
- package/dist/editors/windsurf.js +21 -0
- package/dist/editors/windsurf.js.map +1 -0
- package/dist/embedder-downloader.d.ts +87 -0
- package/dist/embedder-downloader.d.ts.map +1 -0
- package/dist/embedder-downloader.js +261 -0
- package/dist/embedder-downloader.js.map +1 -0
- package/dist/fs-atomic.d.ts +22 -0
- package/dist/fs-atomic.d.ts.map +1 -0
- package/dist/fs-atomic.js +28 -0
- package/dist/fs-atomic.js.map +1 -0
- package/dist/groups.d.ts +64 -0
- package/dist/groups.d.ts.map +1 -0
- package/dist/groups.js +172 -0
- package/dist/groups.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +703 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/is-indexed.d.ts +20 -0
- package/dist/lib/is-indexed.d.ts.map +1 -0
- package/dist/lib/is-indexed.js +35 -0
- package/dist/lib/is-indexed.js.map +1 -0
- package/dist/registry.d.ts +64 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +145 -0
- package/dist/registry.js.map +1 -0
- package/dist/scip-downloader.d.ts +138 -0
- package/dist/scip-downloader.d.ts.map +1 -0
- package/dist/scip-downloader.js +372 -0
- package/dist/scip-downloader.js.map +1 -0
- package/dist/scip-pins.d.ts +99 -0
- package/dist/scip-pins.d.ts.map +1 -0
- package/dist/scip-pins.js +195 -0
- package/dist/scip-pins.js.map +1 -0
- package/dist/skills-gen.d.ts +47 -0
- package/dist/skills-gen.d.ts.map +1 -0
- package/dist/skills-gen.js +292 -0
- package/dist/skills-gen.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codehub pack [path]` — produce a single-file repo snapshot suitable
|
|
3
|
+
* for dropping into an LLM context window, via the `repomix` CLI.
|
|
4
|
+
*
|
|
5
|
+
* Repomix is invoked with `--style xml --compress` by default so the
|
|
6
|
+
* output is Anthropic-friendly and tree-sitter-signature-compressed. The
|
|
7
|
+
* command is an OUTPUT-side convenience; OpenCodeHub does NOT use
|
|
8
|
+
* repomix for indexing or embedding (see ADR 0004).
|
|
9
|
+
*
|
|
10
|
+
* This is a thin wrapper — we shell to `npx repomix@<pin>` so operators
|
|
11
|
+
* can override by running repomix directly. The wrapper exists to make
|
|
12
|
+
* the output path discoverable and to put the produced file under
|
|
13
|
+
* `.codehub/pack/` so it's ignored by the standard gitignore pattern.
|
|
14
|
+
*/
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { existsSync, statSync } from "node:fs";
|
|
17
|
+
import { mkdir } from "node:fs/promises";
|
|
18
|
+
import { dirname, join, resolve } from "node:path";
|
|
19
|
+
const DEFAULT_REPOMIX_VERSION = "1.14.0";
|
|
20
|
+
export async function runPack(path, opts = {}) {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
const repoPath = resolve(path);
|
|
23
|
+
const style = opts.style ?? "xml";
|
|
24
|
+
const compress = opts.compress ?? true;
|
|
25
|
+
const version = opts.repomixVersion ?? DEFAULT_REPOMIX_VERSION;
|
|
26
|
+
const outputPath = opts.outputPath
|
|
27
|
+
? resolve(opts.outputPath)
|
|
28
|
+
: join(repoPath, ".codehub", "pack", `repo.${extForStyle(style)}`);
|
|
29
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
30
|
+
const args = [`repomix@${version}`, "--style", style, "--output", outputPath];
|
|
31
|
+
if (compress)
|
|
32
|
+
args.push("--compress");
|
|
33
|
+
if (opts.removeComments)
|
|
34
|
+
args.push("--remove-comments");
|
|
35
|
+
await new Promise((res, rej) => {
|
|
36
|
+
const child = spawn("npx", args, {
|
|
37
|
+
cwd: repoPath,
|
|
38
|
+
env: { ...process.env },
|
|
39
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
40
|
+
});
|
|
41
|
+
const timer = opts.timeoutMs
|
|
42
|
+
? setTimeout(() => {
|
|
43
|
+
child.kill("SIGTERM");
|
|
44
|
+
}, opts.timeoutMs)
|
|
45
|
+
: undefined;
|
|
46
|
+
child.on("error", (err) => {
|
|
47
|
+
if (timer)
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
if (err.code === "ENOENT") {
|
|
50
|
+
rej(new Error("codehub pack: `npx` not found on PATH. Install Node.js 20+."));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
rej(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
child.on("exit", (code) => {
|
|
57
|
+
if (timer)
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
if (code === 0)
|
|
60
|
+
res();
|
|
61
|
+
else
|
|
62
|
+
rej(new Error(`codehub pack: repomix exited ${code}`));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
if (!existsSync(outputPath)) {
|
|
66
|
+
throw new Error(`codehub pack: repomix did not produce ${outputPath}`);
|
|
67
|
+
}
|
|
68
|
+
const bytes = statSync(outputPath).size;
|
|
69
|
+
return { outputPath, bytes, durationMs: Date.now() - start };
|
|
70
|
+
}
|
|
71
|
+
function extForStyle(style) {
|
|
72
|
+
switch (style) {
|
|
73
|
+
case "xml":
|
|
74
|
+
return "xml";
|
|
75
|
+
case "markdown":
|
|
76
|
+
return "md";
|
|
77
|
+
case "json":
|
|
78
|
+
return "json";
|
|
79
|
+
case "plain":
|
|
80
|
+
return "txt";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=pack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../src/commands/pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBnD,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAQzC,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,OAAoB,EAAE;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,IAAI,uBAAuB,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU;QAChC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;QAC1B,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAErE,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtD,MAAM,IAAI,GAAG,CAAC,WAAW,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9E,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,cAAc;QAAE,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAExD,MAAM,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;YAC/B,GAAG,EAAE,QAAQ;YACb,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;YACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;SACxC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS;YAC1B,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;gBACd,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YACpB,CAAC,CAAC,SAAS,CAAC;QACd,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAC/C,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,GAAG,CAAC,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC,CAAC;YAChF,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,GAAG,CAAC,CAAC;YACX,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,IAAI,KAAK,CAAC;gBAAE,GAAG,EAAE,CAAC;;gBACjB,GAAG,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,yCAAyC,UAAU,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IACxC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,WAAW,CAAC,KAA4C;IAC/D,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,UAAU;YACb,OAAO,IAAI,CAAC;QACd,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codehub query <text>` — hybrid BM25 + vector search.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP `query` tool's smart path: probe the `embeddings` table,
|
|
5
|
+
* try to open an embedder, run `hybridSearch` when both succeed, and
|
|
6
|
+
* collapse to BM25 with a single stderr warning on any failure. Shares the
|
|
7
|
+
* probe + open helpers (`embeddingsPopulated`, `tryOpenEmbedder`) via
|
|
8
|
+
* `@opencodehub/search` so CLI and MCP surfaces cannot drift.
|
|
9
|
+
*
|
|
10
|
+
* Flags:
|
|
11
|
+
* - `--bm25-only` — skip the embedder probe entirely.
|
|
12
|
+
* - `--rerank-top-k <n>` — number of fused hits RRF returns (default
|
|
13
|
+
* `DEFAULT_RRF_TOP_K = 50`); clamped by `--limit` at print time.
|
|
14
|
+
* - `--context <text>` + `--goal <text>` — prefixed to the search text.
|
|
15
|
+
* - `--content` — attach capped symbol source to each hit.
|
|
16
|
+
* - `--json` — emit machine-readable output.
|
|
17
|
+
* - `--zoom` — P03 coarse-to-fine retrieval (file tier → symbol tier).
|
|
18
|
+
* - `--fanout <n>` — files to shortlist at the coarse step for `--zoom`.
|
|
19
|
+
* - `--granularity <tier>` — restrict ANN to one hierarchical tier
|
|
20
|
+
* (symbol/file/community). Defaults to "symbol".
|
|
21
|
+
*
|
|
22
|
+
* Hybrid ranking priority matches the MCP tool:
|
|
23
|
+
* 1. `CODEHUB_EMBEDDING_URL` + `CODEHUB_EMBEDDING_MODEL` → HTTP embedder.
|
|
24
|
+
* 2. Otherwise local ONNX gte-modernbert-base weights.
|
|
25
|
+
* 3. On failure to open (missing weights, unreachable HTTP) → warn + BM25.
|
|
26
|
+
*/
|
|
27
|
+
import { type Embedder } from "@opencodehub/embedder";
|
|
28
|
+
import { type OpenStoreResult } from "./open-store.js";
|
|
29
|
+
/**
|
|
30
|
+
* Hook for tests to inject a pre-built store without touching DuckDB. The
|
|
31
|
+
* default implementation delegates to {@link openStoreForCommand}. Kept
|
|
32
|
+
* separate from the public `QueryOptions` interface so end-user CLI callers
|
|
33
|
+
* aren't tempted to pass an in-process store.
|
|
34
|
+
*/
|
|
35
|
+
export interface QueryRuntimeHooks {
|
|
36
|
+
readonly openStore?: (opts: QueryOptions) => Promise<OpenStoreResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Embedder factory — production uses the default lazy-import path; tests
|
|
39
|
+
* inject a fake so they don't need gte-modernbert-base weights on disk. Any
|
|
40
|
+
* throw is caught by {@link tryOpenEmbedder} and collapses to BM25.
|
|
41
|
+
*/
|
|
42
|
+
readonly openEmbedder?: () => Promise<Embedder>;
|
|
43
|
+
}
|
|
44
|
+
export interface QueryOptions {
|
|
45
|
+
readonly limit?: number;
|
|
46
|
+
readonly repo?: string;
|
|
47
|
+
readonly home?: string;
|
|
48
|
+
readonly json?: boolean;
|
|
49
|
+
/** `--content` — attach the symbol body (capped at 2000 chars) to each hit. */
|
|
50
|
+
readonly content?: boolean;
|
|
51
|
+
/** `--context <text>` — prefix to the search text before BM25 + embedding. */
|
|
52
|
+
readonly context?: string;
|
|
53
|
+
/** `--goal <text>` — additional prefix to the search text (steers ranking). */
|
|
54
|
+
readonly goal?: string;
|
|
55
|
+
/** `--max-symbols <n>` — cap on process-grouped symbols. Today: no-op. */
|
|
56
|
+
readonly maxSymbols?: number;
|
|
57
|
+
/** `--bm25-only` — skip the embedder probe, go straight to BM25. */
|
|
58
|
+
readonly bm25Only?: boolean;
|
|
59
|
+
/** `--rerank-top-k <n>` — number of fused hits RRF should return. */
|
|
60
|
+
readonly rerankTopK?: number;
|
|
61
|
+
/**
|
|
62
|
+
* `--zoom` — enable P03 coarse-to-fine retrieval. Requires the index to
|
|
63
|
+
* have been built with `--granularity symbol,file,community` AND an
|
|
64
|
+
* embedder to be available (weights on disk or `CODEHUB_EMBEDDING_URL`
|
|
65
|
+
* set). Falls back to BM25 when no embedder is available.
|
|
66
|
+
*/
|
|
67
|
+
readonly zoom?: boolean;
|
|
68
|
+
/** `--fanout <n>` — files to shortlist at the coarse step when `--zoom` is on. */
|
|
69
|
+
readonly fanout?: number;
|
|
70
|
+
/**
|
|
71
|
+
* `--granularity <tier>` — restrict the ANN leg to this hierarchical
|
|
72
|
+
* tier. Defaults to "symbol". Pass "community" for architectural
|
|
73
|
+
* queries that should land on Community nodes.
|
|
74
|
+
*/
|
|
75
|
+
readonly granularity?: "symbol" | "file" | "community";
|
|
76
|
+
/**
|
|
77
|
+
* `--force-backend-mismatch` — bypass the embedder fingerprint refusal.
|
|
78
|
+
* Lets a query proceed against an `embeddings` table that was populated
|
|
79
|
+
* by a different embedder than the one currently active. The vectors
|
|
80
|
+
* may be stale; results may misrank. Default `false`.
|
|
81
|
+
*/
|
|
82
|
+
readonly forceBackendMismatch?: boolean;
|
|
83
|
+
}
|
|
84
|
+
export declare function runQuery(text: string, opts?: QueryOptions, hooks?: QueryRuntimeHooks): Promise<void>;
|
|
85
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,uBAAuB,CAAC;AAW/B,OAAO,EAAE,KAAK,eAAe,EAAuB,MAAM,iBAAiB,CAAC;AAO5E;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACtE;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACvD;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAoBD,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,YAAiB,EACvB,KAAK,GAAE,iBAAsB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiHf"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codehub query <text>` — hybrid BM25 + vector search.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP `query` tool's smart path: probe the `embeddings` table,
|
|
5
|
+
* try to open an embedder, run `hybridSearch` when both succeed, and
|
|
6
|
+
* collapse to BM25 with a single stderr warning on any failure. Shares the
|
|
7
|
+
* probe + open helpers (`embeddingsPopulated`, `tryOpenEmbedder`) via
|
|
8
|
+
* `@opencodehub/search` so CLI and MCP surfaces cannot drift.
|
|
9
|
+
*
|
|
10
|
+
* Flags:
|
|
11
|
+
* - `--bm25-only` — skip the embedder probe entirely.
|
|
12
|
+
* - `--rerank-top-k <n>` — number of fused hits RRF returns (default
|
|
13
|
+
* `DEFAULT_RRF_TOP_K = 50`); clamped by `--limit` at print time.
|
|
14
|
+
* - `--context <text>` + `--goal <text>` — prefixed to the search text.
|
|
15
|
+
* - `--content` — attach capped symbol source to each hit.
|
|
16
|
+
* - `--json` — emit machine-readable output.
|
|
17
|
+
* - `--zoom` — P03 coarse-to-fine retrieval (file tier → symbol tier).
|
|
18
|
+
* - `--fanout <n>` — files to shortlist at the coarse step for `--zoom`.
|
|
19
|
+
* - `--granularity <tier>` — restrict ANN to one hierarchical tier
|
|
20
|
+
* (symbol/file/community). Defaults to "symbol".
|
|
21
|
+
*
|
|
22
|
+
* Hybrid ranking priority matches the MCP tool:
|
|
23
|
+
* 1. `CODEHUB_EMBEDDING_URL` + `CODEHUB_EMBEDDING_MODEL` → HTTP embedder.
|
|
24
|
+
* 2. Otherwise local ONNX gte-modernbert-base weights.
|
|
25
|
+
* 3. On failure to open (missing weights, unreachable HTTP) → warn + BM25.
|
|
26
|
+
*/
|
|
27
|
+
import { readFile } from "node:fs/promises";
|
|
28
|
+
import { isAbsolute, resolve } from "node:path";
|
|
29
|
+
import { assertEmbedderCompatible, openDefaultEmbedder, } from "@opencodehub/embedder";
|
|
30
|
+
import { bm25Search, DEFAULT_RRF_TOP_K, embeddingsPopulated, hybridSearch, tryOpenEmbedder, } from "@opencodehub/search";
|
|
31
|
+
import { openStoreForCommand } from "./open-store.js";
|
|
32
|
+
/** Per-symbol cap for `--content`. Matches the MCP `query` tool contract. */
|
|
33
|
+
const INCLUDE_CONTENT_CHAR_CAP = 2000;
|
|
34
|
+
/** Truncation cap for the text-mode SUMMARY column. Matches the MCP snippet cap. */
|
|
35
|
+
const SUMMARY_COLUMN_CHAR_CAP = 120;
|
|
36
|
+
export async function runQuery(text, opts = {}, hooks = {}) {
|
|
37
|
+
const limit = opts.limit ?? 10;
|
|
38
|
+
const rerankTopK = opts.rerankTopK ?? DEFAULT_RRF_TOP_K;
|
|
39
|
+
const openStore = hooks.openStore ?? openStoreForCommand;
|
|
40
|
+
// Shared HTTP-priority + ONNX-fallback factory. ONNX binding only loads
|
|
41
|
+
// on the fallback branch, so plain (non-dynamic) import is fine here.
|
|
42
|
+
const openEmbedder = hooks.openEmbedder ?? (() => openDefaultEmbedder());
|
|
43
|
+
const { store, repoPath } = await openStore(opts);
|
|
44
|
+
const graph = store.graph;
|
|
45
|
+
try {
|
|
46
|
+
const searchText = buildSearchText(text, opts.context, opts.goal);
|
|
47
|
+
let ranked;
|
|
48
|
+
let mode;
|
|
49
|
+
if (opts.bm25Only === true) {
|
|
50
|
+
// Explicit opt-out: never touch the embedder probe.
|
|
51
|
+
ranked = await runBm25(graph, searchText, limit);
|
|
52
|
+
mode = "bm25";
|
|
53
|
+
}
|
|
54
|
+
else if (await embeddingsPopulated(graph)) {
|
|
55
|
+
const embedder = await tryOpenEmbedder(openEmbedder, "[cli:query]");
|
|
56
|
+
if (embedder !== null) {
|
|
57
|
+
try {
|
|
58
|
+
// Refuse the hybrid path when the persisted embedder modelId
|
|
59
|
+
// differs from the current one. Same-dim vectors from different
|
|
60
|
+
// embedders silently corrupt ranking. `--force-backend-mismatch`
|
|
61
|
+
// lets the operator override; legacy stores have
|
|
62
|
+
// `embedderModelId === undefined` and the check passes.
|
|
63
|
+
const meta = await store.graph.getMeta();
|
|
64
|
+
const compat = assertEmbedderCompatible(meta?.embedderModelId, embedder.modelId, opts.forceBackendMismatch === true);
|
|
65
|
+
if (!compat.ok) {
|
|
66
|
+
process.stderr.write(`Embedder mismatch: store was indexed with '${compat.persistedModelId}', ` +
|
|
67
|
+
`current embedder is '${compat.currentModelId}'.\n${compat.hint}\n`);
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
const fused = await hybridSearch(graph, {
|
|
71
|
+
text: searchText,
|
|
72
|
+
limit: rerankTopK,
|
|
73
|
+
...(opts.zoom === true ? { mode: "zoom" } : {}),
|
|
74
|
+
...(opts.fanout !== undefined ? { zoomFanout: opts.fanout } : {}),
|
|
75
|
+
...(opts.granularity !== undefined ? { granularity: opts.granularity } : {}),
|
|
76
|
+
}, embedder);
|
|
77
|
+
ranked = await hydrateFused(graph, fused, limit);
|
|
78
|
+
mode = "hybrid";
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
// Always release the native session — even on error — so the ONNX
|
|
82
|
+
// runtime resources aren't leaked between CLI invocations.
|
|
83
|
+
await embedder.close();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
ranked = await runBm25(graph, searchText, limit);
|
|
88
|
+
mode = "bm25";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
ranked = await runBm25(graph, searchText, limit);
|
|
93
|
+
mode = "bm25";
|
|
94
|
+
}
|
|
95
|
+
// Merge P04 summary-hydration onto the P02 hybrid/BM25 rows. Single
|
|
96
|
+
// round trip via the temporal-tier `lookupSymbolSummariesByNode`
|
|
97
|
+
// finder; missing table / missing rows / lookup failures all degrade
|
|
98
|
+
// silently — summaries are enrichment, not load-bearing.
|
|
99
|
+
const summaryMap = await joinSummaries(store, ranked.map((r) => r.nodeId));
|
|
100
|
+
const rows = summaryMap.size === 0
|
|
101
|
+
? ranked
|
|
102
|
+
: ranked.map((r) => {
|
|
103
|
+
const row = summaryMap.get(r.nodeId);
|
|
104
|
+
if (row === undefined)
|
|
105
|
+
return r;
|
|
106
|
+
return {
|
|
107
|
+
...r,
|
|
108
|
+
summary: row.summaryText,
|
|
109
|
+
...(row.signatureSummary !== undefined
|
|
110
|
+
? { signatureSummary: row.signatureSummary }
|
|
111
|
+
: {}),
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
// Best-effort `--content` attachment runs the same way for BM25 and
|
|
115
|
+
// hybrid; the store-native BM25 path already surfaces filePath but not
|
|
116
|
+
// line ranges, so the CLI reads the whole file (capped) — matching the
|
|
117
|
+
// previous CLI contract.
|
|
118
|
+
const withContent = opts.content === true
|
|
119
|
+
? await Promise.all(rows.map(async (r) => {
|
|
120
|
+
const content = await readSymbolContent(repoPath, r);
|
|
121
|
+
return content !== null ? { ...r, content } : r;
|
|
122
|
+
}))
|
|
123
|
+
: rows;
|
|
124
|
+
if (opts.json === true) {
|
|
125
|
+
console.log(JSON.stringify({ repoPath, mode, results: withContent }, null, 2));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
printResults(withContent, text, repoPath, mode);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
await store.close();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Run the BM25-only leg directly through `@opencodehub/search`. Same
|
|
136
|
+
* parameters the MCP tool passes, so ranking parity is automatic.
|
|
137
|
+
*/
|
|
138
|
+
async function runBm25(graph, searchText, limit) {
|
|
139
|
+
const hits = await bm25Search(graph, { text: searchText, limit });
|
|
140
|
+
return hits.map((h) => ({
|
|
141
|
+
nodeId: h.nodeId,
|
|
142
|
+
name: h.name,
|
|
143
|
+
kind: h.kind,
|
|
144
|
+
filePath: h.filePath,
|
|
145
|
+
score: h.score,
|
|
146
|
+
sources: ["bm25"],
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Hybrid ranking returns `FusedHit`s which carry only `{ nodeId, score,
|
|
151
|
+
* sources }` — the CLI needs name/kind/filePath for each hit too. Re-read
|
|
152
|
+
* them from the `nodes` table in one round trip. Missing ids (stale
|
|
153
|
+
* embeddings) are silently dropped. Input order is preserved.
|
|
154
|
+
*/
|
|
155
|
+
async function hydrateFused(graph, fused, limit) {
|
|
156
|
+
if (fused.length === 0)
|
|
157
|
+
return [];
|
|
158
|
+
const capped = fused.slice(0, limit);
|
|
159
|
+
const ids = Array.from(new Set(capped.map((f) => f.nodeId)));
|
|
160
|
+
const meta = new Map();
|
|
161
|
+
try {
|
|
162
|
+
// Typed-finder hydration replaces the legacy `SELECT id, name, kind,
|
|
163
|
+
// file_path FROM nodes WHERE id IN (...)`. `listNodes({ids})`
|
|
164
|
+
// already returns the rehydrated `GraphNode` shape with name + kind
|
|
165
|
+
// + filePath populated.
|
|
166
|
+
const nodes = await graph.listNodes({ ids });
|
|
167
|
+
for (const n of nodes) {
|
|
168
|
+
meta.set(n.id, { name: n.name, kind: n.kind, filePath: n.filePath });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Any metadata-hydration failure collapses to "hit with blank fields"
|
|
173
|
+
// rather than aborting the whole query — we still have valid nodeIds
|
|
174
|
+
// + scores + sources. The agent can call `context` on the nodeId to
|
|
175
|
+
// recover the details.
|
|
176
|
+
}
|
|
177
|
+
const out = [];
|
|
178
|
+
for (const f of capped) {
|
|
179
|
+
const m = meta.get(f.nodeId);
|
|
180
|
+
if (m === undefined)
|
|
181
|
+
continue;
|
|
182
|
+
out.push({
|
|
183
|
+
nodeId: f.nodeId,
|
|
184
|
+
name: m.name,
|
|
185
|
+
kind: m.kind,
|
|
186
|
+
filePath: m.filePath,
|
|
187
|
+
score: f.score,
|
|
188
|
+
sources: f.sources,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Fetch `symbol_summaries` rows for every hit nodeId in a single query.
|
|
195
|
+
* Collapses multiple prompt-version rows per node by keeping the last
|
|
196
|
+
* row in the storage layer's documented `(node_id ASC, prompt_version
|
|
197
|
+
* ASC, content_hash ASC)` order, which deterministically selects the
|
|
198
|
+
* newest prompt version. Returns an empty map on any failure so a
|
|
199
|
+
* missing `symbol_summaries` table never blocks a query. Test fakes
|
|
200
|
+
* without `lookupSymbolSummariesByNode` get an empty join transparently.
|
|
201
|
+
*/
|
|
202
|
+
async function joinSummaries(store, nodeIds) {
|
|
203
|
+
const out = new Map();
|
|
204
|
+
if (nodeIds.length === 0)
|
|
205
|
+
return out;
|
|
206
|
+
// Test fakes that omit a real temporal view (or set it to a partial
|
|
207
|
+
// shape) get an empty join transparently — `lookupSymbolSummariesByNode`
|
|
208
|
+
// is required on `ITemporalStore` but we still duck-check at runtime so
|
|
209
|
+
// a hand-rolled mock without the method doesn't blow up.
|
|
210
|
+
const temporal = store.temporal;
|
|
211
|
+
if (typeof temporal.lookupSymbolSummariesByNode !== "function")
|
|
212
|
+
return out;
|
|
213
|
+
const uniqIds = Array.from(new Set(nodeIds));
|
|
214
|
+
try {
|
|
215
|
+
const rows = await temporal.lookupSymbolSummariesByNode.call(store.temporal, uniqIds);
|
|
216
|
+
for (const row of rows) {
|
|
217
|
+
// Overwriting per node id keeps the newest prompt version because of
|
|
218
|
+
// the storage layer's ORDER BY contract on `lookupSymbolSummariesByNode`.
|
|
219
|
+
out.set(row.nodeId, row);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Degrade silently — summaries are enrichment, not load-bearing.
|
|
224
|
+
}
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Join `context — goal — text` with whitespace-safe em-dash separators.
|
|
229
|
+
* Missing / blank parts are dropped so the ranker never sees a dangling
|
|
230
|
+
* separator.
|
|
231
|
+
*/
|
|
232
|
+
function buildSearchText(text, context, goal) {
|
|
233
|
+
const parts = [];
|
|
234
|
+
if (context !== undefined && context.trim() !== "")
|
|
235
|
+
parts.push(context.trim());
|
|
236
|
+
if (goal !== undefined && goal.trim() !== "")
|
|
237
|
+
parts.push(goal.trim());
|
|
238
|
+
parts.push(text);
|
|
239
|
+
return parts.join(" — ");
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Read the symbol body from disk. The CLI `QueryRow` doesn't carry
|
|
243
|
+
* startLine / endLine, so on the CLI path we return the first
|
|
244
|
+
* {@link INCLUDE_CONTENT_CHAR_CAP} characters of the whole file — the MCP
|
|
245
|
+
* tool has access to the richer node metadata and can slice more tightly.
|
|
246
|
+
* Any read error returns `null`.
|
|
247
|
+
*/
|
|
248
|
+
async function readSymbolContent(repoPath, r) {
|
|
249
|
+
const abs = isAbsolute(r.filePath) ? r.filePath : resolve(repoPath, r.filePath);
|
|
250
|
+
let source;
|
|
251
|
+
try {
|
|
252
|
+
source = await readFile(abs, "utf8");
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
if (source.length <= INCLUDE_CONTENT_CHAR_CAP)
|
|
258
|
+
return source;
|
|
259
|
+
return `${source.slice(0, INCLUDE_CONTENT_CHAR_CAP - 1)}…`;
|
|
260
|
+
}
|
|
261
|
+
function printResults(results, text, repoPath, mode) {
|
|
262
|
+
const label = mode === "hybrid" ? "hybrid" : "BM25";
|
|
263
|
+
console.warn(`query: "${text}" in ${repoPath} (${results.length} ${label} results)`);
|
|
264
|
+
if (results.length === 0)
|
|
265
|
+
return;
|
|
266
|
+
// Only render the SUMMARY column when at least one hit carries one —
|
|
267
|
+
// skip the extra whitespace on indexes that haven't run the summarize
|
|
268
|
+
// phase yet. SOURCES stays on every row so agents can tell which ranker
|
|
269
|
+
// contributed to each hit.
|
|
270
|
+
const anySummary = results.some((r) => typeof r.summary === "string" && r.summary.length > 0);
|
|
271
|
+
const header = anySummary
|
|
272
|
+
? ["SCORE", "KIND", "NAME", "FILE", "SOURCES", "SUMMARY"]
|
|
273
|
+
: ["SCORE", "KIND", "NAME", "FILE", "SOURCES"];
|
|
274
|
+
const rows = results.map((r) => {
|
|
275
|
+
const base = [r.score.toFixed(3), r.kind, r.name, r.filePath, r.sources.join("+")];
|
|
276
|
+
if (!anySummary)
|
|
277
|
+
return base;
|
|
278
|
+
return [...base, truncateSummary(r.summary)];
|
|
279
|
+
});
|
|
280
|
+
const widths = header.map((h, i) => Math.max(h.length, ...rows.map((row) => (row[i] ?? "").length)));
|
|
281
|
+
const line = (cols) => cols.map((c, i) => c.padEnd(widths[i] ?? 0)).join(" ");
|
|
282
|
+
console.log(line(header));
|
|
283
|
+
for (const row of rows)
|
|
284
|
+
console.log(line(row));
|
|
285
|
+
// When --content was passed, append each symbol body below the table so
|
|
286
|
+
// agents piping the output can grep/read it without JSON parsing.
|
|
287
|
+
for (const r of results) {
|
|
288
|
+
if (r.content === undefined)
|
|
289
|
+
continue;
|
|
290
|
+
console.log("");
|
|
291
|
+
console.log(`# ${r.name} [${r.kind}] — ${r.filePath}`);
|
|
292
|
+
console.log(r.content);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Render a summary string to fit the single-line SUMMARY column. Newlines
|
|
297
|
+
* collapse to spaces so the column width survives; anything past the cap
|
|
298
|
+
* is trimmed and closed with an ellipsis. Absent summaries render as an
|
|
299
|
+
* empty string so the column aligns.
|
|
300
|
+
*/
|
|
301
|
+
function truncateSummary(summary) {
|
|
302
|
+
if (summary === undefined || summary.length === 0)
|
|
303
|
+
return "";
|
|
304
|
+
const flattened = summary.replace(/\s+/g, " ").trim();
|
|
305
|
+
if (flattened.length <= SUMMARY_COLUMN_CHAR_CAP)
|
|
306
|
+
return flattened;
|
|
307
|
+
return `${flattened.slice(0, SUMMARY_COLUMN_CHAR_CAP - 1)}…`;
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/commands/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codehub scan [path]` — run P1 + profile-gated P2 scanners, emit merged
|
|
3
|
+
* SARIF, ingest findings into the graph.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. Resolve the target repo (optionally from the registry).
|
|
7
|
+
* 2. Read the ProjectProfile row (if any) so we can gate scanners by
|
|
8
|
+
* detected languages / iacTypes / apiContracts.
|
|
9
|
+
* 3. Filter the catalog by --scanners, --with, and the profile:
|
|
10
|
+
* - P1 scanners are gated by language overlap (polyglot always in).
|
|
11
|
+
* - P2 scanners (trivy, checkov, hadolint, tflint, spectral) are
|
|
12
|
+
* opt-in via ProjectProfile fields. `--with trivy,checkov`
|
|
13
|
+
* force-adds them regardless of profile.
|
|
14
|
+
* 4. Build per-scanner context (checkov frameworks, hadolint Dockerfile
|
|
15
|
+
* list, spectral contract files, pip-audit requirements path) from
|
|
16
|
+
* the profile + filesystem probe.
|
|
17
|
+
* 5. Run the selected scanners in parallel via `runScanners`.
|
|
18
|
+
* 6. Merge SARIF and write to `.codehub/scan.sarif`.
|
|
19
|
+
* 7. Ingest findings into the graph via `runIngestSarif`.
|
|
20
|
+
* 8. Exit with 0 when no HIGH+CRIT findings, 1 when any, 2 when a
|
|
21
|
+
* scanner returned non-zero or crashed.
|
|
22
|
+
*
|
|
23
|
+
* The --severity filter gates the exit code only; every finding is
|
|
24
|
+
* still written to SARIF and the graph.
|
|
25
|
+
*/
|
|
26
|
+
import { P1_SPECS, type ProjectProfileGate, type ScannerSpec } from "@opencodehub/scanners";
|
|
27
|
+
export interface ScanOptions {
|
|
28
|
+
/** Explicit scanner ids (--scanners=semgrep,osv). Overrides profile gating. */
|
|
29
|
+
readonly scanners?: readonly string[];
|
|
30
|
+
/** Additional scanner ids to include on top of defaults. */
|
|
31
|
+
readonly withScanners?: readonly string[];
|
|
32
|
+
/** Override output path. Defaults to `<repo>/.codehub/scan.sarif`. */
|
|
33
|
+
readonly output?: string;
|
|
34
|
+
/** Severity filter for the exit-code gate (default: HIGH,CRITICAL). */
|
|
35
|
+
readonly severity?: readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* Path to a baseline SARIF log. When supplied, every result in the
|
|
38
|
+
* scan output is tagged via `applyBaselineState` and findings with
|
|
39
|
+
* `baselineState === "unchanged"` are excluded from the severity-gate
|
|
40
|
+
* exit code — they are not new relative to the baseline.
|
|
41
|
+
*/
|
|
42
|
+
readonly baseline?: string;
|
|
43
|
+
/** Override the registry home (tests). */
|
|
44
|
+
readonly home?: string;
|
|
45
|
+
/** `--repo <name>`: look up a registered repo instead of using `path`. */
|
|
46
|
+
readonly repo?: string;
|
|
47
|
+
/** Concurrency override. */
|
|
48
|
+
readonly concurrency?: number;
|
|
49
|
+
/** Per-scanner timeout override in ms. */
|
|
50
|
+
readonly timeoutMs?: number;
|
|
51
|
+
}
|
|
52
|
+
export interface ScanSummary {
|
|
53
|
+
readonly repoPath: string;
|
|
54
|
+
readonly outputPath: string;
|
|
55
|
+
readonly runs: readonly {
|
|
56
|
+
readonly scanner: string;
|
|
57
|
+
readonly findings: number;
|
|
58
|
+
readonly skipped?: string;
|
|
59
|
+
}[];
|
|
60
|
+
readonly totalFindings: number;
|
|
61
|
+
readonly bySeverity: Record<string, number>;
|
|
62
|
+
/** 0 = clean, 1 = findings above severity threshold, 2 = scanner error. */
|
|
63
|
+
readonly exitCode: 0 | 1 | 2;
|
|
64
|
+
}
|
|
65
|
+
export declare function runScan(path: string, opts?: ScanOptions): Promise<ScanSummary>;
|
|
66
|
+
/**
|
|
67
|
+
* Read the ProjectProfile node (if present) so we can gate scanners by
|
|
68
|
+
* detected languages, IaC types, and API contracts. If the graph is
|
|
69
|
+
* absent, every field is returned empty — falls back to the polyglot P1
|
|
70
|
+
* subset.
|
|
71
|
+
*/
|
|
72
|
+
export declare function readProjectProfile(repoPath: string): Promise<ProjectProfileGate>;
|
|
73
|
+
/**
|
|
74
|
+
* Exported for tests: apply --scanners / --with / profile gating to
|
|
75
|
+
* produce the final scanner list.
|
|
76
|
+
*/
|
|
77
|
+
export declare function selectScanners(profile: ProjectProfileGate, opts: ScanOptions): readonly ScannerSpec[];
|
|
78
|
+
/** Helper exposed for tests: parse a SARIF file from disk. */
|
|
79
|
+
export declare function readSarifFile(path: string): Promise<unknown>;
|
|
80
|
+
export { P1_SPECS };
|
|
81
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAaH,OAAO,EAOL,QAAQ,EAER,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EAGjB,MAAM,uBAAuB,CAAC;AAK/B,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,4DAA4D;IAC5D,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,4BAA4B;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,SAAS;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,EAAE,CAAC;IACJ,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC9B;AAID,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAoIxF;AA+BD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0BtF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,WAAW,GAChB,SAAS,WAAW,EAAE,CAuBxB;AAoID,8DAA8D;AAC9D,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGlE;AAyBD,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|