@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/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/accessibility-auditor/index.ts
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { isAbsolute as
|
|
3
|
+
import { isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/runtime/index.ts
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
|
-
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
import { basename, extname as extname2, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
8
8
|
|
|
9
9
|
// src/runtime/llm.ts
|
|
10
10
|
function stripOuterMarkdownFence(text) {
|
|
@@ -52,6 +52,249 @@ async function runOptionalPluginLlm(request) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// src/runtime/local-bin.ts
|
|
56
|
+
import { createRequire } from "node:module";
|
|
57
|
+
import { delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
58
|
+
import { accessSync, constants, readFileSync } from "node:fs";
|
|
59
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
60
|
+
function resolveExecInvocation(command, args = []) {
|
|
61
|
+
const resolved = resolveWin32Command(command);
|
|
62
|
+
const normalizedResolved = resolved.toLowerCase();
|
|
63
|
+
const needsShell = process.platform === "win32" && (normalizedResolved.endsWith(".cmd") || normalizedResolved.endsWith(".bat"));
|
|
64
|
+
if (needsShell) {
|
|
65
|
+
const shim = buildWin32CmdShimInvocation(resolved, args);
|
|
66
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
67
|
+
}
|
|
68
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
69
|
+
}
|
|
70
|
+
function findOnPath(cmd) {
|
|
71
|
+
if (!cmd) return null;
|
|
72
|
+
const exists = (p) => {
|
|
73
|
+
try {
|
|
74
|
+
accessSync(p, constants.X_OK);
|
|
75
|
+
return true;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
81
|
+
return exists(cmd) ? resolve(cmd) : null;
|
|
82
|
+
}
|
|
83
|
+
const suffixes = process.platform === "win32" && extname(cmd) === "" ? (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
84
|
+
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
85
|
+
if (!dir) continue;
|
|
86
|
+
const base = join(dir, cmd);
|
|
87
|
+
for (const suffix of suffixes) {
|
|
88
|
+
const candidate = `${base}${suffix}`;
|
|
89
|
+
if (exists(candidate)) return candidate;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
function isInside(parent, candidate) {
|
|
95
|
+
const rel = relative(parent, candidate);
|
|
96
|
+
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
|
|
97
|
+
}
|
|
98
|
+
var binCache = /* @__PURE__ */ new Map();
|
|
99
|
+
var BIN_CACHE_MAX = 64;
|
|
100
|
+
var NEGATIVE_BIN_CACHE_TTL_MS = 5e3;
|
|
101
|
+
function cachePut(key, value) {
|
|
102
|
+
while (binCache.size >= BIN_CACHE_MAX) {
|
|
103
|
+
const oldest = binCache.keys().next().value;
|
|
104
|
+
if (oldest === void 0) break;
|
|
105
|
+
binCache.delete(oldest);
|
|
106
|
+
}
|
|
107
|
+
binCache.set(key, { value, cachedAt: Date.now() });
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
function clearLocalBinCache() {
|
|
111
|
+
binCache.clear();
|
|
112
|
+
}
|
|
113
|
+
function resolveNodeBin(packageName, binName, cwd, extraArgs = []) {
|
|
114
|
+
const key = `${packageName}|${binName}|${cwd}`;
|
|
115
|
+
const cached = binCache.get(key);
|
|
116
|
+
if (cached !== void 0) {
|
|
117
|
+
if (cached.value !== null || Date.now() - cached.cachedAt < NEGATIVE_BIN_CACHE_TTL_MS) {
|
|
118
|
+
return cached.value === null ? null : { ...cached.value, args: [cached.value.entry, ...extraArgs] };
|
|
119
|
+
}
|
|
120
|
+
binCache.delete(key);
|
|
121
|
+
}
|
|
122
|
+
let resolved = null;
|
|
123
|
+
try {
|
|
124
|
+
const requireFromProject = createRequire(resolve(cwd, "package.json"));
|
|
125
|
+
const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
|
|
126
|
+
const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
127
|
+
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[binName] ?? Object.values(packageJson.bin ?? {})[0];
|
|
128
|
+
if (relativeBin && !isAbsolute(relativeBin)) {
|
|
129
|
+
const packageDir = dirname(packagePath);
|
|
130
|
+
const entry = resolve(packageDir, relativeBin);
|
|
131
|
+
if (isInside(packageDir, entry)) {
|
|
132
|
+
resolved = { cmd: process.execPath, args: [entry], entry };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
resolved = null;
|
|
137
|
+
}
|
|
138
|
+
cachePut(key, resolved);
|
|
139
|
+
return resolved === null ? null : { ...resolved, args: [resolved.entry, ...extraArgs] };
|
|
140
|
+
}
|
|
141
|
+
function resolveFirstNodeBin(candidates, cwd) {
|
|
142
|
+
for (const c of candidates) {
|
|
143
|
+
const hit = resolveNodeBin(c.packageName, c.binName, cwd, c.args ?? []);
|
|
144
|
+
if (hit) return { ...hit, packageName: c.packageName, binName: c.binName };
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/runtime/bounded-map.ts
|
|
150
|
+
var BoundedMap = class {
|
|
151
|
+
map = /* @__PURE__ */ new Map();
|
|
152
|
+
max;
|
|
153
|
+
ttlMs;
|
|
154
|
+
now;
|
|
155
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
156
|
+
evictions = 0;
|
|
157
|
+
constructor(options) {
|
|
158
|
+
const normalizedMax = Math.floor(options.max);
|
|
159
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
160
|
+
this.ttlMs = options.ttlMs;
|
|
161
|
+
this.now = options.now ?? Date.now;
|
|
162
|
+
}
|
|
163
|
+
expired(entry) {
|
|
164
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
165
|
+
}
|
|
166
|
+
get(key) {
|
|
167
|
+
const entry = this.map.get(key);
|
|
168
|
+
if (entry === void 0) return void 0;
|
|
169
|
+
if (this.expired(entry)) {
|
|
170
|
+
this.map.delete(key);
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
this.map.delete(key);
|
|
174
|
+
this.map.set(key, entry);
|
|
175
|
+
return entry.value;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
179
|
+
* diagnostics that must not perturb the eviction order.
|
|
180
|
+
*/
|
|
181
|
+
peek(key) {
|
|
182
|
+
const entry = this.map.get(key);
|
|
183
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
184
|
+
return entry.value;
|
|
185
|
+
}
|
|
186
|
+
has(key) {
|
|
187
|
+
const entry = this.map.get(key);
|
|
188
|
+
if (entry === void 0) return false;
|
|
189
|
+
if (this.expired(entry)) {
|
|
190
|
+
this.map.delete(key);
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
set(key, value) {
|
|
196
|
+
this.map.delete(key);
|
|
197
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
198
|
+
while (this.map.size > this.max) {
|
|
199
|
+
const coldest = this.map.keys().next().value;
|
|
200
|
+
if (coldest === void 0) break;
|
|
201
|
+
this.map.delete(coldest);
|
|
202
|
+
this.evictions += 1;
|
|
203
|
+
}
|
|
204
|
+
return this;
|
|
205
|
+
}
|
|
206
|
+
delete(key) {
|
|
207
|
+
return this.map.delete(key);
|
|
208
|
+
}
|
|
209
|
+
clear() {
|
|
210
|
+
this.map.clear();
|
|
211
|
+
this.evictions = 0;
|
|
212
|
+
}
|
|
213
|
+
get size() {
|
|
214
|
+
return this.map.size;
|
|
215
|
+
}
|
|
216
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
217
|
+
get evictionCount() {
|
|
218
|
+
return this.evictions;
|
|
219
|
+
}
|
|
220
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
221
|
+
prune() {
|
|
222
|
+
if (this.ttlMs === void 0) return 0;
|
|
223
|
+
let removed = 0;
|
|
224
|
+
for (const [key, entry] of this.map) {
|
|
225
|
+
if (this.expired(entry)) {
|
|
226
|
+
this.map.delete(key);
|
|
227
|
+
removed += 1;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return removed;
|
|
231
|
+
}
|
|
232
|
+
/** Live (non-expired) entries, coldest first. */
|
|
233
|
+
*entries() {
|
|
234
|
+
for (const [key, entry] of this.map) {
|
|
235
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
[Symbol.iterator]() {
|
|
239
|
+
return this.entries();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var BoundedSet = class {
|
|
243
|
+
inner;
|
|
244
|
+
constructor(options) {
|
|
245
|
+
this.inner = new BoundedMap(options);
|
|
246
|
+
}
|
|
247
|
+
has(value) {
|
|
248
|
+
return this.inner.has(value);
|
|
249
|
+
}
|
|
250
|
+
add(value) {
|
|
251
|
+
this.inner.set(value, true);
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
delete(value) {
|
|
255
|
+
return this.inner.delete(value);
|
|
256
|
+
}
|
|
257
|
+
clear() {
|
|
258
|
+
this.inner.clear();
|
|
259
|
+
}
|
|
260
|
+
get size() {
|
|
261
|
+
return this.inner.size;
|
|
262
|
+
}
|
|
263
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
264
|
+
get evictionCount() {
|
|
265
|
+
return this.inner.evictionCount;
|
|
266
|
+
}
|
|
267
|
+
*values() {
|
|
268
|
+
for (const [key] of this.inner) yield key;
|
|
269
|
+
}
|
|
270
|
+
[Symbol.iterator]() {
|
|
271
|
+
return this.values();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// src/runtime/safe-json.ts
|
|
276
|
+
var UNSERIALIZABLE = "[unserializable]";
|
|
277
|
+
function safeJsonStringify(value, indent) {
|
|
278
|
+
try {
|
|
279
|
+
const stack = [];
|
|
280
|
+
const out = JSON.stringify(
|
|
281
|
+
value,
|
|
282
|
+
function replacer(_key, val) {
|
|
283
|
+
if (typeof val === "bigint") return `${val.toString()}n`;
|
|
284
|
+
if (val === null || typeof val !== "object") return val;
|
|
285
|
+
while (stack.length > 0 && stack[stack.length - 1] !== this) stack.pop();
|
|
286
|
+
if (stack.includes(val)) return "[circular]";
|
|
287
|
+
stack.push(val);
|
|
288
|
+
return val;
|
|
289
|
+
},
|
|
290
|
+
indent
|
|
291
|
+
);
|
|
292
|
+
return out ?? String(value);
|
|
293
|
+
} catch {
|
|
294
|
+
return UNSERIALIZABLE;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
55
298
|
// src/runtime/index.ts
|
|
56
299
|
var META_CHARS = /["'`;&|<>\r\n]/;
|
|
57
300
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
@@ -66,9 +309,9 @@ function safeSplit(command) {
|
|
|
66
309
|
function withinProjectPath(projectRoot, candidate) {
|
|
67
310
|
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
68
311
|
if (hasLeadingDash(candidate)) return false;
|
|
69
|
-
const resolved =
|
|
70
|
-
const rel =
|
|
71
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
312
|
+
const resolved = isAbsolute2(candidate) ? resolve2(candidate) : resolve2(projectRoot, candidate);
|
|
313
|
+
const rel = relative2(projectRoot, resolved);
|
|
314
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
|
|
72
315
|
}
|
|
73
316
|
function everyFlagAllowed(allowed, args) {
|
|
74
317
|
for (const arg of args) {
|
|
@@ -80,14 +323,14 @@ function everyFlagAllowed(allowed, args) {
|
|
|
80
323
|
}
|
|
81
324
|
function sanitizeRunnerPath(value, options = {}) {
|
|
82
325
|
if (!value || hasLeadingDash(value)) return null;
|
|
83
|
-
const projectRoot =
|
|
326
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
84
327
|
if (!withinProjectPath(projectRoot, value)) return null;
|
|
85
|
-
return
|
|
328
|
+
return isAbsolute2(value) ? resolve2(value) : resolve2(projectRoot, value);
|
|
86
329
|
}
|
|
87
330
|
function resolveRunnerCommand(runtime, command, options = {}) {
|
|
88
331
|
const tokens = safeSplit(command);
|
|
89
332
|
if (!tokens || tokens.length === 0) return null;
|
|
90
|
-
const projectRoot =
|
|
333
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
91
334
|
const launcher = runtime.packageManager;
|
|
92
335
|
const [head, second, ...rest] = tokens;
|
|
93
336
|
if (!head) return null;
|
|
@@ -118,7 +361,7 @@ function resolveRunnerCommand(runtime, command, options = {}) {
|
|
|
118
361
|
return { cmd: head, args: [second, exe, ...tail], display };
|
|
119
362
|
}
|
|
120
363
|
}
|
|
121
|
-
if (
|
|
364
|
+
if (isAbsolute2(head)) {
|
|
122
365
|
if (!withinProjectPath(projectRoot, head)) return null;
|
|
123
366
|
const base = basename(head);
|
|
124
367
|
if (base !== runtime.executable && base !== launcher) return null;
|
|
@@ -139,7 +382,7 @@ function runRunnerCommand(argv, options) {
|
|
|
139
382
|
});
|
|
140
383
|
}
|
|
141
384
|
return new Promise((resolvePromise) => {
|
|
142
|
-
const projectRoot =
|
|
385
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
143
386
|
const trimmedCwd = options.cwd.trim();
|
|
144
387
|
if (!withinProjectPath(projectRoot, trimmedCwd)) {
|
|
145
388
|
resolvePromise({
|
|
@@ -157,21 +400,37 @@ function runRunnerCommand(argv, options) {
|
|
|
157
400
|
const stderrChunks = [];
|
|
158
401
|
let stdoutBytes = 0;
|
|
159
402
|
let stderrBytes = 0;
|
|
160
|
-
|
|
403
|
+
const onAbort = () => {
|
|
161
404
|
timedOut = true;
|
|
162
|
-
}
|
|
405
|
+
};
|
|
406
|
+
let invocation;
|
|
407
|
+
try {
|
|
408
|
+
invocation = resolveExecInvocation(argv[0], argv.slice(1));
|
|
409
|
+
} catch (err) {
|
|
410
|
+
resolvePromise({
|
|
411
|
+
code: null,
|
|
412
|
+
stdout: "",
|
|
413
|
+
stderr: `runtime helper: ${err instanceof Error ? err.message : String(err)}`,
|
|
414
|
+
timedOut: false,
|
|
415
|
+
spawnError: true
|
|
416
|
+
});
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
163
420
|
const child = execFile(
|
|
164
|
-
|
|
165
|
-
|
|
421
|
+
invocation.cmd,
|
|
422
|
+
invocation.args,
|
|
166
423
|
{
|
|
167
424
|
cwd: trimmedCwd,
|
|
168
425
|
timeout: options.timeoutMs,
|
|
169
426
|
signal: options.signal,
|
|
170
427
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
171
428
|
windowsHide: true,
|
|
172
|
-
shell: false
|
|
429
|
+
shell: false,
|
|
430
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
173
431
|
},
|
|
174
432
|
(err) => {
|
|
433
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
175
434
|
if (timedOut) {
|
|
176
435
|
resolvePromise({
|
|
177
436
|
code: null,
|
|
@@ -235,7 +494,7 @@ function runRunnerCommand(argv, options) {
|
|
|
235
494
|
}
|
|
236
495
|
function withinProject(p) {
|
|
237
496
|
const cwd = process.cwd();
|
|
238
|
-
return withinProjectPath(cwd, p) ||
|
|
497
|
+
return withinProjectPath(cwd, p) || relative2(cwd, p) === ".";
|
|
239
498
|
}
|
|
240
499
|
var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
|
|
241
500
|
async function collectSourceFilesAsync(root, opts) {
|
|
@@ -264,7 +523,7 @@ async function collectSourceFilesAsync(root, opts) {
|
|
|
264
523
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
265
524
|
for (const entry of entries) {
|
|
266
525
|
if (excludeSet.has(entry.name)) continue;
|
|
267
|
-
const full =
|
|
526
|
+
const full = resolve2(dir, entry.name);
|
|
268
527
|
if (entry.isDirectory()) {
|
|
269
528
|
await walk(full, depth + 1);
|
|
270
529
|
} else if (entry.isFile() && matchesExtension(full, opts.extensions)) {
|
|
@@ -276,7 +535,7 @@ async function collectSourceFilesAsync(root, opts) {
|
|
|
276
535
|
return files;
|
|
277
536
|
}
|
|
278
537
|
function matchesExtension(p, exts) {
|
|
279
|
-
return exts.includes(
|
|
538
|
+
return exts.includes(extname2(p).toLowerCase());
|
|
280
539
|
}
|
|
281
540
|
|
|
282
541
|
// src/accessibility-auditor/index.ts
|
|
@@ -339,7 +598,7 @@ async function auditFile(filePath, projectRoot) {
|
|
|
339
598
|
const idsByValue = /* @__PURE__ */ new Map();
|
|
340
599
|
function add(line, rule, severity, message) {
|
|
341
600
|
findings.push({
|
|
342
|
-
file:
|
|
601
|
+
file: relative3(projectRoot, filePath),
|
|
343
602
|
line,
|
|
344
603
|
rule,
|
|
345
604
|
severity,
|
|
@@ -418,19 +677,27 @@ async function auditFile(filePath, projectRoot) {
|
|
|
418
677
|
}
|
|
419
678
|
async function auditPath(rawPath, cfg) {
|
|
420
679
|
const root = process.cwd();
|
|
421
|
-
const resolved =
|
|
680
|
+
const resolved = isAbsolute3(rawPath) ? resolve3(rawPath) : resolve3(root, rawPath);
|
|
422
681
|
const exts = normalizeExtensions(cfg.includeExtensions);
|
|
423
682
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
424
683
|
const findings = [];
|
|
684
|
+
let scannedFiles = 0;
|
|
685
|
+
let truncated = false;
|
|
425
686
|
for (const file of files) {
|
|
426
687
|
const fileFindings = await auditFile(file, root);
|
|
688
|
+
scannedFiles += 1;
|
|
427
689
|
findings.push(...fileFindings);
|
|
428
|
-
if (findings.length >= cfg.maxFindings)
|
|
690
|
+
if (findings.length >= cfg.maxFindings) {
|
|
691
|
+
truncated = scannedFiles < files.length;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
429
694
|
}
|
|
430
695
|
return {
|
|
431
|
-
path:
|
|
696
|
+
path: relative3(root, resolved),
|
|
432
697
|
findings: findings.slice(0, cfg.maxFindings),
|
|
433
|
-
fileCount: files.length
|
|
698
|
+
fileCount: files.length,
|
|
699
|
+
scannedFiles,
|
|
700
|
+
truncated
|
|
434
701
|
};
|
|
435
702
|
}
|
|
436
703
|
function formatSummary(result) {
|
|
@@ -559,6 +826,10 @@ var plugin = {
|
|
|
559
826
|
ok: true,
|
|
560
827
|
path: result.path,
|
|
561
828
|
fileCount: result.fileCount,
|
|
829
|
+
scannedFiles: result.scannedFiles,
|
|
830
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
831
|
+
// that reports few findings must not read as a clean result.
|
|
832
|
+
truncated: result.truncated,
|
|
562
833
|
findingCount: result.findings.length,
|
|
563
834
|
findings: result.findings
|
|
564
835
|
};
|
|
@@ -689,7 +960,7 @@ function buildBody(payload, cfg) {
|
|
|
689
960
|
if (cfg.includeResult && payload.result !== void 0) {
|
|
690
961
|
lines.push("## Result");
|
|
691
962
|
lines.push("```json");
|
|
692
|
-
lines.push(
|
|
963
|
+
lines.push(safeJsonStringify(payload.result, 2));
|
|
693
964
|
lines.push("```");
|
|
694
965
|
lines.push("");
|
|
695
966
|
}
|
|
@@ -931,9 +1202,9 @@ var agent_handoff_default = plugin2;
|
|
|
931
1202
|
|
|
932
1203
|
// src/api-compatibility-gate/index.ts
|
|
933
1204
|
import { execFile as execFile2 } from "node:child_process";
|
|
934
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1205
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
935
1206
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
936
|
-
import { basename as basename2, dirname, extname as
|
|
1207
|
+
import { basename as basename2, dirname as dirname2, extname as extname3, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4 } from "node:path";
|
|
937
1208
|
var API_VERSION3 = "^0.1.10";
|
|
938
1209
|
var state3 = {
|
|
939
1210
|
invocationCount: 0,
|
|
@@ -997,25 +1268,25 @@ function matchesAnyPattern(filePath, patterns) {
|
|
|
997
1268
|
return patterns.some((p) => patternToRegex(p).test(normalized));
|
|
998
1269
|
}
|
|
999
1270
|
function resolveToProjectRoot(filePath) {
|
|
1000
|
-
if (
|
|
1001
|
-
return
|
|
1271
|
+
if (isAbsolute4(filePath)) return resolve4(filePath);
|
|
1272
|
+
return resolve4(process.cwd(), filePath);
|
|
1002
1273
|
}
|
|
1003
1274
|
function withinProject2(filePath) {
|
|
1004
1275
|
if (typeof filePath !== "string" || filePath.length === 0 || filePath.length > 4096) return false;
|
|
1005
1276
|
const resolved = resolveToProjectRoot(filePath);
|
|
1006
|
-
const rel =
|
|
1277
|
+
const rel = relative4(process.cwd(), resolved);
|
|
1007
1278
|
if (rel === "" || rel === ".") return true;
|
|
1008
1279
|
if (rel.startsWith("..")) return false;
|
|
1009
|
-
if (
|
|
1280
|
+
if (isAbsolute4(rel)) return false;
|
|
1010
1281
|
return true;
|
|
1011
1282
|
}
|
|
1012
1283
|
function isPackageEntryPoint(filePath) {
|
|
1013
1284
|
const resolved = resolveToProjectRoot(filePath);
|
|
1014
|
-
const dir =
|
|
1015
|
-
const pkgPath =
|
|
1285
|
+
const dir = dirname2(resolved);
|
|
1286
|
+
const pkgPath = resolve4(dir, "package.json");
|
|
1016
1287
|
if (!existsSync(pkgPath)) return false;
|
|
1017
1288
|
try {
|
|
1018
|
-
const pkg = JSON.parse(
|
|
1289
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1019
1290
|
const entries = [];
|
|
1020
1291
|
if (pkg.main) entries.push(pkg.main);
|
|
1021
1292
|
if (pkg.module) entries.push(pkg.module);
|
|
@@ -1033,9 +1304,9 @@ function isPackageEntryPoint(filePath) {
|
|
|
1033
1304
|
}
|
|
1034
1305
|
}
|
|
1035
1306
|
for (const entry of entries) {
|
|
1036
|
-
const entryResolved =
|
|
1307
|
+
const entryResolved = resolve4(dir, entry);
|
|
1037
1308
|
if (entryResolved === resolved) return true;
|
|
1038
|
-
if (basename2(
|
|
1309
|
+
if (basename2(dirname2(entryResolved)) === basename2(dirname2(resolved)) && basename2(entryResolved, extname3(entryResolved)) === basename2(resolved, extname3(resolved))) {
|
|
1039
1310
|
return true;
|
|
1040
1311
|
}
|
|
1041
1312
|
}
|
|
@@ -1086,7 +1357,7 @@ function extractExports(source) {
|
|
|
1086
1357
|
}
|
|
1087
1358
|
function readGitVersion(filePath) {
|
|
1088
1359
|
const resolved = resolveToProjectRoot(filePath);
|
|
1089
|
-
const relPath = normalizePath(
|
|
1360
|
+
const relPath = normalizePath(relative4(process.cwd(), resolved));
|
|
1090
1361
|
return new Promise((resolveVersion) => {
|
|
1091
1362
|
execFile2(
|
|
1092
1363
|
"git",
|
|
@@ -1290,14 +1561,14 @@ var plugin3 = {
|
|
|
1290
1561
|
var api_compatibility_gate_default = plugin3;
|
|
1291
1562
|
|
|
1292
1563
|
// src/auto-doc/index.ts
|
|
1293
|
-
import { isAbsolute as
|
|
1564
|
+
import { isAbsolute as isAbsolute5, relative as relative5, resolve as resolve5 } from "node:path";
|
|
1294
1565
|
var AUTO_DOC_API_VERSION = "^0.1.10";
|
|
1295
1566
|
function resolveProjectPath(rawPath, cwd = process.cwd()) {
|
|
1296
1567
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
1297
|
-
const root =
|
|
1298
|
-
const resolved =
|
|
1299
|
-
const rel =
|
|
1300
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
1568
|
+
const root = resolve5(cwd);
|
|
1569
|
+
const resolved = isAbsolute5(rawPath) ? resolve5(rawPath) : resolve5(root, rawPath);
|
|
1570
|
+
const rel = relative5(root, resolved);
|
|
1571
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute5(rel)) return resolved;
|
|
1301
1572
|
return null;
|
|
1302
1573
|
}
|
|
1303
1574
|
var state4 = {
|
|
@@ -1477,16 +1748,17 @@ async function runAutoDoc(input, api) {
|
|
|
1477
1748
|
continue;
|
|
1478
1749
|
}
|
|
1479
1750
|
try {
|
|
1480
|
-
const { readFileSync:
|
|
1751
|
+
const { readFileSync: readFileSync17, writeFileSync: writeFileSync3 } = await import("node:fs");
|
|
1481
1752
|
let content;
|
|
1482
1753
|
try {
|
|
1483
|
-
content =
|
|
1754
|
+
content = readFileSync17(safeFile, "utf-8");
|
|
1484
1755
|
} catch {
|
|
1485
1756
|
api.log.warn(`auto-doc: could not read file ${safeFile}`);
|
|
1486
1757
|
continue;
|
|
1487
1758
|
}
|
|
1488
1759
|
const entities = parseSource(content);
|
|
1489
1760
|
let modified = content;
|
|
1761
|
+
const beforeCount = results.length;
|
|
1490
1762
|
for (const entity of entities) {
|
|
1491
1763
|
if (!input.force && !needsDocComment(modified, entity)) continue;
|
|
1492
1764
|
let doc = null;
|
|
@@ -1512,8 +1784,9 @@ async function runAutoDoc(input, api) {
|
|
|
1512
1784
|
modified = injectDocComment(modified, entity, doc);
|
|
1513
1785
|
results.push({ file: safeFile, entity: entity.name, source });
|
|
1514
1786
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1787
|
+
const changedThisFile = results.length > beforeCount && modified !== content;
|
|
1788
|
+
if (!input.dry_run && changedThisFile) {
|
|
1789
|
+
writeFileSync3(safeFile, modified, "utf-8");
|
|
1517
1790
|
api.log.info(`auto-doc: updated ${safeFile}`);
|
|
1518
1791
|
}
|
|
1519
1792
|
} catch (err) {
|
|
@@ -1828,7 +2101,7 @@ var plugin5 = {
|
|
|
1828
2101
|
var auto_escalate_default = plugin5;
|
|
1829
2102
|
|
|
1830
2103
|
// src/auto-i18n-extractor/index.ts
|
|
1831
|
-
import { readFileSync as
|
|
2104
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1832
2105
|
var API_VERSION4 = "^0.1.10";
|
|
1833
2106
|
var state6 = {
|
|
1834
2107
|
filesScanned: 0,
|
|
@@ -1913,7 +2186,7 @@ function extractStrings(content, cfg) {
|
|
|
1913
2186
|
}
|
|
1914
2187
|
function readSourceFile(filePath) {
|
|
1915
2188
|
try {
|
|
1916
|
-
return
|
|
2189
|
+
return readFileSync3(filePath, "utf-8");
|
|
1917
2190
|
} catch {
|
|
1918
2191
|
return null;
|
|
1919
2192
|
}
|
|
@@ -2201,16 +2474,16 @@ function hasDisabledPluginEntry(raw) {
|
|
|
2201
2474
|
return name === "branch-guard" || name === "@wrongstack/plugins/branch-guard";
|
|
2202
2475
|
});
|
|
2203
2476
|
}
|
|
2204
|
-
var branchCache =
|
|
2477
|
+
var branchCache = new BoundedMap({ max: 64, ttlMs: 3e4 });
|
|
2205
2478
|
function runGit(args, cwd, signal) {
|
|
2206
|
-
return new Promise((
|
|
2479
|
+
return new Promise((resolve28, reject) => {
|
|
2207
2480
|
execFile3(
|
|
2208
2481
|
"git",
|
|
2209
2482
|
args,
|
|
2210
2483
|
{ encoding: "utf-8", timeout: 3e3, cwd, windowsHide: true, signal },
|
|
2211
2484
|
(error, stdout) => {
|
|
2212
2485
|
if (error) reject(error);
|
|
2213
|
-
else
|
|
2486
|
+
else resolve28(stdout);
|
|
2214
2487
|
}
|
|
2215
2488
|
);
|
|
2216
2489
|
});
|
|
@@ -2458,11 +2731,11 @@ var plugin7 = {
|
|
|
2458
2731
|
var branch_guard_default = plugin7;
|
|
2459
2732
|
|
|
2460
2733
|
// src/changelog-writer/index.ts
|
|
2461
|
-
import { readFileSync as
|
|
2462
|
-
import { isAbsolute as
|
|
2734
|
+
import { readFileSync as readFileSync4, writeFileSync } from "node:fs";
|
|
2735
|
+
import { isAbsolute as isAbsolute6, relative as relative6, resolve as resolve6 } from "node:path";
|
|
2463
2736
|
var state8 = {
|
|
2464
2737
|
entries: [],
|
|
2465
|
-
filesTouched:
|
|
2738
|
+
filesTouched: new BoundedSet({ max: 2e3 }),
|
|
2466
2739
|
commitsSeen: 0,
|
|
2467
2740
|
writes: 0,
|
|
2468
2741
|
polishes: 0,
|
|
@@ -2476,10 +2749,10 @@ var DEFAULTS6 = {
|
|
|
2476
2749
|
maxEntries: 200
|
|
2477
2750
|
};
|
|
2478
2751
|
function resolveProjectPath2(rawPath, cwd = process.cwd()) {
|
|
2479
|
-
const root =
|
|
2480
|
-
const resolved =
|
|
2481
|
-
const rel =
|
|
2482
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
2752
|
+
const root = resolve6(cwd);
|
|
2753
|
+
const resolved = isAbsolute6(rawPath) ? resolve6(rawPath) : resolve6(root, rawPath);
|
|
2754
|
+
const rel = relative6(root, resolved);
|
|
2755
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute6(rel)) return resolved;
|
|
2483
2756
|
return null;
|
|
2484
2757
|
}
|
|
2485
2758
|
function readConfig7(raw) {
|
|
@@ -2623,7 +2896,7 @@ var plugin8 = {
|
|
|
2623
2896
|
},
|
|
2624
2897
|
setup(api) {
|
|
2625
2898
|
state8.entries = [];
|
|
2626
|
-
state8.filesTouched =
|
|
2899
|
+
state8.filesTouched = new BoundedSet({ max: 2e3 });
|
|
2627
2900
|
state8.commitsSeen = 0;
|
|
2628
2901
|
state8.writes = 0;
|
|
2629
2902
|
for (const off of state8.eventUnsubscribers) {
|
|
@@ -2769,7 +3042,7 @@ var plugin8 = {
|
|
|
2769
3042
|
);
|
|
2770
3043
|
let existing = null;
|
|
2771
3044
|
try {
|
|
2772
|
-
existing =
|
|
3045
|
+
existing = readFileSync4(cfg.filePath, "utf-8");
|
|
2773
3046
|
} catch {
|
|
2774
3047
|
existing = null;
|
|
2775
3048
|
}
|
|
@@ -2815,7 +3088,7 @@ var plugin8 = {
|
|
|
2815
3088
|
filesTouched: state8.filesTouched.size
|
|
2816
3089
|
};
|
|
2817
3090
|
state8.entries = [];
|
|
2818
|
-
state8.filesTouched =
|
|
3091
|
+
state8.filesTouched = new BoundedSet({ max: 2e3 });
|
|
2819
3092
|
state8.commitsSeen = 0;
|
|
2820
3093
|
state8.writes = 0;
|
|
2821
3094
|
api.log.info("changelog-writer: teardown complete", { final });
|
|
@@ -2837,20 +3110,22 @@ var changelog_writer_default = plugin8;
|
|
|
2837
3110
|
|
|
2838
3111
|
// src/checkpoint/index.ts
|
|
2839
3112
|
import { mkdir, readFile as readFile3, stat, writeFile } from "node:fs/promises";
|
|
2840
|
-
import { dirname as
|
|
3113
|
+
import { dirname as dirname3, isAbsolute as isAbsolute7, relative as relative7, resolve as resolve7 } from "node:path";
|
|
2841
3114
|
var state9 = {
|
|
2842
3115
|
snapshots: [],
|
|
2843
3116
|
nextId: 1,
|
|
2844
3117
|
captures: 0,
|
|
2845
3118
|
restores: 0,
|
|
2846
3119
|
skippedLarge: 0,
|
|
3120
|
+
evictedForBytes: 0,
|
|
2847
3121
|
hookUnregister: null
|
|
2848
3122
|
};
|
|
2849
3123
|
var DEFAULTS7 = {
|
|
2850
3124
|
enabled: true,
|
|
2851
3125
|
autoCapture: true,
|
|
2852
3126
|
maxSnapshots: 50,
|
|
2853
|
-
maxFileBytes: 1048576
|
|
3127
|
+
maxFileBytes: 1048576,
|
|
3128
|
+
maxTotalBytes: 64 * 1048576
|
|
2854
3129
|
};
|
|
2855
3130
|
function readConfig8(raw) {
|
|
2856
3131
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS7 };
|
|
@@ -2859,14 +3134,15 @@ function readConfig8(raw) {
|
|
|
2859
3134
|
enabled: r["enabled"] !== false,
|
|
2860
3135
|
autoCapture: r["autoCapture"] !== false,
|
|
2861
3136
|
maxSnapshots: typeof r["maxSnapshots"] === "number" && r["maxSnapshots"] >= 1 && r["maxSnapshots"] <= 500 ? r["maxSnapshots"] : DEFAULTS7.maxSnapshots,
|
|
3137
|
+
maxTotalBytes: typeof r["maxTotalBytes"] === "number" && r["maxTotalBytes"] >= 1024 ? r["maxTotalBytes"] : DEFAULTS7.maxTotalBytes,
|
|
2862
3138
|
maxFileBytes: typeof r["maxFileBytes"] === "number" && r["maxFileBytes"] >= 1024 ? r["maxFileBytes"] : DEFAULTS7.maxFileBytes
|
|
2863
3139
|
};
|
|
2864
3140
|
}
|
|
2865
3141
|
function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2866
|
-
const root =
|
|
2867
|
-
const resolved =
|
|
2868
|
-
const rel =
|
|
2869
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
3142
|
+
const root = resolve7(cwd);
|
|
3143
|
+
const resolved = isAbsolute7(rawPath) ? resolve7(rawPath) : resolve7(root, rawPath);
|
|
3144
|
+
const rel = relative7(root, resolved);
|
|
3145
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute7(rel)) return resolved;
|
|
2870
3146
|
return null;
|
|
2871
3147
|
}
|
|
2872
3148
|
function hashContent(s) {
|
|
@@ -2900,11 +3176,22 @@ async function captureFileForHook(path, maxBytes, signal) {
|
|
|
2900
3176
|
return { path, content: null, bytes: 0 };
|
|
2901
3177
|
}
|
|
2902
3178
|
}
|
|
2903
|
-
function
|
|
3179
|
+
function retainedSnapshotBytes() {
|
|
3180
|
+
let total = 0;
|
|
3181
|
+
for (const snap of state9.snapshots) {
|
|
3182
|
+
for (const f of snap.files) total += f.content === null ? 0 : f.content.length;
|
|
3183
|
+
}
|
|
3184
|
+
return total;
|
|
3185
|
+
}
|
|
3186
|
+
function pushSnapshot(snapshot, maxSnapshots, maxTotalBytes) {
|
|
2904
3187
|
state9.snapshots.push(snapshot);
|
|
2905
3188
|
if (state9.snapshots.length > maxSnapshots) {
|
|
2906
3189
|
state9.snapshots.splice(0, state9.snapshots.length - maxSnapshots);
|
|
2907
3190
|
}
|
|
3191
|
+
while (state9.snapshots.length > 1 && retainedSnapshotBytes() > maxTotalBytes) {
|
|
3192
|
+
state9.snapshots.shift();
|
|
3193
|
+
state9.evictedForBytes += 1;
|
|
3194
|
+
}
|
|
2908
3195
|
}
|
|
2909
3196
|
var plugin9 = {
|
|
2910
3197
|
name: "checkpoint",
|
|
@@ -2943,6 +3230,7 @@ var plugin9 = {
|
|
|
2943
3230
|
state9.captures = 0;
|
|
2944
3231
|
state9.restores = 0;
|
|
2945
3232
|
state9.skippedLarge = 0;
|
|
3233
|
+
state9.evictedForBytes = 0;
|
|
2946
3234
|
if (state9.hookUnregister) {
|
|
2947
3235
|
try {
|
|
2948
3236
|
state9.hookUnregister();
|
|
@@ -2970,7 +3258,8 @@ var plugin9 = {
|
|
|
2970
3258
|
origin: `auto:${input.toolName ?? "unknown"}`,
|
|
2971
3259
|
files: [captured]
|
|
2972
3260
|
},
|
|
2973
|
-
cfg.maxSnapshots
|
|
3261
|
+
cfg.maxSnapshots,
|
|
3262
|
+
cfg.maxTotalBytes
|
|
2974
3263
|
);
|
|
2975
3264
|
state9.captures += 1;
|
|
2976
3265
|
api.metrics.counter("captures");
|
|
@@ -3048,7 +3337,7 @@ var plugin9 = {
|
|
|
3048
3337
|
origin: input.label?.trim() ? `manual:${input.label.trim()}` : "manual",
|
|
3049
3338
|
files
|
|
3050
3339
|
};
|
|
3051
|
-
pushSnapshot(snapshot, cfg.maxSnapshots);
|
|
3340
|
+
pushSnapshot(snapshot, cfg.maxSnapshots, cfg.maxTotalBytes);
|
|
3052
3341
|
state9.captures += 1;
|
|
3053
3342
|
api.metrics.counter("captures");
|
|
3054
3343
|
return {
|
|
@@ -3091,7 +3380,9 @@ var plugin9 = {
|
|
|
3091
3380
|
counters: {
|
|
3092
3381
|
captures: state9.captures,
|
|
3093
3382
|
restores: state9.restores,
|
|
3094
|
-
skippedLarge: state9.skippedLarge
|
|
3383
|
+
skippedLarge: state9.skippedLarge,
|
|
3384
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3385
|
+
evictedForBytes: state9.evictedForBytes
|
|
3095
3386
|
}
|
|
3096
3387
|
};
|
|
3097
3388
|
}
|
|
@@ -3134,7 +3425,7 @@ var plugin9 = {
|
|
|
3134
3425
|
continue;
|
|
3135
3426
|
}
|
|
3136
3427
|
try {
|
|
3137
|
-
await mkdir(
|
|
3428
|
+
await mkdir(dirname3(f.path), { recursive: true });
|
|
3138
3429
|
await writeFile(f.path, f.content);
|
|
3139
3430
|
restored.push(f.path);
|
|
3140
3431
|
} catch (err) {
|
|
@@ -3173,13 +3464,16 @@ var plugin9 = {
|
|
|
3173
3464
|
captures: state9.captures,
|
|
3174
3465
|
restores: state9.restores,
|
|
3175
3466
|
skippedLarge: state9.skippedLarge,
|
|
3176
|
-
snapshotsHeld: state9.snapshots.length
|
|
3467
|
+
snapshotsHeld: state9.snapshots.length,
|
|
3468
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3469
|
+
evictedForBytes: state9.evictedForBytes
|
|
3177
3470
|
};
|
|
3178
3471
|
state9.snapshots = [];
|
|
3179
3472
|
state9.nextId = 1;
|
|
3180
3473
|
state9.captures = 0;
|
|
3181
3474
|
state9.restores = 0;
|
|
3182
3475
|
state9.skippedLarge = 0;
|
|
3476
|
+
state9.evictedForBytes = 0;
|
|
3183
3477
|
api.log.info("checkpoint: teardown complete", { final });
|
|
3184
3478
|
},
|
|
3185
3479
|
async health() {
|
|
@@ -3190,7 +3484,11 @@ var plugin9 = {
|
|
|
3190
3484
|
snapshotsHeld: state9.snapshots.length,
|
|
3191
3485
|
captures: state9.captures,
|
|
3192
3486
|
restores: state9.restores,
|
|
3193
|
-
skippedLarge: state9.skippedLarge
|
|
3487
|
+
skippedLarge: state9.skippedLarge,
|
|
3488
|
+
// Retained snapshot bytes: the count-based ring alone does not
|
|
3489
|
+
// bound memory, so surface the number the byte budget acts on.
|
|
3490
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3491
|
+
evictedForBytes: state9.evictedForBytes
|
|
3194
3492
|
}
|
|
3195
3493
|
};
|
|
3196
3494
|
}
|
|
@@ -3199,7 +3497,7 @@ var checkpoint_default = plugin9;
|
|
|
3199
3497
|
|
|
3200
3498
|
// src/code-metrics/index.ts
|
|
3201
3499
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
3202
|
-
import { isAbsolute as
|
|
3500
|
+
import { isAbsolute as isAbsolute8, relative as relative8, resolve as resolve8 } from "node:path";
|
|
3203
3501
|
var API_VERSION6 = "^0.1.10";
|
|
3204
3502
|
var state10 = {
|
|
3205
3503
|
measureCount: 0,
|
|
@@ -3229,7 +3527,7 @@ function toPosix(p) {
|
|
|
3229
3527
|
return p.replace(/\\/g, "/");
|
|
3230
3528
|
}
|
|
3231
3529
|
function relativePath(p) {
|
|
3232
|
-
return toPosix(
|
|
3530
|
+
return toPosix(relative8(process.cwd(), p));
|
|
3233
3531
|
}
|
|
3234
3532
|
function countFunctions(content) {
|
|
3235
3533
|
let count = 0;
|
|
@@ -3306,7 +3604,7 @@ function analyzeFile(filePath, content) {
|
|
|
3306
3604
|
}
|
|
3307
3605
|
async function measurePath(rawPath, cfg) {
|
|
3308
3606
|
const root = process.cwd();
|
|
3309
|
-
const resolved =
|
|
3607
|
+
const resolved = isAbsolute8(rawPath) ? resolve8(rawPath) : resolve8(root, rawPath);
|
|
3310
3608
|
const exts = normalizeExtensions2(cfg.extensions);
|
|
3311
3609
|
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
3312
3610
|
const files = allFiles.slice(0, cfg.maxFiles);
|
|
@@ -3369,7 +3667,7 @@ var plugin10 = {
|
|
|
3369
3667
|
const exts = normalizeExtensions2(cfg.extensions);
|
|
3370
3668
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
3371
3669
|
state10.hookInvocationCount += 1;
|
|
3372
|
-
const resolved =
|
|
3670
|
+
const resolved = resolve8(process.cwd(), sourcePath);
|
|
3373
3671
|
let content;
|
|
3374
3672
|
try {
|
|
3375
3673
|
content = await readFile4(resolved, "utf-8");
|
|
@@ -3413,7 +3711,7 @@ var plugin10 = {
|
|
|
3413
3711
|
state10.fileCount += result.files.length;
|
|
3414
3712
|
return {
|
|
3415
3713
|
ok: true,
|
|
3416
|
-
path: relativePath(
|
|
3714
|
+
path: relativePath(resolve8(process.cwd(), rawPath)),
|
|
3417
3715
|
files: result.files,
|
|
3418
3716
|
totalFiles: result.totalFiles,
|
|
3419
3717
|
capped: result.totalFiles > cfg.maxFiles
|
|
@@ -3601,14 +3899,24 @@ function parseCommitMessage(message, cfg) {
|
|
|
3601
3899
|
errors
|
|
3602
3900
|
};
|
|
3603
3901
|
}
|
|
3902
|
+
var GIT_MESSAGE_FLAG_RE = new RegExp(
|
|
3903
|
+
[
|
|
3904
|
+
// -m "…" | -m '…' | -m=… ; --message "…" | --message='…' | --message=…
|
|
3905
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)"([^"]*)"`,
|
|
3906
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)'([^']*)'`,
|
|
3907
|
+
// Bare value: stops at whitespace or a shell separator.
|
|
3908
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)([^\s;&|"']+)`
|
|
3909
|
+
].join("|"),
|
|
3910
|
+
"g"
|
|
3911
|
+
);
|
|
3604
3912
|
function extractMessageFromBash(command) {
|
|
3605
|
-
const
|
|
3606
|
-
const
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
if (
|
|
3611
|
-
return
|
|
3913
|
+
const parts = [];
|
|
3914
|
+
for (const m of command.matchAll(GIT_MESSAGE_FLAG_RE)) {
|
|
3915
|
+
const value = m[1] ?? m[2] ?? m[3];
|
|
3916
|
+
if (value !== void 0) parts.push(value);
|
|
3917
|
+
}
|
|
3918
|
+
if (parts.length === 0) return null;
|
|
3919
|
+
return parts.join("\n");
|
|
3612
3920
|
}
|
|
3613
3921
|
var plugin11 = {
|
|
3614
3922
|
name: "commit-validator",
|
|
@@ -3859,7 +4167,7 @@ Suggested rewrite (${suggest.model}):
|
|
|
3859
4167
|
var commit_validator_default = plugin11;
|
|
3860
4168
|
|
|
3861
4169
|
// src/config-validator/index.ts
|
|
3862
|
-
import { readFileSync as
|
|
4170
|
+
import { readFileSync as readFileSync5, statSync } from "node:fs";
|
|
3863
4171
|
var state12 = {
|
|
3864
4172
|
invocations: 0,
|
|
3865
4173
|
filesChecked: 0,
|
|
@@ -4121,7 +4429,7 @@ var plugin12 = {
|
|
|
4121
4429
|
let text;
|
|
4122
4430
|
try {
|
|
4123
4431
|
if (statSync(raw).size > cfg.maxFileBytes) return;
|
|
4124
|
-
text =
|
|
4432
|
+
text = readFileSync5(raw, "utf-8");
|
|
4125
4433
|
} catch {
|
|
4126
4434
|
return;
|
|
4127
4435
|
}
|
|
@@ -4205,7 +4513,8 @@ var config_validator_default = plugin12;
|
|
|
4205
4513
|
|
|
4206
4514
|
// src/context-pins/index.ts
|
|
4207
4515
|
import * as fs from "node:fs";
|
|
4208
|
-
import { dirname as
|
|
4516
|
+
import { dirname as dirname4, isAbsolute as isAbsolute9, relative as relative9, resolve as resolve9 } from "node:path";
|
|
4517
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4209
4518
|
var state13 = {
|
|
4210
4519
|
pins: [],
|
|
4211
4520
|
nextId: 1,
|
|
@@ -4222,10 +4531,10 @@ var DEFAULTS11 = {
|
|
|
4222
4531
|
};
|
|
4223
4532
|
function resolveProjectPath4(rawPath, cwd = process.cwd()) {
|
|
4224
4533
|
if (typeof rawPath !== "string" || rawPath.length === 0) return "";
|
|
4225
|
-
const root =
|
|
4226
|
-
const resolved =
|
|
4227
|
-
const rel =
|
|
4228
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
4534
|
+
const root = resolve9(cwd);
|
|
4535
|
+
const resolved = isAbsolute9(rawPath) ? resolve9(rawPath) : resolve9(root, rawPath);
|
|
4536
|
+
const rel = relative9(root, resolved);
|
|
4537
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute9(rel)) return resolved;
|
|
4229
4538
|
return null;
|
|
4230
4539
|
}
|
|
4231
4540
|
function readConfig12(raw) {
|
|
@@ -4252,11 +4561,11 @@ function loadPins(filePath) {
|
|
|
4252
4561
|
return { pins: [], nextId: 1 };
|
|
4253
4562
|
}
|
|
4254
4563
|
}
|
|
4255
|
-
function persistPins(filePath) {
|
|
4564
|
+
async function persistPins(filePath) {
|
|
4256
4565
|
if (!filePath) return true;
|
|
4257
4566
|
try {
|
|
4258
|
-
|
|
4259
|
-
|
|
4567
|
+
await ensureDir(dirname4(filePath));
|
|
4568
|
+
await atomicWrite(filePath, JSON.stringify({ pins: state13.pins, nextId: state13.nextId }, null, 2));
|
|
4260
4569
|
return true;
|
|
4261
4570
|
} catch {
|
|
4262
4571
|
state13.persistErrors += 1;
|
|
@@ -4354,7 +4663,7 @@ var plugin13 = {
|
|
|
4354
4663
|
state13.pins.push(pin);
|
|
4355
4664
|
state13.adds += 1;
|
|
4356
4665
|
api.metrics.counter("adds");
|
|
4357
|
-
const persisted = persistPins(cfg.filePath);
|
|
4666
|
+
const persisted = await persistPins(cfg.filePath);
|
|
4358
4667
|
return { ok: true, pin, persisted, totalPins: state13.pins.length };
|
|
4359
4668
|
}
|
|
4360
4669
|
});
|
|
@@ -4380,7 +4689,7 @@ var plugin13 = {
|
|
|
4380
4689
|
if (removed === 0) return { ok: false, error: `no pin matches "${key}"` };
|
|
4381
4690
|
state13.removals += removed;
|
|
4382
4691
|
api.metrics.counter("removals", removed);
|
|
4383
|
-
const persisted = persistPins(cfg.filePath);
|
|
4692
|
+
const persisted = await persistPins(cfg.filePath);
|
|
4384
4693
|
return { ok: true, removed, persisted, totalPins: state13.pins.length };
|
|
4385
4694
|
}
|
|
4386
4695
|
});
|
|
@@ -4480,7 +4789,7 @@ function readCostTrackerConfig(raw) {
|
|
|
4480
4789
|
mailboxDigestTo: typeof digestTo === "string" && digestTo.length > 0 ? digestTo : "cost-tracker"
|
|
4481
4790
|
};
|
|
4482
4791
|
}
|
|
4483
|
-
var modelKeyCache =
|
|
4792
|
+
var modelKeyCache = new BoundedMap({ max: 256 });
|
|
4484
4793
|
function estimateCost(model, promptTokens, completionTokens) {
|
|
4485
4794
|
let key = modelKeyCache.get(model);
|
|
4486
4795
|
if (!key) {
|
|
@@ -4904,6 +5213,7 @@ var plugin15 = {
|
|
|
4904
5213
|
api.metrics.histogram("cron_job_interval_ms", job.intervalMs, { job: name });
|
|
4905
5214
|
scheduleNextRun(name);
|
|
4906
5215
|
}, delay);
|
|
5216
|
+
timer.unref?.();
|
|
4907
5217
|
state14.timers.set(name, timer);
|
|
4908
5218
|
}
|
|
4909
5219
|
function cancelJob(name) {
|
|
@@ -5089,7 +5399,7 @@ var cron_default = plugin15;
|
|
|
5089
5399
|
|
|
5090
5400
|
// src/dead-code-detector/index.ts
|
|
5091
5401
|
import { readdir, readFile as readFile5, stat as stat2 } from "node:fs/promises";
|
|
5092
|
-
import { extname as
|
|
5402
|
+
import { extname as extname4, join as join2, relative as relative10, resolve as resolve10 } from "node:path";
|
|
5093
5403
|
var API_VERSION10 = "^0.1.10";
|
|
5094
5404
|
var state15 = {
|
|
5095
5405
|
scanCount: 0,
|
|
@@ -5132,17 +5442,17 @@ async function gatherFiles(root, depth, cfg) {
|
|
|
5132
5442
|
for (const entry of entries) {
|
|
5133
5443
|
if (entry.isDirectory()) {
|
|
5134
5444
|
if (remaining > 0 && !excludeSet.has(entry.name)) {
|
|
5135
|
-
await walk(
|
|
5445
|
+
await walk(join2(dir, entry.name), remaining - 1);
|
|
5136
5446
|
}
|
|
5137
5447
|
} else if (entry.isFile()) {
|
|
5138
|
-
const ext =
|
|
5448
|
+
const ext = extname4(entry.name).toLowerCase();
|
|
5139
5449
|
if (cfg.extensions.includes(ext)) {
|
|
5140
|
-
files.push(
|
|
5450
|
+
files.push(join2(dir, entry.name));
|
|
5141
5451
|
}
|
|
5142
5452
|
}
|
|
5143
5453
|
}
|
|
5144
5454
|
}
|
|
5145
|
-
await walk(
|
|
5455
|
+
await walk(resolve10(root), depth);
|
|
5146
5456
|
return files;
|
|
5147
5457
|
}
|
|
5148
5458
|
function stripNoise(content) {
|
|
@@ -5231,11 +5541,11 @@ async function scan(root, depth, cfg) {
|
|
|
5231
5541
|
return { findings: findUnusedSymbols(files), scannedFiles: files.length };
|
|
5232
5542
|
}
|
|
5233
5543
|
async function resolveScanRoot(rawPath) {
|
|
5234
|
-
const resolved =
|
|
5544
|
+
const resolved = resolve10(process.cwd(), rawPath);
|
|
5235
5545
|
try {
|
|
5236
5546
|
const stats = await stat2(resolved);
|
|
5237
5547
|
if (!stats.isDirectory()) {
|
|
5238
|
-
return
|
|
5548
|
+
return resolve10(resolved, "..");
|
|
5239
5549
|
}
|
|
5240
5550
|
} catch {
|
|
5241
5551
|
}
|
|
@@ -5245,7 +5555,7 @@ function toPosix2(p) {
|
|
|
5245
5555
|
return p.replace(/\\/g, "/");
|
|
5246
5556
|
}
|
|
5247
5557
|
function relativePath2(p) {
|
|
5248
|
-
return toPosix2(
|
|
5558
|
+
return toPosix2(relative10(process.cwd(), p));
|
|
5249
5559
|
}
|
|
5250
5560
|
var plugin16 = {
|
|
5251
5561
|
name: "dead-code-detector",
|
|
@@ -5316,8 +5626,8 @@ var plugin16 = {
|
|
|
5316
5626
|
state15.errorCount += 1;
|
|
5317
5627
|
return;
|
|
5318
5628
|
}
|
|
5319
|
-
const changedFile =
|
|
5320
|
-
const relevant = result.findings.filter((f) =>
|
|
5629
|
+
const changedFile = resolve10(process.cwd(), sourcePath);
|
|
5630
|
+
const relevant = result.findings.filter((f) => resolve10(f.file) === changedFile);
|
|
5321
5631
|
if (relevant.length === 0) {
|
|
5322
5632
|
state15.missCount += 1;
|
|
5323
5633
|
return;
|
|
@@ -5910,34 +6220,51 @@ function isInstallCommand(input) {
|
|
|
5910
6220
|
const command = typeof ti["command"] === "string" ? ti["command"] : "";
|
|
5911
6221
|
return INSTALL_RE2.test(command);
|
|
5912
6222
|
}
|
|
6223
|
+
var LOCKFILE_MANAGERS = [
|
|
6224
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
6225
|
+
{ file: "bun.lockb", manager: "bun" },
|
|
6226
|
+
{ file: "bun.lock", manager: "bun" },
|
|
6227
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
6228
|
+
{ file: "package-lock.json", manager: "npm" }
|
|
6229
|
+
];
|
|
5913
6230
|
async function detectManager() {
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
6231
|
+
for (const { file, manager } of LOCKFILE_MANAGERS) {
|
|
6232
|
+
try {
|
|
6233
|
+
await access(file);
|
|
6234
|
+
return manager;
|
|
6235
|
+
} catch {
|
|
6236
|
+
}
|
|
5919
6237
|
}
|
|
6238
|
+
return "npm";
|
|
5920
6239
|
}
|
|
5921
6240
|
async function runAudit(cfg) {
|
|
5922
6241
|
const manager = await detectManager();
|
|
5923
6242
|
const start = Date.now();
|
|
5924
|
-
|
|
6243
|
+
let invocation;
|
|
6244
|
+
try {
|
|
6245
|
+
invocation = resolveExecInvocation(manager, ["audit", "--json"]);
|
|
6246
|
+
} catch {
|
|
6247
|
+
return null;
|
|
6248
|
+
}
|
|
6249
|
+
const stdout = await new Promise((resolve28) => {
|
|
5925
6250
|
execFile4(
|
|
5926
|
-
|
|
5927
|
-
|
|
6251
|
+
invocation.cmd,
|
|
6252
|
+
invocation.args,
|
|
5928
6253
|
{
|
|
5929
6254
|
encoding: "utf8",
|
|
5930
6255
|
timeout: cfg.timeoutMs,
|
|
5931
6256
|
cwd: process.cwd(),
|
|
5932
6257
|
windowsHide: true,
|
|
5933
|
-
maxBuffer: 10 * 1024 * 1024
|
|
6258
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
6259
|
+
shell: false,
|
|
6260
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
5934
6261
|
},
|
|
5935
6262
|
(error, output) => {
|
|
5936
6263
|
if (error && error.killed) {
|
|
5937
|
-
|
|
6264
|
+
resolve28(null);
|
|
5938
6265
|
return;
|
|
5939
6266
|
}
|
|
5940
|
-
|
|
6267
|
+
resolve28(output);
|
|
5941
6268
|
}
|
|
5942
6269
|
);
|
|
5943
6270
|
});
|
|
@@ -6160,7 +6487,7 @@ function contentHash(s) {
|
|
|
6160
6487
|
}
|
|
6161
6488
|
return h >>> 0;
|
|
6162
6489
|
}
|
|
6163
|
-
var pathMemo =
|
|
6490
|
+
var pathMemo = new BoundedMap({ max: 512 });
|
|
6164
6491
|
function runGit2(args, cwd) {
|
|
6165
6492
|
return new Promise((resolveCommand) => {
|
|
6166
6493
|
execFile5(
|
|
@@ -6422,7 +6749,7 @@ var plugin19 = {
|
|
|
6422
6749
|
var diff_summary_default = plugin19;
|
|
6423
6750
|
|
|
6424
6751
|
// src/doc-sync-guard/index.ts
|
|
6425
|
-
import { basename as basename3, extname as
|
|
6752
|
+
import { basename as basename3, extname as extname5 } from "node:path";
|
|
6426
6753
|
var API_VERSION13 = "^0.1.10";
|
|
6427
6754
|
var state19 = {
|
|
6428
6755
|
changedFiles: [],
|
|
@@ -6451,7 +6778,7 @@ function normalizeSlashes(p) {
|
|
|
6451
6778
|
return p.replace(/\\/g, "/");
|
|
6452
6779
|
}
|
|
6453
6780
|
function isSourceFile(p, extensions) {
|
|
6454
|
-
const ext =
|
|
6781
|
+
const ext = extname5(p).toLowerCase();
|
|
6455
6782
|
return extensions.includes(ext);
|
|
6456
6783
|
}
|
|
6457
6784
|
function isPublicSource(p, extensions) {
|
|
@@ -6634,8 +6961,9 @@ var doc_sync_guard_default = plugin20;
|
|
|
6634
6961
|
|
|
6635
6962
|
// src/duplicate-code-detector/index.ts
|
|
6636
6963
|
import { readFile as readFile6, realpath, stat as stat3 } from "node:fs/promises";
|
|
6637
|
-
import { isAbsolute as
|
|
6964
|
+
import { isAbsolute as isAbsolute10, relative as relative11, resolve as resolve11, sep as sep2 } from "node:path";
|
|
6638
6965
|
var API_VERSION14 = "^0.1.10";
|
|
6966
|
+
var HOOK_WARNING_COOLDOWN_MS = 6e4;
|
|
6639
6967
|
var state20 = {
|
|
6640
6968
|
scanCount: 0,
|
|
6641
6969
|
findingCount: 0,
|
|
@@ -6643,7 +6971,7 @@ var state20 = {
|
|
|
6643
6971
|
warningCount: 0,
|
|
6644
6972
|
errorCount: 0,
|
|
6645
6973
|
hookUnregister: null,
|
|
6646
|
-
lastHookWarning:
|
|
6974
|
+
lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS }),
|
|
6647
6975
|
fileIndex: /* @__PURE__ */ new Map(),
|
|
6648
6976
|
inFlightFingerprintReads: /* @__PURE__ */ new Map(),
|
|
6649
6977
|
indexFingerprintCount: 0,
|
|
@@ -6690,14 +7018,14 @@ function readConfig18(raw) {
|
|
|
6690
7018
|
};
|
|
6691
7019
|
}
|
|
6692
7020
|
function isWithinRoot(projectRoot, candidate) {
|
|
6693
|
-
const rel =
|
|
6694
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
7021
|
+
const rel = relative11(projectRoot, candidate);
|
|
7022
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute10(rel);
|
|
6695
7023
|
}
|
|
6696
7024
|
function toPosix3(p) {
|
|
6697
7025
|
return p.replace(/\\/g, "/");
|
|
6698
7026
|
}
|
|
6699
7027
|
function relativePath3(p) {
|
|
6700
|
-
return toPosix3(
|
|
7028
|
+
return toPosix3(relative11(process.cwd(), p));
|
|
6701
7029
|
}
|
|
6702
7030
|
function removeInlineComments(line) {
|
|
6703
7031
|
return line.replace(/\/\/.*$/, "").replace(/\/\*[\s\S]*?\*\//, "");
|
|
@@ -6789,7 +7117,7 @@ function findDuplicates(files, minLines, maxFindings) {
|
|
|
6789
7117
|
}
|
|
6790
7118
|
async function scanPath(rawPath, cfg) {
|
|
6791
7119
|
const root = process.cwd();
|
|
6792
|
-
const resolved =
|
|
7120
|
+
const resolved = isAbsolute10(rawPath) ? resolve11(rawPath) : resolve11(root, rawPath);
|
|
6793
7121
|
const filePaths = await collectSourceFilesAsync(resolved, {
|
|
6794
7122
|
extensions: cfg.extensions,
|
|
6795
7123
|
excludeDirs: cfg.excludeDirs
|
|
@@ -6917,8 +7245,8 @@ var plugin21 = {
|
|
|
6917
7245
|
const inp = input.toolInput ?? {};
|
|
6918
7246
|
const sourcePath = inp["path"];
|
|
6919
7247
|
if (!sourcePath || typeof sourcePath !== "string") return;
|
|
6920
|
-
const projectRoot =
|
|
6921
|
-
const resolvedFile =
|
|
7248
|
+
const projectRoot = resolve11(process.cwd());
|
|
7249
|
+
const resolvedFile = isAbsolute10(sourcePath) ? resolve11(sourcePath) : resolve11(projectRoot, sourcePath);
|
|
6922
7250
|
if (!isWithinRoot(projectRoot, resolvedFile)) return;
|
|
6923
7251
|
let changedFile;
|
|
6924
7252
|
try {
|
|
@@ -6933,7 +7261,7 @@ var plugin21 = {
|
|
|
6933
7261
|
state20.hookInvocationCount += 1;
|
|
6934
7262
|
const now = Date.now();
|
|
6935
7263
|
const lastWarning = state20.lastHookWarning.get(changedFile);
|
|
6936
|
-
if (lastWarning !== void 0 && now - lastWarning <
|
|
7264
|
+
if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS) return;
|
|
6937
7265
|
const changedFps = await readCachedFingerprints(changedFile, cfg.minLines);
|
|
6938
7266
|
if (changedFps === null) {
|
|
6939
7267
|
state20.errorCount += 1;
|
|
@@ -6952,7 +7280,7 @@ var plugin21 = {
|
|
|
6952
7280
|
}
|
|
6953
7281
|
const matched = /* @__PURE__ */ new Set();
|
|
6954
7282
|
for (const p of otherFilePaths) {
|
|
6955
|
-
if (
|
|
7283
|
+
if (resolve11(p) === resolve11(changedFile)) continue;
|
|
6956
7284
|
const otherFps = await readCachedFingerprints(p, cfg.minLines);
|
|
6957
7285
|
if (otherFps === null || otherFps.size === 0) continue;
|
|
6958
7286
|
for (const fp of changedFps) {
|
|
@@ -6998,7 +7326,7 @@ var plugin21 = {
|
|
|
6998
7326
|
state20.findingCount += result.findings.length;
|
|
6999
7327
|
return {
|
|
7000
7328
|
ok: true,
|
|
7001
|
-
path: relativePath3(
|
|
7329
|
+
path: relativePath3(resolve11(process.cwd(), rawPath)),
|
|
7002
7330
|
scannedFiles: result.scannedFiles,
|
|
7003
7331
|
minLines: cfg.minLines,
|
|
7004
7332
|
findings: result.findings
|
|
@@ -7373,7 +7701,7 @@ var error_lens_default = plugin22;
|
|
|
7373
7701
|
|
|
7374
7702
|
// src/feature-flag-tracker/index.ts
|
|
7375
7703
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
7376
|
-
import { isAbsolute as
|
|
7704
|
+
import { isAbsolute as isAbsolute11, relative as relative12, resolve as resolve12 } from "node:path";
|
|
7377
7705
|
var API_VERSION15 = "^0.1.10";
|
|
7378
7706
|
var state22 = {
|
|
7379
7707
|
scanCount: 0,
|
|
@@ -7412,11 +7740,17 @@ function toPosix4(p) {
|
|
|
7412
7740
|
return p.replace(/\\/g, "/");
|
|
7413
7741
|
}
|
|
7414
7742
|
function relativePath4(p) {
|
|
7415
|
-
return toPosix4(
|
|
7743
|
+
return toPosix4(relative12(process.cwd(), p));
|
|
7416
7744
|
}
|
|
7417
7745
|
function compilePatterns(patterns) {
|
|
7418
|
-
const
|
|
7419
|
-
|
|
7746
|
+
const out = [];
|
|
7747
|
+
for (const src of [...DEFAULT_PATTERNS2, ...patterns]) {
|
|
7748
|
+
try {
|
|
7749
|
+
out.push(new RegExp(src, "g"));
|
|
7750
|
+
} catch {
|
|
7751
|
+
}
|
|
7752
|
+
}
|
|
7753
|
+
return out;
|
|
7420
7754
|
}
|
|
7421
7755
|
function scanFile(filePath, content, patterns, maxFindings) {
|
|
7422
7756
|
const usages = [];
|
|
@@ -7442,20 +7776,31 @@ function scanFile(filePath, content, patterns, maxFindings) {
|
|
|
7442
7776
|
}
|
|
7443
7777
|
async function scanPath2(rawPath, cfg) {
|
|
7444
7778
|
const root = process.cwd();
|
|
7445
|
-
const resolved =
|
|
7779
|
+
const resolved = isAbsolute11(rawPath) ? resolve12(rawPath) : resolve12(root, rawPath);
|
|
7446
7780
|
const exts = normalizeExtensions3(cfg.extensions);
|
|
7447
7781
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
7448
7782
|
const patterns = compilePatterns(cfg.patterns);
|
|
7449
7783
|
const usages = [];
|
|
7784
|
+
let scannedFiles = 0;
|
|
7785
|
+
let truncated = false;
|
|
7450
7786
|
for (const p of files) {
|
|
7451
7787
|
try {
|
|
7452
7788
|
const content = await readFile7(p, "utf-8");
|
|
7789
|
+
scannedFiles += 1;
|
|
7453
7790
|
usages.push(...scanFile(p, content, patterns, cfg.maxFindings));
|
|
7454
|
-
if (usages.length >= cfg.maxFindings)
|
|
7791
|
+
if (usages.length >= cfg.maxFindings) {
|
|
7792
|
+
truncated = scannedFiles < files.length;
|
|
7793
|
+
break;
|
|
7794
|
+
}
|
|
7455
7795
|
} catch {
|
|
7456
7796
|
}
|
|
7457
7797
|
}
|
|
7458
|
-
return {
|
|
7798
|
+
return {
|
|
7799
|
+
usages: usages.slice(0, cfg.maxFindings),
|
|
7800
|
+
scannedFiles,
|
|
7801
|
+
discoveredFiles: files.length,
|
|
7802
|
+
truncated
|
|
7803
|
+
};
|
|
7459
7804
|
}
|
|
7460
7805
|
var plugin23 = {
|
|
7461
7806
|
name: "feature-flag-tracker",
|
|
@@ -7513,7 +7858,7 @@ var plugin23 = {
|
|
|
7513
7858
|
const exts = normalizeExtensions3(cfg.extensions);
|
|
7514
7859
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
7515
7860
|
state22.hookInvocationCount += 1;
|
|
7516
|
-
const resolved =
|
|
7861
|
+
const resolved = resolve12(process.cwd(), sourcePath);
|
|
7517
7862
|
let content;
|
|
7518
7863
|
try {
|
|
7519
7864
|
content = await readFile7(resolved, "utf-8");
|
|
@@ -7562,8 +7907,12 @@ Make sure flag behavior is intentional and consider updating flag inventory/docs
|
|
|
7562
7907
|
state22.flagCount += result.usages.length;
|
|
7563
7908
|
return {
|
|
7564
7909
|
ok: true,
|
|
7565
|
-
path: relativePath4(
|
|
7910
|
+
path: relativePath4(resolve12(process.cwd(), rawPath)),
|
|
7566
7911
|
scannedFiles: result.scannedFiles,
|
|
7912
|
+
discoveredFiles: result.discoveredFiles,
|
|
7913
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
7914
|
+
// that reports few findings must not read as a clean result.
|
|
7915
|
+
truncated: result.truncated,
|
|
7567
7916
|
usages: result.usages
|
|
7568
7917
|
};
|
|
7569
7918
|
}
|
|
@@ -7638,16 +7987,16 @@ var feature_flag_tracker_default = plugin23;
|
|
|
7638
7987
|
|
|
7639
7988
|
// src/file-watcher/index.ts
|
|
7640
7989
|
import { watch as fsWatch } from "node:fs";
|
|
7641
|
-
import { isAbsolute as
|
|
7990
|
+
import { isAbsolute as isAbsolute12, join as join3, relative as relative13, resolve as resolve13 } from "node:path";
|
|
7642
7991
|
var API_VERSION16 = "^0.1.10";
|
|
7643
7992
|
function withinProject3(p) {
|
|
7644
7993
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
7645
7994
|
const root = process.cwd();
|
|
7646
|
-
const resolved =
|
|
7647
|
-
const rel =
|
|
7995
|
+
const resolved = isAbsolute12(p) ? resolve13(p) : resolve13(root, p);
|
|
7996
|
+
const rel = relative13(root, resolved);
|
|
7648
7997
|
if (rel === "" || rel === ".") return true;
|
|
7649
7998
|
if (rel.startsWith("..")) return false;
|
|
7650
|
-
if (
|
|
7999
|
+
if (isAbsolute12(rel)) return false;
|
|
7651
8000
|
return true;
|
|
7652
8001
|
}
|
|
7653
8002
|
var watch_idCounter = 0;
|
|
@@ -7718,13 +8067,12 @@ var plugin24 = {
|
|
|
7718
8067
|
function debounceEvent(key, fn, ms) {
|
|
7719
8068
|
const existing = debounceTimers.get(key);
|
|
7720
8069
|
if (existing) clearTimeout(existing);
|
|
7721
|
-
|
|
7722
|
-
key
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
);
|
|
8070
|
+
const timer = setTimeout(() => {
|
|
8071
|
+
debounceTimers.delete(key);
|
|
8072
|
+
fn();
|
|
8073
|
+
}, ms);
|
|
8074
|
+
timer.unref?.();
|
|
8075
|
+
debounceTimers.set(key, timer);
|
|
7728
8076
|
}
|
|
7729
8077
|
const autoIndex = api.config.extensions?.["file-watcher"]?.["autoIndex"] ?? false;
|
|
7730
8078
|
const indexProjectRoot = api.config.extensions?.["file-watcher"]?.["indexProjectRoot"] ?? "";
|
|
@@ -7750,7 +8098,7 @@ var plugin24 = {
|
|
|
7750
8098
|
if (handle.events.length > 0 && !(eventType === "change" ? handle.events.includes("change") : handle.events.includes("add") || handle.events.includes("delete"))) {
|
|
7751
8099
|
return;
|
|
7752
8100
|
}
|
|
7753
|
-
const rawPath = filename.startsWith(dirPath) ? filename :
|
|
8101
|
+
const rawPath = filename.startsWith(dirPath) ? filename : join3(dirPath, filename);
|
|
7754
8102
|
const fullPath = rawPath.replace(/\\/g, "/");
|
|
7755
8103
|
const key = `${handle.id}:${fullPath}:${eventType}`;
|
|
7756
8104
|
debounceEvent(
|
|
@@ -7970,7 +8318,8 @@ var file_watcher_default = plugin24;
|
|
|
7970
8318
|
|
|
7971
8319
|
// src/format-on-save/index.ts
|
|
7972
8320
|
import { execFile as execFile6 } from "node:child_process";
|
|
7973
|
-
import {
|
|
8321
|
+
import { createHash } from "node:crypto";
|
|
8322
|
+
import { access as access2, readFile as readFile8, stat as stat4 } from "node:fs/promises";
|
|
7974
8323
|
var API_VERSION17 = "^0.1.10";
|
|
7975
8324
|
var state23 = {
|
|
7976
8325
|
invocationCount: 0,
|
|
@@ -8006,7 +8355,7 @@ function readConfig21(raw) {
|
|
|
8006
8355
|
skipTtlMs: typeof r["skipTtlMs"] === "number" && r["skipTtlMs"] >= 0 ? r["skipTtlMs"] : DEFAULTS20.skipTtlMs
|
|
8007
8356
|
};
|
|
8008
8357
|
}
|
|
8009
|
-
var recentlyCovered =
|
|
8358
|
+
var recentlyCovered = new BoundedMap({ max: 256 });
|
|
8010
8359
|
function clearRegistrations() {
|
|
8011
8360
|
if (state23.hookUnregister) {
|
|
8012
8361
|
try {
|
|
@@ -8029,6 +8378,55 @@ function evictExpired(ttlMs) {
|
|
|
8029
8378
|
if (ts < cutoff) recentlyCovered.delete(path);
|
|
8030
8379
|
}
|
|
8031
8380
|
}
|
|
8381
|
+
var FORMATTERS = [
|
|
8382
|
+
{
|
|
8383
|
+
packageName: "@biomejs/biome",
|
|
8384
|
+
binName: "biome",
|
|
8385
|
+
writeArgs: ["format", "--write"],
|
|
8386
|
+
label: "biome"
|
|
8387
|
+
},
|
|
8388
|
+
{ packageName: "prettier", binName: "prettier", writeArgs: ["--write"], label: "prettier" },
|
|
8389
|
+
{ packageName: "dprint", binName: "dprint", writeArgs: ["fmt"], label: "dprint" }
|
|
8390
|
+
];
|
|
8391
|
+
var activeFormatter;
|
|
8392
|
+
function resetFormatter() {
|
|
8393
|
+
activeFormatter = void 0;
|
|
8394
|
+
clearLocalBinCache();
|
|
8395
|
+
}
|
|
8396
|
+
function resolveFormatter() {
|
|
8397
|
+
if (activeFormatter !== void 0) return activeFormatter;
|
|
8398
|
+
const cwd = process.cwd();
|
|
8399
|
+
for (const f of FORMATTERS) {
|
|
8400
|
+
const local = resolveNodeBinFor(f, cwd);
|
|
8401
|
+
if (local) {
|
|
8402
|
+
activeFormatter = local;
|
|
8403
|
+
return local;
|
|
8404
|
+
}
|
|
8405
|
+
}
|
|
8406
|
+
for (const f of FORMATTERS) {
|
|
8407
|
+
const onPath = findOnPath(f.binName);
|
|
8408
|
+
if (!onPath) continue;
|
|
8409
|
+
activeFormatter = { cmd: onPath, args: [...f.writeArgs], label: f.label };
|
|
8410
|
+
return activeFormatter;
|
|
8411
|
+
}
|
|
8412
|
+
activeFormatter = null;
|
|
8413
|
+
return null;
|
|
8414
|
+
}
|
|
8415
|
+
function resolveNodeBinFor(f, cwd) {
|
|
8416
|
+
const hit = resolveFirstNodeBin([{ packageName: f.packageName, binName: f.binName }], cwd);
|
|
8417
|
+
if (!hit) return null;
|
|
8418
|
+
return { cmd: hit.cmd, args: [...hit.args, ...f.writeArgs], label: f.label };
|
|
8419
|
+
}
|
|
8420
|
+
function activeFormatterLabel() {
|
|
8421
|
+
return activeFormatter?.label ?? null;
|
|
8422
|
+
}
|
|
8423
|
+
async function sha256File(filePath) {
|
|
8424
|
+
try {
|
|
8425
|
+
return createHash("sha256").update(await readFile8(filePath)).digest("hex");
|
|
8426
|
+
} catch {
|
|
8427
|
+
return null;
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8032
8430
|
async function formatFile(filePath, timeoutMs) {
|
|
8033
8431
|
if (!withinProject(filePath)) return null;
|
|
8034
8432
|
try {
|
|
@@ -8036,30 +8434,40 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
8036
8434
|
} catch {
|
|
8037
8435
|
return null;
|
|
8038
8436
|
}
|
|
8437
|
+
const formatter = resolveFormatter();
|
|
8438
|
+
if (!formatter) return null;
|
|
8039
8439
|
let bytesBefore;
|
|
8040
8440
|
try {
|
|
8041
8441
|
bytesBefore = (await stat4(filePath)).size;
|
|
8042
8442
|
} catch {
|
|
8043
8443
|
return null;
|
|
8044
8444
|
}
|
|
8445
|
+
const hashBefore = await sha256File(filePath);
|
|
8446
|
+
let invocation;
|
|
8045
8447
|
try {
|
|
8046
|
-
|
|
8448
|
+
invocation = resolveExecInvocation(formatter.cmd, [...formatter.args, filePath]);
|
|
8449
|
+
} catch {
|
|
8450
|
+
return null;
|
|
8451
|
+
}
|
|
8452
|
+
try {
|
|
8453
|
+
await new Promise((resolve28, reject) => {
|
|
8047
8454
|
execFile6(
|
|
8048
|
-
|
|
8049
|
-
|
|
8455
|
+
invocation.cmd,
|
|
8456
|
+
invocation.args,
|
|
8050
8457
|
{
|
|
8051
8458
|
encoding: "utf-8",
|
|
8052
8459
|
timeout: timeoutMs,
|
|
8053
8460
|
cwd: process.cwd(),
|
|
8054
8461
|
windowsHide: true,
|
|
8055
|
-
maxBuffer: 16 * 1024 * 1024
|
|
8462
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
8463
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
8056
8464
|
},
|
|
8057
8465
|
(err) => {
|
|
8058
8466
|
if (err) {
|
|
8059
8467
|
const e = err;
|
|
8060
8468
|
if (e.killed) return reject(err);
|
|
8061
8469
|
}
|
|
8062
|
-
|
|
8470
|
+
resolve28();
|
|
8063
8471
|
}
|
|
8064
8472
|
);
|
|
8065
8473
|
});
|
|
@@ -8075,28 +8483,11 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
8075
8483
|
if (bytesAfter !== bytesBefore) {
|
|
8076
8484
|
return { changed: true, bytesBefore, bytesAfter };
|
|
8077
8485
|
}
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
execFile6(
|
|
8081
|
-
"npx",
|
|
8082
|
-
["biome", "format", filePath],
|
|
8083
|
-
{
|
|
8084
|
-
encoding: "utf-8",
|
|
8085
|
-
timeout: timeoutMs,
|
|
8086
|
-
cwd: process.cwd(),
|
|
8087
|
-
windowsHide: true,
|
|
8088
|
-
maxBuffer: 16 * 1024 * 1024
|
|
8089
|
-
},
|
|
8090
|
-
(err) => {
|
|
8091
|
-
if (err) return reject(err);
|
|
8092
|
-
resolve27();
|
|
8093
|
-
}
|
|
8094
|
-
);
|
|
8095
|
-
});
|
|
8486
|
+
const hashAfter = await sha256File(filePath);
|
|
8487
|
+
if (hashBefore === null || hashAfter === null) {
|
|
8096
8488
|
return { changed: false, bytesBefore, bytesAfter };
|
|
8097
|
-
} catch {
|
|
8098
|
-
return { changed: true, bytesBefore, bytesAfter };
|
|
8099
8489
|
}
|
|
8490
|
+
return { changed: hashBefore !== hashAfter, bytesBefore, bytesAfter };
|
|
8100
8491
|
}
|
|
8101
8492
|
var plugin25 = {
|
|
8102
8493
|
name: "format-on-save",
|
|
@@ -8142,32 +8533,18 @@ var plugin25 = {
|
|
|
8142
8533
|
state23.lastResult = null;
|
|
8143
8534
|
recentlyCovered.clear();
|
|
8144
8535
|
const cfg = readConfig21(api.config.extensions?.["format-on-save"]);
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
cwd: process.cwd(),
|
|
8155
|
-
windowsHide: true
|
|
8156
|
-
},
|
|
8157
|
-
(err) => {
|
|
8158
|
-
if (err) reject(err);
|
|
8159
|
-
else resolve27();
|
|
8160
|
-
}
|
|
8161
|
-
);
|
|
8162
|
-
});
|
|
8163
|
-
biomeAvailable = true;
|
|
8164
|
-
api.log.info("format-on-save: biome detected");
|
|
8165
|
-
} catch {
|
|
8166
|
-
biomeAvailable = false;
|
|
8167
|
-
api.log.warn("format-on-save: biome not found \u2014 hook will be a no-op");
|
|
8536
|
+
resetFormatter();
|
|
8537
|
+
const formatter = resolveFormatter();
|
|
8538
|
+
const formatterAvailable = formatter !== null;
|
|
8539
|
+
if (formatter) {
|
|
8540
|
+
api.log.info(`format-on-save: ${formatter.label} detected`);
|
|
8541
|
+
} else {
|
|
8542
|
+
api.log.warn(
|
|
8543
|
+
"format-on-save: no formatter found (biome, prettier, dprint) \u2014 hook will be a no-op"
|
|
8544
|
+
);
|
|
8168
8545
|
}
|
|
8169
8546
|
const hook = async (input) => {
|
|
8170
|
-
if (!cfg.enabled || !
|
|
8547
|
+
if (!cfg.enabled || !formatterAvailable) return;
|
|
8171
8548
|
if (input.toolResult?.isError) return;
|
|
8172
8549
|
const toolName = input.toolName ?? "";
|
|
8173
8550
|
const inp = input.toolInput ?? {};
|
|
@@ -8228,7 +8605,7 @@ var plugin25 = {
|
|
|
8228
8605
|
);
|
|
8229
8606
|
api.tools.register({
|
|
8230
8607
|
name: "format_on_save_status",
|
|
8231
|
-
description: "Reports format-on-save state:
|
|
8608
|
+
description: "Reports format-on-save state: which formatter is active, and per-session formatted/clean/error/skipped counters.",
|
|
8232
8609
|
inputSchema: { type: "object", properties: {} },
|
|
8233
8610
|
permission: "auto",
|
|
8234
8611
|
category: "Code Quality",
|
|
@@ -8237,7 +8614,14 @@ var plugin25 = {
|
|
|
8237
8614
|
return {
|
|
8238
8615
|
ok: true,
|
|
8239
8616
|
enabled: cfg.enabled,
|
|
8240
|
-
|
|
8617
|
+
formatterAvailable,
|
|
8618
|
+
formatter: activeFormatterLabel(),
|
|
8619
|
+
/**
|
|
8620
|
+
* Back-compat alias for the pre-multi-formatter status shape.
|
|
8621
|
+
* Now accurate rather than assumed: true only when the resolved
|
|
8622
|
+
* formatter really is biome.
|
|
8623
|
+
*/
|
|
8624
|
+
biomeAvailable: activeFormatterLabel() === "biome",
|
|
8241
8625
|
timeoutMs: cfg.timeoutMs,
|
|
8242
8626
|
skipWhenCoveredBy: cfg.skipWhenCoveredBy,
|
|
8243
8627
|
skipTtlMs: cfg.skipTtlMs,
|
|
@@ -8255,11 +8639,13 @@ var plugin25 = {
|
|
|
8255
8639
|
api.log.info("format-on-save plugin loaded", {
|
|
8256
8640
|
version: "0.1.0",
|
|
8257
8641
|
enabled: cfg.enabled,
|
|
8258
|
-
|
|
8642
|
+
formatterAvailable,
|
|
8643
|
+
formatter: activeFormatterLabel()
|
|
8259
8644
|
});
|
|
8260
8645
|
},
|
|
8261
8646
|
teardown(api) {
|
|
8262
8647
|
clearRegistrations();
|
|
8648
|
+
resetFormatter();
|
|
8263
8649
|
const final = {
|
|
8264
8650
|
invocations: state23.invocationCount,
|
|
8265
8651
|
formatted: state23.formattedCount,
|
|
@@ -8768,7 +9154,7 @@ var git_autocommit_default = plugin26;
|
|
|
8768
9154
|
// src/import-organizer/index.ts
|
|
8769
9155
|
import { spawn } from "node:child_process";
|
|
8770
9156
|
import { existsSync as existsSync3, statSync as statSync2 } from "node:fs";
|
|
8771
|
-
import { basename as basename4, isAbsolute as
|
|
9157
|
+
import { basename as basename4, isAbsolute as isAbsolute13 } from "node:path";
|
|
8772
9158
|
var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
8773
9159
|
"npx",
|
|
8774
9160
|
"pnpm",
|
|
@@ -8777,23 +9163,51 @@ var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
|
8777
9163
|
"biome",
|
|
8778
9164
|
"@biomejs/biome",
|
|
8779
9165
|
"eslint",
|
|
9166
|
+
"oxlint",
|
|
8780
9167
|
"node"
|
|
8781
9168
|
// Recognise a fully-qualified project-local path like
|
|
8782
9169
|
// "./node_modules/.bin/biome"; basename check kicks in below.
|
|
8783
9170
|
]);
|
|
9171
|
+
var PACKAGE_RUNNERS = /* @__PURE__ */ new Set(["npx", "pnpm", "npm", "yarn"]);
|
|
9172
|
+
var LOCAL_BIN_PACKAGES = {
|
|
9173
|
+
biome: { packageName: "@biomejs/biome", binName: "biome" },
|
|
9174
|
+
"@biomejs/biome": { packageName: "@biomejs/biome", binName: "biome" },
|
|
9175
|
+
eslint: { packageName: "eslint", binName: "eslint" },
|
|
9176
|
+
oxlint: { packageName: "oxlint", binName: "oxlint" }
|
|
9177
|
+
};
|
|
9178
|
+
function resolveLocalToolCommand(tokens) {
|
|
9179
|
+
if (tokens.length === 0) return null;
|
|
9180
|
+
let i = 0;
|
|
9181
|
+
if (PACKAGE_RUNNERS.has(tokens[i])) {
|
|
9182
|
+
i++;
|
|
9183
|
+
while (i < tokens.length && (tokens[i] === "exec" || tokens[i] === "dlx" || tokens[i] === "run")) {
|
|
9184
|
+
i++;
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
9187
|
+
const toolToken = tokens[i];
|
|
9188
|
+
if (!toolToken) return null;
|
|
9189
|
+
const rest = tokens.slice(i + 1);
|
|
9190
|
+
const pkg = LOCAL_BIN_PACKAGES[toolToken];
|
|
9191
|
+
if (!pkg) return null;
|
|
9192
|
+
const local = resolveNodeBin(pkg.packageName, pkg.binName, process.cwd(), rest);
|
|
9193
|
+
if (!local) return null;
|
|
9194
|
+
return { cmd: local.cmd, args: local.args };
|
|
9195
|
+
}
|
|
8784
9196
|
function resolveAllowedCommand(command) {
|
|
8785
9197
|
const tokens = command.split(/\s+/).filter(Boolean);
|
|
8786
9198
|
if (tokens.length === 0) return null;
|
|
8787
9199
|
const head = tokens[0];
|
|
9200
|
+
const local = ALLOWED_FIRST_TOKENS.has(head) ? resolveLocalToolCommand(tokens) : null;
|
|
9201
|
+
if (local) return local;
|
|
8788
9202
|
if (ALLOWED_FIRST_TOKENS.has(head)) {
|
|
8789
9203
|
return { cmd: head, args: tokens.slice(1) };
|
|
8790
9204
|
}
|
|
8791
|
-
if (
|
|
9205
|
+
if (isAbsolute13(head)) {
|
|
8792
9206
|
if (!withinProject(head)) return null;
|
|
8793
9207
|
const base = basename4(head);
|
|
8794
9208
|
if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
|
|
8795
9209
|
}
|
|
8796
|
-
if (!
|
|
9210
|
+
if (!isAbsolute13(head) && withinProject(head)) {
|
|
8797
9211
|
const base = basename4(head);
|
|
8798
9212
|
if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
|
|
8799
9213
|
}
|
|
@@ -8828,40 +9242,70 @@ function readConfig22(raw) {
|
|
|
8828
9242
|
notifyFormatOnSave: r["notifyFormatOnSave"] !== false
|
|
8829
9243
|
};
|
|
8830
9244
|
}
|
|
9245
|
+
var MAX_CAPTURE_BYTES = 4 * 1024 * 1024;
|
|
8831
9246
|
function runCommand(command, args, timeoutMs, cwd) {
|
|
8832
|
-
return new Promise((
|
|
9247
|
+
return new Promise((resolve28) => {
|
|
8833
9248
|
let timedOut = false;
|
|
9249
|
+
let settled = false;
|
|
9250
|
+
const settle = (r) => {
|
|
9251
|
+
if (settled) return;
|
|
9252
|
+
settled = true;
|
|
9253
|
+
resolve28(r);
|
|
9254
|
+
};
|
|
8834
9255
|
const stdoutChunks = [];
|
|
8835
9256
|
const stderrChunks = [];
|
|
9257
|
+
let stdoutBytes = 0;
|
|
9258
|
+
let stderrBytes = 0;
|
|
9259
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
9260
|
+
const onAbort = () => {
|
|
9261
|
+
timedOut = true;
|
|
9262
|
+
settle({ code: null, stdout: "", stderr: "", timedOut: true });
|
|
9263
|
+
};
|
|
9264
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8836
9265
|
let child;
|
|
9266
|
+
let invocation;
|
|
9267
|
+
try {
|
|
9268
|
+
invocation = resolveExecInvocation(command, args);
|
|
9269
|
+
} catch {
|
|
9270
|
+
signal.removeEventListener("abort", onAbort);
|
|
9271
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
9272
|
+
return;
|
|
9273
|
+
}
|
|
8837
9274
|
try {
|
|
8838
|
-
child = spawn(
|
|
9275
|
+
child = spawn(invocation.cmd, invocation.args, {
|
|
8839
9276
|
cwd,
|
|
8840
9277
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8841
|
-
signal
|
|
9278
|
+
signal,
|
|
9279
|
+
windowsHide: true,
|
|
9280
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
8842
9281
|
});
|
|
8843
9282
|
} catch {
|
|
8844
|
-
|
|
9283
|
+
signal.removeEventListener("abort", onAbort);
|
|
9284
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
8845
9285
|
return;
|
|
8846
9286
|
}
|
|
8847
|
-
child.stdout?.on("data", (c) =>
|
|
8848
|
-
|
|
9287
|
+
child.stdout?.on("data", (c) => {
|
|
9288
|
+
stdoutBytes += c.length;
|
|
9289
|
+
if (stdoutBytes <= MAX_CAPTURE_BYTES) stdoutChunks.push(c);
|
|
9290
|
+
});
|
|
9291
|
+
child.stderr?.on("data", (c) => {
|
|
9292
|
+
stderrBytes += c.length;
|
|
9293
|
+
if (stderrBytes <= MAX_CAPTURE_BYTES) stderrChunks.push(c);
|
|
9294
|
+
});
|
|
8849
9295
|
child.on("error", () => {
|
|
8850
|
-
|
|
9296
|
+
signal.removeEventListener("abort", onAbort);
|
|
9297
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
8851
9298
|
});
|
|
8852
9299
|
child.on("close", (code) => {
|
|
9300
|
+
signal.removeEventListener("abort", onAbort);
|
|
8853
9301
|
if (timedOut) return;
|
|
8854
|
-
|
|
9302
|
+
settle({
|
|
8855
9303
|
code,
|
|
8856
9304
|
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
8857
9305
|
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
8858
9306
|
timedOut: false
|
|
8859
9307
|
});
|
|
8860
9308
|
});
|
|
8861
|
-
child.on("abort", () => {
|
|
8862
|
-
timedOut = true;
|
|
8863
|
-
resolve27({ code: null, stdout: "", stderr: "", timedOut: true });
|
|
8864
|
-
});
|
|
8865
9309
|
});
|
|
8866
9310
|
}
|
|
8867
9311
|
async function organizeImports(filePath, cfg, cwd) {
|
|
@@ -9292,8 +9736,8 @@ var plugin28 = {
|
|
|
9292
9736
|
var injection_shield_default = plugin28;
|
|
9293
9737
|
|
|
9294
9738
|
// src/interface-contract-guard/index.ts
|
|
9295
|
-
import { readFile as
|
|
9296
|
-
import { isAbsolute as
|
|
9739
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
9740
|
+
import { isAbsolute as isAbsolute14, relative as relative14, resolve as resolve14 } from "node:path";
|
|
9297
9741
|
var API_VERSION20 = "^0.1.10";
|
|
9298
9742
|
var state26 = {
|
|
9299
9743
|
scanCount: 0,
|
|
@@ -9306,7 +9750,8 @@ var state26 = {
|
|
|
9306
9750
|
var DEFAULTS23 = {
|
|
9307
9751
|
enabled: false,
|
|
9308
9752
|
extensions: [".ts", ".tsx"],
|
|
9309
|
-
maxFindings: 50
|
|
9753
|
+
maxFindings: 50,
|
|
9754
|
+
maxFiles: 2e3
|
|
9310
9755
|
};
|
|
9311
9756
|
function readConfig24(raw) {
|
|
9312
9757
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS23 };
|
|
@@ -9314,7 +9759,8 @@ function readConfig24(raw) {
|
|
|
9314
9759
|
return {
|
|
9315
9760
|
enabled: r["enabled"] !== false,
|
|
9316
9761
|
extensions: Array.isArray(r["extensions"]) ? r["extensions"].filter((x) => typeof x === "string") : DEFAULTS23.extensions,
|
|
9317
|
-
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS23.maxFindings
|
|
9762
|
+
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS23.maxFindings,
|
|
9763
|
+
maxFiles: typeof r["maxFiles"] === "number" && r["maxFiles"] >= 1 && r["maxFiles"] <= 5e4 ? Math.floor(r["maxFiles"]) : DEFAULTS23.maxFiles
|
|
9318
9764
|
};
|
|
9319
9765
|
}
|
|
9320
9766
|
function normalizeExtensions4(exts) {
|
|
@@ -9324,53 +9770,66 @@ function toPosix5(p) {
|
|
|
9324
9770
|
return p.replace(/\\/g, "/");
|
|
9325
9771
|
}
|
|
9326
9772
|
function relativePath5(p) {
|
|
9327
|
-
return toPosix5(
|
|
9773
|
+
return toPosix5(relative14(process.cwd(), p));
|
|
9328
9774
|
}
|
|
9329
9775
|
var INTERFACE_RE = /(?:export\s+)?interface\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
9330
9776
|
function extractInterfaceNames(content) {
|
|
9331
9777
|
const names = [];
|
|
9332
9778
|
INTERFACE_RE.lastIndex = 0;
|
|
9779
|
+
let searchedUpTo = 0;
|
|
9780
|
+
let line = 1;
|
|
9333
9781
|
for (const m of content.matchAll(INTERFACE_RE)) {
|
|
9334
|
-
|
|
9782
|
+
const index = m.index ?? 0;
|
|
9783
|
+
for (let i = searchedUpTo; i < index; i++) {
|
|
9784
|
+
if (content.charCodeAt(i) === 10) line += 1;
|
|
9785
|
+
}
|
|
9786
|
+
searchedUpTo = index;
|
|
9787
|
+
names.push({ name: m[1], line });
|
|
9335
9788
|
}
|
|
9336
9789
|
return names;
|
|
9337
9790
|
}
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9791
|
+
var IMPLEMENTER_RE = /(?:implements|satisfies|\bas)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
9792
|
+
function collectImplementedNames(content, into) {
|
|
9793
|
+
IMPLEMENTER_RE.lastIndex = 0;
|
|
9794
|
+
for (const m of content.matchAll(IMPLEMENTER_RE)) {
|
|
9795
|
+
const name = m[1];
|
|
9796
|
+
if (name) into.add(name);
|
|
9342
9797
|
}
|
|
9343
|
-
return false;
|
|
9344
9798
|
}
|
|
9345
9799
|
async function scanPath3(rawPath, cfg) {
|
|
9346
9800
|
const root = process.cwd();
|
|
9347
|
-
const resolved =
|
|
9801
|
+
const resolved = isAbsolute14(rawPath) ? resolve14(rawPath) : resolve14(root, rawPath);
|
|
9348
9802
|
const exts = normalizeExtensions4(cfg.extensions);
|
|
9349
|
-
const
|
|
9350
|
-
const
|
|
9803
|
+
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
9804
|
+
const files = allFiles.slice(0, cfg.maxFiles);
|
|
9805
|
+
const implemented = /* @__PURE__ */ new Set();
|
|
9806
|
+
const declarations = [];
|
|
9807
|
+
let scannedFiles = 0;
|
|
9351
9808
|
for (const p of files) {
|
|
9809
|
+
let content;
|
|
9352
9810
|
try {
|
|
9353
|
-
|
|
9811
|
+
content = await readFile9(p, "utf-8");
|
|
9354
9812
|
} catch {
|
|
9813
|
+
continue;
|
|
9355
9814
|
}
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
const findings = [];
|
|
9359
|
-
for (const { path, content } of contents) {
|
|
9815
|
+
scannedFiles += 1;
|
|
9816
|
+
collectImplementedNames(content, implemented);
|
|
9360
9817
|
for (const { name, line } of extractInterfaceNames(content)) {
|
|
9361
|
-
|
|
9362
|
-
findings.push({
|
|
9363
|
-
interfaceName: name,
|
|
9364
|
-
file: relativePath5(path),
|
|
9365
|
-
line,
|
|
9366
|
-
message: `interface "${name}" is declared but has no visible implementer`
|
|
9367
|
-
});
|
|
9368
|
-
if (findings.length >= cfg.maxFindings) break;
|
|
9369
|
-
}
|
|
9818
|
+
declarations.push({ name, line, file: p });
|
|
9370
9819
|
}
|
|
9820
|
+
}
|
|
9821
|
+
const findings = [];
|
|
9822
|
+
for (const { name, line, file } of declarations) {
|
|
9823
|
+
if (implemented.has(name)) continue;
|
|
9824
|
+
findings.push({
|
|
9825
|
+
interfaceName: name,
|
|
9826
|
+
file: relativePath5(file),
|
|
9827
|
+
line,
|
|
9828
|
+
message: `interface "${name}" is declared but has no visible implementer`
|
|
9829
|
+
});
|
|
9371
9830
|
if (findings.length >= cfg.maxFindings) break;
|
|
9372
9831
|
}
|
|
9373
|
-
return { findings, scannedFiles:
|
|
9832
|
+
return { findings, scannedFiles, truncated: allFiles.length > files.length };
|
|
9374
9833
|
}
|
|
9375
9834
|
var plugin29 = {
|
|
9376
9835
|
name: "interface-contract-guard",
|
|
@@ -9389,6 +9848,13 @@ var plugin29 = {
|
|
|
9389
9848
|
default: [".ts", ".tsx"],
|
|
9390
9849
|
description: "File extensions to scan."
|
|
9391
9850
|
},
|
|
9851
|
+
maxFiles: {
|
|
9852
|
+
type: "number",
|
|
9853
|
+
minimum: 1,
|
|
9854
|
+
maximum: 5e4,
|
|
9855
|
+
default: 2e3,
|
|
9856
|
+
description: "Upper bound on files read per scan."
|
|
9857
|
+
},
|
|
9392
9858
|
maxFindings: {
|
|
9393
9859
|
type: "number",
|
|
9394
9860
|
minimum: 1,
|
|
@@ -9422,10 +9888,10 @@ var plugin29 = {
|
|
|
9422
9888
|
const exts = normalizeExtensions4(cfg.extensions);
|
|
9423
9889
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
9424
9890
|
state26.hookInvocationCount += 1;
|
|
9425
|
-
const resolved =
|
|
9891
|
+
const resolved = resolve14(process.cwd(), sourcePath);
|
|
9426
9892
|
let content;
|
|
9427
9893
|
try {
|
|
9428
|
-
content = await
|
|
9894
|
+
content = await readFile9(resolved, "utf-8");
|
|
9429
9895
|
} catch {
|
|
9430
9896
|
state26.errorCount += 1;
|
|
9431
9897
|
return;
|
|
@@ -9470,9 +9936,16 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
9470
9936
|
state26.findingCount += result.findings.length;
|
|
9471
9937
|
return {
|
|
9472
9938
|
ok: true,
|
|
9473
|
-
path: relativePath5(
|
|
9939
|
+
path: relativePath5(resolve14(process.cwd(), rawPath)),
|
|
9474
9940
|
scannedFiles: result.scannedFiles,
|
|
9475
|
-
findings: result.findings
|
|
9941
|
+
findings: result.findings,
|
|
9942
|
+
// Say so when the corpus was cut short. A partial scan that
|
|
9943
|
+
// reports "no findings" is not the same as a clean result, and
|
|
9944
|
+
// the caller has no other way to tell the difference.
|
|
9945
|
+
truncated: result.truncated,
|
|
9946
|
+
...result.truncated ? {
|
|
9947
|
+
note: `Scan stopped at the maxFiles limit (${cfg.maxFiles}); results are partial. Raise \`maxFiles\` or scan a narrower path for full coverage.`
|
|
9948
|
+
} : {}
|
|
9476
9949
|
};
|
|
9477
9950
|
}
|
|
9478
9951
|
});
|
|
@@ -9543,8 +10016,9 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
9543
10016
|
var interface_contract_guard_default = plugin29;
|
|
9544
10017
|
|
|
9545
10018
|
// src/knowledge-graph/index.ts
|
|
9546
|
-
import {
|
|
9547
|
-
import { dirname as
|
|
10019
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
10020
|
+
import { dirname as dirname5, isAbsolute as isAbsolute15, relative as relative15, resolve as resolve15 } from "node:path";
|
|
10021
|
+
import { atomicWrite as atomicWrite2, ensureDir as ensureDir2 } from "@wrongstack/core/utils";
|
|
9548
10022
|
var API_VERSION21 = "^0.1.10";
|
|
9549
10023
|
var state27 = {
|
|
9550
10024
|
facts: [],
|
|
@@ -9565,10 +10039,10 @@ var DEFAULTS24 = {
|
|
|
9565
10039
|
};
|
|
9566
10040
|
function resolveProjectPath5(rawPath, cwd = process.cwd()) {
|
|
9567
10041
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
9568
|
-
const root =
|
|
9569
|
-
const resolved =
|
|
9570
|
-
const rel =
|
|
9571
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
10042
|
+
const root = resolve15(cwd);
|
|
10043
|
+
const resolved = isAbsolute15(rawPath) ? resolve15(rawPath) : resolve15(root, rawPath);
|
|
10044
|
+
const rel = relative15(root, resolved);
|
|
10045
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute15(rel)) return resolved;
|
|
9572
10046
|
return null;
|
|
9573
10047
|
}
|
|
9574
10048
|
function readConfig25(raw) {
|
|
@@ -9586,7 +10060,7 @@ function readConfig25(raw) {
|
|
|
9586
10060
|
function loadFacts(filePath) {
|
|
9587
10061
|
if (!filePath) return { facts: [], nextId: 1 };
|
|
9588
10062
|
try {
|
|
9589
|
-
const raw = JSON.parse(
|
|
10063
|
+
const raw = JSON.parse(readFileSync7(filePath, "utf-8"));
|
|
9590
10064
|
const facts = Array.isArray(raw.facts) ? raw.facts.filter(
|
|
9591
10065
|
(f) => !!f && typeof f === "object" && typeof f.id === "string" && typeof f.subject === "string" && typeof f.relation === "string" && typeof f.object === "string"
|
|
9592
10066
|
) : [];
|
|
@@ -9596,11 +10070,11 @@ function loadFacts(filePath) {
|
|
|
9596
10070
|
return { facts: [], nextId: 1 };
|
|
9597
10071
|
}
|
|
9598
10072
|
}
|
|
9599
|
-
function persistFacts(filePath) {
|
|
10073
|
+
async function persistFacts(filePath) {
|
|
9600
10074
|
if (!filePath) return true;
|
|
9601
10075
|
try {
|
|
9602
|
-
|
|
9603
|
-
|
|
10076
|
+
await ensureDir2(dirname5(filePath));
|
|
10077
|
+
await atomicWrite2(
|
|
9604
10078
|
filePath,
|
|
9605
10079
|
JSON.stringify({ facts: state27.facts, nextId: state27.nextId }, null, 2)
|
|
9606
10080
|
);
|
|
@@ -9731,7 +10205,7 @@ var plugin30 = {
|
|
|
9731
10205
|
state27.facts.push(fact);
|
|
9732
10206
|
state27.adds += 1;
|
|
9733
10207
|
api.metrics.counter("adds");
|
|
9734
|
-
const persisted = persistFacts(resolved);
|
|
10208
|
+
const persisted = await persistFacts(resolved);
|
|
9735
10209
|
return { ok: true, fact, persisted, totalFacts: state27.facts.length };
|
|
9736
10210
|
}
|
|
9737
10211
|
});
|
|
@@ -9791,7 +10265,7 @@ var plugin30 = {
|
|
|
9791
10265
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id}"` };
|
|
9792
10266
|
state27.removals += removed;
|
|
9793
10267
|
api.metrics.counter("removals", removed);
|
|
9794
|
-
const persisted = persistFacts(resolved);
|
|
10268
|
+
const persisted = await persistFacts(resolved);
|
|
9795
10269
|
return { ok: true, removed, persisted, totalFacts: state27.facts.length };
|
|
9796
10270
|
}
|
|
9797
10271
|
});
|
|
@@ -9866,8 +10340,8 @@ var plugin30 = {
|
|
|
9866
10340
|
var knowledge_graph_default = plugin30;
|
|
9867
10341
|
|
|
9868
10342
|
// src/license-audit-gate/index.ts
|
|
9869
|
-
import { readFileSync as
|
|
9870
|
-
import { resolve as
|
|
10343
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
10344
|
+
import { resolve as resolve16 } from "node:path";
|
|
9871
10345
|
var API_VERSION22 = "^0.1.10";
|
|
9872
10346
|
var state28 = {
|
|
9873
10347
|
invocations: 0,
|
|
@@ -9943,8 +10417,8 @@ function auditPackages(names, allowedLicenses) {
|
|
|
9943
10417
|
for (const name of names) {
|
|
9944
10418
|
let licenses = [];
|
|
9945
10419
|
try {
|
|
9946
|
-
const pkgPath =
|
|
9947
|
-
const raw = JSON.parse(
|
|
10420
|
+
const pkgPath = resolve16("node_modules", name, "package.json");
|
|
10421
|
+
const raw = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
9948
10422
|
licenses = extractLicenseStrings(raw);
|
|
9949
10423
|
} catch {
|
|
9950
10424
|
errors.push(name);
|
|
@@ -10124,11 +10598,11 @@ var license_audit_gate_default = plugin31;
|
|
|
10124
10598
|
|
|
10125
10599
|
// src/lint-gate/index.ts
|
|
10126
10600
|
import { execFile as execFile8 } from "node:child_process";
|
|
10127
|
-
import { readFileSync as
|
|
10128
|
-
import { mkdtemp, readFile as
|
|
10129
|
-
import { createRequire } from "node:module";
|
|
10601
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
10602
|
+
import { mkdtemp, readFile as readFile10, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
10603
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
10130
10604
|
import { tmpdir } from "node:os";
|
|
10131
|
-
import { dirname as
|
|
10605
|
+
import { dirname as dirname6, isAbsolute as isAbsolute16, join as join4, relative as relative16, resolve as resolve17, sep as sep3 } from "node:path";
|
|
10132
10606
|
var API_VERSION23 = "^0.1.10";
|
|
10133
10607
|
var state29 = {
|
|
10134
10608
|
/** Total PreToolUse invocations. */
|
|
@@ -10166,22 +10640,22 @@ var LINTER_PACKAGES = {
|
|
|
10166
10640
|
biome: "@biomejs/biome",
|
|
10167
10641
|
eslint: "eslint"
|
|
10168
10642
|
};
|
|
10169
|
-
var linterCache =
|
|
10170
|
-
function
|
|
10171
|
-
const rel =
|
|
10172
|
-
return rel === "" || !rel.startsWith(`..${
|
|
10643
|
+
var linterCache = new BoundedMap({ max: 32, ttlMs: 3e5 });
|
|
10644
|
+
function isInside2(parent, candidate) {
|
|
10645
|
+
const rel = relative16(parent, candidate);
|
|
10646
|
+
return rel === "" || !rel.startsWith(`..${sep3}`) && rel !== ".." && !isAbsolute16(rel);
|
|
10173
10647
|
}
|
|
10174
10648
|
function resolveLocalLinter(name, cwd) {
|
|
10175
10649
|
try {
|
|
10176
10650
|
const packageName = LINTER_PACKAGES[name];
|
|
10177
|
-
const requireFromProject =
|
|
10651
|
+
const requireFromProject = createRequire2(resolve17(cwd, "package.json"));
|
|
10178
10652
|
const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
|
|
10179
|
-
const packageJson = JSON.parse(
|
|
10653
|
+
const packageJson = JSON.parse(readFileSync9(packagePath, "utf-8"));
|
|
10180
10654
|
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[name] ?? Object.values(packageJson.bin ?? {})[0];
|
|
10181
|
-
if (!relativeBin ||
|
|
10182
|
-
const packageDir =
|
|
10183
|
-
const entry =
|
|
10184
|
-
if (!
|
|
10655
|
+
if (!relativeBin || isAbsolute16(relativeBin)) return null;
|
|
10656
|
+
const packageDir = dirname6(packagePath);
|
|
10657
|
+
const entry = resolve17(packageDir, relativeBin);
|
|
10658
|
+
if (!isInside2(packageDir, entry)) return null;
|
|
10185
10659
|
return {
|
|
10186
10660
|
cmd: process.execPath,
|
|
10187
10661
|
args: name === "biome" ? [entry, "check", "--reporter=json"] : [entry, "--format=json"],
|
|
@@ -10232,8 +10706,8 @@ async function detectLinter(requested, cwd) {
|
|
|
10232
10706
|
}
|
|
10233
10707
|
async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
10234
10708
|
const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
|
|
10235
|
-
const tmpDir = await mkdtemp(
|
|
10236
|
-
const tmpFile =
|
|
10709
|
+
const tmpDir = await mkdtemp(join4(tmpdir(), "lint-gate-"));
|
|
10710
|
+
const tmpFile = join4(tmpDir, `input${ext}`);
|
|
10237
10711
|
try {
|
|
10238
10712
|
await writeFile2(tmpFile, content, "utf-8");
|
|
10239
10713
|
const fullArgs = [...linter.args, tmpFile];
|
|
@@ -10250,14 +10724,14 @@ async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
|
10250
10724
|
}
|
|
10251
10725
|
async function lintAndFix(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
10252
10726
|
const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
|
|
10253
|
-
const tmpDir = await mkdtemp(
|
|
10254
|
-
const tmpFile =
|
|
10727
|
+
const tmpDir = await mkdtemp(join4(tmpdir(), "lint-gate-fix-"));
|
|
10728
|
+
const tmpFile = join4(tmpDir, `input${ext}`);
|
|
10255
10729
|
try {
|
|
10256
10730
|
await writeFile2(tmpFile, content, "utf-8");
|
|
10257
10731
|
const fixArgs = linter.name === "biome" ? [linter.args[0], "check", "--write", tmpFile] : [linter.args[0], "--fix", tmpFile];
|
|
10258
10732
|
await runCommand2(linter.cmd, fixArgs, timeoutMs, cwd, signal);
|
|
10259
10733
|
if (signal.aborted) throw signal.reason;
|
|
10260
|
-
return await
|
|
10734
|
+
return await readFile10(tmpFile, "utf-8");
|
|
10261
10735
|
} catch {
|
|
10262
10736
|
if (signal.aborted) throw signal.reason;
|
|
10263
10737
|
return content;
|
|
@@ -10357,7 +10831,7 @@ var plugin32 = {
|
|
|
10357
10831
|
state29.lastResult = null;
|
|
10358
10832
|
linterCache.clear();
|
|
10359
10833
|
const cfg = readConfig27(api.config.extensions?.["lint-gate"]);
|
|
10360
|
-
const cwd =
|
|
10834
|
+
const cwd = resolve17(api.config.cwd ?? process.cwd());
|
|
10361
10835
|
const linterReady = detectLinter(cfg.linter, cwd).then((linter) => {
|
|
10362
10836
|
if (!linter) {
|
|
10363
10837
|
api.log.warn("lint-gate: no linter found (biome or eslint) \u2014 hook will be a no-op", {
|
|
@@ -10386,7 +10860,7 @@ var plugin32 = {
|
|
|
10386
10860
|
const newStr = inp["new_string"];
|
|
10387
10861
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return;
|
|
10388
10862
|
try {
|
|
10389
|
-
const current = await
|
|
10863
|
+
const current = await readFile10(filePath, "utf-8");
|
|
10390
10864
|
content = applyEdit(current, oldStr, newStr);
|
|
10391
10865
|
} catch {
|
|
10392
10866
|
return;
|
|
@@ -10591,7 +11065,7 @@ ${summary}${truncated}`
|
|
|
10591
11065
|
var lint_gate_default = plugin32;
|
|
10592
11066
|
|
|
10593
11067
|
// src/llm-cache/index.ts
|
|
10594
|
-
import { createHash } from "node:crypto";
|
|
11068
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
10595
11069
|
var state30 = {
|
|
10596
11070
|
cache: /* @__PURE__ */ new Map(),
|
|
10597
11071
|
hits: 0,
|
|
@@ -10641,7 +11115,7 @@ function fingerprintRequest(request) {
|
|
|
10641
11115
|
topK: request["topK"] ?? null,
|
|
10642
11116
|
topP: request["topP"] ?? null
|
|
10643
11117
|
};
|
|
10644
|
-
const fingerprint2 =
|
|
11118
|
+
const fingerprint2 = createHash2("sha256").update(JSON.stringify(subset)).digest("hex");
|
|
10645
11119
|
fingerprintCache.set(request, fingerprint2);
|
|
10646
11120
|
return fingerprint2;
|
|
10647
11121
|
}
|
|
@@ -10920,16 +11394,26 @@ function canonicalize(value) {
|
|
|
10920
11394
|
return String(value);
|
|
10921
11395
|
}
|
|
10922
11396
|
}
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
if (value
|
|
11397
|
+
var CANONICALIZE_MAX_DEPTH = 12;
|
|
11398
|
+
function sortKeys(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
11399
|
+
if (value === null || typeof value !== "object") return value;
|
|
11400
|
+
if (seen.has(value)) return "[circular]";
|
|
11401
|
+
if (depth >= CANONICALIZE_MAX_DEPTH) {
|
|
11402
|
+
return Array.isArray(value) ? `[array:${value.length}]` : "[deep-object]";
|
|
11403
|
+
}
|
|
11404
|
+
seen.add(value);
|
|
11405
|
+
try {
|
|
11406
|
+
if (Array.isArray(value)) {
|
|
11407
|
+
return value.map((v) => sortKeys(v, depth + 1, seen));
|
|
11408
|
+
}
|
|
10926
11409
|
const out = {};
|
|
10927
11410
|
for (const key of Object.keys(value).sort()) {
|
|
10928
|
-
out[key] = sortKeys(value[key]);
|
|
11411
|
+
out[key] = sortKeys(value[key], depth + 1, seen);
|
|
10929
11412
|
}
|
|
10930
11413
|
return out;
|
|
11414
|
+
} finally {
|
|
11415
|
+
seen.delete(value);
|
|
10931
11416
|
}
|
|
10932
|
-
return value;
|
|
10933
11417
|
}
|
|
10934
11418
|
function fingerprint(toolName, toolInput) {
|
|
10935
11419
|
return `${toolName}\0${canonicalize(toolInput)}`;
|
|
@@ -10955,7 +11439,7 @@ function hashString2(value) {
|
|
|
10955
11439
|
}
|
|
10956
11440
|
async function gitDiffFingerprint(cwd, signal) {
|
|
10957
11441
|
try {
|
|
10958
|
-
const diff = await new Promise((
|
|
11442
|
+
const diff = await new Promise((resolve28, reject) => {
|
|
10959
11443
|
execFile9(
|
|
10960
11444
|
"git",
|
|
10961
11445
|
["diff", "--no-ext-diff", "--"],
|
|
@@ -10972,7 +11456,7 @@ async function gitDiffFingerprint(cwd, signal) {
|
|
|
10972
11456
|
},
|
|
10973
11457
|
(error, stdout) => {
|
|
10974
11458
|
if (error) reject(error);
|
|
10975
|
-
else
|
|
11459
|
+
else resolve28(stdout);
|
|
10976
11460
|
}
|
|
10977
11461
|
);
|
|
10978
11462
|
});
|
|
@@ -11322,7 +11806,7 @@ var plugin34 = {
|
|
|
11322
11806
|
var loop_breaker_default = plugin34;
|
|
11323
11807
|
|
|
11324
11808
|
// src/migration-planner/index.ts
|
|
11325
|
-
import { existsSync as existsSync4, readFileSync as
|
|
11809
|
+
import { existsSync as existsSync4, readFileSync as readFileSync10 } from "node:fs";
|
|
11326
11810
|
var API_VERSION24 = "^0.1.10";
|
|
11327
11811
|
var state32 = {
|
|
11328
11812
|
plansGenerated: 0,
|
|
@@ -11362,7 +11846,7 @@ function readChangelog(packageName, cfg) {
|
|
|
11362
11846
|
if (!withinProject(candidate)) continue;
|
|
11363
11847
|
if (existsSync4(candidate)) {
|
|
11364
11848
|
try {
|
|
11365
|
-
const content =
|
|
11849
|
+
const content = readFileSync10(candidate, "utf-8");
|
|
11366
11850
|
return { source: candidate, content: content.slice(0, cfg.maxChars) };
|
|
11367
11851
|
} catch {
|
|
11368
11852
|
}
|
|
@@ -12189,13 +12673,21 @@ async function deliver(event, payload) {
|
|
|
12189
12673
|
}
|
|
12190
12674
|
const result = await deliverViaChannel(ch, event, {
|
|
12191
12675
|
title: typeof payload.title === "string" ? payload.title : event,
|
|
12192
|
-
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error :
|
|
12676
|
+
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : safeJsonStringify(payload),
|
|
12193
12677
|
level: event === "tool.error" || event === "budget.threshold" ? "warning" : "info",
|
|
12194
12678
|
source: event,
|
|
12195
12679
|
metadata: payload
|
|
12196
12680
|
});
|
|
12197
12681
|
return result.ok;
|
|
12198
12682
|
}
|
|
12683
|
+
function deliverDetached(event, payload) {
|
|
12684
|
+
deliver(event, payload).catch((err) => {
|
|
12685
|
+
_pluginLog?.warn("notify-hub: notification delivery failed", {
|
|
12686
|
+
event,
|
|
12687
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12688
|
+
});
|
|
12689
|
+
});
|
|
12690
|
+
}
|
|
12199
12691
|
async function deliverViaChannel(ch, event, msg) {
|
|
12200
12692
|
const result = await ch.deliver(msg);
|
|
12201
12693
|
if (result.ok) {
|
|
@@ -12304,7 +12796,7 @@ var plugin37 = {
|
|
|
12304
12796
|
}
|
|
12305
12797
|
if (active && cfg.events.includes("session.stop")) {
|
|
12306
12798
|
const stopHook = (input) => {
|
|
12307
|
-
|
|
12799
|
+
deliverDetached("session.stop", {
|
|
12308
12800
|
sessionId: input.sessionId ?? null,
|
|
12309
12801
|
cwd: input.cwd ?? null
|
|
12310
12802
|
});
|
|
@@ -12315,7 +12807,7 @@ var plugin37 = {
|
|
|
12315
12807
|
const off = api.onPattern("tool.*", (eventName, payload) => {
|
|
12316
12808
|
if (!/error|failed/.test(eventName)) return;
|
|
12317
12809
|
const p = payload;
|
|
12318
|
-
|
|
12810
|
+
deliverDetached("tool.error", {
|
|
12319
12811
|
tool: p?.tool ?? p?.name ?? "unknown",
|
|
12320
12812
|
busEvent: eventName,
|
|
12321
12813
|
error: truncateText(
|
|
@@ -12329,7 +12821,7 @@ var plugin37 = {
|
|
|
12329
12821
|
if (active && cfg.events.includes("budget.threshold")) {
|
|
12330
12822
|
const off = api.onPattern("budget.*", (eventName, payload) => {
|
|
12331
12823
|
if (!eventName.includes("threshold")) return;
|
|
12332
|
-
|
|
12824
|
+
deliverDetached("budget.threshold", { busEvent: eventName, detail: payload });
|
|
12333
12825
|
});
|
|
12334
12826
|
state34.eventUnsubscribers.push(off);
|
|
12335
12827
|
}
|
|
@@ -12692,8 +13184,8 @@ var plugin38 = {
|
|
|
12692
13184
|
var path_guard_default = plugin38;
|
|
12693
13185
|
|
|
12694
13186
|
// src/performance-regression-gate/index.ts
|
|
12695
|
-
import { existsSync as existsSync5, readFileSync as
|
|
12696
|
-
import { isAbsolute as
|
|
13187
|
+
import { existsSync as existsSync5, readFileSync as readFileSync11 } from "node:fs";
|
|
13188
|
+
import { isAbsolute as isAbsolute17, relative as relative17, resolve as resolve18 } from "node:path";
|
|
12697
13189
|
var API_VERSION25 = "^0.1.10";
|
|
12698
13190
|
var state36 = {
|
|
12699
13191
|
invocationCount: 0,
|
|
@@ -12718,18 +13210,18 @@ function readConfig34(raw) {
|
|
|
12718
13210
|
}
|
|
12719
13211
|
function withinProject4(p, cwd = process.cwd()) {
|
|
12720
13212
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
12721
|
-
const root =
|
|
12722
|
-
const resolved =
|
|
12723
|
-
const rel =
|
|
13213
|
+
const root = resolve18(cwd);
|
|
13214
|
+
const resolved = isAbsolute17(p) ? resolve18(p) : resolve18(root, p);
|
|
13215
|
+
const rel = relative17(root, resolved);
|
|
12724
13216
|
if (rel === "" || rel === ".") return true;
|
|
12725
13217
|
if (rel.startsWith("..")) return false;
|
|
12726
|
-
if (
|
|
13218
|
+
if (isAbsolute17(rel)) return false;
|
|
12727
13219
|
return true;
|
|
12728
13220
|
}
|
|
12729
13221
|
function resolveProjectPath6(rawPath, cwd = process.cwd()) {
|
|
12730
13222
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
12731
|
-
const root =
|
|
12732
|
-
const resolved =
|
|
13223
|
+
const root = resolve18(cwd);
|
|
13224
|
+
const resolved = isAbsolute17(rawPath) ? resolve18(rawPath) : resolve18(root, rawPath);
|
|
12733
13225
|
if (!withinProject4(resolved, cwd)) return null;
|
|
12734
13226
|
return resolved;
|
|
12735
13227
|
}
|
|
@@ -12760,7 +13252,7 @@ function flattenResults(results) {
|
|
|
12760
13252
|
function loadResults(path) {
|
|
12761
13253
|
if (!path || !existsSync5(path)) return null;
|
|
12762
13254
|
try {
|
|
12763
|
-
const raw = JSON.parse(
|
|
13255
|
+
const raw = JSON.parse(readFileSync11(path, "utf-8"));
|
|
12764
13256
|
return raw;
|
|
12765
13257
|
} catch {
|
|
12766
13258
|
return null;
|
|
@@ -13144,7 +13636,7 @@ var plugin_stack_observer_default = PLUGIN;
|
|
|
13144
13636
|
// src/pr-drafter/index.ts
|
|
13145
13637
|
import { execFile as execFile10 } from "node:child_process";
|
|
13146
13638
|
import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
|
|
13147
|
-
import { dirname as
|
|
13639
|
+
import { dirname as dirname7, isAbsolute as isAbsolute18, relative as relative18, resolve as resolve19 } from "node:path";
|
|
13148
13640
|
var API_VERSION26 = "^0.1.10";
|
|
13149
13641
|
var state38 = {
|
|
13150
13642
|
commits: [],
|
|
@@ -13183,10 +13675,10 @@ function readConfig36(raw) {
|
|
|
13183
13675
|
}
|
|
13184
13676
|
function resolveProjectPath7(rawPath, cwd = process.cwd()) {
|
|
13185
13677
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
13186
|
-
const root =
|
|
13187
|
-
const resolved =
|
|
13188
|
-
const rel =
|
|
13189
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
13678
|
+
const root = resolve19(cwd);
|
|
13679
|
+
const resolved = isAbsolute18(rawPath) ? resolve19(rawPath) : resolve19(root, rawPath);
|
|
13680
|
+
const rel = relative18(root, resolved);
|
|
13681
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute18(rel)) return resolved;
|
|
13190
13682
|
return null;
|
|
13191
13683
|
}
|
|
13192
13684
|
function runGit4(args, timeout) {
|
|
@@ -13272,7 +13764,7 @@ async function writeDraft(cfg, llm) {
|
|
|
13272
13764
|
}
|
|
13273
13765
|
const draft = await buildDraft(cfg, llm);
|
|
13274
13766
|
try {
|
|
13275
|
-
await mkdir2(
|
|
13767
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
13276
13768
|
await writeFile3(resolved, draft.body);
|
|
13277
13769
|
state38.draftsWritten += 1;
|
|
13278
13770
|
} catch {
|
|
@@ -13399,7 +13891,7 @@ var plugin40 = {
|
|
|
13399
13891
|
const resolved = resolveProjectPath7(cfg.outputPath);
|
|
13400
13892
|
if (!resolved) return { ok: false, error: "outputPath resolves outside project" };
|
|
13401
13893
|
try {
|
|
13402
|
-
await mkdir2(
|
|
13894
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
13403
13895
|
await writeFile3(resolved, draft.body);
|
|
13404
13896
|
state38.draftsWritten += 1;
|
|
13405
13897
|
return {
|
|
@@ -13620,26 +14112,155 @@ var plugin41 = {
|
|
|
13620
14112
|
};
|
|
13621
14113
|
var process_guard_default = plugin41;
|
|
13622
14114
|
|
|
14115
|
+
// src/runtime/credential-patterns.ts
|
|
14116
|
+
var CREDENTIAL_PATTERNS = [
|
|
14117
|
+
// LLM provider keys
|
|
14118
|
+
{
|
|
14119
|
+
type: "anthropic_key",
|
|
14120
|
+
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
14121
|
+
},
|
|
14122
|
+
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?!ant)(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
14123
|
+
// GitHub. `ghp_` is only the personal-access-token prefix — the OAuth
|
|
14124
|
+
// (`gho_`), user-to-server (`ghu_`), server-to-server (`ghs_`) and
|
|
14125
|
+
// refresh (`ghr_`) tokens grant the same or broader access and were
|
|
14126
|
+
// previously not detected at all.
|
|
14127
|
+
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
14128
|
+
{
|
|
14129
|
+
type: "github_oauth_token",
|
|
14130
|
+
regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g
|
|
14131
|
+
},
|
|
14132
|
+
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
14133
|
+
// GitLab
|
|
14134
|
+
{ type: "gitlab_pat", regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14135
|
+
{
|
|
14136
|
+
type: "gitlab_runner_token",
|
|
14137
|
+
regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14138
|
+
},
|
|
14139
|
+
// npm — a leaked publish token is a supply-chain compromise.
|
|
14140
|
+
{ type: "npm_token", regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g },
|
|
14141
|
+
// AWS
|
|
14142
|
+
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
14143
|
+
// GCP
|
|
14144
|
+
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
14145
|
+
// Slack. `xoxe` (token-rotation) and `xapp` (app-level) were missing;
|
|
14146
|
+
// both are as sensitive as the bot/user tokens already covered.
|
|
14147
|
+
{
|
|
14148
|
+
type: "slack_token",
|
|
14149
|
+
regex: /(?<![A-Za-z0-9-])xox[abposer]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g
|
|
14150
|
+
},
|
|
14151
|
+
{ type: "slack_app_token", regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
14152
|
+
{
|
|
14153
|
+
type: "slack_webhook",
|
|
14154
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g
|
|
14155
|
+
},
|
|
14156
|
+
// Stripe
|
|
14157
|
+
{
|
|
14158
|
+
type: "stripe_key",
|
|
14159
|
+
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g
|
|
14160
|
+
},
|
|
14161
|
+
// Twilio
|
|
14162
|
+
{ type: "twilio_sid", regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g },
|
|
14163
|
+
// Telegram
|
|
14164
|
+
{
|
|
14165
|
+
type: "telegram_bot_token",
|
|
14166
|
+
regex: /(?:(?<![A-Za-z0-9_])|(?<=(?:^|[^A-Za-z0-9_])bot))\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14167
|
+
},
|
|
14168
|
+
// JWT
|
|
14169
|
+
{
|
|
14170
|
+
type: "jwt",
|
|
14171
|
+
regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g
|
|
14172
|
+
},
|
|
14173
|
+
// Private keys
|
|
14174
|
+
{
|
|
14175
|
+
type: "private_key",
|
|
14176
|
+
regex: /(?:^|\n)(?:-----BEGIN (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----[\s\S]*?-----END (?:RSA|EC|OPENSSH|DSA)? ?PRIVATE KEY-----|-----BEGIN PGP PRIVATE KEY BLOCK-----[\s\S]*?-----END PGP PRIVATE KEY BLOCK-----)(?!\S)/g
|
|
14177
|
+
},
|
|
14178
|
+
// AI/ML provider tokens
|
|
14179
|
+
{ type: "huggingface_token", regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g },
|
|
14180
|
+
{ type: "replicate_token", regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14181
|
+
{ type: "perplexity_key", regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14182
|
+
{ type: "groq_key", regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14183
|
+
// SaaS / infrastructure tokens — each grants API access on the user's
|
|
14184
|
+
// account, and each was previously invisible to this gate.
|
|
14185
|
+
{ type: "sendgrid_key", regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14186
|
+
{ type: "digitalocean_token", regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g },
|
|
14187
|
+
{ type: "doppler_token", regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14188
|
+
{ type: "shopify_token", regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g },
|
|
14189
|
+
{ type: "docker_pat", regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14190
|
+
{ type: "linear_key", regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14191
|
+
{ type: "atlassian_token", regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g },
|
|
14192
|
+
{ type: "square_token", regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14193
|
+
{
|
|
14194
|
+
type: "azure_storage_key",
|
|
14195
|
+
regex: /AccountKey=[A-Za-z0-9+/]{80,}={0,2}/g
|
|
14196
|
+
},
|
|
14197
|
+
{
|
|
14198
|
+
type: "google_oauth_client_secret",
|
|
14199
|
+
regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14200
|
+
},
|
|
14201
|
+
// Bearer tokens
|
|
14202
|
+
{
|
|
14203
|
+
type: "bearer_token",
|
|
14204
|
+
regex: /(?<![A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?![A-Za-z0-9._~+/-])/g
|
|
14205
|
+
},
|
|
14206
|
+
// Database URIs. Require password-bearing user-info; credential-free values stay scannable.
|
|
14207
|
+
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
14208
|
+
{
|
|
14209
|
+
type: "postgres_uri",
|
|
14210
|
+
// Query parsers decode percent-encoded parameter names. Recognize each
|
|
14211
|
+
// encoded character in `password` so mixed forms such as `pass%77ord`
|
|
14212
|
+
// cannot bypass detection while keeping the scan strictly bounded.
|
|
14213
|
+
regex: /postgres(?:ql)?:\/\/(?:[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+|[^&\s?"'`#]{1,2048}\?(?:(?!(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=)[^&\s#"'`]{1,256}&){0,32}(?:p|%70)(?:a|%61)(?:s|%73)(?:s|%73)(?:w|%77)(?:o|%6[fF])(?:r|%72)(?:d|%64)=[^&\s#"'`]{1,4096})/g
|
|
14214
|
+
},
|
|
14215
|
+
{ type: "mysql_uri", regex: /mysql:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
14216
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g }
|
|
14217
|
+
];
|
|
14218
|
+
function cloneCredentialPatterns() {
|
|
14219
|
+
return CREDENTIAL_PATTERNS.map((p) => ({
|
|
14220
|
+
type: p.type,
|
|
14221
|
+
regex: new RegExp(p.regex.source, p.regex.flags)
|
|
14222
|
+
}));
|
|
14223
|
+
}
|
|
14224
|
+
|
|
13623
14225
|
// src/prompt-firewall/index.ts
|
|
13624
|
-
var
|
|
13625
|
-
|
|
14226
|
+
var KIND_ALIASES = {
|
|
14227
|
+
aws_access_key: "aws-access-key",
|
|
14228
|
+
private_key: "private-key-block",
|
|
14229
|
+
github_pat: "github-token",
|
|
14230
|
+
github_oauth_token: "github-token",
|
|
14231
|
+
openai_key: "openai-key",
|
|
14232
|
+
anthropic_key: "anthropic-key",
|
|
14233
|
+
slack_token: "slack-token",
|
|
14234
|
+
gcp_key: "google-api-key",
|
|
14235
|
+
bearer_token: "bearer-token"
|
|
14236
|
+
};
|
|
14237
|
+
var EXTRA_PATTERNS = [
|
|
13626
14238
|
{
|
|
14239
|
+
// AWS secret access keys have no prefix — only a 40-char base64-ish
|
|
14240
|
+
// shape — so they need a nearby `aws`/`secret` mention to be worth
|
|
14241
|
+
// acting on.
|
|
14242
|
+
//
|
|
14243
|
+
// The previous spelling required the word "aws" to appear AFTER the
|
|
14244
|
+
// key and wrapped the run in `\b`. Both are wrong: the real layout is
|
|
14245
|
+
// `AWS_SECRET_ACCESS_KEY=<key>` (context first), and a `\b` cannot
|
|
14246
|
+
// hold next to the `+` or `/` that base64 keys routinely end with. The
|
|
14247
|
+
// pattern therefore never fired on a real key. Anchor on the context
|
|
14248
|
+
// token instead and let the key follow it.
|
|
13627
14249
|
kind: "aws-secret-key",
|
|
13628
|
-
re:
|
|
14250
|
+
re: /(?:aws|amazon)[A-Za-z0-9_-]*(?:secret|key)[A-Za-z0-9_-]*\s*[:=]\s*['"]?([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/gi
|
|
13629
14251
|
},
|
|
13630
|
-
{ kind: "private-key-block", re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g },
|
|
13631
|
-
{ kind: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g },
|
|
13632
|
-
{ kind: "openai-key", re: /\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b/g },
|
|
13633
|
-
{ kind: "anthropic-key", re: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g },
|
|
13634
|
-
{ kind: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
13635
|
-
{ kind: "google-api-key", re: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
13636
|
-
{ kind: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
13637
|
-
{ kind: "bearer-token", re: /\bBearer\s+[A-Za-z0-9._-]{20,}\b/g },
|
|
13638
14252
|
{
|
|
13639
14253
|
kind: "generic-secret-assignment",
|
|
13640
14254
|
re: /\b(?:api[_-]?key|secret|password|passwd|token)\s*[:=]\s*['"]?[A-Za-z0-9._/+-]{12,}['"]?/gi
|
|
13641
14255
|
}
|
|
13642
14256
|
];
|
|
14257
|
+
var PATTERNS2 = [
|
|
14258
|
+
...cloneCredentialPatterns().map((p) => ({
|
|
14259
|
+
kind: KIND_ALIASES[p.type] ?? p.type,
|
|
14260
|
+
re: p.regex
|
|
14261
|
+
})),
|
|
14262
|
+
...EXTRA_PATTERNS
|
|
14263
|
+
];
|
|
13643
14264
|
function detectSecrets(text, allow) {
|
|
13644
14265
|
const counts = /* @__PURE__ */ new Map();
|
|
13645
14266
|
for (const p of PATTERNS2) {
|
|
@@ -13915,9 +14536,10 @@ var plugin42 = {
|
|
|
13915
14536
|
var prompt_firewall_default = plugin42;
|
|
13916
14537
|
|
|
13917
14538
|
// src/refactor-suggester/index.ts
|
|
13918
|
-
import { readFile as
|
|
13919
|
-
import { isAbsolute as
|
|
14539
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
14540
|
+
import { isAbsolute as isAbsolute19, relative as relative19, resolve as resolve20 } from "node:path";
|
|
13920
14541
|
var API_VERSION27 = "^0.1.10";
|
|
14542
|
+
var HOOK_WARNING_COOLDOWN_MS2 = 6e4;
|
|
13921
14543
|
var state41 = {
|
|
13922
14544
|
scanCount: 0,
|
|
13923
14545
|
suggestionCount: 0,
|
|
@@ -13925,7 +14547,7 @@ var state41 = {
|
|
|
13925
14547
|
warningCount: 0,
|
|
13926
14548
|
errorCount: 0,
|
|
13927
14549
|
hookUnregister: null,
|
|
13928
|
-
lastHookWarning:
|
|
14550
|
+
lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS2 })
|
|
13929
14551
|
};
|
|
13930
14552
|
var DEFAULTS36 = {
|
|
13931
14553
|
enabled: false,
|
|
@@ -13959,7 +14581,7 @@ function toPosix6(p) {
|
|
|
13959
14581
|
return p.replace(/\\/g, "/");
|
|
13960
14582
|
}
|
|
13961
14583
|
function relativePath6(p) {
|
|
13962
|
-
return toPosix6(
|
|
14584
|
+
return toPosix6(relative19(process.cwd(), p));
|
|
13963
14585
|
}
|
|
13964
14586
|
function leadingIndentLevel(line) {
|
|
13965
14587
|
const leading = line.match(/^(\s*)/)?.[1] ?? "";
|
|
@@ -14046,19 +14668,30 @@ function detectSmells(filePath, content, rules) {
|
|
|
14046
14668
|
}
|
|
14047
14669
|
async function scanPath4(rawPath, cfg) {
|
|
14048
14670
|
const root = process.cwd();
|
|
14049
|
-
const resolved =
|
|
14671
|
+
const resolved = isAbsolute19(rawPath) ? resolve20(rawPath) : resolve20(root, rawPath);
|
|
14050
14672
|
const exts = normalizeExtensions5(cfg.extensions);
|
|
14051
14673
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
14052
14674
|
const suggestions = [];
|
|
14675
|
+
let scannedFiles = 0;
|
|
14676
|
+
let truncated = false;
|
|
14053
14677
|
for (const p of files) {
|
|
14054
14678
|
try {
|
|
14055
|
-
const content = await
|
|
14679
|
+
const content = await readFile11(p, "utf-8");
|
|
14680
|
+
scannedFiles += 1;
|
|
14056
14681
|
suggestions.push(...detectSmells(p, content, cfg.rules));
|
|
14057
|
-
if (suggestions.length >= cfg.maxSuggestions)
|
|
14682
|
+
if (suggestions.length >= cfg.maxSuggestions) {
|
|
14683
|
+
truncated = scannedFiles < files.length;
|
|
14684
|
+
break;
|
|
14685
|
+
}
|
|
14058
14686
|
} catch {
|
|
14059
14687
|
}
|
|
14060
14688
|
}
|
|
14061
|
-
return {
|
|
14689
|
+
return {
|
|
14690
|
+
suggestions: suggestions.slice(0, cfg.maxSuggestions),
|
|
14691
|
+
scannedFiles,
|
|
14692
|
+
discoveredFiles: files.length,
|
|
14693
|
+
truncated
|
|
14694
|
+
};
|
|
14062
14695
|
}
|
|
14063
14696
|
var plugin43 = {
|
|
14064
14697
|
name: "refactor-suggester",
|
|
@@ -14121,11 +14754,11 @@ var plugin43 = {
|
|
|
14121
14754
|
state41.hookInvocationCount += 1;
|
|
14122
14755
|
const now = Date.now();
|
|
14123
14756
|
const lastWarning = state41.lastHookWarning.get(sourcePath);
|
|
14124
|
-
if (lastWarning !== void 0 && now - lastWarning <
|
|
14125
|
-
const resolved =
|
|
14757
|
+
if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS2) return;
|
|
14758
|
+
const resolved = resolve20(process.cwd(), sourcePath);
|
|
14126
14759
|
let content;
|
|
14127
14760
|
try {
|
|
14128
|
-
content = await
|
|
14761
|
+
content = await readFile11(resolved, "utf-8");
|
|
14129
14762
|
} catch {
|
|
14130
14763
|
state41.errorCount += 1;
|
|
14131
14764
|
return;
|
|
@@ -14169,8 +14802,12 @@ var plugin43 = {
|
|
|
14169
14802
|
state41.suggestionCount += result.suggestions.length;
|
|
14170
14803
|
return {
|
|
14171
14804
|
ok: true,
|
|
14172
|
-
path: relativePath6(
|
|
14805
|
+
path: relativePath6(resolve20(process.cwd(), rawPath)),
|
|
14173
14806
|
scannedFiles: result.scannedFiles,
|
|
14807
|
+
discoveredFiles: result.discoveredFiles,
|
|
14808
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
14809
|
+
// that reports few findings must not read as a clean result.
|
|
14810
|
+
truncated: result.truncated,
|
|
14174
14811
|
suggestions: result.suggestions,
|
|
14175
14812
|
rules: cfg.rules
|
|
14176
14813
|
};
|
|
@@ -14579,7 +15216,7 @@ var plugin44 = {
|
|
|
14579
15216
|
var release_notes_generator_default = plugin44;
|
|
14580
15217
|
|
|
14581
15218
|
// src/schema-evolution-guard/index.ts
|
|
14582
|
-
import { readFileSync as
|
|
15219
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
14583
15220
|
import { basename as basename5 } from "node:path";
|
|
14584
15221
|
var API_VERSION29 = "^0.1.10";
|
|
14585
15222
|
var state43 = {
|
|
@@ -14782,7 +15419,7 @@ var plugin45 = {
|
|
|
14782
15419
|
content = toolInput["content"];
|
|
14783
15420
|
} else if (withinProject(filePath)) {
|
|
14784
15421
|
try {
|
|
14785
|
-
content =
|
|
15422
|
+
content = readFileSync12(filePath, "utf-8");
|
|
14786
15423
|
} catch {
|
|
14787
15424
|
content = void 0;
|
|
14788
15425
|
}
|
|
@@ -14886,71 +15523,43 @@ ${body}${suffix}`;
|
|
|
14886
15523
|
var schema_evolution_guard_default = plugin45;
|
|
14887
15524
|
|
|
14888
15525
|
// src/secret-scanner/index.ts
|
|
14889
|
-
var BASE_PATTERNS =
|
|
14890
|
-
// LLM provider keys
|
|
14891
|
-
{
|
|
14892
|
-
type: "anthropic_key",
|
|
14893
|
-
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
14894
|
-
},
|
|
14895
|
-
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
14896
|
-
// GitHub
|
|
14897
|
-
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
14898
|
-
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
14899
|
-
// AWS
|
|
14900
|
-
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
14901
|
-
// GCP
|
|
14902
|
-
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
14903
|
-
// Slack
|
|
14904
|
-
{ type: "slack_token", regex: /(?<![A-Za-z0-9-])xox[abpos]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
14905
|
-
// Stripe
|
|
14906
|
-
{
|
|
14907
|
-
type: "stripe_key",
|
|
14908
|
-
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g
|
|
14909
|
-
},
|
|
14910
|
-
// Twilio
|
|
14911
|
-
{ type: "twilio_sid", regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g },
|
|
14912
|
-
// Telegram
|
|
14913
|
-
{
|
|
14914
|
-
type: "telegram_bot_token",
|
|
14915
|
-
regex: /\/bot\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14916
|
-
},
|
|
14917
|
-
// JWT
|
|
14918
|
-
{
|
|
14919
|
-
type: "jwt",
|
|
14920
|
-
regex: /(?<![A-Za-z0-9/+=])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9/+=])/g
|
|
14921
|
-
},
|
|
14922
|
-
// Private keys
|
|
14923
|
-
{
|
|
14924
|
-
type: "private_key",
|
|
14925
|
-
regex: /(?:^|\n)-----BEGIN (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----[\s\S]*?-----END (?:RSA|EC|OPENSSH|DSA|PGP)? ?PRIVATE KEY-----(?!\S)/g
|
|
14926
|
-
},
|
|
14927
|
-
// AI/ML provider tokens
|
|
14928
|
-
{ type: "huggingface_token", regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g },
|
|
14929
|
-
{ type: "replicate_token", regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14930
|
-
{ type: "perplexity_key", regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14931
|
-
{ type: "groq_key", regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14932
|
-
// Bearer tokens
|
|
14933
|
-
{
|
|
14934
|
-
type: "bearer_token",
|
|
14935
|
-
regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?![A-Za-z0-9._~+/-])/g
|
|
14936
|
-
},
|
|
14937
|
-
// Database URIs
|
|
14938
|
-
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s"'`]+/g },
|
|
14939
|
-
{ type: "postgres_uri", regex: /postgres(?:ql)?:\/\/[^\s"'`]+/g },
|
|
14940
|
-
{ type: "mysql_uri", regex: /mysql:\/\/[^\s"'`]+/g },
|
|
14941
|
-
{ type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g }
|
|
14942
|
-
];
|
|
15526
|
+
var BASE_PATTERNS = cloneCredentialPatterns();
|
|
14943
15527
|
var PATTERNS3 = [...BASE_PATTERNS];
|
|
14944
15528
|
var patternCacheKey = "";
|
|
15529
|
+
var GROUP_INDEX_OF_PATTERN = [];
|
|
14945
15530
|
var COMBINED_REGEX = buildCombinedRegex(PATTERNS3);
|
|
14946
|
-
var
|
|
15531
|
+
var SCAN_WINDOW_LENGTH = 1e5;
|
|
15532
|
+
var SCAN_WINDOW_OVERLAP = 4096;
|
|
15533
|
+
var MAX_TOTAL_SCAN_LENGTH = 8 * 1024 * 1024;
|
|
15534
|
+
var TOO_LARGE_MARKER = "unscannable_oversized_input";
|
|
14947
15535
|
var RE_DOS_TIMEOUT_MS = 100;
|
|
15536
|
+
function countCaptureGroups(source) {
|
|
15537
|
+
try {
|
|
15538
|
+
return new RegExp(`${source}|`).exec("").length - 1;
|
|
15539
|
+
} catch {
|
|
15540
|
+
return 0;
|
|
15541
|
+
}
|
|
15542
|
+
}
|
|
15543
|
+
function patternTypeForGroups(groups) {
|
|
15544
|
+
for (let i = 0; i < PATTERNS3.length; i++) {
|
|
15545
|
+
const at = GROUP_INDEX_OF_PATTERN[i];
|
|
15546
|
+
if (at !== void 0 && groups[at] !== void 0) return PATTERNS3[i].type;
|
|
15547
|
+
}
|
|
15548
|
+
return void 0;
|
|
15549
|
+
}
|
|
14948
15550
|
function buildCombinedRegex(patterns) {
|
|
14949
|
-
const newCacheKey = JSON.stringify(patterns.map((p) => p.type));
|
|
15551
|
+
const newCacheKey = JSON.stringify(patterns.map((p) => [p.type, p.regex.source]));
|
|
14950
15552
|
if (newCacheKey === patternCacheKey && COMBINED_REGEX) {
|
|
14951
15553
|
return COMBINED_REGEX;
|
|
14952
15554
|
}
|
|
14953
15555
|
patternCacheKey = newCacheKey;
|
|
15556
|
+
const offsets = [];
|
|
15557
|
+
let cursor = 0;
|
|
15558
|
+
for (const p of patterns) {
|
|
15559
|
+
offsets.push(cursor);
|
|
15560
|
+
cursor += 1 + countCaptureGroups(p.regex.source);
|
|
15561
|
+
}
|
|
15562
|
+
GROUP_INDEX_OF_PATTERN = offsets;
|
|
14954
15563
|
return new RegExp(patterns.map((p) => `(${p.regex.source})`).join("|"), "g");
|
|
14955
15564
|
}
|
|
14956
15565
|
var state44 = {
|
|
@@ -14968,29 +15577,37 @@ var state44 = {
|
|
|
14968
15577
|
/** PostToolUse hook handle so teardown can unregister. */
|
|
14969
15578
|
postHookUnregister: null
|
|
14970
15579
|
};
|
|
14971
|
-
function
|
|
14972
|
-
if (!text) return [];
|
|
14973
|
-
if (text.length > RE_DOS_MAX_SCAN_LENGTH) return [];
|
|
14974
|
-
const found = /* @__PURE__ */ new Set();
|
|
15580
|
+
function scanWindow(window, found, startTime) {
|
|
14975
15581
|
COMBINED_REGEX.lastIndex = 0;
|
|
14976
15582
|
let m;
|
|
14977
|
-
|
|
14978
|
-
while ((m = COMBINED_REGEX.exec(text)) !== null) {
|
|
15583
|
+
while ((m = COMBINED_REGEX.exec(window)) !== null) {
|
|
14979
15584
|
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
14980
15585
|
throw new Error(
|
|
14981
|
-
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${
|
|
15586
|
+
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${window.length}-char window`
|
|
14982
15587
|
);
|
|
14983
15588
|
}
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
found.add(PATTERNS3[i].type);
|
|
14987
|
-
break;
|
|
14988
|
-
}
|
|
14989
|
-
}
|
|
15589
|
+
const type = patternTypeForGroups(m.slice(1));
|
|
15590
|
+
if (type !== void 0) found.add(type);
|
|
14990
15591
|
if (m.index === COMBINED_REGEX.lastIndex) {
|
|
14991
15592
|
COMBINED_REGEX.lastIndex += 1;
|
|
14992
15593
|
}
|
|
14993
15594
|
}
|
|
15595
|
+
}
|
|
15596
|
+
function findMatches(text) {
|
|
15597
|
+
if (!text) return [];
|
|
15598
|
+
const found = /* @__PURE__ */ new Set();
|
|
15599
|
+
const startTime = performance.now();
|
|
15600
|
+
if (text.length <= SCAN_WINDOW_LENGTH) {
|
|
15601
|
+
scanWindow(text, found, startTime);
|
|
15602
|
+
return Array.from(found).sort();
|
|
15603
|
+
}
|
|
15604
|
+
if (text.length > MAX_TOTAL_SCAN_LENGTH) {
|
|
15605
|
+
return [TOO_LARGE_MARKER];
|
|
15606
|
+
}
|
|
15607
|
+
const stride = SCAN_WINDOW_LENGTH - SCAN_WINDOW_OVERLAP;
|
|
15608
|
+
for (let offset = 0; offset < text.length; offset += stride) {
|
|
15609
|
+
scanWindow(text.slice(offset, offset + SCAN_WINDOW_LENGTH), found, startTime);
|
|
15610
|
+
}
|
|
14994
15611
|
return Array.from(found).sort();
|
|
14995
15612
|
}
|
|
14996
15613
|
function scanInput(input, depth = 0) {
|
|
@@ -15016,30 +15633,55 @@ function scanInput(input, depth = 0) {
|
|
|
15016
15633
|
}
|
|
15017
15634
|
return null;
|
|
15018
15635
|
}
|
|
15636
|
+
function redactString(text) {
|
|
15637
|
+
if (text.length > SCAN_WINDOW_LENGTH) {
|
|
15638
|
+
return { ok: false, reason: "oversized_input" };
|
|
15639
|
+
}
|
|
15640
|
+
const startTime = performance.now();
|
|
15641
|
+
let cursor = 0;
|
|
15642
|
+
let output = "";
|
|
15643
|
+
COMBINED_REGEX.lastIndex = 0;
|
|
15644
|
+
let match;
|
|
15645
|
+
while ((match = COMBINED_REGEX.exec(text)) !== null) {
|
|
15646
|
+
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
15647
|
+
return { ok: false, reason: "oversized_input" };
|
|
15648
|
+
}
|
|
15649
|
+
const type = patternTypeForGroups(match.slice(1));
|
|
15650
|
+
output += text.slice(cursor, match.index);
|
|
15651
|
+
output += `[REDACTED:${type ?? "unknown"}]`;
|
|
15652
|
+
cursor = COMBINED_REGEX.lastIndex;
|
|
15653
|
+
if (match.index === COMBINED_REGEX.lastIndex) {
|
|
15654
|
+
COMBINED_REGEX.lastIndex += 1;
|
|
15655
|
+
}
|
|
15656
|
+
}
|
|
15657
|
+
if (cursor === 0) return { ok: true, value: text };
|
|
15658
|
+
return { ok: true, value: output + text.slice(cursor) };
|
|
15659
|
+
}
|
|
15019
15660
|
function redactInput(input, depth = 0) {
|
|
15020
|
-
if (input === null || input === void 0) return input;
|
|
15021
|
-
if (depth > 50) return
|
|
15661
|
+
if (input === null || input === void 0) return { ok: true, value: input };
|
|
15662
|
+
if (depth > 50) return { ok: false, reason: "maximum_depth_exceeded" };
|
|
15022
15663
|
if (typeof input === "string") {
|
|
15023
|
-
return input
|
|
15024
|
-
for (let i = 0; i < PATTERNS3.length; i++) {
|
|
15025
|
-
if (groups[i] !== void 0) {
|
|
15026
|
-
return `[REDACTED:${PATTERNS3[i].type}]`;
|
|
15027
|
-
}
|
|
15028
|
-
}
|
|
15029
|
-
return "[REDACTED:unknown]";
|
|
15030
|
-
});
|
|
15664
|
+
return redactString(input);
|
|
15031
15665
|
}
|
|
15032
15666
|
if (Array.isArray(input)) {
|
|
15033
|
-
|
|
15667
|
+
const out = [];
|
|
15668
|
+
for (const item of input) {
|
|
15669
|
+
const redacted = redactInput(item, depth + 1);
|
|
15670
|
+
if (!redacted.ok) return redacted;
|
|
15671
|
+
out.push(redacted.value);
|
|
15672
|
+
}
|
|
15673
|
+
return { ok: true, value: out };
|
|
15034
15674
|
}
|
|
15035
15675
|
if (typeof input === "object") {
|
|
15036
15676
|
const out = {};
|
|
15037
15677
|
for (const [k, v] of Object.entries(input)) {
|
|
15038
|
-
|
|
15678
|
+
const redacted = redactInput(v, depth + 1);
|
|
15679
|
+
if (!redacted.ok) return redacted;
|
|
15680
|
+
out[k] = redacted.value;
|
|
15039
15681
|
}
|
|
15040
|
-
return out;
|
|
15682
|
+
return { ok: true, value: out };
|
|
15041
15683
|
}
|
|
15042
|
-
return input;
|
|
15684
|
+
return { ok: true, value: input };
|
|
15043
15685
|
}
|
|
15044
15686
|
var DEFAULTS39 = {
|
|
15045
15687
|
matcher: "bash|write|edit",
|
|
@@ -15099,20 +15741,21 @@ function buildHook(cfg, log) {
|
|
|
15099
15741
|
}
|
|
15100
15742
|
if (cfg.mode === "redact") {
|
|
15101
15743
|
const redacted = redactInput(input.toolInput);
|
|
15102
|
-
if (redacted !== null && typeof redacted === "object" && !Array.isArray(redacted)) {
|
|
15744
|
+
if (redacted.ok && redacted.value !== null && typeof redacted.value === "object" && !Array.isArray(redacted.value)) {
|
|
15103
15745
|
state44.redactCount += 1;
|
|
15104
15746
|
log.info(`[secret-scanner] redacted ${toolName} \u2014 matched: ${summary}`);
|
|
15105
15747
|
return {
|
|
15106
15748
|
decision: "allow",
|
|
15107
|
-
modifiedInput: redacted,
|
|
15749
|
+
modifiedInput: redacted.value,
|
|
15108
15750
|
additionalContext: `secret-scanner: redacted ${matched.length} credential pattern(s) from the ${toolName} arguments before execution.`
|
|
15109
15751
|
};
|
|
15110
15752
|
}
|
|
15111
15753
|
state44.blockCount += 1;
|
|
15112
15754
|
state44.lastBlock = { toolName, matchedTypes: matched, when };
|
|
15755
|
+
const detail = !redacted.ok ? redacted.reason === "oversized_input" ? "an input field exceeds the safe scan limit" : "the input exceeds the safe nesting depth" : "the input has a non-object shape";
|
|
15113
15756
|
return {
|
|
15114
15757
|
decision: "block",
|
|
15115
|
-
reason: `secret-scanner: cannot safely redact '${toolName}'
|
|
15758
|
+
reason: `secret-scanner: cannot safely redact '${toolName}' because ${detail}; refusing to run.`
|
|
15116
15759
|
};
|
|
15117
15760
|
}
|
|
15118
15761
|
state44.allowCount += 1;
|
|
@@ -15130,10 +15773,21 @@ function buildPostHook(cfg, log) {
|
|
|
15130
15773
|
const matched = findMatches(result.content);
|
|
15131
15774
|
if (matched.length === 0) return;
|
|
15132
15775
|
const toolName = input.toolName ?? "unknown";
|
|
15133
|
-
const
|
|
15776
|
+
const oversized = matched.includes(TOO_LARGE_MARKER);
|
|
15777
|
+
const credentialMatches = matched.filter((type) => type !== TOO_LARGE_MARKER);
|
|
15778
|
+
if (oversized && credentialMatches.length === 0) {
|
|
15779
|
+
log.warn(
|
|
15780
|
+
`[secret-scanner] POST-TOOL UNSCANNABLE: ${toolName} output exceeds ${MAX_TOTAL_SCAN_LENGTH} characters`
|
|
15781
|
+
);
|
|
15782
|
+
return {
|
|
15783
|
+
additionalContext: `
|
|
15784
|
+
\u26A0\uFE0F secret-scanner: the output of '${toolName}' exceeds the safe scan limit and could not be inspected for plaintext credentials. Do not treat this output as verified clean; avoid echoing, storing, committing, or transmitting it until it can be reviewed in smaller bounded sections.`
|
|
15785
|
+
};
|
|
15786
|
+
}
|
|
15787
|
+
const summary = credentialMatches.join(", ");
|
|
15134
15788
|
const when = (/* @__PURE__ */ new Date()).toISOString();
|
|
15135
15789
|
state44.leakCount += 1;
|
|
15136
|
-
state44.lastLeak = { toolName, matchedTypes:
|
|
15790
|
+
state44.lastLeak = { toolName, matchedTypes: credentialMatches, when };
|
|
15137
15791
|
log.warn(`[secret-scanner] POST-TOOL LEAK: ${toolName} output matched ${summary}`);
|
|
15138
15792
|
return {
|
|
15139
15793
|
additionalContext: `
|
|
@@ -15326,8 +15980,8 @@ var plugin46 = {
|
|
|
15326
15980
|
var secret_scanner_default = plugin46;
|
|
15327
15981
|
|
|
15328
15982
|
// src/security-hotspot-scanner/index.ts
|
|
15329
|
-
import { readdir as readdir2, readFile as
|
|
15330
|
-
import { isAbsolute as
|
|
15983
|
+
import { readdir as readdir2, readFile as readFile12, stat as stat5 } from "node:fs/promises";
|
|
15984
|
+
import { isAbsolute as isAbsolute20, relative as relative20, resolve as resolve21 } from "node:path";
|
|
15331
15985
|
var API_VERSION30 = "^0.1.10";
|
|
15332
15986
|
var state45 = {
|
|
15333
15987
|
scanCount: 0,
|
|
@@ -15337,7 +15991,7 @@ var state45 = {
|
|
|
15337
15991
|
skippedCount: 0,
|
|
15338
15992
|
blockedCount: 0,
|
|
15339
15993
|
lastResult: null,
|
|
15340
|
-
knownHotspots:
|
|
15994
|
+
knownHotspots: new BoundedSet({ max: 5e3 }),
|
|
15341
15995
|
hookUnregister: null
|
|
15342
15996
|
};
|
|
15343
15997
|
var DEFAULTS40 = {
|
|
@@ -15418,7 +16072,7 @@ function isSourceFile2(filePath, extensions) {
|
|
|
15418
16072
|
async function scanPath5(inputPath, cfg) {
|
|
15419
16073
|
const start = Date.now();
|
|
15420
16074
|
const root = process.cwd();
|
|
15421
|
-
const resolved =
|
|
16075
|
+
const resolved = isAbsolute20(inputPath) ? resolve21(inputPath) : resolve21(root, inputPath);
|
|
15422
16076
|
if (!withinProject(inputPath)) {
|
|
15423
16077
|
return {
|
|
15424
16078
|
path: inputPath,
|
|
@@ -15435,11 +16089,11 @@ async function scanPath5(inputPath, cfg) {
|
|
|
15435
16089
|
const scanFile2 = async (filePath) => {
|
|
15436
16090
|
if (!isSourceFile2(filePath, cfg.scanOnChange)) return;
|
|
15437
16091
|
try {
|
|
15438
|
-
const content = await
|
|
16092
|
+
const content = await readFile12(filePath, "utf-8");
|
|
15439
16093
|
filesScanned += 1;
|
|
15440
16094
|
const findings = scanSource(content, maxPerFile);
|
|
15441
16095
|
for (const f of findings) {
|
|
15442
|
-
allFindings.push({ ...f, snippet: `${
|
|
16096
|
+
allFindings.push({ ...f, snippet: `${relative20(root, filePath)}:${f.line}: ${f.snippet}` });
|
|
15443
16097
|
if (allFindings.length >= cfg.maxFindings) return;
|
|
15444
16098
|
}
|
|
15445
16099
|
} catch {
|
|
@@ -15454,7 +16108,7 @@ async function scanPath5(inputPath, cfg) {
|
|
|
15454
16108
|
}
|
|
15455
16109
|
for (const entry of entries) {
|
|
15456
16110
|
if (allFindings.length >= cfg.maxFindings) return;
|
|
15457
|
-
const full =
|
|
16111
|
+
const full = resolve21(dir, entry);
|
|
15458
16112
|
try {
|
|
15459
16113
|
const st = await stat5(full);
|
|
15460
16114
|
if (st.isDirectory()) {
|
|
@@ -15723,8 +16377,10 @@ var security_hotspot_scanner_default = plugin47;
|
|
|
15723
16377
|
|
|
15724
16378
|
// src/semantic-search-indexer/index.ts
|
|
15725
16379
|
import * as fs2 from "node:fs/promises";
|
|
15726
|
-
import { isAbsolute as
|
|
16380
|
+
import { isAbsolute as isAbsolute21, relative as relative21, resolve as resolve22 } from "node:path";
|
|
16381
|
+
import { DEFAULT_WALK_IGNORE_DIRS } from "@wrongstack/core/utils";
|
|
15727
16382
|
var API_VERSION31 = "^0.1.10";
|
|
16383
|
+
var escapeRegex2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15728
16384
|
var state46 = {
|
|
15729
16385
|
index: null,
|
|
15730
16386
|
cachedPath: null,
|
|
@@ -15768,7 +16424,11 @@ var DEFAULTS41 = {
|
|
|
15768
16424
|
".scss",
|
|
15769
16425
|
".html"
|
|
15770
16426
|
],
|
|
15771
|
-
excludePatterns: [
|
|
16427
|
+
excludePatterns: [
|
|
16428
|
+
...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex2),
|
|
16429
|
+
"\\.wrongstack",
|
|
16430
|
+
"\\.temp_files"
|
|
16431
|
+
],
|
|
15772
16432
|
maxFileBytes: 1e6,
|
|
15773
16433
|
defaultLimit: 10,
|
|
15774
16434
|
minTokenLength: 2,
|
|
@@ -15798,18 +16458,18 @@ function normalizeSlashes2(p) {
|
|
|
15798
16458
|
function withinProject5(p) {
|
|
15799
16459
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
15800
16460
|
const root = normalizeSlashes2(process.cwd());
|
|
15801
|
-
const resolved = normalizeSlashes2(
|
|
15802
|
-
const rel = normalizeSlashes2(
|
|
16461
|
+
const resolved = normalizeSlashes2(isAbsolute21(p) ? resolve22(p) : resolve22(root, p));
|
|
16462
|
+
const rel = normalizeSlashes2(relative21(root, resolved));
|
|
15803
16463
|
if (rel === "" || rel === ".") return true;
|
|
15804
16464
|
if (rel.startsWith("..")) return false;
|
|
15805
|
-
if (
|
|
16465
|
+
if (isAbsolute21(rel)) return false;
|
|
15806
16466
|
return true;
|
|
15807
16467
|
}
|
|
15808
16468
|
function resolveProjectPath8(p) {
|
|
15809
16469
|
const raw = typeof p === "string" && p.length > 0 ? p : ".";
|
|
15810
16470
|
if (!withinProject5(raw)) return null;
|
|
15811
16471
|
const root = normalizeSlashes2(process.cwd());
|
|
15812
|
-
return normalizeSlashes2(
|
|
16472
|
+
return normalizeSlashes2(isAbsolute21(raw) ? resolve22(raw) : resolve22(root, raw));
|
|
15813
16473
|
}
|
|
15814
16474
|
function tokenize(text, minLength) {
|
|
15815
16475
|
const tokens = [];
|
|
@@ -15839,7 +16499,7 @@ function shouldIndexFile(filePath, cfg) {
|
|
|
15839
16499
|
var INDEX_BATCH_SIZE = 32;
|
|
15840
16500
|
var YIELD_EVERY_FILES = 64;
|
|
15841
16501
|
function yieldEventLoop() {
|
|
15842
|
-
return new Promise((
|
|
16502
|
+
return new Promise((resolve28) => setImmediate(resolve28));
|
|
15843
16503
|
}
|
|
15844
16504
|
function addFileToIndex(relPath, content, size, cfg) {
|
|
15845
16505
|
if (!state46.index || content.includes("\0")) return;
|
|
@@ -15893,8 +16553,8 @@ async function walkDirectory(absPath, cfg, excludes, fileBatch) {
|
|
|
15893
16553
|
state46.truncated = true;
|
|
15894
16554
|
return;
|
|
15895
16555
|
}
|
|
15896
|
-
const absChild = normalizeSlashes2(
|
|
15897
|
-
const relChild = normalizeSlashes2(
|
|
16556
|
+
const absChild = normalizeSlashes2(resolve22(absPath, ent.name));
|
|
16557
|
+
const relChild = normalizeSlashes2(relative21(root, absChild));
|
|
15898
16558
|
if (relChild === "" || relChild === ".") continue;
|
|
15899
16559
|
if (excludes.some((re) => re.test(relChild))) continue;
|
|
15900
16560
|
if (ent.isDirectory()) {
|
|
@@ -15936,7 +16596,7 @@ async function buildIndex(rootPath, cfg) {
|
|
|
15936
16596
|
return;
|
|
15937
16597
|
}
|
|
15938
16598
|
if (rootStats.isFile()) {
|
|
15939
|
-
const relPath = normalizeSlashes2(
|
|
16599
|
+
const relPath = normalizeSlashes2(relative21(normalizeSlashes2(process.cwd()), rootPath));
|
|
15940
16600
|
await indexFileFromStats(rootPath, relPath === "" ? "." : relPath, rootStats, cfg);
|
|
15941
16601
|
state46.fileCount = state46.index.files.size;
|
|
15942
16602
|
} else if (rootStats.isDirectory()) {
|
|
@@ -16232,15 +16892,15 @@ var semantic_search_indexer_default = plugin48;
|
|
|
16232
16892
|
import { expectDefined as expectDefined2 } from "@wrongstack/core/utils";
|
|
16233
16893
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
16234
16894
|
import { execFile as execFile12 } from "node:child_process";
|
|
16235
|
-
import { access as access3, readFile as
|
|
16236
|
-
import { isAbsolute as
|
|
16895
|
+
import { access as access3, readFile as readFile14, readdir as readdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
16896
|
+
import { isAbsolute as isAbsolute22, join as join5, relative as relative22, resolve as resolve23 } from "node:path";
|
|
16237
16897
|
var API_VERSION32 = "^0.1.10";
|
|
16238
16898
|
function resolveProjectRoot(rawCwd, root = process.cwd()) {
|
|
16239
16899
|
if (typeof rawCwd !== "string" || rawCwd.length === 0) return root;
|
|
16240
|
-
const base =
|
|
16241
|
-
const resolved =
|
|
16242
|
-
const rel =
|
|
16243
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
16900
|
+
const base = resolve23(root);
|
|
16901
|
+
const resolved = isAbsolute22(rawCwd) ? resolve23(rawCwd) : resolve23(base, rawCwd);
|
|
16902
|
+
const rel = relative22(base, resolved);
|
|
16903
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute22(rel)) return resolved;
|
|
16244
16904
|
return null;
|
|
16245
16905
|
}
|
|
16246
16906
|
var state47 = {
|
|
@@ -16252,7 +16912,7 @@ var state47 = {
|
|
|
16252
16912
|
lastBump: null
|
|
16253
16913
|
};
|
|
16254
16914
|
function runCommand3(command, args, cwd) {
|
|
16255
|
-
return new Promise((
|
|
16915
|
+
return new Promise((resolve28, reject) => {
|
|
16256
16916
|
execFile12(command, args, {
|
|
16257
16917
|
encoding: "utf-8",
|
|
16258
16918
|
cwd,
|
|
@@ -16260,7 +16920,7 @@ function runCommand3(command, args, cwd) {
|
|
|
16260
16920
|
windowsHide: true
|
|
16261
16921
|
}, (err, stdout, stderr) => {
|
|
16262
16922
|
if (!err) {
|
|
16263
|
-
|
|
16923
|
+
resolve28(stdout.trim());
|
|
16264
16924
|
return;
|
|
16265
16925
|
}
|
|
16266
16926
|
const failure = err;
|
|
@@ -16281,21 +16941,21 @@ async function getPackageJson(cwd) {
|
|
|
16281
16941
|
const path = cwd ? `${cwd}/package.json` : "package.json";
|
|
16282
16942
|
try {
|
|
16283
16943
|
await access3(path);
|
|
16284
|
-
return JSON.parse(await
|
|
16944
|
+
return JSON.parse(await readFile14(path, "utf-8"));
|
|
16285
16945
|
} catch {
|
|
16286
16946
|
return null;
|
|
16287
16947
|
}
|
|
16288
16948
|
}
|
|
16289
16949
|
async function collectManifests(root) {
|
|
16290
16950
|
const paths = [];
|
|
16291
|
-
const rootPkg =
|
|
16951
|
+
const rootPkg = join5(root, "package.json");
|
|
16292
16952
|
try {
|
|
16293
16953
|
await access3(rootPkg);
|
|
16294
16954
|
paths.push(rootPkg);
|
|
16295
16955
|
} catch {
|
|
16296
16956
|
}
|
|
16297
16957
|
for (const group of ["packages", "apps"]) {
|
|
16298
|
-
const groupDir =
|
|
16958
|
+
const groupDir = join5(root, group);
|
|
16299
16959
|
let entries;
|
|
16300
16960
|
try {
|
|
16301
16961
|
entries = await readdir4(groupDir, { withFileTypes: true });
|
|
@@ -16304,7 +16964,7 @@ async function collectManifests(root) {
|
|
|
16304
16964
|
}
|
|
16305
16965
|
for (const entry of entries) {
|
|
16306
16966
|
if (!entry.isDirectory()) continue;
|
|
16307
|
-
const candidate =
|
|
16967
|
+
const candidate = join5(groupDir, entry.name, "package.json");
|
|
16308
16968
|
try {
|
|
16309
16969
|
await access3(candidate);
|
|
16310
16970
|
paths.push(candidate);
|
|
@@ -16499,7 +17159,7 @@ var plugin49 = {
|
|
|
16499
17159
|
};
|
|
16500
17160
|
}
|
|
16501
17161
|
const root = cwd ?? process.cwd();
|
|
16502
|
-
const bumpScript =
|
|
17162
|
+
const bumpScript = join5(root, "scripts", "bump-version.mjs");
|
|
16503
17163
|
const changed = await collectManifests(root);
|
|
16504
17164
|
let hasBumpScript = true;
|
|
16505
17165
|
try {
|
|
@@ -16515,7 +17175,7 @@ var plugin49 = {
|
|
|
16515
17175
|
return { ok: false, error: `bump script failed: ${msg}` };
|
|
16516
17176
|
}
|
|
16517
17177
|
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
16518
|
-
const p =
|
|
17178
|
+
const p = join5(root, "website", rel);
|
|
16519
17179
|
try {
|
|
16520
17180
|
await access3(p);
|
|
16521
17181
|
changed.push(p);
|
|
@@ -16523,10 +17183,29 @@ var plugin49 = {
|
|
|
16523
17183
|
}
|
|
16524
17184
|
}
|
|
16525
17185
|
} else {
|
|
17186
|
+
const pending = [];
|
|
16526
17187
|
for (const manifest of changed) {
|
|
16527
|
-
|
|
17188
|
+
let pkgData;
|
|
17189
|
+
try {
|
|
17190
|
+
pkgData = JSON.parse(await readFile14(manifest, "utf-8"));
|
|
17191
|
+
} catch (err) {
|
|
17192
|
+
return {
|
|
17193
|
+
ok: false,
|
|
17194
|
+
error: `cannot bump: ${manifest} is not readable as JSON (${toErrorMessage(err)}). No manifests were modified.`
|
|
17195
|
+
};
|
|
17196
|
+
}
|
|
17197
|
+
if (!pkgData || typeof pkgData !== "object") {
|
|
17198
|
+
return {
|
|
17199
|
+
ok: false,
|
|
17200
|
+
error: `cannot bump: ${manifest} does not contain a JSON object. No manifests were modified.`
|
|
17201
|
+
};
|
|
17202
|
+
}
|
|
16528
17203
|
pkgData.version = newVersion;
|
|
16529
|
-
|
|
17204
|
+
pending.push({ path: manifest, contents: `${JSON.stringify(pkgData, null, 2)}
|
|
17205
|
+
` });
|
|
17206
|
+
}
|
|
17207
|
+
for (const { path, contents } of pending) {
|
|
17208
|
+
await writeFile4(path, contents, "utf-8");
|
|
16530
17209
|
}
|
|
16531
17210
|
}
|
|
16532
17211
|
try {
|
|
@@ -16864,8 +17543,8 @@ async function readTranscriptTail(transcriptPath, n) {
|
|
|
16864
17543
|
if (!transcriptPath || n <= 0) return [];
|
|
16865
17544
|
let raw;
|
|
16866
17545
|
try {
|
|
16867
|
-
const { readFile:
|
|
16868
|
-
raw = await
|
|
17546
|
+
const { readFile: readFile18 } = await import("node:fs/promises");
|
|
17547
|
+
raw = await readFile18(transcriptPath, "utf-8");
|
|
16869
17548
|
} catch {
|
|
16870
17549
|
return [];
|
|
16871
17550
|
}
|
|
@@ -17206,15 +17885,15 @@ var session_recap_default = plugin50;
|
|
|
17206
17885
|
// src/shell-check/index.ts
|
|
17207
17886
|
import { execFile as execFile13 } from "node:child_process";
|
|
17208
17887
|
import { readdir as readdir5 } from "node:fs/promises";
|
|
17209
|
-
import { isAbsolute as
|
|
17888
|
+
import { isAbsolute as isAbsolute23, join as join6, relative as relative23, resolve as resolve24 } from "node:path";
|
|
17210
17889
|
var API_VERSION33 = "^0.1.10";
|
|
17211
17890
|
function withinProject6(p) {
|
|
17212
17891
|
const root = process.cwd();
|
|
17213
|
-
const resolved =
|
|
17214
|
-
const rel =
|
|
17892
|
+
const resolved = isAbsolute23(p) ? resolve24(p) : resolve24(root, p);
|
|
17893
|
+
const rel = relative23(root, resolved);
|
|
17215
17894
|
if (rel === "" || rel === ".") return true;
|
|
17216
17895
|
if (rel.startsWith("..")) return false;
|
|
17217
|
-
if (
|
|
17896
|
+
if (isAbsolute23(rel)) return false;
|
|
17218
17897
|
return true;
|
|
17219
17898
|
}
|
|
17220
17899
|
var MAX_PATH_LEN = 4096;
|
|
@@ -17307,7 +17986,7 @@ async function findShellFiles(dir, pattern) {
|
|
|
17307
17986
|
return results;
|
|
17308
17987
|
}
|
|
17309
17988
|
for (const entry of entries) {
|
|
17310
|
-
const full =
|
|
17989
|
+
const full = join6(dir, entry.name);
|
|
17311
17990
|
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
|
|
17312
17991
|
results.push(...await findShellFiles(full, pattern));
|
|
17313
17992
|
} else if (entry.isFile() && (entry.name.endsWith(".sh") || entry.name === "Dockerfile")) {
|
|
@@ -17506,8 +18185,8 @@ var plugin51 = {
|
|
|
17506
18185
|
var shell_check_default = plugin51;
|
|
17507
18186
|
|
|
17508
18187
|
// src/smart-rename/index.ts
|
|
17509
|
-
import { readFileSync as
|
|
17510
|
-
import { extname as
|
|
18188
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18189
|
+
import { extname as extname6, isAbsolute as isAbsolute24, relative as relative24, resolve as resolve25 } from "node:path";
|
|
17511
18190
|
var API_VERSION34 = "^0.1.10";
|
|
17512
18191
|
var state50 = {
|
|
17513
18192
|
renameCount: 0,
|
|
@@ -17529,24 +18208,24 @@ function readConfig46(raw) {
|
|
|
17529
18208
|
function withinProject7(p) {
|
|
17530
18209
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
17531
18210
|
const root = process.cwd();
|
|
17532
|
-
const resolved =
|
|
17533
|
-
const rel =
|
|
18211
|
+
const resolved = isAbsolute24(p) ? resolve25(p) : resolve25(root, p);
|
|
18212
|
+
const rel = relative24(root, resolved);
|
|
17534
18213
|
if (rel === "" || rel === ".") return true;
|
|
17535
18214
|
if (rel.startsWith("..")) return false;
|
|
17536
|
-
if (
|
|
18215
|
+
if (isAbsolute24(rel)) return false;
|
|
17537
18216
|
return true;
|
|
17538
18217
|
}
|
|
17539
18218
|
function toPosix7(p) {
|
|
17540
18219
|
return p.replace(/\\/g, "/");
|
|
17541
18220
|
}
|
|
17542
18221
|
function relativePath7(p) {
|
|
17543
|
-
return toPosix7(
|
|
18222
|
+
return toPosix7(relative24(process.cwd(), p));
|
|
17544
18223
|
}
|
|
17545
|
-
function
|
|
18224
|
+
function escapeRegex3(s) {
|
|
17546
18225
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17547
18226
|
}
|
|
17548
18227
|
function renameInContent(content, oldName, newName) {
|
|
17549
|
-
const re = new RegExp(`\\b${
|
|
18228
|
+
const re = new RegExp(`\\b${escapeRegex3(oldName)}\\b`, "g");
|
|
17550
18229
|
let replacements = 0;
|
|
17551
18230
|
const preview = content.replace(re, () => {
|
|
17552
18231
|
replacements++;
|
|
@@ -17611,14 +18290,14 @@ var plugin52 = {
|
|
|
17611
18290
|
if (!withinProject7(rawPath)) {
|
|
17612
18291
|
return { ok: false, error: "path is outside the project root" };
|
|
17613
18292
|
}
|
|
17614
|
-
const ext =
|
|
18293
|
+
const ext = extname6(rawPath).toLowerCase();
|
|
17615
18294
|
if (!cfg.extensions.includes(ext)) {
|
|
17616
18295
|
return { ok: false, error: `extension ${ext} is not allowed for rename` };
|
|
17617
18296
|
}
|
|
17618
|
-
const resolved =
|
|
18297
|
+
const resolved = resolve25(process.cwd(), rawPath);
|
|
17619
18298
|
let content;
|
|
17620
18299
|
try {
|
|
17621
|
-
content =
|
|
18300
|
+
content = readFileSync13(resolved, "utf-8");
|
|
17622
18301
|
} catch (err) {
|
|
17623
18302
|
state50.errorCount += 1;
|
|
17624
18303
|
return { ok: false, error: String(err) };
|
|
@@ -17628,7 +18307,7 @@ var plugin52 = {
|
|
|
17628
18307
|
state50.replacementCount += replacements;
|
|
17629
18308
|
if (input.apply) {
|
|
17630
18309
|
try {
|
|
17631
|
-
|
|
18310
|
+
writeFileSync2(resolved, preview, "utf-8");
|
|
17632
18311
|
} catch (err) {
|
|
17633
18312
|
state50.errorCount += 1;
|
|
17634
18313
|
return { ok: false, error: String(err) };
|
|
@@ -18159,8 +18838,8 @@ ${lines}${overflowNote}`
|
|
|
18159
18838
|
var spec_linker_default = plugin53;
|
|
18160
18839
|
|
|
18161
18840
|
// src/template-engine/index.ts
|
|
18162
|
-
import { readFile as
|
|
18163
|
-
import { isAbsolute as
|
|
18841
|
+
import { readFile as readFile16, writeFile as writeFile5 } from "node:fs/promises";
|
|
18842
|
+
import { isAbsolute as isAbsolute25 } from "node:path";
|
|
18164
18843
|
var API_VERSION35 = "^0.1.10";
|
|
18165
18844
|
var templates = /* @__PURE__ */ new Map();
|
|
18166
18845
|
function expandTemplate(template, variables) {
|
|
@@ -18207,9 +18886,12 @@ function renderTemplateRaw(template, variables) {
|
|
|
18207
18886
|
return result;
|
|
18208
18887
|
}
|
|
18209
18888
|
function validateRelativeTemplatePath(field, value) {
|
|
18210
|
-
if (
|
|
18889
|
+
if (isAbsolute25(value) || value.split(/[\\/]+/).includes("..")) {
|
|
18211
18890
|
return `${field} must be a relative path without ".." components`;
|
|
18212
18891
|
}
|
|
18892
|
+
if (!withinProject(value)) {
|
|
18893
|
+
return `${field} must resolve inside the project directory`;
|
|
18894
|
+
}
|
|
18213
18895
|
return null;
|
|
18214
18896
|
}
|
|
18215
18897
|
var plugin54 = {
|
|
@@ -18333,7 +19015,7 @@ var plugin54 = {
|
|
|
18333
19015
|
}
|
|
18334
19016
|
let content;
|
|
18335
19017
|
try {
|
|
18336
|
-
content = await
|
|
19018
|
+
content = await readFile16(template_path, "utf-8");
|
|
18337
19019
|
} catch (err) {
|
|
18338
19020
|
return { ok: false, error: `Could not read template file: ${err}` };
|
|
18339
19021
|
}
|
|
@@ -18465,7 +19147,7 @@ var plugin54 = {
|
|
|
18465
19147
|
var template_engine_default = plugin54;
|
|
18466
19148
|
|
|
18467
19149
|
// src/test-coverage-gate/index.ts
|
|
18468
|
-
import { readFileSync as
|
|
19150
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
18469
19151
|
var API_VERSION36 = "^0.1.10";
|
|
18470
19152
|
var state52 = {
|
|
18471
19153
|
invocationCount: 0,
|
|
@@ -18506,7 +19188,7 @@ function readConfig48(raw) {
|
|
|
18506
19188
|
}
|
|
18507
19189
|
function readCoverageSummary(coveragePath) {
|
|
18508
19190
|
try {
|
|
18509
|
-
const raw =
|
|
19191
|
+
const raw = readFileSync14(coveragePath, "utf-8");
|
|
18510
19192
|
return JSON.parse(raw);
|
|
18511
19193
|
} catch {
|
|
18512
19194
|
return null;
|
|
@@ -18722,9 +19404,9 @@ var test_coverage_gate_default = plugin55;
|
|
|
18722
19404
|
|
|
18723
19405
|
// src/test-flake-detector/index.ts
|
|
18724
19406
|
import { execFile as execFile14 } from "node:child_process";
|
|
18725
|
-
import { readFileSync as
|
|
18726
|
-
import { createRequire as
|
|
18727
|
-
import { dirname as
|
|
19407
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
19408
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
19409
|
+
import { dirname as dirname8, isAbsolute as isAbsolute26, relative as relative25, resolve as resolve26 } from "node:path";
|
|
18728
19410
|
var API_VERSION37 = "^0.1.10";
|
|
18729
19411
|
var state53 = {
|
|
18730
19412
|
invocationCount: 0,
|
|
@@ -18795,15 +19477,15 @@ var ALLOWED_RUNNER_FLAGS = /* @__PURE__ */ new Set([
|
|
|
18795
19477
|
]);
|
|
18796
19478
|
function withinProject8(p) {
|
|
18797
19479
|
if (p.length === 0 || p.length > 4096 || p.startsWith("-")) return false;
|
|
18798
|
-
const root =
|
|
18799
|
-
const resolved =
|
|
18800
|
-
const rel =
|
|
18801
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
19480
|
+
const root = resolve26(process.cwd());
|
|
19481
|
+
const resolved = isAbsolute26(p) ? resolve26(p) : resolve26(root, p);
|
|
19482
|
+
const rel = relative25(root, resolved);
|
|
19483
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute26(rel);
|
|
18802
19484
|
}
|
|
18803
|
-
function
|
|
19485
|
+
function isInside3(parent, child) {
|
|
18804
19486
|
if (parent === child) return true;
|
|
18805
|
-
const rel =
|
|
18806
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
19487
|
+
const rel = relative25(parent, child);
|
|
19488
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute26(rel);
|
|
18807
19489
|
}
|
|
18808
19490
|
function tokenizeCommand(command) {
|
|
18809
19491
|
const trimmed = command.trim();
|
|
@@ -18840,14 +19522,14 @@ function resolveTestCommand(baseCommand, testPattern) {
|
|
|
18840
19522
|
if (runnerArgs.some((arg) => !ALLOWED_RUNNER_FLAGS.has(arg))) return null;
|
|
18841
19523
|
let resolvedEntry;
|
|
18842
19524
|
try {
|
|
18843
|
-
const requireFromProject =
|
|
19525
|
+
const requireFromProject = createRequire3(resolve26(process.cwd(), "package.json"));
|
|
18844
19526
|
const packagePath = requireFromProject.resolve(`${runner}/package.json`);
|
|
18845
|
-
const packageJson = JSON.parse(
|
|
19527
|
+
const packageJson = JSON.parse(readFileSync15(packagePath, "utf8"));
|
|
18846
19528
|
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[runner] ?? Object.values(packageJson.bin ?? {})[0];
|
|
18847
19529
|
if (!relativeBin) return null;
|
|
18848
|
-
const packageDir =
|
|
18849
|
-
const candidate =
|
|
18850
|
-
if (
|
|
19530
|
+
const packageDir = dirname8(packagePath);
|
|
19531
|
+
const candidate = resolve26(packageDir, relativeBin);
|
|
19532
|
+
if (isAbsolute26(relativeBin) || !isInside3(packageDir, candidate)) {
|
|
18851
19533
|
return null;
|
|
18852
19534
|
}
|
|
18853
19535
|
resolvedEntry = candidate;
|
|
@@ -19089,8 +19771,8 @@ var plugin56 = {
|
|
|
19089
19771
|
var test_flake_detector_default = plugin56;
|
|
19090
19772
|
|
|
19091
19773
|
// src/test-generator/index.ts
|
|
19092
|
-
import { readFileSync as
|
|
19093
|
-
import { isAbsolute as
|
|
19774
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
19775
|
+
import { isAbsolute as isAbsolute27, relative as relative26, resolve as resolve27 } from "node:path";
|
|
19094
19776
|
var API_VERSION38 = "^0.1.10";
|
|
19095
19777
|
var state54 = {
|
|
19096
19778
|
generateCount: 0,
|
|
@@ -19125,18 +19807,18 @@ function readConfig50(raw) {
|
|
|
19125
19807
|
function withinProject9(p) {
|
|
19126
19808
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
19127
19809
|
const root = process.cwd();
|
|
19128
|
-
const resolved =
|
|
19129
|
-
const rel =
|
|
19810
|
+
const resolved = isAbsolute27(p) ? resolve27(p) : resolve27(root, p);
|
|
19811
|
+
const rel = relative26(root, resolved);
|
|
19130
19812
|
if (rel === "" || rel === ".") return true;
|
|
19131
19813
|
if (rel.startsWith("..")) return false;
|
|
19132
|
-
if (
|
|
19814
|
+
if (isAbsolute27(rel)) return false;
|
|
19133
19815
|
return true;
|
|
19134
19816
|
}
|
|
19135
19817
|
function toPosix8(p) {
|
|
19136
19818
|
return p.replace(/\\/g, "/");
|
|
19137
19819
|
}
|
|
19138
19820
|
function relativePath8(p) {
|
|
19139
|
-
return toPosix8(
|
|
19821
|
+
return toPosix8(relative26(process.cwd(), p));
|
|
19140
19822
|
}
|
|
19141
19823
|
function detectExports(content) {
|
|
19142
19824
|
const exports = [];
|
|
@@ -19230,7 +19912,7 @@ function generateTestContent(sourcePath, sourceModule, detected, cfg) {
|
|
|
19230
19912
|
return lines.join("\n");
|
|
19231
19913
|
}
|
|
19232
19914
|
function generateForFile(filePath, cfg) {
|
|
19233
|
-
const sourceContent =
|
|
19915
|
+
const sourceContent = readFileSync16(filePath, "utf-8");
|
|
19234
19916
|
const detected = detectExports(sourceContent);
|
|
19235
19917
|
const sourceFile = relativePath8(filePath);
|
|
19236
19918
|
const sourceParts = sourceFile.split("/");
|
|
@@ -19349,7 +20031,7 @@ var plugin57 = {
|
|
|
19349
20031
|
if (!withinProject9(rawPath)) {
|
|
19350
20032
|
return { ok: false, error: "path is outside the project root" };
|
|
19351
20033
|
}
|
|
19352
|
-
const resolved =
|
|
20034
|
+
const resolved = resolve27(process.cwd(), rawPath);
|
|
19353
20035
|
state54.generateCount += 1;
|
|
19354
20036
|
let result;
|
|
19355
20037
|
try {
|
|
@@ -19435,7 +20117,17 @@ var test_generator_default = plugin57;
|
|
|
19435
20117
|
// src/test-runner-gate/index.ts
|
|
19436
20118
|
import { execFile as execFile15 } from "node:child_process";
|
|
19437
20119
|
import { access as access4 } from "node:fs/promises";
|
|
19438
|
-
import { basename as basename6, dirname as
|
|
20120
|
+
import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute28, join as join7 } from "node:path";
|
|
20121
|
+
import { buildWin32CmdShimInvocation as buildWin32CmdShimInvocation2, resolveWin32Command as resolveWin32Command2 } from "@wrongstack/tools/win32";
|
|
20122
|
+
function resolveExec(command, args) {
|
|
20123
|
+
const resolved = resolveWin32Command2(command);
|
|
20124
|
+
const needsShell = process.platform === "win32" && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
20125
|
+
if (needsShell) {
|
|
20126
|
+
const shim = buildWin32CmdShimInvocation2(resolved, args);
|
|
20127
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
20128
|
+
}
|
|
20129
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
20130
|
+
}
|
|
19439
20131
|
var API_VERSION39 = "^0.1.10";
|
|
19440
20132
|
var state55 = {
|
|
19441
20133
|
invocationCount: 0,
|
|
@@ -19500,7 +20192,7 @@ function pathContentHash(content) {
|
|
|
19500
20192
|
}
|
|
19501
20193
|
return h >>> 0;
|
|
19502
20194
|
}
|
|
19503
|
-
var lastPassedHash =
|
|
20195
|
+
var lastPassedHash = new BoundedMap({ max: 1024 });
|
|
19504
20196
|
var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
19505
20197
|
"npx",
|
|
19506
20198
|
"pnpm",
|
|
@@ -19518,7 +20210,7 @@ var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
19518
20210
|
function resolveTestFiles(sourcePath, patterns) {
|
|
19519
20211
|
const name = basename6(sourcePath).replace(/\.[^.]+$/, "");
|
|
19520
20212
|
const pathNoExt = sourcePath.replace(/\.[^.]+$/, "");
|
|
19521
|
-
const dir =
|
|
20213
|
+
const dir = dirname9(sourcePath);
|
|
19522
20214
|
const candidates = [];
|
|
19523
20215
|
for (const pattern of patterns) {
|
|
19524
20216
|
const candidate = pattern.replace(/\{name\}/g, name).replace(/\{path\}/g, pathNoExt).replace(/\{dir\}/g, dir);
|
|
@@ -19527,7 +20219,7 @@ function resolveTestFiles(sourcePath, patterns) {
|
|
|
19527
20219
|
candidates.push(candidate);
|
|
19528
20220
|
} else {
|
|
19529
20221
|
candidates.push(candidate);
|
|
19530
|
-
candidates.push(
|
|
20222
|
+
candidates.push(join7(dir, candidate));
|
|
19531
20223
|
}
|
|
19532
20224
|
}
|
|
19533
20225
|
}
|
|
@@ -19554,12 +20246,15 @@ async function detectRunner(requested) {
|
|
|
19554
20246
|
const match = candidates.find((c) => c.name === requested);
|
|
19555
20247
|
if (!match) return null;
|
|
19556
20248
|
try {
|
|
19557
|
-
await new Promise((
|
|
19558
|
-
|
|
20249
|
+
await new Promise((resolve28, reject) => {
|
|
20250
|
+
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
20251
|
+
execFile15(ex.cmd, ex.args, {
|
|
19559
20252
|
encoding: "utf-8",
|
|
19560
20253
|
timeout: 5e3,
|
|
19561
|
-
cwd: process.cwd()
|
|
19562
|
-
|
|
20254
|
+
cwd: process.cwd(),
|
|
20255
|
+
windowsHide: true,
|
|
20256
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20257
|
+
}, (err) => err ? reject(err) : resolve28());
|
|
19563
20258
|
});
|
|
19564
20259
|
return match;
|
|
19565
20260
|
} catch {
|
|
@@ -19568,12 +20263,15 @@ async function detectRunner(requested) {
|
|
|
19568
20263
|
}
|
|
19569
20264
|
for (const candidate of candidates) {
|
|
19570
20265
|
try {
|
|
19571
|
-
await new Promise((
|
|
19572
|
-
|
|
20266
|
+
await new Promise((resolve28, reject) => {
|
|
20267
|
+
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
20268
|
+
execFile15(ex.cmd, ex.args, {
|
|
19573
20269
|
encoding: "utf-8",
|
|
19574
20270
|
timeout: 5e3,
|
|
19575
|
-
cwd: process.cwd()
|
|
19576
|
-
|
|
20271
|
+
cwd: process.cwd(),
|
|
20272
|
+
windowsHide: true,
|
|
20273
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20274
|
+
}, (err) => err ? reject(err) : resolve28());
|
|
19577
20275
|
});
|
|
19578
20276
|
return candidate;
|
|
19579
20277
|
} catch {
|
|
@@ -19588,7 +20286,7 @@ function resolveAllowedCommand2(customCommand) {
|
|
|
19588
20286
|
if (ALLOWED_COMMAND_TOKENS.has(head)) {
|
|
19589
20287
|
return { cmd: head, args: tokens.slice(1) };
|
|
19590
20288
|
}
|
|
19591
|
-
if (
|
|
20289
|
+
if (isAbsolute28(head)) {
|
|
19592
20290
|
if (!withinProject(head)) return null;
|
|
19593
20291
|
const base = basename6(head);
|
|
19594
20292
|
if (ALLOWED_COMMAND_TOKENS.has(base)) {
|
|
@@ -19619,14 +20317,21 @@ async function runTests(testFile, runner, customCommand, timeoutMs) {
|
|
|
19619
20317
|
let stdout = "";
|
|
19620
20318
|
try {
|
|
19621
20319
|
const { stdout: out } = await new Promise(
|
|
19622
|
-
(
|
|
20320
|
+
(resolve28, reject) => {
|
|
20321
|
+
const ex = resolveExec(cmd, fullArgs);
|
|
19623
20322
|
execFile15(
|
|
19624
|
-
cmd,
|
|
19625
|
-
|
|
19626
|
-
{
|
|
20323
|
+
ex.cmd,
|
|
20324
|
+
ex.args,
|
|
20325
|
+
{
|
|
20326
|
+
encoding: "utf-8",
|
|
20327
|
+
timeout: timeoutMs,
|
|
20328
|
+
cwd: process.cwd(),
|
|
20329
|
+
windowsHide: true,
|
|
20330
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20331
|
+
},
|
|
19627
20332
|
(err, out2, stderr) => {
|
|
19628
20333
|
if (err) reject(Object.assign(err, { stdout: out2, stderr }));
|
|
19629
|
-
else
|
|
20334
|
+
else resolve28({ stdout: out2, stderr });
|
|
19630
20335
|
}
|
|
19631
20336
|
);
|
|
19632
20337
|
}
|
|
@@ -20035,7 +20740,7 @@ var plugin59 = {
|
|
|
20035
20740
|
0,
|
|
20036
20741
|
200
|
|
20037
20742
|
);
|
|
20038
|
-
const body =
|
|
20743
|
+
const body = safeJsonStringify(payload, 2);
|
|
20039
20744
|
const sendInput = {
|
|
20040
20745
|
from: `plugin:todo-listener`,
|
|
20041
20746
|
to: "*",
|
|
@@ -20139,6 +20844,7 @@ var todo_listener_default = plugin59;
|
|
|
20139
20844
|
// src/todo-tracker/index.ts
|
|
20140
20845
|
import * as fsp from "node:fs/promises";
|
|
20141
20846
|
import { randomUUID } from "node:crypto";
|
|
20847
|
+
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
20142
20848
|
function deriveFilePath(api) {
|
|
20143
20849
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
20144
20850
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -20168,10 +20874,8 @@ async function loadFile(filePath) {
|
|
|
20168
20874
|
}
|
|
20169
20875
|
}
|
|
20170
20876
|
async function saveFile(filePath, file) {
|
|
20171
|
-
|
|
20172
|
-
await
|
|
20173
|
-
await fsp.writeFile(tmp, JSON.stringify(file, null, 2), { encoding: "utf8", mode: 384 });
|
|
20174
|
-
await fsp.rename(tmp, filePath);
|
|
20877
|
+
await ensureDir3(filePath.replace(/[/\\][^/\\]+$/, ""));
|
|
20878
|
+
await atomicWrite3(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
20175
20879
|
}
|
|
20176
20880
|
var state57 = {
|
|
20177
20881
|
filePath: null,
|
|
@@ -20890,7 +21594,21 @@ function estimateRequestTokens(request, charsPerToken) {
|
|
|
20890
21594
|
walk(request["messages"]);
|
|
20891
21595
|
return Math.ceil(chars / charsPerToken);
|
|
20892
21596
|
}
|
|
20893
|
-
|
|
21597
|
+
function sleep(ms, signal) {
|
|
21598
|
+
if (signal?.aborted) return Promise.resolve();
|
|
21599
|
+
return new Promise((resolve28) => {
|
|
21600
|
+
const timer = setTimeout(() => {
|
|
21601
|
+
signal?.removeEventListener("abort", onAbort);
|
|
21602
|
+
resolve28();
|
|
21603
|
+
}, ms);
|
|
21604
|
+
timer.unref?.();
|
|
21605
|
+
function onAbort() {
|
|
21606
|
+
clearTimeout(timer);
|
|
21607
|
+
resolve28();
|
|
21608
|
+
}
|
|
21609
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
21610
|
+
});
|
|
21611
|
+
}
|
|
20894
21612
|
var plugin62 = {
|
|
20895
21613
|
name: "token-throttle",
|
|
20896
21614
|
version: "0.1.0",
|
|
@@ -20949,6 +21667,7 @@ var plugin62 = {
|
|
|
20949
21667
|
name: "token-throttle",
|
|
20950
21668
|
owner: "token-throttle",
|
|
20951
21669
|
async wrapProviderRunner(_ctx, request, inner) {
|
|
21670
|
+
const signal = _ctx?.signal;
|
|
20952
21671
|
const req = request ?? {};
|
|
20953
21672
|
state59.invocations += 1;
|
|
20954
21673
|
const now = Date.now();
|
|
@@ -20962,7 +21681,7 @@ var plugin62 = {
|
|
|
20962
21681
|
api.metrics.counter("throttled");
|
|
20963
21682
|
api.metrics.histogram("delay_ms", delay);
|
|
20964
21683
|
api.log.info("token-throttle: delaying provider call", { delayMs: delay, projected });
|
|
20965
|
-
await sleep(delay);
|
|
21684
|
+
await sleep(delay, signal);
|
|
20966
21685
|
}
|
|
20967
21686
|
const response = await inner(_ctx, request);
|
|
20968
21687
|
const used = (response?.usage?.input ?? 0) + (response?.usage?.output ?? 0) || projected;
|
|
@@ -21110,7 +21829,9 @@ async function runTypeCheck(cfg) {
|
|
|
21110
21829
|
if (!resolved) return null;
|
|
21111
21830
|
argv = [resolved.cmd, ...resolved.args];
|
|
21112
21831
|
} else {
|
|
21113
|
-
|
|
21832
|
+
const tscFlags = ["--noEmit", "--incremental"];
|
|
21833
|
+
const localTsc = resolveNodeBin("typescript", "tsc", process.cwd(), tscFlags);
|
|
21834
|
+
argv = localTsc ? [localTsc.cmd, ...localTsc.args] : ["npx", "tsc", ...tscFlags];
|
|
21114
21835
|
if (tsConfig && tsConfig !== "tsconfig.json") {
|
|
21115
21836
|
argv = [...argv, "-p", tsConfig];
|
|
21116
21837
|
}
|