@wrongstack/plugins 0.317.0 → 0.317.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.
Files changed (72) hide show
  1. package/dist/accessibility-auditor.js +12 -10
  2. package/dist/agent-handoff.js +30 -10
  3. package/dist/auto-doc.js +22 -9
  4. package/dist/auto-escalate.js +17 -7
  5. package/dist/auto-i18n-extractor.js +19 -9
  6. package/dist/branch-guard.js +12 -9
  7. package/dist/changelog-writer/index.d.ts +3 -3
  8. package/dist/changelog-writer.js +59 -14
  9. package/dist/checkpoint.js +18 -7
  10. package/dist/code-metrics.js +17 -9
  11. package/dist/commit-validator.js +18 -11
  12. package/dist/config-validator.js +5 -3
  13. package/dist/context-pins.js +17 -6
  14. package/dist/cost-tracker.js +24 -16
  15. package/dist/cron.js +17 -13
  16. package/dist/dead-code-detector.js +5 -4
  17. package/dist/dep-guard.js +5 -4
  18. package/dist/dependency-vulnerability-gate.js +64 -24
  19. package/dist/diff-summary.js +6 -2
  20. package/dist/doc-sync-guard.js +12 -2
  21. package/dist/duplicate-code-detector.js +87 -15
  22. package/dist/error-lens.js +6 -5
  23. package/dist/feature-flag-tracker.js +43 -9
  24. package/dist/file-watcher.js +26 -3
  25. package/dist/format-on-save.js +9 -5
  26. package/dist/git-autocommit.js +20 -12
  27. package/dist/gitignore-guard.js +7 -4
  28. package/dist/import-organizer.js +9 -5
  29. package/dist/index.js +1675 -745
  30. package/dist/injection-shield/index.d.ts +1 -0
  31. package/dist/injection-shield.js +30 -5
  32. package/dist/interface-contract-guard.js +4 -2
  33. package/dist/knowledge-graph.js +40 -14
  34. package/dist/license-audit-gate.js +61 -8
  35. package/dist/lint-gate.js +13 -5
  36. package/dist/llm-cache.js +20 -6
  37. package/dist/loop-breaker.js +16 -8
  38. package/dist/migration-planner.js +80 -11
  39. package/dist/model-router.js +16 -9
  40. package/dist/notify-hub.js +14 -5
  41. package/dist/path-guard.js +7 -3
  42. package/dist/performance-regression-gate.js +12 -6
  43. package/dist/plugin-stack-observer.js +25 -3
  44. package/dist/pr-drafter.js +16 -7
  45. package/dist/process-guard.js +2 -1
  46. package/dist/prompt-firewall.js +9 -7
  47. package/dist/refactor-suggester.js +37 -8
  48. package/dist/release-notes-generator/index.d.ts +9 -0
  49. package/dist/release-notes-generator.js +50 -12
  50. package/dist/schema-evolution-guard.js +33 -6
  51. package/dist/secret-scanner.js +10 -7
  52. package/dist/security-hotspot-scanner.js +13 -8
  53. package/dist/semantic-search-indexer/index.d.ts +11 -0
  54. package/dist/semantic-search-indexer.js +67 -19
  55. package/dist/semver-bump/index.d.ts +3 -3
  56. package/dist/semver-bump.js +30 -15
  57. package/dist/session-recap/index.d.ts +16 -0
  58. package/dist/session-recap.js +18 -9
  59. package/dist/shell-check.js +27 -6
  60. package/dist/smart-rename.js +18 -9
  61. package/dist/spec-linker.js +70 -19
  62. package/dist/template-engine.js +24 -14
  63. package/dist/test-coverage-gate.js +1 -1
  64. package/dist/test-flake-detector.js +28 -5
  65. package/dist/test-generator/index.d.ts +10 -0
  66. package/dist/test-generator.js +35 -13
  67. package/dist/todo-listener.js +2 -2
  68. package/dist/todo-tracker.js +19 -11
  69. package/dist/token-budget.js +14 -9
  70. package/dist/token-throttle.js +8 -3
  71. package/dist/type-gate.js +9 -5
  72. package/package.json +5 -5
@@ -215,13 +215,16 @@ function readConfig(raw) {
215
215
  if (typeof v === "string") headers[k] = v;
216
216
  }
217
217
  }
218
+ const rawUrl = r["webhookUrl"] ?? r["webhook_url"] ?? r["url"];
219
+ const rawTimeout = r["timeoutMs"] ?? r["timeout_ms"] ?? r["timeout"];
220
+ const rawFailures = r["maxConsecutiveFailures"] ?? r["max_consecutive_failures"] ?? r["maxFailures"] ?? r["max_failures"];
218
221
  return {
219
222
  enabled: r["enabled"] !== false,
220
- webhookUrl: normalizeWebhookUrl(r["webhookUrl"]),
223
+ webhookUrl: normalizeWebhookUrl(rawUrl),
221
224
  events: Array.isArray(r["events"]) ? r["events"].filter((e) => KNOWN_EVENTS.includes(e)) : [...DEFAULTS.events],
222
225
  headers,
223
- timeoutMs: typeof r["timeoutMs"] === "number" && r["timeoutMs"] >= 500 && r["timeoutMs"] <= 6e4 ? r["timeoutMs"] : DEFAULTS.timeoutMs,
224
- maxConsecutiveFailures: typeof r["maxConsecutiveFailures"] === "number" && r["maxConsecutiveFailures"] >= 1 ? r["maxConsecutiveFailures"] : DEFAULTS.maxConsecutiveFailures
226
+ timeoutMs: typeof rawTimeout === "number" && rawTimeout >= 500 && rawTimeout <= 6e4 ? rawTimeout : DEFAULTS.timeoutMs,
227
+ maxConsecutiveFailures: typeof rawFailures === "number" && rawFailures >= 1 ? rawFailures : DEFAULTS.maxConsecutiveFailures
225
228
  };
226
229
  }
227
230
  async function deliver(event, payload) {
@@ -411,9 +414,15 @@ var plugin = {
411
414
  error: 'no webhookUrl configured \u2014 set config.extensions["notify-hub"].webhookUrl to enable deliveries'
412
415
  };
413
416
  }
417
+ const inp = input ?? {};
418
+ const rawMsg = inp["message"] ?? inp["body"] ?? inp["text"] ?? inp["content"] ?? inp["msg"];
419
+ const message = typeof rawMsg === "string" && rawMsg.trim().length > 0 ? rawMsg.trim() : "";
420
+ if (!message) return { ok: false, error: "message is required" };
421
+ const rawTitle = inp["title"] ?? inp["subject"] ?? inp["header"];
422
+ const title = typeof rawTitle === "string" && rawTitle.trim() ? rawTitle.trim() : "WrongStack notification";
414
423
  const result = await deliverViaChannel(ch, "manual", {
415
- title: truncateText(String(input.title ?? "WrongStack notification"), 200),
416
- body: truncateText(String(input.message ?? ""), 2e3),
424
+ title: truncateText(title, 200),
425
+ body: truncateText(message, 2e3),
417
426
  level: input.level === "warning" || input.level === "critical" ? input.level : "info",
418
427
  source: "manual"
419
428
  });
@@ -1354,11 +1354,15 @@ var DEFAULTS = {
1354
1354
  function readConfig(raw) {
1355
1355
  if (!raw || typeof raw !== "object") return { ...DEFAULTS, protect: [...DEFAULT_PROTECT] };
1356
1356
  const r = raw;
1357
+ const rawMode = typeof (r["mode"] ?? r["action"] ?? r["behavior"]) === "string" ? String(r["mode"] ?? r["action"] ?? r["behavior"]).trim().toLowerCase() : void 0;
1358
+ const mode = rawMode === "warn" ? "warn" : "block";
1359
+ const rawProtect = r["protect"] ?? r["protectedPaths"] ?? r["protected_paths"] ?? r["protected"];
1360
+ const rawAllow = r["allow"] ?? r["allowedPaths"] ?? r["allowed_paths"] ?? r["allowed"];
1357
1361
  return {
1358
1362
  enabled: r["enabled"] !== false,
1359
- mode: r["mode"] === "warn" ? "warn" : "block",
1360
- protect: Array.isArray(r["protect"]) ? r["protect"].filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
1361
- allow: Array.isArray(r["allow"]) ? r["allow"].filter((p) => typeof p === "string" && p.length > 0) : []
1363
+ mode,
1364
+ protect: Array.isArray(rawProtect) ? rawProtect.filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
1365
+ allow: Array.isArray(rawAllow) ? rawAllow.filter((p) => typeof p === "string" && p.length > 0) : []
1362
1366
  };
1363
1367
  }
1364
1368
  var plugin = {
@@ -200,8 +200,12 @@ var plugin = {
200
200
  return { ok: false, error: "performance-regression-gate is disabled" };
201
201
  }
202
202
  state.invocationCount += 1;
203
- const threshold = typeof input.thresholdPercent === "number" && input.thresholdPercent >= 0 && input.thresholdPercent <= 1e3 ? input.thresholdPercent : cfg.thresholdPercent;
204
- const resultsPath = resolveProjectPath(input.resultsPath || "bench-results.json") ?? "";
203
+ const raw = input ?? {};
204
+ const rawThreshold = input.thresholdPercent ?? raw["threshold"] ?? raw["threshold_percent"] ?? raw["thresholdPercent"] ?? raw["percent"];
205
+ const threshold = typeof rawThreshold === "number" && rawThreshold >= 0 && rawThreshold <= 1e3 ? rawThreshold : cfg.thresholdPercent;
206
+ const rawResultsPath = input.resultsPath ?? raw["results_path"] ?? raw["file_path"] ?? raw["path"] ?? raw["filePath"] ?? raw["file"] ?? raw["TargetFile"] ?? raw["targetFile"] ?? "bench-results.json";
207
+ const resultsPathStr = typeof rawResultsPath === "string" && rawResultsPath.trim() ? rawResultsPath.trim() : "bench-results.json";
208
+ const resultsPath = resolveProjectPath(resultsPathStr) ?? "";
205
209
  if (!resultsPath) {
206
210
  state.errorCount += 1;
207
211
  return { ok: false, error: "invalid results path (must be inside project)" };
@@ -215,7 +219,7 @@ var plugin = {
215
219
  thresholdPercent: threshold,
216
220
  comparisons: 0,
217
221
  regressions: [],
218
- message: `No benchmark results found at ${input.resultsPath || "bench-results.json"}.`
222
+ message: `No benchmark results found at ${resultsPathStr}.`
219
223
  };
220
224
  }
221
225
  const current = flattenResults(results);
@@ -230,9 +234,11 @@ var plugin = {
230
234
  message: "No benchmarks with valid mean/period values were found."
231
235
  };
232
236
  }
237
+ const rawBaselinePath = input.baselinePath ?? raw["baseline_path"] ?? raw["baseline"] ?? raw["basePath"] ?? raw["base_path"];
238
+ const baselinePathStr = typeof rawBaselinePath === "string" && rawBaselinePath.trim() ? rawBaselinePath.trim() : void 0;
233
239
  let pairs;
234
- if (input.baselinePath) {
235
- const baselineResolved = resolveProjectPath(input.baselinePath) ?? "";
240
+ if (baselinePathStr) {
241
+ const baselineResolved = resolveProjectPath(baselinePathStr) ?? "";
236
242
  if (!baselineResolved) {
237
243
  state.errorCount += 1;
238
244
  return { ok: false, error: "invalid baseline path (must be inside project)" };
@@ -242,7 +248,7 @@ var plugin = {
242
248
  state.errorCount += 1;
243
249
  return {
244
250
  ok: false,
245
- error: `Could not read baseline results at ${input.baselinePath}.`
251
+ error: `Could not read baseline results at ${baselinePathStr}.`
246
252
  };
247
253
  }
248
254
  const baseline = flattenResults(baselineResults);
@@ -1,8 +1,28 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __copyProps = (to, from, except, desc) => {
6
+ if (from && typeof from === "object" || typeof from === "function") {
7
+ for (let key of __getOwnPropNames(from))
8
+ if (!__hasOwnProp.call(to, key) && key !== except)
9
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
10
+ }
11
+ return to;
12
+ };
13
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
14
+
15
+ // src/runtime/index.ts
16
+ var runtime_exports = {};
17
+ __reExport(runtime_exports, runtime_star);
18
+ import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
19
+
1
20
  // src/plugin-stack-observer/index.ts
2
21
  var state = {
3
22
  wraps: [],
4
23
  contributions: 0,
5
- patternUnregister: null
24
+ patternUnregister: null,
25
+ contributorUnregister: null
6
26
  };
7
27
  function clearObserverState() {
8
28
  if (state.patternUnregister) {
@@ -12,6 +32,7 @@ function clearObserverState() {
12
32
  }
13
33
  state.patternUnregister = null;
14
34
  }
35
+ state.contributorUnregister = (0, runtime_exports.releaseHandle)(state.contributorUnregister);
15
36
  state.wraps = [];
16
37
  state.contributions = 0;
17
38
  }
@@ -65,8 +86,9 @@ var PLUGIN = {
65
86
  api.metrics.counter("wrap_loaded");
66
87
  }
67
88
  );
89
+ state.contributorUnregister = (0, runtime_exports.releaseHandle)(state.contributorUnregister);
68
90
  if (cfg.injectIntoSystemPrompt) {
69
- api.registerSystemPromptContributor(async () => {
91
+ state.contributorUnregister = api.registerSystemPromptContributor(async () => {
70
92
  if (state.wraps.length === 0) return [];
71
93
  state.contributions += 1;
72
94
  api.metrics.counter("system_prompt_contribution");
@@ -131,7 +153,7 @@ function readConfig(raw) {
131
153
  const r = raw;
132
154
  return {
133
155
  enabled: r["enabled"] !== false,
134
- injectIntoSystemPrompt: r["injectIntoSystemPrompt"] === true
156
+ injectIntoSystemPrompt: r["injectIntoSystemPrompt"] === true || r["inject_into_system_prompt"] === true
135
157
  };
136
158
  }
137
159
  var plugin_stack_observer_default = PLUGIN;
@@ -236,8 +236,10 @@ var plugin = {
236
236
  const msg = p.result.commitMessage ?? p.input?.message ?? "commit";
237
237
  state.commits.push(msg);
238
238
  }
239
- if ((toolName === "write" || toolName === "edit") && p?.input?.path) {
240
- state.files.add(p.input.path);
239
+ const rawInput = p?.input ?? {};
240
+ const filePath = typeof rawInput["path"] === "string" && rawInput["path"] || typeof rawInput["filePath"] === "string" && rawInput["filePath"] || typeof rawInput["file_path"] === "string" && rawInput["file_path"] || typeof rawInput["TargetFile"] === "string" && rawInput["TargetFile"] || typeof rawInput["targetFile"] === "string" && rawInput["targetFile"] || typeof rawInput["file"] === "string" && rawInput["file"];
241
+ if ((toolName === "write" || toolName === "edit" || toolName === "write_to_file" || toolName === "replace_file_content") && filePath) {
242
+ state.files.add(filePath);
241
243
  }
242
244
  });
243
245
  state.eventUnsubscribers.push(offTool);
@@ -246,8 +248,11 @@ var plugin = {
246
248
  const offUsage = api.onEvent("provider.response", (payload) => {
247
249
  const p = payload;
248
250
  if (p?.model) state.models.add(p.model);
249
- state.totalInputTokens += p?.usage?.input ?? 0;
250
- state.totalOutputTokens += p?.usage?.output ?? 0;
251
+ const rawUsage = p?.usage;
252
+ const inputTokens = (typeof rawUsage?.["input"] === "number" ? rawUsage["input"] : void 0) ?? (typeof rawUsage?.["prompt_tokens"] === "number" ? rawUsage["prompt_tokens"] : void 0) ?? (typeof rawUsage?.["input_tokens"] === "number" ? rawUsage["input_tokens"] : void 0) ?? (typeof rawUsage?.["promptTokens"] === "number" ? rawUsage["promptTokens"] : 0);
253
+ const outputTokens = (typeof rawUsage?.["output"] === "number" ? rawUsage["output"] : void 0) ?? (typeof rawUsage?.["completion_tokens"] === "number" ? rawUsage["completion_tokens"] : void 0) ?? (typeof rawUsage?.["output_tokens"] === "number" ? rawUsage["output_tokens"] : void 0) ?? (typeof rawUsage?.["completionTokens"] === "number" ? rawUsage["completionTokens"] : 0);
254
+ state.totalInputTokens += inputTokens;
255
+ state.totalOutputTokens += outputTokens;
251
256
  });
252
257
  state.eventUnsubscribers.push(offUsage);
253
258
  }
@@ -280,11 +285,15 @@ var plugin = {
280
285
  capabilities: ["fs.write"],
281
286
  async execute(input = {}) {
282
287
  if (!cfg.enabled) return { ok: false, error: "pr-drafter is disabled" };
288
+ const raw = input ?? {};
289
+ const preview = Boolean(input?.preview ?? raw["dryRun"] ?? raw["dry_run"] ?? raw["dry"] ?? raw["previewOnly"]);
290
+ const rawOutputPath = raw["outputPath"] ?? raw["output_path"] ?? raw["path"] ?? raw["filePath"] ?? raw["file"] ?? raw["TargetFile"] ?? raw["targetFile"] ?? cfg.outputPath;
291
+ const outputPathStr = typeof rawOutputPath === "string" && rawOutputPath.trim().length > 0 ? rawOutputPath.trim() : cfg.outputPath;
283
292
  const draft = await buildDraft(cfg, api.llm);
284
- if (input?.preview) {
293
+ if (preview) {
285
294
  return { ok: true, preview: true, title: draft.title, body: draft.body };
286
295
  }
287
- const resolved = resolveProjectPath(cfg.outputPath);
296
+ const resolved = resolveProjectPath(outputPathStr);
288
297
  if (!resolved) return { ok: false, error: "outputPath resolves outside project" };
289
298
  try {
290
299
  await mkdir(dirname(resolved), { recursive: true });
@@ -292,7 +301,7 @@ var plugin = {
292
301
  state.draftsWritten += 1;
293
302
  return {
294
303
  ok: true,
295
- path: cfg.outputPath,
304
+ path: outputPathStr,
296
305
  resolvedPath: resolved,
297
306
  title: draft.title
298
307
  };
@@ -61,7 +61,8 @@ var plugin = {
61
61
  const toolName = input.toolName ?? "";
62
62
  if (toolName !== "bash" && toolName !== "exec") return;
63
63
  const ti = input.toolInput ?? {};
64
- const command = typeof ti["command"] === "string" ? ti["command"] : "";
64
+ const rawCmd = ti["command"] ?? ti["CommandLine"] ?? ti["cmd"] ?? ti["script"] ?? ti["input"];
65
+ const command = typeof rawCmd === "string" ? rawCmd : "";
65
66
  if (!command) return;
66
67
  const isKillRelated = /\b(?:kill|taskkill|stop-process|tskill|pkill|killall|wmic)\b/i.test(command);
67
68
  if (!isKillRelated) return;
@@ -256,17 +256,21 @@ function readConfig(raw) {
256
256
  };
257
257
  if (!raw || typeof raw !== "object") return base;
258
258
  const r = raw;
259
- const allow = Array.isArray(r["allow"]) ? r["allow"].filter((s) => typeof s === "string" && s.length > 0).flatMap((s) => {
259
+ const rawAllow = r["allow"] ?? r["allowlist"] ?? r["allowed"];
260
+ const allow = Array.isArray(rawAllow) ? rawAllow.filter((s) => typeof s === "string" && s.length > 0).flatMap((s) => {
260
261
  try {
261
262
  return [new RegExp(s)];
262
263
  } catch {
263
264
  return [];
264
265
  }
265
266
  }) : [];
267
+ const rawMode = typeof (r["mode"] ?? r["action"] ?? r["behavior"]) === "string" ? String(r["mode"] ?? r["action"] ?? r["behavior"]).trim().toLowerCase() : void 0;
268
+ const mode = rawMode === "warn" ? "warn" : rawMode === "block" ? "block" : "redact";
269
+ const rawScan = r["scanResponse"] ?? r["scan_response"];
266
270
  return {
267
271
  enabled: r["enabled"] === true,
268
- mode: r["mode"] === "warn" ? "warn" : r["mode"] === "block" ? "block" : "redact",
269
- scanResponse: r["scanResponse"] !== false,
272
+ mode,
273
+ scanResponse: rawScan !== false,
270
274
  allow
271
275
  };
272
276
  }
@@ -412,11 +416,9 @@ var plugin = {
412
416
  function redactResponse(response, allow, skip) {
413
417
  if (!response || typeof response !== "object") return response;
414
418
  const counter = { n: 0 };
415
- const content = response.content;
416
- if (content === void 0) return response;
417
419
  const budget = { remaining: RESPONSE_SCAN_BUDGET, truncated: false };
418
420
  const deadline = createScanDeadline();
419
- const redacted = redactDeep(content, allow, counter, skip, budget, deadline);
421
+ const redacted = redactDeep(response, allow, counter, skip, budget, deadline);
420
422
  if (deadline.tripped.size > 0) surfaceScanTrips(api, deadline.tripped);
421
423
  if (budget.truncated) {
422
424
  state.responseTruncated = true;
@@ -434,7 +436,7 @@ var plugin = {
434
436
  when: (/* @__PURE__ */ new Date()).toISOString()
435
437
  };
436
438
  }
437
- return { ...response, content: redacted };
439
+ return redacted;
438
440
  }
439
441
  api.tools.register({
440
442
  name: "prompt_firewall_status",
@@ -42,19 +42,24 @@ var DEFAULTS = {
42
42
  function readRules(raw) {
43
43
  if (!raw || typeof raw !== "object") return { ...DEFAULTS.rules };
44
44
  const r = raw;
45
+ const rawLong = r["longFunctionLines"] ?? r["long_function_lines"] ?? r["maxLines"] ?? r["max_lines"];
46
+ const rawParams = r["maxParams"] ?? r["max_params"];
47
+ const rawNesting = r["maxNesting"] ?? r["max_nesting"] ?? r["nesting"];
45
48
  return {
46
- longFunctionLines: typeof r["longFunctionLines"] === "number" && r["longFunctionLines"] >= 1 ? r["longFunctionLines"] : DEFAULTS.rules.longFunctionLines,
47
- maxParams: typeof r["maxParams"] === "number" && r["maxParams"] >= 1 ? r["maxParams"] : DEFAULTS.rules.maxParams,
48
- maxNesting: typeof r["maxNesting"] === "number" && r["maxNesting"] >= 1 ? r["maxNesting"] : DEFAULTS.rules.maxNesting
49
+ longFunctionLines: typeof rawLong === "number" && rawLong >= 1 ? rawLong : DEFAULTS.rules.longFunctionLines,
50
+ maxParams: typeof rawParams === "number" && rawParams >= 1 ? rawParams : DEFAULTS.rules.maxParams,
51
+ maxNesting: typeof rawNesting === "number" && rawNesting >= 1 ? rawNesting : DEFAULTS.rules.maxNesting
49
52
  };
50
53
  }
51
54
  function readConfig(raw) {
52
55
  if (!raw || typeof raw !== "object") return { ...DEFAULTS };
53
56
  const r = raw;
57
+ const rawExts = r["extensions"] ?? r["file_extensions"] ?? r["fileExtensions"];
58
+ const rawMax = r["maxSuggestions"] ?? r["max_suggestions"] ?? r["limit"];
54
59
  return {
55
60
  enabled: r["enabled"] === true,
56
- extensions: Array.isArray(r["extensions"]) ? r["extensions"].filter((x) => typeof x === "string") : DEFAULTS.extensions,
57
- maxSuggestions: typeof r["maxSuggestions"] === "number" && r["maxSuggestions"] >= 1 && r["maxSuggestions"] <= 500 ? r["maxSuggestions"] : DEFAULTS.maxSuggestions,
61
+ extensions: Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : DEFAULTS.extensions,
62
+ maxSuggestions: typeof rawMax === "number" && rawMax >= 1 && rawMax <= 500 ? rawMax : DEFAULTS.maxSuggestions,
58
63
  rules: readRules(r["rules"])
59
64
  };
60
65
  }
@@ -67,6 +72,28 @@ function toPosix(p) {
67
72
  function relativePath(p) {
68
73
  return toPosix(relative(process.cwd(), p));
69
74
  }
75
+ function splitTopLevelParams(paramsRaw) {
76
+ const result = [];
77
+ let current = "";
78
+ let depth = 0;
79
+ for (let i = 0; i < paramsRaw.length; i++) {
80
+ const ch = paramsRaw[i];
81
+ if (ch === "(" || ch === "{" || ch === "[" || ch === "<") {
82
+ depth++;
83
+ current += ch;
84
+ } else if (ch === ")" || ch === "}" || ch === "]" || ch === ">") {
85
+ if (depth > 0) depth--;
86
+ current += ch;
87
+ } else if (ch === "," && depth === 0) {
88
+ if (current.trim().length > 0) result.push(current.trim());
89
+ current = "";
90
+ } else {
91
+ current += ch;
92
+ }
93
+ }
94
+ if (current.trim().length > 0) result.push(current.trim());
95
+ return result;
96
+ }
70
97
  function leadingIndentLevel(line) {
71
98
  const leading = line.match(/^(\s*)/)?.[1] ?? "";
72
99
  const tabs = leading.split(" ").length - 1;
@@ -93,7 +120,7 @@ function detectSmells(filePath, content, rules) {
93
120
  const name = match[1];
94
121
  if (CONTROL_KEYWORDS.has(name)) continue;
95
122
  const paramsRaw = match[2];
96
- const params = paramsRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
123
+ const params = splitTopLevelParams(paramsRaw);
97
124
  if (params.length > rules.maxParams) {
98
125
  suggestions.push({
99
126
  file: relativePath(filePath),
@@ -241,7 +268,8 @@ var plugin = {
241
268
  if (!cfg.enabled) return;
242
269
  if (input.toolResult?.isError) return;
243
270
  const inp = input.toolInput ?? {};
244
- const sourcePath = inp["path"];
271
+ const rawPath = inp["path"] ?? inp["filePath"] ?? inp["file_path"] ?? inp["TargetFile"] ?? inp["targetFile"] ?? inp["file"];
272
+ const sourcePath = typeof rawPath === "string" && rawPath.trim() ? rawPath.trim() : void 0;
245
273
  if (!sourcePath || typeof sourcePath !== "string") return;
246
274
  if (!(0, runtime_exports.withinProject)(sourcePath)) return;
247
275
  const exts = normalizeExtensions(cfg.extensions);
@@ -282,7 +310,8 @@ var plugin = {
282
310
  mutating: false,
283
311
  async execute(input) {
284
312
  if (!cfg.enabled) return { ok: false, error: "refactor-suggester is disabled" };
285
- const rawPath = typeof input.path === "string" ? input.path : ".";
313
+ const raw = input ?? {};
314
+ const rawPath = (typeof input.path === "string" && input.path.trim().length > 0 ? input.path.trim() : void 0) ?? (typeof raw["directory"] === "string" ? raw["directory"] : void 0) ?? (typeof raw["dir"] === "string" ? raw["dir"] : void 0) ?? (typeof raw["SearchDirectory"] === "string" ? raw["SearchDirectory"] : void 0) ?? (typeof raw["TargetFile"] === "string" ? raw["TargetFile"] : void 0) ?? (typeof raw["filePath"] === "string" ? raw["filePath"] : void 0) ?? (typeof raw["targetFile"] === "string" ? raw["targetFile"] : void 0) ?? ".";
286
315
  if (!(0, runtime_exports.withinProject)(rawPath)) {
287
316
  return { ok: false, error: "path is outside the project root" };
288
317
  }
@@ -22,6 +22,15 @@
22
22
  * @public
23
23
  */
24
24
  import type { Plugin } from '@wrongstack/core/types';
25
+ interface ReleaseNotesGeneratorConfig {
26
+ enabled: boolean;
27
+ includeScope: boolean;
28
+ defaultFrom: string;
29
+ useLlm: boolean;
30
+ audience: ReleaseAudience;
31
+ }
32
+ type ReleaseAudience = 'users' | 'developers' | 'operators';
33
+ export declare function readConfig(raw: unknown): ReleaseNotesGeneratorConfig;
25
34
  declare const plugin: Plugin;
26
35
  export default plugin;
27
36
  //# sourceMappingURL=index.d.ts.map
@@ -26,26 +26,44 @@ var DEFAULTS = {
26
26
  audience: "users"
27
27
  };
28
28
  function readAudience(raw) {
29
- return raw === "developers" || raw === "operators" || raw === "users" ? raw : DEFAULTS.audience;
29
+ const norm = typeof raw === "string" ? raw.trim().toLowerCase() : "";
30
+ return norm === "developers" || norm === "operators" || norm === "users" ? norm : DEFAULTS.audience;
30
31
  }
31
32
  function readConfig(raw) {
32
33
  if (!raw || typeof raw !== "object") return { ...DEFAULTS };
33
34
  const r = raw;
35
+ const rawScope = r["includeScope"] ?? r["include_scope"];
36
+ const rawFrom = r["defaultFrom"] ?? r["default_from"] ?? r["from"];
37
+ const rawLlm = r["useLlm"] ?? r["use_llm"];
34
38
  return {
35
39
  enabled: r["enabled"] !== false,
36
- includeScope: r["includeScope"] !== false,
37
- defaultFrom: typeof r["defaultFrom"] === "string" ? r["defaultFrom"] : DEFAULTS.defaultFrom,
38
- useLlm: r["useLlm"] === true,
40
+ includeScope: rawScope !== false,
41
+ defaultFrom: typeof rawFrom === "string" ? rawFrom : DEFAULTS.defaultFrom,
42
+ useLlm: rawLlm === true,
39
43
  audience: readAudience(r["audience"])
40
44
  };
41
45
  }
42
- var CONVENTIONAL_TYPES = ["feat", "fix", "docs", "refactor", "perf", "test", "chore"];
46
+ var CONVENTIONAL_TYPES = [
47
+ "feat",
48
+ "fix",
49
+ "docs",
50
+ "refactor",
51
+ "perf",
52
+ "test",
53
+ "chore",
54
+ "revert",
55
+ "build",
56
+ "ci",
57
+ "style",
58
+ "i18n",
59
+ "a11y"
60
+ ];
43
61
  function parseConventionalCommit(subject) {
44
- const match = subject.match(/^([a-z]+)(?:\(([^)]+)\))?!?:\s*(.+)$/);
62
+ const match = subject.match(/^([a-zA-Z][a-zA-Z0-9_-]*)(?:\(([^)]+)\))?!?:\s*(.+)$/);
45
63
  if (!match) {
46
64
  return { type: "uncategorized", scope: null, description: subject };
47
65
  }
48
- const rawType = match[1];
66
+ const rawType = match[1].toLowerCase();
49
67
  const scope = match[2] ?? null;
50
68
  const description = match[3];
51
69
  const type = CONVENTIONAL_TYPES.includes(rawType) ? rawType : "uncategorized";
@@ -128,7 +146,21 @@ function generateNotes(commits, includeScope) {
128
146
  const lines = [];
129
147
  lines.push(`## Release Notes (${commits.length} commit${commits.length === 1 ? "" : "s"})`);
130
148
  lines.push("");
131
- const order = ["feat", "fix", "perf", "refactor", "docs", "test", "chore"];
149
+ const order = [
150
+ "feat",
151
+ "fix",
152
+ "perf",
153
+ "refactor",
154
+ "docs",
155
+ "test",
156
+ "chore",
157
+ "revert",
158
+ "build",
159
+ "ci",
160
+ "style",
161
+ "i18n",
162
+ "a11y"
163
+ ];
132
164
  for (const type of order) {
133
165
  const list = groups[type];
134
166
  if (!list || list.length === 0) continue;
@@ -254,8 +286,13 @@ var plugin = {
254
286
  async execute(input, _ctx, execOpts) {
255
287
  if (!cfg.enabled) return { ok: false, error: "release-notes-generator is disabled" };
256
288
  execOpts?.signal?.throwIfAborted();
257
- const toRef = typeof input.to === "string" ? input.to : "HEAD";
258
- const fromRef = await resolveFromRef(cfg.defaultFrom, input.from, execOpts?.signal);
289
+ const raw = input ?? {};
290
+ const rawTo = input.to ?? raw["to_ref"] ?? raw["toRef"] ?? raw["until"] ?? raw["end"];
291
+ const rawFrom = input.from ?? raw["from_ref"] ?? raw["fromRef"] ?? raw["since"] ?? raw["start"];
292
+ const rawUseLlm = input.use_llm ?? raw["useLlm"] ?? raw["use_ai"] ?? raw["useAi"];
293
+ const toRef = typeof rawTo === "string" && rawTo.trim() ? rawTo.trim() : "HEAD";
294
+ const fromInput = typeof rawFrom === "string" && rawFrom.trim() ? rawFrom.trim() : void 0;
295
+ const fromRef = await resolveFromRef(cfg.defaultFrom, fromInput, execOpts?.signal);
259
296
  state.generateCount += 1;
260
297
  let commits;
261
298
  try {
@@ -267,7 +304,7 @@ var plugin = {
267
304
  state.commitCount += commits.length;
268
305
  execOpts?.signal?.throwIfAborted();
269
306
  const deterministicNotes = generateNotes(commits, cfg.includeScope);
270
- const requested = (input.use_llm ?? cfg.useLlm) && commits.length > 0;
307
+ const requested = ((typeof rawUseLlm === "boolean" ? rawUseLlm : void 0) ?? cfg.useLlm) && commits.length > 0;
271
308
  const audience = readAudience(input.audience ?? cfg.audience);
272
309
  const llm = await runOptionalPluginLlm({
273
310
  requested,
@@ -342,5 +379,6 @@ var plugin = {
342
379
  };
343
380
  var release_notes_generator_default = plugin;
344
381
  export {
345
- release_notes_generator_default as default
382
+ release_notes_generator_default as default,
383
+ readConfig
346
384
  };
@@ -49,11 +49,14 @@ var DEFAULTS = {
49
49
  function readConfig(raw) {
50
50
  if (!raw || typeof raw !== "object") return { ...DEFAULTS };
51
51
  const r = raw;
52
+ const rawSev = typeof (r["failSeverity"] ?? r["fail_severity"] ?? r["severity"] ?? r["mode"]) === "string" ? String(r["failSeverity"] ?? r["fail_severity"] ?? r["severity"] ?? r["mode"]).trim().toLowerCase() : void 0;
53
+ const rawMax = r["maxFindings"] ?? r["max_findings"] ?? r["limit"];
54
+ const rawPatterns = r["filePatterns"] ?? r["file_patterns"] ?? r["patterns"];
52
55
  return {
53
56
  enabled: r["enabled"] !== false,
54
- failSeverity: r["failSeverity"] === "block" ? "block" : DEFAULTS.failSeverity,
55
- maxFindings: typeof r["maxFindings"] === "number" && Number.isFinite(r["maxFindings"]) && r["maxFindings"] >= 1 && r["maxFindings"] <= 50 ? Math.floor(r["maxFindings"]) : DEFAULTS.maxFindings,
56
- filePatterns: Array.isArray(r["filePatterns"]) ? r["filePatterns"].filter((x) => typeof x === "string") : DEFAULTS.filePatterns
57
+ failSeverity: rawSev === "block" ? "block" : DEFAULTS.failSeverity,
58
+ maxFindings: typeof rawMax === "number" && Number.isFinite(rawMax) && rawMax >= 1 && rawMax <= 50 ? Math.floor(rawMax) : DEFAULTS.maxFindings,
59
+ filePatterns: Array.isArray(rawPatterns) ? rawPatterns.filter((x) => typeof x === "string") : DEFAULTS.filePatterns
57
60
  };
58
61
  }
59
62
  function patternToRegExp(pattern) {
@@ -95,7 +98,12 @@ function findIssues(content, kind, maxFindings) {
95
98
  }
96
99
  case "prisma": {
97
100
  const match = line.match(/^\s+([A-Za-z_]\w*)\s+([A-Za-z_]\w+)(\?)?(\s+@.*)?$/);
98
- if (match && !match[3] && !match[4]?.includes("@default")) {
101
+ const attrs = match?.[4] ?? "";
102
+ const isExempt = attrs.split(/\s+/).some((t) => {
103
+ const name = t.replace(/\(.*$/, "");
104
+ return name === "@default" || name === "@id" || name === "@updatedAt" || name === "@relation" || name === "@ignore";
105
+ });
106
+ if (match && !match[3] && !isExempt) {
99
107
  findings.push(
100
108
  `required field without default at line ${lineNumber}: ${match[1]} (${match[2]})`
101
109
  );
@@ -205,7 +213,8 @@ var plugin = {
205
213
  if (!cfg.enabled) return;
206
214
  if (input.toolResult?.isError) return;
207
215
  const toolInput = input.toolInput ?? {};
208
- const filePath = typeof toolInput["path"] === "string" ? toolInput["path"] : void 0;
216
+ const rawPath = toolInput["path"] ?? toolInput["filePath"] ?? toolInput["file_path"] ?? toolInput["TargetFile"] ?? toolInput["targetFile"] ?? toolInput["file"];
217
+ const filePath = typeof rawPath === "string" && rawPath.trim() ? rawPath.trim() : void 0;
209
218
  if (!filePath) return;
210
219
  state.invocationCount += 1;
211
220
  const fileName = basename(filePath);
@@ -221,6 +230,22 @@ var plugin = {
221
230
  let content;
222
231
  if (typeof toolInput["content"] === "string") {
223
232
  content = toolInput["content"];
233
+ } else if (typeof toolInput["CodeContent"] === "string") {
234
+ content = toolInput["CodeContent"];
235
+ } else if (typeof toolInput["code"] === "string") {
236
+ content = toolInput["code"];
237
+ } else if (typeof toolInput["text"] === "string") {
238
+ content = toolInput["text"];
239
+ } else if (typeof toolInput["contents"] === "string") {
240
+ content = toolInput["contents"];
241
+ } else if (typeof toolInput["body"] === "string") {
242
+ content = toolInput["body"];
243
+ } else if (typeof toolInput["new_string"] === "string") {
244
+ content = toolInput["new_string"];
245
+ } else if (typeof toolInput["ReplacementContent"] === "string") {
246
+ content = toolInput["ReplacementContent"];
247
+ } else if (typeof toolInput["newContent"] === "string") {
248
+ content = toolInput["newContent"];
224
249
  } else if ((0, runtime_exports.withinProject)(filePath)) {
225
250
  try {
226
251
  content = readFileSync(filePath, "utf-8");
@@ -250,7 +275,9 @@ ${body}${suffix}`;
250
275
  state.warningCount += 1;
251
276
  return { additionalContext: message };
252
277
  };
253
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
278
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
279
+ background: true
280
+ });
254
281
  api.tools.register({
255
282
  name: "schema_evolution_status",
256
283
  description: "Reports schema-evolution-guard state: config, file patterns, and per-session counters.",
@@ -198,14 +198,16 @@ var DEFAULTS = {
198
198
  function readConfig(raw) {
199
199
  if (!raw || typeof raw !== "object") return { ...DEFAULTS };
200
200
  const r = raw;
201
- const mode = r["mode"] === "redact" || r["mode"] === "allow" ? r["mode"] : "block";
201
+ const rawMode = typeof (r["mode"] ?? r["action"] ?? r["behavior"]) === "string" ? String(r["mode"] ?? r["action"] ?? r["behavior"]).trim().toLowerCase() : void 0;
202
+ const mode = rawMode === "redact" || rawMode === "allow" || rawMode === "warn" ? rawMode === "warn" ? "allow" : rawMode : "block";
202
203
  const customPatterns = [];
203
- if (Array.isArray(r["customPatterns"])) {
204
- for (const entry of r["customPatterns"]) {
204
+ const rawCustom = r["customPatterns"] ?? r["custom_patterns"] ?? r["patterns"];
205
+ if (Array.isArray(rawCustom)) {
206
+ for (const entry of rawCustom) {
205
207
  if (!entry || typeof entry !== "object") continue;
206
208
  const e = entry;
207
- const type = e["type"];
208
- const regex = e["regex"];
209
+ const type = e["type"] ?? e["name"] ?? e["kind"];
210
+ const regex = e["regex"] ?? e["pattern"];
209
211
  if (typeof type !== "string" || typeof regex !== "string") continue;
210
212
  try {
211
213
  new RegExp(regex, "g");
@@ -221,7 +223,7 @@ function readConfig(raw) {
221
223
  }
222
224
  return {
223
225
  matcher: typeof r["matcher"] === "string" ? r["matcher"] : DEFAULTS.matcher,
224
- postToolUseMatcher: typeof r["postToolUseMatcher"] === "string" ? r["postToolUseMatcher"] : DEFAULTS.postToolUseMatcher,
226
+ postToolUseMatcher: typeof (r["postToolUseMatcher"] ?? r["post_tool_use_matcher"] ?? r["outputMatcher"]) === "string" ? r["postToolUseMatcher"] ?? r["post_tool_use_matcher"] ?? r["outputMatcher"] : DEFAULTS.postToolUseMatcher,
225
227
  mode,
226
228
  enabled: r["enabled"] !== false,
227
229
  customPatterns
@@ -445,7 +447,8 @@ var plugin = {
445
447
  mutating: false,
446
448
  async execute(input) {
447
449
  activateRuntime(runtime);
448
- const text = typeof input["text"] === "string" ? input["text"] : "";
450
+ const rawText = input["text"] ?? input["content"] ?? input["string"] ?? input["input"] ?? input["code"] ?? input["value"] ?? "";
451
+ const text = typeof rawText === "string" ? rawText : "";
449
452
  const matched = findMatches(text);
450
453
  return {
451
454
  ok: true,