@specverse/engines 6.0.8 → 6.0.10

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.
@@ -0,0 +1,109 @@
1
+ import type { StructuralPrepass, Symbol, Import, FileFilter, ClassFilter, MethodFilter, InterfaceFilter, IndexResult, MethodFactSheet } from '../interface.js';
2
+ export interface GitNexusBackendOptions {
3
+ /** Path to the gitnexus binary. Auto-detected via PATH if omitted. */
4
+ gitnexusPath?: string;
5
+ /** Skip running `gitnexus analyze` if .gitnexus/ already exists. */
6
+ reuseExistingIndex?: boolean;
7
+ }
8
+ export declare class GitNexusBackend implements StructuralPrepass {
9
+ private sourceDir;
10
+ /**
11
+ * Canonical repo name as registered in `~/.gitnexus/registry.json`.
12
+ * Resolved by `init()` from the registry; passed as `--repo <name>`
13
+ * to every `gitnexus cypher` call so multi-repo registries don't
14
+ * cross-contaminate query results.
15
+ */
16
+ private repoName;
17
+ private gitnexusPath;
18
+ private reuseExistingIndex;
19
+ capabilities: {
20
+ callGraph: boolean;
21
+ crossFileResolution: boolean;
22
+ componentClustering: boolean;
23
+ fullTextSearch: boolean;
24
+ fileWatching: boolean;
25
+ };
26
+ constructor(options?: GitNexusBackendOptions);
27
+ static isAvailable(): boolean;
28
+ init(sourceDir: string): Promise<void>;
29
+ /**
30
+ * Resolve a sourceDir to its canonical gitnexus repo name by reading
31
+ * `~/.gitnexus/registry.json`. Falls back to the dir's basename if the
32
+ * registry isn't readable or has no matching entry — but a basename
33
+ * fallback is unsafe in multi-repo registries (it can collide with
34
+ * another project that happens to have the same dir name), so we log
35
+ * a warning to stderr in that case.
36
+ */
37
+ private resolveRepoName;
38
+ index(): Promise<IndexResult>;
39
+ listFiles(filter?: FileFilter): Promise<string[]>;
40
+ listClasses(filter?: ClassFilter): Promise<Symbol[]>;
41
+ listMethods(filter?: MethodFilter): Promise<Symbol[]>;
42
+ listInterfaces(filter?: InterfaceFilter): Promise<Symbol[]>;
43
+ listImports(file: string): Promise<Import[]>;
44
+ fileSourceText(file: string): Promise<string>;
45
+ callers(symbol: string): Promise<Symbol[]>;
46
+ callees(symbol: string): Promise<Symbol[]>;
47
+ /**
48
+ * Cluster files via GitNexus's Leiden community detection.
49
+ * This is the distinguishing feature vs CodeGraph — surfaces natural
50
+ * component boundaries for SpecVerse `components:` inference.
51
+ *
52
+ * GitNexus's edge model: a single `CodeRelation` table with a `type`
53
+ * property — relationship discrimination happens via WHERE on that
54
+ * property, not by edge label. Community membership is `MEMBER_OF`.
55
+ *
56
+ * Note: GitNexus's MEMBER_OF connects symbols (not files directly) to
57
+ * communities. We aggregate per-community by filePath of the member symbols.
58
+ */
59
+ clusterFiles(): Promise<Array<{
60
+ id: string;
61
+ files: string[];
62
+ }>>;
63
+ /**
64
+ * GitNexus's call graph traversal — same `CodeRelation` table pattern
65
+ * as MEMBER_OF, with `type='CALLS'` as the discriminating property.
66
+ * (Override the default callers/callees from the parent class above
67
+ * because the relation type isn't `:CALLS` — it's `:CodeRelation` with
68
+ * a property filter.)
69
+ */
70
+ getMethodDetails(qualifiedName: string): Promise<MethodFactSheet | null>;
71
+ /**
72
+ * Run a Cypher query via the `gitnexus cypher` CLI and parse the
73
+ * markdown-table output into a row array. Each row is a map of
74
+ * column name → value (string, number, or array depending on Cypher).
75
+ *
76
+ * Passes `--repo <name>` to disambiguate when multiple repos are
77
+ * registered globally. The name comes from `~/.gitnexus/registry.json`
78
+ * (resolved by `init()`), NOT the basename of sourceDir — the basename
79
+ * is unsafe because gitnexus derives the registered name from the git
80
+ * remote / package.json, which usually differs from the dir name
81
+ * (e.g. clones into `./source/` register as `nestjs-realworld-example-app`).
82
+ */
83
+ private cypher;
84
+ private rowToSymbol;
85
+ private mapLabel;
86
+ private toRelativePath;
87
+ private escape;
88
+ private detectBinary;
89
+ }
90
+ /**
91
+ * Extract the basename of a sourceDir for fallback-naming. `/foo/bar/source/`
92
+ * → `source`. Empty path → `source` (the gitnexus default for unnamed dirs).
93
+ */
94
+ export declare function basenameOrSource(sourceDir: string): string;
95
+ /**
96
+ * Pure-function version of the registry-lookup logic — takes the registry
97
+ * file content + the sourceDir and returns the canonical name (or null if
98
+ * not found, plus an optional warning). Exported for unit testing without
99
+ * needing gitnexus installed or a real ~/.gitnexus directory.
100
+ *
101
+ * Match order:
102
+ * 1. Exact `path === sourceDir`
103
+ * 2. `storagePath` is inside sourceDir (handles symlink-resolved paths)
104
+ */
105
+ export declare function resolveRepoNameFromRegistry(registryContent: string, sourceDir: string): {
106
+ name: string | null;
107
+ warning: string | null;
108
+ };
109
+ //# sourceMappingURL=gitnexus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitnexus.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/gitnexus.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAYzB,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,qBAAa,eAAgB,YAAW,iBAAiB;IACvD,OAAO,CAAC,SAAS,CAAM;IACvB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,kBAAkB,CAAU;IAEpC,YAAY;;;;;;MAMV;gBAEU,OAAO,GAAE,sBAA2B;IAKhD,MAAM,CAAC,WAAW,IAAI,OAAO;IASvB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB5C;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAkBjB,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAqB7B,SAAS,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcjD,WAAW,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAYpD,WAAW,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA4BrD,cAAc,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAY3D,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAY5C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAM1C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMhD;;;;;;;;;;;OAWG;IACG,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IASrE;;;;;;OAMG;IAEG,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA0C9E;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,MAAM;IA2Bd,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,YAAY;CASrB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,MAAM,GAChB;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAuBjD"}
@@ -0,0 +1,453 @@
1
+ /**
2
+ * GitNexus backend — `StructuralPrepass` against `gitnexus` CLI.
3
+ *
4
+ * GitNexus indexes a codebase into a graph (LadybugDB) with tree-sitter
5
+ * symbol extraction + cross-file resolution + Leiden community detection.
6
+ * It exposes Cypher queries via the `gitnexus cypher <query>` CLI command,
7
+ * which returns JSON with a markdown-table inner format. We shell out to
8
+ * the CLI and parse the markdown table.
9
+ *
10
+ * The distinguishing capability vs CodeGraph is `clusterFiles()` — GitNexus
11
+ * tracks `Community` nodes (via Leiden community detection on the call graph)
12
+ * which give natural component-boundary suggestions for SpecVerse `components:`.
13
+ *
14
+ * Storage: GitNexus stores per-repo data in `.gitnexus/` and a global
15
+ * registry pointer at `~/.gitnexus/`. Like CodeGraph, indexing happens once;
16
+ * subsequent queries hit the persistent index.
17
+ */
18
+ import { execSync, execFileSync } from 'child_process';
19
+ import { existsSync, readFileSync } from 'fs';
20
+ import { homedir } from 'os';
21
+ import { join } from 'path';
22
+ import { walkSourceTree, detectLanguage, globToRegex } from './walk.js';
23
+ import { extractEmits, extractDbWrites, extractExternalCalls, extractThrows, extractAsyncBoundaries, countBranchPoints, sliceBody, } from './method-patterns.js';
24
+ export class GitNexusBackend {
25
+ sourceDir = '';
26
+ /**
27
+ * Canonical repo name as registered in `~/.gitnexus/registry.json`.
28
+ * Resolved by `init()` from the registry; passed as `--repo <name>`
29
+ * to every `gitnexus cypher` call so multi-repo registries don't
30
+ * cross-contaminate query results.
31
+ */
32
+ repoName = '';
33
+ gitnexusPath;
34
+ reuseExistingIndex;
35
+ capabilities = {
36
+ callGraph: true,
37
+ crossFileResolution: true,
38
+ componentClustering: true, // Leiden community detection (the differentiator)
39
+ fullTextSearch: true, // hybrid BM25 + semantic + RRF
40
+ fileWatching: false, // GitNexus doesn't auto-sync; needs explicit re-analyze
41
+ };
42
+ constructor(options = {}) {
43
+ this.gitnexusPath = options.gitnexusPath ?? this.detectBinary('gitnexus');
44
+ this.reuseExistingIndex = options.reuseExistingIndex ?? false;
45
+ }
46
+ static isAvailable() {
47
+ try {
48
+ execSync('gitnexus --version', { stdio: 'ignore', timeout: 5000 });
49
+ return true;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ async init(sourceDir) {
56
+ this.sourceDir = sourceDir;
57
+ const gitnexusDir = join(sourceDir, '.gitnexus');
58
+ if (!this.reuseExistingIndex || !existsSync(gitnexusDir)) {
59
+ // Run `gitnexus analyze` to build the index. --skip-git lets us index
60
+ // arbitrary directories (like our realized backends in /private/tmp).
61
+ if (!existsSync(gitnexusDir)) {
62
+ execSync(`${this.gitnexusPath} analyze --skip-git .`, {
63
+ cwd: sourceDir,
64
+ stdio: 'ignore',
65
+ timeout: 600_000,
66
+ });
67
+ }
68
+ }
69
+ // Resolve the canonical repo name from the gitnexus registry. The
70
+ // registry is the authoritative mapping of source paths → repo names
71
+ // (gitnexus derives `name` from the git remote, the `package.json`,
72
+ // or the dir basename — we don't replicate that logic, just look it up).
73
+ this.repoName = this.resolveRepoName(sourceDir);
74
+ }
75
+ /**
76
+ * Resolve a sourceDir to its canonical gitnexus repo name by reading
77
+ * `~/.gitnexus/registry.json`. Falls back to the dir's basename if the
78
+ * registry isn't readable or has no matching entry — but a basename
79
+ * fallback is unsafe in multi-repo registries (it can collide with
80
+ * another project that happens to have the same dir name), so we log
81
+ * a warning to stderr in that case.
82
+ */
83
+ resolveRepoName(sourceDir) {
84
+ const registryPath = join(homedir(), '.gitnexus', 'registry.json');
85
+ const fallback = basenameOrSource(sourceDir);
86
+ if (!existsSync(registryPath))
87
+ return fallback;
88
+ let registryContent;
89
+ try {
90
+ registryContent = readFileSync(registryPath, 'utf8');
91
+ }
92
+ catch (err) {
93
+ process.stderr.write(`[gitnexus-backend] failed to read registry: ${err.message}; using basename fallback "${fallback}".\n`);
94
+ return fallback;
95
+ }
96
+ const result = resolveRepoNameFromRegistry(registryContent, sourceDir);
97
+ if (result.warning)
98
+ process.stderr.write(`[gitnexus-backend] ${result.warning}\n`);
99
+ return result.name ?? fallback;
100
+ }
101
+ async index() {
102
+ const start = Date.now();
103
+ if (!existsSync(join(this.sourceDir, '.gitnexus'))) {
104
+ execSync(`${this.gitnexusPath} analyze --skip-git .`, {
105
+ cwd: this.sourceDir,
106
+ stdio: 'ignore',
107
+ timeout: 600_000,
108
+ });
109
+ }
110
+ // GitNexus prints stats during analyze; query for them via Cypher
111
+ const rows = this.cypher('MATCH (n) RETURN count(*) AS c');
112
+ const totalNodes = rows.length > 0 ? Number(rows[0].c) : 0;
113
+ const fileRows = this.cypher('MATCH (n:File) RETURN count(*) AS c');
114
+ const fileCount = fileRows.length > 0 ? Number(fileRows[0].c) : 0;
115
+ return {
116
+ files: fileCount,
117
+ symbols: totalNodes - fileCount,
118
+ durationMs: Date.now() - start,
119
+ };
120
+ }
121
+ async listFiles(filter) {
122
+ // Same pattern as CodeGraph backend — FS walk, not the index, so adapters
123
+ // can find arbitrary file types (schema.prisma, package.json, etc.) the
124
+ // tree-sitter indexer doesn't track.
125
+ let result = walkSourceTree(this.sourceDir);
126
+ if (filter?.dir)
127
+ result = result.filter((f) => f.startsWith(filter.dir));
128
+ if (filter?.lang)
129
+ result = result.filter((f) => detectLanguage(f) === filter.lang);
130
+ if (filter?.glob) {
131
+ const re = globToRegex(filter.glob);
132
+ result = result.filter((f) => re.test(f));
133
+ }
134
+ return result;
135
+ }
136
+ async listClasses(filter) {
137
+ let cypher = `MATCH (n:Class) RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
138
+ if (filter?.dir) {
139
+ const rel = this.toRelativePath(filter.dir);
140
+ cypher = `MATCH (n:Class) WHERE n.filePath STARTS WITH '${this.escape(rel)}' RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
141
+ }
142
+ const rows = this.cypher(cypher);
143
+ return rows
144
+ .filter((r) => !filter?.namePattern || filter.namePattern.test(r.name))
145
+ .map((r) => this.rowToSymbol(r, 'class'));
146
+ }
147
+ async listMethods(filter) {
148
+ // GitNexus doesn't store class membership as a property; we derive it
149
+ // from the Method node's `name` plus filePath. For the `class` filter,
150
+ // we scope by the class's file path range.
151
+ let cypher = `MATCH (n:Method) RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
152
+ if (filter?.class) {
153
+ // Find the class's file + line range first, then filter methods by it.
154
+ const classRows = this.cypher(`MATCH (c:Class {name: '${this.escape(filter.class)}'}) RETURN c.filePath AS filePath, c.startLine AS startLine, c.endLine AS endLine LIMIT 1`);
155
+ if (classRows.length === 0)
156
+ return [];
157
+ const cls = classRows[0];
158
+ cypher = `MATCH (n:Method) WHERE n.filePath = '${this.escape(cls.filePath)}' AND n.startLine >= ${Number(cls.startLine)} AND n.startLine <= ${Number(cls.endLine)} RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
159
+ }
160
+ const rows = this.cypher(cypher);
161
+ let methods = rows.map((r) => {
162
+ const sym = this.rowToSymbol(r, 'method');
163
+ // Approximate qualifiedName: ClassName.methodName when class context is known
164
+ if (filter?.class)
165
+ sym.qualifiedName = `${filter.class}.${sym.name}`;
166
+ return sym;
167
+ });
168
+ if (filter?.nameIn && filter.nameIn.length > 0) {
169
+ const allowedNames = new Set(filter.nameIn);
170
+ methods = methods.filter((m) => allowedNames.has(m.name));
171
+ }
172
+ return methods;
173
+ }
174
+ async listInterfaces(filter) {
175
+ let cypher = `MATCH (n:Interface) RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
176
+ if (filter?.dir) {
177
+ const rel = this.toRelativePath(filter.dir);
178
+ cypher = `MATCH (n:Interface) WHERE n.filePath STARTS WITH '${this.escape(rel)}' RETURN n.name AS name, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine, n.isExported AS isExported`;
179
+ }
180
+ const rows = this.cypher(cypher);
181
+ return rows
182
+ .filter((r) => !filter?.namePattern || filter.namePattern.test(r.name))
183
+ .map((r) => this.rowToSymbol(r, 'interface'));
184
+ }
185
+ async listImports(file) {
186
+ // GitNexus tracks imports via CodeRelation edges with type='IMPORTS'.
187
+ const rel = this.toRelativePath(file);
188
+ const cypher = `MATCH (f:File {filePath: '${this.escape(rel)}'})-[:CodeRelation {type: "IMPORTS"}]->(target) RETURN target.name AS name, target.filePath AS targetPath`;
189
+ const rows = this.cypher(cypher);
190
+ return rows.map((r) => ({
191
+ fromFile: file,
192
+ toModule: r.targetPath || r.name,
193
+ symbols: [r.name],
194
+ }));
195
+ }
196
+ async fileSourceText(file) {
197
+ return readFileSync(file, 'utf8');
198
+ }
199
+ async callers(symbol) {
200
+ const cypher = `MATCH (caller)-[:CodeRelation {type: "CALLS"}]->(callee) WHERE callee.name = '${this.escape(symbol)}' RETURN caller.name AS name, caller.filePath AS filePath, caller.startLine AS startLine, caller.endLine AS endLine, labels(caller)[0] AS kind LIMIT 100`;
201
+ const rows = this.cypher(cypher);
202
+ return rows.map((r) => this.rowToSymbol(r, this.mapLabel(r.kind)));
203
+ }
204
+ async callees(symbol) {
205
+ const cypher = `MATCH (caller)-[:CodeRelation {type: "CALLS"}]->(callee) WHERE caller.name = '${this.escape(symbol)}' RETURN callee.name AS name, callee.filePath AS filePath, callee.startLine AS startLine, callee.endLine AS endLine, labels(callee)[0] AS kind LIMIT 100`;
206
+ const rows = this.cypher(cypher);
207
+ return rows.map((r) => this.rowToSymbol(r, this.mapLabel(r.kind)));
208
+ }
209
+ /**
210
+ * Cluster files via GitNexus's Leiden community detection.
211
+ * This is the distinguishing feature vs CodeGraph — surfaces natural
212
+ * component boundaries for SpecVerse `components:` inference.
213
+ *
214
+ * GitNexus's edge model: a single `CodeRelation` table with a `type`
215
+ * property — relationship discrimination happens via WHERE on that
216
+ * property, not by edge label. Community membership is `MEMBER_OF`.
217
+ *
218
+ * Note: GitNexus's MEMBER_OF connects symbols (not files directly) to
219
+ * communities. We aggregate per-community by filePath of the member symbols.
220
+ */
221
+ async clusterFiles() {
222
+ const cypher = `MATCH (member)-[:CodeRelation {type: "MEMBER_OF"}]->(c:Community) RETURN c.id AS id, c.heuristicLabel AS label, collect(DISTINCT member.filePath) AS files`;
223
+ const rows = this.cypher(cypher);
224
+ return rows.map((r) => ({
225
+ id: String(r.label || r.id || 'unnamed'),
226
+ files: Array.isArray(r.files) ? r.files.filter(Boolean) : [],
227
+ }));
228
+ }
229
+ /**
230
+ * GitNexus's call graph traversal — same `CodeRelation` table pattern
231
+ * as MEMBER_OF, with `type='CALLS'` as the discriminating property.
232
+ * (Override the default callers/callees from the parent class above
233
+ * because the relation type isn't `:CALLS` — it's `:CodeRelation` with
234
+ * a property filter.)
235
+ */
236
+ async getMethodDetails(qualifiedName) {
237
+ const lastDot = qualifiedName.lastIndexOf('.');
238
+ if (lastDot < 0)
239
+ return null;
240
+ const className = qualifiedName.slice(0, lastDot);
241
+ const methodName = qualifiedName.slice(lastDot + 1);
242
+ // Find the method via class-scoped query
243
+ const methods = await this.listMethods({ class: className, nameIn: [methodName] });
244
+ if (methods.length === 0)
245
+ return null;
246
+ const method = methods[0];
247
+ const fileText = readFileSync(method.filePath, 'utf8');
248
+ const fileLines = fileText.split('\n');
249
+ const bodyLines = fileLines.slice(method.startLine - 1, method.endLine);
250
+ const body = bodyLines.join('\n');
251
+ // Calls — use the call graph (GitNexus's strength like CodeGraph's)
252
+ const calls = await this.callees(qualifiedName);
253
+ return {
254
+ qualifiedName,
255
+ signature: method.signature ?? '',
256
+ body,
257
+ filePath: method.filePath,
258
+ startLine: method.startLine,
259
+ endLine: method.endLine,
260
+ language: method.language,
261
+ calls,
262
+ emits: extractEmits(body),
263
+ dbWrites: extractDbWrites(body),
264
+ externalCalls: extractExternalCalls(body),
265
+ throws: extractThrows(body),
266
+ asyncBoundaries: extractAsyncBoundaries(body),
267
+ branchPoints: countBranchPoints(body),
268
+ bodyTextSliced: sliceBody(body),
269
+ };
270
+ }
271
+ // ────────────────────────────────────────────────────────────────────
272
+ // Internals
273
+ // ────────────────────────────────────────────────────────────────────
274
+ /**
275
+ * Run a Cypher query via the `gitnexus cypher` CLI and parse the
276
+ * markdown-table output into a row array. Each row is a map of
277
+ * column name → value (string, number, or array depending on Cypher).
278
+ *
279
+ * Passes `--repo <name>` to disambiguate when multiple repos are
280
+ * registered globally. The name comes from `~/.gitnexus/registry.json`
281
+ * (resolved by `init()`), NOT the basename of sourceDir — the basename
282
+ * is unsafe because gitnexus derives the registered name from the git
283
+ * remote / package.json, which usually differs from the dir name
284
+ * (e.g. clones into `./source/` register as `nestjs-realworld-example-app`).
285
+ */
286
+ cypher(query) {
287
+ if (!this.repoName) {
288
+ throw new Error('[gitnexus-backend] repoName not set — did you call init() before querying? ' +
289
+ 'init() resolves the canonical repo name from ~/.gitnexus/registry.json.');
290
+ }
291
+ const stdout = execFileSync(this.gitnexusPath, ['cypher', '--repo', this.repoName, query], {
292
+ cwd: this.sourceDir,
293
+ encoding: 'utf8',
294
+ timeout: 60_000,
295
+ maxBuffer: 50 * 1024 * 1024,
296
+ });
297
+ if (!stdout.trim())
298
+ return [];
299
+ let payload;
300
+ try {
301
+ payload = JSON.parse(stdout);
302
+ }
303
+ catch {
304
+ throw new Error(`gitnexus cypher: failed to parse JSON output:\n${stdout.slice(0, 500)}`);
305
+ }
306
+ if (payload.error) {
307
+ throw new Error(`gitnexus cypher error: ${payload.error}`);
308
+ }
309
+ if (!payload.markdown)
310
+ return [];
311
+ return parseMarkdownTable(payload.markdown);
312
+ }
313
+ rowToSymbol(row, kind) {
314
+ const filePath = String(row.filePath || '');
315
+ const absPath = filePath.startsWith('/') ? filePath : join(this.sourceDir, filePath);
316
+ return {
317
+ kind,
318
+ name: String(row.name),
319
+ qualifiedName: String(row.name), // GitNexus's qualified IDs are colon-separated; we use plain name for now
320
+ filePath: absPath,
321
+ startLine: Number(row.startLine ?? 0),
322
+ endLine: Number(row.endLine ?? 0),
323
+ signature: row.signature ?? undefined,
324
+ docstring: row.docstring ?? undefined,
325
+ isExported: row.isExported === 'true' || row.isExported === true,
326
+ language: detectLanguage(absPath) || 'unknown',
327
+ };
328
+ }
329
+ mapLabel(label) {
330
+ switch (label) {
331
+ case 'Class': return 'class';
332
+ case 'Method': return 'method';
333
+ case 'Function': return 'function';
334
+ case 'Interface': return 'interface';
335
+ case 'Const': return 'constant';
336
+ default: return 'function';
337
+ }
338
+ }
339
+ toRelativePath(p) {
340
+ return p.startsWith(this.sourceDir)
341
+ ? p.slice(this.sourceDir.length).replace(/^\//, '')
342
+ : p;
343
+ }
344
+ escape(s) {
345
+ return s.replace(/'/g, "\\'");
346
+ }
347
+ detectBinary(name) {
348
+ try {
349
+ const path = execSync(`which ${name}`, { encoding: 'utf8', timeout: 3000 }).trim();
350
+ if (path)
351
+ return path;
352
+ }
353
+ catch {
354
+ // Fall through
355
+ }
356
+ return name;
357
+ }
358
+ }
359
+ /**
360
+ * Extract the basename of a sourceDir for fallback-naming. `/foo/bar/source/`
361
+ * → `source`. Empty path → `source` (the gitnexus default for unnamed dirs).
362
+ */
363
+ export function basenameOrSource(sourceDir) {
364
+ return sourceDir.split('/').filter(Boolean).pop() || 'source';
365
+ }
366
+ /**
367
+ * Pure-function version of the registry-lookup logic — takes the registry
368
+ * file content + the sourceDir and returns the canonical name (or null if
369
+ * not found, plus an optional warning). Exported for unit testing without
370
+ * needing gitnexus installed or a real ~/.gitnexus directory.
371
+ *
372
+ * Match order:
373
+ * 1. Exact `path === sourceDir`
374
+ * 2. `storagePath` is inside sourceDir (handles symlink-resolved paths)
375
+ */
376
+ export function resolveRepoNameFromRegistry(registryContent, sourceDir) {
377
+ let entries;
378
+ try {
379
+ entries = JSON.parse(registryContent);
380
+ }
381
+ catch (err) {
382
+ return {
383
+ name: null,
384
+ warning: `failed to parse registry JSON: ${err.message}`,
385
+ };
386
+ }
387
+ if (!Array.isArray(entries)) {
388
+ return { name: null, warning: 'registry is not an array' };
389
+ }
390
+ const match = entries.find((e) => e.path === sourceDir) ??
391
+ entries.find((e) => e.storagePath?.startsWith(sourceDir + '/'));
392
+ if (match)
393
+ return { name: match.name, warning: null };
394
+ return {
395
+ name: null,
396
+ warning: `no registry entry for ${sourceDir}; using basename fallback. ` +
397
+ `Multi-repo queries may cross-contaminate.`,
398
+ };
399
+ }
400
+ /**
401
+ * Parse a GitHub-flavored markdown table into a row array.
402
+ *
403
+ * Input shape:
404
+ * | col1 | col2 |
405
+ * | --- | --- |
406
+ * | val1 | val2 |
407
+ *
408
+ * Returns: [ { col1: 'val1', col2: 'val2' }, ... ]
409
+ *
410
+ * Cell values are strings; callers can convert to number/boolean/JSON
411
+ * as needed. Cells starting with `[` are parsed as JSON arrays
412
+ * (GitNexus's `collect()` returns arrays in markdown form).
413
+ */
414
+ function parseMarkdownTable(md) {
415
+ const lines = md.split('\n').filter((l) => l.trim().length > 0);
416
+ if (lines.length < 2)
417
+ return [];
418
+ const headerLine = lines[0];
419
+ const headers = headerLine
420
+ .split('|')
421
+ .map((s) => s.trim())
422
+ .filter(Boolean);
423
+ // Skip the separator row (---|---|---)
424
+ const rows = [];
425
+ for (let i = 2; i < lines.length; i++) {
426
+ const cells = lines[i]
427
+ .split('|')
428
+ .map((s) => s.trim())
429
+ .filter((_, idx, arr) => idx > 0 && idx < arr.length - 1 || arr.length === headers.length);
430
+ // Sometimes the leading/trailing | are missing — fall back to a permissive split.
431
+ const rawCells = lines[i].split('|');
432
+ const cleaned = rawCells.length === headers.length + 2
433
+ ? rawCells.slice(1, -1).map((s) => s.trim())
434
+ : rawCells.map((s) => s.trim()).filter(Boolean);
435
+ const row = {};
436
+ for (let j = 0; j < headers.length; j++) {
437
+ let val = cleaned[j] ?? '';
438
+ // Try to parse JSON arrays (collect() output)
439
+ if (typeof val === 'string' && val.startsWith('[') && val.endsWith(']')) {
440
+ try {
441
+ val = JSON.parse(val);
442
+ }
443
+ catch {
444
+ // leave as string
445
+ }
446
+ }
447
+ row[headers[j]] = val;
448
+ }
449
+ rows.push(row);
450
+ }
451
+ return rows;
452
+ }
453
+ //# sourceMappingURL=gitnexus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitnexus.js","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/gitnexus.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,28 @@
1
1
  /**
2
2
  * Backend selector — picks the best available `StructuralPrepass`.
3
3
  *
4
- * Order: codegraph (if available) → grep-only (always works).
5
- * GitNexus to be added later.
4
+ * Order: gitnexus (if available + opted-in) → codegraph (if available)
5
+ * grep-only (always works).
6
+ *
7
+ * GitNexus is more invasive (heavier stack, longer index time) but provides
8
+ * Leiden community detection (clusterFiles capability) which can help with
9
+ * multi-component codebases. Default `auto` prefers CodeGraph for the
10
+ * smaller-footprint case; explicitly request `gitnexus` for clustering.
6
11
  */
7
12
  import type { StructuralPrepass } from '../interface.js';
8
13
  import { GrepOnlyBackend } from './grep-only.js';
9
14
  import { CodeGraphBackend } from './codegraph.js';
10
- export { GrepOnlyBackend, CodeGraphBackend };
11
- export type BackendName = 'codegraph' | 'grep-only' | 'auto';
15
+ import { GitNexusBackend } from './gitnexus.js';
16
+ export { GrepOnlyBackend, CodeGraphBackend, GitNexusBackend };
17
+ export type BackendName = 'codegraph' | 'gitnexus' | 'grep-only' | 'auto';
12
18
  /**
13
- * Select a backend by name, or auto-pick the richest available.
19
+ * Select a backend by name, or auto-pick a sensible default.
14
20
  *
15
21
  * `auto` semantics:
16
- * - CodeGraph + sqlite3 both available → CodeGraph (richer, has call graph)
22
+ * - CodeGraph + sqlite3 both available → CodeGraph (lighter; richest baseline)
17
23
  * - Otherwise → grep-only (always works, no external tools)
24
+ * - Note: GitNexus is NOT auto-selected even when available, because its
25
+ * index overhead is significant. Explicit opt-in via name='gitnexus'.
18
26
  */
19
27
  export declare function selectBackend(name?: BackendName): StructuralPrepass;
20
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;AAE7D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,WAAoB,GAAG,iBAAiB,CAiB3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAE9D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;AAE1E;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAE,WAAoB,GAAG,iBAAiB,CAyB3E"}
@@ -1,12 +1,15 @@
1
1
  import { GrepOnlyBackend } from './grep-only.js';
2
2
  import { CodeGraphBackend } from './codegraph.js';
3
- export { GrepOnlyBackend, CodeGraphBackend };
3
+ import { GitNexusBackend } from './gitnexus.js';
4
+ export { GrepOnlyBackend, CodeGraphBackend, GitNexusBackend };
4
5
  /**
5
- * Select a backend by name, or auto-pick the richest available.
6
+ * Select a backend by name, or auto-pick a sensible default.
6
7
  *
7
8
  * `auto` semantics:
8
- * - CodeGraph + sqlite3 both available → CodeGraph (richer, has call graph)
9
+ * - CodeGraph + sqlite3 both available → CodeGraph (lighter; richest baseline)
9
10
  * - Otherwise → grep-only (always works, no external tools)
11
+ * - Note: GitNexus is NOT auto-selected even when available, because its
12
+ * index overhead is significant. Explicit opt-in via name='gitnexus'.
10
13
  */
11
14
  export function selectBackend(name = 'auto') {
12
15
  if (name === 'codegraph') {
@@ -15,10 +18,16 @@ export function selectBackend(name = 'auto') {
15
18
  }
16
19
  return new CodeGraphBackend();
17
20
  }
21
+ if (name === 'gitnexus') {
22
+ if (!GitNexusBackend.isAvailable()) {
23
+ throw new Error('GitNexus backend requested but not available. Install with `npm i -g gitnexus`.');
24
+ }
25
+ return new GitNexusBackend();
26
+ }
18
27
  if (name === 'grep-only') {
19
28
  return new GrepOnlyBackend();
20
29
  }
21
- // auto
30
+ // auto — prefer CodeGraph (lighter, fast); GitNexus stays opt-in.
22
31
  if (CodeGraphBackend.isAvailable()) {
23
32
  return new CodeGraphBackend();
24
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC;AAI7C;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,OAAoB,MAAM;IACtD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,+HAA+H,CAChI,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,IAAI,eAAe,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO;IACP,IAAI,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analyse-prepass/backends/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAI9D;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,OAAoB,MAAM;IACtD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,+HAA+H,CAChI,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChC,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,eAAe,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,IAAI,eAAe,EAAE,CAAC;IAC/B,CAAC;IACD,kEAAkE;IAClE,IAAI,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC;QACnC,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,eAAe,EAAE,CAAC;AAC/B,CAAC"}
@@ -14,7 +14,7 @@
14
14
  * // facts.entities, facts.relationships, facts.lifecycles, ...
15
15
  */
16
16
  export type { StructuralPrepass, Symbol, Import, Capabilities, FileFilter, ClassFilter, MethodFilter, InterfaceFilter, IndexResult, MethodFactSheet, } from './interface.js';
17
- export { GrepOnlyBackend, CodeGraphBackend, selectBackend, type BackendName, } from './backends/index.js';
17
+ export { GrepOnlyBackend, CodeGraphBackend, GitNexusBackend, selectBackend, type BackendName, } from './backends/index.js';
18
18
  export { extractTypeScriptPrisma, type PrismaFacts, type PrismaEntity, type PrismaField, type PrismaRelation, } from './adapters/index.js';
19
19
  import { type BackendName } from './backends/index.js';
20
20
  import type { StructuralPrepass } from './interface.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,+CAA+C;IAC/C,aAAa,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;QACzC,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;IACH,kFAAkF;IAClF,UAAU,EAAE,KAAK,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC,CAAC;IACH,+DAA+D;IAC/D,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7C,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,qEAAqE;IACrE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;CACvC;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyD5G;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA2CnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,uBAAuB,EACvB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,+CAA+C;IAC/C,aAAa,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;QACzC,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;IACH,kFAAkF;IAClF,UAAU,EAAE,KAAK,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC,CAAC;IACH,+DAA+D;IAC/D,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7C,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,qEAAqE;IACrE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;CACvC;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CAyD5G;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA2CnE"}
@@ -1,4 +1,4 @@
1
- export { GrepOnlyBackend, CodeGraphBackend, selectBackend, } from './backends/index.js';
1
+ export { GrepOnlyBackend, CodeGraphBackend, GitNexusBackend, selectBackend, } from './backends/index.js';
2
2
  export { extractTypeScriptPrisma, } from './adapters/index.js';
3
3
  import { selectBackend } from './backends/index.js';
4
4
  import { extractTypeScriptPrisma } from './adapters/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyse-prepass/index.ts"],"names":[],"mappings":"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"}
@@ -374,6 +374,110 @@ import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/ty
374
374
  }
375
375
  const inferredSpec = { ...componentData, componentName, components: inferredYaml?.components || {} };
376
376
 
377
+ // --estimate: report what realize WOULD do, broken down by layer.
378
+ // Skip the actual realizeAll call (no manifest needed, no LLM cost).
379
+ // The three layers:
380
+ // L1 \u2014 Instance factory (templates, no LLM)
381
+ // L2 \u2014 Convention pattern matching (CURVED ops + default events, no LLM)
382
+ // L3 \u2014 AI from steps (one LLM call per declared step)
383
+ if (options.estimate) {
384
+ const components = inferredSpec.components || {};
385
+ const compNames = Object.keys(components);
386
+ let entityCount = 0, controllerCount = 0, serviceCount = 0, eventCount = 0, viewCount = 0;
387
+ let modelBehaviorSteps = 0, controllerActionSteps = 0, serviceOpSteps = 0;
388
+ let modelBehaviorsWithSteps = 0, controllerActionsWithSteps = 0, serviceOpsWithSteps = 0;
389
+ let curvedOpCount = 0;
390
+ const sumSteps = (block: any) => {
391
+ if (!block || typeof block !== 'object') return { ops: 0, opsWithSteps: 0, totalSteps: 0 };
392
+ let ops = 0, opsWithSteps = 0, totalSteps = 0;
393
+ for (const def of Object.values(block)) {
394
+ ops++;
395
+ const steps = (def as any)?.steps;
396
+ if (Array.isArray(steps) && steps.length > 0) {
397
+ opsWithSteps++;
398
+ totalSteps += steps.length;
399
+ }
400
+ }
401
+ return { ops, opsWithSteps, totalSteps };
402
+ };
403
+ for (const compName of compNames) {
404
+ const comp = components[compName] || {};
405
+ const models = comp.models || {};
406
+ const controllers = comp.controllers || {};
407
+ const services = comp.services || {};
408
+ const events = comp.events || {};
409
+ const views = comp.views || {};
410
+ entityCount += Object.keys(models).length;
411
+ controllerCount += Object.keys(controllers).length;
412
+ serviceCount += Object.keys(services).length;
413
+ eventCount += Object.keys(events).length;
414
+ viewCount += Object.keys(views).length;
415
+ for (const m of Object.values(models)) {
416
+ const r = sumSteps((m as any)?.behaviors);
417
+ modelBehaviorsWithSteps += r.opsWithSteps;
418
+ modelBehaviorSteps += r.totalSteps;
419
+ }
420
+ for (const c of Object.values(controllers)) {
421
+ const r = sumSteps((c as any)?.actions);
422
+ controllerActionsWithSteps += r.opsWithSteps;
423
+ controllerActionSteps += r.totalSteps;
424
+ const cured = (c as any)?.cured || (c as any)?.curved;
425
+ if (cured && typeof cured === 'object') curvedOpCount += Object.keys(cured).length;
426
+ }
427
+ for (const s of Object.values(services)) {
428
+ const r = sumSteps((s as any)?.operations);
429
+ serviceOpsWithSteps += r.opsWithSteps;
430
+ serviceOpSteps += r.totalSteps;
431
+ }
432
+ }
433
+ const totalLlmCalls = modelBehaviorSteps + controllerActionSteps + serviceOpSteps;
434
+ const fileEstimate = entityCount * 7 + controllerCount + serviceCount * 2 + viewCount + 15;
435
+ console.log('');
436
+ console.log('\u2554\u2550\u2550 spv realize --estimate \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
437
+ console.log('\u2551');
438
+ console.log('\u2551 Type: ' + type);
439
+ console.log('\u2551 Components: ' + compNames.length + (compNames.length > 0 ? ' (' + compNames.join(', ') + ')' : ''));
440
+ console.log('\u2551');
441
+ console.log('\u2551 \u2500\u2500 Spec inventory (post-inference) \u2500\u2500');
442
+ console.log('\u2551 Entities (models): ' + entityCount);
443
+ console.log('\u2551 Controllers: ' + controllerCount);
444
+ console.log('\u2551 Services: ' + serviceCount);
445
+ console.log('\u2551 Events: ' + eventCount);
446
+ console.log('\u2551 Views: ' + viewCount);
447
+ console.log('\u2551');
448
+ console.log('\u2551 \u2500\u2500 Output by realize layer \u2500\u2500');
449
+ console.log('\u2551');
450
+ console.log('\u2551 L1 \u2014 Instance factory (file scaffolding, no LLM):');
451
+ console.log('\u2551 File scaffolding for each entity / controller / service / view');
452
+ console.log('\u2551 + framework boilerplate (Fastify routes, Prisma schema, React shell)');
453
+ console.log('\u2551 Estimate: ~' + fileEstimate + ' files');
454
+ console.log('\u2551');
455
+ console.log('\u2551 L2 \u2014 Convention pattern matching (bodies, no LLM):');
456
+ console.log('\u2551 CURVED ops auto-implemented: ' + curvedOpCount);
457
+ console.log('\u2551 Default events on lifecycles: ' + eventCount + ' (declared) + auto-derived');
458
+ console.log('\u2551 Default validation patterns: ~' + (entityCount * 2));
459
+ console.log('\u2551');
460
+ console.log('\u2551 L3 \u2014 AI from steps (LLM, 1 call per step):');
461
+ console.log('\u2551 Model behaviors with steps: ' + modelBehaviorsWithSteps + ' behaviors \u2192 ' + modelBehaviorSteps + ' steps');
462
+ console.log('\u2551 Controller actions with steps: ' + controllerActionsWithSteps + ' actions \u2192 ' + controllerActionSteps + ' steps');
463
+ console.log('\u2551 Service ops with steps: ' + serviceOpsWithSteps + ' operations \u2192 ' + serviceOpSteps + ' steps');
464
+ console.log('\u2551 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500');
465
+ console.log('\u2551 Total LLM calls: ' + totalLlmCalls);
466
+ console.log('\u2551');
467
+ if (totalLlmCalls > 0) {
468
+ console.log('\u2551 \u2500\u2500 Estimated wall time + cost (L3 only) \u2500\u2500');
469
+ console.log('\u2551 On Opus 4.7 / Max: ~' + Math.ceil(totalLlmCalls * 0.2) + ' min wall (free, claude-cli session-cached)');
470
+ console.log('\u2551 On Sonnet 4.6: ~' + Math.ceil(totalLlmCalls * 0.1) + ' min wall (free)');
471
+ console.log('\u2551 On Anthropic API: ~' + Math.ceil(totalLlmCalls * 0.1) + ' min wall, ~$' + (totalLlmCalls * 0.015).toFixed(2) + ' (Sonnet rates)');
472
+ console.log('\u2551 On DeepSeek/Together: ~' + Math.ceil(totalLlmCalls * 0.08) + ' min wall, ~$' + (totalLlmCalls * 0.0008).toFixed(3) + ' (10-30\xD7 cheaper)');
473
+ } else {
474
+ console.log('\u2551 No LLM cost \u2014 all output is L1 + L2 (templates + conventions only).');
475
+ }
476
+ console.log('\u2551');
477
+ console.log('\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550');
478
+ return;
479
+ }
480
+
377
481
  // Realize \u2014 let the realize engine handle its own library.
378
482
  // Locate the nearest implementation manifest by walking up from the
379
483
  // spec file, then falling back to the user's cwd. This lets the same
@@ -429,6 +429,110 @@ import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/ty
429
429
  }
430
430
  const inferredSpec = { ...componentData, componentName, components: inferredYaml?.components || {} };
431
431
 
432
+ // --estimate: report what realize WOULD do, broken down by layer.
433
+ // Skip the actual realizeAll call (no manifest needed, no LLM cost).
434
+ // The three layers:
435
+ // L1 — Instance factory (templates, no LLM)
436
+ // L2 — Convention pattern matching (CURVED ops + default events, no LLM)
437
+ // L3 — AI from steps (one LLM call per declared step)
438
+ if (options.estimate) {
439
+ const components = inferredSpec.components || {};
440
+ const compNames = Object.keys(components);
441
+ let entityCount = 0, controllerCount = 0, serviceCount = 0, eventCount = 0, viewCount = 0;
442
+ let modelBehaviorSteps = 0, controllerActionSteps = 0, serviceOpSteps = 0;
443
+ let modelBehaviorsWithSteps = 0, controllerActionsWithSteps = 0, serviceOpsWithSteps = 0;
444
+ let curvedOpCount = 0;
445
+ const sumSteps = (block: any) => {
446
+ if (!block || typeof block !== 'object') return { ops: 0, opsWithSteps: 0, totalSteps: 0 };
447
+ let ops = 0, opsWithSteps = 0, totalSteps = 0;
448
+ for (const def of Object.values(block)) {
449
+ ops++;
450
+ const steps = (def as any)?.steps;
451
+ if (Array.isArray(steps) && steps.length > 0) {
452
+ opsWithSteps++;
453
+ totalSteps += steps.length;
454
+ }
455
+ }
456
+ return { ops, opsWithSteps, totalSteps };
457
+ };
458
+ for (const compName of compNames) {
459
+ const comp = components[compName] || {};
460
+ const models = comp.models || {};
461
+ const controllers = comp.controllers || {};
462
+ const services = comp.services || {};
463
+ const events = comp.events || {};
464
+ const views = comp.views || {};
465
+ entityCount += Object.keys(models).length;
466
+ controllerCount += Object.keys(controllers).length;
467
+ serviceCount += Object.keys(services).length;
468
+ eventCount += Object.keys(events).length;
469
+ viewCount += Object.keys(views).length;
470
+ for (const m of Object.values(models)) {
471
+ const r = sumSteps((m as any)?.behaviors);
472
+ modelBehaviorsWithSteps += r.opsWithSteps;
473
+ modelBehaviorSteps += r.totalSteps;
474
+ }
475
+ for (const c of Object.values(controllers)) {
476
+ const r = sumSteps((c as any)?.actions);
477
+ controllerActionsWithSteps += r.opsWithSteps;
478
+ controllerActionSteps += r.totalSteps;
479
+ const cured = (c as any)?.cured || (c as any)?.curved;
480
+ if (cured && typeof cured === 'object') curvedOpCount += Object.keys(cured).length;
481
+ }
482
+ for (const s of Object.values(services)) {
483
+ const r = sumSteps((s as any)?.operations);
484
+ serviceOpsWithSteps += r.opsWithSteps;
485
+ serviceOpSteps += r.totalSteps;
486
+ }
487
+ }
488
+ const totalLlmCalls = modelBehaviorSteps + controllerActionSteps + serviceOpSteps;
489
+ const fileEstimate = entityCount * 7 + controllerCount + serviceCount * 2 + viewCount + 15;
490
+ console.log('');
491
+ console.log('╔══ spv realize --estimate ══════════════════════════════════════════');
492
+ console.log('║');
493
+ console.log('║ Type: ' + type);
494
+ console.log('║ Components: ' + compNames.length + (compNames.length > 0 ? ' (' + compNames.join(', ') + ')' : ''));
495
+ console.log('║');
496
+ console.log('║ ── Spec inventory (post-inference) ──');
497
+ console.log('║ Entities (models): ' + entityCount);
498
+ console.log('║ Controllers: ' + controllerCount);
499
+ console.log('║ Services: ' + serviceCount);
500
+ console.log('║ Events: ' + eventCount);
501
+ console.log('║ Views: ' + viewCount);
502
+ console.log('║');
503
+ console.log('║ ── Output by realize layer ──');
504
+ console.log('║');
505
+ console.log('║ L1 — Instance factory (file scaffolding, no LLM):');
506
+ console.log('║ File scaffolding for each entity / controller / service / view');
507
+ console.log('║ + framework boilerplate (Fastify routes, Prisma schema, React shell)');
508
+ console.log('║ Estimate: ~' + fileEstimate + ' files');
509
+ console.log('║');
510
+ console.log('║ L2 — Convention pattern matching (bodies, no LLM):');
511
+ console.log('║ CURVED ops auto-implemented: ' + curvedOpCount);
512
+ console.log('║ Default events on lifecycles: ' + eventCount + ' (declared) + auto-derived');
513
+ console.log('║ Default validation patterns: ~' + (entityCount * 2));
514
+ console.log('║');
515
+ console.log('║ L3 — AI from steps (LLM, 1 call per step):');
516
+ console.log('║ Model behaviors with steps: ' + modelBehaviorsWithSteps + ' behaviors → ' + modelBehaviorSteps + ' steps');
517
+ console.log('║ Controller actions with steps: ' + controllerActionsWithSteps + ' actions → ' + controllerActionSteps + ' steps');
518
+ console.log('║ Service ops with steps: ' + serviceOpsWithSteps + ' operations → ' + serviceOpSteps + ' steps');
519
+ console.log('║ ────────────────────────────────────────────────────────');
520
+ console.log('║ Total LLM calls: ' + totalLlmCalls);
521
+ console.log('║');
522
+ if (totalLlmCalls > 0) {
523
+ console.log('║ ── Estimated wall time + cost (L3 only) ──');
524
+ console.log('║ On Opus 4.7 / Max: ~' + Math.ceil(totalLlmCalls * 0.2) + ' min wall (free, claude-cli session-cached)');
525
+ console.log('║ On Sonnet 4.6: ~' + Math.ceil(totalLlmCalls * 0.1) + ' min wall (free)');
526
+ console.log('║ On Anthropic API: ~' + Math.ceil(totalLlmCalls * 0.1) + ' min wall, ~$' + (totalLlmCalls * 0.015).toFixed(2) + ' (Sonnet rates)');
527
+ console.log('║ On DeepSeek/Together: ~' + Math.ceil(totalLlmCalls * 0.08) + ' min wall, ~$' + (totalLlmCalls * 0.0008).toFixed(3) + ' (10-30× cheaper)');
528
+ } else {
529
+ console.log('║ No LLM cost — all output is L1 + L2 (templates + conventions only).');
530
+ }
531
+ console.log('║');
532
+ console.log('╚════════════════════════════════════════════════════════════════════');
533
+ return;
534
+ }
535
+
432
536
  // Realize — let the realize engine handle its own library.
433
537
  // Locate the nearest implementation manifest by walking up from the
434
538
  // spec file, then falling back to the user's cwd. This lets the same
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "6.0.8",
3
+ "version": "6.0.10",
4
4
  "description": "SpecVerse toolchain — parser, inference, realize, generators, AI, registry, bundles",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,14 +0,0 @@
1
- /**
2
- * Command Generator
3
- *
4
- * Generates individual command files from command specifications.
5
- * Each command registers itself on a Commander program and wires
6
- * to its corresponding service for business logic delegation.
7
- */
8
- import type { TemplateContext } from '@specverse/types';
9
- /**
10
- * Generate a single command file.
11
- * Called once per command in the spec.
12
- */
13
- export default function generateCommand(context: TemplateContext): string;
14
- //# sourceMappingURL=command-generator.d.ts.map
@@ -1,182 +0,0 @@
1
- /**
2
- * Command Generator
3
- *
4
- * Generates individual command files from command specifications.
5
- * Each command registers itself on a Commander program and wires
6
- * to its corresponding service for business logic delegation.
7
- */
8
- /**
9
- * Generate a single command file.
10
- * Called once per command in the spec.
11
- */
12
- export default function generateCommand(context) {
13
- const { command } = context;
14
- if (!command) {
15
- throw new Error('Command is required in template context');
16
- }
17
- const name = command.name;
18
- const description = command.description || '';
19
- const args = command.arguments || {};
20
- const flags = command.flags || {};
21
- const exitCodes = command.exitCodes || {};
22
- const subcommands = command.subcommands || {};
23
- const serviceRef = command.serviceRef;
24
- // Build positional argument string for Commander
25
- const positionalArgs = Object.entries(args)
26
- .filter(([_, arg]) => arg.positional)
27
- .sort((a, b) => (a[1].position || 0) - (b[1].position || 0))
28
- .map(([argName, arg]) => {
29
- const required = arg.required;
30
- return required ? `<${argName}>` : `[${argName}]`;
31
- })
32
- .join(' ');
33
- const commandStr = positionalArgs ? `${name} ${positionalArgs}` : name;
34
- // Build options
35
- const optionDefs = Object.entries(flags).map(([flagName, flag]) => {
36
- const alias = flag.alias ? `${flag.alias}, ` : '';
37
- const flagType = flag.type?.toLowerCase();
38
- const valuePart = flagType === 'boolean' ? '' : ` <${flagName.replace(/^--/, '')}>`;
39
- const defaultVal = flag.default !== undefined ? `, ${JSON.stringify(flag.default)}` : '';
40
- const desc = flag.description || `${flagName} option`;
41
- return ` .option('${alias}${flagName}${valuePart}', '${desc}'${defaultVal})`;
42
- });
43
- // Build type interface for options
44
- const optionTypes = Object.entries(flags).map(([flagName, flag]) => {
45
- const tsType = mapFlagTypeToTS(flag.type);
46
- const key = flagName.replace(/^--/, '').replace(/-([a-z])/g, (_, c) => c.toUpperCase());
47
- return ` ${key}${flag.required ? '' : '?'}: ${tsType};`;
48
- });
49
- // Build positional arg types
50
- const argTypes = Object.entries(args)
51
- .filter(([_, arg]) => arg.positional)
52
- .map(([argName, arg]) => {
53
- const tsType = mapArgTypeToTS(arg.type);
54
- return `${argName}: ${tsType}`;
55
- });
56
- // Generate action handler
57
- const actionParams = argTypes.length > 0
58
- ? argTypes.join(', ') + ', options: CommandOptions'
59
- : 'options: CommandOptions';
60
- // Generate exit code comments
61
- const exitCodeComments = Object.entries(exitCodes).length > 0
62
- ? Object.entries(exitCodes).map(([code, meaning]) => ` // ${code}: ${meaning}`).join('\n')
63
- : '';
64
- // Handle subcommands
65
- const hasSubcommands = Object.keys(subcommands).length > 0;
66
- const subcommandRegistrations = hasSubcommands
67
- ? generateSubcommandRegistrations(name, subcommands)
68
- : '';
69
- // Service import
70
- const serviceImport = serviceRef
71
- ? `import { ${serviceRef} } from '../services/${serviceRef}.js';`
72
- : '';
73
- return `/**
74
- * ${name} command
75
- * ${description}
76
- * Generated from SpecVerse specification
77
- */
78
-
79
- import { Command } from 'commander';
80
- ${serviceImport}
81
-
82
- interface CommandOptions {
83
- ${optionTypes.length > 0 ? optionTypes.join('\n') : ' [key: string]: any;'}
84
- }
85
-
86
- ${exitCodeComments ? `/**\n * Exit codes:\n${exitCodeComments}\n */` : ''}
87
-
88
- /**
89
- * Register the ${name} command on the program.
90
- */
91
- export function register${capitalize(name)}Command(program: Command): void {
92
- ${hasSubcommands ? generateCommandWithSubcommands(name, description, subcommands, optionDefs) : generateLeafCommand(name, description, commandStr, optionDefs, actionParams, serviceRef, exitCodes)}
93
- }
94
- ${subcommandRegistrations}
95
- `;
96
- }
97
- function generateLeafCommand(name, description, commandStr, optionDefs, actionParams, serviceRef, exitCodes) {
98
- const handler = serviceRef
99
- ? `const service = new ${serviceRef}();
100
- const result = await service.execute(${actionParams.includes(':') ? '{ ' + actionParams.split(',').map(p => p.trim().split(':')[0].trim()).join(', ') + ', ...options }' : 'options'});
101
- console.log(result);`
102
- : `console.log('Executing ${name}...');
103
- // TODO: Wire to service`;
104
- return `const cmd = program
105
- .command('${commandStr}')
106
- .description('${description}')
107
- ${optionDefs.join('\n')}
108
- .action(async (${actionParams}) => {
109
- try {
110
- ${handler}
111
- } catch (error: any) {
112
- console.error('Error:', error.message);
113
- process.exit(${Object.keys(exitCodes).find(k => k !== '0') || '1'});
114
- }
115
- });`;
116
- }
117
- function generateCommandWithSubcommands(name, description, subcommands, optionDefs) {
118
- const subcmdRegistrations = Object.entries(subcommands).map(([subName, subDef]) => {
119
- const subDesc = subDef.description || '';
120
- const subArgs = subDef.arguments || {};
121
- const subFlags = subDef.flags || {};
122
- const positionalStr = Object.entries(subArgs)
123
- .filter(([_, a]) => a.positional)
124
- .map(([n, a]) => a.required ? `<${n}>` : `[${n}]`)
125
- .join(' ');
126
- const subCmdStr = positionalStr ? `${subName} ${positionalStr}` : subName;
127
- const subOptionDefs = Object.entries(subFlags).map(([flagName, flag]) => {
128
- const alias = flag.alias ? `${flag.alias}, ` : '';
129
- const flagType = flag.type?.toLowerCase();
130
- const valuePart = flagType === 'boolean' ? '' : ` <${flagName.replace(/^--/, '')}>`;
131
- const defaultVal = flag.default !== undefined ? `, ${JSON.stringify(flag.default)}` : '';
132
- return ` .option('${alias}${flagName}${valuePart}', '${flag.description || flagName}'${defaultVal})`;
133
- });
134
- return `
135
- cmd
136
- .command('${subCmdStr}')
137
- .description('${subDesc}')
138
- ${subOptionDefs.join('\n')}
139
- .action(async (...args: any[]) => {
140
- try {
141
- console.log('Executing ${name} ${subName}...');
142
- // TODO: Wire to service
143
- } catch (error: any) {
144
- console.error('Error:', error.message);
145
- process.exit(1);
146
- }
147
- });`;
148
- });
149
- return `const cmd = program
150
- .command('${name}')
151
- .description('${description}');
152
- ${subcmdRegistrations.join('\n')}`;
153
- }
154
- function generateSubcommandRegistrations(_parentName, _subcommands) {
155
- return ''; // Subcommands are registered inline
156
- }
157
- function mapFlagTypeToTS(type) {
158
- if (!type)
159
- return 'string';
160
- const lower = type.toLowerCase();
161
- if (lower === 'boolean')
162
- return 'boolean';
163
- if (lower === 'number' || lower === 'integer')
164
- return 'number';
165
- return 'string';
166
- }
167
- function mapArgTypeToTS(type) {
168
- if (!type)
169
- return 'string';
170
- const lower = type.toLowerCase();
171
- if (lower === 'filepath' || lower === 'string')
172
- return 'string';
173
- if (lower === 'number' || lower === 'integer')
174
- return 'number';
175
- if (lower === 'boolean')
176
- return 'boolean';
177
- return 'string';
178
- }
179
- function capitalize(str) {
180
- return str.charAt(0).toUpperCase() + str.slice(1);
181
- }
182
- //# sourceMappingURL=command-generator.js.map