nexus-agents 2.82.0 → 2.83.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{child-mcp-config-BMSYR7VV.js → child-mcp-config-3ZW2UPKZ.js} +2 -2
- package/dist/{chunk-BQ4YXGGQ.js → chunk-3ACDP4E6.js} +124 -2
- package/dist/chunk-3ACDP4E6.js.map +1 -0
- package/dist/{chunk-S36LIUV2.js → chunk-4XSCU4B3.js} +8 -8
- package/dist/{chunk-HJUHDPXJ.js → chunk-5QJPM5CB.js} +3 -3
- package/dist/{chunk-633WH2ML.js → chunk-6T3EPABN.js} +1 -1
- package/dist/chunk-6T3EPABN.js.map +1 -0
- package/dist/{chunk-7VNVDFD5.js → chunk-6UI4NKT4.js} +44 -18
- package/dist/{chunk-7VNVDFD5.js.map → chunk-6UI4NKT4.js.map} +1 -1
- package/dist/{chunk-NTLJ3INA.js → chunk-6XRNFLPI.js} +2 -2
- package/dist/{chunk-U7JXQSEM.js → chunk-7V367KT4.js} +4 -4
- package/dist/{chunk-BL5IBHEY.js → chunk-A6WC5I7V.js} +3 -3
- package/dist/{chunk-OYDJ3C4N.js → chunk-BICIQYET.js} +3 -3
- package/dist/{chunk-SXL744NF.js → chunk-BUXXAN6V.js} +2 -2
- package/dist/{chunk-SHWGK7X6.js → chunk-DWOSFYI2.js} +2 -2
- package/dist/{chunk-2SQXJQTA.js → chunk-ELRNVADA.js} +16 -13
- package/dist/{chunk-2SQXJQTA.js.map → chunk-ELRNVADA.js.map} +1 -1
- package/dist/{chunk-2R5UUBGA.js → chunk-FHY7I736.js} +2 -2
- package/dist/{chunk-7J7PNOJQ.js → chunk-HFOQKCD2.js} +22 -5
- package/dist/chunk-HFOQKCD2.js.map +1 -0
- package/dist/{chunk-TXIUCEFT.js → chunk-HGPIHDC4.js} +3 -3
- package/dist/{chunk-X3JR3GMT.js → chunk-IM2B3FK2.js} +3 -3
- package/dist/{chunk-4XNVJS5A.js → chunk-J4ZBKE4B.js} +866 -892
- package/dist/chunk-J4ZBKE4B.js.map +1 -0
- package/dist/{chunk-SBZVRH4S.js → chunk-JA6ON2RP.js} +2 -2
- package/dist/{chunk-QHL4KGNB.js → chunk-LM2S2QWO.js} +2 -2
- package/dist/{chunk-QHL4KGNB.js.map → chunk-LM2S2QWO.js.map} +1 -1
- package/dist/{chunk-C7P2HLJX.js → chunk-MATFDJRW.js} +4 -4
- package/dist/{chunk-XGUDCUMB.js → chunk-O3XJLOEX.js} +2 -2
- package/dist/{chunk-FTT2IYYX.js → chunk-ODKIRXN7.js} +34 -43
- package/dist/chunk-ODKIRXN7.js.map +1 -0
- package/dist/{chunk-HMXQKDUV.js → chunk-SZZS57X7.js} +23 -7
- package/dist/chunk-SZZS57X7.js.map +1 -0
- package/dist/{chunk-W2AIGD35.js → chunk-TKGVRHEI.js} +3 -3
- package/dist/{chunk-HVZ52LOL.js → chunk-UFUR6RBP.js} +2 -2
- package/dist/{chunk-WUUEKFKG.js → chunk-VXIHHHLQ.js} +2 -2
- package/dist/{chunk-GNG7URCR.js → chunk-W6MLS2UL.js} +2 -2
- package/dist/{chunk-G2DZBEMU.js → chunk-XODXYOFN.js} +2 -2
- package/dist/{chunk-JM3R267Z.js → chunk-ZA6AZ7LK.js} +5 -5
- package/dist/{chunk-PZESEBD3.js → chunk-ZLGU7T6J.js} +2 -2
- package/dist/{cli-circuit-breaker-BIJUQRQI.js → cli-circuit-breaker-LC4NZUGD.js} +4 -4
- package/dist/cli.js +367 -345
- package/dist/cli.js.map +1 -1
- package/dist/codebase-search-ZFJUVMVR.js +8 -0
- package/dist/{composite-router-FB7P22L5.js → composite-router-GXQ25DO4.js} +2 -2
- package/dist/{consensus-vote-KKAIFULI.js → consensus-vote-MTLP6E72.js} +12 -12
- package/dist/{context-retriever-4JCGMWH7.js → context-retriever-GQRC2MVM.js} +6 -6
- package/dist/{doctor-deep-7YK4BZIJ.js → doctor-deep-T3UUJX2E.js} +3 -3
- package/dist/expert-bridge-7LPGCPPR.js +13 -0
- package/dist/{factory-DOWBGVAL.js → factory-3XB5CAAA.js} +5 -5
- package/dist/{factory-PK4EZL7K.js → factory-OKNCTJO6.js} +4 -4
- package/dist/index.d.ts +98 -194
- package/dist/index.js +90 -193
- package/dist/index.js.map +1 -1
- package/dist/{init-opencode-QP5CAMWN.js → init-opencode-KDTBKLXS.js} +5 -5
- package/dist/{issue-triage-T3SKNBH5.js → issue-triage-MURMDN2G.js} +4 -4
- package/dist/{registry-command-TH7U6UMC.js → registry-command-D56ROMFJ.js} +2 -2
- package/dist/{repo-analyze-D2OY2QSR.js → repo-analyze-JZEMBE6R.js} +2 -2
- package/dist/{repo-security-plan-V257RYTW.js → repo-security-plan-N3CDMW6L.js} +4 -4
- package/dist/{research-helpers-synthesize-Y3O76PY4.js → research-helpers-synthesize-36QBOKII.js} +3 -3
- package/dist/{routing-memory-AAH7NIHD.js → routing-memory-6IEPJ3EP.js} +2 -2
- package/dist/{session-memory-MY6YS2VX.js → session-memory-X6SCDFER.js} +3 -3
- package/dist/{setup-command-B6EC3OJA.js → setup-command-5AEO5A4Z.js} +11 -11
- package/dist/{setup-config-HVO6ZSLW.js → setup-config-RPSVIQJO.js} +3 -3
- package/dist/{setup-custom-api-UOIKUQL4.js → setup-custom-api-RBOJT3SS.js} +4 -4
- package/dist/{tool-memory-T7ZYIUJ2.js → tool-memory-EEHITQRJ.js} +5 -5
- package/dist/{weather-report-O3Z3BBAX.js → weather-report-6BC3JK5H.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-4XNVJS5A.js.map +0 -1
- package/dist/chunk-633WH2ML.js.map +0 -1
- package/dist/chunk-7J7PNOJQ.js.map +0 -1
- package/dist/chunk-AP2FD37C.js +0 -127
- package/dist/chunk-AP2FD37C.js.map +0 -1
- package/dist/chunk-BQ4YXGGQ.js.map +0 -1
- package/dist/chunk-ED6VQWNG.js +0 -63
- package/dist/chunk-ED6VQWNG.js.map +0 -1
- package/dist/chunk-FTT2IYYX.js.map +0 -1
- package/dist/chunk-HMXQKDUV.js.map +0 -1
- package/dist/codebase-search-PIBRTGBE.js +0 -9
- package/dist/expert-bridge-DJM5GAWZ.js +0 -11
- package/dist/shared-memory-CM6T2MYE.js +0 -8
- package/dist/symbol-extractor-WYXPJH65.js +0 -10
- package/dist/tool-memory-T7ZYIUJ2.js.map +0 -1
- package/dist/weather-report-O3Z3BBAX.js.map +0 -1
- /package/dist/{child-mcp-config-BMSYR7VV.js.map → child-mcp-config-3ZW2UPKZ.js.map} +0 -0
- /package/dist/{chunk-S36LIUV2.js.map → chunk-4XSCU4B3.js.map} +0 -0
- /package/dist/{chunk-HJUHDPXJ.js.map → chunk-5QJPM5CB.js.map} +0 -0
- /package/dist/{chunk-NTLJ3INA.js.map → chunk-6XRNFLPI.js.map} +0 -0
- /package/dist/{chunk-U7JXQSEM.js.map → chunk-7V367KT4.js.map} +0 -0
- /package/dist/{chunk-BL5IBHEY.js.map → chunk-A6WC5I7V.js.map} +0 -0
- /package/dist/{chunk-OYDJ3C4N.js.map → chunk-BICIQYET.js.map} +0 -0
- /package/dist/{chunk-SXL744NF.js.map → chunk-BUXXAN6V.js.map} +0 -0
- /package/dist/{chunk-SHWGK7X6.js.map → chunk-DWOSFYI2.js.map} +0 -0
- /package/dist/{chunk-2R5UUBGA.js.map → chunk-FHY7I736.js.map} +0 -0
- /package/dist/{chunk-TXIUCEFT.js.map → chunk-HGPIHDC4.js.map} +0 -0
- /package/dist/{chunk-X3JR3GMT.js.map → chunk-IM2B3FK2.js.map} +0 -0
- /package/dist/{chunk-SBZVRH4S.js.map → chunk-JA6ON2RP.js.map} +0 -0
- /package/dist/{chunk-C7P2HLJX.js.map → chunk-MATFDJRW.js.map} +0 -0
- /package/dist/{chunk-XGUDCUMB.js.map → chunk-O3XJLOEX.js.map} +0 -0
- /package/dist/{chunk-W2AIGD35.js.map → chunk-TKGVRHEI.js.map} +0 -0
- /package/dist/{chunk-HVZ52LOL.js.map → chunk-UFUR6RBP.js.map} +0 -0
- /package/dist/{chunk-WUUEKFKG.js.map → chunk-VXIHHHLQ.js.map} +0 -0
- /package/dist/{chunk-GNG7URCR.js.map → chunk-W6MLS2UL.js.map} +0 -0
- /package/dist/{chunk-G2DZBEMU.js.map → chunk-XODXYOFN.js.map} +0 -0
- /package/dist/{chunk-JM3R267Z.js.map → chunk-ZA6AZ7LK.js.map} +0 -0
- /package/dist/{chunk-PZESEBD3.js.map → chunk-ZLGU7T6J.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-BIJUQRQI.js.map → cli-circuit-breaker-LC4NZUGD.js.map} +0 -0
- /package/dist/{codebase-search-PIBRTGBE.js.map → codebase-search-ZFJUVMVR.js.map} +0 -0
- /package/dist/{composite-router-FB7P22L5.js.map → composite-router-GXQ25DO4.js.map} +0 -0
- /package/dist/{consensus-vote-KKAIFULI.js.map → consensus-vote-MTLP6E72.js.map} +0 -0
- /package/dist/{context-retriever-4JCGMWH7.js.map → context-retriever-GQRC2MVM.js.map} +0 -0
- /package/dist/{doctor-deep-7YK4BZIJ.js.map → doctor-deep-T3UUJX2E.js.map} +0 -0
- /package/dist/{expert-bridge-DJM5GAWZ.js.map → expert-bridge-7LPGCPPR.js.map} +0 -0
- /package/dist/{factory-DOWBGVAL.js.map → factory-3XB5CAAA.js.map} +0 -0
- /package/dist/{factory-PK4EZL7K.js.map → factory-OKNCTJO6.js.map} +0 -0
- /package/dist/{init-opencode-QP5CAMWN.js.map → init-opencode-KDTBKLXS.js.map} +0 -0
- /package/dist/{issue-triage-T3SKNBH5.js.map → issue-triage-MURMDN2G.js.map} +0 -0
- /package/dist/{registry-command-TH7U6UMC.js.map → registry-command-D56ROMFJ.js.map} +0 -0
- /package/dist/{repo-analyze-D2OY2QSR.js.map → repo-analyze-JZEMBE6R.js.map} +0 -0
- /package/dist/{repo-security-plan-V257RYTW.js.map → repo-security-plan-N3CDMW6L.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-Y3O76PY4.js.map → research-helpers-synthesize-36QBOKII.js.map} +0 -0
- /package/dist/{routing-memory-AAH7NIHD.js.map → routing-memory-6IEPJ3EP.js.map} +0 -0
- /package/dist/{session-memory-MY6YS2VX.js.map → session-memory-X6SCDFER.js.map} +0 -0
- /package/dist/{setup-command-B6EC3OJA.js.map → setup-command-5AEO5A4Z.js.map} +0 -0
- /package/dist/{setup-config-HVO6ZSLW.js.map → setup-config-RPSVIQJO.js.map} +0 -0
- /package/dist/{setup-custom-api-UOIKUQL4.js.map → setup-custom-api-RBOJT3SS.js.map} +0 -0
- /package/dist/{shared-memory-CM6T2MYE.js.map → tool-memory-EEHITQRJ.js.map} +0 -0
- /package/dist/{symbol-extractor-WYXPJH65.js.map → weather-report-6BC3JK5H.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createLogger
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6UI4NKT4.js";
|
|
4
4
|
import "./chunk-I2HMWH4R.js";
|
|
5
5
|
import "./chunk-PR4QN5HX.js";
|
|
6
6
|
|
|
@@ -59,4 +59,4 @@ export {
|
|
|
59
59
|
generateMcpConfig,
|
|
60
60
|
getDefaultAllowedTools
|
|
61
61
|
};
|
|
62
|
-
//# sourceMappingURL=child-mcp-config-
|
|
62
|
+
//# sourceMappingURL=child-mcp-config-3ZW2UPKZ.js.map
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// src/indexer/codebase-search.ts
|
|
2
|
+
import { readdir } from "fs/promises";
|
|
3
|
+
import { resolve, extname as extname2, relative } from "path";
|
|
4
|
+
|
|
1
5
|
// src/indexer/symbol-extractor.ts
|
|
2
6
|
import { readFile } from "fs/promises";
|
|
3
7
|
import { extname } from "path";
|
|
@@ -120,8 +124,126 @@ async function extractSymbolIndex(filePath) {
|
|
|
120
124
|
${lines.join("\n")}`;
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
// src/indexer/codebase-search.ts
|
|
128
|
+
var SCORE_EXACT = 20;
|
|
129
|
+
var SCORE_PREFIX = 10;
|
|
130
|
+
var SCORE_WORD = 5;
|
|
131
|
+
var SCORE_SUBSTRING = 2;
|
|
132
|
+
var SCORE_EXPORTED_BONUS = 3;
|
|
133
|
+
function isSourceFile(name) {
|
|
134
|
+
const ext = extname2(name).toLowerCase();
|
|
135
|
+
return [".ts", ".tsx", ".js", ".jsx"].includes(ext) && !name.endsWith(".test.ts") && !name.endsWith(".test.tsx") && !name.endsWith(".d.ts");
|
|
136
|
+
}
|
|
137
|
+
async function findSourceFiles(dir, maxDepth) {
|
|
138
|
+
if (maxDepth <= 0) return [];
|
|
139
|
+
const files = [];
|
|
140
|
+
const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
const fullPath = resolve(dir, entry.name);
|
|
143
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist") {
|
|
144
|
+
files.push(...await findSourceFiles(fullPath, maxDepth - 1));
|
|
145
|
+
}
|
|
146
|
+
if (entry.isFile() && isSourceFile(entry.name)) {
|
|
147
|
+
files.push(fullPath);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return files;
|
|
151
|
+
}
|
|
152
|
+
function scoreMatch(symbolName, query) {
|
|
153
|
+
const nameLower = symbolName.toLowerCase();
|
|
154
|
+
const queryLower = query.toLowerCase();
|
|
155
|
+
if (nameLower === queryLower) return SCORE_EXACT;
|
|
156
|
+
if (nameLower.startsWith(queryLower)) return SCORE_PREFIX;
|
|
157
|
+
const words = symbolName.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/[\s_-]+/);
|
|
158
|
+
if (words.some((w) => w === queryLower)) return SCORE_WORD;
|
|
159
|
+
if (nameLower.includes(queryLower)) return SCORE_SUBSTRING;
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function getMatchType(score) {
|
|
163
|
+
if (score >= SCORE_EXACT) return "exact";
|
|
164
|
+
if (score >= SCORE_PREFIX) return "prefix";
|
|
165
|
+
if (score >= SCORE_WORD) return "word";
|
|
166
|
+
return "substring";
|
|
167
|
+
}
|
|
168
|
+
var CodebaseIndex = class {
|
|
169
|
+
symbols = [];
|
|
170
|
+
fileResults = /* @__PURE__ */ new Map();
|
|
171
|
+
rootDir;
|
|
172
|
+
constructor(rootDir) {
|
|
173
|
+
this.rootDir = rootDir;
|
|
174
|
+
}
|
|
175
|
+
/** Index all TS/JS source files in the directory. */
|
|
176
|
+
async index(maxDepth = 4) {
|
|
177
|
+
const files = await findSourceFiles(this.rootDir, maxDepth);
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
const result = await extractSymbols(file);
|
|
180
|
+
const relPath = relative(this.rootDir, file);
|
|
181
|
+
this.fileResults.set(relPath, result);
|
|
182
|
+
for (const symbol of result.symbols) {
|
|
183
|
+
this.symbols.push({ ...symbol, filePath: relPath });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
totalFiles: files.length,
|
|
188
|
+
totalSymbols: this.symbols.length,
|
|
189
|
+
indexedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** Search symbols by keyword. Returns top N results sorted by relevance. */
|
|
193
|
+
search(query, limit = 20) {
|
|
194
|
+
const results = [];
|
|
195
|
+
for (const symbol of this.symbols) {
|
|
196
|
+
const baseScore = scoreMatch(symbol.name, query);
|
|
197
|
+
if (baseScore === null) continue;
|
|
198
|
+
const bonus = symbol.exported ? SCORE_EXPORTED_BONUS : 0;
|
|
199
|
+
results.push({
|
|
200
|
+
symbol,
|
|
201
|
+
score: baseScore + bonus,
|
|
202
|
+
matchType: getMatchType(baseScore)
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
206
|
+
}
|
|
207
|
+
/** Get a compact summary of a file's symbols. */
|
|
208
|
+
getFileSummary(filePath) {
|
|
209
|
+
const result = this.fileResults.get(filePath);
|
|
210
|
+
if (result === void 0) return void 0;
|
|
211
|
+
const kinds = {};
|
|
212
|
+
let exported = 0;
|
|
213
|
+
let priv = 0;
|
|
214
|
+
for (const s of result.symbols) {
|
|
215
|
+
kinds[s.kind] = (kinds[s.kind] ?? 0) + 1;
|
|
216
|
+
if (s.exported) exported++;
|
|
217
|
+
else priv++;
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
filePath,
|
|
221
|
+
totalLines: result.totalLines,
|
|
222
|
+
exportedSymbols: exported,
|
|
223
|
+
privateSymbols: priv,
|
|
224
|
+
kinds
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** List all indexed files with symbol counts. */
|
|
228
|
+
listFiles() {
|
|
229
|
+
return [...this.fileResults.entries()].map(([path, result]) => ({
|
|
230
|
+
path,
|
|
231
|
+
symbols: result.symbols.length,
|
|
232
|
+
lines: result.totalLines
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
/** Get index statistics. */
|
|
236
|
+
get stats() {
|
|
237
|
+
return {
|
|
238
|
+
files: this.fileResults.size,
|
|
239
|
+
symbols: this.symbols.length
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
123
244
|
export {
|
|
124
245
|
extractSymbols,
|
|
125
|
-
extractSymbolIndex
|
|
246
|
+
extractSymbolIndex,
|
|
247
|
+
CodebaseIndex
|
|
126
248
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
249
|
+
//# sourceMappingURL=chunk-3ACDP4E6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/indexer/codebase-search.ts","../src/indexer/symbol-extractor.ts"],"sourcesContent":["/**\n * Codebase search — keyword search across symbol indices.\n *\n * Builds an in-memory symbol index for a directory of TS/JS files,\n * then supports keyword search, file summaries, and symbol lookup.\n *\n * Inspired by Augment Code's Context Engine. Uses the existing\n * extractSymbols() function for AST parsing.\n *\n * @module indexer/codebase-search\n */\n\nimport { readdir } from 'node:fs/promises';\nimport { resolve, extname, relative } from 'node:path';\nimport {\n extractSymbols,\n type CodeSymbol,\n type SymbolExtractionResult,\n} from './symbol-extractor.js';\n\n/** A symbol with its source file path. */\nexport interface IndexedSymbol extends CodeSymbol {\n /** Relative file path from the indexed root. */\n filePath: string;\n}\n\n/** Search result with relevance scoring. */\nexport interface SearchResult {\n symbol: IndexedSymbol;\n /** Relevance score (higher = better match). */\n score: number;\n /** How the query matched (exact, prefix, substring, word). */\n matchType: 'exact' | 'prefix' | 'substring' | 'word';\n}\n\n/** File summary — compact overview of a source file. */\nexport interface FileSummary {\n filePath: string;\n totalLines: number;\n exportedSymbols: number;\n privateSymbols: number;\n kinds: Record<string, number>;\n}\n\n/** Index statistics. */\nexport interface IndexStats {\n totalFiles: number;\n totalSymbols: number;\n indexedAt: string;\n}\n\n// Score weights for different match types\nconst SCORE_EXACT = 20;\nconst SCORE_PREFIX = 10;\nconst SCORE_WORD = 5;\nconst SCORE_SUBSTRING = 2;\nconst SCORE_EXPORTED_BONUS = 3;\n\nfunction isSourceFile(name: string): boolean {\n const ext = extname(name).toLowerCase();\n return (\n ['.ts', '.tsx', '.js', '.jsx'].includes(ext) &&\n !name.endsWith('.test.ts') &&\n !name.endsWith('.test.tsx') &&\n !name.endsWith('.d.ts')\n );\n}\n\nasync function findSourceFiles(dir: string, maxDepth: number): Promise<string[]> {\n if (maxDepth <= 0) return [];\n const files: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);\n for (const entry of entries) {\n const fullPath = resolve(dir, entry.name);\n if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== 'dist') {\n files.push(...(await findSourceFiles(fullPath, maxDepth - 1)));\n }\n if (entry.isFile() && isSourceFile(entry.name)) {\n files.push(fullPath);\n }\n }\n return files;\n}\n\nfunction scoreMatch(symbolName: string, query: string): SearchResult['score'] | null {\n const nameLower = symbolName.toLowerCase();\n const queryLower = query.toLowerCase();\n\n if (nameLower === queryLower) return SCORE_EXACT;\n if (nameLower.startsWith(queryLower)) return SCORE_PREFIX;\n\n // Word boundary match (camelCase splitting)\n const words = symbolName\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .toLowerCase()\n .split(/[\\s_-]+/);\n if (words.some((w) => w === queryLower)) return SCORE_WORD;\n\n if (nameLower.includes(queryLower)) return SCORE_SUBSTRING;\n\n return null;\n}\n\nfunction getMatchType(score: number): SearchResult['matchType'] {\n if (score >= SCORE_EXACT) return 'exact';\n if (score >= SCORE_PREFIX) return 'prefix';\n if (score >= SCORE_WORD) return 'word';\n return 'substring';\n}\n\n/** In-memory codebase symbol index. */\nexport class CodebaseIndex {\n private readonly symbols: IndexedSymbol[] = [];\n private readonly fileResults = new Map<string, SymbolExtractionResult>();\n private readonly rootDir: string;\n\n constructor(rootDir: string) {\n this.rootDir = rootDir;\n }\n\n /** Index all TS/JS source files in the directory. */\n async index(maxDepth = 4): Promise<IndexStats> {\n const files = await findSourceFiles(this.rootDir, maxDepth);\n\n for (const file of files) {\n const result = await extractSymbols(file);\n const relPath = relative(this.rootDir, file);\n this.fileResults.set(relPath, result);\n\n for (const symbol of result.symbols) {\n this.symbols.push({ ...symbol, filePath: relPath });\n }\n }\n\n return {\n totalFiles: files.length,\n totalSymbols: this.symbols.length,\n indexedAt: new Date().toISOString(),\n };\n }\n\n /** Search symbols by keyword. Returns top N results sorted by relevance. */\n search(query: string, limit = 20): SearchResult[] {\n const results: SearchResult[] = [];\n\n for (const symbol of this.symbols) {\n const baseScore = scoreMatch(symbol.name, query);\n if (baseScore === null) continue;\n\n const bonus = symbol.exported ? SCORE_EXPORTED_BONUS : 0;\n results.push({\n symbol,\n score: baseScore + bonus,\n matchType: getMatchType(baseScore),\n });\n }\n\n return results.sort((a, b) => b.score - a.score).slice(0, limit);\n }\n\n /** Get a compact summary of a file's symbols. */\n getFileSummary(filePath: string): FileSummary | undefined {\n const result = this.fileResults.get(filePath);\n if (result === undefined) return undefined;\n\n const kinds: Record<string, number> = {};\n let exported = 0;\n let priv = 0;\n\n for (const s of result.symbols) {\n kinds[s.kind] = (kinds[s.kind] ?? 0) + 1;\n if (s.exported) exported++;\n else priv++;\n }\n\n return {\n filePath,\n totalLines: result.totalLines,\n exportedSymbols: exported,\n privateSymbols: priv,\n kinds,\n };\n }\n\n /** List all indexed files with symbol counts. */\n listFiles(): Array<{ path: string; symbols: number; lines: number }> {\n return [...this.fileResults.entries()].map(([path, result]) => ({\n path,\n symbols: result.symbols.length,\n lines: result.totalLines,\n }));\n }\n\n /** Get index statistics. */\n get stats(): { files: number; symbols: number } {\n return {\n files: this.fileResults.size,\n symbols: this.symbols.length,\n };\n }\n}\n","/**\n * AST symbol extraction for token-efficient code retrieval.\n *\n * Uses TypeScript's compiler API to extract function, class, method,\n * interface, and type definitions from source files.\n *\n * Token savings: ~80-99% vs reading full files.\n * No additional dependencies — uses TypeScript (already a project dep).\n *\n * @module indexer/symbol-extractor\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport ts from 'typescript';\n\n/** A symbol extracted from source code. */\nexport interface CodeSymbol {\n /** Symbol name */\n name: string;\n /** Symbol kind */\n kind: 'function' | 'class' | 'method' | 'interface' | 'type' | 'variable' | 'enum';\n /** Start line (1-based) */\n startLine: number;\n /** End line (1-based) */\n endLine: number;\n /** Full source text of the symbol */\n text: string;\n /** Whether the symbol is exported */\n exported: boolean;\n}\n\n/** Result of extracting symbols from a file. */\nexport interface SymbolExtractionResult {\n filePath: string;\n symbols: CodeSymbol[];\n totalLines: number;\n totalChars: number;\n symbolChars: number;\n savingsPercent: number;\n}\n\nfunction getKind(node: ts.Node): CodeSymbol['kind'] | null {\n if (ts.isFunctionDeclaration(node)) return 'function';\n if (ts.isClassDeclaration(node)) return 'class';\n if (ts.isInterfaceDeclaration(node)) return 'interface';\n if (ts.isTypeAliasDeclaration(node)) return 'type';\n if (ts.isEnumDeclaration(node)) return 'enum';\n if (ts.isMethodDeclaration(node)) return 'method';\n if (ts.isVariableStatement(node)) return 'variable';\n return null;\n}\n\nfunction getName(node: ts.Node): string {\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isTypeAliasDeclaration(node) ||\n ts.isEnumDeclaration(node) ||\n ts.isMethodDeclaration(node)\n ) {\n const nameNode = (node as ts.NamedDeclaration).name;\n return nameNode ? nameNode.getText() : '<anonymous>';\n }\n if (ts.isVariableStatement(node)) {\n const decls = node.declarationList.declarations;\n const firstDecl = decls[0];\n if (firstDecl !== undefined) {\n return firstDecl.name.getText();\n }\n }\n return '<anonymous>';\n}\n\nfunction isExported(node: ts.Node): boolean {\n const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;\n if (modifiers) {\n return modifiers.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);\n }\n return false;\n}\n\nfunction visitNode(node: ts.Node, sourceFile: ts.SourceFile, symbols: CodeSymbol[]): void {\n const kind = getKind(node);\n if (kind !== null) {\n const name = getName(node);\n if (name !== '<anonymous>') {\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n symbols.push({\n name,\n kind,\n startLine: start.line + 1,\n endLine: end.line + 1,\n text: node.getText(sourceFile),\n exported: isExported(node),\n });\n }\n }\n if (ts.isClassDeclaration(node)) {\n visitClassMembers(node, sourceFile, symbols);\n return;\n }\n ts.forEachChild(node, (child) => {\n visitNode(child, sourceFile, symbols);\n });\n}\n\nfunction visitClassMembers(\n node: ts.ClassDeclaration,\n sourceFile: ts.SourceFile,\n symbols: CodeSymbol[]\n): void {\n for (const member of node.members) {\n if (ts.isMethodDeclaration(member) || ts.isPropertyDeclaration(member)) {\n const memberName = member.name.getText();\n if (memberName !== '<anonymous>') {\n const start = sourceFile.getLineAndCharacterOfPosition(member.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(member.getEnd());\n symbols.push({\n name: memberName,\n kind: 'method',\n startLine: start.line + 1,\n endLine: end.line + 1,\n text: member.getText(sourceFile),\n exported: false,\n });\n }\n }\n }\n}\n\nfunction computeSavings(totalChars: number, symbolChars: number): number {\n return totalChars > 0 ? Math.round(100 * (1 - symbolChars / totalChars) * 10) / 10 : 0;\n}\n\n/**\n * Extract symbols from a TypeScript/JavaScript file.\n */\nexport async function extractSymbols(filePath: string): Promise<SymbolExtractionResult> {\n const ext = extname(filePath).toLowerCase();\n if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {\n return {\n filePath,\n symbols: [],\n totalLines: 0,\n totalChars: 0,\n symbolChars: 0,\n savingsPercent: 0,\n };\n }\n\n const source = await readFile(filePath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true);\n const symbols: CodeSymbol[] = [];\n\n ts.forEachChild(sourceFile, (node) => {\n visitNode(node, sourceFile, symbols);\n });\n\n const totalChars = source.length;\n const symbolChars = symbols.reduce((sum, s) => sum + s.text.length, 0);\n\n return {\n filePath,\n symbols,\n totalLines: source.split('\\n').length,\n totalChars,\n symbolChars,\n savingsPercent: computeSavings(totalChars, symbolChars),\n };\n}\n\n/**\n * Extract a compact symbol index (names + locations only, no source text).\n * This is the minimal representation for LLM context — ~95%+ token savings.\n */\nexport async function extractSymbolIndex(filePath: string): Promise<string> {\n const result = await extractSymbols(filePath);\n if (result.symbols.length === 0) return '';\n\n const lines = result.symbols.map((s) => {\n const exp = s.exported ? 'export ' : '';\n return `${exp}${s.kind} ${s.name} (L${String(s.startLine)}-${String(s.endLine)})`;\n });\n\n return `// ${filePath} — ${String(result.symbols.length)} symbols\\n${lines.join('\\n')}`;\n}\n"],"mappings":";AAYA,SAAS,eAAe;AACxB,SAAS,SAAS,WAAAA,UAAS,gBAAgB;;;ACD3C,SAAS,gBAAgB;AACzB,SAAS,eAAe;AACxB,OAAO,QAAQ;AA4Bf,SAAS,QAAQ,MAA0C;AACzD,MAAI,GAAG,sBAAsB,IAAI,EAAG,QAAO;AAC3C,MAAI,GAAG,mBAAmB,IAAI,EAAG,QAAO;AACxC,MAAI,GAAG,uBAAuB,IAAI,EAAG,QAAO;AAC5C,MAAI,GAAG,uBAAuB,IAAI,EAAG,QAAO;AAC5C,MAAI,GAAG,kBAAkB,IAAI,EAAG,QAAO;AACvC,MAAI,GAAG,oBAAoB,IAAI,EAAG,QAAO;AACzC,MAAI,GAAG,oBAAoB,IAAI,EAAG,QAAO;AACzC,SAAO;AACT;AAEA,SAAS,QAAQ,MAAuB;AACtC,MACE,GAAG,sBAAsB,IAAI,KAC7B,GAAG,mBAAmB,IAAI,KAC1B,GAAG,uBAAuB,IAAI,KAC9B,GAAG,uBAAuB,IAAI,KAC9B,GAAG,kBAAkB,IAAI,KACzB,GAAG,oBAAoB,IAAI,GAC3B;AACA,UAAM,WAAY,KAA6B;AAC/C,WAAO,WAAW,SAAS,QAAQ,IAAI;AAAA,EACzC;AACA,MAAI,GAAG,oBAAoB,IAAI,GAAG;AAChC,UAAM,QAAQ,KAAK,gBAAgB;AACnC,UAAM,YAAY,MAAM,CAAC;AACzB,QAAI,cAAc,QAAW;AAC3B,aAAO,UAAU,KAAK,QAAQ;AAAA,IAChC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAwB;AAC1C,QAAM,YAAY,GAAG,iBAAiB,IAAI,IAAI,GAAG,aAAa,IAAI,IAAI;AACtE,MAAI,WAAW;AACb,WAAO,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,aAAa;AAAA,EACrE;AACA,SAAO;AACT;AAEA,SAAS,UAAU,MAAe,YAA2B,SAA6B;AACxF,QAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,SAAS,MAAM;AACjB,UAAM,OAAO,QAAQ,IAAI;AACzB,QAAI,SAAS,eAAe;AAC1B,YAAM,QAAQ,WAAW,8BAA8B,KAAK,SAAS,CAAC;AACtE,YAAM,MAAM,WAAW,8BAA8B,KAAK,OAAO,CAAC;AAClE,cAAQ,KAAK;AAAA,QACX;AAAA,QACA;AAAA,QACA,WAAW,MAAM,OAAO;AAAA,QACxB,SAAS,IAAI,OAAO;AAAA,QACpB,MAAM,KAAK,QAAQ,UAAU;AAAA,QAC7B,UAAU,WAAW,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AACA,MAAI,GAAG,mBAAmB,IAAI,GAAG;AAC/B,sBAAkB,MAAM,YAAY,OAAO;AAC3C;AAAA,EACF;AACA,KAAG,aAAa,MAAM,CAAC,UAAU;AAC/B,cAAU,OAAO,YAAY,OAAO;AAAA,EACtC,CAAC;AACH;AAEA,SAAS,kBACP,MACA,YACA,SACM;AACN,aAAW,UAAU,KAAK,SAAS;AACjC,QAAI,GAAG,oBAAoB,MAAM,KAAK,GAAG,sBAAsB,MAAM,GAAG;AACtE,YAAM,aAAa,OAAO,KAAK,QAAQ;AACvC,UAAI,eAAe,eAAe;AAChC,cAAM,QAAQ,WAAW,8BAA8B,OAAO,SAAS,CAAC;AACxE,cAAM,MAAM,WAAW,8BAA8B,OAAO,OAAO,CAAC;AACpE,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,MAAM;AAAA,UACN,WAAW,MAAM,OAAO;AAAA,UACxB,SAAS,IAAI,OAAO;AAAA,UACpB,MAAM,OAAO,QAAQ,UAAU;AAAA,UAC/B,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,eAAe,YAAoB,aAA6B;AACvE,SAAO,aAAa,IAAI,KAAK,MAAM,OAAO,IAAI,cAAc,cAAc,EAAE,IAAI,KAAK;AACvF;AAKA,eAAsB,eAAe,UAAmD;AACtF,QAAM,MAAM,QAAQ,QAAQ,EAAE,YAAY;AAC1C,MAAI,CAAC,CAAC,OAAO,QAAQ,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;AACjD,WAAO;AAAA,MACL;AAAA,MACA,SAAS,CAAC;AAAA,MACV,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,SAAS,UAAU,OAAO;AAC/C,QAAM,aAAa,GAAG,iBAAiB,UAAU,QAAQ,GAAG,aAAa,QAAQ,IAAI;AACrF,QAAM,UAAwB,CAAC;AAE/B,KAAG,aAAa,YAAY,CAAC,SAAS;AACpC,cAAU,MAAM,YAAY,OAAO;AAAA,EACrC,CAAC;AAED,QAAM,aAAa,OAAO;AAC1B,QAAM,cAAc,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,QAAQ,CAAC;AAErE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,OAAO,MAAM,IAAI,EAAE;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,gBAAgB,eAAe,YAAY,WAAW;AAAA,EACxD;AACF;AAMA,eAAsB,mBAAmB,UAAmC;AAC1E,QAAM,SAAS,MAAM,eAAe,QAAQ;AAC5C,MAAI,OAAO,QAAQ,WAAW,EAAG,QAAO;AAExC,QAAM,QAAQ,OAAO,QAAQ,IAAI,CAAC,MAAM;AACtC,UAAM,MAAM,EAAE,WAAW,YAAY;AACrC,WAAO,GAAG,GAAG,GAAG,EAAE,IAAI,IAAI,EAAE,IAAI,MAAM,OAAO,EAAE,SAAS,CAAC,IAAI,OAAO,EAAE,OAAO,CAAC;AAAA,EAChF,CAAC;AAED,SAAO,MAAM,QAAQ,WAAM,OAAO,OAAO,QAAQ,MAAM,CAAC;AAAA,EAAa,MAAM,KAAK,IAAI,CAAC;AACvF;;;ADxIA,IAAM,cAAc;AACpB,IAAM,eAAe;AACrB,IAAM,aAAa;AACnB,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;AAE7B,SAAS,aAAa,MAAuB;AAC3C,QAAM,MAAMC,SAAQ,IAAI,EAAE,YAAY;AACtC,SACE,CAAC,OAAO,QAAQ,OAAO,MAAM,EAAE,SAAS,GAAG,KAC3C,CAAC,KAAK,SAAS,UAAU,KACzB,CAAC,KAAK,SAAS,WAAW,KAC1B,CAAC,KAAK,SAAS,OAAO;AAE1B;AAEA,eAAe,gBAAgB,KAAa,UAAqC;AAC/E,MAAI,YAAY,EAAG,QAAO,CAAC;AAC3B,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC,CAAC;AAC1E,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,QAAQ,KAAK,MAAM,IAAI;AACxC,QAAI,MAAM,YAAY,KAAK,MAAM,SAAS,kBAAkB,MAAM,SAAS,QAAQ;AACjF,YAAM,KAAK,GAAI,MAAM,gBAAgB,UAAU,WAAW,CAAC,CAAE;AAAA,IAC/D;AACA,QAAI,MAAM,OAAO,KAAK,aAAa,MAAM,IAAI,GAAG;AAC9C,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,YAAoB,OAA6C;AACnF,QAAM,YAAY,WAAW,YAAY;AACzC,QAAM,aAAa,MAAM,YAAY;AAErC,MAAI,cAAc,WAAY,QAAO;AACrC,MAAI,UAAU,WAAW,UAAU,EAAG,QAAO;AAG7C,QAAM,QAAQ,WACX,QAAQ,mBAAmB,OAAO,EAClC,YAAY,EACZ,MAAM,SAAS;AAClB,MAAI,MAAM,KAAK,CAAC,MAAM,MAAM,UAAU,EAAG,QAAO;AAEhD,MAAI,UAAU,SAAS,UAAU,EAAG,QAAO;AAE3C,SAAO;AACT;AAEA,SAAS,aAAa,OAA0C;AAC9D,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,WAAY,QAAO;AAChC,SAAO;AACT;AAGO,IAAM,gBAAN,MAAoB;AAAA,EACR,UAA2B,CAAC;AAAA,EAC5B,cAAc,oBAAI,IAAoC;AAAA,EACtD;AAAA,EAEjB,YAAY,SAAiB;AAC3B,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,MAAM,MAAM,WAAW,GAAwB;AAC7C,UAAM,QAAQ,MAAM,gBAAgB,KAAK,SAAS,QAAQ;AAE1D,eAAW,QAAQ,OAAO;AACxB,YAAM,SAAS,MAAM,eAAe,IAAI;AACxC,YAAM,UAAU,SAAS,KAAK,SAAS,IAAI;AAC3C,WAAK,YAAY,IAAI,SAAS,MAAM;AAEpC,iBAAW,UAAU,OAAO,SAAS;AACnC,aAAK,QAAQ,KAAK,EAAE,GAAG,QAAQ,UAAU,QAAQ,CAAC;AAAA,MACpD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,cAAc,KAAK,QAAQ;AAAA,MAC3B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,OAAe,QAAQ,IAAoB;AAChD,UAAM,UAA0B,CAAC;AAEjC,eAAW,UAAU,KAAK,SAAS;AACjC,YAAM,YAAY,WAAW,OAAO,MAAM,KAAK;AAC/C,UAAI,cAAc,KAAM;AAExB,YAAM,QAAQ,OAAO,WAAW,uBAAuB;AACvD,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,OAAO,YAAY;AAAA,QACnB,WAAW,aAAa,SAAS;AAAA,MACnC,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;AAAA,EACjE;AAAA;AAAA,EAGA,eAAe,UAA2C;AACxD,UAAM,SAAS,KAAK,YAAY,IAAI,QAAQ;AAC5C,QAAI,WAAW,OAAW,QAAO;AAEjC,UAAM,QAAgC,CAAC;AACvC,QAAI,WAAW;AACf,QAAI,OAAO;AAEX,eAAW,KAAK,OAAO,SAAS;AAC9B,YAAM,EAAE,IAAI,KAAK,MAAM,EAAE,IAAI,KAAK,KAAK;AACvC,UAAI,EAAE,SAAU;AAAA,UACX;AAAA,IACP;AAEA,WAAO;AAAA,MACL;AAAA,MACA,YAAY,OAAO;AAAA,MACnB,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,YAAqE;AACnE,WAAO,CAAC,GAAG,KAAK,YAAY,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,MAAM,OAAO;AAAA,MAC9D;AAAA,MACA,SAAS,OAAO,QAAQ;AAAA,MACxB,OAAO,OAAO;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA,EAGA,IAAI,QAA4C;AAC9C,WAAO;AAAA,MACL,OAAO,KAAK,YAAY;AAAA,MACxB,SAAS,KAAK,QAAQ;AAAA,IACxB;AAAA,EACF;AACF;","names":["extname","extname"]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULTS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DWOSFYI2.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveInsideRoot
|
|
6
6
|
} from "./chunk-NUBSJGQZ.js";
|
|
7
7
|
import {
|
|
8
8
|
capitalize
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6T3EPABN.js";
|
|
10
10
|
import {
|
|
11
11
|
createAllAdapters,
|
|
12
12
|
probeCli
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ELRNVADA.js";
|
|
14
14
|
import {
|
|
15
15
|
CliNameSchema,
|
|
16
16
|
DEFAULT_CAPABILITIES,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
ok,
|
|
27
27
|
symbols,
|
|
28
28
|
writeLine
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-6UI4NKT4.js";
|
|
30
30
|
import {
|
|
31
31
|
detectSandbox,
|
|
32
32
|
getLearningDir,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
} from "./chunk-I2HMWH4R.js";
|
|
41
41
|
|
|
42
42
|
// src/version.ts
|
|
43
|
-
var VERSION = true ? "2.
|
|
43
|
+
var VERSION = true ? "2.83.1" : "dev";
|
|
44
44
|
|
|
45
45
|
// src/config/schemas-core.ts
|
|
46
46
|
import { z } from "zod";
|
|
@@ -2096,7 +2096,7 @@ async function runDoctorFix(result) {
|
|
|
2096
2096
|
writeLine2("\u2500".repeat(40));
|
|
2097
2097
|
let fixCount = 0;
|
|
2098
2098
|
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
|
|
2099
|
-
const { runSetup } = await import("./setup-command-
|
|
2099
|
+
const { runSetup } = await import("./setup-command-5AEO5A4Z.js");
|
|
2100
2100
|
const setupResult = runSetup({
|
|
2101
2101
|
skipMcp: true,
|
|
2102
2102
|
skipRules: true,
|
|
@@ -2110,7 +2110,7 @@ async function runDoctorFix(result) {
|
|
|
2110
2110
|
}
|
|
2111
2111
|
}
|
|
2112
2112
|
if (!result.configFile.found) {
|
|
2113
|
-
const { runConfigInitSync } = await import("./setup-config-
|
|
2113
|
+
const { runConfigInitSync } = await import("./setup-config-RPSVIQJO.js");
|
|
2114
2114
|
const configResult = runConfigInitSync(process.cwd(), false, false);
|
|
2115
2115
|
if (configResult.success && configResult.created) {
|
|
2116
2116
|
writeLine2(`\u2713 Generated config: ${configResult.path}`);
|
|
@@ -2208,4 +2208,4 @@ export {
|
|
|
2208
2208
|
startStdioServer,
|
|
2209
2209
|
closeServer
|
|
2210
2210
|
};
|
|
2211
|
-
//# sourceMappingURL=chunk-
|
|
2211
|
+
//# sourceMappingURL=chunk-4XSCU4B3.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GitHubProvider,
|
|
3
3
|
ScmError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZLGU7T6J.js";
|
|
5
5
|
import {
|
|
6
6
|
CACHE_TIMEOUTS,
|
|
7
7
|
createLogger,
|
|
8
8
|
err,
|
|
9
9
|
getTimeProvider,
|
|
10
10
|
ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-6UI4NKT4.js";
|
|
12
12
|
|
|
13
13
|
// src/security/trust-types.ts
|
|
14
14
|
import { z } from "zod";
|
|
@@ -1656,4 +1656,4 @@ export {
|
|
|
1656
1656
|
IssueTriage,
|
|
1657
1657
|
createIssueTriage
|
|
1658
1658
|
};
|
|
1659
|
-
//# sourceMappingURL=chunk-
|
|
1659
|
+
//# sourceMappingURL=chunk-5QJPM5CB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/text-utils.ts"],"sourcesContent":["/**\n * nexus-agents/utils - Text Processing Utilities\n *\n * Shared utility functions for text tokenization and processing.\n * Consolidates duplicate code from multiple modules per ADR-0013.\n *\n * Used by:\n * - context/agentic-memory-extraction.ts\n * - context/adaptive-memory-helpers.ts\n * - cli-adapters/agreement-cascade-helpers.ts\n *\n * @module utils/text-utils\n * @see docs/adr/0013-memory-helpers-consolidation.md\n */\n\n// ============================================================================\n// Stopwords\n// ============================================================================\n\n/**\n * Common English stopwords to filter from keyword extraction.\n */\nexport const STOPWORDS = new Set([\n 'a',\n 'an',\n 'and',\n 'are',\n 'as',\n 'at',\n 'be',\n 'by',\n 'for',\n 'from',\n 'has',\n 'he',\n 'in',\n 'is',\n 'it',\n 'its',\n 'of',\n 'on',\n 'or',\n 'that',\n 'the',\n 'to',\n 'was',\n 'were',\n 'will',\n 'with',\n 'this',\n 'but',\n 'they',\n 'have',\n 'had',\n 'what',\n 'when',\n 'where',\n 'who',\n 'which',\n 'why',\n 'how',\n 'all',\n 'each',\n 'every',\n 'both',\n 'few',\n 'more',\n 'most',\n 'other',\n 'some',\n 'such',\n 'no',\n 'nor',\n 'not',\n 'only',\n 'own',\n 'same',\n 'so',\n 'than',\n 'too',\n 'very',\n 'can',\n 'just',\n 'should',\n 'now',\n 'i',\n 'you',\n 'we',\n 'me',\n 'my',\n 'your',\n 'our',\n 'their',\n 'him',\n 'her',\n 'them',\n 'his',\n 'hers',\n 'able',\n]);\n\n// ============================================================================\n// Tokenization\n// ============================================================================\n\n/**\n * Tokenize text into normalized words.\n *\n * Process:\n * 1. Convert to lowercase\n * 2. Replace non-alphanumeric characters with spaces\n * 3. Split on whitespace\n * 4. Filter tokens by minimum length\n *\n * @param text - Input text to tokenize\n * @param minLength - Minimum token length (default: 2)\n * @returns Array of normalized tokens\n */\nexport function tokenize(text: string, minLength = 2): string[] {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, ' ')\n .split(/\\s+/)\n .filter((t) => t.length >= minLength);\n}\n\n/**\n * Tokenize text and return as a Set for fast lookups.\n *\n * @param text - Input text to tokenize\n * @param minLength - Minimum token length (default: 2)\n * @returns Set of normalized tokens\n */\nexport function tokenizeToSet(text: string, minLength = 2): Set<string> {\n return new Set(tokenize(text, minLength));\n}\n\n/**\n * Tokenize text with stopword filtering.\n *\n * @param text - Input text to tokenize\n * @param minLength - Minimum token length (default: 2)\n * @returns Array of tokens with stopwords removed\n */\nexport function tokenizeFiltered(text: string, minLength = 2): string[] {\n return tokenize(text, minLength).filter((t) => !STOPWORDS.has(t));\n}\n\n// ============================================================================\n// Value Stringification\n// ============================================================================\n\n/**\n * Convert a value to string for text processing.\n *\n * @param value - Value to stringify\n * @returns String representation\n */\nexport function stringifyValue(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value === null || value === undefined) return '';\n return JSON.stringify(value);\n}\n\n// ============================================================================\n// String Capitalization\n// ============================================================================\n\n/**\n * Capitalize the first character of a string.\n *\n * @param str - Input string\n * @returns String with first character uppercased\n * @example capitalize('hello') // 'Hello'\n */\nexport function capitalize(str: string): string {\n if (str.length === 0) return str;\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Capitalize the first character of each word in a string.\n *\n * @param str - Input string\n * @returns String with each word capitalized\n * @example capitalizeWords('hello world') // 'Hello World'\n */\nexport function capitalizeWords(str: string): string {\n return str\n .split(' ')\n .map((word) => capitalize(word))\n .join(' ');\n}\n\n/**\n * Convert a kebab-case string to Title Case.\n *\n * @param str - Kebab-case string\n * @returns Title Case string with hyphens replaced by spaces\n * @example capitalizeKebab('hello-world') // 'Hello World'\n */\nexport function capitalizeKebab(str: string): string {\n return str\n .split('-')\n .map((word) => capitalize(word))\n .join(' ');\n}\n\n// ============================================================================\n// Text Truncation\n// ============================================================================\n\n/**\n * Truncate text to a maximum length with a suffix.\n *\n * @param text - Input text\n * @param maxLength - Maximum length including suffix\n * @param suffix - Suffix to append when truncated (default: '...')\n * @returns Truncated text with suffix if needed\n * @example truncateText('hello world', 8) // 'hello...'\n */\nexport function truncateText(text: string, maxLength: number, suffix = '...'): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength - suffix.length) + suffix;\n}\n\n/**\n * Truncate text and include byte count information.\n * Commonly used for output truncation in CLI tools.\n *\n * @param text - Input text\n * @param maxLength - Maximum length before truncation marker\n * @returns Truncated text with byte count info\n * @example truncateWithInfo('hello world...', 5) // 'hello\\n... [truncated 9 bytes]'\n */\nexport function truncateWithInfo(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n const truncatedBytes = text.length - maxLength;\n return `${text.slice(0, maxLength)}\\n... [truncated ${String(truncatedBytes)} bytes]`;\n}\n\n/**\n * Truncate to the first sentence or a maximum length.\n * Useful for extracting descriptions from longer text.\n *\n * @param text - Input text\n * @param maxLength - Maximum length (default: 150)\n * @returns First sentence or truncated text\n * @example truncateSentence('Hello world. More text.', 150) // 'Hello world.'\n */\nexport function truncateSentence(text: string, maxLength = 150): string {\n // Find first sentence ending\n const sentenceEnd = text.search(/[.!?](?:\\s|$)/);\n if (sentenceEnd !== -1 && sentenceEnd < maxLength) {\n return text.slice(0, sentenceEnd + 1).trim();\n }\n // Fall back to truncation\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength).trim() + '...';\n}\n\n// ============================================================================\n// Line Splitting\n// ============================================================================\n\n/**\n * Split text into lines.\n * Handles both Unix (\\n) and Windows (\\r\\n) line endings.\n *\n * @param text - Input text to split\n * @returns Array of lines (may include empty strings)\n * @example splitLines('a\\nb\\nc') // ['a', 'b', 'c']\n * @example splitLines('a\\n\\nb') // ['a', '', 'b']\n */\nexport function splitLines(text: string): string[] {\n return text.split(/\\r?\\n/);\n}\n\n/**\n * Split text into non-empty lines.\n * Filters out empty lines and whitespace-only lines.\n *\n * @param text - Input text to split\n * @returns Array of non-empty lines\n * @example splitNonEmptyLines('a\\n\\nb\\n \\nc') // ['a', 'b', 'c']\n */\nexport function splitNonEmptyLines(text: string): string[] {\n return text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\n/**\n * Split text into trimmed lines, preserving empty lines.\n * Trims each line but keeps empty lines in the output.\n *\n * @param text - Input text to split\n * @returns Array of trimmed lines\n * @example splitTrimmedLines(' a \\n\\n b ') // ['a', '', 'b']\n */\nexport function splitTrimmedLines(text: string): string[] {\n return text.split(/\\r?\\n/).map((line) => line.trim());\n}\n\n// ============================================================================\n// Sentence/Word Splitting\n// ============================================================================\n\n/**\n * Count the number of sentences in text.\n * Counts sentence-ending punctuation followed by space or end of string.\n *\n * @param text - Input text\n * @returns Number of sentences\n * @example countSentences('Hello world. How are you?') // 2\n */\nexport function countSentences(text: string): number {\n const matches = text.match(/[.!?]+(?:\\s|$)/g);\n return matches !== null ? matches.length : 0;\n}\n\n/**\n * Split text into sentences.\n * Splits on sentence-ending punctuation followed by space.\n *\n * @param text - Input text\n * @returns Array of sentences (trimmed)\n * @example splitSentences('Hello world. How are you?') // ['Hello world.', 'How are you?']\n */\nexport function splitSentences(text: string): string[] {\n // Split on sentence endings followed by space, keeping the punctuation\n return text\n .split(/(?<=[.!?])\\s+/)\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n}\n\n/**\n * Count the number of words in text.\n * Splits on whitespace and counts non-empty tokens.\n *\n * @param text - Input text\n * @returns Number of words\n * @example countWords('Hello world') // 2\n */\nexport function countWords(text: string): number {\n return text\n .trim()\n .split(/\\s+/)\n .filter((w) => w.length > 0).length;\n}\n"],"mappings":";AAsBO,IAAM,YAAY,oBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAmBM,SAAS,SAAS,MAAc,YAAY,GAAa;AAC9D,SAAO,KACJ,YAAY,EACZ,QAAQ,gBAAgB,GAAG,EAC3B,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS;AACxC;AAoBO,SAAS,iBAAiB,MAAc,YAAY,GAAa;AACtE,SAAO,SAAS,MAAM,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;AAClE;AAYO,SAAS,eAAe,OAAwB;AACrD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,SAAO,KAAK,UAAU,KAAK;AAC7B;AAaO,SAAS,WAAW,KAAqB;AAC9C,MAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,SAAO,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC;AAClD;AASO,SAAS,gBAAgB,KAAqB;AACnD,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,WAAW,IAAI,CAAC,EAC9B,KAAK,GAAG;AACb;AASO,SAAS,gBAAgB,KAAqB;AACnD,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,WAAW,IAAI,CAAC,EAC9B,KAAK,GAAG;AACb;AA6BO,SAAS,iBAAiB,MAAc,WAA2B;AACxE,MAAI,KAAK,UAAU,UAAW,QAAO;AACrC,QAAM,iBAAiB,KAAK,SAAS;AACrC,SAAO,GAAG,KAAK,MAAM,GAAG,SAAS,CAAC;AAAA,iBAAoB,OAAO,cAAc,CAAC;AAC9E;AAWO,SAAS,iBAAiB,MAAc,YAAY,KAAa;AAEtE,QAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,MAAI,gBAAgB,MAAM,cAAc,WAAW;AACjD,WAAO,KAAK,MAAM,GAAG,cAAc,CAAC,EAAE,KAAK;AAAA,EAC7C;AAEA,MAAI,KAAK,UAAU,UAAW,QAAO;AACrC,SAAO,KAAK,MAAM,GAAG,SAAS,EAAE,KAAK,IAAI;AAC3C;","names":[]}
|
|
@@ -7923,8 +7923,8 @@ var OutcomeStore = class {
|
|
|
7923
7923
|
/** Query outcomes with optional filters. */
|
|
7924
7924
|
query(filter) {
|
|
7925
7925
|
if (filter === void 0) return [...this.entries];
|
|
7926
|
-
|
|
7927
|
-
return
|
|
7926
|
+
if (filter.limit === void 0) return applyFilters(this.entries, filter);
|
|
7927
|
+
return tailScan(this.entries, filter, filter.limit);
|
|
7928
7928
|
}
|
|
7929
7929
|
/**
|
|
7930
7930
|
* Query outcomes for a specific model with a family-level warm-start
|
|
@@ -7940,20 +7940,16 @@ var OutcomeStore = class {
|
|
|
7940
7940
|
queryByModelWithFamilyFallback(modelId, options) {
|
|
7941
7941
|
const threshold = options?.threshold ?? DEFAULT_FAMILY_FALLBACK_THRESHOLD;
|
|
7942
7942
|
const base = options?.extraFilter ?? {};
|
|
7943
|
-
const literal = applyFilters(this.entries, base).filter((o) => o.model === modelId);
|
|
7944
|
-
if (literal.length >= threshold) {
|
|
7945
|
-
const entry2 = this.registry.getEntry(modelId);
|
|
7946
|
-
return { outcomes: literal, scope: "literal", vendor: entry2.vendor, family: entry2.family };
|
|
7947
|
-
}
|
|
7948
7943
|
const entry = this.registry.getEntry(modelId);
|
|
7949
|
-
const family =
|
|
7950
|
-
(
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
o.vendor === entry.vendor && o.family === entry.family
|
|
7955
|
-
)
|
|
7944
|
+
const { literal, family } = partitionByLiteralAndFamily(
|
|
7945
|
+
applyFilters(this.entries, base),
|
|
7946
|
+
modelId,
|
|
7947
|
+
entry.vendor,
|
|
7948
|
+
entry.family
|
|
7956
7949
|
);
|
|
7950
|
+
if (literal.length >= threshold) {
|
|
7951
|
+
return { outcomes: literal, scope: "literal", vendor: entry.vendor, family: entry.family };
|
|
7952
|
+
}
|
|
7957
7953
|
if (family.length === 0) {
|
|
7958
7954
|
return { outcomes: literal, scope: "empty", vendor: entry.vendor, family: entry.family };
|
|
7959
7955
|
}
|
|
@@ -8123,6 +8119,30 @@ function applyFilters(entries, filter) {
|
|
|
8123
8119
|
const preds = buildPredicates(filter);
|
|
8124
8120
|
return entries.filter((o) => preds.every((p) => p(o)));
|
|
8125
8121
|
}
|
|
8122
|
+
function partitionByLiteralAndFamily(baseFiltered, modelId, vendor, family) {
|
|
8123
|
+
const literalBucket = [];
|
|
8124
|
+
const familyBucket = [];
|
|
8125
|
+
for (const o of baseFiltered) {
|
|
8126
|
+
if (o.vendor !== vendor || o.family !== family) continue;
|
|
8127
|
+
familyBucket.push(o);
|
|
8128
|
+
if (o.model === modelId) literalBucket.push(o);
|
|
8129
|
+
}
|
|
8130
|
+
return { literal: literalBucket, family: familyBucket };
|
|
8131
|
+
}
|
|
8132
|
+
function tailScan(entries, filter, limit) {
|
|
8133
|
+
if (limit <= 0) return [];
|
|
8134
|
+
const preds = buildPredicates(filter);
|
|
8135
|
+
const collected = [];
|
|
8136
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
8137
|
+
const o = entries[i];
|
|
8138
|
+
if (o === void 0) continue;
|
|
8139
|
+
if (preds.every((p) => p(o))) {
|
|
8140
|
+
collected.push(o);
|
|
8141
|
+
if (collected.length >= limit) break;
|
|
8142
|
+
}
|
|
8143
|
+
}
|
|
8144
|
+
return collected.reverse();
|
|
8145
|
+
}
|
|
8126
8146
|
function groupBy(outcomes, keyFn) {
|
|
8127
8147
|
const groups = /* @__PURE__ */ new Map();
|
|
8128
8148
|
for (const o of outcomes) {
|
|
@@ -10297,7 +10317,10 @@ function getPerformanceDataForCategory(taskContent) {
|
|
|
10297
10317
|
});
|
|
10298
10318
|
}
|
|
10299
10319
|
return result;
|
|
10300
|
-
} catch {
|
|
10320
|
+
} catch (error) {
|
|
10321
|
+
logger9.debug("Performance-floor outcome-store read failed; skipping penalty", {
|
|
10322
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10323
|
+
});
|
|
10301
10324
|
return /* @__PURE__ */ new Map();
|
|
10302
10325
|
}
|
|
10303
10326
|
}
|
|
@@ -10456,7 +10479,10 @@ function getWeatherBonusForTask(taskContent) {
|
|
|
10456
10479
|
const match = detectTaskCategory(taskContent);
|
|
10457
10480
|
if (match === null) return /* @__PURE__ */ new Map();
|
|
10458
10481
|
return getWeatherBonusScores(match.category);
|
|
10459
|
-
} catch {
|
|
10482
|
+
} catch (error) {
|
|
10483
|
+
logger9.debug("Weather bonus outcome-store read failed; skipping bonus", {
|
|
10484
|
+
error: error instanceof Error ? error.message : String(error)
|
|
10485
|
+
});
|
|
10460
10486
|
return /* @__PURE__ */ new Map();
|
|
10461
10487
|
}
|
|
10462
10488
|
}
|
|
@@ -10971,7 +10997,7 @@ var CompositeRouter = class _CompositeRouter {
|
|
|
10971
10997
|
*/
|
|
10972
10998
|
async consultUnifiedContext(task) {
|
|
10973
10999
|
try {
|
|
10974
|
-
const { getContextForTask, inferTaskCategory } = await import("./context-retriever-
|
|
11000
|
+
const { getContextForTask, inferTaskCategory } = await import("./context-retriever-GQRC2MVM.js");
|
|
10975
11001
|
const ctx = await getContextForTask({
|
|
10976
11002
|
task: task.content,
|
|
10977
11003
|
category: inferTaskCategory(task.content),
|
|
@@ -12269,4 +12295,4 @@ export {
|
|
|
12269
12295
|
ParseError,
|
|
12270
12296
|
OrchestratorError
|
|
12271
12297
|
};
|
|
12272
|
-
//# sourceMappingURL=chunk-
|
|
12298
|
+
//# sourceMappingURL=chunk-6UI4NKT4.js.map
|