nexus-agents 11.1.0 → 11.1.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.
- package/dist/{ast-rule-runner-RL6XHXJB.js → ast-rule-runner-XESMURYB.js} +2 -2
- package/dist/{chunk-PNYCRRT6.js → chunk-7WT6TFEK.js} +3 -3
- package/dist/{chunk-3RUQILL4.js → chunk-A622LB4J.js} +3 -3
- package/dist/{chunk-QKWZZM2D.js → chunk-KVTLV44O.js} +13 -7
- package/dist/chunk-KVTLV44O.js.map +1 -0
- package/dist/{chunk-I7S3R5SQ.js → chunk-OOAPDIEW.js} +2 -2
- package/dist/{chunk-2JBWGPU6.js → chunk-QAWELEGH.js} +2 -2
- package/dist/{chunk-7HPCEKK7.js → chunk-QKEC2EDG.js} +22 -18
- package/dist/{chunk-7HPCEKK7.js.map → chunk-QKEC2EDG.js.map} +1 -1
- package/dist/{chunk-GAMT4NFP.js → chunk-YTV3O55W.js} +2 -2
- package/dist/cli.js +12 -11
- package/dist/cli.js.map +1 -1
- package/dist/{consensus-vote-YVJGZGGG.js → consensus-vote-UREYCWLL.js} +4 -4
- package/dist/{improvement-review-VYT24FPH.js → improvement-review-SXL6EJ6T.js} +4 -4
- package/dist/index.js +7 -7
- package/dist/{setup-custom-api-U3IGIJI7.js → setup-custom-api-W3645WL2.js} +1 -1
- package/dist/setup-custom-api-W3645WL2.js.map +1 -0
- package/dist/{setup-data-dir-VCH62L7T.js → setup-data-dir-7AH5ID4F.js} +3 -3
- package/package.json +3 -2
- package/dist/chunk-QKWZZM2D.js.map +0 -1
- package/dist/setup-custom-api-U3IGIJI7.js.map +0 -1
- /package/dist/{ast-rule-runner-RL6XHXJB.js.map → ast-rule-runner-XESMURYB.js.map} +0 -0
- /package/dist/{chunk-PNYCRRT6.js.map → chunk-7WT6TFEK.js.map} +0 -0
- /package/dist/{chunk-3RUQILL4.js.map → chunk-A622LB4J.js.map} +0 -0
- /package/dist/{chunk-I7S3R5SQ.js.map → chunk-OOAPDIEW.js.map} +0 -0
- /package/dist/{chunk-2JBWGPU6.js.map → chunk-QAWELEGH.js.map} +0 -0
- /package/dist/{chunk-GAMT4NFP.js.map → chunk-YTV3O55W.js.map} +0 -0
- /package/dist/{consensus-vote-YVJGZGGG.js.map → consensus-vote-UREYCWLL.js.map} +0 -0
- /package/dist/{improvement-review-VYT24FPH.js.map → improvement-review-SXL6EJ6T.js.map} +0 -0
- /package/dist/{setup-data-dir-VCH62L7T.js.map → setup-data-dir-7AH5ID4F.js.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getBuiltInAstRulesPath,
|
|
10
10
|
loadRules,
|
|
11
11
|
runAstQaRules
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KVTLV44O.js";
|
|
13
13
|
import "./chunk-EBOAFTOG.js";
|
|
14
14
|
import "./chunk-XBEKMUTO.js";
|
|
15
15
|
import "./chunk-RUHKJC3X.js";
|
|
@@ -28,4 +28,4 @@ export {
|
|
|
28
28
|
loadRules,
|
|
29
29
|
runAstQaRules
|
|
30
30
|
};
|
|
31
|
-
//# sourceMappingURL=ast-rule-runner-
|
|
31
|
+
//# sourceMappingURL=ast-rule-runner-XESMURYB.js.map
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
toolSuccess,
|
|
22
22
|
withProgressHeartbeat,
|
|
23
23
|
wrapToolWithTimeout
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-YTV3O55W.js";
|
|
25
25
|
import {
|
|
26
26
|
getToolMemory
|
|
27
27
|
} from "./chunk-RR2Y2HVZ.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
} from "./chunk-EZNIYU5T.js";
|
|
31
31
|
import {
|
|
32
32
|
VERSION
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-OOAPDIEW.js";
|
|
34
34
|
import {
|
|
35
35
|
ModelBoundAdapter,
|
|
36
36
|
UNVERIFIABLE_STDERR_RE,
|
|
@@ -9905,4 +9905,4 @@ export {
|
|
|
9905
9905
|
CONSENSUS_VOTE_TOOL_SCHEMA,
|
|
9906
9906
|
registerConsensusVoteTool
|
|
9907
9907
|
};
|
|
9908
|
-
//# sourceMappingURL=chunk-
|
|
9908
|
+
//# sourceMappingURL=chunk-7WT6TFEK.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
VERSION,
|
|
8
8
|
isNodeVersionSupported,
|
|
9
9
|
recordServerTransport
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OOAPDIEW.js";
|
|
11
11
|
import {
|
|
12
12
|
checkGatewayHealth,
|
|
13
13
|
cliFailsVerdict,
|
|
@@ -2251,7 +2251,7 @@ async function runDoctorFix(result) {
|
|
|
2251
2251
|
writeLine2("\u2500".repeat(40));
|
|
2252
2252
|
let fixCount = 0;
|
|
2253
2253
|
if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
|
|
2254
|
-
const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-
|
|
2254
|
+
const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-7AH5ID4F.js");
|
|
2255
2255
|
const outcome = describeDataDirFix2(initDataDirectories2());
|
|
2256
2256
|
writeLine2(outcome.line);
|
|
2257
2257
|
if (outcome.counted) fixCount++;
|
|
@@ -2371,4 +2371,4 @@ export {
|
|
|
2371
2371
|
startStdioServer,
|
|
2372
2372
|
closeServer
|
|
2373
2373
|
};
|
|
2374
|
-
//# sourceMappingURL=chunk-
|
|
2374
|
+
//# sourceMappingURL=chunk-A622LB4J.js.map
|
|
@@ -100,7 +100,10 @@ function resolveWithinCwd(target) {
|
|
|
100
100
|
}
|
|
101
101
|
return { resolved };
|
|
102
102
|
}
|
|
103
|
-
var
|
|
103
|
+
var EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set(["node_modules", "dist"]);
|
|
104
|
+
function isWalkedDir(name) {
|
|
105
|
+
return !name.startsWith(".") && !EXCLUDED_DIR_NAMES.has(name);
|
|
106
|
+
}
|
|
104
107
|
var POLYGLOT_EXT_TO_LANG = {
|
|
105
108
|
".py": "python",
|
|
106
109
|
".go": "go"
|
|
@@ -109,25 +112,28 @@ function inferRuleLang(file) {
|
|
|
109
112
|
return POLYGLOT_EXT_TO_LANG[extname(file).toLowerCase()] ?? null;
|
|
110
113
|
}
|
|
111
114
|
async function findPolyglotFiles(dir, maxDepth) {
|
|
112
|
-
if (maxDepth <= 0) return [];
|
|
113
115
|
const out = [];
|
|
116
|
+
await collectPolyglotFiles(dir, maxDepth, out);
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
async function collectPolyglotFiles(dir, maxDepth, out) {
|
|
120
|
+
if (maxDepth <= 0) return;
|
|
114
121
|
let entries;
|
|
115
122
|
try {
|
|
116
123
|
entries = await readdir(dir, { withFileTypes: true });
|
|
117
124
|
} catch (caught) {
|
|
118
125
|
const e = caught instanceof Error ? caught : new Error(String(caught));
|
|
119
126
|
logger.warn(`ast-rule-runner: skipped unreadable directory ${dir}: ${e.message}`);
|
|
120
|
-
return
|
|
127
|
+
return;
|
|
121
128
|
}
|
|
122
129
|
for (const entry of entries) {
|
|
123
130
|
const fullPath = join(dir, entry.name);
|
|
124
|
-
if (entry.isDirectory() &&
|
|
125
|
-
|
|
131
|
+
if (entry.isDirectory() && isWalkedDir(entry.name)) {
|
|
132
|
+
await collectPolyglotFiles(fullPath, maxDepth - 1, out);
|
|
126
133
|
} else if (entry.isFile() && inferRuleLang(entry.name) !== null) {
|
|
127
134
|
out.push(fullPath);
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
|
-
return out;
|
|
131
137
|
}
|
|
132
138
|
function langToParseArg(lang) {
|
|
133
139
|
ensurePolyglotLangs();
|
|
@@ -241,4 +247,4 @@ export {
|
|
|
241
247
|
collectAstQaFindings,
|
|
242
248
|
runAstQaRules
|
|
243
249
|
};
|
|
244
|
-
//# sourceMappingURL=chunk-
|
|
250
|
+
//# sourceMappingURL=chunk-KVTLV44O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/security/ast-rule-runner.ts"],"sourcesContent":["/**\n * nexus-agents/security - Polyglot (Python/Go) AST QA/Security Rule Runner (#4249 child C)\n *\n * Runs YAML-defined `@ast-grep/napi` rules against Python/Go source, detecting\n * common QA/security anti-patterns (dynamic `eval`/`exec`, shell injection,\n * unchecked external command execution). Same engine already used by\n * `search_usages` (indexer/usage-ast.ts, #4265) and the ast-fixer rewrites\n * (agents/collaboration/ast-rewrites.ts, #4243/#4249 child B) — no new AST\n * dependency, just new language grammars for it.\n *\n * **Language support gap.** `Lang` in `@ast-grep/napi@0.44.1` ships only\n * Html/JavaScript/Tsx/Css/TypeScript — no Python, no Go. This module closes\n * that gap via napi's `@experimental registerDynamicLanguage` API, backed by\n * the `@ast-grep/lang-python`/`@ast-grep/lang-go` prebuilt tree-sitter\n * grammars. Both are EXACT-pinned in package.json (no caret): these are\n * early/experimental packages and a caret range could silently swap in an\n * incompatible native `.so` grammar build underneath a \"safe\" semver-minor\n * bump. `registerDynamicLanguage` throws if called more than once per\n * process (napi-rs's own documented constraint) — {@link ensurePolyglotLangs}\n * is a lazy, module-level, once-only guard so repeated calls (tests, repeat\n * runner invocations within one process) never trip it twice.\n *\n * **Read-only.** Reads rule YAML and target source files, walks their ASTs,\n * performs NO writes. ast-grep YAML rule files support a `fix:` key for\n * autofixing, but napi's `SgNode.findAll` (used here) never applies it —\n * only ast-grep's separate rewrite/CLI machinery does — so even a rule\n * author who adds `fix:` cannot turn this runner into a writer by accident.\n * MCP exposure is deliberately deferred (see the follow-up issue referenced\n * in the #4249 child C PR) to keep this surface a plain function until a\n * named consumer needs it wired through a tool.\n *\n * @module security/ast-rule-runner\n * @see Issue #4249 - epic: ast-grep adoption (Child C: polyglot QA/security rules)\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { dirname, extname, join, relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { parse, registerDynamicLanguage } from '@ast-grep/napi';\nimport type { NapiConfig } from '@ast-grep/napi';\n// Both packages are CJS `export = <LanguageRegistration>` modules — the\n// default import is the whole registration object (`libraryPath` getter,\n// `extensions`, `languageSymbol`, `expandoChar`). See their `index.d.ts`.\nimport goLangRegistration from '@ast-grep/lang-go';\nimport pythonLangRegistration from '@ast-grep/lang-python';\nimport { parse as parseYaml } from 'yaml';\nimport { z } from 'zod';\nimport { createLogger, SecurityError, ValidationError, formatZodError } from '../core/index.js';\nimport { resolveInsideRoot } from './safe-path.js';\n\n// ============================================================================\n// Dynamic language registration (@experimental, call-once)\n// ============================================================================\n\nlet polyglotLangsRegistered = false;\n\n/**\n * Lazily register the Python/Go tree-sitter grammars with ast-grep's\n * `registerDynamicLanguage`. That API throws if called more than once in a\n * process; this guard makes every call after the first a no-op so repeated\n * runner invocations (or a test suite that constructs the runner many times)\n * never trip the constraint.\n */\nexport function ensurePolyglotLangs(): void {\n if (polyglotLangsRegistered) return;\n registerDynamicLanguage({ python: pythonLangRegistration, go: goLangRegistration });\n polyglotLangsRegistered = true;\n}\n\n// ============================================================================\n// Rule schema (fail-closed)\n// ============================================================================\n\n/** Languages a rule file may declare. Deliberately narrowed to the two this\n * runner actually SCANS (python/go): admitting `typescript`/`javascript` here\n * would let a TS/JS rule file validate at load time and then silently never\n * fire (there is no TS/JS extension in {@link POLYGLOT_EXT_TO_LANG}), which is\n * a fail-OPEN gap for a security scanner where \"no findings\" reads as \"clean\".\n * TS/JS structural analysis is already covered by `search_usages` (#4265) and\n * the ast-fixer rewrites (#4243); a TS/JS rule here would fail LOUD at load\n * (unknown-language Zod error) instead of loading dead. */\nexport const AST_RULE_LANGUAGES = ['python', 'go'] as const;\nexport type AstRuleLanguage = (typeof AST_RULE_LANGUAGES)[number];\n\nexport const AST_RULE_SEVERITIES = ['error', 'warning', 'info'] as const;\nexport type AstRuleSeverity = (typeof AST_RULE_SEVERITIES)[number];\n\n/** Schema for one `*.yml` rule file. `rule` is passed through as ast-grep's\n * own `Rule` object (napi already validates it structurally at match time);\n * Zod only pins down the envelope so an unknown `language` or a missing\n * field FAILS CLOSED instead of silently loading a partial/broken rule. */\nconst RuleFileSchema = z.object({\n id: z.string().min(1),\n language: z.enum(AST_RULE_LANGUAGES),\n severity: z.enum(AST_RULE_SEVERITIES),\n message: z.string().min(1),\n rule: z.record(z.string(), z.unknown()),\n});\n\nexport type AstQaRuleFile = z.infer<typeof RuleFileSchema>;\n\n/** Per-match snippet char cap (matches indexer/usage-ast.ts's discipline). */\nconst MAX_SNIPPET_CHARS = 200;\n\n/** Default cap on emitted findings. Excess is counted + reported, never silently dropped. */\nexport const DEFAULT_AST_QA_LIMIT = 200;\n/** Hard upper bound a caller may request for the finding cap. */\nexport const MAX_AST_QA_LIMIT = 2000;\n/** Directory walk depth for the target-dir scan (not caller-configurable — no\n * named consumer needs a deeper/shallower walk yet; YAGNI). */\nconst AST_QA_MAX_DEPTH = 24;\n/** Upper bound on files parsed in a single run, to bound worst-case cost.\n * Exceeding it makes the scan PARTIAL — surfaced via {@link AstQaCollectResult}'s\n * `filesTruncated`/`filesSkipped` + a warn, never silently dropped. */\nexport const MAX_FILES_SCANNED = 5000;\n\nconst logger = createLogger({ component: 'ast-rule-runner' });\n\n// ============================================================================\n// Rule loading\n// ============================================================================\n\n/**\n * Load and Zod-validate every `*.yml` rule file in `dir`. FAILS CLOSED: a\n * single malformed YAML file, or a file with an unrecognized `language` or\n * missing field, throws a {@link ValidationError} — there is no\n * \"load what parsed, skip the rest\" partial mode.\n */\nexport async function loadRules(dir: string): Promise<AstQaRuleFile[]> {\n let entries: string[];\n try {\n entries = (await readdir(dir)).filter((f) => f.endsWith('.yml') || f.endsWith('.yaml')).sort();\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read rules dir ${dir}: ${e.message}`, {\n cause: e,\n });\n }\n\n const rules: AstQaRuleFile[] = [];\n for (const file of entries) {\n const path = join(dir, file);\n const raw = await readFile(path, 'utf8');\n\n let parsed: unknown;\n try {\n parsed = parseYaml(raw);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: malformed YAML in ${path}: ${e.message}`, {\n cause: e,\n });\n }\n\n const result = RuleFileSchema.safeParse(parsed);\n if (!result.success) {\n throw new ValidationError(\n `ast-rule-runner: invalid rule file ${path}: ${formatZodError(result.error)}`\n );\n }\n rules.push(result.data);\n }\n return rules;\n}\n\n// ============================================================================\n// Built-in rules dir resolution (mirrors workflows/template-loader.ts)\n// ============================================================================\n\n/**\n * Resolve the built-in `ast-rules/` directory, handling both dev (unbundled,\n * `src/security/ast-rule-runner.ts`) and published (bundled,\n * `dist/index.js` + `dist/security/ast-rules/*.yml` copied by tsup's\n * `onSuccess` step) layouts — the same two-layout problem\n * `getBuiltInTemplatesPath` solves for workflow templates.\n */\nexport function getBuiltInAstRulesPath(): string {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFile);\n\n if (currentFile.includes(`${sep}dist${sep}`) || currentFile.endsWith(`${sep}dist`)) {\n const distIndex = currentFile.lastIndexOf(`${sep}dist${sep}`);\n if (distIndex !== -1) {\n const distDir = currentFile.substring(0, distIndex + 5); // +5 for \"/dist\"\n const bundledPath = join(distDir, 'security', 'ast-rules');\n if (existsSync(bundledPath)) return bundledPath;\n }\n }\n\n const possiblePaths = [\n join(currentDir, 'ast-rules'), // Unbundled: sibling of this file in src/security/\n join(currentDir, 'security', 'ast-rules'), // Bundled chunk: dist/security sibling\n join(dirname(currentDir), 'security', 'ast-rules'),\n ];\n for (const path of possiblePaths) {\n if (existsSync(path)) return path;\n }\n return join(currentDir, 'ast-rules'); // Fallback (for error reporting)\n}\n\n// ============================================================================\n// Path-traversal guard (same shape as mcp/tools/search-usages-tool.ts)\n// ============================================================================\n\n/**\n * Resolve a caller path against a path-traversal guard (must stay within cwd).\n * Realpath-aware: a symlink inside cwd whose target is outside it is refused,\n * and the returned path is the canonical one the scan then walks.\n */\nfunction resolveWithinCwd(target: string): { resolved: string } | { error: string } {\n const resolved = resolveInsideRoot(target);\n if (resolved === null) {\n return { error: `Path traversal denied: scope must be within ${process.cwd()}` };\n }\n return { resolved };\n}\n\n// ============================================================================\n// File walk (LOCAL extension map — python/go only; does NOT reuse\n// indexer/usage-ast.ts's TS/JS inferLang or indexer/codebase-search.ts's\n// TS/JS-only findSourceFiles)\n// ============================================================================\n\n/** Directory names the walk never descends into, in addition to every dot-directory. */\nconst EXCLUDED_DIR_NAMES: ReadonlySet<string> = new Set(['node_modules', 'dist']);\n\n/**\n * Whether the walk descends into a directory entry. Dot-directories are skipped\n * as a class (#7184), the same rule `findSourceFiles` and `governance/source-scan.ts`\n * apply: `.git` and the gitignored `.nexus-agents/worktrees` copies are never the\n * caller's source, and scanning the worktrees duplicated every finding. The rule\n * applies to entries only, so a caller may still root the scan at a dot-dir.\n */\nfunction isWalkedDir(name: string): boolean {\n return !name.startsWith('.') && !EXCLUDED_DIR_NAMES.has(name);\n}\n\n/** file-extension -> ast-rule language, for the two languages this runner scans. */\nconst POLYGLOT_EXT_TO_LANG: Readonly<Record<string, AstRuleLanguage>> = {\n '.py': 'python',\n '.go': 'go',\n};\n\n/** Infer the ast-rule language for a file from its extension, or `null` if unsupported. */\nfunction inferRuleLang(file: string): AstRuleLanguage | null {\n return POLYGLOT_EXT_TO_LANG[extname(file).toLowerCase()] ?? null;\n}\n\n/**\n * Recursively collect `.py`/`.go` files under `dir`, bounded by `maxDepth`,\n * skipping dot-directories and `node_modules`/`dist`.\n * A subdirectory whose `readdir` fails mid-walk (e.g. a `chmod 000` dir) is\n * WARNED about per-dir and skipped rather than silently swallowed — the scan\n * continues, but the partiality is surfaced in the log. The SCAN ROOT's own\n * readability is validated up front by {@link collectAstQaFindings} (fail\n * loud), so this soft-skip only ever applies to descendant dirs.\n */\nasync function findPolyglotFiles(dir: string, maxDepth: number): Promise<string[]> {\n const out: string[] = [];\n await collectPolyglotFiles(dir, maxDepth, out);\n return out;\n}\n\n/**\n * Walk into a shared accumulator. Appending per file, rather than\n * `out.push(...sub)`, keeps the walk safe on large trees: a spread passes every\n * element as a call argument and throws \"Maximum call stack size exceeded\"\n * past roughly 120k entries (#7184, the #7178 class).\n */\nasync function collectPolyglotFiles(dir: string, maxDepth: number, out: string[]): Promise<void> {\n if (maxDepth <= 0) return;\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n logger.warn(`ast-rule-runner: skipped unreadable directory ${dir}: ${e.message}`);\n return;\n }\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory() && isWalkedDir(entry.name)) {\n await collectPolyglotFiles(fullPath, maxDepth - 1, out);\n } else if (entry.isFile() && inferRuleLang(entry.name) !== null) {\n out.push(fullPath);\n }\n }\n}\n\n/** Map a rule's declared language to the `parse()` first argument, registering\n * the dynamic grammars on first use. Both supported languages (python/go) are\n * dynamically-registered CustomLangs, so the language name string IS the\n * `parse()` key set up in {@link ensurePolyglotLangs}. */\nfunction langToParseArg(lang: AstRuleLanguage): AstRuleLanguage {\n ensurePolyglotLangs();\n return lang; // the CustomLang string keys used in registerDynamicLanguage()\n}\n\n// ============================================================================\n// Findings\n// ============================================================================\n\n/** One ast-grep rule match against a source file. */\nexport interface AstRuleFinding {\n ruleId: string;\n severity: AstRuleSeverity;\n message: string;\n /** Path relative to the resolved `targetDir`. */\n file: string;\n /** 1-based line number. */\n line: number;\n /** 1-based column number. */\n column: number;\n /** Trimmed, length-capped source line for the match. */\n snippet: string;\n}\n\nexport interface RunAstQaRulesOptions {\n /** Directory containing `*.yml` rule files (default: the built-in bundled rules). */\n rulesDir?: string;\n /** Directory to scan for `.py`/`.go` source files (must stay within cwd). */\n targetDir: string;\n /** Max findings emitted (default {@link DEFAULT_AST_QA_LIMIT}). Excess is counted + reported. */\n limit?: number;\n}\n\n/** {@link collectAstQaFindings}'s full result — findings plus the true total,\n * so overflow beyond `limit` is counted and reported, never silently dropped. */\nexport interface AstQaCollectResult {\n findings: AstRuleFinding[];\n /** True count of matches found, before the `limit` cap was applied. */\n total: number;\n limit: number;\n /** Number of `.py`/`.go` files actually scanned (after the file cap). */\n filesScanned: number;\n /** Number of discovered files DROPPED because the file cap ({@link MAX_FILES_SCANNED})\n * was exceeded. Non-zero means the scan was PARTIAL — a downstream consumer\n * must not treat empty/low findings as a clean bill of health. */\n filesSkipped: number;\n /** True iff `filesSkipped > 0` — the scan did not cover every candidate file. */\n filesTruncated: boolean;\n}\n\n/** Findings + true-match-count from scanning ONE already-read source file. */\ninterface FileScanResult {\n findings: AstRuleFinding[];\n total: number;\n}\n\n/** Bundles {@link scanFile}'s cap-tracking inputs (max-params discipline). */\ninterface FileScanBudget {\n /** Path emitted on each finding (relative to the resolved `targetDir`). */\n rel: string;\n /** Max TOTAL findings across the whole run. */\n limit: number;\n /** Findings already accepted by earlier files in this run. */\n alreadyFound: number;\n}\n\n/**\n * Scan one already-read source file against the rules applicable to its\n * language, pushing findings only while the running total (`budget.alreadyFound`\n * + findings pushed so far) stays under `budget.limit` — while still counting\n * every true match, so the caller can report overflow instead of silently\n * dropping it.\n */\nfunction scanFile(\n src: string,\n lang: AstRuleLanguage,\n applicable: readonly AstQaRuleFile[],\n budget: FileScanBudget\n): FileScanResult {\n const { rel, limit, alreadyFound } = budget;\n const root = parse(langToParseArg(lang), src).root();\n const lines = src.split('\\n');\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const rule of applicable) {\n const config: NapiConfig = { rule: rule.rule };\n for (const node of root.findAll(config)) {\n total += 1;\n if (alreadyFound + findings.length < limit) {\n const { start } = node.range();\n const rawLine = lines[start.line] ?? node.text();\n findings.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: rule.message,\n file: rel,\n line: start.line + 1,\n column: start.column + 1,\n snippet: rawLine.trim().slice(0, MAX_SNIPPET_CHARS),\n });\n }\n }\n }\n return { findings, total };\n}\n\n/**\n * Fail LOUD on an unreadable / non-directory scan root. `loadRules` already\n * throws on an unreadable RULES dir; the TARGET traversal must not fail OPEN —\n * a lone file path, a bad path, or a `000` root would otherwise return an empty\n * finding set that reads as \"clean\" for a security scanner.\n */\nasync function assertScanRootIsDirectory(resolved: string): Promise<void> {\n let rootStat;\n try {\n rootStat = await stat(resolved);\n } catch (caught: unknown) {\n const e = caught instanceof Error ? caught : new Error(String(caught));\n throw new ValidationError(`ast-rule-runner: cannot read targetDir ${resolved}: ${e.message}`, {\n cause: e,\n });\n }\n if (!rootStat.isDirectory()) {\n throw new ValidationError(\n `ast-rule-runner: targetDir must be a directory, got a non-directory path: ${resolved}`\n );\n }\n}\n\n/** Result of resolving the candidate file set under a scan root, with the\n * file-cap truncation signal surfaced (never a silent `.slice`). */\ninterface ScanFileSet {\n files: string[];\n filesSkipped: number;\n filesTruncated: boolean;\n}\n\n/** Discover candidate `.py`/`.go` files, applying + SURFACING the file cap. */\nasync function resolveScanFiles(root: string): Promise<ScanFileSet> {\n const discovered = await findPolyglotFiles(root, AST_QA_MAX_DEPTH);\n const files = discovered.slice(0, MAX_FILES_SCANNED);\n const filesSkipped = discovered.length - files.length;\n const filesTruncated = filesSkipped > 0;\n if (filesTruncated) {\n logger.warn(\n `ast-rule-runner: ${String(filesSkipped)} file(s) NOT scanned — file cap ` +\n `${String(MAX_FILES_SCANNED)} exceeded (discovered=${String(discovered.length)}). ` +\n `Scan is PARTIAL; do not treat findings as exhaustive.`\n );\n }\n return { files, filesSkipped, filesTruncated };\n}\n\n/**\n * Run every applicable rule in `rulesDir` against every `.py`/`.go` file under\n * `targetDir`, returning capped findings plus the true total (so callers that\n * need the overflow count — e.g. a future MCP tool wrapper — can report it).\n * {@link runAstQaRules} is the capped-array convenience wrapper over this.\n */\nexport async function collectAstQaFindings(\n opts: RunAstQaRulesOptions\n): Promise<AstQaCollectResult> {\n const guard = resolveWithinCwd(opts.targetDir);\n if ('error' in guard) {\n throw new SecurityError(guard.error);\n }\n await assertScanRootIsDirectory(guard.resolved);\n\n const rulesDir = opts.rulesDir ?? getBuiltInAstRulesPath();\n const rules = await loadRules(rulesDir);\n // Clamp into [1, MAX]: a limit <= 0 would report total > 0 with zero findings\n // (fail-open \"clean\" signal), so the floor is load-bearing, not cosmetic.\n const limit = Math.min(Math.max(opts.limit ?? DEFAULT_AST_QA_LIMIT, 1), MAX_AST_QA_LIMIT);\n\n const { files, filesSkipped, filesTruncated } = await resolveScanFiles(guard.resolved);\n\n const findings: AstRuleFinding[] = [];\n let total = 0;\n\n for (const file of files) {\n const lang = inferRuleLang(file);\n if (lang === null) continue;\n const applicable = rules.filter((r) => r.language === lang);\n if (applicable.length === 0) continue;\n\n let src: string;\n try {\n src = await readFile(file, 'utf8');\n } catch {\n logger.warn(`ast-rule-runner: skipped unreadable file ${file}`);\n continue;\n }\n\n const rel = relative(guard.resolved, file) || file;\n const scanned = scanFile(src, lang, applicable, { rel, limit, alreadyFound: findings.length });\n findings.push(...scanned.findings);\n total += scanned.total;\n }\n\n if (total > findings.length) {\n logger.warn(\n `ast-rule-runner: ${String(total - findings.length)} finding(s) omitted beyond ` +\n `limit=${String(limit)} (total=${String(total)})`\n );\n }\n\n return { findings, total, limit, filesScanned: files.length, filesSkipped, filesTruncated };\n}\n\n/**\n * Run the polyglot QA/security ast-grep rules and return the capped findings\n * array. Overflow beyond `limit` is counted and logged (never silently\n * dropped) — use {@link collectAstQaFindings} directly when the caller needs\n * the true total/overflow count programmatically.\n */\nexport async function runAstQaRules(opts: RunAstQaRulesOptions): Promise<AstRuleFinding[]> {\n const { findings } = await collectAstQaFindings(opts);\n return findings;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
6
|
import semver from "semver";
|
|
7
|
-
var VERSION = true ? "11.1.
|
|
7
|
+
var VERSION = true ? "11.1.2" : "dev";
|
|
8
8
|
var NODE_ENGINE_RANGE = ">=24";
|
|
9
9
|
function isNodeVersionSupported(version) {
|
|
10
10
|
return semver.satisfies(version, NODE_ENGINE_RANGE);
|
|
@@ -106,4 +106,4 @@ export {
|
|
|
106
106
|
contextForLogging,
|
|
107
107
|
measuredTrustTier
|
|
108
108
|
};
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
109
|
+
//# sourceMappingURL=chunk-OOAPDIEW.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
toSdkCallback,
|
|
8
8
|
toolStructuredError,
|
|
9
9
|
wrapToolWithTimeout
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-YTV3O55W.js";
|
|
11
11
|
import {
|
|
12
12
|
JsonlStore,
|
|
13
13
|
SECURITY_KEYWORDS,
|
|
@@ -2431,4 +2431,4 @@ export {
|
|
|
2431
2431
|
runImprovementReview,
|
|
2432
2432
|
registerImprovementReviewTool
|
|
2433
2433
|
};
|
|
2434
|
-
//# sourceMappingURL=chunk-
|
|
2434
|
+
//# sourceMappingURL=chunk-QAWELEGH.js.map
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
updateStage,
|
|
59
59
|
withFileLock,
|
|
60
60
|
writeJobCancelled
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-7WT6TFEK.js";
|
|
62
62
|
import {
|
|
63
63
|
normalizeTopicToCanonical,
|
|
64
64
|
synthesizeResearch
|
|
@@ -77,7 +77,7 @@ import {
|
|
|
77
77
|
} from "./chunk-NY7IMAG5.js";
|
|
78
78
|
import {
|
|
79
79
|
withPrerequisite
|
|
80
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-QAWELEGH.js";
|
|
81
81
|
import {
|
|
82
82
|
NOOP_NOTIFIER,
|
|
83
83
|
RateLimiter,
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
toolSuccess,
|
|
106
106
|
withProgressHeartbeat,
|
|
107
107
|
wrapToolWithTimeout
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-YTV3O55W.js";
|
|
109
109
|
import {
|
|
110
110
|
generateSecurityPlan
|
|
111
111
|
} from "./chunk-AX5DBV3M.js";
|
|
@@ -187,7 +187,7 @@ import {
|
|
|
187
187
|
import {
|
|
188
188
|
DEFAULT_TASK_TTL_MS,
|
|
189
189
|
clampTaskTtl
|
|
190
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-A622LB4J.js";
|
|
191
191
|
import {
|
|
192
192
|
allOf,
|
|
193
193
|
anyOf
|
|
@@ -196,7 +196,7 @@ import {
|
|
|
196
196
|
VERSION,
|
|
197
197
|
createRequestContext,
|
|
198
198
|
measuredTrustTier
|
|
199
|
-
} from "./chunk-
|
|
199
|
+
} from "./chunk-OOAPDIEW.js";
|
|
200
200
|
import {
|
|
201
201
|
BWRAP_READ_ONLY_ARGS,
|
|
202
202
|
CliDetectionCache,
|
|
@@ -46657,7 +46657,7 @@ function buildVotingInput(plan, config) {
|
|
|
46657
46657
|
}
|
|
46658
46658
|
async function executeSingleVote(plan, config, log) {
|
|
46659
46659
|
try {
|
|
46660
|
-
const { executeVoting } = await import("./consensus-vote-
|
|
46660
|
+
const { executeVoting } = await import("./consensus-vote-UREYCWLL.js");
|
|
46661
46661
|
const input = buildVotingInput(plan, config);
|
|
46662
46662
|
const result = await executeVoting(input, log);
|
|
46663
46663
|
return parseVotingResult(result);
|
|
@@ -48489,7 +48489,7 @@ function createVoteStage({ config, startStage }) {
|
|
|
48489
48489
|
const strategy = config.votingStrategy ?? "higher_order";
|
|
48490
48490
|
await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
|
|
48491
48491
|
try {
|
|
48492
|
-
const { executeVoting } = await import("./consensus-vote-
|
|
48492
|
+
const { executeVoting } = await import("./consensus-vote-UREYCWLL.js");
|
|
48493
48493
|
const proposal = buildVoteProposal(plan, research);
|
|
48494
48494
|
const votingResult = await executeVoting(
|
|
48495
48495
|
{
|
|
@@ -52960,10 +52960,11 @@ function classifyConsensusResult(record, mode) {
|
|
|
52960
52960
|
const wouldBlock = typeof enforcement === "object" && enforcement !== null && enforcement["wouldBlock"] === true;
|
|
52961
52961
|
if (mode === "enforce" && (BLOCKING_CONSENSUS_DECISIONS.has(record["decision"]) || wouldBlock)) {
|
|
52962
52962
|
const reason = consensusReason(record);
|
|
52963
|
-
|
|
52964
|
-
|
|
52965
|
-
|
|
52966
|
-
}
|
|
52963
|
+
const failureReason = reason === record["decision"] ? `Consensus ${reason}` : `Consensus ${String(record["decision"])}: ${reason}`;
|
|
52964
|
+
if (record["decision"] === "rejected" && reason === "rejected") {
|
|
52965
|
+
return { success: false, failureReason, gateRefusal: failureReason };
|
|
52966
|
+
}
|
|
52967
|
+
return { success: false, failureReason };
|
|
52967
52968
|
}
|
|
52968
52969
|
return { success: true };
|
|
52969
52970
|
}
|
|
@@ -52983,14 +52984,16 @@ function classifyEngineResult(result, mode = "audit") {
|
|
|
52983
52984
|
}
|
|
52984
52985
|
return classifyConsensusResult(record, mode);
|
|
52985
52986
|
}
|
|
52986
|
-
function recordOutcome2(deps, decision, start,
|
|
52987
|
+
function recordOutcome2(deps, decision, start, verdict) {
|
|
52988
|
+
const refused = verdict.gateRefusal !== void 0;
|
|
52987
52989
|
const record = {
|
|
52988
52990
|
decisionId: decision.decisionId,
|
|
52989
52991
|
timestamp: new Date(getTimeProvider().now()).toISOString(),
|
|
52990
52992
|
strategy: decision.strategy,
|
|
52991
|
-
success,
|
|
52993
|
+
success: verdict.success || refused,
|
|
52992
52994
|
durationMs: Math.max(0, getTimeProvider().now() - start),
|
|
52993
|
-
|
|
52995
|
+
...!refused && verdict.failureReason !== void 0 ? { failureReason: verdict.failureReason } : {},
|
|
52996
|
+
...refused ? { gateRefusal: verdict.gateRefusal } : {}
|
|
52994
52997
|
};
|
|
52995
52998
|
deps.outcomeSink.recordOutcome(record);
|
|
52996
52999
|
if (deps.onOutcome !== void 0) {
|
|
@@ -53010,7 +53013,7 @@ async function dispatchDecision(decision, input, deps) {
|
|
|
53010
53013
|
const executor = deps.executors[strategy];
|
|
53011
53014
|
if (executor === void 0) {
|
|
53012
53015
|
const reason = `No executor registered for strategy "${strategy}"`;
|
|
53013
|
-
recordOutcome2(deps, decision, start, false, reason);
|
|
53016
|
+
recordOutcome2(deps, decision, start, { success: false, failureReason: reason });
|
|
53014
53017
|
deps.logger.error("MetaDispatcher dispatch failed", void 0, {
|
|
53015
53018
|
decisionId,
|
|
53016
53019
|
strategy,
|
|
@@ -53021,7 +53024,7 @@ async function dispatchDecision(decision, input, deps) {
|
|
|
53021
53024
|
try {
|
|
53022
53025
|
const result = await executor(decision, input);
|
|
53023
53026
|
const classification = deps.classifyResult(result);
|
|
53024
|
-
recordOutcome2(deps, decision, start, classification
|
|
53027
|
+
recordOutcome2(deps, decision, start, classification);
|
|
53025
53028
|
return {
|
|
53026
53029
|
decisionId,
|
|
53027
53030
|
strategy,
|
|
@@ -53030,7 +53033,7 @@ async function dispatchDecision(decision, input, deps) {
|
|
|
53030
53033
|
};
|
|
53031
53034
|
} catch (err2) {
|
|
53032
53035
|
const reason = errorMessage(err2);
|
|
53033
|
-
recordOutcome2(deps, decision, start, false, reason);
|
|
53036
|
+
recordOutcome2(deps, decision, start, { success: false, failureReason: reason });
|
|
53034
53037
|
deps.logger.error(
|
|
53035
53038
|
"MetaDispatcher strategy executor threw",
|
|
53036
53039
|
err2 instanceof Error ? err2 : void 0,
|
|
@@ -54894,6 +54897,7 @@ function buildShadowTrainObserver(logger58) {
|
|
|
54894
54897
|
decisionId: decision.decisionId,
|
|
54895
54898
|
strategy: decision.strategy,
|
|
54896
54899
|
success: record.success,
|
|
54900
|
+
...record.gateRefusal !== void 0 ? { gateRefusal: record.gateRefusal } : {},
|
|
54897
54901
|
armStats: getShadowSelector().stats()
|
|
54898
54902
|
});
|
|
54899
54903
|
}
|
|
@@ -58469,4 +58473,4 @@ export {
|
|
|
58469
58473
|
initializeSandbox,
|
|
58470
58474
|
getSandboxMode
|
|
58471
58475
|
};
|
|
58472
|
-
//# sourceMappingURL=chunk-
|
|
58476
|
+
//# sourceMappingURL=chunk-QKEC2EDG.js.map
|