@wrongstack/plugins 0.318.0 → 0.319.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -175,7 +175,12 @@ async function auditFile(filePath, projectRoot) {
175
175
  );
176
176
  }
177
177
  if (!hasPrimaryLabel && ATTR_PLACEHOLDER.test(tag)) {
178
- add(lineNo, "low-contrast-placeholder", "warning", "<input> uses placeholder text (often low contrast and disappears on input)");
178
+ add(
179
+ lineNo,
180
+ "low-contrast-placeholder",
181
+ "warning",
182
+ "<input> uses placeholder text (often low contrast and disappears on input)"
183
+ );
179
184
  }
180
185
  }
181
186
  TAG_INPUT.lastIndex = 0;
@@ -186,14 +191,24 @@ async function auditFile(filePath, projectRoot) {
186
191
  const hasAriaLabel = ATTR_ARIA_LABEL.test(tag);
187
192
  const hasTitle = ATTR_TITLE.test(tag);
188
193
  if (!hasText && !hasAriaLabel && !hasTitle) {
189
- add(lineNo, "missing-button-text", "error", "<button> has no visible text or accessible label");
194
+ add(
195
+ lineNo,
196
+ "missing-button-text",
197
+ "error",
198
+ "<button> has no visible text or accessible label"
199
+ );
190
200
  }
191
201
  }
192
202
  TAG_BUTTON.lastIndex = 0;
193
203
  for (const inputButtonMatch of line.matchAll(INPUT_BUTTON)) {
194
204
  const tag = inputButtonMatch[0];
195
205
  if (!ATTR_VALUE.test(tag) && !ATTR_ARIA_LABEL.test(tag) && !ATTR_TITLE.test(tag)) {
196
- add(lineNo, "missing-button-text", "error", `<input type="${inputButtonMatch[1]}"> is missing value/aria-label/title`);
206
+ add(
207
+ lineNo,
208
+ "missing-button-text",
209
+ "error",
210
+ `<input type="${inputButtonMatch[1]}"> is missing value/aria-label/title`
211
+ );
197
212
  }
198
213
  }
199
214
  INPUT_BUTTON.lastIndex = 0;
@@ -328,7 +343,9 @@ var plugin = {
328
343
  }
329
344
  return { additionalContext: summary };
330
345
  };
331
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
346
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
347
+ background: true
348
+ });
332
349
  api.tools.register({
333
350
  name: "a11y_audit",
334
351
  description: "Audit a file or directory for accessibility issues. Scans .tsx/.jsx/.html/.vue files for missing alt text, missing labels, low-contrast placeholders, missing button text, and duplicate ids.",
@@ -284,7 +284,9 @@ var plugin = {
284
284
  }
285
285
  return { additionalContext: message };
286
286
  };
287
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
287
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
288
+ background: true
289
+ });
288
290
  api.tools.register({
289
291
  name: "api_compat_status",
290
292
  description: "Reports api-compatibility-gate state: severity, entry-point patterns, and per-session counters.",
@@ -80,7 +80,9 @@ function looksLikeUserText(value, minLength) {
80
80
  if (value.length < minLength) return false;
81
81
  if (/^\s*$/.test(value)) return false;
82
82
  if (/^[0-9\s\W_]+$/.test(value)) return false;
83
- if (/^(https?:|ftp:|www\.|\/|\.\/|@|#[0-9a-f]{3,8}$|\.?(jsx?|tsx?|vue|css|scss|json|png|svg|jpg)$)/i.test(value)) {
83
+ if (/^(https?:|ftp:|www\.|\/|\.\/|@|#[0-9a-f]{3,8}$|\.?(jsx?|tsx?|vue|css|scss|json|png|svg|jpg)$)/i.test(
84
+ value
85
+ )) {
84
86
  return false;
85
87
  }
86
88
  return true;
@@ -88,7 +90,9 @@ function looksLikeUserText(value, minLength) {
88
90
  function isExcludedContext(line, quoteIndex, excludeAttributes) {
89
91
  const before = line.slice(0, quoteIndex);
90
92
  for (const attr of excludeAttributes) {
91
- const re = new RegExp(`\\b${attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=\\s*(?:\\{\\s*)?["']?$`);
93
+ const re = new RegExp(
94
+ `\\b${attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=\\s*(?:\\{\\s*)?["']?$`
95
+ );
92
96
  if (re.test(before)) return true;
93
97
  }
94
98
  return false;
@@ -220,7 +224,9 @@ var plugin = {
220
224
  ${lines.join("\n")}${more}`;
221
225
  return { additionalContext: context };
222
226
  };
223
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
227
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
228
+ background: true
229
+ });
224
230
  api.tools.register({
225
231
  name: "i18n_extract",
226
232
  description: "Scan a UI source file (.tsx/.jsx/.vue) for hardcoded user-facing string literals and return suggested i18n keys.",
@@ -386,10 +386,7 @@ var plugin = {
386
386
  }
387
387
  const rawInput = input ?? {};
388
388
  const shouldPolish = input.polish === true || rawInput["use_llm"] === true || rawInput["useLlm"] === true || rawInput["ai"] === true || rawInput["use_ai"] === true;
389
- const block = await maybePolish(
390
- renderUnreleasedBlock(state.entries),
391
- shouldPolish
392
- );
389
+ const block = await maybePolish(renderUnreleasedBlock(state.entries), shouldPolish);
393
390
  let existing = null;
394
391
  try {
395
392
  existing = readFileSync(cfg.filePath, "utf-8");
@@ -241,7 +241,9 @@ var plugin = {
241
241
  \u{1F4CA} code-metrics: ${relativePath(resolved)} \u2014 ${metrics.lines} lines (${metrics.codeLines} code, ${metrics.commentLines} comments, ${metrics.blankLines} blank), ${metrics.functionCount} function(s), complexity ${metrics.complexity}.`
242
242
  };
243
243
  };
244
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
244
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
245
+ background: true
246
+ });
245
247
  api.tools.register({
246
248
  name: "measure_code_metrics",
247
249
  description: "Measure lines, comments, blank lines, function count, and cyclomatic-complexity-like score for a source file or directory.",
@@ -41,7 +41,9 @@ function readConfig(raw) {
41
41
  const rawMax = r["maxFileBytes"] ?? r["max_file_bytes"] ?? r["maxBytes"] ?? r["max_bytes"];
42
42
  return {
43
43
  enabled: r["enabled"] !== false,
44
- extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map((e) => e.trim().startsWith(".") ? e.trim().toLowerCase() : `.${e.trim().toLowerCase()}`) : [...DEFAULT_EXTENSIONS],
44
+ extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map(
45
+ (e) => e.trim().startsWith(".") ? e.trim().toLowerCase() : `.${e.trim().toLowerCase()}`
46
+ ) : [...DEFAULT_EXTENSIONS],
45
47
  maxFileBytes: typeof rawMax === "number" && rawMax >= 1024 ? rawMax : DEFAULTS.maxFileBytes
46
48
  };
47
49
  }
@@ -335,7 +337,9 @@ var plugin = {
335
337
  \u2026 and ${problems.length - 10} more` : "") + "\nFix these before moving on \u2014 downstream tools will fail on this file."
336
338
  };
337
339
  };
338
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
340
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
341
+ background: true
342
+ });
339
343
  api.tools.register({
340
344
  name: "config_validator_status",
341
345
  description: "Reports config-validator state: watched extensions and counters (files checked, problems found).",
@@ -58,7 +58,10 @@ async function persistPins(filePath) {
58
58
  if (!filePath) return true;
59
59
  try {
60
60
  await ensureDir(dirname(filePath));
61
- await atomicWrite(filePath, JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2));
61
+ await atomicWrite(
62
+ filePath,
63
+ JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2)
64
+ );
62
65
  return true;
63
66
  } catch {
64
67
  state.persistErrors += 1;
@@ -191,7 +191,9 @@ var plugin = {
191
191
  const rawCacheWrite = Number(u["cacheWrite"] ?? u["cache_creation_input_tokens"] ?? 0) || 0;
192
192
  const freshTokens = rawInput + rawCacheWrite;
193
193
  const promptTokens = freshTokens + cachedTokens;
194
- const completionTokens = Number(u["output"] ?? u["completion_tokens"] ?? u["outputTokens"] ?? u["completionTokens"] ?? 0) || 0;
194
+ const completionTokens = Number(
195
+ u["output"] ?? u["completion_tokens"] ?? u["outputTokens"] ?? u["completionTokens"] ?? 0
196
+ ) || 0;
195
197
  const totalTokens = promptTokens + completionTokens;
196
198
  const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
197
199
  const record = {
package/dist/cron.js CHANGED
@@ -144,8 +144,14 @@ var plugin = {
144
144
  type: "object",
145
145
  properties: {
146
146
  name: { type: "string", description: "Unique name for this cron job" },
147
- intervalMs: { type: "number", description: "Interval between runs in milliseconds (minimum 1000)" },
148
- action: { type: "string", description: "Action identifier or description of what to run" },
147
+ intervalMs: {
148
+ type: "number",
149
+ description: "Interval between runs in milliseconds (minimum 1000)"
150
+ },
151
+ action: {
152
+ type: "string",
153
+ description: "Action identifier or description of what to run"
154
+ },
149
155
  enabled: { type: "boolean", default: true }
150
156
  },
151
157
  required: ["name", "intervalMs", "action"]
package/dist/dep-guard.js CHANGED
@@ -48,7 +48,9 @@ function parseInstallCommands(command) {
48
48
  if (!cleaned) continue;
49
49
  let name = cleaned;
50
50
  let version = null;
51
- const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(cleaned);
51
+ const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
52
+ cleaned
53
+ );
52
54
  if (pipMatch?.[1]) {
53
55
  name = pipMatch[1];
54
56
  const op = pipMatch[2] ?? "";
@@ -71,7 +71,9 @@ function parseInstallCommands(command) {
71
71
  if (!cleaned) continue;
72
72
  let name = cleaned;
73
73
  let version = null;
74
- const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(cleaned);
74
+ const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
75
+ cleaned
76
+ );
75
77
  if (pipMatch?.[1]) {
76
78
  name = pipMatch[1];
77
79
  const op = pipMatch[2] ?? "";
@@ -199,8 +199,12 @@ var plugin = {
199
199
  return;
200
200
  }
201
201
  const oldStr = String(inp["old_string"] ?? inp["TargetContent"] ?? inp["oldContent"] ?? "");
202
- const newStr = String(inp["new_string"] ?? inp["ReplacementContent"] ?? inp["newContent"] ?? "");
203
- const contentStr = String(inp["content"] ?? inp["CodeContent"] ?? inp["code"] ?? inp["text"] ?? inp["contents"] ?? inp["body"] ?? "");
202
+ const newStr = String(
203
+ inp["new_string"] ?? inp["ReplacementContent"] ?? inp["newContent"] ?? ""
204
+ );
205
+ const contentStr = String(
206
+ inp["content"] ?? inp["CodeContent"] ?? inp["code"] ?? inp["text"] ?? inp["contents"] ?? inp["body"] ?? ""
207
+ );
204
208
  const toolInputForHash = oldStr || newStr ? `${oldStr}:::${newStr}` : contentStr;
205
209
  const now = Date.now();
206
210
  const memo = pathMemo.get(filePath);
@@ -255,7 +259,9 @@ var plugin = {
255
259
  additionalContext: header + summary
256
260
  };
257
261
  };
258
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
262
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
263
+ background: true
264
+ });
259
265
  api.tools.register({
260
266
  name: "diff_summary_status",
261
267
  description: "Reports diff-summary state: mode, maxLines, and per-session invocation/injected/fallback counters.",
@@ -172,7 +172,9 @@ var plugin = {
172
172
  }
173
173
  }
174
174
  if (!content || state.changedFiles.length === 0) return;
175
- const missing = state.changedFiles.filter((changedPath) => !isReferenced(changedPath, content));
175
+ const missing = state.changedFiles.filter(
176
+ (changedPath) => !isReferenced(changedPath, content)
177
+ );
176
178
  if (missing.length === 0) return;
177
179
  state.warningsIssued += 1;
178
180
  const missingList = missing.map((p) => ` - ${p}`).join("\n");
@@ -183,7 +185,9 @@ Consider mentioning these changes in the documentation.`;
183
185
  return { additionalContext: message };
184
186
  }
185
187
  };
186
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
188
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
189
+ background: true
190
+ });
187
191
  api.tools.register({
188
192
  name: "doc_sync_status",
189
193
  description: "Reports doc-sync-guard state: tracked changed files, doc-write count, and warning count.",
@@ -230,7 +230,9 @@ var plugin = {
230
230
  Make sure flag behavior is intentional and consider updating flag inventory/docs.`
231
231
  };
232
232
  };
233
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
233
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
234
+ background: true
235
+ });
234
236
  api.tools.register({
235
237
  name: "scan_feature_flags",
236
238
  description: "Scan source files for feature-flag-like expressions (isFeatureEnabled, featureFlags.*, useFeatureFlag, flags.*, plus custom patterns).",
@@ -303,7 +303,9 @@ var plugin = {
303
303
  state.cleanCount += 1;
304
304
  return;
305
305
  };
306
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
306
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
307
+ background: true
308
+ });
307
309
  state.patternUnregister = api.onPattern(
308
310
  "import-organizer:done",
309
311
  (_eventName, payload) => {
@@ -355,7 +355,9 @@ ${result.stderr.trim()}`
355
355
  }
356
356
  return;
357
357
  };
358
- state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
358
+ state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
359
+ background: true
360
+ });
359
361
  api.tools.register({
360
362
  name: "import_organizer_status",
361
363
  description: "Reports import-organizer state: linter availability, config, and per-session organized/clean/error counters.",