@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,187 @@
1
+ /**
2
+ * `codehub code-pack [path]` — produce the deterministic 9-item BOM via
3
+ * `@opencodehub/pack`.
4
+ *
5
+ * Output goes to `<repo>/.codehub/packs/<packHash>/` so a pack's identity
6
+ * is encoded in its on-disk path. The function writes to a temp directory
7
+ * first, then renames into place once the manifest's `packHash` is known
8
+ * — this keeps the path-includes-hash invariant without requiring
9
+ * `generatePack` to know its own hash up front.
10
+ *
11
+ * Two engines are supported via the `--engine` flag:
12
+ * - `pack` (DEFAULT) — `@opencodehub/pack`'s `generatePack`. Opens a
13
+ * read-only graph store via `openStore({ readOnly: true })` and walks
14
+ * the indexed graph to produce the 8 mandatory BOM items + manifest +
15
+ * optional Parquet embeddings sidecar. The sidecar emitter lives in
16
+ * `@opencodehub/pack`; cli/ passes the composed `Store` and pack
17
+ * dispatches on `store.backend` (DuckDB COPY for `duck`, degraded
18
+ * stamp for `lbug` v1).
19
+ * - `repomix` — legacy single-file snapshot via `npx repomix`. Retained
20
+ * under an opt-in flag for one milestone before removal. Internally
21
+ * delegates to `runPack` so the repomix shell-out is implemented
22
+ * exactly once.
23
+ *
24
+ * The CLI surface is:
25
+ *
26
+ * codehub code-pack [path]
27
+ * [--budget <N>] token budget (default 100_000)
28
+ * [--tokenizer <ID>] "<vendor>:<name>@<pin>" (default openai:o200k_base@tiktoken-0.8.0)
29
+ * [--out-dir <DIR>] overrides the .codehub/packs/<packHash>/ default
30
+ * [--engine pack|repomix] default "pack"
31
+ *
32
+ * Exits non-zero on missing index (the pack engine requires `codehub
33
+ * analyze` to have already populated the graph store).
34
+ */
35
+ import { createHash } from "node:crypto";
36
+ import { existsSync, statSync } from "node:fs";
37
+ import { mkdir, mkdtemp, readFile, rename, rm } from "node:fs/promises";
38
+ import { tmpdir } from "node:os";
39
+ import { join, resolve } from "node:path";
40
+ import { generatePack } from "@opencodehub/pack";
41
+ import { openStore, resolveDbPath } from "@opencodehub/storage";
42
+ import { runPack } from "./pack.js";
43
+ /** Default token budget when `--budget` is omitted. */
44
+ export const DEFAULT_BUDGET_TOKENS = 100_000;
45
+ /** Default tokenizer identifier when `--tokenizer` is omitted. */
46
+ export const DEFAULT_TOKENIZER_ID = "openai:o200k_base@tiktoken-0.8.0";
47
+ /** Default engine when `--engine` is omitted — the new `@opencodehub/pack` BOM. */
48
+ export const DEFAULT_ENGINE = "pack";
49
+ export async function runCodePack(args = {}) {
50
+ const repoPath = resolve(args.repo ?? process.cwd());
51
+ const engine = args.engine ?? DEFAULT_ENGINE;
52
+ if (engine === "repomix") {
53
+ return runRepomixEngine(repoPath, args);
54
+ }
55
+ return runPackEngine(repoPath, args);
56
+ }
57
+ async function runPackEngine(repoPath, args) {
58
+ const budget = args.budget ?? DEFAULT_BUDGET_TOKENS;
59
+ const tokenizer = args.tokenizer ?? DEFAULT_TOKENIZER_ID;
60
+ const generate = args._generatePack ?? generatePack;
61
+ // Production: open a read-only graph store via the backend-agnostic
62
+ // factory; tests inject `_store` to skip the native binding entirely.
63
+ const dbPath = resolveDbPath(repoPath);
64
+ if (args._store === undefined && !existsSync(dbPath)) {
65
+ throw new Error(`codehub code-pack: no graph index at ${dbPath}. ` +
66
+ "Run `codehub analyze` first to populate the store.");
67
+ }
68
+ const ownsStore = args._store === undefined;
69
+ // Composed-store envelope used only when this command owns lifecycle.
70
+ // Holds it here so the finally block can close graph + temporal in
71
+ // deterministic order without re-running the factory.
72
+ const owned = ownsStore
73
+ ? await (async () => {
74
+ const composed = await openStore({ path: dbPath, backend: "auto", readOnly: true });
75
+ await composed.graph.open();
76
+ return composed;
77
+ })()
78
+ : undefined;
79
+ // generatePack consumes `Store` (= `OpenStoreResult`) so the
80
+ // embeddings sidecar can dispatch on `store.backend`. Tests
81
+ // historically passed an `IGraphStore` stub via `_store`; route that
82
+ // through the `internal.graphOnly` seam which auto-wraps it into a
83
+ // no-op-temporal Store with `backend: "duck"` (the sidecar then
84
+ // resolves to absent unless the stub duck-types
85
+ // `exportEmbeddingsParquet` itself).
86
+ const composedStore = isStoreShape(args._store)
87
+ ? args._store
88
+ : (owned ?? undefined);
89
+ const graphOnlyStub = isStoreShape(args._store)
90
+ ? undefined
91
+ : args._store;
92
+ // Stage in a temp dir; we don't know `packHash` until generatePack returns,
93
+ // and the canonical layout puts the hash in the directory name.
94
+ const stagingDir = await mkdtemp(join(tmpdir(), "codehub-code-pack-"));
95
+ try {
96
+ const manifest = await generate({
97
+ repoPath,
98
+ outDir: stagingDir,
99
+ budgetTokens: budget,
100
+ tokenizerId: tokenizer,
101
+ }, composedStore !== undefined
102
+ ? { store: composedStore }
103
+ : { graphOnly: graphOnlyStub });
104
+ const finalOutDir = args.outDir !== undefined
105
+ ? resolve(args.outDir)
106
+ : join(repoPath, ".codehub", "packs", manifest.packHash);
107
+ // If `--out-dir` was supplied, honor it as the literal final path; otherwise
108
+ // build the canonical .codehub/packs/<hash>/ layout. Either way, ensure the
109
+ // parent exists, then move the staging dir into place.
110
+ await mkdir(join(finalOutDir, ".."), { recursive: true });
111
+ if (existsSync(finalOutDir)) {
112
+ // Idempotent re-runs land on the same packHash — clear the old dir so
113
+ // `rename` succeeds atomically. The rm is recursive because the
114
+ // staging contents are non-empty.
115
+ await rm(finalOutDir, { recursive: true, force: true });
116
+ }
117
+ await rename(stagingDir, finalOutDir);
118
+ // BOM item count = manifest.files[].length (skeleton, file-tree, deps,
119
+ // ast-chunks, xrefs, findings, licenses, [embeddings.parquet]) + 1 for
120
+ // the manifest itself. The readme.md is consumer-facing metadata and is
121
+ // not part of the manifest hash preimage; we still report it as an
122
+ // on-disk artifact downstream by walking the dir, but the BOM count
123
+ // tracks the deterministic items only.
124
+ const bomItemCount = manifest.files.length + 1;
125
+ return {
126
+ outDir: finalOutDir,
127
+ packHash: manifest.packHash,
128
+ bomItemCount,
129
+ manifest,
130
+ engine: "pack",
131
+ };
132
+ }
133
+ finally {
134
+ if (owned !== undefined) {
135
+ await owned.close();
136
+ }
137
+ // Best-effort cleanup of the staging dir if we never renamed it (e.g.
138
+ // generatePack threw). `rm` with `force` swallows ENOENT.
139
+ await rm(stagingDir, { recursive: true, force: true });
140
+ }
141
+ }
142
+ async function runRepomixEngine(repoPath, args) {
143
+ const repomix = args._runRepomix ?? runPack;
144
+ const result = await repomix(repoPath, {});
145
+ // Build a CodePackResult-shaped envelope so callers can reason about
146
+ // either engine uniformly. `packHash` is a sha256 over the file's bytes,
147
+ // which gives operators a deterministic identifier even though repomix
148
+ // does not emit a manifest. `bomItemCount` is 1 — repomix is a
149
+ // single-file snapshot, not the 9-item BOM.
150
+ const bytes = await readFile(result.outputPath);
151
+ const packHash = createHash("sha256").update(bytes).digest("hex");
152
+ return {
153
+ outDir: repoPath,
154
+ packHash,
155
+ bomItemCount: 1,
156
+ manifest: null,
157
+ engine: "repomix",
158
+ repomixOutputPath: result.outputPath,
159
+ };
160
+ }
161
+ /**
162
+ * Read the on-disk size of `path`. Exported so the CLI's user-facing
163
+ * recap can format byte counts without re-walking the dir tree.
164
+ */
165
+ export function statSizeOrZero(path) {
166
+ try {
167
+ return statSync(path).size;
168
+ }
169
+ catch {
170
+ return 0;
171
+ }
172
+ }
173
+ /**
174
+ * Discriminate between the composed {@link Store} and a bare
175
+ * {@link IGraphStore} stub. Tests historically passed a flat IGraphStore
176
+ * via `_store`; production passes the full Store envelope from
177
+ * {@link openStore}. We detect the envelope shape by the presence of
178
+ * `graph` + `temporal` + `backend` so both paths flow through the
179
+ * sidecar dispatch correctly.
180
+ */
181
+ function isStoreShape(s) {
182
+ if (s === undefined)
183
+ return false;
184
+ const obj = s;
185
+ return typeof obj.backend === "string" && obj.graph !== undefined && obj.temporal !== undefined;
186
+ }
187
+ //# sourceMappingURL=code-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-pack.js","sourceRoot":"","sources":["../../src/commands/code-pack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `codehub context <symbol>` — 360-degree view of a single symbol.
3
+ *
4
+ * Resolves the target by exact name against the graph, filtering out
5
+ * synthetic import-tracking stubs (`filePath = '<external>'` and
6
+ * `kind = 'CodeElement'`) that carry no caller/callee edges. Optional
7
+ * `targetUid`, `filePath`, and `kind` narrow same-named candidates.
8
+ * When exact-name yields zero rows we fall back to the BM25 index so
9
+ * concept-phrase queries still work; when it yields more than one row
10
+ * and no disambiguator narrows the set, we surface the candidate list.
11
+ *
12
+ * This command is graph-only — the lifecycle owner
13
+ * (`openStoreForCommand`) constructs the composed `Store` envelope, but
14
+ * `runContext` reaches through `store.graph` for every read so the
15
+ * `IGraphStore` typed-finder surface stays the only contract.
16
+ */
17
+ import { type OpenStoreResult } from "./open-store.js";
18
+ export interface ContextOptions {
19
+ readonly repo?: string;
20
+ readonly home?: string;
21
+ readonly json?: boolean;
22
+ readonly targetUid?: string;
23
+ readonly filePath?: string;
24
+ readonly kind?: string;
25
+ }
26
+ export interface ContextRuntimeHooks {
27
+ readonly openStore?: (opts: ContextOptions) => Promise<OpenStoreResult>;
28
+ }
29
+ export declare function runContext(symbol: string, opts?: ContextOptions, hooks?: ContextRuntimeHooks): Promise<void>;
30
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAAE,KAAK,eAAe,EAAuB,MAAM,iBAAiB,CAAC;AAE5E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CACzE;AAyJD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,cAAmB,EACzB,KAAK,GAAE,mBAAwB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA0Hf"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * `codehub context <symbol>` — 360-degree view of a single symbol.
3
+ *
4
+ * Resolves the target by exact name against the graph, filtering out
5
+ * synthetic import-tracking stubs (`filePath = '<external>'` and
6
+ * `kind = 'CodeElement'`) that carry no caller/callee edges. Optional
7
+ * `targetUid`, `filePath`, and `kind` narrow same-named candidates.
8
+ * When exact-name yields zero rows we fall back to the BM25 index so
9
+ * concept-phrase queries still work; when it yields more than one row
10
+ * and no disambiguator narrows the set, we surface the candidate list.
11
+ *
12
+ * This command is graph-only — the lifecycle owner
13
+ * (`openStoreForCommand`) constructs the composed `Store` envelope, but
14
+ * `runContext` reaches through `store.graph` for every read so the
15
+ * `IGraphStore` typed-finder surface stays the only contract.
16
+ */
17
+ import { openStoreForCommand } from "./open-store.js";
18
+ /**
19
+ * Find Process-kind partners reachable from the target via `PROCESS_STEP`
20
+ * edges. Mirrors the post-A-6c MCP equivalent in
21
+ * `packages/mcp/src/tools/context.ts:567` so the two surfaces stay in
22
+ * lockstep on edge semantics + ordering.
23
+ */
24
+ async function fetchProcessParticipation(graph, targetId) {
25
+ const [outEdges, inEdges] = await Promise.all([
26
+ graph.listEdgesByType("PROCESS_STEP", { fromIds: [targetId] }),
27
+ graph.listEdgesByType("PROCESS_STEP", { toIds: [targetId] }),
28
+ ]);
29
+ const partnerIds = new Set();
30
+ for (const e of [...outEdges, ...inEdges]) {
31
+ const id = e.from === targetId ? e.to : e.from;
32
+ partnerIds.add(id);
33
+ }
34
+ if (partnerIds.size === 0)
35
+ return [];
36
+ const partners = await graph.listNodes({ ids: [...partnerIds] });
37
+ const partnerById = new Map();
38
+ for (const p of partners)
39
+ partnerById.set(p.id, p);
40
+ const dedup = new Map();
41
+ for (const e of [...outEdges, ...inEdges]) {
42
+ const partnerId = e.from === targetId ? e.to : e.from;
43
+ const partner = partnerById.get(partnerId);
44
+ if (!partner || partner.kind !== "Process")
45
+ continue;
46
+ if (dedup.has(partner.id))
47
+ continue;
48
+ const inferredLabelRaw = partner.inferredLabel;
49
+ const label = typeof inferredLabelRaw === "string" && inferredLabelRaw.length > 0
50
+ ? inferredLabelRaw
51
+ : partner.name;
52
+ const stepRaw = e.step;
53
+ const stepNum = typeof stepRaw === "number" && Number.isFinite(stepRaw) && stepRaw > 0
54
+ ? Math.trunc(stepRaw)
55
+ : null;
56
+ dedup.set(partner.id, { label, step: stepNum });
57
+ }
58
+ const items = Array.from(dedup.entries()).map(([id, v]) => ({
59
+ id,
60
+ label: v.label,
61
+ step: v.step,
62
+ }));
63
+ // Match the prior `ORDER BY r.step` then deterministic id tiebreak.
64
+ items.sort((a, b) => {
65
+ const as = a.step ?? Number.POSITIVE_INFINITY;
66
+ const bs = b.step ?? Number.POSITIVE_INFINITY;
67
+ if (as !== bs)
68
+ return as - bs;
69
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
70
+ });
71
+ return items.slice(0, 20);
72
+ }
73
+ function nodeToResolved(n) {
74
+ return {
75
+ nodeId: n.id,
76
+ name: n.name,
77
+ kind: n.kind,
78
+ filePath: n.filePath,
79
+ score: 0,
80
+ };
81
+ }
82
+ function searchResultToResolvedNode(r) {
83
+ return {
84
+ nodeId: r.nodeId,
85
+ name: r.name,
86
+ kind: r.kind,
87
+ filePath: r.filePath,
88
+ score: r.score,
89
+ };
90
+ }
91
+ async function resolveTarget(graph, symbol, opts) {
92
+ if (opts.targetUid !== undefined && opts.targetUid.length > 0) {
93
+ const list = await graph.listNodes({ ids: [opts.targetUid], limit: 1 });
94
+ const node = list[0];
95
+ if (!node)
96
+ return { kind: "not_found" };
97
+ return { kind: "resolved", target: nodeToResolved(node), alternates: [] };
98
+ }
99
+ // Name-keyed lookup with optional kind narrowing. The `file_path != '<external>'
100
+ // AND kind != 'CodeElement'` invariants from the legacy SQL are now applied
101
+ // post-finder so we don't need a `NOT IN` shape. The MCP-side migration in
102
+ // `packages/mcp/src/tools/context.ts:418-429` pioneered this pattern.
103
+ const listOpts = opts.kind !== undefined && opts.kind.length > 0 ? { kinds: [opts.kind] } : {};
104
+ let candidates = await graph.listNodesByName(symbol, listOpts);
105
+ // Drop synthetic import stubs.
106
+ candidates = candidates.filter((n) => n.filePath !== "<external>" && n.kind !== "CodeElement");
107
+ // Optional file-path substring narrow (LIKE %x%).
108
+ if (opts.filePath !== undefined && opts.filePath.length > 0) {
109
+ const sub = opts.filePath;
110
+ candidates = candidates.filter((n) => n.filePath.includes(sub));
111
+ }
112
+ // Match prior `ORDER BY file_path LIMIT 25`.
113
+ const sorted = [...candidates].sort((a, b) => a.filePath < b.filePath ? -1 : a.filePath > b.filePath ? 1 : 0);
114
+ const sliced = sorted.slice(0, 25);
115
+ if (sliced.length === 1) {
116
+ const head = sliced[0];
117
+ if (!head)
118
+ return { kind: "not_found" };
119
+ return { kind: "resolved", target: nodeToResolved(head), alternates: [] };
120
+ }
121
+ if (sliced.length > 1) {
122
+ return { kind: "ambiguous", candidates: sliced.map(nodeToResolved) };
123
+ }
124
+ const fallback = await graph.search({ text: symbol, limit: 5 });
125
+ if (fallback.length === 0)
126
+ return { kind: "not_found" };
127
+ const [head, ...rest] = fallback;
128
+ if (head === undefined)
129
+ return { kind: "not_found" };
130
+ return {
131
+ kind: "resolved",
132
+ target: searchResultToResolvedNode(head),
133
+ alternates: rest.map(searchResultToResolvedNode),
134
+ };
135
+ }
136
+ export async function runContext(symbol, opts = {}, hooks = {}) {
137
+ const openStore = hooks.openStore ?? openStoreForCommand;
138
+ const { store, repoPath } = await openStore(opts);
139
+ const graph = store.graph;
140
+ try {
141
+ const resolution = await resolveTarget(graph, symbol, opts);
142
+ if (resolution.kind === "not_found") {
143
+ if (opts.json) {
144
+ console.log(JSON.stringify({
145
+ repoPath,
146
+ target: null,
147
+ callers: [],
148
+ callees: [],
149
+ processes: [],
150
+ alternateCandidates: [],
151
+ }, null, 2));
152
+ return;
153
+ }
154
+ console.warn(`context: no symbol matching "${symbol}" in ${repoPath}`);
155
+ return;
156
+ }
157
+ if (resolution.kind === "ambiguous") {
158
+ const candidates = resolution.candidates.slice(0, 10);
159
+ if (opts.json) {
160
+ console.log(JSON.stringify({
161
+ repoPath,
162
+ ambiguous: true,
163
+ candidates: resolution.candidates,
164
+ }, null, 2));
165
+ process.exitCode = 1;
166
+ return;
167
+ }
168
+ console.warn(`context: "${symbol}" matched ${resolution.candidates.length} symbols in ${repoPath}. Re-call with --target-uid, --file-path, or --kind.`);
169
+ for (let i = 0; i < candidates.length; i += 1) {
170
+ const c = candidates[i];
171
+ if (!c)
172
+ continue;
173
+ console.warn(` ${i + 1}. [${c.kind}] ${c.name} — ${c.filePath} (${c.nodeId})`);
174
+ }
175
+ if (resolution.candidates.length > candidates.length) {
176
+ console.warn(` … ${resolution.candidates.length - candidates.length} more`);
177
+ }
178
+ process.exitCode = 1;
179
+ return;
180
+ }
181
+ const target = resolution.target;
182
+ const [up, down, processes] = await Promise.all([
183
+ graph.traverse({
184
+ startId: target.nodeId,
185
+ direction: "up",
186
+ maxDepth: 1,
187
+ relationTypes: ["CALLS"],
188
+ }),
189
+ graph.traverse({
190
+ startId: target.nodeId,
191
+ direction: "down",
192
+ maxDepth: 1,
193
+ relationTypes: ["CALLS"],
194
+ }),
195
+ fetchProcessParticipation(graph, target.nodeId),
196
+ ]);
197
+ if (opts.json) {
198
+ console.log(JSON.stringify({
199
+ repoPath,
200
+ target,
201
+ callers: up,
202
+ callees: down,
203
+ processes,
204
+ alternateCandidates: resolution.alternates,
205
+ }, null, 2));
206
+ return;
207
+ }
208
+ console.warn(`context: ${target.name} (${target.kind}) — ${target.filePath}`);
209
+ console.log("");
210
+ console.log(`Inbound (depth 1): ${up.length}`);
211
+ for (const r of up)
212
+ console.log(` ← ${r.nodeId}`);
213
+ console.log("");
214
+ console.log(`Outbound (depth 1): ${down.length}`);
215
+ for (const r of down)
216
+ console.log(` → ${r.nodeId}`);
217
+ if (processes.length > 0) {
218
+ console.log("");
219
+ console.log(`Processes (${processes.length}):`);
220
+ for (const p of processes) {
221
+ const stepLabel = p.step !== null ? `step ${p.step}` : "participant";
222
+ console.log(` ⊿ ${p.label} — ${stepLabel} (${p.id})`);
223
+ }
224
+ }
225
+ if (resolution.alternates.length > 0) {
226
+ console.log("");
227
+ console.log(`Other candidates for "${symbol}":`);
228
+ for (const c of resolution.alternates) {
229
+ console.log(` - ${c.name} (${c.kind}) — ${c.filePath}`);
230
+ }
231
+ }
232
+ }
233
+ finally {
234
+ await store.close();
235
+ }
236
+ }
237
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `codehub detect-changes` — map a git diff onto affected graph symbols.
3
+ *
4
+ * Delegates to `@opencodehub/analysis.runDetectChanges`. The CLI layer
5
+ * only resolves the scope flag, runs git against the repo, and formats
6
+ * the result. Useful from CI (GitHub Actions, GitLab CI) without
7
+ * launching the MCP server.
8
+ *
9
+ * Exit codes:
10
+ * 0 — diff produced zero affected symbols (risk: LOW or empty diff).
11
+ * 1 — diff produced HIGH or CRITICAL risk. Operators configure CI
12
+ * gates to fail on non-zero.
13
+ * Any risk tier MEDIUM or below stays on exit 0 so informational runs
14
+ * are non-blocking.
15
+ */
16
+ export interface DetectChangesOptions {
17
+ readonly scope?: "unstaged" | "staged" | "all" | "compare";
18
+ readonly compareRef?: string;
19
+ readonly repo?: string;
20
+ readonly home?: string;
21
+ readonly json?: boolean;
22
+ /** When true, fail (exit 1) on any non-LOW risk. Default: HIGH+CRIT only. */
23
+ readonly strict?: boolean;
24
+ }
25
+ export declare function runDetectChangesCmd(opts?: DetectChangesOptions): Promise<void>;
26
+ //# sourceMappingURL=detect-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-changes.d.ts","sourceRoot":"","sources":["../../src/commands/detect-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DxF"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `codehub detect-changes` — map a git diff onto affected graph symbols.
3
+ *
4
+ * Delegates to `@opencodehub/analysis.runDetectChanges`. The CLI layer
5
+ * only resolves the scope flag, runs git against the repo, and formats
6
+ * the result. Useful from CI (GitHub Actions, GitLab CI) without
7
+ * launching the MCP server.
8
+ *
9
+ * Exit codes:
10
+ * 0 — diff produced zero affected symbols (risk: LOW or empty diff).
11
+ * 1 — diff produced HIGH or CRITICAL risk. Operators configure CI
12
+ * gates to fail on non-zero.
13
+ * Any risk tier MEDIUM or below stays on exit 0 so informational runs
14
+ * are non-blocking.
15
+ */
16
+ import { runDetectChanges } from "@opencodehub/analysis";
17
+ import { openStoreForCommand } from "./open-store.js";
18
+ export async function runDetectChangesCmd(opts = {}) {
19
+ const scope = opts.scope ?? "all";
20
+ if (scope === "compare" && (opts.compareRef === undefined || opts.compareRef.length === 0)) {
21
+ console.error("codehub detect-changes: --scope=compare requires --compare-ref <git-ref> (e.g. origin/main)");
22
+ process.exitCode = 2;
23
+ return;
24
+ }
25
+ const { store, repoPath } = await openStoreForCommand(opts);
26
+ try {
27
+ const q = { scope, repoPath };
28
+ if (opts.compareRef !== undefined)
29
+ q.compareRef = opts.compareRef;
30
+ const result = await runDetectChanges(store.graph, q);
31
+ if (opts.json) {
32
+ console.log(JSON.stringify(result, null, 2));
33
+ }
34
+ else {
35
+ const { summary, changedFiles, affectedSymbols, affectedProcesses } = result;
36
+ console.log(`detect-changes: ${summary.fileCount} file(s), ${summary.symbolCount} symbol(s), ${summary.processCount} process(es) affected. Risk: ${summary.risk}.`);
37
+ if (changedFiles.length > 0) {
38
+ console.log("Changed files:");
39
+ for (const f of changedFiles.slice(0, 30))
40
+ console.log(` • ${f}`);
41
+ if (changedFiles.length > 30) {
42
+ console.log(` … ${changedFiles.length - 30} more`);
43
+ }
44
+ }
45
+ if (affectedSymbols.length > 0) {
46
+ console.log(`Affected symbols (${affectedSymbols.length}):`);
47
+ for (const s of affectedSymbols.slice(0, 50)) {
48
+ console.log(` • ${s.name} [${s.kind}] — ${s.filePath}`);
49
+ }
50
+ if (affectedSymbols.length > 50) {
51
+ console.log(` … ${affectedSymbols.length - 50} more`);
52
+ }
53
+ }
54
+ if (affectedProcesses.length > 0) {
55
+ console.log(`Affected processes (${affectedProcesses.length}):`);
56
+ for (const p of affectedProcesses) {
57
+ console.log(` ⊿ ${p.name} — ${p.entryPointFile}`);
58
+ }
59
+ }
60
+ }
61
+ const risk = result.summary.risk;
62
+ const blockOn = opts.strict
63
+ ? new Set(["MEDIUM", "HIGH", "CRITICAL"])
64
+ : new Set(["HIGH", "CRITICAL"]);
65
+ if (blockOn.has(risk)) {
66
+ process.exitCode = 1;
67
+ }
68
+ }
69
+ finally {
70
+ await store.close();
71
+ }
72
+ }
73
+ //# sourceMappingURL=detect-changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-changes.js","sourceRoot":"","sources":["../../src/commands/detect-changes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `codehub doctor` — environment probe.
3
+ *
4
+ * Runs every `Check` registered in `CHECKS`, prints a table, and exits
5
+ * with a status code that maps to the worst result seen:
6
+ *
7
+ * 0 all ok
8
+ * 1 at least one warn (non-blocking)
9
+ * 2 at least one fail (blocking — something is broken)
10
+ *
11
+ * Checks are strictly diagnostic — they never auto-heal. Each one returns
12
+ * a `hint` string the user can copy-paste when things are off.
13
+ */
14
+ export type CheckStatus = "ok" | "warn" | "fail";
15
+ export interface CheckResult {
16
+ readonly status: CheckStatus;
17
+ readonly message: string;
18
+ readonly hint?: string;
19
+ }
20
+ export interface Check {
21
+ readonly name: string;
22
+ run(): Promise<CheckResult>;
23
+ }
24
+ export interface DoctorOptions {
25
+ /** Override HOME so tests can point at a fake dotdir. */
26
+ readonly home?: string;
27
+ /** Skip checks that rely on native bindings (e.g. in CI sandboxes). */
28
+ readonly skipNative?: boolean;
29
+ /** Override the repo root when resolving workspace packages. */
30
+ readonly repoRoot?: string;
31
+ }
32
+ export interface DoctorReport {
33
+ readonly rows: readonly {
34
+ readonly name: string;
35
+ readonly result: CheckResult;
36
+ }[];
37
+ readonly exitCode: 0 | 1 | 2;
38
+ }
39
+ /**
40
+ * Entry point invoked by `codehub doctor`. Prints the table and sets
41
+ * `process.exitCode`. Also returns the structured report so tests and
42
+ * acceptance scripts can assert the outcome without parsing stdout.
43
+ */
44
+ export declare function runDoctor(opts?: DoctorOptions): Promise<DoctorReport>;
45
+ /**
46
+ * Ordered list of environment probes. Order matters only for the output
47
+ * table — runs are independent, but we surface foundational checks first
48
+ * (Node, pnpm, native bindings) so the user can fix a broken foundation
49
+ * before worrying about downstream extras.
50
+ */
51
+ export declare function buildChecks(opts?: DoctorOptions): readonly Check[];
52
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,CAAC;IAClF,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CA2B/E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,GAAE,aAAkB,GAAG,SAAS,KAAK,EAAE,CA2CtE"}