@wrongstack/plugins 0.295.0 → 0.295.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.
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +19 -2
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-i18n-extractor.js +5 -0
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +103 -1
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +2 -0
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +34 -8
- package/dist/code-metrics.js +5 -0
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +17 -7
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +101 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector.js +5 -0
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +43 -8
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +100 -1
- package/dist/doc-sync-guard.js +5 -0
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +102 -2
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +30 -4
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +2 -0
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +288 -59
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +140 -20
- package/dist/index.js +1265 -544
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +60 -26
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +103 -1
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +15 -5
- package/dist/migration-planner.js +3 -0
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +119 -4
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +291 -22
- package/dist/schema-evolution-guard.js +5 -0
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +175 -48
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +132 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +21 -2
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +30 -2
- package/dist/test-coverage-gate.js +5 -0
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +130 -8
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +30 -1
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +96 -16
- package/package.json +3 -3
package/dist/test-runner-gate.js
CHANGED
|
@@ -2,9 +2,109 @@
|
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { access } from "node:fs/promises";
|
|
4
4
|
import { basename as basename2, dirname, isAbsolute as isAbsolute2, join } from "node:path";
|
|
5
|
+
import { buildWin32CmdShimInvocation as buildWin32CmdShimInvocation2, resolveWin32Command as resolveWin32Command2 } from "@wrongstack/tools/win32";
|
|
5
6
|
|
|
6
7
|
// src/runtime/index.ts
|
|
7
8
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
9
|
+
|
|
10
|
+
// src/runtime/local-bin.ts
|
|
11
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
12
|
+
|
|
13
|
+
// src/runtime/bounded-map.ts
|
|
14
|
+
var BoundedMap = class {
|
|
15
|
+
map = /* @__PURE__ */ new Map();
|
|
16
|
+
max;
|
|
17
|
+
ttlMs;
|
|
18
|
+
now;
|
|
19
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
20
|
+
evictions = 0;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
const normalizedMax = Math.floor(options.max);
|
|
23
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
24
|
+
this.ttlMs = options.ttlMs;
|
|
25
|
+
this.now = options.now ?? Date.now;
|
|
26
|
+
}
|
|
27
|
+
expired(entry) {
|
|
28
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
29
|
+
}
|
|
30
|
+
get(key) {
|
|
31
|
+
const entry = this.map.get(key);
|
|
32
|
+
if (entry === void 0) return void 0;
|
|
33
|
+
if (this.expired(entry)) {
|
|
34
|
+
this.map.delete(key);
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
this.map.delete(key);
|
|
38
|
+
this.map.set(key, entry);
|
|
39
|
+
return entry.value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
43
|
+
* diagnostics that must not perturb the eviction order.
|
|
44
|
+
*/
|
|
45
|
+
peek(key) {
|
|
46
|
+
const entry = this.map.get(key);
|
|
47
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
48
|
+
return entry.value;
|
|
49
|
+
}
|
|
50
|
+
has(key) {
|
|
51
|
+
const entry = this.map.get(key);
|
|
52
|
+
if (entry === void 0) return false;
|
|
53
|
+
if (this.expired(entry)) {
|
|
54
|
+
this.map.delete(key);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
set(key, value) {
|
|
60
|
+
this.map.delete(key);
|
|
61
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
62
|
+
while (this.map.size > this.max) {
|
|
63
|
+
const coldest = this.map.keys().next().value;
|
|
64
|
+
if (coldest === void 0) break;
|
|
65
|
+
this.map.delete(coldest);
|
|
66
|
+
this.evictions += 1;
|
|
67
|
+
}
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
delete(key) {
|
|
71
|
+
return this.map.delete(key);
|
|
72
|
+
}
|
|
73
|
+
clear() {
|
|
74
|
+
this.map.clear();
|
|
75
|
+
this.evictions = 0;
|
|
76
|
+
}
|
|
77
|
+
get size() {
|
|
78
|
+
return this.map.size;
|
|
79
|
+
}
|
|
80
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
81
|
+
get evictionCount() {
|
|
82
|
+
return this.evictions;
|
|
83
|
+
}
|
|
84
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
85
|
+
prune() {
|
|
86
|
+
if (this.ttlMs === void 0) return 0;
|
|
87
|
+
let removed = 0;
|
|
88
|
+
for (const [key, entry] of this.map) {
|
|
89
|
+
if (this.expired(entry)) {
|
|
90
|
+
this.map.delete(key);
|
|
91
|
+
removed += 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return removed;
|
|
95
|
+
}
|
|
96
|
+
/** Live (non-expired) entries, coldest first. */
|
|
97
|
+
*entries() {
|
|
98
|
+
for (const [key, entry] of this.map) {
|
|
99
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
[Symbol.iterator]() {
|
|
103
|
+
return this.entries();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// src/runtime/index.ts
|
|
8
108
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
9
109
|
function hasLeadingDash(arg) {
|
|
10
110
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -22,6 +122,15 @@ function withinProject(p) {
|
|
|
22
122
|
}
|
|
23
123
|
|
|
24
124
|
// src/test-runner-gate/index.ts
|
|
125
|
+
function resolveExec(command, args) {
|
|
126
|
+
const resolved = resolveWin32Command2(command);
|
|
127
|
+
const needsShell = process.platform === "win32" && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
128
|
+
if (needsShell) {
|
|
129
|
+
const shim = buildWin32CmdShimInvocation2(resolved, args);
|
|
130
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
131
|
+
}
|
|
132
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
133
|
+
}
|
|
25
134
|
var API_VERSION = "^0.1.10";
|
|
26
135
|
var state = {
|
|
27
136
|
invocationCount: 0,
|
|
@@ -86,7 +195,7 @@ function pathContentHash(content) {
|
|
|
86
195
|
}
|
|
87
196
|
return h >>> 0;
|
|
88
197
|
}
|
|
89
|
-
var lastPassedHash =
|
|
198
|
+
var lastPassedHash = new BoundedMap({ max: 1024 });
|
|
90
199
|
var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
91
200
|
"npx",
|
|
92
201
|
"pnpm",
|
|
@@ -141,10 +250,13 @@ async function detectRunner(requested) {
|
|
|
141
250
|
if (!match) return null;
|
|
142
251
|
try {
|
|
143
252
|
await new Promise((resolve2, reject) => {
|
|
144
|
-
|
|
253
|
+
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
254
|
+
execFile(ex.cmd, ex.args, {
|
|
145
255
|
encoding: "utf-8",
|
|
146
256
|
timeout: 5e3,
|
|
147
|
-
cwd: process.cwd()
|
|
257
|
+
cwd: process.cwd(),
|
|
258
|
+
windowsHide: true,
|
|
259
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
148
260
|
}, (err) => err ? reject(err) : resolve2());
|
|
149
261
|
});
|
|
150
262
|
return match;
|
|
@@ -155,10 +267,13 @@ async function detectRunner(requested) {
|
|
|
155
267
|
for (const candidate of candidates) {
|
|
156
268
|
try {
|
|
157
269
|
await new Promise((resolve2, reject) => {
|
|
158
|
-
|
|
270
|
+
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
271
|
+
execFile(ex.cmd, ex.args, {
|
|
159
272
|
encoding: "utf-8",
|
|
160
273
|
timeout: 5e3,
|
|
161
|
-
cwd: process.cwd()
|
|
274
|
+
cwd: process.cwd(),
|
|
275
|
+
windowsHide: true,
|
|
276
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
162
277
|
}, (err) => err ? reject(err) : resolve2());
|
|
163
278
|
});
|
|
164
279
|
return candidate;
|
|
@@ -206,10 +321,17 @@ async function runTests(testFile, runner, customCommand, timeoutMs) {
|
|
|
206
321
|
try {
|
|
207
322
|
const { stdout: out } = await new Promise(
|
|
208
323
|
(resolve2, reject) => {
|
|
324
|
+
const ex = resolveExec(cmd, fullArgs);
|
|
209
325
|
execFile(
|
|
210
|
-
cmd,
|
|
211
|
-
|
|
212
|
-
{
|
|
326
|
+
ex.cmd,
|
|
327
|
+
ex.args,
|
|
328
|
+
{
|
|
329
|
+
encoding: "utf-8",
|
|
330
|
+
timeout: timeoutMs,
|
|
331
|
+
cwd: process.cwd(),
|
|
332
|
+
windowsHide: true,
|
|
333
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
334
|
+
},
|
|
213
335
|
(err, out2, stderr) => {
|
|
214
336
|
if (err) reject(Object.assign(err, { stdout: out2, stderr }));
|
|
215
337
|
else resolve2({ stdout: out2, stderr });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-listener/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-listener/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAoGrD,QAAA,MAAM,MAAM,EAAE,MAuNb,CAAC;eAEa,MAAM"}
|
package/dist/todo-listener.js
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
// src/runtime/local-bin.ts
|
|
2
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
3
|
+
|
|
4
|
+
// src/runtime/safe-json.ts
|
|
5
|
+
var UNSERIALIZABLE = "[unserializable]";
|
|
6
|
+
function safeJsonStringify(value, indent) {
|
|
7
|
+
try {
|
|
8
|
+
const stack = [];
|
|
9
|
+
const out = JSON.stringify(
|
|
10
|
+
value,
|
|
11
|
+
function replacer(_key, val) {
|
|
12
|
+
if (typeof val === "bigint") return `${val.toString()}n`;
|
|
13
|
+
if (val === null || typeof val !== "object") return val;
|
|
14
|
+
while (stack.length > 0 && stack[stack.length - 1] !== this) stack.pop();
|
|
15
|
+
if (stack.includes(val)) return "[circular]";
|
|
16
|
+
stack.push(val);
|
|
17
|
+
return val;
|
|
18
|
+
},
|
|
19
|
+
indent
|
|
20
|
+
);
|
|
21
|
+
return out ?? String(value);
|
|
22
|
+
} catch {
|
|
23
|
+
return UNSERIALIZABLE;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/runtime/index.ts
|
|
28
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
29
|
+
|
|
1
30
|
// src/todo-listener/index.ts
|
|
2
31
|
var state = {
|
|
3
32
|
invocationCount: 0,
|
|
@@ -112,7 +141,7 @@ var plugin = {
|
|
|
112
141
|
0,
|
|
113
142
|
200
|
|
114
143
|
);
|
|
115
|
-
const body =
|
|
144
|
+
const body = safeJsonStringify(payload, 2);
|
|
116
145
|
const sendInput = {
|
|
117
146
|
from: `plugin:todo-listener`,
|
|
118
147
|
to: "*",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-tracker/index.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/todo-tracker/index.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAuKrD,QAAA,MAAM,MAAM,EAAE,MAsZb,CAAC;eAEa,MAAM"}
|
package/dist/todo-tracker.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/todo-tracker/index.ts
|
|
2
2
|
import * as fsp from "node:fs/promises";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4
5
|
function deriveFilePath(api) {
|
|
5
6
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
6
7
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -30,10 +31,8 @@ async function loadFile(filePath) {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
async function saveFile(filePath, file) {
|
|
33
|
-
|
|
34
|
-
await
|
|
35
|
-
await fsp.writeFile(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", mode: 384 });
|
|
36
|
-
await fsp.rename(tmp, filePath);
|
|
34
|
+
await ensureDir(filePath.replace(/[/\\][^/\\]+$/, ""));
|
|
35
|
+
await atomicWrite(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
37
36
|
}
|
|
38
37
|
var state = {
|
|
39
38
|
filePath: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-throttle/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AA8ChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAE5E;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EAAE,EACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,MAAM,CAoBR;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-throttle/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AA8ChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAE5E;AAED,0CAA0C;AAC1C,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,UAAU,EAAE,EACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,MAAM,CAoBR;AAyED,QAAA,MAAM,MAAM,EAAE,MAqKb,CAAC;eAEa,MAAM"}
|
package/dist/token-throttle.js
CHANGED
|
@@ -60,7 +60,21 @@ function estimateRequestTokens(request, charsPerToken) {
|
|
|
60
60
|
walk(request["messages"]);
|
|
61
61
|
return Math.ceil(chars / charsPerToken);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
function sleep(ms, signal) {
|
|
64
|
+
if (signal?.aborted) return Promise.resolve();
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
signal?.removeEventListener("abort", onAbort);
|
|
68
|
+
resolve();
|
|
69
|
+
}, ms);
|
|
70
|
+
timer.unref?.();
|
|
71
|
+
function onAbort() {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
resolve();
|
|
74
|
+
}
|
|
75
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
64
78
|
var plugin = {
|
|
65
79
|
name: "token-throttle",
|
|
66
80
|
version: "0.1.0",
|
|
@@ -119,6 +133,7 @@ var plugin = {
|
|
|
119
133
|
name: "token-throttle",
|
|
120
134
|
owner: "token-throttle",
|
|
121
135
|
async wrapProviderRunner(_ctx, request, inner) {
|
|
136
|
+
const signal = _ctx?.signal;
|
|
122
137
|
const req = request ?? {};
|
|
123
138
|
state.invocations += 1;
|
|
124
139
|
const now = Date.now();
|
|
@@ -132,7 +147,7 @@ var plugin = {
|
|
|
132
147
|
api.metrics.counter("throttled");
|
|
133
148
|
api.metrics.histogram("delay_ms", delay);
|
|
134
149
|
api.log.info("token-throttle: delaying provider call", { delayMs: delay, projected });
|
|
135
|
-
await sleep(delay);
|
|
150
|
+
await sleep(delay, signal);
|
|
136
151
|
}
|
|
137
152
|
const response = await inner(_ctx, request);
|
|
138
153
|
const used = (response?.usage?.input ?? 0) + (response?.usage?.output ?? 0) || projected;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/type-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/type-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+NrD,QAAA,MAAM,MAAM,EAAE,MAkOb,CAAC;eAEa,MAAM"}
|
package/dist/type-gate.js
CHANGED
|
@@ -3,7 +3,69 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
|
|
4
4
|
// src/runtime/index.ts
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
6
|
-
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
6
|
+
import { basename, extname as extname2, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
import { delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
11
|
+
import { accessSync, constants, readFileSync } from "node:fs";
|
|
12
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
13
|
+
function resolveExecInvocation(command, args = []) {
|
|
14
|
+
const resolved = resolveWin32Command(command);
|
|
15
|
+
const normalizedResolved = resolved.toLowerCase();
|
|
16
|
+
const needsShell = process.platform === "win32" && (normalizedResolved.endsWith(".cmd") || normalizedResolved.endsWith(".bat"));
|
|
17
|
+
if (needsShell) {
|
|
18
|
+
const shim = buildWin32CmdShimInvocation(resolved, args);
|
|
19
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
20
|
+
}
|
|
21
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
22
|
+
}
|
|
23
|
+
function isInside(parent, candidate) {
|
|
24
|
+
const rel = relative(parent, candidate);
|
|
25
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
|
|
26
|
+
}
|
|
27
|
+
var binCache = /* @__PURE__ */ new Map();
|
|
28
|
+
var BIN_CACHE_MAX = 64;
|
|
29
|
+
var NEGATIVE_BIN_CACHE_TTL_MS = 5e3;
|
|
30
|
+
function cachePut(key, value) {
|
|
31
|
+
while (binCache.size >= BIN_CACHE_MAX) {
|
|
32
|
+
const oldest = binCache.keys().next().value;
|
|
33
|
+
if (oldest === void 0) break;
|
|
34
|
+
binCache.delete(oldest);
|
|
35
|
+
}
|
|
36
|
+
binCache.set(key, { value, cachedAt: Date.now() });
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function resolveNodeBin(packageName, binName, cwd, extraArgs = []) {
|
|
40
|
+
const key = `${packageName}|${binName}|${cwd}`;
|
|
41
|
+
const cached = binCache.get(key);
|
|
42
|
+
if (cached !== void 0) {
|
|
43
|
+
if (cached.value !== null || Date.now() - cached.cachedAt < NEGATIVE_BIN_CACHE_TTL_MS) {
|
|
44
|
+
return cached.value === null ? null : { ...cached.value, args: [cached.value.entry, ...extraArgs] };
|
|
45
|
+
}
|
|
46
|
+
binCache.delete(key);
|
|
47
|
+
}
|
|
48
|
+
let resolved = null;
|
|
49
|
+
try {
|
|
50
|
+
const requireFromProject = createRequire(resolve(cwd, "package.json"));
|
|
51
|
+
const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
|
|
52
|
+
const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
53
|
+
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[binName] ?? Object.values(packageJson.bin ?? {})[0];
|
|
54
|
+
if (relativeBin && !isAbsolute(relativeBin)) {
|
|
55
|
+
const packageDir = dirname(packagePath);
|
|
56
|
+
const entry = resolve(packageDir, relativeBin);
|
|
57
|
+
if (isInside(packageDir, entry)) {
|
|
58
|
+
resolved = { cmd: process.execPath, args: [entry], entry };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
resolved = null;
|
|
63
|
+
}
|
|
64
|
+
cachePut(key, resolved);
|
|
65
|
+
return resolved === null ? null : { ...resolved, args: [resolved.entry, ...extraArgs] };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/runtime/index.ts
|
|
7
69
|
var META_CHARS = /["'`;&|<>\r\n]/;
|
|
8
70
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
9
71
|
function hasLeadingDash(arg) {
|
|
@@ -17,9 +79,9 @@ function safeSplit(command) {
|
|
|
17
79
|
function withinProjectPath(projectRoot, candidate) {
|
|
18
80
|
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
19
81
|
if (hasLeadingDash(candidate)) return false;
|
|
20
|
-
const resolved =
|
|
21
|
-
const rel =
|
|
22
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
82
|
+
const resolved = isAbsolute2(candidate) ? resolve2(candidate) : resolve2(projectRoot, candidate);
|
|
83
|
+
const rel = relative2(projectRoot, resolved);
|
|
84
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
|
|
23
85
|
}
|
|
24
86
|
function everyFlagAllowed(allowed, args) {
|
|
25
87
|
for (const arg of args) {
|
|
@@ -31,14 +93,14 @@ function everyFlagAllowed(allowed, args) {
|
|
|
31
93
|
}
|
|
32
94
|
function sanitizeRunnerPath(value, options = {}) {
|
|
33
95
|
if (!value || hasLeadingDash(value)) return null;
|
|
34
|
-
const projectRoot =
|
|
96
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
35
97
|
if (!withinProjectPath(projectRoot, value)) return null;
|
|
36
|
-
return
|
|
98
|
+
return isAbsolute2(value) ? resolve2(value) : resolve2(projectRoot, value);
|
|
37
99
|
}
|
|
38
100
|
function resolveRunnerCommand(runtime, command, options = {}) {
|
|
39
101
|
const tokens = safeSplit(command);
|
|
40
102
|
if (!tokens || tokens.length === 0) return null;
|
|
41
|
-
const projectRoot =
|
|
103
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
42
104
|
const launcher = runtime.packageManager;
|
|
43
105
|
const [head, second, ...rest] = tokens;
|
|
44
106
|
if (!head) return null;
|
|
@@ -69,7 +131,7 @@ function resolveRunnerCommand(runtime, command, options = {}) {
|
|
|
69
131
|
return { cmd: head, args: [second, exe, ...tail], display };
|
|
70
132
|
}
|
|
71
133
|
}
|
|
72
|
-
if (
|
|
134
|
+
if (isAbsolute2(head)) {
|
|
73
135
|
if (!withinProjectPath(projectRoot, head)) return null;
|
|
74
136
|
const base = basename(head);
|
|
75
137
|
if (base !== runtime.executable && base !== launcher) return null;
|
|
@@ -90,7 +152,7 @@ function runRunnerCommand(argv, options) {
|
|
|
90
152
|
});
|
|
91
153
|
}
|
|
92
154
|
return new Promise((resolvePromise) => {
|
|
93
|
-
const projectRoot =
|
|
155
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
94
156
|
const trimmedCwd = options.cwd.trim();
|
|
95
157
|
if (!withinProjectPath(projectRoot, trimmedCwd)) {
|
|
96
158
|
resolvePromise({
|
|
@@ -108,21 +170,37 @@ function runRunnerCommand(argv, options) {
|
|
|
108
170
|
const stderrChunks = [];
|
|
109
171
|
let stdoutBytes = 0;
|
|
110
172
|
let stderrBytes = 0;
|
|
111
|
-
|
|
173
|
+
const onAbort = () => {
|
|
112
174
|
timedOut = true;
|
|
113
|
-
}
|
|
175
|
+
};
|
|
176
|
+
let invocation;
|
|
177
|
+
try {
|
|
178
|
+
invocation = resolveExecInvocation(argv[0], argv.slice(1));
|
|
179
|
+
} catch (err) {
|
|
180
|
+
resolvePromise({
|
|
181
|
+
code: null,
|
|
182
|
+
stdout: "",
|
|
183
|
+
stderr: `runtime helper: ${err instanceof Error ? err.message : String(err)}`,
|
|
184
|
+
timedOut: false,
|
|
185
|
+
spawnError: true
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
114
190
|
const child = execFile(
|
|
115
|
-
|
|
116
|
-
|
|
191
|
+
invocation.cmd,
|
|
192
|
+
invocation.args,
|
|
117
193
|
{
|
|
118
194
|
cwd: trimmedCwd,
|
|
119
195
|
timeout: options.timeoutMs,
|
|
120
196
|
signal: options.signal,
|
|
121
197
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
122
198
|
windowsHide: true,
|
|
123
|
-
shell: false
|
|
199
|
+
shell: false,
|
|
200
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
124
201
|
},
|
|
125
202
|
(err) => {
|
|
203
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
126
204
|
if (timedOut) {
|
|
127
205
|
resolvePromise({
|
|
128
206
|
code: null,
|
|
@@ -186,7 +264,7 @@ function runRunnerCommand(argv, options) {
|
|
|
186
264
|
}
|
|
187
265
|
function withinProject(p) {
|
|
188
266
|
const cwd = process.cwd();
|
|
189
|
-
return withinProjectPath(cwd, p) ||
|
|
267
|
+
return withinProjectPath(cwd, p) || relative2(cwd, p) === ".";
|
|
190
268
|
}
|
|
191
269
|
|
|
192
270
|
// src/type-gate/index.ts
|
|
@@ -263,7 +341,9 @@ async function runTypeCheck(cfg) {
|
|
|
263
341
|
if (!resolved) return null;
|
|
264
342
|
argv = [resolved.cmd, ...resolved.args];
|
|
265
343
|
} else {
|
|
266
|
-
|
|
344
|
+
const tscFlags = ["--noEmit", "--incremental"];
|
|
345
|
+
const localTsc = resolveNodeBin("typescript", "tsc", process.cwd(), tscFlags);
|
|
346
|
+
argv = localTsc ? [localTsc.cmd, ...localTsc.args] : ["npx", "tsc", ...tscFlags];
|
|
267
347
|
if (tsConfig && tsConfig !== "tsconfig.json") {
|
|
268
348
|
argv = [...argv, "-p", tsConfig];
|
|
269
349
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.295.
|
|
3
|
+
"version": "0.295.1",
|
|
4
4
|
"description": "Official WrongStack collection of focused plugins for code quality, security, observability, planning, and agent coordination",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -294,8 +294,8 @@
|
|
|
294
294
|
"vitest": "^4.1.10"
|
|
295
295
|
},
|
|
296
296
|
"dependencies": {
|
|
297
|
-
"@wrongstack/core": "0.295.
|
|
298
|
-
"@wrongstack/tools": "0.295.
|
|
297
|
+
"@wrongstack/core": "0.295.1",
|
|
298
|
+
"@wrongstack/tools": "0.295.1"
|
|
299
299
|
},
|
|
300
300
|
"scripts": {
|
|
301
301
|
"build": "node ../../scripts/build-package.mjs",
|