@wrongstack/plugins 0.281.1 → 0.282.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 (78) hide show
  1. package/README.md +29 -3
  2. package/dist/accessibility-auditor.d.ts +40 -0
  3. package/dist/accessibility-auditor.js +411 -0
  4. package/dist/agent-handoff.d.ts +37 -0
  5. package/dist/agent-handoff.js +298 -0
  6. package/dist/api-compatibility-gate.d.ts +38 -0
  7. package/dist/api-compatibility-gate.js +357 -0
  8. package/dist/auto-i18n-extractor.d.ts +36 -0
  9. package/dist/auto-i18n-extractor.js +335 -0
  10. package/dist/checkpoint.js +18 -0
  11. package/dist/code-metrics.d.ts +31 -0
  12. package/dist/code-metrics.js +338 -0
  13. package/dist/commit-validator.js +67 -12
  14. package/dist/cost-tracker.js +58 -16
  15. package/dist/dead-code-detector.d.ts +34 -0
  16. package/dist/dead-code-detector.js +354 -0
  17. package/dist/dep-guard.js +47 -6
  18. package/dist/dependency-vulnerability-gate.d.ts +35 -0
  19. package/dist/dependency-vulnerability-gate.js +308 -0
  20. package/dist/diff-summary.js +97 -10
  21. package/dist/doc-sync-guard.d.ts +33 -0
  22. package/dist/doc-sync-guard.js +223 -0
  23. package/dist/duplicate-code-detector.d.ts +33 -0
  24. package/dist/duplicate-code-detector.js +384 -0
  25. package/dist/feature-flag-tracker.d.ts +38 -0
  26. package/dist/feature-flag-tracker.js +316 -0
  27. package/dist/file-watcher.js +85 -36
  28. package/dist/format-on-save.js +76 -10
  29. package/dist/import-organizer.js +73 -14
  30. package/dist/index.d.ts +27 -0
  31. package/dist/index.js +14067 -5054
  32. package/dist/interface-contract-guard.d.ts +37 -0
  33. package/dist/interface-contract-guard.js +302 -0
  34. package/dist/knowledge-graph.d.ts +45 -0
  35. package/dist/knowledge-graph.js +325 -0
  36. package/dist/license-audit-gate.d.ts +34 -0
  37. package/dist/license-audit-gate.js +260 -0
  38. package/dist/llm-cache.js +5 -0
  39. package/dist/loop-breaker.d.ts +0 -38
  40. package/dist/loop-breaker.js +209 -8
  41. package/dist/migration-planner.d.ts +30 -0
  42. package/dist/migration-planner.js +349 -0
  43. package/dist/model-router.js +5 -0
  44. package/dist/performance-regression-gate.d.ts +33 -0
  45. package/dist/performance-regression-gate.js +315 -0
  46. package/dist/plugin-stack-observer.d.ts +35 -0
  47. package/dist/plugin-stack-observer.js +125 -0
  48. package/dist/pr-drafter.d.ts +35 -0
  49. package/dist/pr-drafter.js +334 -0
  50. package/dist/prompt-firewall.js +5 -0
  51. package/dist/refactor-suggester.d.ts +38 -0
  52. package/dist/refactor-suggester.js +382 -0
  53. package/dist/release-notes-generator.d.ts +27 -0
  54. package/dist/release-notes-generator.js +209 -0
  55. package/dist/schema-evolution-guard.d.ts +42 -0
  56. package/dist/schema-evolution-guard.js +319 -0
  57. package/dist/security-hotspot-scanner.d.ts +30 -0
  58. package/dist/security-hotspot-scanner.js +402 -0
  59. package/dist/semantic-search-indexer.d.ts +38 -0
  60. package/dist/semantic-search-indexer.js +436 -0
  61. package/dist/shell-check.js +38 -3
  62. package/dist/smart-rename.d.ts +26 -0
  63. package/dist/smart-rename.js +170 -0
  64. package/dist/spec-linker.js +273 -133
  65. package/dist/test-coverage-gate.d.ts +37 -0
  66. package/dist/test-coverage-gate.js +263 -0
  67. package/dist/test-flake-detector.d.ts +27 -0
  68. package/dist/test-flake-detector.js +274 -0
  69. package/dist/test-generator.d.ts +32 -0
  70. package/dist/test-generator.js +243 -0
  71. package/dist/test-runner-gate.js +154 -22
  72. package/dist/todo-listener.d.ts +2 -2
  73. package/dist/todo-listener.js +5 -5
  74. package/dist/token-throttle.js +5 -0
  75. package/dist/type-gate.d.ts +37 -0
  76. package/dist/type-gate.js +311 -0
  77. package/package.json +112 -4
  78. package/LICENSE +0 -21
@@ -9,83 +9,95 @@ import '@wrongstack/core/utils';
9
9
 
10
10
  // src/spec-linker/index.ts
11
11
  var plugin = {
12
- name: "auto-doc"};
13
- var auto_doc_default = plugin;
12
+ name: "agent-handoff"};
13
+ var agent_handoff_default = plugin;
14
14
  var plugin2 = {
15
- name: "auto-escalate"};
16
- var auto_escalate_default = plugin2;
15
+ name: "auto-doc"};
16
+ var auto_doc_default = plugin2;
17
17
  var plugin3 = {
18
- name: "branch-guard"};
19
- var branch_guard_default = plugin3;
18
+ name: "auto-escalate"};
19
+ var auto_escalate_default = plugin3;
20
20
  var plugin4 = {
21
- name: "changelog-writer"};
22
- var changelog_writer_default = plugin4;
21
+ name: "branch-guard"};
22
+ var branch_guard_default = plugin4;
23
23
  var plugin5 = {
24
- name: "checkpoint"};
25
- var checkpoint_default = plugin5;
24
+ name: "changelog-writer"};
25
+ var changelog_writer_default = plugin5;
26
26
  var plugin6 = {
27
- name: "commit-validator"};
28
- var commit_validator_default = plugin6;
27
+ name: "checkpoint"};
28
+ var checkpoint_default = plugin6;
29
29
  var plugin7 = {
30
- name: "config-validator"};
31
- var config_validator_default = plugin7;
30
+ name: "commit-validator"};
31
+ var commit_validator_default = plugin7;
32
32
  var plugin8 = {
33
- name: "context-pins"};
34
- var context_pins_default = plugin8;
33
+ name: "config-validator"};
34
+ var config_validator_default = plugin8;
35
35
  var plugin9 = {
36
+ name: "context-pins"};
37
+ var context_pins_default = plugin9;
38
+ var plugin10 = {
36
39
  name: "cost-tracker"};
37
- var cost_tracker_default = plugin9;
40
+ var cost_tracker_default = plugin10;
38
41
  ({
39
42
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
40
43
  });
41
- var plugin10 = {
42
- name: "cron"};
43
- var cron_default = plugin10;
44
44
  var plugin11 = {
45
- name: "dep-guard"};
46
- var dep_guard_default = plugin11;
45
+ name: "cron"};
46
+ var cron_default = plugin11;
47
47
  var plugin12 = {
48
- name: "diff-summary"};
49
- var diff_summary_default = plugin12;
48
+ name: "dep-guard"};
49
+ var dep_guard_default = plugin12;
50
50
  var plugin13 = {
51
- name: "error-lens"};
52
- var error_lens_default = plugin13;
51
+ name: "diff-summary"};
52
+ var diff_summary_default = plugin13;
53
53
  var plugin14 = {
54
- name: "file-watcher"};
55
- var file_watcher_default = plugin14;
54
+ name: "error-lens"};
55
+ var error_lens_default = plugin14;
56
56
  var plugin15 = {
57
- name: "format-on-save"};
58
- var format_on_save_default = plugin15;
57
+ name: "file-watcher"};
58
+ var file_watcher_default = plugin15;
59
59
  var plugin16 = {
60
- name: "git-autocommit"};
61
- var git_autocommit_default = plugin16;
60
+ name: "format-on-save"};
61
+ var format_on_save_default = plugin16;
62
62
  var plugin17 = {
63
- name: "import-organizer"};
64
- var import_organizer_default = plugin17;
63
+ name: "git-autocommit"};
64
+ var git_autocommit_default = plugin17;
65
65
  var plugin18 = {
66
- name: "injection-shield"};
67
- var injection_shield_default = plugin18;
66
+ name: "import-organizer"};
67
+ var import_organizer_default = plugin18;
68
68
  var plugin19 = {
69
- name: "lint-gate"};
70
- var lint_gate_default = plugin19;
69
+ name: "injection-shield"};
70
+ var injection_shield_default = plugin19;
71
71
  var plugin20 = {
72
- name: "llm-cache"};
73
- var llm_cache_default = plugin20;
72
+ name: "knowledge-graph"};
73
+ var knowledge_graph_default = plugin20;
74
74
  var plugin21 = {
75
- name: "loop-breaker"};
76
- var loop_breaker_default = plugin21;
75
+ name: "lint-gate"};
76
+ var lint_gate_default = plugin21;
77
77
  var plugin22 = {
78
- name: "model-router"};
79
- var model_router_default = plugin22;
78
+ name: "llm-cache"};
79
+ var llm_cache_default = plugin22;
80
80
  var plugin23 = {
81
- name: "notify-hub"};
82
- var notify_hub_default = plugin23;
81
+ name: "loop-breaker"};
82
+ var loop_breaker_default = plugin23;
83
83
  var plugin24 = {
84
- name: "path-guard"};
85
- var path_guard_default = plugin24;
84
+ name: "model-router"};
85
+ var model_router_default = plugin24;
86
86
  var plugin25 = {
87
+ name: "notify-hub"};
88
+ var notify_hub_default = plugin25;
89
+ var plugin26 = {
90
+ name: "path-guard"};
91
+ var path_guard_default = plugin26;
92
+ var PLUGIN = {
93
+ name: "plugin-stack-observer"};
94
+ var plugin_stack_observer_default = PLUGIN;
95
+ var plugin27 = {
96
+ name: "pr-drafter"};
97
+ var pr_drafter_default = plugin27;
98
+ var plugin28 = {
87
99
  name: "prompt-firewall"};
88
- var prompt_firewall_default = plugin25;
100
+ var prompt_firewall_default = plugin28;
89
101
 
90
102
  // src/secret-scanner/index.ts
91
103
  var BASE_PATTERNS = [
@@ -144,39 +156,141 @@ function buildCombinedRegex(patterns) {
144
156
  "g"
145
157
  );
146
158
  }
147
- var plugin26 = {
159
+ var plugin29 = {
148
160
  name: "secret-scanner"};
149
- var secret_scanner_default = plugin26;
150
- var plugin27 = {
161
+ var secret_scanner_default = plugin29;
162
+ var plugin30 = {
151
163
  name: "semver-bump"};
152
- var semver_bump_default = plugin27;
153
- var plugin28 = {
164
+ var semver_bump_default = plugin30;
165
+ var plugin31 = {
154
166
  name: "session-recap"};
155
- var session_recap_default = plugin28;
156
- var plugin29 = {
167
+ var session_recap_default = plugin31;
168
+ var plugin32 = {
157
169
  name: "shell-check"};
158
- var shell_check_default = plugin29;
159
- var plugin30 = {
170
+ var shell_check_default = plugin32;
171
+ var plugin33 = {
160
172
  name: "template-engine"};
161
- var template_engine_default = plugin30;
162
- var plugin31 = {
173
+ var template_engine_default = plugin33;
174
+ var plugin34 = {
175
+ name: "test-coverage-gate"};
176
+ var test_coverage_gate_default = plugin34;
177
+ var plugin35 = {
163
178
  name: "test-runner-gate"};
164
- var test_runner_gate_default = plugin31;
165
- var plugin32 = {
179
+ var test_runner_gate_default = plugin35;
180
+ var plugin36 = {
181
+ name: "type-gate"};
182
+ var type_gate_default = plugin36;
183
+ var plugin37 = {
166
184
  name: "todo-listener"};
167
- var todo_listener_default = plugin32;
168
- var plugin33 = {
185
+ var todo_listener_default = plugin37;
186
+ var plugin38 = {
169
187
  name: "todo-tracker"};
170
- var todo_tracker_default = plugin33;
171
- var plugin34 = {
188
+ var todo_tracker_default = plugin38;
189
+ var plugin39 = {
172
190
  name: "token-budget"};
173
- var token_budget_default = plugin34;
174
- var plugin35 = {
191
+ var token_budget_default = plugin39;
192
+ var plugin40 = {
175
193
  name: "token-throttle"};
176
- var token_throttle_default = plugin35;
194
+ var token_throttle_default = plugin40;
195
+ var plugin41 = {
196
+ name: "accessibility-auditor"};
197
+ var accessibility_auditor_default = plugin41;
198
+ var plugin42 = {
199
+ name: "api-compatibility-gate"};
200
+ var api_compatibility_gate_default = plugin42;
201
+ var plugin43 = {
202
+ name: "auto-i18n-extractor"};
203
+ var auto_i18n_extractor_default = plugin43;
204
+ var plugin44 = {
205
+ name: "code-metrics"};
206
+ var code_metrics_default = plugin44;
207
+ var plugin45 = {
208
+ name: "dead-code-detector"};
209
+ var dead_code_detector_default = plugin45;
210
+ var plugin46 = {
211
+ name: "dependency-vulnerability-gate"};
212
+ var dependency_vulnerability_gate_default = plugin46;
213
+ var plugin47 = {
214
+ name: "doc-sync-guard"};
215
+ var doc_sync_guard_default = plugin47;
216
+ var plugin48 = {
217
+ name: "duplicate-code-detector"};
218
+ var duplicate_code_detector_default = plugin48;
219
+ var plugin49 = {
220
+ name: "feature-flag-tracker"};
221
+ var feature_flag_tracker_default = plugin49;
222
+ var plugin50 = {
223
+ name: "interface-contract-guard"};
224
+ var interface_contract_guard_default = plugin50;
225
+ var plugin51 = {
226
+ name: "license-audit-gate"};
227
+ var license_audit_gate_default = plugin51;
228
+ var plugin52 = {
229
+ name: "migration-planner"};
230
+ var migration_planner_default = plugin52;
231
+ var plugin53 = {
232
+ name: "performance-regression-gate"};
233
+ var performance_regression_gate_default = plugin53;
234
+ var plugin54 = {
235
+ name: "refactor-suggester"};
236
+ var refactor_suggester_default = plugin54;
237
+ var plugin55 = {
238
+ name: "release-notes-generator"};
239
+ var release_notes_generator_default = plugin55;
240
+ var plugin56 = {
241
+ name: "schema-evolution-guard"};
242
+ var schema_evolution_guard_default = plugin56;
243
+ var plugin57 = {
244
+ name: "security-hotspot-scanner"};
245
+ var security_hotspot_scanner_default = plugin57;
246
+ var DEFAULTS47 = {
247
+ includeExtensions: [
248
+ ".ts",
249
+ ".tsx",
250
+ ".js",
251
+ ".jsx",
252
+ ".mjs",
253
+ ".cjs",
254
+ ".py",
255
+ ".java",
256
+ ".go",
257
+ ".rs",
258
+ ".rb",
259
+ ".php",
260
+ ".cpp",
261
+ ".c",
262
+ ".h",
263
+ ".cs",
264
+ ".swift",
265
+ ".kt",
266
+ ".scala",
267
+ ".sh",
268
+ ".md",
269
+ ".json",
270
+ ".yaml",
271
+ ".yml",
272
+ ".css",
273
+ ".scss",
274
+ ".html"
275
+ ],
276
+ excludePatterns: ["node_modules", "\\.git", "\\.wrongstack", "\\.temp_files", "coverage", "dist"]};
277
+ var plugin58 = {
278
+ name: "semantic-search-indexer",
279
+ defaultConfig: { includeExtensions: [...DEFAULTS47.includeExtensions], excludePatterns: [...DEFAULTS47.excludePatterns] }};
280
+ var semantic_search_indexer_default = plugin58;
281
+ var plugin59 = {
282
+ name: "smart-rename"};
283
+ var smart_rename_default = plugin59;
284
+ var plugin60 = {
285
+ name: "test-flake-detector"};
286
+ var test_flake_detector_default = plugin60;
287
+ var plugin61 = {
288
+ name: "test-generator"};
289
+ var test_generator_default = plugin61;
177
290
 
178
291
  // src/catalog.ts
179
292
  var ENTRIES = [
293
+ { name: agent_handoff_default.name, path: "./src/agent-handoff" },
180
294
  { name: auto_doc_default.name, path: "./src/auto-doc" },
181
295
  { name: git_autocommit_default.name, path: "./src/git-autocommit" },
182
296
  { name: shell_check_default.name, path: "./src/shell-check" },
@@ -212,7 +326,33 @@ var ENTRIES = [
212
326
  { name: model_router_default.name, path: "./src/model-router" },
213
327
  { name: prompt_firewall_default.name, path: "./src/prompt-firewall" },
214
328
  { name: auto_escalate_default.name, path: "./src/auto-escalate" },
215
- { name: token_throttle_default.name, path: "./src/token-throttle" }
329
+ { name: token_throttle_default.name, path: "./src/token-throttle" },
330
+ { name: plugin_stack_observer_default.name, path: "./src/plugin-stack-observer" },
331
+ { name: knowledge_graph_default.name, path: "./src/knowledge-graph" },
332
+ { name: pr_drafter_default.name, path: "./src/pr-drafter" },
333
+ { name: test_coverage_gate_default.name, path: "./src/test-coverage-gate" },
334
+ { name: type_gate_default.name, path: "./src/type-gate" },
335
+ { name: accessibility_auditor_default.name, path: "./src/accessibility-auditor" },
336
+ { name: api_compatibility_gate_default.name, path: "./src/api-compatibility-gate" },
337
+ { name: auto_i18n_extractor_default.name, path: "./src/auto-i18n-extractor" },
338
+ { name: code_metrics_default.name, path: "./src/code-metrics" },
339
+ { name: dead_code_detector_default.name, path: "./src/dead-code-detector" },
340
+ { name: dependency_vulnerability_gate_default.name, path: "./src/dependency-vulnerability-gate" },
341
+ { name: doc_sync_guard_default.name, path: "./src/doc-sync-guard" },
342
+ { name: duplicate_code_detector_default.name, path: "./src/duplicate-code-detector" },
343
+ { name: feature_flag_tracker_default.name, path: "./src/feature-flag-tracker" },
344
+ { name: interface_contract_guard_default.name, path: "./src/interface-contract-guard" },
345
+ { name: license_audit_gate_default.name, path: "./src/license-audit-gate" },
346
+ { name: migration_planner_default.name, path: "./src/migration-planner" },
347
+ { name: performance_regression_gate_default.name, path: "./src/performance-regression-gate" },
348
+ { name: refactor_suggester_default.name, path: "./src/refactor-suggester" },
349
+ { name: release_notes_generator_default.name, path: "./src/release-notes-generator" },
350
+ { name: schema_evolution_guard_default.name, path: "./src/schema-evolution-guard" },
351
+ { name: security_hotspot_scanner_default.name, path: "./src/security-hotspot-scanner" },
352
+ { name: semantic_search_indexer_default.name, path: "./src/semantic-search-indexer" },
353
+ { name: smart_rename_default.name, path: "./src/smart-rename" },
354
+ { name: test_flake_detector_default.name, path: "./src/test-flake-detector" },
355
+ { name: test_generator_default.name, path: "./src/test-generator" }
216
356
  ];
217
357
  function assertValidCatalog(entries) {
218
358
  for (const e of entries) {
@@ -243,7 +383,7 @@ var PLUGIN_CATALOG_ENTRIES = Object.freeze(
243
383
  var PLUGIN_NAMES = PLUGIN_CATALOG_ENTRIES.map((e) => e.name);
244
384
 
245
385
  // src/spec-linker/index.ts
246
- var state32 = {
386
+ var state59 = {
247
387
  postInvocations: 0,
248
388
  preInvocations: 0,
249
389
  unlinkedCount: 0,
@@ -254,19 +394,19 @@ var state32 = {
254
394
  postHookUnregister: null,
255
395
  preHookUnregister: null
256
396
  };
257
- var DEFAULTS25 = {
397
+ var DEFAULTS51 = {
258
398
  enabled: true,
259
399
  fileGlobs: ["**/*.md", "**/*.mdx"],
260
400
  maxReferences: 8,
261
401
  autoFix: false
262
402
  };
263
- function readConfig27(raw) {
264
- if (!raw || typeof raw !== "object") return { ...DEFAULTS25 };
403
+ function readConfig54(raw) {
404
+ if (!raw || typeof raw !== "object") return { ...DEFAULTS51 };
265
405
  const r = raw;
266
406
  return {
267
407
  enabled: r["enabled"] !== false,
268
- fileGlobs: Array.isArray(r["fileGlobs"]) ? r["fileGlobs"].filter((g) => typeof g === "string") : DEFAULTS25.fileGlobs,
269
- maxReferences: typeof r["maxReferences"] === "number" && r["maxReferences"] > 0 ? r["maxReferences"] : DEFAULTS25.maxReferences,
408
+ fileGlobs: Array.isArray(r["fileGlobs"]) ? r["fileGlobs"].filter((g) => typeof g === "string") : DEFAULTS51.fileGlobs,
409
+ maxReferences: typeof r["maxReferences"] === "number" && r["maxReferences"] > 0 ? r["maxReferences"] : DEFAULTS51.maxReferences,
270
410
  autoFix: r["autoFix"] === true
271
411
  };
272
412
  }
@@ -363,20 +503,20 @@ function wrapLineReferences(line) {
363
503
  spans.sort((a, b) => a.start - b.start);
364
504
  for (const span of spans) {
365
505
  out += line.slice(cursor, span.start);
366
- const path2 = PLUGIN_CATALOG.get(span.name.toLowerCase()) ?? `./src/${span.name.toLowerCase()}`;
367
- out += `[${span.name}](${path2})`;
506
+ const path = PLUGIN_CATALOG.get(span.name.toLowerCase()) ?? `./src/${span.name.toLowerCase()}`;
507
+ out += `[${span.name}](${path})`;
368
508
  cursor = span.end;
369
509
  }
370
510
  out += line.slice(cursor);
371
511
  return out;
372
512
  }
373
- var plugin36 = {
513
+ var plugin62 = {
374
514
  name: "spec-linker",
375
515
  version: "0.2.0",
376
516
  description: "Markdown link auditor for plugin references. PostToolUse surfaces unlinked references; PreToolUse on `write` (autoFix) wraps them in markdown links via modifiedInput.",
377
517
  apiVersion: "^0.1.10",
378
518
  capabilities: { tools: true, hooks: true },
379
- defaultConfig: { ...DEFAULTS25 },
519
+ defaultConfig: { ...DEFAULTS51 },
380
520
  configSchema: {
381
521
  type: "object",
382
522
  properties: {
@@ -384,7 +524,7 @@ var plugin36 = {
384
524
  fileGlobs: {
385
525
  type: "array",
386
526
  items: { type: "string" },
387
- default: DEFAULTS25.fileGlobs,
527
+ default: DEFAULTS51.fileGlobs,
388
528
  description: "Glob patterns to match (markdown by default)."
389
529
  },
390
530
  maxReferences: {
@@ -402,16 +542,16 @@ var plugin36 = {
402
542
  }
403
543
  },
404
544
  setup(api) {
405
- state32.postInvocations = 0;
406
- state32.preInvocations = 0;
407
- state32.unlinkedCount = 0;
408
- state32.cleanCount = 0;
409
- state32.skippedNonMd = 0;
410
- state32.readErrorCount = 0;
411
- state32.autoFixApplied = 0;
412
- state32.postHookUnregister = null;
413
- state32.preHookUnregister = null;
414
- const cfg = readConfig27(api.config.extensions?.["spec-linker"]);
545
+ state59.postInvocations = 0;
546
+ state59.preInvocations = 0;
547
+ state59.unlinkedCount = 0;
548
+ state59.cleanCount = 0;
549
+ state59.skippedNonMd = 0;
550
+ state59.readErrorCount = 0;
551
+ state59.autoFixApplied = 0;
552
+ state59.postHookUnregister = null;
553
+ state59.preHookUnregister = null;
554
+ const cfg = readConfig54(api.config.extensions?.["spec-linker"]);
415
555
  const postHook = async (input) => {
416
556
  if (!cfg.enabled) return;
417
557
  if (input.toolResult?.isError) return;
@@ -421,10 +561,10 @@ var plugin36 = {
421
561
  const filePath = inp.path;
422
562
  if (!filePath || typeof filePath !== "string") return;
423
563
  if (!fileMatchesGlobs(filePath, cfg.fileGlobs)) {
424
- state32.skippedNonMd += 1;
564
+ state59.skippedNonMd += 1;
425
565
  return;
426
566
  }
427
- state32.postInvocations += 1;
567
+ state59.postInvocations += 1;
428
568
  if (!existsSync(filePath)) return;
429
569
  let content;
430
570
  try {
@@ -432,15 +572,15 @@ var plugin36 = {
432
572
  if (!stat.isFile()) return;
433
573
  content = await fsp.readFile(filePath, "utf-8");
434
574
  } catch {
435
- state32.readErrorCount += 1;
575
+ state59.readErrorCount += 1;
436
576
  return;
437
577
  }
438
578
  const unlinked = findUnlinkedReferences(content.split("\n"), [...PLUGIN_NAMES]);
439
579
  if (unlinked.length === 0) {
440
- state32.cleanCount += 1;
580
+ state59.cleanCount += 1;
441
581
  return;
442
582
  }
443
- state32.unlinkedCount += 1;
583
+ state59.unlinkedCount += 1;
444
584
  const limited = unlinked.slice(0, cfg.maxReferences);
445
585
  const overflow = unlinked.length - limited.length;
446
586
  const lines = limited.map(
@@ -454,7 +594,7 @@ var plugin36 = {
454
594
  ${lines}${overflowNote}`
455
595
  };
456
596
  };
457
- state32.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook);
597
+ state59.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook);
458
598
  if (cfg.autoFix) {
459
599
  const preHook = async (input) => {
460
600
  if (!cfg.enabled) return;
@@ -464,10 +604,10 @@ ${lines}${overflowNote}`
464
604
  if (!filePath || typeof filePath !== "string") return;
465
605
  if (!fileMatchesGlobs(filePath, cfg.fileGlobs)) return;
466
606
  if (typeof inp.content !== "string" || inp.content.length === 0) return;
467
- state32.preInvocations += 1;
607
+ state59.preInvocations += 1;
468
608
  const fixed = wrapUnlinkedReferences(inp.content);
469
609
  if (fixed === inp.content) return;
470
- state32.autoFixApplied += 1;
610
+ state59.autoFixApplied += 1;
471
611
  return {
472
612
  decision: "allow",
473
613
  modifiedInput: { ...inp, content: fixed, path: filePath },
@@ -475,7 +615,7 @@ ${lines}${overflowNote}`
475
615
  \u{1F517} spec-linker (autoFix): wrapped unlinked plugin reference(s) in '${filePath}'.`
476
616
  };
477
617
  };
478
- state32.preHookUnregister = api.registerHook("PreToolUse", "write", preHook);
618
+ state59.preHookUnregister = api.registerHook("PreToolUse", "write", preHook);
479
619
  }
480
620
  api.tools.register({
481
621
  name: "spec_linker_status",
@@ -492,13 +632,13 @@ ${lines}${overflowNote}`
492
632
  maxReferences: cfg.maxReferences,
493
633
  autoFix: cfg.autoFix,
494
634
  counters: {
495
- postInvocations: state32.postInvocations,
496
- preInvocations: state32.preInvocations,
497
- unlinked: state32.unlinkedCount,
498
- clean: state32.cleanCount,
499
- skippedNonMd: state32.skippedNonMd,
500
- readErrors: state32.readErrorCount,
501
- autoFixApplied: state32.autoFixApplied
635
+ postInvocations: state59.postInvocations,
636
+ preInvocations: state59.preInvocations,
637
+ unlinked: state59.unlinkedCount,
638
+ clean: state59.cleanCount,
639
+ skippedNonMd: state59.skippedNonMd,
640
+ readErrors: state59.readErrorCount,
641
+ autoFixApplied: state59.autoFixApplied
502
642
  },
503
643
  catalogSize: PLUGIN_NAMES.length
504
644
  };
@@ -513,7 +653,7 @@ ${lines}${overflowNote}`
513
653
  });
514
654
  },
515
655
  teardown(api) {
516
- for (const off of [state32.postHookUnregister, state32.preHookUnregister]) {
656
+ for (const off of [state59.postHookUnregister, state59.preHookUnregister]) {
517
657
  if (off) {
518
658
  try {
519
659
  off();
@@ -521,42 +661,42 @@ ${lines}${overflowNote}`
521
661
  }
522
662
  }
523
663
  }
524
- state32.postHookUnregister = null;
525
- state32.preHookUnregister = null;
664
+ state59.postHookUnregister = null;
665
+ state59.preHookUnregister = null;
526
666
  const final = {
527
- postInvocations: state32.postInvocations,
528
- preInvocations: state32.preInvocations,
529
- unlinked: state32.unlinkedCount,
530
- clean: state32.cleanCount,
531
- skippedNonMd: state32.skippedNonMd,
532
- readErrors: state32.readErrorCount,
533
- autoFixApplied: state32.autoFixApplied
667
+ postInvocations: state59.postInvocations,
668
+ preInvocations: state59.preInvocations,
669
+ unlinked: state59.unlinkedCount,
670
+ clean: state59.cleanCount,
671
+ skippedNonMd: state59.skippedNonMd,
672
+ readErrors: state59.readErrorCount,
673
+ autoFixApplied: state59.autoFixApplied
534
674
  };
535
- state32.postInvocations = 0;
536
- state32.preInvocations = 0;
537
- state32.unlinkedCount = 0;
538
- state32.cleanCount = 0;
539
- state32.skippedNonMd = 0;
540
- state32.readErrorCount = 0;
541
- state32.autoFixApplied = 0;
675
+ state59.postInvocations = 0;
676
+ state59.preInvocations = 0;
677
+ state59.unlinkedCount = 0;
678
+ state59.cleanCount = 0;
679
+ state59.skippedNonMd = 0;
680
+ state59.readErrorCount = 0;
681
+ state59.autoFixApplied = 0;
542
682
  api.log.info("spec-linker: teardown complete", { final });
543
683
  },
544
684
  async health() {
545
685
  return {
546
686
  ok: true,
547
- message: `spec-linker: post=${state32.postInvocations} pre=${state32.preInvocations}, unlinked=${state32.unlinkedCount}, autoFix=${state32.autoFixApplied}, clean=${state32.cleanCount}, non-md=${state32.skippedNonMd}`,
687
+ message: `spec-linker: post=${state59.postInvocations} pre=${state59.preInvocations}, unlinked=${state59.unlinkedCount}, autoFix=${state59.autoFixApplied}, clean=${state59.cleanCount}, non-md=${state59.skippedNonMd}`,
548
688
  counters: {
549
- postInvocations: state32.postInvocations,
550
- preInvocations: state32.preInvocations,
551
- unlinked: state32.unlinkedCount,
552
- clean: state32.cleanCount,
553
- skippedNonMd: state32.skippedNonMd,
554
- readErrors: state32.readErrorCount,
555
- autoFixApplied: state32.autoFixApplied
689
+ postInvocations: state59.postInvocations,
690
+ preInvocations: state59.preInvocations,
691
+ unlinked: state59.unlinkedCount,
692
+ clean: state59.cleanCount,
693
+ skippedNonMd: state59.skippedNonMd,
694
+ readErrors: state59.readErrorCount,
695
+ autoFixApplied: state59.autoFixApplied
556
696
  }
557
697
  };
558
698
  }
559
699
  };
560
- var spec_linker_default = plugin36;
700
+ var spec_linker_default = plugin62;
561
701
 
562
702
  export { spec_linker_default as default };
@@ -0,0 +1,37 @@
1
+ import { Plugin } from '@wrongstack/core';
2
+
3
+ /**
4
+ * test-coverage-gate plugin — PostToolUse hook that watches for test
5
+ * coverage regressions after source-file edits.
6
+ *
7
+ * The plugin reads a coverage summary (e.g. `coverage/coverage-summary.json`
8
+ * produced by c8/vitest/istanbul) after each `write`/`edit` to a source
9
+ * file, compares it to the previous snapshot, and warns/block when the
10
+ * overall coverage drops below a configured threshold or when a single
11
+ * edited file loses coverage.
12
+ *
13
+ * Tools registered:
14
+ * - coverage_gate_status : Show config + per-session counters + last diff.
15
+ *
16
+ * Hooks registered:
17
+ * - PostToolUse with matcher `write|edit`.
18
+ *
19
+ * Config (`config.extensions['test-coverage-gate']`):
20
+ *
21
+ * ```jsonc
22
+ * {
23
+ * "enabled": true,
24
+ * "coveragePath": "coverage/coverage-summary.json",
25
+ * "threshold": 80.0, // minimum overall percent
26
+ * "mode": "warn", // "warn" | "block"
27
+ * "deltaThreshold": 1.0, // warn/block when coverage drops by >= this percent
28
+ * "runOnChange": [".ts", ".tsx", ".js", ".jsx"]
29
+ * }
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+
35
+ declare const plugin: Plugin;
36
+
37
+ export { plugin as default };