@wrongstack/plugins 0.295.0 → 0.296.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 (110) hide show
  1. package/dist/accessibility-auditor/index.d.ts.map +1 -1
  2. package/dist/accessibility-auditor.js +31 -3
  3. package/dist/agent-handoff/index.d.ts.map +1 -1
  4. package/dist/agent-handoff.js +30 -1
  5. package/dist/auto-doc/index.d.ts.map +1 -1
  6. package/dist/auto-doc.js +3 -1
  7. package/dist/auto-i18n-extractor.js +5 -0
  8. package/dist/branch-guard/index.d.ts.map +1 -1
  9. package/dist/branch-guard.js +116 -3
  10. package/dist/changelog-writer/index.d.ts.map +1 -1
  11. package/dist/changelog-writer.js +137 -3
  12. package/dist/checkpoint/index.d.ts +2 -0
  13. package/dist/checkpoint/index.d.ts.map +1 -1
  14. package/dist/checkpoint.js +34 -8
  15. package/dist/code-metrics.js +5 -0
  16. package/dist/commit-validator/index.d.ts.map +1 -1
  17. package/dist/commit-validator.js +35 -8
  18. package/dist/context-pins/index.d.ts.map +1 -1
  19. package/dist/context-pins.js +6 -5
  20. package/dist/cost-tracker/index.d.ts.map +1 -1
  21. package/dist/cost-tracker.js +101 -1
  22. package/dist/cron/index.d.ts.map +1 -1
  23. package/dist/cron.js +1 -0
  24. package/dist/dead-code-detector/index.d.ts.map +1 -1
  25. package/dist/dead-code-detector.js +9 -1
  26. package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
  27. package/dist/dependency-vulnerability-gate.js +43 -8
  28. package/dist/diff-summary/index.d.ts.map +1 -1
  29. package/dist/diff-summary.js +112 -2
  30. package/dist/doc-sync-guard.js +17 -1
  31. package/dist/duplicate-code-detector/index.d.ts.map +1 -1
  32. package/dist/duplicate-code-detector.js +102 -2
  33. package/dist/feature-flag-tracker/index.d.ts.map +1 -1
  34. package/dist/feature-flag-tracker.js +30 -4
  35. package/dist/file-watcher/index.d.ts.map +1 -1
  36. package/dist/file-watcher.js +6 -7
  37. package/dist/format-on-save/index.d.ts +2 -0
  38. package/dist/format-on-save/index.d.ts.map +1 -1
  39. package/dist/format-on-save.js +288 -59
  40. package/dist/git-autocommit/index.d.ts +12 -0
  41. package/dist/git-autocommit/index.d.ts.map +1 -1
  42. package/dist/git-autocommit.js +58 -4
  43. package/dist/import-organizer/index.d.ts.map +1 -1
  44. package/dist/import-organizer.js +152 -21
  45. package/dist/index.js +1413 -590
  46. package/dist/injection-shield/index.d.ts +16 -0
  47. package/dist/injection-shield/index.d.ts.map +1 -1
  48. package/dist/injection-shield.js +12 -4
  49. package/dist/interface-contract-guard/index.d.ts.map +1 -1
  50. package/dist/interface-contract-guard.js +60 -26
  51. package/dist/knowledge-graph/index.d.ts.map +1 -1
  52. package/dist/knowledge-graph.js +7 -6
  53. package/dist/lint-gate/index.d.ts.map +1 -1
  54. package/dist/lint-gate.js +115 -2
  55. package/dist/loop-breaker/index.d.ts.map +1 -1
  56. package/dist/loop-breaker.js +15 -5
  57. package/dist/migration-planner.js +15 -1
  58. package/dist/notify-hub/index.d.ts.map +1 -1
  59. package/dist/notify-hub.js +41 -4
  60. package/dist/pr-drafter/index.d.ts.map +1 -1
  61. package/dist/pr-drafter.js +20 -1
  62. package/dist/prompt-firewall/index.d.ts.map +1 -1
  63. package/dist/prompt-firewall.js +140 -11
  64. package/dist/refactor-suggester/index.d.ts.map +1 -1
  65. package/dist/refactor-suggester.js +119 -4
  66. package/dist/runtime/bounded-map.d.ts +86 -0
  67. package/dist/runtime/bounded-map.d.ts.map +1 -0
  68. package/dist/runtime/credential-patterns.d.ts +42 -0
  69. package/dist/runtime/credential-patterns.d.ts.map +1 -0
  70. package/dist/runtime/handles.d.ts +46 -0
  71. package/dist/runtime/handles.d.ts.map +1 -0
  72. package/dist/runtime/index.d.ts +4 -0
  73. package/dist/runtime/index.d.ts.map +1 -1
  74. package/dist/runtime/local-bin.d.ts +120 -0
  75. package/dist/runtime/local-bin.d.ts.map +1 -0
  76. package/dist/runtime/safe-json.d.ts +25 -0
  77. package/dist/runtime/safe-json.d.ts.map +1 -0
  78. package/dist/runtime.js +309 -22
  79. package/dist/schema-evolution-guard.js +5 -0
  80. package/dist/secret-scanner/index.d.ts.map +1 -1
  81. package/dist/secret-scanner.js +194 -50
  82. package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
  83. package/dist/security-hotspot-scanner.js +132 -1
  84. package/dist/semantic-search-indexer/index.d.ts.map +1 -1
  85. package/dist/semantic-search-indexer.js +7 -1
  86. package/dist/semver-bump/index.d.ts.map +1 -1
  87. package/dist/semver-bump.js +21 -2
  88. package/dist/session-recap/index.d.ts.map +1 -1
  89. package/dist/session-recap.js +18 -1
  90. package/dist/smart-rename/index.d.ts +2 -0
  91. package/dist/smart-rename/index.d.ts.map +1 -1
  92. package/dist/smart-rename.js +16 -2
  93. package/dist/spec-linker/index.d.ts.map +1 -1
  94. package/dist/spec-linker.js +19 -2
  95. package/dist/template-engine/index.d.ts.map +1 -1
  96. package/dist/template-engine.js +45 -3
  97. package/dist/test-coverage-gate.js +17 -1
  98. package/dist/test-runner-gate/index.d.ts.map +1 -1
  99. package/dist/test-runner-gate.js +142 -9
  100. package/dist/todo-listener/index.d.ts.map +1 -1
  101. package/dist/todo-listener.js +42 -2
  102. package/dist/todo-tracker/index.d.ts.map +1 -1
  103. package/dist/todo-tracker.js +3 -4
  104. package/dist/token-budget/index.d.ts.map +1 -1
  105. package/dist/token-budget.js +31 -19
  106. package/dist/token-throttle/index.d.ts.map +1 -1
  107. package/dist/token-throttle.js +17 -2
  108. package/dist/type-gate/index.d.ts.map +1 -1
  109. package/dist/type-gate.js +108 -17
  110. package/package.json +3 -3
@@ -1,3 +1,20 @@
1
+ // src/runtime/local-bin.ts
2
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
3
+
4
+ // src/runtime/handles.ts
5
+ function releaseHandle(off) {
6
+ if (off) {
7
+ try {
8
+ off();
9
+ } catch {
10
+ }
11
+ }
12
+ return null;
13
+ }
14
+
15
+ // src/runtime/index.ts
16
+ var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
17
+
1
18
  // src/commit-validator/index.ts
2
19
  var API_VERSION = "^0.1.10";
3
20
  var state = {
@@ -116,14 +133,24 @@ function parseCommitMessage(message, cfg) {
116
133
  errors
117
134
  };
118
135
  }
136
+ var GIT_MESSAGE_FLAG_RE = new RegExp(
137
+ [
138
+ // -m "…" | -m '…' | -m=… ; --message "…" | --message='…' | --message=…
139
+ String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)"([^"]*)"`,
140
+ String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)'([^']*)'`,
141
+ // Bare value: stops at whitespace or a shell separator.
142
+ String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)([^\s;&|"']+)`
143
+ ].join("|"),
144
+ "g"
145
+ );
119
146
  function extractMessageFromBash(command) {
120
- const flags = [];
121
- const doubleQuoted = command.matchAll(/-m\s+"([^"]*)"/g);
122
- const singleQuoted = command.matchAll(/-m\s+'([^']*)'/g);
123
- for (const m of doubleQuoted) flags.push(m[1] ?? "");
124
- for (const m of singleQuoted) flags.push(m[1] ?? "");
125
- if (flags.length === 0) return null;
126
- return flags.join("\n");
147
+ const parts = [];
148
+ for (const m of command.matchAll(GIT_MESSAGE_FLAG_RE)) {
149
+ const value = m[1] ?? m[2] ?? m[3];
150
+ if (value !== void 0) parts.push(value);
151
+ }
152
+ if (parts.length === 0) return null;
153
+ return parts.join("\n");
127
154
  }
128
155
  var plugin = {
129
156
  name: "commit-validator",
@@ -182,7 +209,7 @@ var plugin = {
182
209
  state.invalidCount = 0;
183
210
  state.suggestFixCount = 0;
184
211
  state.suggestFixErrors = 0;
185
- state.hookUnregister = null;
212
+ state.hookUnregister = releaseHandle(state.hookUnregister);
186
213
  state.lastValidation = null;
187
214
  const cfg = readConfig(api.config.extensions?.["commit-validator"]);
188
215
  const hook = async (input) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context-pins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAMrD,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AA8GD,QAAA,MAAM,MAAM,EAAE,MA8Mb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context-pins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAOrD,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAoHD,QAAA,MAAM,MAAM,EAAE,MA8Mb,CAAC;eAEa,MAAM"}
@@ -1,6 +1,7 @@
1
1
  // src/context-pins/index.ts
2
2
  import * as fs from "node:fs";
3
3
  import { dirname, isAbsolute, relative, resolve } from "node:path";
4
+ import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
4
5
  var state = {
5
6
  pins: [],
6
7
  nextId: 1,
@@ -47,11 +48,11 @@ function loadPins(filePath) {
47
48
  return { pins: [], nextId: 1 };
48
49
  }
49
50
  }
50
- function persistPins(filePath) {
51
+ async function persistPins(filePath) {
51
52
  if (!filePath) return true;
52
53
  try {
53
- fs.mkdirSync(dirname(filePath), { recursive: true });
54
- fs.writeFileSync(filePath, JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2));
54
+ await ensureDir(dirname(filePath));
55
+ await atomicWrite(filePath, JSON.stringify({ pins: state.pins, nextId: state.nextId }, null, 2));
55
56
  return true;
56
57
  } catch {
57
58
  state.persistErrors += 1;
@@ -149,7 +150,7 @@ var plugin = {
149
150
  state.pins.push(pin);
150
151
  state.adds += 1;
151
152
  api.metrics.counter("adds");
152
- const persisted = persistPins(cfg.filePath);
153
+ const persisted = await persistPins(cfg.filePath);
153
154
  return { ok: true, pin, persisted, totalPins: state.pins.length };
154
155
  }
155
156
  });
@@ -175,7 +176,7 @@ var plugin = {
175
176
  if (removed === 0) return { ok: false, error: `no pin matches "${key}"` };
176
177
  state.removals += removed;
177
178
  api.metrics.counter("removals", removed);
178
- const persisted = persistPins(cfg.filePath);
179
+ const persisted = await persistPins(cfg.filePath);
179
180
  return { ok: true, removed, persisted, totalPins: state.pins.length };
180
181
  }
181
182
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cost-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAKrD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB;AAoLD,QAAA,MAAM,MAAM,EAAE,MAoab,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cost-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAMrD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB;AAuLD,QAAA,MAAM,MAAM,EAAE,MAoab,CAAC;eAEa,MAAM"}
@@ -1,3 +1,103 @@
1
+ // src/runtime/local-bin.ts
2
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
3
+
4
+ // src/runtime/bounded-map.ts
5
+ var BoundedMap = class {
6
+ map = /* @__PURE__ */ new Map();
7
+ max;
8
+ ttlMs;
9
+ now;
10
+ /** Entries dropped to stay under `max`. Surfaced by plugin health(). */
11
+ evictions = 0;
12
+ constructor(options) {
13
+ const normalizedMax = Math.floor(options.max);
14
+ this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
15
+ this.ttlMs = options.ttlMs;
16
+ this.now = options.now ?? Date.now;
17
+ }
18
+ expired(entry) {
19
+ return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
20
+ }
21
+ get(key) {
22
+ const entry = this.map.get(key);
23
+ if (entry === void 0) return void 0;
24
+ if (this.expired(entry)) {
25
+ this.map.delete(key);
26
+ return void 0;
27
+ }
28
+ this.map.delete(key);
29
+ this.map.set(key, entry);
30
+ return entry.value;
31
+ }
32
+ /**
33
+ * Read without promoting the key to most-recently-used. Use for
34
+ * diagnostics that must not perturb the eviction order.
35
+ */
36
+ peek(key) {
37
+ const entry = this.map.get(key);
38
+ if (entry === void 0 || this.expired(entry)) return void 0;
39
+ return entry.value;
40
+ }
41
+ has(key) {
42
+ const entry = this.map.get(key);
43
+ if (entry === void 0) return false;
44
+ if (this.expired(entry)) {
45
+ this.map.delete(key);
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+ set(key, value) {
51
+ this.map.delete(key);
52
+ this.map.set(key, { value, storedAt: this.now() });
53
+ while (this.map.size > this.max) {
54
+ const coldest = this.map.keys().next().value;
55
+ if (coldest === void 0) break;
56
+ this.map.delete(coldest);
57
+ this.evictions += 1;
58
+ }
59
+ return this;
60
+ }
61
+ delete(key) {
62
+ return this.map.delete(key);
63
+ }
64
+ clear() {
65
+ this.map.clear();
66
+ this.evictions = 0;
67
+ }
68
+ get size() {
69
+ return this.map.size;
70
+ }
71
+ /** How many entries have been dropped to respect `max`, since the last clear. */
72
+ get evictionCount() {
73
+ return this.evictions;
74
+ }
75
+ /** Drop every expired entry. Cheap enough to call from a status tool. */
76
+ prune() {
77
+ if (this.ttlMs === void 0) return 0;
78
+ let removed = 0;
79
+ for (const [key, entry] of this.map) {
80
+ if (this.expired(entry)) {
81
+ this.map.delete(key);
82
+ removed += 1;
83
+ }
84
+ }
85
+ return removed;
86
+ }
87
+ /** Live (non-expired) entries, coldest first. */
88
+ *entries() {
89
+ for (const [key, entry] of this.map) {
90
+ if (!this.expired(entry)) yield [key, entry.value];
91
+ }
92
+ }
93
+ [Symbol.iterator]() {
94
+ return this.entries();
95
+ }
96
+ };
97
+
98
+ // src/runtime/index.ts
99
+ var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
100
+
1
101
  // src/cost-tracker/index.ts
2
102
  import { expectDefined } from "@wrongstack/core/utils";
3
103
  var API_VERSION = "^0.1.10";
@@ -28,7 +128,7 @@ function readCostTrackerConfig(raw) {
28
128
  mailboxDigestTo: typeof digestTo === "string" && digestTo.length > 0 ? digestTo : "cost-tracker"
29
129
  };
30
130
  }
31
- var modelKeyCache = /* @__PURE__ */ new Map();
131
+ var modelKeyCache = new BoundedMap({ max: 256 });
32
132
  function estimateCost(model, promptTokens, completionTokens) {
33
133
  let key = modelKeyCache.get(model);
34
134
  if (!key) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cron/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+FrD,QAAA,MAAM,MAAM,EAAE,MAqRb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cron/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+FrD,QAAA,MAAM,MAAM,EAAE,MA2Rb,CAAC;eAEa,MAAM"}
package/dist/cron.js CHANGED
@@ -82,6 +82,7 @@ var plugin = {
82
82
  api.metrics.histogram("cron_job_interval_ms", job.intervalMs, { job: name });
83
83
  scheduleNextRun(name);
84
84
  }, delay);
85
+ timer.unref?.();
85
86
  state.timers.set(name, timer);
86
87
  }
87
88
  function cancelJob(name) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dead-code-detector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAiSrD,QAAA,MAAM,MAAM,EAAE,MAkOb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dead-code-detector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAySrD,QAAA,MAAM,MAAM,EAAE,MAkOb,CAAC;eAEa,MAAM"}
@@ -4,6 +4,11 @@ import { extname as extname2, join, relative as relative2, resolve as resolve2 }
4
4
 
5
5
  // src/runtime/index.ts
6
6
  import { basename, extname, isAbsolute, relative, resolve } from "node:path";
7
+
8
+ // src/runtime/local-bin.ts
9
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
10
+
11
+ // src/runtime/index.ts
7
12
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
8
13
  function hasLeadingDash(arg) {
9
14
  return arg.length > 0 && arg.startsWith("-");
@@ -128,7 +133,10 @@ function findUnusedSymbols(files) {
128
133
  for (const file of files) {
129
134
  const fileExports = extractExports(file.content, file.path);
130
135
  for (const exp of fileExports) {
131
- const pattern = new RegExp(`\\b${escapeRegex(exp.identifier)}\\b`, "g");
136
+ const pattern = new RegExp(
137
+ `(?<![A-Za-z0-9_$])${escapeRegex(exp.identifier)}(?![A-Za-z0-9_$])`,
138
+ "g"
139
+ );
132
140
  let usedElsewhere = false;
133
141
  for (const other of files) {
134
142
  if (other.path === file.path) continue;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dependency-vulnerability-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAqPrD,QAAA,MAAM,MAAM,EAAE,MAwMb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dependency-vulnerability-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA2RrD,QAAA,MAAM,MAAM,EAAE,MAwMb,CAAC;eAEa,MAAM"}
@@ -1,6 +1,24 @@
1
1
  // src/dependency-vulnerability-gate/index.ts
2
2
  import { execFile } from "node:child_process";
3
3
  import { access } from "node:fs/promises";
4
+
5
+ // src/runtime/local-bin.ts
6
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
7
+ function resolveExecInvocation(command, args = []) {
8
+ const resolved = resolveWin32Command(command);
9
+ const normalizedResolved = resolved.toLowerCase();
10
+ const needsShell = process.platform === "win32" && (normalizedResolved.endsWith(".cmd") || normalizedResolved.endsWith(".bat"));
11
+ if (needsShell) {
12
+ const shim = buildWin32CmdShimInvocation(resolved, args);
13
+ return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
14
+ }
15
+ return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
16
+ }
17
+
18
+ // src/runtime/index.ts
19
+ var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
20
+
21
+ // src/dependency-vulnerability-gate/index.ts
4
22
  var API_VERSION = "^0.1.10";
5
23
  var state = {
6
24
  invocations: 0,
@@ -112,27 +130,44 @@ function isInstallCommand(input) {
112
130
  const command = typeof ti["command"] === "string" ? ti["command"] : "";
113
131
  return INSTALL_RE.test(command);
114
132
  }
133
+ var LOCKFILE_MANAGERS = [
134
+ { file: "pnpm-lock.yaml", manager: "pnpm" },
135
+ { file: "bun.lockb", manager: "bun" },
136
+ { file: "bun.lock", manager: "bun" },
137
+ { file: "yarn.lock", manager: "yarn" },
138
+ { file: "package-lock.json", manager: "npm" }
139
+ ];
115
140
  async function detectManager() {
116
- try {
117
- await access("pnpm-lock.yaml");
118
- return "pnpm";
119
- } catch {
120
- return "npm";
141
+ for (const { file, manager } of LOCKFILE_MANAGERS) {
142
+ try {
143
+ await access(file);
144
+ return manager;
145
+ } catch {
146
+ }
121
147
  }
148
+ return "npm";
122
149
  }
123
150
  async function runAudit(cfg) {
124
151
  const manager = await detectManager();
125
152
  const start = Date.now();
153
+ let invocation;
154
+ try {
155
+ invocation = resolveExecInvocation(manager, ["audit", "--json"]);
156
+ } catch {
157
+ return null;
158
+ }
126
159
  const stdout = await new Promise((resolve) => {
127
160
  execFile(
128
- manager,
129
- ["audit", "--json"],
161
+ invocation.cmd,
162
+ invocation.args,
130
163
  {
131
164
  encoding: "utf8",
132
165
  timeout: cfg.timeoutMs,
133
166
  cwd: process.cwd(),
134
167
  windowsHide: true,
135
- maxBuffer: 10 * 1024 * 1024
168
+ maxBuffer: 10 * 1024 * 1024,
169
+ shell: false,
170
+ ...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
136
171
  },
137
172
  (error, output) => {
138
173
  if (error && error.killed) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/diff-summary/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA2PrD,QAAA,MAAM,MAAM,EAAE,MA4Pb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/diff-summary/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+PrD,QAAA,MAAM,MAAM,EAAE,MA4Pb,CAAC;eAEa,MAAM"}
@@ -3,6 +3,116 @@ import { execFile } from "node:child_process";
3
3
 
4
4
  // src/runtime/index.ts
5
5
  import { basename, extname, isAbsolute, relative, resolve } from "node:path";
6
+
7
+ // src/runtime/local-bin.ts
8
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
9
+
10
+ // src/runtime/bounded-map.ts
11
+ var BoundedMap = class {
12
+ map = /* @__PURE__ */ new Map();
13
+ max;
14
+ ttlMs;
15
+ now;
16
+ /** Entries dropped to stay under `max`. Surfaced by plugin health(). */
17
+ evictions = 0;
18
+ constructor(options) {
19
+ const normalizedMax = Math.floor(options.max);
20
+ this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
21
+ this.ttlMs = options.ttlMs;
22
+ this.now = options.now ?? Date.now;
23
+ }
24
+ expired(entry) {
25
+ return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
26
+ }
27
+ get(key) {
28
+ const entry = this.map.get(key);
29
+ if (entry === void 0) return void 0;
30
+ if (this.expired(entry)) {
31
+ this.map.delete(key);
32
+ return void 0;
33
+ }
34
+ this.map.delete(key);
35
+ this.map.set(key, entry);
36
+ return entry.value;
37
+ }
38
+ /**
39
+ * Read without promoting the key to most-recently-used. Use for
40
+ * diagnostics that must not perturb the eviction order.
41
+ */
42
+ peek(key) {
43
+ const entry = this.map.get(key);
44
+ if (entry === void 0 || this.expired(entry)) return void 0;
45
+ return entry.value;
46
+ }
47
+ has(key) {
48
+ const entry = this.map.get(key);
49
+ if (entry === void 0) return false;
50
+ if (this.expired(entry)) {
51
+ this.map.delete(key);
52
+ return false;
53
+ }
54
+ return true;
55
+ }
56
+ set(key, value) {
57
+ this.map.delete(key);
58
+ this.map.set(key, { value, storedAt: this.now() });
59
+ while (this.map.size > this.max) {
60
+ const coldest = this.map.keys().next().value;
61
+ if (coldest === void 0) break;
62
+ this.map.delete(coldest);
63
+ this.evictions += 1;
64
+ }
65
+ return this;
66
+ }
67
+ delete(key) {
68
+ return this.map.delete(key);
69
+ }
70
+ clear() {
71
+ this.map.clear();
72
+ this.evictions = 0;
73
+ }
74
+ get size() {
75
+ return this.map.size;
76
+ }
77
+ /** How many entries have been dropped to respect `max`, since the last clear. */
78
+ get evictionCount() {
79
+ return this.evictions;
80
+ }
81
+ /** Drop every expired entry. Cheap enough to call from a status tool. */
82
+ prune() {
83
+ if (this.ttlMs === void 0) return 0;
84
+ let removed = 0;
85
+ for (const [key, entry] of this.map) {
86
+ if (this.expired(entry)) {
87
+ this.map.delete(key);
88
+ removed += 1;
89
+ }
90
+ }
91
+ return removed;
92
+ }
93
+ /** Live (non-expired) entries, coldest first. */
94
+ *entries() {
95
+ for (const [key, entry] of this.map) {
96
+ if (!this.expired(entry)) yield [key, entry.value];
97
+ }
98
+ }
99
+ [Symbol.iterator]() {
100
+ return this.entries();
101
+ }
102
+ };
103
+
104
+ // src/runtime/handles.ts
105
+ function releaseHandle(off) {
106
+ if (off) {
107
+ try {
108
+ off();
109
+ } catch {
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+
115
+ // src/runtime/index.ts
6
116
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
7
117
  function hasLeadingDash(arg) {
8
118
  return arg.length > 0 && arg.startsWith("-");
@@ -64,7 +174,7 @@ function contentHash(s) {
64
174
  }
65
175
  return h >>> 0;
66
176
  }
67
- var pathMemo = /* @__PURE__ */ new Map();
177
+ var pathMemo = new BoundedMap({ max: 512 });
68
178
  function runGit(args, cwd) {
69
179
  return new Promise((resolveCommand) => {
70
180
  execFile(
@@ -179,7 +289,7 @@ var plugin = {
179
289
  state.fallbackCount = 0;
180
290
  state.throttledCount = 0;
181
291
  state.duplicateContentCount = 0;
182
- state.hookUnregister = null;
292
+ state.hookUnregister = releaseHandle(state.hookUnregister);
183
293
  state.lastSummary = null;
184
294
  pathMemo.clear();
185
295
  const cfg = readConfig(api.config.extensions?.["diff-summary"]);
@@ -3,6 +3,22 @@ import { basename as basename2, extname as extname2 } from "node:path";
3
3
 
4
4
  // src/runtime/index.ts
5
5
  import { basename, extname, isAbsolute, relative, resolve } from "node:path";
6
+
7
+ // src/runtime/local-bin.ts
8
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
9
+
10
+ // src/runtime/handles.ts
11
+ function releaseHandle(off) {
12
+ if (off) {
13
+ try {
14
+ off();
15
+ } catch {
16
+ }
17
+ }
18
+ return null;
19
+ }
20
+
21
+ // src/runtime/index.ts
6
22
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
7
23
  function hasLeadingDash(arg) {
8
24
  return arg.length > 0 && arg.startsWith("-");
@@ -138,7 +154,7 @@ var plugin = {
138
154
  state.sourceWrites = 0;
139
155
  state.docWrites = 0;
140
156
  state.warningsIssued = 0;
141
- state.hookUnregister = null;
157
+ state.hookUnregister = releaseHandle(state.hookUnregister);
142
158
  const cfg = readConfig(api.config.extensions?.["doc-sync-guard"]);
143
159
  const hook = (input) => {
144
160
  if (!cfg.enabled) return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/duplicate-code-detector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA8ErD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B,gFAAgF;IAChF,QAAQ;IACR,yFAAyF;IACzF,eAAe;IACf;;;OAGG;IACH,sBAAsB;IACtB,6FAA6F;IAC7F,YAAY;CACb,CAAC;AAyGF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAelD;AA4HD,QAAA,MAAM,MAAM,EAAE,MA4Wb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/duplicate-code-detector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA8FrD;;;GAGG;AACH,eAAO,MAAM,gBAAgB;IAC3B,gFAAgF;IAChF,QAAQ;IACR,yFAAyF;IACzF,eAAe;IACf;;;OAGG;IACH,sBAAsB;IACtB,6FAA6F;IAC7F,YAAY;CACb,CAAC;AAyGF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAelD;AA4HD,QAAA,MAAM,MAAM,EAAE,MA4Wb,CAAC;eAEa,MAAM"}
@@ -4,6 +4,105 @@ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2,
4
4
 
5
5
  // src/runtime/index.ts
6
6
  import { basename, extname, isAbsolute, relative, resolve } from "node:path";
7
+
8
+ // src/runtime/local-bin.ts
9
+ import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
10
+
11
+ // src/runtime/bounded-map.ts
12
+ var BoundedMap = class {
13
+ map = /* @__PURE__ */ new Map();
14
+ max;
15
+ ttlMs;
16
+ now;
17
+ /** Entries dropped to stay under `max`. Surfaced by plugin health(). */
18
+ evictions = 0;
19
+ constructor(options) {
20
+ const normalizedMax = Math.floor(options.max);
21
+ this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
22
+ this.ttlMs = options.ttlMs;
23
+ this.now = options.now ?? Date.now;
24
+ }
25
+ expired(entry) {
26
+ return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
27
+ }
28
+ get(key) {
29
+ const entry = this.map.get(key);
30
+ if (entry === void 0) return void 0;
31
+ if (this.expired(entry)) {
32
+ this.map.delete(key);
33
+ return void 0;
34
+ }
35
+ this.map.delete(key);
36
+ this.map.set(key, entry);
37
+ return entry.value;
38
+ }
39
+ /**
40
+ * Read without promoting the key to most-recently-used. Use for
41
+ * diagnostics that must not perturb the eviction order.
42
+ */
43
+ peek(key) {
44
+ const entry = this.map.get(key);
45
+ if (entry === void 0 || this.expired(entry)) return void 0;
46
+ return entry.value;
47
+ }
48
+ has(key) {
49
+ const entry = this.map.get(key);
50
+ if (entry === void 0) return false;
51
+ if (this.expired(entry)) {
52
+ this.map.delete(key);
53
+ return false;
54
+ }
55
+ return true;
56
+ }
57
+ set(key, value) {
58
+ this.map.delete(key);
59
+ this.map.set(key, { value, storedAt: this.now() });
60
+ while (this.map.size > this.max) {
61
+ const coldest = this.map.keys().next().value;
62
+ if (coldest === void 0) break;
63
+ this.map.delete(coldest);
64
+ this.evictions += 1;
65
+ }
66
+ return this;
67
+ }
68
+ delete(key) {
69
+ return this.map.delete(key);
70
+ }
71
+ clear() {
72
+ this.map.clear();
73
+ this.evictions = 0;
74
+ }
75
+ get size() {
76
+ return this.map.size;
77
+ }
78
+ /** How many entries have been dropped to respect `max`, since the last clear. */
79
+ get evictionCount() {
80
+ return this.evictions;
81
+ }
82
+ /** Drop every expired entry. Cheap enough to call from a status tool. */
83
+ prune() {
84
+ if (this.ttlMs === void 0) return 0;
85
+ let removed = 0;
86
+ for (const [key, entry] of this.map) {
87
+ if (this.expired(entry)) {
88
+ this.map.delete(key);
89
+ removed += 1;
90
+ }
91
+ }
92
+ return removed;
93
+ }
94
+ /** Live (non-expired) entries, coldest first. */
95
+ *entries() {
96
+ for (const [key, entry] of this.map) {
97
+ if (!this.expired(entry)) yield [key, entry.value];
98
+ }
99
+ }
100
+ [Symbol.iterator]() {
101
+ return this.entries();
102
+ }
103
+ };
104
+
105
+ // src/runtime/index.ts
7
106
  var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
8
107
  function hasLeadingDash(arg) {
9
108
  return arg.length > 0 && arg.startsWith("-");
@@ -63,6 +162,7 @@ function matchesExtension(p, exts) {
63
162
 
64
163
  // src/duplicate-code-detector/index.ts
65
164
  var API_VERSION = "^0.1.10";
165
+ var HOOK_WARNING_COOLDOWN_MS = 6e4;
66
166
  var state = {
67
167
  scanCount: 0,
68
168
  findingCount: 0,
@@ -70,7 +170,7 @@ var state = {
70
170
  warningCount: 0,
71
171
  errorCount: 0,
72
172
  hookUnregister: null,
73
- lastHookWarning: /* @__PURE__ */ new Map(),
173
+ lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS }),
74
174
  fileIndex: /* @__PURE__ */ new Map(),
75
175
  inFlightFingerprintReads: /* @__PURE__ */ new Map(),
76
176
  indexFingerprintCount: 0,
@@ -360,7 +460,7 @@ var plugin = {
360
460
  state.hookInvocationCount += 1;
361
461
  const now = Date.now();
362
462
  const lastWarning = state.lastHookWarning.get(changedFile);
363
- if (lastWarning !== void 0 && now - lastWarning < 6e4) return;
463
+ if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS) return;
364
464
  const changedFps = await readCachedFingerprints(changedFile, cfg.minLines);
365
465
  if (changedFps === null) {
366
466
  state.errorCount += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/feature-flag-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA6ID,QAAA,MAAM,MAAM,EAAE,MA+Mb,CAAC;eAEa,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/feature-flag-tracker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAmLD,QAAA,MAAM,MAAM,EAAE,MAmNb,CAAC;eAEa,MAAM"}