nexus-agents 3.5.0 → 3.5.2

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.
@@ -8,7 +8,7 @@ import {
8
8
  checkSqlite,
9
9
  defaultConfig,
10
10
  initDataDirectories
11
- } from "./chunk-3EIACKNR.js";
11
+ } from "./chunk-J2FUCIPH.js";
12
12
  import {
13
13
  BUILT_IN_EXPERTS
14
14
  } from "./chunk-YPNQPT2F.js";
@@ -2001,4 +2001,4 @@ export {
2001
2001
  setupCommand,
2002
2002
  setupCommandAsync
2003
2003
  };
2004
- //# sourceMappingURL=chunk-NWTACWXE.js.map
2004
+ //# sourceMappingURL=chunk-66QB5SML.js.map
@@ -6,6 +6,7 @@ import { resolve, extname as extname2, relative } from "path";
6
6
  import { readFile } from "fs/promises";
7
7
  import { extname } from "path";
8
8
  import ts from "typescript";
9
+ var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
9
10
  function getKind(node) {
10
11
  if (ts.isFunctionDeclaration(node)) return "function";
11
12
  if (ts.isClassDeclaration(node)) return "class";
@@ -86,14 +87,15 @@ function computeSavings(totalChars, symbolChars) {
86
87
  }
87
88
  async function extractSymbols(filePath) {
88
89
  const ext = extname(filePath).toLowerCase();
89
- if (![".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
90
+ if (!SUPPORTED_EXTENSIONS.includes(ext)) {
90
91
  return {
91
92
  filePath,
92
93
  symbols: [],
93
94
  totalLines: 0,
94
95
  totalChars: 0,
95
96
  symbolChars: 0,
96
- savingsPercent: 0
97
+ savingsPercent: 0,
98
+ parsed: false
97
99
  };
98
100
  }
99
101
  const source = await readFile(filePath, "utf-8");
@@ -110,12 +112,17 @@ async function extractSymbols(filePath) {
110
112
  totalLines: source.split("\n").length,
111
113
  totalChars,
112
114
  symbolChars,
113
- savingsPercent: computeSavings(totalChars, symbolChars)
115
+ savingsPercent: computeSavings(totalChars, symbolChars),
116
+ parsed: true
114
117
  };
115
118
  }
116
- async function extractSymbolIndex(filePath) {
119
+ async function extractSymbolIndexResult(filePath) {
117
120
  const result = await extractSymbols(filePath);
118
- if (result.symbols.length === 0) return "";
121
+ if (!result.parsed) return { kind: "empty", reason: "unsupported" };
122
+ if (result.symbols.length === 0) return { kind: "empty", reason: "no-declarations" };
123
+ return { kind: "index", index: renderIndex(filePath, result) };
124
+ }
125
+ function renderIndex(filePath, result) {
119
126
  const lines = result.symbols.map((s) => {
120
127
  const exp = s.exported ? "export " : "";
121
128
  return `${exp}${s.kind} ${s.name} (L${String(s.startLine)}-${String(s.endLine)})`;
@@ -257,11 +264,12 @@ var CodebaseIndex = class {
257
264
  };
258
265
 
259
266
  export {
267
+ SUPPORTED_EXTENSIONS,
260
268
  extractSymbols,
261
- extractSymbolIndex,
269
+ extractSymbolIndexResult,
262
270
  DEFAULT_INDEX_MAX_DEPTH,
263
271
  MAX_INDEX_MAX_DEPTH,
264
272
  findSourceFiles,
265
273
  CodebaseIndex
266
274
  };
267
- //# sourceMappingURL=chunk-YF35FKKD.js.map
275
+ //# sourceMappingURL=chunk-BQTMMLQQ.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 /** Directories not descended into because `maxDepth` was exhausted (#4243). */\n skippedDirs: number;\n}\n\n/** Default recursion depth for `CodebaseIndex.index()` (#4243 — was hardcoded 4). */\nexport const DEFAULT_INDEX_MAX_DEPTH = 24;\n/** Upper clamp for caller-supplied `maxDepth` to bound worst-case tree-walk cost. */\nexport const MAX_INDEX_MAX_DEPTH = 64;\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\n/** Result of a recursive source-file walk: the files found plus a truncation signal. */\nexport interface FindSourceFilesResult {\n files: string[];\n /** Count of directories that were NOT descended into because maxDepth hit 0. */\n skippedDirs: number;\n}\n\n/**\n * Recursively collect TS/JS source files under `dir`, bounded by `maxDepth`,\n * skipping `node_modules`/`dist` and test/declaration files. Exported so the\n * `search_usages` tool (#4265) reuses the exact same source-file set the symbol\n * index walks — keeping the two tools' scopes apples-to-apples (DRY).\n */\nexport async function findSourceFiles(\n dir: string,\n maxDepth: number\n): Promise<FindSourceFilesResult> {\n if (maxDepth <= 0) return { files: [], skippedDirs: 1 };\n const files: string[] = [];\n let skippedDirs = 0;\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 const sub = await findSourceFiles(fullPath, maxDepth - 1);\n files.push(...sub.files);\n skippedDirs += sub.skippedDirs;\n }\n if (entry.isFile() && isSourceFile(entry.name)) {\n files.push(fullPath);\n }\n }\n return { files, skippedDirs };\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 private skippedDirs = 0;\n\n constructor(rootDir: string) {\n this.rootDir = rootDir;\n }\n\n /**\n * Index all TS/JS source files in the directory.\n *\n * `maxDepth` is clamped to `[1, MAX_INDEX_MAX_DEPTH]` so a caller-supplied\n * value can't force an unbounded tree-walk (#4243).\n */\n async index(maxDepth: number = DEFAULT_INDEX_MAX_DEPTH): Promise<IndexStats> {\n const clampedDepth = Math.min(Math.max(maxDepth, 1), MAX_INDEX_MAX_DEPTH);\n const { files, skippedDirs } = await findSourceFiles(this.rootDir, clampedDepth);\n this.skippedDirs = skippedDirs;\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 skippedDirs,\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; skippedDirs: number } {\n return {\n files: this.fileResults.size,\n symbols: this.symbols.length,\n skippedDirs: this.skippedDirs,\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/**\n * Extensions the TypeScript compiler API path can parse (#4517).\n *\n * Exported so the tool layer can name them in its error message instead of\n * asserting a file \"may not be TypeScript/JavaScript\" without saying what\n * would count.\n */\nexport const SUPPORTED_EXTENSIONS: readonly string[] = ['.ts', '.tsx', '.js', '.jsx'];\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 * Whether the file was actually parsed (#4517).\n *\n * `false` means the extension is not supported, so `symbols: []` reports\n * that nothing was READ — not that nothing is there. An unsupported file and\n * a genuinely symbol-free file previously returned identical results, and\n * the tool guessed between them wrongly: a valid TypeScript barrel of 20\n * re-exports was reported as possibly-not-TypeScript.\n */\n parsed: boolean;\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 (!SUPPORTED_EXTENSIONS.includes(ext)) {\n return {\n filePath,\n symbols: [],\n totalLines: 0,\n totalChars: 0,\n symbolChars: 0,\n savingsPercent: 0,\n parsed: false,\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 parsed: true,\n };\n}\n\n/**\n * Why {@link extractSymbolIndex} produced no index (#4517).\n *\n * `unsupported` and `no-declarations` are different facts about the world:\n * the first says the file was never read, the second says it was read and\n * genuinely declares nothing locally — a re-export barrel, typically. Callers\n * that collapse them tell the user to check a file type that was never the\n * problem.\n */\nexport type EmptyIndexReason = 'unsupported' | 'no-declarations';\n\n/** A symbol index, or the reason there is none. */\nexport type SymbolIndexResult =\n | { readonly kind: 'index'; readonly index: string }\n | { readonly kind: 'empty'; readonly reason: EmptyIndexReason };\n\n/**\n * Extract a compact symbol index, reporting why when there is nothing to show.\n *\n * Names + locations only, no source text — the minimal representation for LLM\n * context (~95%+ token savings). Replaced the earlier `extractSymbolIndex`,\n * which returned a bare `''` for both \"could not read\" and \"read, found\n * nothing\" and so could not tell a caller which had happened.\n */\nexport async function extractSymbolIndexResult(filePath: string): Promise<SymbolIndexResult> {\n const result = await extractSymbols(filePath);\n if (!result.parsed) return { kind: 'empty', reason: 'unsupported' };\n if (result.symbols.length === 0) return { kind: 'empty', reason: 'no-declarations' };\n return { kind: 'index', index: renderIndex(filePath, result) };\n}\n\nfunction renderIndex(filePath: string, result: SymbolExtractionResult): string {\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 return `// ${filePath} — ${String(result.symbols.length)} symbols\\n${lines.join('\\n')}`;\n}\n"],"mappings":"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","names":["extname","extname"]}
@@ -49,7 +49,7 @@ import {
49
49
  } from "./chunk-OQLFRJCW.js";
50
50
 
51
51
  // src/version.ts
52
- var VERSION = true ? "3.5.0" : "dev";
52
+ var VERSION = true ? "3.5.2" : "dev";
53
53
 
54
54
  // src/config/schemas-core.ts
55
55
  import { z } from "zod";
@@ -2287,7 +2287,7 @@ async function runDoctorFix(result) {
2287
2287
  writeLine2("\u2500".repeat(40));
2288
2288
  let fixCount = 0;
2289
2289
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
2290
- const { runSetup } = await import("./setup-command-ISVGN73J.js");
2290
+ const { runSetup } = await import("./setup-command-DOPNW32N.js");
2291
2291
  const setupResult = runSetup({
2292
2292
  skipMcp: true,
2293
2293
  skipRules: true,
@@ -2400,4 +2400,4 @@ export {
2400
2400
  startStdioServer,
2401
2401
  closeServer
2402
2402
  };
2403
- //# sourceMappingURL=chunk-3EIACKNR.js.map
2403
+ //# sourceMappingURL=chunk-J2FUCIPH.js.map
@@ -8,10 +8,11 @@ import {
8
8
  CodebaseIndex,
9
9
  DEFAULT_INDEX_MAX_DEPTH,
10
10
  MAX_INDEX_MAX_DEPTH,
11
- extractSymbolIndex,
11
+ SUPPORTED_EXTENSIONS,
12
+ extractSymbolIndexResult,
12
13
  extractSymbols,
13
14
  findSourceFiles
14
- } from "./chunk-YF35FKKD.js";
15
+ } from "./chunk-BQTMMLQQ.js";
15
16
  import {
16
17
  FINDING_SEVERITY_LEVELS,
17
18
  SARIF_LEVEL_MAP,
@@ -21,7 +22,7 @@ import {
21
22
  DEFAULT_TASK_TTL_MS,
22
23
  DEFAULT_TOOL_RATE_LIMITS,
23
24
  clampTaskTtl
24
- } from "./chunk-3EIACKNR.js";
25
+ } from "./chunk-J2FUCIPH.js";
25
26
  import {
26
27
  executeExpert
27
28
  } from "./chunk-GVLDWGSK.js";
@@ -20780,7 +20781,7 @@ import * as fs2 from "fs/promises";
20780
20781
  import * as path2 from "path";
20781
20782
  import * as yaml from "yaml";
20782
20783
  var MAX_FILE_SIZE_BYTES = 1024 * 1024;
20783
- var SUPPORTED_EXTENSIONS = [".yaml", ".yml", ".json"];
20784
+ var SUPPORTED_EXTENSIONS2 = [".yaml", ".yml", ".json"];
20784
20785
  function validatePath(userPath, allowedRoot) {
20785
20786
  const resolved = resolveInsideRoot(userPath, allowedRoot);
20786
20787
  if (resolved === null) {
@@ -20912,10 +20913,10 @@ async function loadWorkflowFile(filePath, allowedRoot = process.cwd()) {
20912
20913
  }
20913
20914
  const validatedPath = pathValidation.value;
20914
20915
  const ext = path2.extname(validatedPath).toLowerCase();
20915
- if (!SUPPORTED_EXTENSIONS.includes(ext)) {
20916
+ if (!SUPPORTED_EXTENSIONS2.includes(ext)) {
20916
20917
  return err(
20917
20918
  new ParseError(
20918
- `Unsupported file extension: ${ext}. Supported: ${SUPPORTED_EXTENSIONS.join(", ")}`
20919
+ `Unsupported file extension: ${ext}. Supported: ${SUPPORTED_EXTENSIONS2.join(", ")}`
20919
20920
  )
20920
20921
  );
20921
20922
  }
@@ -41741,7 +41742,7 @@ function registerSearchCodebaseTool(server, deps) {
41741
41742
  }
41742
41743
 
41743
41744
  // src/mcp/tools/extract-symbols-tool.ts
41744
- import { resolve as resolve8, sep as sep4 } from "path";
41745
+ import { extname as extname3, resolve as resolve8, sep as sep4 } from "path";
41745
41746
  import { z as z81 } from "zod";
41746
41747
  var DEFAULT_EXTRACT_MAX_CHARS = 2e4;
41747
41748
  var DEFAULT_EXTRACT_MAX_SYMBOLS = 200;
@@ -41857,11 +41858,11 @@ async function extractSymbolsHandler(args, ctx) {
41857
41858
  );
41858
41859
  return toolSuccess(output2);
41859
41860
  }
41860
- const index = await extractSymbolIndex(resolvedPath);
41861
- if (index === "") {
41862
- return toolSuccess("No symbols found (file may not be TypeScript/JavaScript)");
41861
+ const result = await extractSymbolIndexResult(resolvedPath);
41862
+ if (result.kind === "empty") {
41863
+ return toolSuccess(emptyIndexMessage(result.reason, resolvedPath));
41863
41864
  }
41864
- return toolSuccess(index);
41865
+ return toolSuccess(result.index);
41865
41866
  } catch (caught) {
41866
41867
  const e = caught instanceof Error ? caught : new Error(String(caught));
41867
41868
  ctx.logger.error("Symbol extraction failed", e);
@@ -41871,6 +41872,14 @@ async function extractSymbolsHandler(args, ctx) {
41871
41872
  });
41872
41873
  }
41873
41874
  }
41875
+ function emptyIndexMessage(reason, filePath) {
41876
+ if (reason === "unsupported") {
41877
+ const ext = extname3(filePath).toLowerCase();
41878
+ const shown = ext === "" ? "(no extension)" : ext;
41879
+ return `Not parsed: extract_symbols cannot read ${shown} files. Supported: ${SUPPORTED_EXTENSIONS.join(", ")}. This says nothing about whether the file contains symbols.`;
41880
+ }
41881
+ return "Parsed successfully; no local declarations found. A re-export barrel (`export { X } from ...`) reports zero symbols because re-exports declare nothing locally.";
41882
+ }
41874
41883
  function registerExtractSymbolsTool(server, deps) {
41875
41884
  const logger58 = deps.logger ?? createLogger({ tool: "extract_symbols" });
41876
41885
  const toolSchema = {
@@ -45335,6 +45344,68 @@ function buildScanSummary(total, confirmed, falsePositives, osvCount) {
45335
45344
  return parts.join(", ");
45336
45345
  }
45337
45346
 
45347
+ // src/security/quality-gate-commands.ts
45348
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
45349
+ import { join as join9 } from "path";
45350
+ var LOCKFILES = [
45351
+ { file: "pnpm-lock.yaml", manager: "pnpm" },
45352
+ { file: "yarn.lock", manager: "yarn" },
45353
+ { file: "bun.lockb", manager: "bun" },
45354
+ { file: "package-lock.json", manager: "npm" }
45355
+ ];
45356
+ var SCRIPT_CANDIDATES = {
45357
+ lint: ["lint"],
45358
+ typecheck: ["typecheck", "type-check", "types"],
45359
+ tests: ["test", "tests"],
45360
+ build: ["build"]
45361
+ };
45362
+ function detectPackageManager(projectDir) {
45363
+ for (const { file, manager } of LOCKFILES) {
45364
+ if (existsSync9(join9(projectDir, file))) return manager;
45365
+ }
45366
+ return "npm";
45367
+ }
45368
+ function readScripts(projectDir) {
45369
+ const manifest = join9(projectDir, "package.json");
45370
+ if (!existsSync9(manifest)) return void 0;
45371
+ try {
45372
+ const parsed = JSON.parse(readFileSync7(manifest, "utf-8"));
45373
+ if (typeof parsed !== "object" || parsed === null) return void 0;
45374
+ const scripts = parsed.scripts;
45375
+ if (typeof scripts !== "object" || scripts === null) return void 0;
45376
+ const out = {};
45377
+ for (const [name, body] of Object.entries(scripts)) {
45378
+ if (typeof body === "string") out[name] = body;
45379
+ }
45380
+ return out;
45381
+ } catch {
45382
+ return void 0;
45383
+ }
45384
+ }
45385
+ function resolveCheckCommand(projectDir, check) {
45386
+ const scripts = readScripts(projectDir);
45387
+ if (scripts === void 0) {
45388
+ return {
45389
+ kind: "unconfigured",
45390
+ reason: `no readable package.json in ${projectDir}, so the "${check}" script could not be resolved`
45391
+ };
45392
+ }
45393
+ const candidates = SCRIPT_CANDIDATES[check];
45394
+ const found = candidates.find((name) => (scripts[name] ?? "").trim() !== "");
45395
+ if (found === void 0) {
45396
+ return {
45397
+ kind: "unconfigured",
45398
+ reason: `no "${check}" script declared (looked for: ${candidates.join(", ")})`
45399
+ };
45400
+ }
45401
+ return {
45402
+ kind: "command",
45403
+ command: detectPackageManager(projectDir),
45404
+ args: ["run", "--silent", found],
45405
+ script: found
45406
+ };
45407
+ }
45408
+
45338
45409
  // src/security/quality-gate.ts
45339
45410
  async function runCommandCheck(name, command, args, cwd) {
45340
45411
  const start = Date.now();
@@ -45359,17 +45430,31 @@ async function runCommandCheck(name, command, args, cwd) {
45359
45430
  };
45360
45431
  }
45361
45432
  }
45433
+ function scriptedCheck(name, check, projectDir) {
45434
+ return async () => {
45435
+ const resolved = resolveCheckCommand(projectDir, check);
45436
+ if (resolved.kind === "unconfigured") {
45437
+ return {
45438
+ name,
45439
+ verdict: "skip",
45440
+ details: `Not run: ${resolved.reason}. Declare the script to enable this check.`,
45441
+ durationMs: 0
45442
+ };
45443
+ }
45444
+ return runCommandCheck(name, resolved.command, resolved.args, projectDir);
45445
+ };
45446
+ }
45362
45447
  function checkTypeCheck(projectDir) {
45363
- return () => runCommandCheck("type_check", "npx", ["tsc", "--noEmit", "--project", projectDir], projectDir);
45448
+ return scriptedCheck("type_check", "typecheck", projectDir);
45364
45449
  }
45365
45450
  function checkLint(projectDir) {
45366
- return () => runCommandCheck("lint", "npx", ["eslint", "--max-warnings", "0", projectDir], projectDir);
45451
+ return scriptedCheck("lint", "lint", projectDir);
45367
45452
  }
45368
45453
  function checkTests(projectDir) {
45369
- return () => runCommandCheck("tests", "npx", ["vitest", "run", "--dir", projectDir], projectDir);
45454
+ return scriptedCheck("tests", "tests", projectDir);
45370
45455
  }
45371
45456
  function checkBuild(projectDir) {
45372
- return () => runCommandCheck("build", "pnpm", ["build"], projectDir);
45457
+ return scriptedCheck("build", "build", projectDir);
45373
45458
  }
45374
45459
  function aggregateResults2(checks) {
45375
45460
  let pass = 0;
@@ -45380,14 +45465,23 @@ function aggregateResults2(checks) {
45380
45465
  else if (c.verdict === "fail") fail++;
45381
45466
  else skip2++;
45382
45467
  }
45383
- return { verdict: fail > 0 ? "fail" : "pass", summary: { pass, fail, skip: skip2 } };
45468
+ const verdict = fail > 0 ? "fail" : pass === 0 && skip2 > 0 ? "skip" : "pass";
45469
+ return { verdict, summary: { pass, fail, skip: skip2 } };
45384
45470
  }
45385
45471
  function generateFeedback2(checks) {
45386
45472
  const failures = checks.filter((c) => c.verdict === "fail");
45387
- if (failures.length === 0) return "All checks passed.";
45473
+ const skipped = checks.filter((c) => c.verdict === "skip");
45474
+ const skipNote = skipped.length > 0 ? `
45475
+ ${String(skipped.length)} check(s) did not run:
45476
+ ${skipped.map((s) => `- ${s.name}: ${s.details}`).join("\n")}` : "";
45477
+ if (failures.length === 0) {
45478
+ const ran = checks.length - skipped.length;
45479
+ const headline = ran === 0 ? "No checks ran." : `All ${String(ran)} check(s) that ran passed.`;
45480
+ return `${headline}${skipNote}`;
45481
+ }
45388
45482
  const lines = failures.map((f) => `- ${f.name}: ${f.details}`);
45389
45483
  return `${String(failures.length)} check(s) failed:
45390
- ${lines.join("\n")}`;
45484
+ ${lines.join("\n")}${skipNote}`;
45391
45485
  }
45392
45486
  async function runQualityGate(stage, checks, iteration = 1) {
45393
45487
  const results = [];
@@ -46210,7 +46304,7 @@ function createScaffoldStageWrapper() {
46210
46304
  }
46211
46305
  async function searchCodebaseForTask(task) {
46212
46306
  try {
46213
- const { CodebaseIndex: CodebaseIndex2 } = await import("./codebase-search-LUF5YJLQ.js");
46307
+ const { CodebaseIndex: CodebaseIndex2 } = await import("./codebase-search-AATGEN2H.js");
46214
46308
  const index = new CodebaseIndex2(process.cwd());
46215
46309
  const terms = task.toLowerCase().split(/\s+/).filter((w) => w.length > 4).slice(0, 3);
46216
46310
  if (terms.length === 0) return null;
@@ -46447,8 +46541,8 @@ function reviewedDiffWasTruncated(diff) {
46447
46541
  }
46448
46542
 
46449
46543
  // src/audit/pr-review-record-store.ts
46450
- import { appendFileSync as appendFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync7 } from "fs";
46451
- import { dirname as dirname4, isAbsolute, join as join9, resolve as resolve13 } from "path";
46544
+ import { appendFileSync as appendFileSync4, existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "fs";
46545
+ import { dirname as dirname4, isAbsolute, join as join10, resolve as resolve13 } from "path";
46452
46546
 
46453
46547
  // src/audit/pr-review-record.ts
46454
46548
  import * as crypto3 from "crypto";
@@ -46579,7 +46673,7 @@ function assertNotSourceCheckoutWrite(filePath) {
46579
46673
  if (!isUnderTestRunner()) return;
46580
46674
  const here = findRepoRoot(process.cwd());
46581
46675
  if (here === null) return;
46582
- if (resolve13(filePath) !== resolve13(join9(here, PR_REVIEW_RECORDS_REL_PATH))) return;
46676
+ if (resolve13(filePath) !== resolve13(join10(here, PR_REVIEW_RECORDS_REL_PATH))) return;
46583
46677
  throw new Error(
46584
46678
  `Refusing to write ${filePath} from a test run (#4415): this is the source checkout's tracked, hash-chained audit file, and a fabricated record that chains cleanly is indistinguishable from a real verdict. Pass repoPath to a throwaway repo, or set NEXUS_PR_REVIEW_RECORDS_PATH.`
46585
46679
  );
@@ -46591,17 +46685,17 @@ function resolvePrReviewRecordsPath(repoPathOverride) {
46591
46685
  }
46592
46686
  if (repoPathOverride !== void 0 && repoPathOverride.trim() !== "") {
46593
46687
  const overrideRoot = findRepoRoot(repoPathOverride);
46594
- if (overrideRoot !== null) return join9(overrideRoot, PR_REVIEW_RECORDS_REL_PATH);
46688
+ if (overrideRoot !== null) return join10(overrideRoot, PR_REVIEW_RECORDS_REL_PATH);
46595
46689
  }
46596
46690
  const root = findRepoRoot(process.cwd());
46597
46691
  if (root === null) return void 0;
46598
- return join9(root, PR_REVIEW_RECORDS_REL_PATH);
46692
+ return join10(root, PR_REVIEW_RECORDS_REL_PATH);
46599
46693
  }
46600
46694
  function readPrReviewRecords(filePath) {
46601
46695
  const records = [];
46602
46696
  const invalidLines = [];
46603
- if (!existsSync9(filePath)) return { records, invalidLines };
46604
- const lines = readFileSync7(filePath, "utf-8").split("\n").filter((l) => l.trim() !== "");
46697
+ if (!existsSync10(filePath)) return { records, invalidLines };
46698
+ const lines = readFileSync8(filePath, "utf-8").split("\n").filter((l) => l.trim() !== "");
46605
46699
  for (const [i, line] of lines.entries()) {
46606
46700
  try {
46607
46701
  const parsed = PrReviewRecordSchema.safeParse(JSON.parse(line));
@@ -46614,7 +46708,7 @@ function readPrReviewRecords(filePath) {
46614
46708
  return { records, invalidLines };
46615
46709
  }
46616
46710
  function readPrReviewLedgerTip(filePath, logger58) {
46617
- if (!existsSync9(filePath)) return { maxSequence: -1, lastHash: void 0 };
46711
+ if (!existsSync10(filePath)) return { maxSequence: -1, lastHash: void 0 };
46618
46712
  try {
46619
46713
  const { records } = readPrReviewRecords(filePath);
46620
46714
  if (records.length === 0) return { maxSequence: -1, lastHash: void 0 };
@@ -47847,7 +47941,7 @@ function registerQueryTaskStateTool(server, deps) {
47847
47941
  import { z as z100 } from "zod";
47848
47942
 
47849
47943
  // src/mcp/tools/ci-health-log.ts
47850
- import { appendFileSync as appendFileSync5, existsSync as existsSync11, readFileSync as readFileSync9, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
47944
+ import { appendFileSync as appendFileSync5, existsSync as existsSync12, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
47851
47945
  import { z as z99 } from "zod";
47852
47946
 
47853
47947
  // src/mcp/tools/ci-health-types.ts
@@ -47889,7 +47983,7 @@ function capLogSize(path12) {
47889
47983
  }
47890
47984
  if (size <= max) return;
47891
47985
  try {
47892
- const lines = readFileSync9(path12, "utf-8").split("\n").filter((l) => l !== "");
47986
+ const lines = readFileSync10(path12, "utf-8").split("\n").filter((l) => l !== "");
47893
47987
  const kept = [];
47894
47988
  let bytes = 0;
47895
47989
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -48692,7 +48786,7 @@ function createMetaOrchestrator(options) {
48692
48786
  }
48693
48787
 
48694
48788
  // src/orchestration/meta-shadow-selector.ts
48695
- import { appendFileSync as appendFileSync6, existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
48789
+ import { appendFileSync as appendFileSync6, existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
48696
48790
  import { z as z104 } from "zod";
48697
48791
  var SHADOW_STRATEGY_ARMS = [
48698
48792
  "single-shot",
@@ -48811,11 +48905,11 @@ function hydrateShadowSelector(selector) {
48811
48905
  const hydratable = selector;
48812
48906
  if (typeof hydratable.recordFromContext !== "function") return 0;
48813
48907
  const file = getMetaOutcomesFile();
48814
- if (!existsSync12(file)) return 0;
48908
+ if (!existsSync13(file)) return 0;
48815
48909
  let replayed = 0;
48816
48910
  try {
48817
48911
  const cutoff = Date.now() - HYDRATE_LOOKBACK_MS;
48818
- const lines = readFileSync10(file, "utf-8").split("\n").filter((l) => l.trim().length > 0);
48912
+ const lines = readFileSync11(file, "utf-8").split("\n").filter((l) => l.trim().length > 0);
48819
48913
  for (const line of lines) {
48820
48914
  let parsed;
48821
48915
  try {
@@ -54163,4 +54257,4 @@ export {
54163
54257
  shutdownFeedbackSubscriber,
54164
54258
  createEventBusBridge
54165
54259
  };
54166
- //# sourceMappingURL=chunk-DDY7JDTZ.js.map
54260
+ //# sourceMappingURL=chunk-W7532ZQG.js.map