@wrongstack/plugins 0.287.0 → 0.289.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/accessibility-auditor/index.d.ts.map +1 -1
  2. package/dist/accessibility-auditor.js +45 -42
  3. package/dist/auto-i18n-extractor.js +1 -1
  4. package/dist/code-metrics/index.d.ts.map +1 -1
  5. package/dist/code-metrics.js +46 -42
  6. package/dist/cost-tracker/index.d.ts.map +1 -1
  7. package/dist/cost-tracker.js +4 -2
  8. package/dist/dead-code-detector.js +3 -3
  9. package/dist/diff-summary.js +1 -1
  10. package/dist/doc-sync-guard.js +3 -3
  11. package/dist/duplicate-code-detector/index.d.ts.map +1 -1
  12. package/dist/duplicate-code-detector.js +47 -43
  13. package/dist/feature-flag-tracker/index.d.ts.map +1 -1
  14. package/dist/feature-flag-tracker.js +46 -42
  15. package/dist/file-watcher/index.d.ts.map +1 -1
  16. package/dist/file-watcher.js +6 -2
  17. package/dist/format-on-save.js +1 -1
  18. package/dist/import-organizer.js +1 -1
  19. package/dist/index.js +396 -539
  20. package/dist/interface-contract-guard/index.d.ts.map +1 -1
  21. package/dist/interface-contract-guard.js +46 -42
  22. package/dist/lint-gate/index.d.ts.map +1 -1
  23. package/dist/lint-gate.js +61 -30
  24. package/dist/migration-planner.js +1 -1
  25. package/dist/prompt-firewall/index.d.ts +14 -6
  26. package/dist/prompt-firewall/index.d.ts.map +1 -1
  27. package/dist/prompt-firewall.js +7 -6
  28. package/dist/refactor-suggester/index.d.ts.map +1 -1
  29. package/dist/refactor-suggester.js +46 -42
  30. package/dist/runtime/index.d.ts +24 -0
  31. package/dist/runtime/index.d.ts.map +1 -1
  32. package/dist/runtime.js +63 -24
  33. package/dist/schema-evolution-guard.js +1 -1
  34. package/dist/secret-scanner/index.d.ts.map +1 -1
  35. package/dist/secret-scanner.js +17 -6
  36. package/dist/security-hotspot-scanner.js +1 -1
  37. package/dist/spec-linker.js +396 -539
  38. package/dist/test-runner-gate.js +1 -1
  39. package/dist/type-gate.js +19 -23
  40. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAS/C,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AA+KD,QAAA,MAAM,MAAM,EAAE,MAuMb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAS/C,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAqID,QAAA,MAAM,MAAM,EAAE,MAuMb,CAAC;eAEa,MAAM"}
@@ -1,9 +1,10 @@
1
1
  // src/interface-contract-guard/index.ts
2
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
- import { extname, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
2
+ import { readFileSync } from "node:fs";
3
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
4
4
 
5
5
  // src/runtime/index.ts
6
- import { basename, isAbsolute, relative, resolve } from "node:path";
6
+ import { existsSync, readdirSync, statSync } from "node:fs";
7
+ import { basename, extname, isAbsolute, relative, resolve } from "node:path";
7
8
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
8
9
  function hasLeadingDash(arg) {
9
10
  return arg.length > 0 && arg.startsWith("-");
@@ -18,6 +19,47 @@ function withinProjectPath(projectRoot, candidate) {
18
19
  function withinProject(p) {
19
20
  return withinProjectPath(process.cwd(), p) || relative(process.cwd(), p) === ".";
20
21
  }
22
+ var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
23
+ function collectSourceFiles(root, opts) {
24
+ const files = [];
25
+ if (!existsSync(root)) return files;
26
+ const s = statSync(root);
27
+ if (s.isFile()) {
28
+ if (matchesExtension(root, opts.extensions)) files.push(root);
29
+ return files;
30
+ }
31
+ if (!s.isDirectory()) return files;
32
+ const exclude = opts.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
33
+ function walk(dir, depth) {
34
+ if (opts.maxDepth !== void 0 && depth > opts.maxDepth) return;
35
+ let entries;
36
+ try {
37
+ entries = readdirSync(dir);
38
+ } catch {
39
+ return;
40
+ }
41
+ for (const entry of entries) {
42
+ if (exclude.includes(entry)) continue;
43
+ const full = resolve(dir, entry);
44
+ let st;
45
+ try {
46
+ st = statSync(full);
47
+ } catch {
48
+ continue;
49
+ }
50
+ if (st.isDirectory()) {
51
+ walk(full, depth + 1);
52
+ } else if (st.isFile() && matchesExtension(full, opts.extensions)) {
53
+ files.push(full);
54
+ }
55
+ }
56
+ }
57
+ walk(root, 0);
58
+ return files;
59
+ }
60
+ function matchesExtension(p, exts) {
61
+ return exts.includes(extname(p).toLowerCase());
62
+ }
21
63
 
22
64
  // src/interface-contract-guard/index.ts
23
65
  var API_VERSION = "^0.1.10";
@@ -46,44 +88,6 @@ function readConfig(raw) {
46
88
  function normalizeExtensions(exts) {
47
89
  return exts.map((e) => e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`);
48
90
  }
49
- function matchesExtension(p, exts) {
50
- return exts.includes(extname(p).toLowerCase());
51
- }
52
- function collectSourceFiles(root, exts) {
53
- const files = [];
54
- if (!existsSync(root)) return files;
55
- const s = statSync(root);
56
- if (s.isFile()) {
57
- if (matchesExtension(root, exts)) files.push(root);
58
- return files;
59
- }
60
- if (!s.isDirectory()) return files;
61
- function walk(dir) {
62
- let entries;
63
- try {
64
- entries = readdirSync(dir);
65
- } catch {
66
- return;
67
- }
68
- for (const entry of entries) {
69
- if (entry === "node_modules" || entry === "dist" || entry === ".git" || entry === "coverage") continue;
70
- const full = resolve2(dir, entry);
71
- let st;
72
- try {
73
- st = statSync(full);
74
- } catch {
75
- continue;
76
- }
77
- if (st.isDirectory()) {
78
- walk(full);
79
- } else if (st.isFile() && matchesExtension(full, exts)) {
80
- files.push(full);
81
- }
82
- }
83
- }
84
- walk(root);
85
- return files;
86
- }
87
91
  function toPosix(p) {
88
92
  return p.replace(/\\/g, "/");
89
93
  }
@@ -110,7 +114,7 @@ function scanPath(rawPath, cfg) {
110
114
  const root = process.cwd();
111
115
  const resolved = isAbsolute2(rawPath) ? resolve2(rawPath) : resolve2(root, rawPath);
112
116
  const exts = normalizeExtensions(cfg.extensions);
113
- const files = collectSourceFiles(resolved, exts);
117
+ const files = collectSourceFiles(resolved, { extensions: exts });
114
118
  const contents = [];
115
119
  for (const p of files) {
116
120
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AA6R/C,QAAA,MAAM,MAAM,EAAE,MA8Vb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAwU/C,QAAA,MAAM,MAAM,EAAE,MAwWb,CAAC;eAEa,MAAM"}
package/dist/lint-gate.js CHANGED
@@ -1,8 +1,10 @@
1
1
  // src/lint-gate/index.ts
2
2
  import { execFile } from "node:child_process";
3
+ import { readFileSync } from "node:fs";
3
4
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
5
+ import { createRequire } from "node:module";
4
6
  import { tmpdir } from "node:os";
5
- import { join } from "node:path";
7
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
8
  var API_VERSION = "^0.1.10";
7
9
  var state = {
8
10
  /** Total PreToolUse invocations. */
@@ -36,55 +38,74 @@ function readConfig(raw) {
36
38
  fixRules: Array.isArray(r["fixRules"]) ? r["fixRules"].filter((x) => typeof x === "string") : []
37
39
  };
38
40
  }
39
- function executable(command) {
40
- return process.platform === "win32" && command === "npx" ? "npx.cmd" : command;
41
+ var LINTER_PACKAGES = {
42
+ biome: "@biomejs/biome",
43
+ eslint: "eslint"
44
+ };
45
+ function isInside(parent, candidate) {
46
+ const rel = relative(parent, candidate);
47
+ return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
48
+ }
49
+ function resolveLocalLinter(name, cwd) {
50
+ try {
51
+ const packageName = LINTER_PACKAGES[name];
52
+ const requireFromProject = createRequire(resolve(cwd, "package.json"));
53
+ const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
54
+ const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
55
+ const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[name] ?? Object.values(packageJson.bin ?? {})[0];
56
+ if (!relativeBin || isAbsolute(relativeBin)) return null;
57
+ const packageDir = dirname(packagePath);
58
+ const entry = resolve(packageDir, relativeBin);
59
+ if (!isInside(packageDir, entry)) return null;
60
+ return {
61
+ cmd: process.execPath,
62
+ args: name === "biome" ? [entry, "check", "--reporter=json"] : [entry, "--format=json"],
63
+ name
64
+ };
65
+ } catch {
66
+ return null;
67
+ }
41
68
  }
42
- function runCommand(command, args, timeoutMs, signal) {
43
- return new Promise((resolve) => {
69
+ function runCommand(command, args, timeoutMs, cwd, signal) {
70
+ return new Promise((resolveResult) => {
44
71
  try {
45
72
  execFile(
46
- executable(command),
73
+ command,
47
74
  args,
48
75
  {
49
76
  encoding: "utf-8",
50
77
  timeout: timeoutMs,
51
- cwd: process.cwd(),
78
+ cwd,
52
79
  windowsHide: true,
80
+ shell: false,
53
81
  maxBuffer: 2 * 1024 * 1024,
54
82
  ...signal ? { signal } : {}
55
83
  },
56
- (error, stdout) => resolve({ stdout, error })
84
+ (error, stdout) => resolveResult({ stdout, error })
57
85
  );
58
86
  } catch (err) {
59
- resolve({ stdout: "", error: err instanceof Error ? err : new Error(String(err)) });
87
+ resolveResult({ stdout: "", error: err instanceof Error ? err : new Error(String(err)) });
60
88
  }
61
89
  });
62
90
  }
63
- async function detectLinter(requested) {
64
- const tryBiome = requested === "biome" || requested === "auto";
65
- const tryEslint = requested === "eslint" || requested === "auto";
66
- if (tryBiome) {
67
- const probe = await runCommand("npx", ["biome", "--version"], 5e3);
68
- if (!probe.error) {
69
- return { cmd: "npx", args: ["biome", "check", "--reporter=json"], name: "biome" };
70
- }
71
- }
72
- if (tryEslint) {
73
- const probe = await runCommand("npx", ["eslint", "--version"], 5e3);
74
- if (!probe.error) {
75
- return { cmd: "npx", args: ["eslint", "--format=json"], name: "eslint" };
76
- }
91
+ async function detectLinter(requested, cwd) {
92
+ const candidates = requested === "auto" ? ["biome", "eslint"] : [requested];
93
+ for (const name of candidates) {
94
+ const linter = resolveLocalLinter(name, cwd);
95
+ if (!linter) continue;
96
+ const probe = await runCommand(linter.cmd, [linter.args[0], "--version"], 5e3, cwd);
97
+ if (!probe.error) return linter;
77
98
  }
78
99
  return null;
79
100
  }
80
- async function lintContent(content, filePath, linter, timeoutMs, signal) {
101
+ async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
81
102
  const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
82
103
  const tmpDir = await mkdtemp(join(tmpdir(), "lint-gate-"));
83
104
  const tmpFile = join(tmpDir, `input${ext}`);
84
105
  try {
85
106
  await writeFile(tmpFile, content, "utf-8");
86
107
  const fullArgs = [...linter.args, tmpFile];
87
- const result = await runCommand(linter.cmd, fullArgs, timeoutMs, signal);
108
+ const result = await runCommand(linter.cmd, fullArgs, timeoutMs, cwd, signal);
88
109
  if (signal.aborted) throw signal.reason;
89
110
  if (result.error && !result.stdout) return null;
90
111
  return parseLinterOutput(result.stdout, linter.name);
@@ -95,14 +116,14 @@ async function lintContent(content, filePath, linter, timeoutMs, signal) {
95
116
  await rm(tmpDir, { recursive: true, force: true }).catch(() => void 0);
96
117
  }
97
118
  }
98
- async function lintAndFix(content, filePath, linter, timeoutMs, signal) {
119
+ async function lintAndFix(content, filePath, linter, timeoutMs, cwd, signal) {
99
120
  const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
100
121
  const tmpDir = await mkdtemp(join(tmpdir(), "lint-gate-fix-"));
101
122
  const tmpFile = join(tmpDir, `input${ext}`);
102
123
  try {
103
124
  await writeFile(tmpFile, content, "utf-8");
104
- const fixArgs = linter.name === "biome" ? ["biome", "check", "--write", tmpFile] : ["eslint", "--fix", tmpFile];
105
- await runCommand(linter.cmd, fixArgs, timeoutMs, signal);
125
+ const fixArgs = linter.name === "biome" ? [linter.args[0], "check", "--write", tmpFile] : [linter.args[0], "--fix", tmpFile];
126
+ await runCommand(linter.cmd, fixArgs, timeoutMs, cwd, signal);
106
127
  if (signal.aborted) throw signal.reason;
107
128
  return await readFile(tmpFile, "utf-8");
108
129
  } catch {
@@ -203,7 +224,8 @@ var plugin = {
203
224
  state.hookUnregister = null;
204
225
  state.lastResult = null;
205
226
  const cfg = readConfig(api.config.extensions?.["lint-gate"]);
206
- const linterReady = detectLinter(cfg.linter).then((linter) => {
227
+ const cwd = resolve(api.config.cwd ?? process.cwd());
228
+ const linterReady = detectLinter(cfg.linter, cwd).then((linter) => {
207
229
  if (!linter) {
208
230
  api.log.warn("lint-gate: no linter found (biome or eslint) \u2014 hook will be a no-op", {
209
231
  requested: cfg.linter
@@ -240,7 +262,14 @@ var plugin = {
240
262
  } else {
241
263
  return;
242
264
  }
243
- const issues = await lintContent(content, filePath, linter, cfg.timeoutMs, runtime.signal);
265
+ const issues = await lintContent(
266
+ content,
267
+ filePath,
268
+ linter,
269
+ cfg.timeoutMs,
270
+ cwd,
271
+ runtime.signal
272
+ );
244
273
  if (issues === null) {
245
274
  state.linterErrorCount += 1;
246
275
  return;
@@ -280,6 +309,7 @@ ${summary}${truncated}`
280
309
  filePath,
281
310
  linter,
282
311
  cfg.timeoutMs,
312
+ cwd,
283
313
  runtime.signal
284
314
  );
285
315
  if (fixedContent !== content) {
@@ -318,6 +348,7 @@ ${remainingSummary}` : "")
318
348
  filePath,
319
349
  linter,
320
350
  cfg.timeoutMs,
351
+ cwd,
321
352
  runtime.signal
322
353
  );
323
354
  if (fixedNewStr !== newStr) {
@@ -2,7 +2,7 @@
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
 
4
4
  // src/runtime/index.ts
5
- import { basename, isAbsolute, relative, resolve } from "node:path";
5
+ import { basename, extname, isAbsolute, relative, resolve } from "node:path";
6
6
 
7
7
  // src/runtime/llm.ts
8
8
  function stripOuterMarkdownFence(text) {
@@ -9,25 +9,25 @@
9
9
  * outgoing request's system + message text for high-confidence
10
10
  * credential patterns and, depending on `mode`:
11
11
  *
12
- * - `warn` (default) — logs + counts + emits a `prompt-firewall:leak`
12
+ * - `warn` — logs + counts + emits a `prompt-firewall:leak`
13
13
  * event; the request goes through unchanged
14
- * - `redact` — replaces each match with `[REDACTED:<kind>]` in a CLONE
14
+ * - `redact` (default) — replaces each match with `[REDACTED:<kind>]` in a CLONE
15
15
  * of the request before sending, and also redacts secrets echoed back
16
16
  * in the response
17
17
  * - `block` — throws before the request is sent (the agent's error
18
18
  * path surfaces it), so the secret never reaches the provider
19
19
  *
20
20
  * Safety posture: opt-in — loads inert until
21
- * `config.extensions['prompt-firewall'].enabled = true`. `warn` is the
22
- * default so it can never corrupt context until you deliberately choose
23
- * `redact`/`block`.
21
+ * `config.extensions['prompt-firewall'].enabled = true`. `redact` is the
22
+ * default so secrets are automatically stripped; switch to `warn` only
23
+ * for detection-mode diagnostics without data loss.
24
24
  *
25
25
  * Config (`config.extensions['prompt-firewall']`):
26
26
  *
27
27
  * ```jsonc
28
28
  * {
29
29
  * "enabled": false,
30
- * "mode": "warn", // "warn" | "redact" | "block"
30
+ * "mode": "redact", // "warn" | "redact" | "block"
31
31
  * "scanResponse": true, // redact secrets echoed back (redact mode)
32
32
  * "allow": [] // regex source strings to exempt (false positives)
33
33
  * }
@@ -50,6 +50,14 @@ export declare function redactSecrets(text: string, allow: RegExp[]): {
50
50
  text: string;
51
51
  redactions: number;
52
52
  };
53
+ type FirewallMode = 'warn' | 'redact' | 'block';
54
+ interface PromptFirewallConfig {
55
+ enabled: boolean;
56
+ mode: FirewallMode;
57
+ scanResponse: boolean;
58
+ allow: RegExp[];
59
+ }
60
+ export declare function readConfig(raw: unknown): PromptFirewallConfig;
53
61
  declare const plugin: Plugin;
54
62
  export default plugin;
55
63
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompt-firewall/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,kBAAkB,CAAC;AA+B1D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAcxE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAWjG;AA6GD,QAAA,MAAM,MAAM,EAAE,MAkNb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompt-firewall/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,kBAAkB,CAAC;AA+B1D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAcxE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAWjG;AA0CD,KAAK,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CA0B7D;AAgCD,QAAA,MAAM,MAAM,EAAE,MAkNb,CAAC;eAEa,MAAM"}
@@ -76,7 +76,7 @@ function redactDeep(value, allow, counter) {
76
76
  function readConfig(raw) {
77
77
  const base = {
78
78
  enabled: false,
79
- mode: "warn",
79
+ mode: "redact",
80
80
  scanResponse: true,
81
81
  allow: []
82
82
  };
@@ -91,7 +91,7 @@ function readConfig(raw) {
91
91
  }) : [];
92
92
  return {
93
93
  enabled: r["enabled"] === true,
94
- mode: r["mode"] === "redact" ? "redact" : r["mode"] === "block" ? "block" : "warn",
94
+ mode: r["mode"] === "warn" ? "warn" : r["mode"] === "block" ? "block" : "redact",
95
95
  scanResponse: r["scanResponse"] !== false,
96
96
  allow
97
97
  };
@@ -109,10 +109,10 @@ var state = {
109
109
  var plugin = {
110
110
  name: "prompt-firewall",
111
111
  version: "0.1.0",
112
- description: "Scans the provider wire for credential leaks before context reaches the LLM API (wrapProviderRunner); warn/redact/block. Opt-in; warn by default.",
112
+ description: "Scans the provider wire for credential leaks before context reaches the LLM API (wrapProviderRunner); redact/warn/block. Opt-in; redact by default.",
113
113
  apiVersion: "^0.1.10",
114
114
  capabilities: { tools: true },
115
- defaultConfig: { enabled: false, mode: "warn", scanResponse: true, allow: [] },
115
+ defaultConfig: { enabled: false, mode: "redact", scanResponse: true, allow: [] },
116
116
  configSchema: {
117
117
  type: "object",
118
118
  properties: {
@@ -124,8 +124,8 @@ var plugin = {
124
124
  mode: {
125
125
  type: "string",
126
126
  enum: ["warn", "redact", "block"],
127
- default: "warn",
128
- description: "warn = detect only; redact = strip secrets from the request/response; block = refuse the request."
127
+ default: "redact",
128
+ description: "redact (default) = strip secrets from the request/response; warn = detect only; block = refuse the request."
129
129
  },
130
130
  scanResponse: {
131
131
  type: "boolean",
@@ -294,5 +294,6 @@ var prompt_firewall_default = plugin;
294
294
  export {
295
295
  prompt_firewall_default as default,
296
296
  detectSecrets,
297
+ readConfig,
297
298
  redactSecrets
298
299
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refactor-suggester/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAS/C,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAuQD,QAAA,MAAM,MAAM,EAAE,MA4Nb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refactor-suggester/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAS/C,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,cAAc,GACd,iBAAiB,GACjB,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA6ND,QAAA,MAAM,MAAM,EAAE,MA4Nb,CAAC;eAEa,MAAM"}
@@ -1,9 +1,10 @@
1
1
  // src/refactor-suggester/index.ts
2
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
- import { extname, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
2
+ import { readFileSync } from "node:fs";
3
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
4
4
 
5
5
  // src/runtime/index.ts
6
- import { basename, isAbsolute, relative, resolve } from "node:path";
6
+ import { existsSync, readdirSync, statSync } from "node:fs";
7
+ import { basename, extname, isAbsolute, relative, resolve } from "node:path";
7
8
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
8
9
  function hasLeadingDash(arg) {
9
10
  return arg.length > 0 && arg.startsWith("-");
@@ -18,6 +19,47 @@ function withinProjectPath(projectRoot, candidate) {
18
19
  function withinProject(p) {
19
20
  return withinProjectPath(process.cwd(), p) || relative(process.cwd(), p) === ".";
20
21
  }
22
+ var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
23
+ function collectSourceFiles(root, opts) {
24
+ const files = [];
25
+ if (!existsSync(root)) return files;
26
+ const s = statSync(root);
27
+ if (s.isFile()) {
28
+ if (matchesExtension(root, opts.extensions)) files.push(root);
29
+ return files;
30
+ }
31
+ if (!s.isDirectory()) return files;
32
+ const exclude = opts.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
33
+ function walk(dir, depth) {
34
+ if (opts.maxDepth !== void 0 && depth > opts.maxDepth) return;
35
+ let entries;
36
+ try {
37
+ entries = readdirSync(dir);
38
+ } catch {
39
+ return;
40
+ }
41
+ for (const entry of entries) {
42
+ if (exclude.includes(entry)) continue;
43
+ const full = resolve(dir, entry);
44
+ let st;
45
+ try {
46
+ st = statSync(full);
47
+ } catch {
48
+ continue;
49
+ }
50
+ if (st.isDirectory()) {
51
+ walk(full, depth + 1);
52
+ } else if (st.isFile() && matchesExtension(full, opts.extensions)) {
53
+ files.push(full);
54
+ }
55
+ }
56
+ }
57
+ walk(root, 0);
58
+ return files;
59
+ }
60
+ function matchesExtension(p, exts) {
61
+ return exts.includes(extname(p).toLowerCase());
62
+ }
21
63
 
22
64
  // src/refactor-suggester/index.ts
23
65
  var API_VERSION = "^0.1.10";
@@ -58,44 +100,6 @@ function readConfig(raw) {
58
100
  function normalizeExtensions(exts) {
59
101
  return exts.map((e) => e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`);
60
102
  }
61
- function matchesExtension(p, exts) {
62
- return exts.includes(extname(p).toLowerCase());
63
- }
64
- function collectSourceFiles(root, exts) {
65
- const files = [];
66
- if (!existsSync(root)) return files;
67
- const s = statSync(root);
68
- if (s.isFile()) {
69
- if (matchesExtension(root, exts)) files.push(root);
70
- return files;
71
- }
72
- if (!s.isDirectory()) return files;
73
- function walk(dir) {
74
- let entries;
75
- try {
76
- entries = readdirSync(dir);
77
- } catch {
78
- return;
79
- }
80
- for (const entry of entries) {
81
- if (entry === "node_modules" || entry === "dist" || entry === ".git" || entry === "coverage") continue;
82
- const full = resolve2(dir, entry);
83
- let st;
84
- try {
85
- st = statSync(full);
86
- } catch {
87
- continue;
88
- }
89
- if (st.isDirectory()) {
90
- walk(full);
91
- } else if (st.isFile() && matchesExtension(full, exts)) {
92
- files.push(full);
93
- }
94
- }
95
- }
96
- walk(root);
97
- return files;
98
- }
99
103
  function toPosix(p) {
100
104
  return p.replace(/\\/g, "/");
101
105
  }
@@ -189,7 +193,7 @@ function scanPath(rawPath, cfg) {
189
193
  const root = process.cwd();
190
194
  const resolved = isAbsolute2(rawPath) ? resolve2(rawPath) : resolve2(root, rawPath);
191
195
  const exts = normalizeExtensions(cfg.extensions);
192
- const files = collectSourceFiles(resolved, exts);
196
+ const files = collectSourceFiles(resolved, { extensions: exts });
193
197
  const suggestions = [];
194
198
  for (const p of files) {
195
199
  try {
@@ -133,4 +133,28 @@ export declare function withinProject(p: string): boolean;
133
133
  * Returns the absolute path or `null`.
134
134
  */
135
135
  export declare function locateRunnerEntry(runtime: LanguageRuntime, projectRoot: string): string | null;
136
+ export interface CollectOptions {
137
+ /** File extensions to include (e.g. ['.ts', '.tsx', '.js']). */
138
+ extensions: string[];
139
+ /** Directory names to skip entirely. Default skips node_modules, dist, .git, coverage. */
140
+ excludeDirs?: string[] | undefined;
141
+ /** Maximum recursion depth. Unlimited when omitted. */
142
+ maxDepth?: number | undefined;
143
+ }
144
+ /**
145
+ * Recursively collect files under `root` whose extension is in
146
+ * `opts.extensions`. Skips directories named in `opts.excludeDirs`
147
+ * (defaulting to node_modules, dist, .git, coverage) and limits depth
148
+ * when `opts.maxDepth` is set.
149
+ *
150
+ * Shared by 6+ plugin source-scan tools that previously duplicated
151
+ * this implementation identically.
152
+ */
153
+ export declare function collectSourceFiles(root: string, opts: CollectOptions): string[];
154
+ /**
155
+ * Check whether `p` has one of the given extensions (case-insensitive).
156
+ * Replaces a 6-copy helper that was duplicated identically across
157
+ * source-scan plugins.
158
+ */
159
+ export declare function matchesExtension(p: string, exts: string[]): boolean;
136
160
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GACxB,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,KAAK,GACL,QAAQ,GACR,IAAI,GACJ,OAAO,GACP,KAAK,GACL,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,EAAE,EAAE,UAAU,CAAC;IACf;;;;OAIG;IACH,cAAc,EAAE,gBAAgB,CAAC;IACjC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACzC;;;;;OAKG;IACH,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,UAAU,EAAE,OAAO,CAAC;CACrB;AAkDD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,cAAmB,GAC3B,eAAe,GAAG,IAAI,CAoExB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,SAAS,CAAC,CAwHpB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,MAAM,YAAc,EAC9B,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAWf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}