@wrongstack/plugins 0.295.0 → 0.296.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +31 -3
- 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 +116 -3
- 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 +35 -8
- 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/index.d.ts.map +1 -1
- package/dist/dead-code-detector.js +9 -1
- 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 +112 -2
- package/dist/doc-sync-guard.js +17 -1
- 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/git-autocommit/index.d.ts +12 -0
- package/dist/git-autocommit/index.d.ts.map +1 -1
- package/dist/git-autocommit.js +58 -4
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +152 -21
- package/dist/index.js +1413 -590
- package/dist/injection-shield/index.d.ts +16 -0
- package/dist/injection-shield/index.d.ts.map +1 -1
- package/dist/injection-shield.js +12 -4
- 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 +115 -2
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +15 -5
- package/dist/migration-planner.js +15 -1
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/pr-drafter/index.d.ts.map +1 -1
- package/dist/pr-drafter.js +20 -1
- 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/handles.d.ts +46 -0
- package/dist/runtime/handles.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +4 -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 +309 -22
- package/dist/schema-evolution-guard.js +5 -0
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +194 -50
- 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/session-recap/index.d.ts.map +1 -1
- package/dist/session-recap.js +18 -1
- package/dist/smart-rename/index.d.ts +2 -0
- package/dist/smart-rename/index.d.ts.map +1 -1
- package/dist/smart-rename.js +16 -2
- package/dist/spec-linker/index.d.ts.map +1 -1
- package/dist/spec-linker.js +19 -2
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +45 -3
- package/dist/test-coverage-gate.js +17 -1
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +142 -9
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +42 -2
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-budget/index.d.ts.map +1 -1
- package/dist/token-budget.js +31 -19
- 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 +108 -17
- 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,260 @@ 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
|
+
|
|
298
|
+
// src/runtime/handles.ts
|
|
299
|
+
function releaseHandle(off) {
|
|
300
|
+
if (off) {
|
|
301
|
+
try {
|
|
302
|
+
off();
|
|
303
|
+
} catch {
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
55
309
|
// src/runtime/index.ts
|
|
56
310
|
var META_CHARS = /["'`;&|<>\r\n]/;
|
|
57
311
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
@@ -66,9 +320,9 @@ function safeSplit(command) {
|
|
|
66
320
|
function withinProjectPath(projectRoot, candidate) {
|
|
67
321
|
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
68
322
|
if (hasLeadingDash(candidate)) return false;
|
|
69
|
-
const resolved =
|
|
70
|
-
const rel =
|
|
71
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
323
|
+
const resolved = isAbsolute2(candidate) ? resolve2(candidate) : resolve2(projectRoot, candidate);
|
|
324
|
+
const rel = relative2(projectRoot, resolved);
|
|
325
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
|
|
72
326
|
}
|
|
73
327
|
function everyFlagAllowed(allowed, args) {
|
|
74
328
|
for (const arg of args) {
|
|
@@ -80,14 +334,14 @@ function everyFlagAllowed(allowed, args) {
|
|
|
80
334
|
}
|
|
81
335
|
function sanitizeRunnerPath(value, options = {}) {
|
|
82
336
|
if (!value || hasLeadingDash(value)) return null;
|
|
83
|
-
const projectRoot =
|
|
337
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
84
338
|
if (!withinProjectPath(projectRoot, value)) return null;
|
|
85
|
-
return
|
|
339
|
+
return isAbsolute2(value) ? resolve2(value) : resolve2(projectRoot, value);
|
|
86
340
|
}
|
|
87
341
|
function resolveRunnerCommand(runtime, command, options = {}) {
|
|
88
342
|
const tokens = safeSplit(command);
|
|
89
343
|
if (!tokens || tokens.length === 0) return null;
|
|
90
|
-
const projectRoot =
|
|
344
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
91
345
|
const launcher = runtime.packageManager;
|
|
92
346
|
const [head, second, ...rest] = tokens;
|
|
93
347
|
if (!head) return null;
|
|
@@ -118,7 +372,7 @@ function resolveRunnerCommand(runtime, command, options = {}) {
|
|
|
118
372
|
return { cmd: head, args: [second, exe, ...tail], display };
|
|
119
373
|
}
|
|
120
374
|
}
|
|
121
|
-
if (
|
|
375
|
+
if (isAbsolute2(head)) {
|
|
122
376
|
if (!withinProjectPath(projectRoot, head)) return null;
|
|
123
377
|
const base = basename(head);
|
|
124
378
|
if (base !== runtime.executable && base !== launcher) return null;
|
|
@@ -139,7 +393,7 @@ function runRunnerCommand(argv, options) {
|
|
|
139
393
|
});
|
|
140
394
|
}
|
|
141
395
|
return new Promise((resolvePromise) => {
|
|
142
|
-
const projectRoot =
|
|
396
|
+
const projectRoot = resolve2(options.projectRoot ?? process.cwd());
|
|
143
397
|
const trimmedCwd = options.cwd.trim();
|
|
144
398
|
if (!withinProjectPath(projectRoot, trimmedCwd)) {
|
|
145
399
|
resolvePromise({
|
|
@@ -157,21 +411,37 @@ function runRunnerCommand(argv, options) {
|
|
|
157
411
|
const stderrChunks = [];
|
|
158
412
|
let stdoutBytes = 0;
|
|
159
413
|
let stderrBytes = 0;
|
|
160
|
-
|
|
414
|
+
const onAbort = () => {
|
|
161
415
|
timedOut = true;
|
|
162
|
-
}
|
|
416
|
+
};
|
|
417
|
+
let invocation;
|
|
418
|
+
try {
|
|
419
|
+
invocation = resolveExecInvocation(argv[0], argv.slice(1));
|
|
420
|
+
} catch (err) {
|
|
421
|
+
resolvePromise({
|
|
422
|
+
code: null,
|
|
423
|
+
stdout: "",
|
|
424
|
+
stderr: `runtime helper: ${err instanceof Error ? err.message : String(err)}`,
|
|
425
|
+
timedOut: false,
|
|
426
|
+
spawnError: true
|
|
427
|
+
});
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
163
431
|
const child = execFile(
|
|
164
|
-
|
|
165
|
-
|
|
432
|
+
invocation.cmd,
|
|
433
|
+
invocation.args,
|
|
166
434
|
{
|
|
167
435
|
cwd: trimmedCwd,
|
|
168
436
|
timeout: options.timeoutMs,
|
|
169
437
|
signal: options.signal,
|
|
170
438
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
171
439
|
windowsHide: true,
|
|
172
|
-
shell: false
|
|
440
|
+
shell: false,
|
|
441
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
173
442
|
},
|
|
174
443
|
(err) => {
|
|
444
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
175
445
|
if (timedOut) {
|
|
176
446
|
resolvePromise({
|
|
177
447
|
code: null,
|
|
@@ -235,7 +505,7 @@ function runRunnerCommand(argv, options) {
|
|
|
235
505
|
}
|
|
236
506
|
function withinProject(p) {
|
|
237
507
|
const cwd = process.cwd();
|
|
238
|
-
return withinProjectPath(cwd, p) ||
|
|
508
|
+
return withinProjectPath(cwd, p) || relative2(cwd, p) === ".";
|
|
239
509
|
}
|
|
240
510
|
var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
|
|
241
511
|
async function collectSourceFilesAsync(root, opts) {
|
|
@@ -264,7 +534,7 @@ async function collectSourceFilesAsync(root, opts) {
|
|
|
264
534
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
265
535
|
for (const entry of entries) {
|
|
266
536
|
if (excludeSet.has(entry.name)) continue;
|
|
267
|
-
const full =
|
|
537
|
+
const full = resolve2(dir, entry.name);
|
|
268
538
|
if (entry.isDirectory()) {
|
|
269
539
|
await walk(full, depth + 1);
|
|
270
540
|
} else if (entry.isFile() && matchesExtension(full, opts.extensions)) {
|
|
@@ -276,7 +546,7 @@ async function collectSourceFilesAsync(root, opts) {
|
|
|
276
546
|
return files;
|
|
277
547
|
}
|
|
278
548
|
function matchesExtension(p, exts) {
|
|
279
|
-
return exts.includes(
|
|
549
|
+
return exts.includes(extname2(p).toLowerCase());
|
|
280
550
|
}
|
|
281
551
|
|
|
282
552
|
// src/accessibility-auditor/index.ts
|
|
@@ -339,7 +609,7 @@ async function auditFile(filePath, projectRoot) {
|
|
|
339
609
|
const idsByValue = /* @__PURE__ */ new Map();
|
|
340
610
|
function add(line, rule, severity, message) {
|
|
341
611
|
findings.push({
|
|
342
|
-
file:
|
|
612
|
+
file: relative3(projectRoot, filePath),
|
|
343
613
|
line,
|
|
344
614
|
rule,
|
|
345
615
|
severity,
|
|
@@ -418,19 +688,27 @@ async function auditFile(filePath, projectRoot) {
|
|
|
418
688
|
}
|
|
419
689
|
async function auditPath(rawPath, cfg) {
|
|
420
690
|
const root = process.cwd();
|
|
421
|
-
const resolved =
|
|
691
|
+
const resolved = isAbsolute3(rawPath) ? resolve3(rawPath) : resolve3(root, rawPath);
|
|
422
692
|
const exts = normalizeExtensions(cfg.includeExtensions);
|
|
423
693
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
424
694
|
const findings = [];
|
|
695
|
+
let scannedFiles = 0;
|
|
696
|
+
let truncated = false;
|
|
425
697
|
for (const file of files) {
|
|
426
698
|
const fileFindings = await auditFile(file, root);
|
|
699
|
+
scannedFiles += 1;
|
|
427
700
|
findings.push(...fileFindings);
|
|
428
|
-
if (findings.length >= cfg.maxFindings)
|
|
701
|
+
if (findings.length >= cfg.maxFindings) {
|
|
702
|
+
truncated = scannedFiles < files.length;
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
429
705
|
}
|
|
430
706
|
return {
|
|
431
|
-
path:
|
|
707
|
+
path: relative3(root, resolved),
|
|
432
708
|
findings: findings.slice(0, cfg.maxFindings),
|
|
433
|
-
fileCount: files.length
|
|
709
|
+
fileCount: files.length,
|
|
710
|
+
scannedFiles,
|
|
711
|
+
truncated
|
|
434
712
|
};
|
|
435
713
|
}
|
|
436
714
|
function formatSummary(result) {
|
|
@@ -490,7 +768,7 @@ var plugin = {
|
|
|
490
768
|
state.findingCount = 0;
|
|
491
769
|
state.hookInvocationCount = 0;
|
|
492
770
|
state.lastResult = null;
|
|
493
|
-
state.hookUnregister =
|
|
771
|
+
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
494
772
|
const cfg = readConfig(api.config.extensions?.["accessibility-auditor"]);
|
|
495
773
|
const hook = async (input) => {
|
|
496
774
|
if (!cfg.enabled || !cfg.onWriteEdit) return;
|
|
@@ -559,6 +837,10 @@ var plugin = {
|
|
|
559
837
|
ok: true,
|
|
560
838
|
path: result.path,
|
|
561
839
|
fileCount: result.fileCount,
|
|
840
|
+
scannedFiles: result.scannedFiles,
|
|
841
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
842
|
+
// that reports few findings must not read as a clean result.
|
|
843
|
+
truncated: result.truncated,
|
|
562
844
|
findingCount: result.findings.length,
|
|
563
845
|
findings: result.findings
|
|
564
846
|
};
|
|
@@ -689,7 +971,7 @@ function buildBody(payload, cfg) {
|
|
|
689
971
|
if (cfg.includeResult && payload.result !== void 0) {
|
|
690
972
|
lines.push("## Result");
|
|
691
973
|
lines.push("```json");
|
|
692
|
-
lines.push(
|
|
974
|
+
lines.push(safeJsonStringify(payload.result, 2));
|
|
693
975
|
lines.push("```");
|
|
694
976
|
lines.push("");
|
|
695
977
|
}
|
|
@@ -931,9 +1213,9 @@ var agent_handoff_default = plugin2;
|
|
|
931
1213
|
|
|
932
1214
|
// src/api-compatibility-gate/index.ts
|
|
933
1215
|
import { execFile as execFile2 } from "node:child_process";
|
|
934
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1216
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
935
1217
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
936
|
-
import { basename as basename2, dirname, extname as
|
|
1218
|
+
import { basename as basename2, dirname as dirname2, extname as extname3, isAbsolute as isAbsolute4, relative as relative4, resolve as resolve4 } from "node:path";
|
|
937
1219
|
var API_VERSION3 = "^0.1.10";
|
|
938
1220
|
var state3 = {
|
|
939
1221
|
invocationCount: 0,
|
|
@@ -997,25 +1279,25 @@ function matchesAnyPattern(filePath, patterns) {
|
|
|
997
1279
|
return patterns.some((p) => patternToRegex(p).test(normalized));
|
|
998
1280
|
}
|
|
999
1281
|
function resolveToProjectRoot(filePath) {
|
|
1000
|
-
if (
|
|
1001
|
-
return
|
|
1282
|
+
if (isAbsolute4(filePath)) return resolve4(filePath);
|
|
1283
|
+
return resolve4(process.cwd(), filePath);
|
|
1002
1284
|
}
|
|
1003
1285
|
function withinProject2(filePath) {
|
|
1004
1286
|
if (typeof filePath !== "string" || filePath.length === 0 || filePath.length > 4096) return false;
|
|
1005
1287
|
const resolved = resolveToProjectRoot(filePath);
|
|
1006
|
-
const rel =
|
|
1288
|
+
const rel = relative4(process.cwd(), resolved);
|
|
1007
1289
|
if (rel === "" || rel === ".") return true;
|
|
1008
1290
|
if (rel.startsWith("..")) return false;
|
|
1009
|
-
if (
|
|
1291
|
+
if (isAbsolute4(rel)) return false;
|
|
1010
1292
|
return true;
|
|
1011
1293
|
}
|
|
1012
1294
|
function isPackageEntryPoint(filePath) {
|
|
1013
1295
|
const resolved = resolveToProjectRoot(filePath);
|
|
1014
|
-
const dir =
|
|
1015
|
-
const pkgPath =
|
|
1296
|
+
const dir = dirname2(resolved);
|
|
1297
|
+
const pkgPath = resolve4(dir, "package.json");
|
|
1016
1298
|
if (!existsSync(pkgPath)) return false;
|
|
1017
1299
|
try {
|
|
1018
|
-
const pkg = JSON.parse(
|
|
1300
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1019
1301
|
const entries = [];
|
|
1020
1302
|
if (pkg.main) entries.push(pkg.main);
|
|
1021
1303
|
if (pkg.module) entries.push(pkg.module);
|
|
@@ -1033,9 +1315,9 @@ function isPackageEntryPoint(filePath) {
|
|
|
1033
1315
|
}
|
|
1034
1316
|
}
|
|
1035
1317
|
for (const entry of entries) {
|
|
1036
|
-
const entryResolved =
|
|
1318
|
+
const entryResolved = resolve4(dir, entry);
|
|
1037
1319
|
if (entryResolved === resolved) return true;
|
|
1038
|
-
if (basename2(
|
|
1320
|
+
if (basename2(dirname2(entryResolved)) === basename2(dirname2(resolved)) && basename2(entryResolved, extname3(entryResolved)) === basename2(resolved, extname3(resolved))) {
|
|
1039
1321
|
return true;
|
|
1040
1322
|
}
|
|
1041
1323
|
}
|
|
@@ -1086,7 +1368,7 @@ function extractExports(source) {
|
|
|
1086
1368
|
}
|
|
1087
1369
|
function readGitVersion(filePath) {
|
|
1088
1370
|
const resolved = resolveToProjectRoot(filePath);
|
|
1089
|
-
const relPath = normalizePath(
|
|
1371
|
+
const relPath = normalizePath(relative4(process.cwd(), resolved));
|
|
1090
1372
|
return new Promise((resolveVersion) => {
|
|
1091
1373
|
execFile2(
|
|
1092
1374
|
"git",
|
|
@@ -1290,14 +1572,14 @@ var plugin3 = {
|
|
|
1290
1572
|
var api_compatibility_gate_default = plugin3;
|
|
1291
1573
|
|
|
1292
1574
|
// src/auto-doc/index.ts
|
|
1293
|
-
import { isAbsolute as
|
|
1575
|
+
import { isAbsolute as isAbsolute5, relative as relative5, resolve as resolve5 } from "node:path";
|
|
1294
1576
|
var AUTO_DOC_API_VERSION = "^0.1.10";
|
|
1295
1577
|
function resolveProjectPath(rawPath, cwd = process.cwd()) {
|
|
1296
1578
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
1297
|
-
const root =
|
|
1298
|
-
const resolved =
|
|
1299
|
-
const rel =
|
|
1300
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
1579
|
+
const root = resolve5(cwd);
|
|
1580
|
+
const resolved = isAbsolute5(rawPath) ? resolve5(rawPath) : resolve5(root, rawPath);
|
|
1581
|
+
const rel = relative5(root, resolved);
|
|
1582
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute5(rel)) return resolved;
|
|
1301
1583
|
return null;
|
|
1302
1584
|
}
|
|
1303
1585
|
var state4 = {
|
|
@@ -1477,16 +1759,17 @@ async function runAutoDoc(input, api) {
|
|
|
1477
1759
|
continue;
|
|
1478
1760
|
}
|
|
1479
1761
|
try {
|
|
1480
|
-
const { readFileSync:
|
|
1762
|
+
const { readFileSync: readFileSync17, writeFileSync: writeFileSync3 } = await import("node:fs");
|
|
1481
1763
|
let content;
|
|
1482
1764
|
try {
|
|
1483
|
-
content =
|
|
1765
|
+
content = readFileSync17(safeFile, "utf-8");
|
|
1484
1766
|
} catch {
|
|
1485
1767
|
api.log.warn(`auto-doc: could not read file ${safeFile}`);
|
|
1486
1768
|
continue;
|
|
1487
1769
|
}
|
|
1488
1770
|
const entities = parseSource(content);
|
|
1489
1771
|
let modified = content;
|
|
1772
|
+
const beforeCount = results.length;
|
|
1490
1773
|
for (const entity of entities) {
|
|
1491
1774
|
if (!input.force && !needsDocComment(modified, entity)) continue;
|
|
1492
1775
|
let doc = null;
|
|
@@ -1512,8 +1795,9 @@ async function runAutoDoc(input, api) {
|
|
|
1512
1795
|
modified = injectDocComment(modified, entity, doc);
|
|
1513
1796
|
results.push({ file: safeFile, entity: entity.name, source });
|
|
1514
1797
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1798
|
+
const changedThisFile = results.length > beforeCount && modified !== content;
|
|
1799
|
+
if (!input.dry_run && changedThisFile) {
|
|
1800
|
+
writeFileSync3(safeFile, modified, "utf-8");
|
|
1517
1801
|
api.log.info(`auto-doc: updated ${safeFile}`);
|
|
1518
1802
|
}
|
|
1519
1803
|
} catch (err) {
|
|
@@ -1828,7 +2112,7 @@ var plugin5 = {
|
|
|
1828
2112
|
var auto_escalate_default = plugin5;
|
|
1829
2113
|
|
|
1830
2114
|
// src/auto-i18n-extractor/index.ts
|
|
1831
|
-
import { readFileSync as
|
|
2115
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1832
2116
|
var API_VERSION4 = "^0.1.10";
|
|
1833
2117
|
var state6 = {
|
|
1834
2118
|
filesScanned: 0,
|
|
@@ -1913,7 +2197,7 @@ function extractStrings(content, cfg) {
|
|
|
1913
2197
|
}
|
|
1914
2198
|
function readSourceFile(filePath) {
|
|
1915
2199
|
try {
|
|
1916
|
-
return
|
|
2200
|
+
return readFileSync3(filePath, "utf-8");
|
|
1917
2201
|
} catch {
|
|
1918
2202
|
return null;
|
|
1919
2203
|
}
|
|
@@ -2201,16 +2485,16 @@ function hasDisabledPluginEntry(raw) {
|
|
|
2201
2485
|
return name === "branch-guard" || name === "@wrongstack/plugins/branch-guard";
|
|
2202
2486
|
});
|
|
2203
2487
|
}
|
|
2204
|
-
var branchCache =
|
|
2488
|
+
var branchCache = new BoundedMap({ max: 64, ttlMs: 3e4 });
|
|
2205
2489
|
function runGit(args, cwd, signal) {
|
|
2206
|
-
return new Promise((
|
|
2490
|
+
return new Promise((resolve28, reject) => {
|
|
2207
2491
|
execFile3(
|
|
2208
2492
|
"git",
|
|
2209
2493
|
args,
|
|
2210
2494
|
{ encoding: "utf-8", timeout: 3e3, cwd, windowsHide: true, signal },
|
|
2211
2495
|
(error, stdout) => {
|
|
2212
2496
|
if (error) reject(error);
|
|
2213
|
-
else
|
|
2497
|
+
else resolve28(stdout);
|
|
2214
2498
|
}
|
|
2215
2499
|
);
|
|
2216
2500
|
});
|
|
@@ -2311,8 +2595,8 @@ var plugin7 = {
|
|
|
2311
2595
|
state7.invocationCount = 0;
|
|
2312
2596
|
state7.blockCount = 0;
|
|
2313
2597
|
state7.warnCount = 0;
|
|
2314
|
-
state7.hookUnregister =
|
|
2315
|
-
state7.configUnregister =
|
|
2598
|
+
state7.hookUnregister = releaseHandle(state7.hookUnregister);
|
|
2599
|
+
state7.configUnregister = releaseHandle(state7.configUnregister);
|
|
2316
2600
|
state7.lastBlock = null;
|
|
2317
2601
|
branchCache.clear();
|
|
2318
2602
|
let cfg = readHostConfig(api.config);
|
|
@@ -2458,11 +2742,11 @@ var plugin7 = {
|
|
|
2458
2742
|
var branch_guard_default = plugin7;
|
|
2459
2743
|
|
|
2460
2744
|
// src/changelog-writer/index.ts
|
|
2461
|
-
import { readFileSync as
|
|
2462
|
-
import { isAbsolute as
|
|
2745
|
+
import { readFileSync as readFileSync4, writeFileSync } from "node:fs";
|
|
2746
|
+
import { isAbsolute as isAbsolute6, relative as relative6, resolve as resolve6 } from "node:path";
|
|
2463
2747
|
var state8 = {
|
|
2464
2748
|
entries: [],
|
|
2465
|
-
filesTouched:
|
|
2749
|
+
filesTouched: new BoundedSet({ max: 2e3 }),
|
|
2466
2750
|
commitsSeen: 0,
|
|
2467
2751
|
writes: 0,
|
|
2468
2752
|
polishes: 0,
|
|
@@ -2476,10 +2760,10 @@ var DEFAULTS6 = {
|
|
|
2476
2760
|
maxEntries: 200
|
|
2477
2761
|
};
|
|
2478
2762
|
function resolveProjectPath2(rawPath, cwd = process.cwd()) {
|
|
2479
|
-
const root =
|
|
2480
|
-
const resolved =
|
|
2481
|
-
const rel =
|
|
2482
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
2763
|
+
const root = resolve6(cwd);
|
|
2764
|
+
const resolved = isAbsolute6(rawPath) ? resolve6(rawPath) : resolve6(root, rawPath);
|
|
2765
|
+
const rel = relative6(root, resolved);
|
|
2766
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute6(rel)) return resolved;
|
|
2483
2767
|
return null;
|
|
2484
2768
|
}
|
|
2485
2769
|
function readConfig7(raw) {
|
|
@@ -2623,7 +2907,7 @@ var plugin8 = {
|
|
|
2623
2907
|
},
|
|
2624
2908
|
setup(api) {
|
|
2625
2909
|
state8.entries = [];
|
|
2626
|
-
state8.filesTouched =
|
|
2910
|
+
state8.filesTouched = new BoundedSet({ max: 2e3 });
|
|
2627
2911
|
state8.commitsSeen = 0;
|
|
2628
2912
|
state8.writes = 0;
|
|
2629
2913
|
for (const off of state8.eventUnsubscribers) {
|
|
@@ -2769,7 +3053,7 @@ var plugin8 = {
|
|
|
2769
3053
|
);
|
|
2770
3054
|
let existing = null;
|
|
2771
3055
|
try {
|
|
2772
|
-
existing =
|
|
3056
|
+
existing = readFileSync4(cfg.filePath, "utf-8");
|
|
2773
3057
|
} catch {
|
|
2774
3058
|
existing = null;
|
|
2775
3059
|
}
|
|
@@ -2815,7 +3099,7 @@ var plugin8 = {
|
|
|
2815
3099
|
filesTouched: state8.filesTouched.size
|
|
2816
3100
|
};
|
|
2817
3101
|
state8.entries = [];
|
|
2818
|
-
state8.filesTouched =
|
|
3102
|
+
state8.filesTouched = new BoundedSet({ max: 2e3 });
|
|
2819
3103
|
state8.commitsSeen = 0;
|
|
2820
3104
|
state8.writes = 0;
|
|
2821
3105
|
api.log.info("changelog-writer: teardown complete", { final });
|
|
@@ -2837,20 +3121,22 @@ var changelog_writer_default = plugin8;
|
|
|
2837
3121
|
|
|
2838
3122
|
// src/checkpoint/index.ts
|
|
2839
3123
|
import { mkdir, readFile as readFile3, stat, writeFile } from "node:fs/promises";
|
|
2840
|
-
import { dirname as
|
|
3124
|
+
import { dirname as dirname3, isAbsolute as isAbsolute7, relative as relative7, resolve as resolve7 } from "node:path";
|
|
2841
3125
|
var state9 = {
|
|
2842
3126
|
snapshots: [],
|
|
2843
3127
|
nextId: 1,
|
|
2844
3128
|
captures: 0,
|
|
2845
3129
|
restores: 0,
|
|
2846
3130
|
skippedLarge: 0,
|
|
3131
|
+
evictedForBytes: 0,
|
|
2847
3132
|
hookUnregister: null
|
|
2848
3133
|
};
|
|
2849
3134
|
var DEFAULTS7 = {
|
|
2850
3135
|
enabled: true,
|
|
2851
3136
|
autoCapture: true,
|
|
2852
3137
|
maxSnapshots: 50,
|
|
2853
|
-
maxFileBytes: 1048576
|
|
3138
|
+
maxFileBytes: 1048576,
|
|
3139
|
+
maxTotalBytes: 64 * 1048576
|
|
2854
3140
|
};
|
|
2855
3141
|
function readConfig8(raw) {
|
|
2856
3142
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS7 };
|
|
@@ -2859,14 +3145,15 @@ function readConfig8(raw) {
|
|
|
2859
3145
|
enabled: r["enabled"] !== false,
|
|
2860
3146
|
autoCapture: r["autoCapture"] !== false,
|
|
2861
3147
|
maxSnapshots: typeof r["maxSnapshots"] === "number" && r["maxSnapshots"] >= 1 && r["maxSnapshots"] <= 500 ? r["maxSnapshots"] : DEFAULTS7.maxSnapshots,
|
|
3148
|
+
maxTotalBytes: typeof r["maxTotalBytes"] === "number" && r["maxTotalBytes"] >= 1024 ? r["maxTotalBytes"] : DEFAULTS7.maxTotalBytes,
|
|
2862
3149
|
maxFileBytes: typeof r["maxFileBytes"] === "number" && r["maxFileBytes"] >= 1024 ? r["maxFileBytes"] : DEFAULTS7.maxFileBytes
|
|
2863
3150
|
};
|
|
2864
3151
|
}
|
|
2865
3152
|
function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2866
|
-
const root =
|
|
2867
|
-
const resolved =
|
|
2868
|
-
const rel =
|
|
2869
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
3153
|
+
const root = resolve7(cwd);
|
|
3154
|
+
const resolved = isAbsolute7(rawPath) ? resolve7(rawPath) : resolve7(root, rawPath);
|
|
3155
|
+
const rel = relative7(root, resolved);
|
|
3156
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute7(rel)) return resolved;
|
|
2870
3157
|
return null;
|
|
2871
3158
|
}
|
|
2872
3159
|
function hashContent(s) {
|
|
@@ -2900,11 +3187,22 @@ async function captureFileForHook(path, maxBytes, signal) {
|
|
|
2900
3187
|
return { path, content: null, bytes: 0 };
|
|
2901
3188
|
}
|
|
2902
3189
|
}
|
|
2903
|
-
function
|
|
3190
|
+
function retainedSnapshotBytes() {
|
|
3191
|
+
let total = 0;
|
|
3192
|
+
for (const snap of state9.snapshots) {
|
|
3193
|
+
for (const f of snap.files) total += f.content === null ? 0 : f.content.length;
|
|
3194
|
+
}
|
|
3195
|
+
return total;
|
|
3196
|
+
}
|
|
3197
|
+
function pushSnapshot(snapshot, maxSnapshots, maxTotalBytes) {
|
|
2904
3198
|
state9.snapshots.push(snapshot);
|
|
2905
3199
|
if (state9.snapshots.length > maxSnapshots) {
|
|
2906
3200
|
state9.snapshots.splice(0, state9.snapshots.length - maxSnapshots);
|
|
2907
3201
|
}
|
|
3202
|
+
while (state9.snapshots.length > 1 && retainedSnapshotBytes() > maxTotalBytes) {
|
|
3203
|
+
state9.snapshots.shift();
|
|
3204
|
+
state9.evictedForBytes += 1;
|
|
3205
|
+
}
|
|
2908
3206
|
}
|
|
2909
3207
|
var plugin9 = {
|
|
2910
3208
|
name: "checkpoint",
|
|
@@ -2943,6 +3241,7 @@ var plugin9 = {
|
|
|
2943
3241
|
state9.captures = 0;
|
|
2944
3242
|
state9.restores = 0;
|
|
2945
3243
|
state9.skippedLarge = 0;
|
|
3244
|
+
state9.evictedForBytes = 0;
|
|
2946
3245
|
if (state9.hookUnregister) {
|
|
2947
3246
|
try {
|
|
2948
3247
|
state9.hookUnregister();
|
|
@@ -2970,7 +3269,8 @@ var plugin9 = {
|
|
|
2970
3269
|
origin: `auto:${input.toolName ?? "unknown"}`,
|
|
2971
3270
|
files: [captured]
|
|
2972
3271
|
},
|
|
2973
|
-
cfg.maxSnapshots
|
|
3272
|
+
cfg.maxSnapshots,
|
|
3273
|
+
cfg.maxTotalBytes
|
|
2974
3274
|
);
|
|
2975
3275
|
state9.captures += 1;
|
|
2976
3276
|
api.metrics.counter("captures");
|
|
@@ -3048,7 +3348,7 @@ var plugin9 = {
|
|
|
3048
3348
|
origin: input.label?.trim() ? `manual:${input.label.trim()}` : "manual",
|
|
3049
3349
|
files
|
|
3050
3350
|
};
|
|
3051
|
-
pushSnapshot(snapshot, cfg.maxSnapshots);
|
|
3351
|
+
pushSnapshot(snapshot, cfg.maxSnapshots, cfg.maxTotalBytes);
|
|
3052
3352
|
state9.captures += 1;
|
|
3053
3353
|
api.metrics.counter("captures");
|
|
3054
3354
|
return {
|
|
@@ -3091,7 +3391,9 @@ var plugin9 = {
|
|
|
3091
3391
|
counters: {
|
|
3092
3392
|
captures: state9.captures,
|
|
3093
3393
|
restores: state9.restores,
|
|
3094
|
-
skippedLarge: state9.skippedLarge
|
|
3394
|
+
skippedLarge: state9.skippedLarge,
|
|
3395
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3396
|
+
evictedForBytes: state9.evictedForBytes
|
|
3095
3397
|
}
|
|
3096
3398
|
};
|
|
3097
3399
|
}
|
|
@@ -3134,7 +3436,7 @@ var plugin9 = {
|
|
|
3134
3436
|
continue;
|
|
3135
3437
|
}
|
|
3136
3438
|
try {
|
|
3137
|
-
await mkdir(
|
|
3439
|
+
await mkdir(dirname3(f.path), { recursive: true });
|
|
3138
3440
|
await writeFile(f.path, f.content);
|
|
3139
3441
|
restored.push(f.path);
|
|
3140
3442
|
} catch (err) {
|
|
@@ -3173,13 +3475,16 @@ var plugin9 = {
|
|
|
3173
3475
|
captures: state9.captures,
|
|
3174
3476
|
restores: state9.restores,
|
|
3175
3477
|
skippedLarge: state9.skippedLarge,
|
|
3176
|
-
snapshotsHeld: state9.snapshots.length
|
|
3478
|
+
snapshotsHeld: state9.snapshots.length,
|
|
3479
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3480
|
+
evictedForBytes: state9.evictedForBytes
|
|
3177
3481
|
};
|
|
3178
3482
|
state9.snapshots = [];
|
|
3179
3483
|
state9.nextId = 1;
|
|
3180
3484
|
state9.captures = 0;
|
|
3181
3485
|
state9.restores = 0;
|
|
3182
3486
|
state9.skippedLarge = 0;
|
|
3487
|
+
state9.evictedForBytes = 0;
|
|
3183
3488
|
api.log.info("checkpoint: teardown complete", { final });
|
|
3184
3489
|
},
|
|
3185
3490
|
async health() {
|
|
@@ -3190,7 +3495,11 @@ var plugin9 = {
|
|
|
3190
3495
|
snapshotsHeld: state9.snapshots.length,
|
|
3191
3496
|
captures: state9.captures,
|
|
3192
3497
|
restores: state9.restores,
|
|
3193
|
-
skippedLarge: state9.skippedLarge
|
|
3498
|
+
skippedLarge: state9.skippedLarge,
|
|
3499
|
+
// Retained snapshot bytes: the count-based ring alone does not
|
|
3500
|
+
// bound memory, so surface the number the byte budget acts on.
|
|
3501
|
+
retainedBytes: retainedSnapshotBytes(),
|
|
3502
|
+
evictedForBytes: state9.evictedForBytes
|
|
3194
3503
|
}
|
|
3195
3504
|
};
|
|
3196
3505
|
}
|
|
@@ -3199,7 +3508,7 @@ var checkpoint_default = plugin9;
|
|
|
3199
3508
|
|
|
3200
3509
|
// src/code-metrics/index.ts
|
|
3201
3510
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
3202
|
-
import { isAbsolute as
|
|
3511
|
+
import { isAbsolute as isAbsolute8, relative as relative8, resolve as resolve8 } from "node:path";
|
|
3203
3512
|
var API_VERSION6 = "^0.1.10";
|
|
3204
3513
|
var state10 = {
|
|
3205
3514
|
measureCount: 0,
|
|
@@ -3229,7 +3538,7 @@ function toPosix(p) {
|
|
|
3229
3538
|
return p.replace(/\\/g, "/");
|
|
3230
3539
|
}
|
|
3231
3540
|
function relativePath(p) {
|
|
3232
|
-
return toPosix(
|
|
3541
|
+
return toPosix(relative8(process.cwd(), p));
|
|
3233
3542
|
}
|
|
3234
3543
|
function countFunctions(content) {
|
|
3235
3544
|
let count = 0;
|
|
@@ -3306,7 +3615,7 @@ function analyzeFile(filePath, content) {
|
|
|
3306
3615
|
}
|
|
3307
3616
|
async function measurePath(rawPath, cfg) {
|
|
3308
3617
|
const root = process.cwd();
|
|
3309
|
-
const resolved =
|
|
3618
|
+
const resolved = isAbsolute8(rawPath) ? resolve8(rawPath) : resolve8(root, rawPath);
|
|
3310
3619
|
const exts = normalizeExtensions2(cfg.extensions);
|
|
3311
3620
|
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
3312
3621
|
const files = allFiles.slice(0, cfg.maxFiles);
|
|
@@ -3369,7 +3678,7 @@ var plugin10 = {
|
|
|
3369
3678
|
const exts = normalizeExtensions2(cfg.extensions);
|
|
3370
3679
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
3371
3680
|
state10.hookInvocationCount += 1;
|
|
3372
|
-
const resolved =
|
|
3681
|
+
const resolved = resolve8(process.cwd(), sourcePath);
|
|
3373
3682
|
let content;
|
|
3374
3683
|
try {
|
|
3375
3684
|
content = await readFile4(resolved, "utf-8");
|
|
@@ -3413,7 +3722,7 @@ var plugin10 = {
|
|
|
3413
3722
|
state10.fileCount += result.files.length;
|
|
3414
3723
|
return {
|
|
3415
3724
|
ok: true,
|
|
3416
|
-
path: relativePath(
|
|
3725
|
+
path: relativePath(resolve8(process.cwd(), rawPath)),
|
|
3417
3726
|
files: result.files,
|
|
3418
3727
|
totalFiles: result.totalFiles,
|
|
3419
3728
|
capped: result.totalFiles > cfg.maxFiles
|
|
@@ -3601,14 +3910,24 @@ function parseCommitMessage(message, cfg) {
|
|
|
3601
3910
|
errors
|
|
3602
3911
|
};
|
|
3603
3912
|
}
|
|
3913
|
+
var GIT_MESSAGE_FLAG_RE = new RegExp(
|
|
3914
|
+
[
|
|
3915
|
+
// -m "…" | -m '…' | -m=… ; --message "…" | --message='…' | --message=…
|
|
3916
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)"([^"]*)"`,
|
|
3917
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)'([^']*)'`,
|
|
3918
|
+
// Bare value: stops at whitespace or a shell separator.
|
|
3919
|
+
String.raw`(?:^|\s)(?:-m|--message)(?:\s+|=)([^\s;&|"']+)`
|
|
3920
|
+
].join("|"),
|
|
3921
|
+
"g"
|
|
3922
|
+
);
|
|
3604
3923
|
function extractMessageFromBash(command) {
|
|
3605
|
-
const
|
|
3606
|
-
const
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
if (
|
|
3611
|
-
return
|
|
3924
|
+
const parts = [];
|
|
3925
|
+
for (const m of command.matchAll(GIT_MESSAGE_FLAG_RE)) {
|
|
3926
|
+
const value = m[1] ?? m[2] ?? m[3];
|
|
3927
|
+
if (value !== void 0) parts.push(value);
|
|
3928
|
+
}
|
|
3929
|
+
if (parts.length === 0) return null;
|
|
3930
|
+
return parts.join("\n");
|
|
3612
3931
|
}
|
|
3613
3932
|
var plugin11 = {
|
|
3614
3933
|
name: "commit-validator",
|
|
@@ -3667,7 +3986,7 @@ var plugin11 = {
|
|
|
3667
3986
|
state11.invalidCount = 0;
|
|
3668
3987
|
state11.suggestFixCount = 0;
|
|
3669
3988
|
state11.suggestFixErrors = 0;
|
|
3670
|
-
state11.hookUnregister =
|
|
3989
|
+
state11.hookUnregister = releaseHandle(state11.hookUnregister);
|
|
3671
3990
|
state11.lastValidation = null;
|
|
3672
3991
|
const cfg = readConfig10(api.config.extensions?.["commit-validator"]);
|
|
3673
3992
|
const hook = async (input) => {
|
|
@@ -3859,7 +4178,7 @@ Suggested rewrite (${suggest.model}):
|
|
|
3859
4178
|
var commit_validator_default = plugin11;
|
|
3860
4179
|
|
|
3861
4180
|
// src/config-validator/index.ts
|
|
3862
|
-
import { readFileSync as
|
|
4181
|
+
import { readFileSync as readFileSync5, statSync } from "node:fs";
|
|
3863
4182
|
var state12 = {
|
|
3864
4183
|
invocations: 0,
|
|
3865
4184
|
filesChecked: 0,
|
|
@@ -4121,7 +4440,7 @@ var plugin12 = {
|
|
|
4121
4440
|
let text;
|
|
4122
4441
|
try {
|
|
4123
4442
|
if (statSync(raw).size > cfg.maxFileBytes) return;
|
|
4124
|
-
text =
|
|
4443
|
+
text = readFileSync5(raw, "utf-8");
|
|
4125
4444
|
} catch {
|
|
4126
4445
|
return;
|
|
4127
4446
|
}
|
|
@@ -4205,7 +4524,8 @@ var config_validator_default = plugin12;
|
|
|
4205
4524
|
|
|
4206
4525
|
// src/context-pins/index.ts
|
|
4207
4526
|
import * as fs from "node:fs";
|
|
4208
|
-
import { dirname as
|
|
4527
|
+
import { dirname as dirname4, isAbsolute as isAbsolute9, relative as relative9, resolve as resolve9 } from "node:path";
|
|
4528
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4209
4529
|
var state13 = {
|
|
4210
4530
|
pins: [],
|
|
4211
4531
|
nextId: 1,
|
|
@@ -4222,10 +4542,10 @@ var DEFAULTS11 = {
|
|
|
4222
4542
|
};
|
|
4223
4543
|
function resolveProjectPath4(rawPath, cwd = process.cwd()) {
|
|
4224
4544
|
if (typeof rawPath !== "string" || rawPath.length === 0) return "";
|
|
4225
|
-
const root =
|
|
4226
|
-
const resolved =
|
|
4227
|
-
const rel =
|
|
4228
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
4545
|
+
const root = resolve9(cwd);
|
|
4546
|
+
const resolved = isAbsolute9(rawPath) ? resolve9(rawPath) : resolve9(root, rawPath);
|
|
4547
|
+
const rel = relative9(root, resolved);
|
|
4548
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute9(rel)) return resolved;
|
|
4229
4549
|
return null;
|
|
4230
4550
|
}
|
|
4231
4551
|
function readConfig12(raw) {
|
|
@@ -4252,11 +4572,11 @@ function loadPins(filePath) {
|
|
|
4252
4572
|
return { pins: [], nextId: 1 };
|
|
4253
4573
|
}
|
|
4254
4574
|
}
|
|
4255
|
-
function persistPins(filePath) {
|
|
4575
|
+
async function persistPins(filePath) {
|
|
4256
4576
|
if (!filePath) return true;
|
|
4257
4577
|
try {
|
|
4258
|
-
|
|
4259
|
-
|
|
4578
|
+
await ensureDir(dirname4(filePath));
|
|
4579
|
+
await atomicWrite(filePath, JSON.stringify({ pins: state13.pins, nextId: state13.nextId }, null, 2));
|
|
4260
4580
|
return true;
|
|
4261
4581
|
} catch {
|
|
4262
4582
|
state13.persistErrors += 1;
|
|
@@ -4354,7 +4674,7 @@ var plugin13 = {
|
|
|
4354
4674
|
state13.pins.push(pin);
|
|
4355
4675
|
state13.adds += 1;
|
|
4356
4676
|
api.metrics.counter("adds");
|
|
4357
|
-
const persisted = persistPins(cfg.filePath);
|
|
4677
|
+
const persisted = await persistPins(cfg.filePath);
|
|
4358
4678
|
return { ok: true, pin, persisted, totalPins: state13.pins.length };
|
|
4359
4679
|
}
|
|
4360
4680
|
});
|
|
@@ -4380,7 +4700,7 @@ var plugin13 = {
|
|
|
4380
4700
|
if (removed === 0) return { ok: false, error: `no pin matches "${key}"` };
|
|
4381
4701
|
state13.removals += removed;
|
|
4382
4702
|
api.metrics.counter("removals", removed);
|
|
4383
|
-
const persisted = persistPins(cfg.filePath);
|
|
4703
|
+
const persisted = await persistPins(cfg.filePath);
|
|
4384
4704
|
return { ok: true, removed, persisted, totalPins: state13.pins.length };
|
|
4385
4705
|
}
|
|
4386
4706
|
});
|
|
@@ -4480,7 +4800,7 @@ function readCostTrackerConfig(raw) {
|
|
|
4480
4800
|
mailboxDigestTo: typeof digestTo === "string" && digestTo.length > 0 ? digestTo : "cost-tracker"
|
|
4481
4801
|
};
|
|
4482
4802
|
}
|
|
4483
|
-
var modelKeyCache =
|
|
4803
|
+
var modelKeyCache = new BoundedMap({ max: 256 });
|
|
4484
4804
|
function estimateCost(model, promptTokens, completionTokens) {
|
|
4485
4805
|
let key = modelKeyCache.get(model);
|
|
4486
4806
|
if (!key) {
|
|
@@ -4904,6 +5224,7 @@ var plugin15 = {
|
|
|
4904
5224
|
api.metrics.histogram("cron_job_interval_ms", job.intervalMs, { job: name });
|
|
4905
5225
|
scheduleNextRun(name);
|
|
4906
5226
|
}, delay);
|
|
5227
|
+
timer.unref?.();
|
|
4907
5228
|
state14.timers.set(name, timer);
|
|
4908
5229
|
}
|
|
4909
5230
|
function cancelJob(name) {
|
|
@@ -5089,7 +5410,7 @@ var cron_default = plugin15;
|
|
|
5089
5410
|
|
|
5090
5411
|
// src/dead-code-detector/index.ts
|
|
5091
5412
|
import { readdir, readFile as readFile5, stat as stat2 } from "node:fs/promises";
|
|
5092
|
-
import { extname as
|
|
5413
|
+
import { extname as extname4, join as join2, relative as relative10, resolve as resolve10 } from "node:path";
|
|
5093
5414
|
var API_VERSION10 = "^0.1.10";
|
|
5094
5415
|
var state15 = {
|
|
5095
5416
|
scanCount: 0,
|
|
@@ -5132,17 +5453,17 @@ async function gatherFiles(root, depth, cfg) {
|
|
|
5132
5453
|
for (const entry of entries) {
|
|
5133
5454
|
if (entry.isDirectory()) {
|
|
5134
5455
|
if (remaining > 0 && !excludeSet.has(entry.name)) {
|
|
5135
|
-
await walk(
|
|
5456
|
+
await walk(join2(dir, entry.name), remaining - 1);
|
|
5136
5457
|
}
|
|
5137
5458
|
} else if (entry.isFile()) {
|
|
5138
|
-
const ext =
|
|
5459
|
+
const ext = extname4(entry.name).toLowerCase();
|
|
5139
5460
|
if (cfg.extensions.includes(ext)) {
|
|
5140
|
-
files.push(
|
|
5461
|
+
files.push(join2(dir, entry.name));
|
|
5141
5462
|
}
|
|
5142
5463
|
}
|
|
5143
5464
|
}
|
|
5144
5465
|
}
|
|
5145
|
-
await walk(
|
|
5466
|
+
await walk(resolve10(root), depth);
|
|
5146
5467
|
return files;
|
|
5147
5468
|
}
|
|
5148
5469
|
function stripNoise(content) {
|
|
@@ -5197,7 +5518,10 @@ function findUnusedSymbols(files) {
|
|
|
5197
5518
|
for (const file of files) {
|
|
5198
5519
|
const fileExports = extractExports2(file.content, file.path);
|
|
5199
5520
|
for (const exp of fileExports) {
|
|
5200
|
-
const pattern = new RegExp(
|
|
5521
|
+
const pattern = new RegExp(
|
|
5522
|
+
`(?<![A-Za-z0-9_$])${escapeRegex(exp.identifier)}(?![A-Za-z0-9_$])`,
|
|
5523
|
+
"g"
|
|
5524
|
+
);
|
|
5201
5525
|
let usedElsewhere = false;
|
|
5202
5526
|
for (const other of files) {
|
|
5203
5527
|
if (other.path === file.path) continue;
|
|
@@ -5231,11 +5555,11 @@ async function scan(root, depth, cfg) {
|
|
|
5231
5555
|
return { findings: findUnusedSymbols(files), scannedFiles: files.length };
|
|
5232
5556
|
}
|
|
5233
5557
|
async function resolveScanRoot(rawPath) {
|
|
5234
|
-
const resolved =
|
|
5558
|
+
const resolved = resolve10(process.cwd(), rawPath);
|
|
5235
5559
|
try {
|
|
5236
5560
|
const stats = await stat2(resolved);
|
|
5237
5561
|
if (!stats.isDirectory()) {
|
|
5238
|
-
return
|
|
5562
|
+
return resolve10(resolved, "..");
|
|
5239
5563
|
}
|
|
5240
5564
|
} catch {
|
|
5241
5565
|
}
|
|
@@ -5245,7 +5569,7 @@ function toPosix2(p) {
|
|
|
5245
5569
|
return p.replace(/\\/g, "/");
|
|
5246
5570
|
}
|
|
5247
5571
|
function relativePath2(p) {
|
|
5248
|
-
return toPosix2(
|
|
5572
|
+
return toPosix2(relative10(process.cwd(), p));
|
|
5249
5573
|
}
|
|
5250
5574
|
var plugin16 = {
|
|
5251
5575
|
name: "dead-code-detector",
|
|
@@ -5316,8 +5640,8 @@ var plugin16 = {
|
|
|
5316
5640
|
state15.errorCount += 1;
|
|
5317
5641
|
return;
|
|
5318
5642
|
}
|
|
5319
|
-
const changedFile =
|
|
5320
|
-
const relevant = result.findings.filter((f) =>
|
|
5643
|
+
const changedFile = resolve10(process.cwd(), sourcePath);
|
|
5644
|
+
const relevant = result.findings.filter((f) => resolve10(f.file) === changedFile);
|
|
5321
5645
|
if (relevant.length === 0) {
|
|
5322
5646
|
state15.missCount += 1;
|
|
5323
5647
|
return;
|
|
@@ -5910,34 +6234,51 @@ function isInstallCommand(input) {
|
|
|
5910
6234
|
const command = typeof ti["command"] === "string" ? ti["command"] : "";
|
|
5911
6235
|
return INSTALL_RE2.test(command);
|
|
5912
6236
|
}
|
|
6237
|
+
var LOCKFILE_MANAGERS = [
|
|
6238
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
6239
|
+
{ file: "bun.lockb", manager: "bun" },
|
|
6240
|
+
{ file: "bun.lock", manager: "bun" },
|
|
6241
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
6242
|
+
{ file: "package-lock.json", manager: "npm" }
|
|
6243
|
+
];
|
|
5913
6244
|
async function detectManager() {
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
6245
|
+
for (const { file, manager } of LOCKFILE_MANAGERS) {
|
|
6246
|
+
try {
|
|
6247
|
+
await access(file);
|
|
6248
|
+
return manager;
|
|
6249
|
+
} catch {
|
|
6250
|
+
}
|
|
5919
6251
|
}
|
|
6252
|
+
return "npm";
|
|
5920
6253
|
}
|
|
5921
6254
|
async function runAudit(cfg) {
|
|
5922
6255
|
const manager = await detectManager();
|
|
5923
6256
|
const start = Date.now();
|
|
5924
|
-
|
|
6257
|
+
let invocation;
|
|
6258
|
+
try {
|
|
6259
|
+
invocation = resolveExecInvocation(manager, ["audit", "--json"]);
|
|
6260
|
+
} catch {
|
|
6261
|
+
return null;
|
|
6262
|
+
}
|
|
6263
|
+
const stdout = await new Promise((resolve28) => {
|
|
5925
6264
|
execFile4(
|
|
5926
|
-
|
|
5927
|
-
|
|
6265
|
+
invocation.cmd,
|
|
6266
|
+
invocation.args,
|
|
5928
6267
|
{
|
|
5929
6268
|
encoding: "utf8",
|
|
5930
6269
|
timeout: cfg.timeoutMs,
|
|
5931
6270
|
cwd: process.cwd(),
|
|
5932
6271
|
windowsHide: true,
|
|
5933
|
-
maxBuffer: 10 * 1024 * 1024
|
|
6272
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
6273
|
+
shell: false,
|
|
6274
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
5934
6275
|
},
|
|
5935
6276
|
(error, output) => {
|
|
5936
6277
|
if (error && error.killed) {
|
|
5937
|
-
|
|
6278
|
+
resolve28(null);
|
|
5938
6279
|
return;
|
|
5939
6280
|
}
|
|
5940
|
-
|
|
6281
|
+
resolve28(output);
|
|
5941
6282
|
}
|
|
5942
6283
|
);
|
|
5943
6284
|
});
|
|
@@ -6160,7 +6501,7 @@ function contentHash(s) {
|
|
|
6160
6501
|
}
|
|
6161
6502
|
return h >>> 0;
|
|
6162
6503
|
}
|
|
6163
|
-
var pathMemo =
|
|
6504
|
+
var pathMemo = new BoundedMap({ max: 512 });
|
|
6164
6505
|
function runGit2(args, cwd) {
|
|
6165
6506
|
return new Promise((resolveCommand) => {
|
|
6166
6507
|
execFile5(
|
|
@@ -6275,7 +6616,7 @@ var plugin19 = {
|
|
|
6275
6616
|
state18.fallbackCount = 0;
|
|
6276
6617
|
state18.throttledCount = 0;
|
|
6277
6618
|
state18.duplicateContentCount = 0;
|
|
6278
|
-
state18.hookUnregister =
|
|
6619
|
+
state18.hookUnregister = releaseHandle(state18.hookUnregister);
|
|
6279
6620
|
state18.lastSummary = null;
|
|
6280
6621
|
pathMemo.clear();
|
|
6281
6622
|
const cfg = readConfig16(api.config.extensions?.["diff-summary"]);
|
|
@@ -6422,7 +6763,7 @@ var plugin19 = {
|
|
|
6422
6763
|
var diff_summary_default = plugin19;
|
|
6423
6764
|
|
|
6424
6765
|
// src/doc-sync-guard/index.ts
|
|
6425
|
-
import { basename as basename3, extname as
|
|
6766
|
+
import { basename as basename3, extname as extname5 } from "node:path";
|
|
6426
6767
|
var API_VERSION13 = "^0.1.10";
|
|
6427
6768
|
var state19 = {
|
|
6428
6769
|
changedFiles: [],
|
|
@@ -6451,7 +6792,7 @@ function normalizeSlashes(p) {
|
|
|
6451
6792
|
return p.replace(/\\/g, "/");
|
|
6452
6793
|
}
|
|
6453
6794
|
function isSourceFile(p, extensions) {
|
|
6454
|
-
const ext =
|
|
6795
|
+
const ext = extname5(p).toLowerCase();
|
|
6455
6796
|
return extensions.includes(ext);
|
|
6456
6797
|
}
|
|
6457
6798
|
function isPublicSource(p, extensions) {
|
|
@@ -6541,7 +6882,7 @@ var plugin20 = {
|
|
|
6541
6882
|
state19.sourceWrites = 0;
|
|
6542
6883
|
state19.docWrites = 0;
|
|
6543
6884
|
state19.warningsIssued = 0;
|
|
6544
|
-
state19.hookUnregister =
|
|
6885
|
+
state19.hookUnregister = releaseHandle(state19.hookUnregister);
|
|
6545
6886
|
const cfg = readConfig17(api.config.extensions?.["doc-sync-guard"]);
|
|
6546
6887
|
const hook = (input) => {
|
|
6547
6888
|
if (!cfg.enabled) return;
|
|
@@ -6634,8 +6975,9 @@ var doc_sync_guard_default = plugin20;
|
|
|
6634
6975
|
|
|
6635
6976
|
// src/duplicate-code-detector/index.ts
|
|
6636
6977
|
import { readFile as readFile6, realpath, stat as stat3 } from "node:fs/promises";
|
|
6637
|
-
import { isAbsolute as
|
|
6978
|
+
import { isAbsolute as isAbsolute10, relative as relative11, resolve as resolve11, sep as sep2 } from "node:path";
|
|
6638
6979
|
var API_VERSION14 = "^0.1.10";
|
|
6980
|
+
var HOOK_WARNING_COOLDOWN_MS = 6e4;
|
|
6639
6981
|
var state20 = {
|
|
6640
6982
|
scanCount: 0,
|
|
6641
6983
|
findingCount: 0,
|
|
@@ -6643,7 +6985,7 @@ var state20 = {
|
|
|
6643
6985
|
warningCount: 0,
|
|
6644
6986
|
errorCount: 0,
|
|
6645
6987
|
hookUnregister: null,
|
|
6646
|
-
lastHookWarning:
|
|
6988
|
+
lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS }),
|
|
6647
6989
|
fileIndex: /* @__PURE__ */ new Map(),
|
|
6648
6990
|
inFlightFingerprintReads: /* @__PURE__ */ new Map(),
|
|
6649
6991
|
indexFingerprintCount: 0,
|
|
@@ -6690,14 +7032,14 @@ function readConfig18(raw) {
|
|
|
6690
7032
|
};
|
|
6691
7033
|
}
|
|
6692
7034
|
function isWithinRoot(projectRoot, candidate) {
|
|
6693
|
-
const rel =
|
|
6694
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
7035
|
+
const rel = relative11(projectRoot, candidate);
|
|
7036
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute10(rel);
|
|
6695
7037
|
}
|
|
6696
7038
|
function toPosix3(p) {
|
|
6697
7039
|
return p.replace(/\\/g, "/");
|
|
6698
7040
|
}
|
|
6699
7041
|
function relativePath3(p) {
|
|
6700
|
-
return toPosix3(
|
|
7042
|
+
return toPosix3(relative11(process.cwd(), p));
|
|
6701
7043
|
}
|
|
6702
7044
|
function removeInlineComments(line) {
|
|
6703
7045
|
return line.replace(/\/\/.*$/, "").replace(/\/\*[\s\S]*?\*\//, "");
|
|
@@ -6789,7 +7131,7 @@ function findDuplicates(files, minLines, maxFindings) {
|
|
|
6789
7131
|
}
|
|
6790
7132
|
async function scanPath(rawPath, cfg) {
|
|
6791
7133
|
const root = process.cwd();
|
|
6792
|
-
const resolved =
|
|
7134
|
+
const resolved = isAbsolute10(rawPath) ? resolve11(rawPath) : resolve11(root, rawPath);
|
|
6793
7135
|
const filePaths = await collectSourceFilesAsync(resolved, {
|
|
6794
7136
|
extensions: cfg.extensions,
|
|
6795
7137
|
excludeDirs: cfg.excludeDirs
|
|
@@ -6917,8 +7259,8 @@ var plugin21 = {
|
|
|
6917
7259
|
const inp = input.toolInput ?? {};
|
|
6918
7260
|
const sourcePath = inp["path"];
|
|
6919
7261
|
if (!sourcePath || typeof sourcePath !== "string") return;
|
|
6920
|
-
const projectRoot =
|
|
6921
|
-
const resolvedFile =
|
|
7262
|
+
const projectRoot = resolve11(process.cwd());
|
|
7263
|
+
const resolvedFile = isAbsolute10(sourcePath) ? resolve11(sourcePath) : resolve11(projectRoot, sourcePath);
|
|
6922
7264
|
if (!isWithinRoot(projectRoot, resolvedFile)) return;
|
|
6923
7265
|
let changedFile;
|
|
6924
7266
|
try {
|
|
@@ -6933,7 +7275,7 @@ var plugin21 = {
|
|
|
6933
7275
|
state20.hookInvocationCount += 1;
|
|
6934
7276
|
const now = Date.now();
|
|
6935
7277
|
const lastWarning = state20.lastHookWarning.get(changedFile);
|
|
6936
|
-
if (lastWarning !== void 0 && now - lastWarning <
|
|
7278
|
+
if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS) return;
|
|
6937
7279
|
const changedFps = await readCachedFingerprints(changedFile, cfg.minLines);
|
|
6938
7280
|
if (changedFps === null) {
|
|
6939
7281
|
state20.errorCount += 1;
|
|
@@ -6952,7 +7294,7 @@ var plugin21 = {
|
|
|
6952
7294
|
}
|
|
6953
7295
|
const matched = /* @__PURE__ */ new Set();
|
|
6954
7296
|
for (const p of otherFilePaths) {
|
|
6955
|
-
if (
|
|
7297
|
+
if (resolve11(p) === resolve11(changedFile)) continue;
|
|
6956
7298
|
const otherFps = await readCachedFingerprints(p, cfg.minLines);
|
|
6957
7299
|
if (otherFps === null || otherFps.size === 0) continue;
|
|
6958
7300
|
for (const fp of changedFps) {
|
|
@@ -6998,7 +7340,7 @@ var plugin21 = {
|
|
|
6998
7340
|
state20.findingCount += result.findings.length;
|
|
6999
7341
|
return {
|
|
7000
7342
|
ok: true,
|
|
7001
|
-
path: relativePath3(
|
|
7343
|
+
path: relativePath3(resolve11(process.cwd(), rawPath)),
|
|
7002
7344
|
scannedFiles: result.scannedFiles,
|
|
7003
7345
|
minLines: cfg.minLines,
|
|
7004
7346
|
findings: result.findings
|
|
@@ -7373,7 +7715,7 @@ var error_lens_default = plugin22;
|
|
|
7373
7715
|
|
|
7374
7716
|
// src/feature-flag-tracker/index.ts
|
|
7375
7717
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
7376
|
-
import { isAbsolute as
|
|
7718
|
+
import { isAbsolute as isAbsolute11, relative as relative12, resolve as resolve12 } from "node:path";
|
|
7377
7719
|
var API_VERSION15 = "^0.1.10";
|
|
7378
7720
|
var state22 = {
|
|
7379
7721
|
scanCount: 0,
|
|
@@ -7412,11 +7754,17 @@ function toPosix4(p) {
|
|
|
7412
7754
|
return p.replace(/\\/g, "/");
|
|
7413
7755
|
}
|
|
7414
7756
|
function relativePath4(p) {
|
|
7415
|
-
return toPosix4(
|
|
7757
|
+
return toPosix4(relative12(process.cwd(), p));
|
|
7416
7758
|
}
|
|
7417
7759
|
function compilePatterns(patterns) {
|
|
7418
|
-
const
|
|
7419
|
-
|
|
7760
|
+
const out = [];
|
|
7761
|
+
for (const src of [...DEFAULT_PATTERNS2, ...patterns]) {
|
|
7762
|
+
try {
|
|
7763
|
+
out.push(new RegExp(src, "g"));
|
|
7764
|
+
} catch {
|
|
7765
|
+
}
|
|
7766
|
+
}
|
|
7767
|
+
return out;
|
|
7420
7768
|
}
|
|
7421
7769
|
function scanFile(filePath, content, patterns, maxFindings) {
|
|
7422
7770
|
const usages = [];
|
|
@@ -7442,20 +7790,31 @@ function scanFile(filePath, content, patterns, maxFindings) {
|
|
|
7442
7790
|
}
|
|
7443
7791
|
async function scanPath2(rawPath, cfg) {
|
|
7444
7792
|
const root = process.cwd();
|
|
7445
|
-
const resolved =
|
|
7793
|
+
const resolved = isAbsolute11(rawPath) ? resolve12(rawPath) : resolve12(root, rawPath);
|
|
7446
7794
|
const exts = normalizeExtensions3(cfg.extensions);
|
|
7447
7795
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
7448
7796
|
const patterns = compilePatterns(cfg.patterns);
|
|
7449
7797
|
const usages = [];
|
|
7798
|
+
let scannedFiles = 0;
|
|
7799
|
+
let truncated = false;
|
|
7450
7800
|
for (const p of files) {
|
|
7451
7801
|
try {
|
|
7452
7802
|
const content = await readFile7(p, "utf-8");
|
|
7803
|
+
scannedFiles += 1;
|
|
7453
7804
|
usages.push(...scanFile(p, content, patterns, cfg.maxFindings));
|
|
7454
|
-
if (usages.length >= cfg.maxFindings)
|
|
7805
|
+
if (usages.length >= cfg.maxFindings) {
|
|
7806
|
+
truncated = scannedFiles < files.length;
|
|
7807
|
+
break;
|
|
7808
|
+
}
|
|
7455
7809
|
} catch {
|
|
7456
7810
|
}
|
|
7457
7811
|
}
|
|
7458
|
-
return {
|
|
7812
|
+
return {
|
|
7813
|
+
usages: usages.slice(0, cfg.maxFindings),
|
|
7814
|
+
scannedFiles,
|
|
7815
|
+
discoveredFiles: files.length,
|
|
7816
|
+
truncated
|
|
7817
|
+
};
|
|
7459
7818
|
}
|
|
7460
7819
|
var plugin23 = {
|
|
7461
7820
|
name: "feature-flag-tracker",
|
|
@@ -7513,7 +7872,7 @@ var plugin23 = {
|
|
|
7513
7872
|
const exts = normalizeExtensions3(cfg.extensions);
|
|
7514
7873
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
7515
7874
|
state22.hookInvocationCount += 1;
|
|
7516
|
-
const resolved =
|
|
7875
|
+
const resolved = resolve12(process.cwd(), sourcePath);
|
|
7517
7876
|
let content;
|
|
7518
7877
|
try {
|
|
7519
7878
|
content = await readFile7(resolved, "utf-8");
|
|
@@ -7562,8 +7921,12 @@ Make sure flag behavior is intentional and consider updating flag inventory/docs
|
|
|
7562
7921
|
state22.flagCount += result.usages.length;
|
|
7563
7922
|
return {
|
|
7564
7923
|
ok: true,
|
|
7565
|
-
path: relativePath4(
|
|
7924
|
+
path: relativePath4(resolve12(process.cwd(), rawPath)),
|
|
7566
7925
|
scannedFiles: result.scannedFiles,
|
|
7926
|
+
discoveredFiles: result.discoveredFiles,
|
|
7927
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
7928
|
+
// that reports few findings must not read as a clean result.
|
|
7929
|
+
truncated: result.truncated,
|
|
7567
7930
|
usages: result.usages
|
|
7568
7931
|
};
|
|
7569
7932
|
}
|
|
@@ -7638,16 +8001,16 @@ var feature_flag_tracker_default = plugin23;
|
|
|
7638
8001
|
|
|
7639
8002
|
// src/file-watcher/index.ts
|
|
7640
8003
|
import { watch as fsWatch } from "node:fs";
|
|
7641
|
-
import { isAbsolute as
|
|
8004
|
+
import { isAbsolute as isAbsolute12, join as join3, relative as relative13, resolve as resolve13 } from "node:path";
|
|
7642
8005
|
var API_VERSION16 = "^0.1.10";
|
|
7643
8006
|
function withinProject3(p) {
|
|
7644
8007
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
7645
8008
|
const root = process.cwd();
|
|
7646
|
-
const resolved =
|
|
7647
|
-
const rel =
|
|
8009
|
+
const resolved = isAbsolute12(p) ? resolve13(p) : resolve13(root, p);
|
|
8010
|
+
const rel = relative13(root, resolved);
|
|
7648
8011
|
if (rel === "" || rel === ".") return true;
|
|
7649
8012
|
if (rel.startsWith("..")) return false;
|
|
7650
|
-
if (
|
|
8013
|
+
if (isAbsolute12(rel)) return false;
|
|
7651
8014
|
return true;
|
|
7652
8015
|
}
|
|
7653
8016
|
var watch_idCounter = 0;
|
|
@@ -7718,13 +8081,12 @@ var plugin24 = {
|
|
|
7718
8081
|
function debounceEvent(key, fn, ms) {
|
|
7719
8082
|
const existing = debounceTimers.get(key);
|
|
7720
8083
|
if (existing) clearTimeout(existing);
|
|
7721
|
-
|
|
7722
|
-
key
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
);
|
|
8084
|
+
const timer = setTimeout(() => {
|
|
8085
|
+
debounceTimers.delete(key);
|
|
8086
|
+
fn();
|
|
8087
|
+
}, ms);
|
|
8088
|
+
timer.unref?.();
|
|
8089
|
+
debounceTimers.set(key, timer);
|
|
7728
8090
|
}
|
|
7729
8091
|
const autoIndex = api.config.extensions?.["file-watcher"]?.["autoIndex"] ?? false;
|
|
7730
8092
|
const indexProjectRoot = api.config.extensions?.["file-watcher"]?.["indexProjectRoot"] ?? "";
|
|
@@ -7750,7 +8112,7 @@ var plugin24 = {
|
|
|
7750
8112
|
if (handle.events.length > 0 && !(eventType === "change" ? handle.events.includes("change") : handle.events.includes("add") || handle.events.includes("delete"))) {
|
|
7751
8113
|
return;
|
|
7752
8114
|
}
|
|
7753
|
-
const rawPath = filename.startsWith(dirPath) ? filename :
|
|
8115
|
+
const rawPath = filename.startsWith(dirPath) ? filename : join3(dirPath, filename);
|
|
7754
8116
|
const fullPath = rawPath.replace(/\\/g, "/");
|
|
7755
8117
|
const key = `${handle.id}:${fullPath}:${eventType}`;
|
|
7756
8118
|
debounceEvent(
|
|
@@ -7970,7 +8332,8 @@ var file_watcher_default = plugin24;
|
|
|
7970
8332
|
|
|
7971
8333
|
// src/format-on-save/index.ts
|
|
7972
8334
|
import { execFile as execFile6 } from "node:child_process";
|
|
7973
|
-
import {
|
|
8335
|
+
import { createHash } from "node:crypto";
|
|
8336
|
+
import { access as access2, readFile as readFile8, stat as stat4 } from "node:fs/promises";
|
|
7974
8337
|
var API_VERSION17 = "^0.1.10";
|
|
7975
8338
|
var state23 = {
|
|
7976
8339
|
invocationCount: 0,
|
|
@@ -8006,7 +8369,7 @@ function readConfig21(raw) {
|
|
|
8006
8369
|
skipTtlMs: typeof r["skipTtlMs"] === "number" && r["skipTtlMs"] >= 0 ? r["skipTtlMs"] : DEFAULTS20.skipTtlMs
|
|
8007
8370
|
};
|
|
8008
8371
|
}
|
|
8009
|
-
var recentlyCovered =
|
|
8372
|
+
var recentlyCovered = new BoundedMap({ max: 256 });
|
|
8010
8373
|
function clearRegistrations() {
|
|
8011
8374
|
if (state23.hookUnregister) {
|
|
8012
8375
|
try {
|
|
@@ -8029,6 +8392,55 @@ function evictExpired(ttlMs) {
|
|
|
8029
8392
|
if (ts < cutoff) recentlyCovered.delete(path);
|
|
8030
8393
|
}
|
|
8031
8394
|
}
|
|
8395
|
+
var FORMATTERS = [
|
|
8396
|
+
{
|
|
8397
|
+
packageName: "@biomejs/biome",
|
|
8398
|
+
binName: "biome",
|
|
8399
|
+
writeArgs: ["format", "--write"],
|
|
8400
|
+
label: "biome"
|
|
8401
|
+
},
|
|
8402
|
+
{ packageName: "prettier", binName: "prettier", writeArgs: ["--write"], label: "prettier" },
|
|
8403
|
+
{ packageName: "dprint", binName: "dprint", writeArgs: ["fmt"], label: "dprint" }
|
|
8404
|
+
];
|
|
8405
|
+
var activeFormatter;
|
|
8406
|
+
function resetFormatter() {
|
|
8407
|
+
activeFormatter = void 0;
|
|
8408
|
+
clearLocalBinCache();
|
|
8409
|
+
}
|
|
8410
|
+
function resolveFormatter() {
|
|
8411
|
+
if (activeFormatter !== void 0) return activeFormatter;
|
|
8412
|
+
const cwd = process.cwd();
|
|
8413
|
+
for (const f of FORMATTERS) {
|
|
8414
|
+
const local = resolveNodeBinFor(f, cwd);
|
|
8415
|
+
if (local) {
|
|
8416
|
+
activeFormatter = local;
|
|
8417
|
+
return local;
|
|
8418
|
+
}
|
|
8419
|
+
}
|
|
8420
|
+
for (const f of FORMATTERS) {
|
|
8421
|
+
const onPath = findOnPath(f.binName);
|
|
8422
|
+
if (!onPath) continue;
|
|
8423
|
+
activeFormatter = { cmd: onPath, args: [...f.writeArgs], label: f.label };
|
|
8424
|
+
return activeFormatter;
|
|
8425
|
+
}
|
|
8426
|
+
activeFormatter = null;
|
|
8427
|
+
return null;
|
|
8428
|
+
}
|
|
8429
|
+
function resolveNodeBinFor(f, cwd) {
|
|
8430
|
+
const hit = resolveFirstNodeBin([{ packageName: f.packageName, binName: f.binName }], cwd);
|
|
8431
|
+
if (!hit) return null;
|
|
8432
|
+
return { cmd: hit.cmd, args: [...hit.args, ...f.writeArgs], label: f.label };
|
|
8433
|
+
}
|
|
8434
|
+
function activeFormatterLabel() {
|
|
8435
|
+
return activeFormatter?.label ?? null;
|
|
8436
|
+
}
|
|
8437
|
+
async function sha256File(filePath) {
|
|
8438
|
+
try {
|
|
8439
|
+
return createHash("sha256").update(await readFile8(filePath)).digest("hex");
|
|
8440
|
+
} catch {
|
|
8441
|
+
return null;
|
|
8442
|
+
}
|
|
8443
|
+
}
|
|
8032
8444
|
async function formatFile(filePath, timeoutMs) {
|
|
8033
8445
|
if (!withinProject(filePath)) return null;
|
|
8034
8446
|
try {
|
|
@@ -8036,30 +8448,40 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
8036
8448
|
} catch {
|
|
8037
8449
|
return null;
|
|
8038
8450
|
}
|
|
8451
|
+
const formatter = resolveFormatter();
|
|
8452
|
+
if (!formatter) return null;
|
|
8039
8453
|
let bytesBefore;
|
|
8040
8454
|
try {
|
|
8041
8455
|
bytesBefore = (await stat4(filePath)).size;
|
|
8042
8456
|
} catch {
|
|
8043
8457
|
return null;
|
|
8044
8458
|
}
|
|
8459
|
+
const hashBefore = await sha256File(filePath);
|
|
8460
|
+
let invocation;
|
|
8461
|
+
try {
|
|
8462
|
+
invocation = resolveExecInvocation(formatter.cmd, [...formatter.args, filePath]);
|
|
8463
|
+
} catch {
|
|
8464
|
+
return null;
|
|
8465
|
+
}
|
|
8045
8466
|
try {
|
|
8046
|
-
await new Promise((
|
|
8467
|
+
await new Promise((resolve28, reject) => {
|
|
8047
8468
|
execFile6(
|
|
8048
|
-
|
|
8049
|
-
|
|
8469
|
+
invocation.cmd,
|
|
8470
|
+
invocation.args,
|
|
8050
8471
|
{
|
|
8051
8472
|
encoding: "utf-8",
|
|
8052
8473
|
timeout: timeoutMs,
|
|
8053
8474
|
cwd: process.cwd(),
|
|
8054
8475
|
windowsHide: true,
|
|
8055
|
-
maxBuffer: 16 * 1024 * 1024
|
|
8476
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
8477
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
8056
8478
|
},
|
|
8057
8479
|
(err) => {
|
|
8058
8480
|
if (err) {
|
|
8059
8481
|
const e = err;
|
|
8060
8482
|
if (e.killed) return reject(err);
|
|
8061
8483
|
}
|
|
8062
|
-
|
|
8484
|
+
resolve28();
|
|
8063
8485
|
}
|
|
8064
8486
|
);
|
|
8065
8487
|
});
|
|
@@ -8075,28 +8497,11 @@ async function formatFile(filePath, timeoutMs) {
|
|
|
8075
8497
|
if (bytesAfter !== bytesBefore) {
|
|
8076
8498
|
return { changed: true, bytesBefore, bytesAfter };
|
|
8077
8499
|
}
|
|
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
|
-
});
|
|
8500
|
+
const hashAfter = await sha256File(filePath);
|
|
8501
|
+
if (hashBefore === null || hashAfter === null) {
|
|
8096
8502
|
return { changed: false, bytesBefore, bytesAfter };
|
|
8097
|
-
} catch {
|
|
8098
|
-
return { changed: true, bytesBefore, bytesAfter };
|
|
8099
8503
|
}
|
|
8504
|
+
return { changed: hashBefore !== hashAfter, bytesBefore, bytesAfter };
|
|
8100
8505
|
}
|
|
8101
8506
|
var plugin25 = {
|
|
8102
8507
|
name: "format-on-save",
|
|
@@ -8142,32 +8547,18 @@ var plugin25 = {
|
|
|
8142
8547
|
state23.lastResult = null;
|
|
8143
8548
|
recentlyCovered.clear();
|
|
8144
8549
|
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");
|
|
8550
|
+
resetFormatter();
|
|
8551
|
+
const formatter = resolveFormatter();
|
|
8552
|
+
const formatterAvailable = formatter !== null;
|
|
8553
|
+
if (formatter) {
|
|
8554
|
+
api.log.info(`format-on-save: ${formatter.label} detected`);
|
|
8555
|
+
} else {
|
|
8556
|
+
api.log.warn(
|
|
8557
|
+
"format-on-save: no formatter found (biome, prettier, dprint) \u2014 hook will be a no-op"
|
|
8558
|
+
);
|
|
8168
8559
|
}
|
|
8169
8560
|
const hook = async (input) => {
|
|
8170
|
-
if (!cfg.enabled || !
|
|
8561
|
+
if (!cfg.enabled || !formatterAvailable) return;
|
|
8171
8562
|
if (input.toolResult?.isError) return;
|
|
8172
8563
|
const toolName = input.toolName ?? "";
|
|
8173
8564
|
const inp = input.toolInput ?? {};
|
|
@@ -8228,7 +8619,7 @@ var plugin25 = {
|
|
|
8228
8619
|
);
|
|
8229
8620
|
api.tools.register({
|
|
8230
8621
|
name: "format_on_save_status",
|
|
8231
|
-
description: "Reports format-on-save state:
|
|
8622
|
+
description: "Reports format-on-save state: which formatter is active, and per-session formatted/clean/error/skipped counters.",
|
|
8232
8623
|
inputSchema: { type: "object", properties: {} },
|
|
8233
8624
|
permission: "auto",
|
|
8234
8625
|
category: "Code Quality",
|
|
@@ -8237,7 +8628,14 @@ var plugin25 = {
|
|
|
8237
8628
|
return {
|
|
8238
8629
|
ok: true,
|
|
8239
8630
|
enabled: cfg.enabled,
|
|
8240
|
-
|
|
8631
|
+
formatterAvailable,
|
|
8632
|
+
formatter: activeFormatterLabel(),
|
|
8633
|
+
/**
|
|
8634
|
+
* Back-compat alias for the pre-multi-formatter status shape.
|
|
8635
|
+
* Now accurate rather than assumed: true only when the resolved
|
|
8636
|
+
* formatter really is biome.
|
|
8637
|
+
*/
|
|
8638
|
+
biomeAvailable: activeFormatterLabel() === "biome",
|
|
8241
8639
|
timeoutMs: cfg.timeoutMs,
|
|
8242
8640
|
skipWhenCoveredBy: cfg.skipWhenCoveredBy,
|
|
8243
8641
|
skipTtlMs: cfg.skipTtlMs,
|
|
@@ -8255,11 +8653,13 @@ var plugin25 = {
|
|
|
8255
8653
|
api.log.info("format-on-save plugin loaded", {
|
|
8256
8654
|
version: "0.1.0",
|
|
8257
8655
|
enabled: cfg.enabled,
|
|
8258
|
-
|
|
8656
|
+
formatterAvailable,
|
|
8657
|
+
formatter: activeFormatterLabel()
|
|
8259
8658
|
});
|
|
8260
8659
|
},
|
|
8261
8660
|
teardown(api) {
|
|
8262
8661
|
clearRegistrations();
|
|
8662
|
+
resetFormatter();
|
|
8263
8663
|
const final = {
|
|
8264
8664
|
invocations: state23.invocationCount,
|
|
8265
8665
|
formatted: state23.formattedCount,
|
|
@@ -8329,10 +8729,63 @@ async function runGit3(args, cwd, timeoutMs = DEFAULT_GIT_TIMEOUT_MS) {
|
|
|
8329
8729
|
);
|
|
8330
8730
|
});
|
|
8331
8731
|
}
|
|
8732
|
+
function unquotePorcelainPath(raw) {
|
|
8733
|
+
if (!raw.startsWith('"') || !raw.endsWith('"') || raw.length < 2) return raw;
|
|
8734
|
+
const inner = raw.slice(1, -1);
|
|
8735
|
+
const bytes = [];
|
|
8736
|
+
for (let i = 0; i < inner.length; i++) {
|
|
8737
|
+
const ch = inner[i];
|
|
8738
|
+
if (ch !== "\\") {
|
|
8739
|
+
for (const b of Buffer.from(ch, "utf8")) bytes.push(b);
|
|
8740
|
+
continue;
|
|
8741
|
+
}
|
|
8742
|
+
const next = inner[i + 1];
|
|
8743
|
+
if (next === void 0) {
|
|
8744
|
+
bytes.push(92);
|
|
8745
|
+
break;
|
|
8746
|
+
}
|
|
8747
|
+
const simple = {
|
|
8748
|
+
n: 10,
|
|
8749
|
+
t: 9,
|
|
8750
|
+
r: 13,
|
|
8751
|
+
a: 7,
|
|
8752
|
+
b: 8,
|
|
8753
|
+
f: 12,
|
|
8754
|
+
v: 11,
|
|
8755
|
+
'"': 34,
|
|
8756
|
+
"\\": 92
|
|
8757
|
+
};
|
|
8758
|
+
const mapped = simple[next];
|
|
8759
|
+
if (mapped !== void 0) {
|
|
8760
|
+
bytes.push(mapped);
|
|
8761
|
+
i += 1;
|
|
8762
|
+
continue;
|
|
8763
|
+
}
|
|
8764
|
+
const octal = /^[0-7]{1,3}/.exec(inner.slice(i + 1));
|
|
8765
|
+
if (octal) {
|
|
8766
|
+
bytes.push(Number.parseInt(octal[0], 8) & 255);
|
|
8767
|
+
i += octal[0].length;
|
|
8768
|
+
continue;
|
|
8769
|
+
}
|
|
8770
|
+
for (const b of Buffer.from(next, "utf8")) bytes.push(b);
|
|
8771
|
+
i += 1;
|
|
8772
|
+
}
|
|
8773
|
+
return Buffer.from(bytes).toString("utf8");
|
|
8774
|
+
}
|
|
8775
|
+
function parsePorcelainLine(line) {
|
|
8776
|
+
const body = line.slice(3);
|
|
8777
|
+
if (!body) return null;
|
|
8778
|
+
const status = line.slice(0, 2);
|
|
8779
|
+
if (status.includes("R") || status.includes("C")) {
|
|
8780
|
+
const arrow = body.lastIndexOf(" -> ");
|
|
8781
|
+
if (arrow !== -1) return unquotePorcelainPath(body.slice(arrow + 4).trim());
|
|
8782
|
+
}
|
|
8783
|
+
return unquotePorcelainPath(body.trim());
|
|
8784
|
+
}
|
|
8332
8785
|
async function getChangedFiles(cwd) {
|
|
8333
8786
|
const output = await runGit3(["status", "--porcelain"], cwd);
|
|
8334
8787
|
if (!output) return [];
|
|
8335
|
-
return output.split("\n").filter((l) => l.trim()).map((l) => l.
|
|
8788
|
+
return output.split("\n").filter((l) => l.trim()).map((l) => parsePorcelainLine(l)).filter((p) => p !== null && p.length > 0);
|
|
8336
8789
|
}
|
|
8337
8790
|
async function getStagedFiles(cwd) {
|
|
8338
8791
|
const output = await runGit3(["diff", "--cached", "--name-only"], cwd);
|
|
@@ -8348,7 +8801,7 @@ async function stageFiles(files, cwd) {
|
|
|
8348
8801
|
}
|
|
8349
8802
|
});
|
|
8350
8803
|
if (existing.length === 0) throw new Error("No files exist to stage");
|
|
8351
|
-
await runGit3(["add", ...existing], cwd);
|
|
8804
|
+
await runGit3(["add", "--", ...existing], cwd);
|
|
8352
8805
|
}
|
|
8353
8806
|
async function commitWithMessage(message, cwd) {
|
|
8354
8807
|
return await runGit3(["commit", "-m", message], cwd, GIT_COMMIT_TIMEOUT_MS);
|
|
@@ -8401,7 +8854,7 @@ async function externalChangesSinceStage(cwd) {
|
|
|
8401
8854
|
const unstaged = out.split("\n").filter((l) => l.trim()).filter((l) => {
|
|
8402
8855
|
const idx = l[0] ?? " ";
|
|
8403
8856
|
return idx === " " || idx === "?";
|
|
8404
|
-
}).map((l) => l.
|
|
8857
|
+
}).map((l) => parsePorcelainLine(l)).filter((p) => p !== null && p.length > 0);
|
|
8405
8858
|
return unstaged.length > 0 ? unstaged : null;
|
|
8406
8859
|
} catch {
|
|
8407
8860
|
return null;
|
|
@@ -8768,7 +9221,7 @@ var git_autocommit_default = plugin26;
|
|
|
8768
9221
|
// src/import-organizer/index.ts
|
|
8769
9222
|
import { spawn } from "node:child_process";
|
|
8770
9223
|
import { existsSync as existsSync3, statSync as statSync2 } from "node:fs";
|
|
8771
|
-
import { basename as basename4, isAbsolute as
|
|
9224
|
+
import { basename as basename4, isAbsolute as isAbsolute13 } from "node:path";
|
|
8772
9225
|
var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
8773
9226
|
"npx",
|
|
8774
9227
|
"pnpm",
|
|
@@ -8777,23 +9230,51 @@ var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
|
|
|
8777
9230
|
"biome",
|
|
8778
9231
|
"@biomejs/biome",
|
|
8779
9232
|
"eslint",
|
|
9233
|
+
"oxlint",
|
|
8780
9234
|
"node"
|
|
8781
9235
|
// Recognise a fully-qualified project-local path like
|
|
8782
9236
|
// "./node_modules/.bin/biome"; basename check kicks in below.
|
|
8783
9237
|
]);
|
|
9238
|
+
var PACKAGE_RUNNERS = /* @__PURE__ */ new Set(["npx", "pnpm", "npm", "yarn"]);
|
|
9239
|
+
var LOCAL_BIN_PACKAGES = {
|
|
9240
|
+
biome: { packageName: "@biomejs/biome", binName: "biome" },
|
|
9241
|
+
"@biomejs/biome": { packageName: "@biomejs/biome", binName: "biome" },
|
|
9242
|
+
eslint: { packageName: "eslint", binName: "eslint" },
|
|
9243
|
+
oxlint: { packageName: "oxlint", binName: "oxlint" }
|
|
9244
|
+
};
|
|
9245
|
+
function resolveLocalToolCommand(tokens) {
|
|
9246
|
+
if (tokens.length === 0) return null;
|
|
9247
|
+
let i = 0;
|
|
9248
|
+
if (PACKAGE_RUNNERS.has(tokens[i])) {
|
|
9249
|
+
i++;
|
|
9250
|
+
while (i < tokens.length && (tokens[i] === "exec" || tokens[i] === "dlx" || tokens[i] === "run")) {
|
|
9251
|
+
i++;
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
const toolToken = tokens[i];
|
|
9255
|
+
if (!toolToken) return null;
|
|
9256
|
+
const rest = tokens.slice(i + 1);
|
|
9257
|
+
const pkg = LOCAL_BIN_PACKAGES[toolToken];
|
|
9258
|
+
if (!pkg) return null;
|
|
9259
|
+
const local = resolveNodeBin(pkg.packageName, pkg.binName, process.cwd(), rest);
|
|
9260
|
+
if (!local) return null;
|
|
9261
|
+
return { cmd: local.cmd, args: local.args };
|
|
9262
|
+
}
|
|
8784
9263
|
function resolveAllowedCommand(command) {
|
|
8785
9264
|
const tokens = command.split(/\s+/).filter(Boolean);
|
|
8786
9265
|
if (tokens.length === 0) return null;
|
|
8787
9266
|
const head = tokens[0];
|
|
9267
|
+
const local = ALLOWED_FIRST_TOKENS.has(head) ? resolveLocalToolCommand(tokens) : null;
|
|
9268
|
+
if (local) return local;
|
|
8788
9269
|
if (ALLOWED_FIRST_TOKENS.has(head)) {
|
|
8789
9270
|
return { cmd: head, args: tokens.slice(1) };
|
|
8790
9271
|
}
|
|
8791
|
-
if (
|
|
9272
|
+
if (isAbsolute13(head)) {
|
|
8792
9273
|
if (!withinProject(head)) return null;
|
|
8793
9274
|
const base = basename4(head);
|
|
8794
9275
|
if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
|
|
8795
9276
|
}
|
|
8796
|
-
if (!
|
|
9277
|
+
if (!isAbsolute13(head) && withinProject(head)) {
|
|
8797
9278
|
const base = basename4(head);
|
|
8798
9279
|
if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
|
|
8799
9280
|
}
|
|
@@ -8828,40 +9309,70 @@ function readConfig22(raw) {
|
|
|
8828
9309
|
notifyFormatOnSave: r["notifyFormatOnSave"] !== false
|
|
8829
9310
|
};
|
|
8830
9311
|
}
|
|
9312
|
+
var MAX_CAPTURE_BYTES = 4 * 1024 * 1024;
|
|
8831
9313
|
function runCommand(command, args, timeoutMs, cwd) {
|
|
8832
|
-
return new Promise((
|
|
9314
|
+
return new Promise((resolve28) => {
|
|
8833
9315
|
let timedOut = false;
|
|
9316
|
+
let settled = false;
|
|
9317
|
+
const settle = (r) => {
|
|
9318
|
+
if (settled) return;
|
|
9319
|
+
settled = true;
|
|
9320
|
+
resolve28(r);
|
|
9321
|
+
};
|
|
8834
9322
|
const stdoutChunks = [];
|
|
8835
9323
|
const stderrChunks = [];
|
|
9324
|
+
let stdoutBytes = 0;
|
|
9325
|
+
let stderrBytes = 0;
|
|
9326
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
9327
|
+
const onAbort = () => {
|
|
9328
|
+
timedOut = true;
|
|
9329
|
+
settle({ code: null, stdout: "", stderr: "", timedOut: true });
|
|
9330
|
+
};
|
|
9331
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
8836
9332
|
let child;
|
|
9333
|
+
let invocation;
|
|
8837
9334
|
try {
|
|
8838
|
-
|
|
9335
|
+
invocation = resolveExecInvocation(command, args);
|
|
9336
|
+
} catch {
|
|
9337
|
+
signal.removeEventListener("abort", onAbort);
|
|
9338
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
9339
|
+
return;
|
|
9340
|
+
}
|
|
9341
|
+
try {
|
|
9342
|
+
child = spawn(invocation.cmd, invocation.args, {
|
|
8839
9343
|
cwd,
|
|
8840
9344
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8841
|
-
signal
|
|
9345
|
+
signal,
|
|
9346
|
+
windowsHide: true,
|
|
9347
|
+
...invocation.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
8842
9348
|
});
|
|
8843
9349
|
} catch {
|
|
8844
|
-
|
|
9350
|
+
signal.removeEventListener("abort", onAbort);
|
|
9351
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
8845
9352
|
return;
|
|
8846
9353
|
}
|
|
8847
|
-
child.stdout?.on("data", (c) =>
|
|
8848
|
-
|
|
9354
|
+
child.stdout?.on("data", (c) => {
|
|
9355
|
+
stdoutBytes += c.length;
|
|
9356
|
+
if (stdoutBytes <= MAX_CAPTURE_BYTES) stdoutChunks.push(c);
|
|
9357
|
+
});
|
|
9358
|
+
child.stderr?.on("data", (c) => {
|
|
9359
|
+
stderrBytes += c.length;
|
|
9360
|
+
if (stderrBytes <= MAX_CAPTURE_BYTES) stderrChunks.push(c);
|
|
9361
|
+
});
|
|
8849
9362
|
child.on("error", () => {
|
|
8850
|
-
|
|
9363
|
+
signal.removeEventListener("abort", onAbort);
|
|
9364
|
+
settle({ code: 127, stdout: "", stderr: "", timedOut: false });
|
|
8851
9365
|
});
|
|
8852
9366
|
child.on("close", (code) => {
|
|
9367
|
+
signal.removeEventListener("abort", onAbort);
|
|
8853
9368
|
if (timedOut) return;
|
|
8854
|
-
|
|
9369
|
+
settle({
|
|
8855
9370
|
code,
|
|
8856
9371
|
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
8857
9372
|
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
8858
9373
|
timedOut: false
|
|
8859
9374
|
});
|
|
8860
9375
|
});
|
|
8861
|
-
child.on("abort", () => {
|
|
8862
|
-
timedOut = true;
|
|
8863
|
-
resolve27({ code: null, stdout: "", stderr: "", timedOut: true });
|
|
8864
|
-
});
|
|
8865
9376
|
});
|
|
8866
9377
|
}
|
|
8867
9378
|
async function organizeImports(filePath, cfg, cwd) {
|
|
@@ -8945,7 +9456,7 @@ var plugin27 = {
|
|
|
8945
9456
|
state24.organizedCount = 0;
|
|
8946
9457
|
state24.cleanCount = 0;
|
|
8947
9458
|
state24.errorCount = 0;
|
|
8948
|
-
state24.hookUnregister =
|
|
9459
|
+
state24.hookUnregister = releaseHandle(state24.hookUnregister);
|
|
8949
9460
|
state24.lastResult = null;
|
|
8950
9461
|
state24.probeComplete = false;
|
|
8951
9462
|
state24.linterAvailable = false;
|
|
@@ -9152,12 +9663,19 @@ var PATTERNS = [
|
|
|
9152
9663
|
re: /(?:\u200B|\u200C|\u200D|\u2060|\uFEFF){20,}/
|
|
9153
9664
|
}
|
|
9154
9665
|
];
|
|
9666
|
+
var INVISIBLE_CHARS = /[\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u2064\uFEFF]/g;
|
|
9667
|
+
function stripInvisible(text) {
|
|
9668
|
+
INVISIBLE_CHARS.lastIndex = 0;
|
|
9669
|
+
return text.replace(INVISIBLE_CHARS, "");
|
|
9670
|
+
}
|
|
9155
9671
|
function scanForInjection(text) {
|
|
9156
|
-
const hits =
|
|
9672
|
+
const hits = /* @__PURE__ */ new Set();
|
|
9673
|
+
const cleaned = stripInvisible(text);
|
|
9157
9674
|
for (const p of PATTERNS) {
|
|
9158
|
-
if (p.re.test(text)) hits.
|
|
9675
|
+
if (p.re.test(text)) hits.add(p.name);
|
|
9676
|
+
else if (cleaned !== text && p.re.test(cleaned)) hits.add(p.name);
|
|
9159
9677
|
}
|
|
9160
|
-
return hits;
|
|
9678
|
+
return [...hits];
|
|
9161
9679
|
}
|
|
9162
9680
|
var plugin28 = {
|
|
9163
9681
|
name: "injection-shield",
|
|
@@ -9292,8 +9810,8 @@ var plugin28 = {
|
|
|
9292
9810
|
var injection_shield_default = plugin28;
|
|
9293
9811
|
|
|
9294
9812
|
// src/interface-contract-guard/index.ts
|
|
9295
|
-
import { readFile as
|
|
9296
|
-
import { isAbsolute as
|
|
9813
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
9814
|
+
import { isAbsolute as isAbsolute14, relative as relative14, resolve as resolve14 } from "node:path";
|
|
9297
9815
|
var API_VERSION20 = "^0.1.10";
|
|
9298
9816
|
var state26 = {
|
|
9299
9817
|
scanCount: 0,
|
|
@@ -9306,7 +9824,8 @@ var state26 = {
|
|
|
9306
9824
|
var DEFAULTS23 = {
|
|
9307
9825
|
enabled: false,
|
|
9308
9826
|
extensions: [".ts", ".tsx"],
|
|
9309
|
-
maxFindings: 50
|
|
9827
|
+
maxFindings: 50,
|
|
9828
|
+
maxFiles: 2e3
|
|
9310
9829
|
};
|
|
9311
9830
|
function readConfig24(raw) {
|
|
9312
9831
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS23 };
|
|
@@ -9314,7 +9833,8 @@ function readConfig24(raw) {
|
|
|
9314
9833
|
return {
|
|
9315
9834
|
enabled: r["enabled"] !== false,
|
|
9316
9835
|
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
|
|
9836
|
+
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS23.maxFindings,
|
|
9837
|
+
maxFiles: typeof r["maxFiles"] === "number" && r["maxFiles"] >= 1 && r["maxFiles"] <= 5e4 ? Math.floor(r["maxFiles"]) : DEFAULTS23.maxFiles
|
|
9318
9838
|
};
|
|
9319
9839
|
}
|
|
9320
9840
|
function normalizeExtensions4(exts) {
|
|
@@ -9324,53 +9844,66 @@ function toPosix5(p) {
|
|
|
9324
9844
|
return p.replace(/\\/g, "/");
|
|
9325
9845
|
}
|
|
9326
9846
|
function relativePath5(p) {
|
|
9327
|
-
return toPosix5(
|
|
9847
|
+
return toPosix5(relative14(process.cwd(), p));
|
|
9328
9848
|
}
|
|
9329
9849
|
var INTERFACE_RE = /(?:export\s+)?interface\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
9330
9850
|
function extractInterfaceNames(content) {
|
|
9331
9851
|
const names = [];
|
|
9332
9852
|
INTERFACE_RE.lastIndex = 0;
|
|
9853
|
+
let searchedUpTo = 0;
|
|
9854
|
+
let line = 1;
|
|
9333
9855
|
for (const m of content.matchAll(INTERFACE_RE)) {
|
|
9334
|
-
|
|
9856
|
+
const index = m.index ?? 0;
|
|
9857
|
+
for (let i = searchedUpTo; i < index; i++) {
|
|
9858
|
+
if (content.charCodeAt(i) === 10) line += 1;
|
|
9859
|
+
}
|
|
9860
|
+
searchedUpTo = index;
|
|
9861
|
+
names.push({ name: m[1], line });
|
|
9335
9862
|
}
|
|
9336
9863
|
return names;
|
|
9337
9864
|
}
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9865
|
+
var IMPLEMENTER_RE = /(?:implements|satisfies|\bas)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
9866
|
+
function collectImplementedNames(content, into) {
|
|
9867
|
+
IMPLEMENTER_RE.lastIndex = 0;
|
|
9868
|
+
for (const m of content.matchAll(IMPLEMENTER_RE)) {
|
|
9869
|
+
const name = m[1];
|
|
9870
|
+
if (name) into.add(name);
|
|
9342
9871
|
}
|
|
9343
|
-
return false;
|
|
9344
9872
|
}
|
|
9345
9873
|
async function scanPath3(rawPath, cfg) {
|
|
9346
9874
|
const root = process.cwd();
|
|
9347
|
-
const resolved =
|
|
9875
|
+
const resolved = isAbsolute14(rawPath) ? resolve14(rawPath) : resolve14(root, rawPath);
|
|
9348
9876
|
const exts = normalizeExtensions4(cfg.extensions);
|
|
9349
|
-
const
|
|
9350
|
-
const
|
|
9877
|
+
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
9878
|
+
const files = allFiles.slice(0, cfg.maxFiles);
|
|
9879
|
+
const implemented = /* @__PURE__ */ new Set();
|
|
9880
|
+
const declarations = [];
|
|
9881
|
+
let scannedFiles = 0;
|
|
9351
9882
|
for (const p of files) {
|
|
9883
|
+
let content;
|
|
9352
9884
|
try {
|
|
9353
|
-
|
|
9885
|
+
content = await readFile9(p, "utf-8");
|
|
9354
9886
|
} catch {
|
|
9887
|
+
continue;
|
|
9355
9888
|
}
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
const findings = [];
|
|
9359
|
-
for (const { path, content } of contents) {
|
|
9889
|
+
scannedFiles += 1;
|
|
9890
|
+
collectImplementedNames(content, implemented);
|
|
9360
9891
|
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
|
-
}
|
|
9892
|
+
declarations.push({ name, line, file: p });
|
|
9370
9893
|
}
|
|
9894
|
+
}
|
|
9895
|
+
const findings = [];
|
|
9896
|
+
for (const { name, line, file } of declarations) {
|
|
9897
|
+
if (implemented.has(name)) continue;
|
|
9898
|
+
findings.push({
|
|
9899
|
+
interfaceName: name,
|
|
9900
|
+
file: relativePath5(file),
|
|
9901
|
+
line,
|
|
9902
|
+
message: `interface "${name}" is declared but has no visible implementer`
|
|
9903
|
+
});
|
|
9371
9904
|
if (findings.length >= cfg.maxFindings) break;
|
|
9372
9905
|
}
|
|
9373
|
-
return { findings, scannedFiles:
|
|
9906
|
+
return { findings, scannedFiles, truncated: allFiles.length > files.length };
|
|
9374
9907
|
}
|
|
9375
9908
|
var plugin29 = {
|
|
9376
9909
|
name: "interface-contract-guard",
|
|
@@ -9389,6 +9922,13 @@ var plugin29 = {
|
|
|
9389
9922
|
default: [".ts", ".tsx"],
|
|
9390
9923
|
description: "File extensions to scan."
|
|
9391
9924
|
},
|
|
9925
|
+
maxFiles: {
|
|
9926
|
+
type: "number",
|
|
9927
|
+
minimum: 1,
|
|
9928
|
+
maximum: 5e4,
|
|
9929
|
+
default: 2e3,
|
|
9930
|
+
description: "Upper bound on files read per scan."
|
|
9931
|
+
},
|
|
9392
9932
|
maxFindings: {
|
|
9393
9933
|
type: "number",
|
|
9394
9934
|
minimum: 1,
|
|
@@ -9422,10 +9962,10 @@ var plugin29 = {
|
|
|
9422
9962
|
const exts = normalizeExtensions4(cfg.extensions);
|
|
9423
9963
|
if (!matchesExtension(sourcePath, exts)) return;
|
|
9424
9964
|
state26.hookInvocationCount += 1;
|
|
9425
|
-
const resolved =
|
|
9965
|
+
const resolved = resolve14(process.cwd(), sourcePath);
|
|
9426
9966
|
let content;
|
|
9427
9967
|
try {
|
|
9428
|
-
content = await
|
|
9968
|
+
content = await readFile9(resolved, "utf-8");
|
|
9429
9969
|
} catch {
|
|
9430
9970
|
state26.errorCount += 1;
|
|
9431
9971
|
return;
|
|
@@ -9470,9 +10010,16 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
9470
10010
|
state26.findingCount += result.findings.length;
|
|
9471
10011
|
return {
|
|
9472
10012
|
ok: true,
|
|
9473
|
-
path: relativePath5(
|
|
10013
|
+
path: relativePath5(resolve14(process.cwd(), rawPath)),
|
|
9474
10014
|
scannedFiles: result.scannedFiles,
|
|
9475
|
-
findings: result.findings
|
|
10015
|
+
findings: result.findings,
|
|
10016
|
+
// Say so when the corpus was cut short. A partial scan that
|
|
10017
|
+
// reports "no findings" is not the same as a clean result, and
|
|
10018
|
+
// the caller has no other way to tell the difference.
|
|
10019
|
+
truncated: result.truncated,
|
|
10020
|
+
...result.truncated ? {
|
|
10021
|
+
note: `Scan stopped at the maxFiles limit (${cfg.maxFiles}); results are partial. Raise \`maxFiles\` or scan a narrower path for full coverage.`
|
|
10022
|
+
} : {}
|
|
9476
10023
|
};
|
|
9477
10024
|
}
|
|
9478
10025
|
});
|
|
@@ -9543,8 +10090,9 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
9543
10090
|
var interface_contract_guard_default = plugin29;
|
|
9544
10091
|
|
|
9545
10092
|
// src/knowledge-graph/index.ts
|
|
9546
|
-
import {
|
|
9547
|
-
import { dirname as
|
|
10093
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
10094
|
+
import { dirname as dirname5, isAbsolute as isAbsolute15, relative as relative15, resolve as resolve15 } from "node:path";
|
|
10095
|
+
import { atomicWrite as atomicWrite2, ensureDir as ensureDir2 } from "@wrongstack/core/utils";
|
|
9548
10096
|
var API_VERSION21 = "^0.1.10";
|
|
9549
10097
|
var state27 = {
|
|
9550
10098
|
facts: [],
|
|
@@ -9565,10 +10113,10 @@ var DEFAULTS24 = {
|
|
|
9565
10113
|
};
|
|
9566
10114
|
function resolveProjectPath5(rawPath, cwd = process.cwd()) {
|
|
9567
10115
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
9568
|
-
const root =
|
|
9569
|
-
const resolved =
|
|
9570
|
-
const rel =
|
|
9571
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
10116
|
+
const root = resolve15(cwd);
|
|
10117
|
+
const resolved = isAbsolute15(rawPath) ? resolve15(rawPath) : resolve15(root, rawPath);
|
|
10118
|
+
const rel = relative15(root, resolved);
|
|
10119
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute15(rel)) return resolved;
|
|
9572
10120
|
return null;
|
|
9573
10121
|
}
|
|
9574
10122
|
function readConfig25(raw) {
|
|
@@ -9586,7 +10134,7 @@ function readConfig25(raw) {
|
|
|
9586
10134
|
function loadFacts(filePath) {
|
|
9587
10135
|
if (!filePath) return { facts: [], nextId: 1 };
|
|
9588
10136
|
try {
|
|
9589
|
-
const raw = JSON.parse(
|
|
10137
|
+
const raw = JSON.parse(readFileSync7(filePath, "utf-8"));
|
|
9590
10138
|
const facts = Array.isArray(raw.facts) ? raw.facts.filter(
|
|
9591
10139
|
(f) => !!f && typeof f === "object" && typeof f.id === "string" && typeof f.subject === "string" && typeof f.relation === "string" && typeof f.object === "string"
|
|
9592
10140
|
) : [];
|
|
@@ -9596,11 +10144,11 @@ function loadFacts(filePath) {
|
|
|
9596
10144
|
return { facts: [], nextId: 1 };
|
|
9597
10145
|
}
|
|
9598
10146
|
}
|
|
9599
|
-
function persistFacts(filePath) {
|
|
10147
|
+
async function persistFacts(filePath) {
|
|
9600
10148
|
if (!filePath) return true;
|
|
9601
10149
|
try {
|
|
9602
|
-
|
|
9603
|
-
|
|
10150
|
+
await ensureDir2(dirname5(filePath));
|
|
10151
|
+
await atomicWrite2(
|
|
9604
10152
|
filePath,
|
|
9605
10153
|
JSON.stringify({ facts: state27.facts, nextId: state27.nextId }, null, 2)
|
|
9606
10154
|
);
|
|
@@ -9731,7 +10279,7 @@ var plugin30 = {
|
|
|
9731
10279
|
state27.facts.push(fact);
|
|
9732
10280
|
state27.adds += 1;
|
|
9733
10281
|
api.metrics.counter("adds");
|
|
9734
|
-
const persisted = persistFacts(resolved);
|
|
10282
|
+
const persisted = await persistFacts(resolved);
|
|
9735
10283
|
return { ok: true, fact, persisted, totalFacts: state27.facts.length };
|
|
9736
10284
|
}
|
|
9737
10285
|
});
|
|
@@ -9791,7 +10339,7 @@ var plugin30 = {
|
|
|
9791
10339
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id}"` };
|
|
9792
10340
|
state27.removals += removed;
|
|
9793
10341
|
api.metrics.counter("removals", removed);
|
|
9794
|
-
const persisted = persistFacts(resolved);
|
|
10342
|
+
const persisted = await persistFacts(resolved);
|
|
9795
10343
|
return { ok: true, removed, persisted, totalFacts: state27.facts.length };
|
|
9796
10344
|
}
|
|
9797
10345
|
});
|
|
@@ -9866,8 +10414,8 @@ var plugin30 = {
|
|
|
9866
10414
|
var knowledge_graph_default = plugin30;
|
|
9867
10415
|
|
|
9868
10416
|
// src/license-audit-gate/index.ts
|
|
9869
|
-
import { readFileSync as
|
|
9870
|
-
import { resolve as
|
|
10417
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
10418
|
+
import { resolve as resolve16 } from "node:path";
|
|
9871
10419
|
var API_VERSION22 = "^0.1.10";
|
|
9872
10420
|
var state28 = {
|
|
9873
10421
|
invocations: 0,
|
|
@@ -9943,8 +10491,8 @@ function auditPackages(names, allowedLicenses) {
|
|
|
9943
10491
|
for (const name of names) {
|
|
9944
10492
|
let licenses = [];
|
|
9945
10493
|
try {
|
|
9946
|
-
const pkgPath =
|
|
9947
|
-
const raw = JSON.parse(
|
|
10494
|
+
const pkgPath = resolve16("node_modules", name, "package.json");
|
|
10495
|
+
const raw = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
9948
10496
|
licenses = extractLicenseStrings(raw);
|
|
9949
10497
|
} catch {
|
|
9950
10498
|
errors.push(name);
|
|
@@ -10124,11 +10672,11 @@ var license_audit_gate_default = plugin31;
|
|
|
10124
10672
|
|
|
10125
10673
|
// src/lint-gate/index.ts
|
|
10126
10674
|
import { execFile as execFile8 } from "node:child_process";
|
|
10127
|
-
import { readFileSync as
|
|
10128
|
-
import { mkdtemp, readFile as
|
|
10129
|
-
import { createRequire } from "node:module";
|
|
10675
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
10676
|
+
import { mkdtemp, readFile as readFile10, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
10677
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
10130
10678
|
import { tmpdir } from "node:os";
|
|
10131
|
-
import { dirname as
|
|
10679
|
+
import { dirname as dirname6, isAbsolute as isAbsolute16, join as join4, relative as relative16, resolve as resolve17, sep as sep3 } from "node:path";
|
|
10132
10680
|
var API_VERSION23 = "^0.1.10";
|
|
10133
10681
|
var state29 = {
|
|
10134
10682
|
/** Total PreToolUse invocations. */
|
|
@@ -10166,22 +10714,22 @@ var LINTER_PACKAGES = {
|
|
|
10166
10714
|
biome: "@biomejs/biome",
|
|
10167
10715
|
eslint: "eslint"
|
|
10168
10716
|
};
|
|
10169
|
-
var linterCache =
|
|
10170
|
-
function
|
|
10171
|
-
const rel =
|
|
10172
|
-
return rel === "" || !rel.startsWith(`..${
|
|
10717
|
+
var linterCache = new BoundedMap({ max: 32, ttlMs: 3e5 });
|
|
10718
|
+
function isInside2(parent, candidate) {
|
|
10719
|
+
const rel = relative16(parent, candidate);
|
|
10720
|
+
return rel === "" || !rel.startsWith(`..${sep3}`) && rel !== ".." && !isAbsolute16(rel);
|
|
10173
10721
|
}
|
|
10174
10722
|
function resolveLocalLinter(name, cwd) {
|
|
10175
10723
|
try {
|
|
10176
10724
|
const packageName = LINTER_PACKAGES[name];
|
|
10177
|
-
const requireFromProject =
|
|
10725
|
+
const requireFromProject = createRequire2(resolve17(cwd, "package.json"));
|
|
10178
10726
|
const packagePath = requireFromProject.resolve(`${packageName}/package.json`);
|
|
10179
|
-
const packageJson = JSON.parse(
|
|
10727
|
+
const packageJson = JSON.parse(readFileSync9(packagePath, "utf-8"));
|
|
10180
10728
|
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 (!
|
|
10729
|
+
if (!relativeBin || isAbsolute16(relativeBin)) return null;
|
|
10730
|
+
const packageDir = dirname6(packagePath);
|
|
10731
|
+
const entry = resolve17(packageDir, relativeBin);
|
|
10732
|
+
if (!isInside2(packageDir, entry)) return null;
|
|
10185
10733
|
return {
|
|
10186
10734
|
cmd: process.execPath,
|
|
10187
10735
|
args: name === "biome" ? [entry, "check", "--reporter=json"] : [entry, "--format=json"],
|
|
@@ -10232,8 +10780,8 @@ async function detectLinter(requested, cwd) {
|
|
|
10232
10780
|
}
|
|
10233
10781
|
async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
10234
10782
|
const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
|
|
10235
|
-
const tmpDir = await mkdtemp(
|
|
10236
|
-
const tmpFile =
|
|
10783
|
+
const tmpDir = await mkdtemp(join4(tmpdir(), "lint-gate-"));
|
|
10784
|
+
const tmpFile = join4(tmpDir, `input${ext}`);
|
|
10237
10785
|
try {
|
|
10238
10786
|
await writeFile2(tmpFile, content, "utf-8");
|
|
10239
10787
|
const fullArgs = [...linter.args, tmpFile];
|
|
@@ -10250,14 +10798,14 @@ async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
|
10250
10798
|
}
|
|
10251
10799
|
async function lintAndFix(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
10252
10800
|
const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".")) : ".ts";
|
|
10253
|
-
const tmpDir = await mkdtemp(
|
|
10254
|
-
const tmpFile =
|
|
10801
|
+
const tmpDir = await mkdtemp(join4(tmpdir(), "lint-gate-fix-"));
|
|
10802
|
+
const tmpFile = join4(tmpDir, `input${ext}`);
|
|
10255
10803
|
try {
|
|
10256
10804
|
await writeFile2(tmpFile, content, "utf-8");
|
|
10257
10805
|
const fixArgs = linter.name === "biome" ? [linter.args[0], "check", "--write", tmpFile] : [linter.args[0], "--fix", tmpFile];
|
|
10258
10806
|
await runCommand2(linter.cmd, fixArgs, timeoutMs, cwd, signal);
|
|
10259
10807
|
if (signal.aborted) throw signal.reason;
|
|
10260
|
-
return await
|
|
10808
|
+
return await readFile10(tmpFile, "utf-8");
|
|
10261
10809
|
} catch {
|
|
10262
10810
|
if (signal.aborted) throw signal.reason;
|
|
10263
10811
|
return content;
|
|
@@ -10353,11 +10901,11 @@ var plugin32 = {
|
|
|
10353
10901
|
state29.hitCount = 0;
|
|
10354
10902
|
state29.fixCount = 0;
|
|
10355
10903
|
state29.linterErrorCount = 0;
|
|
10356
|
-
state29.hookUnregister =
|
|
10904
|
+
state29.hookUnregister = releaseHandle(state29.hookUnregister);
|
|
10357
10905
|
state29.lastResult = null;
|
|
10358
10906
|
linterCache.clear();
|
|
10359
10907
|
const cfg = readConfig27(api.config.extensions?.["lint-gate"]);
|
|
10360
|
-
const cwd =
|
|
10908
|
+
const cwd = resolve17(api.config.cwd ?? process.cwd());
|
|
10361
10909
|
const linterReady = detectLinter(cfg.linter, cwd).then((linter) => {
|
|
10362
10910
|
if (!linter) {
|
|
10363
10911
|
api.log.warn("lint-gate: no linter found (biome or eslint) \u2014 hook will be a no-op", {
|
|
@@ -10386,7 +10934,7 @@ var plugin32 = {
|
|
|
10386
10934
|
const newStr = inp["new_string"];
|
|
10387
10935
|
if (typeof oldStr !== "string" || typeof newStr !== "string") return;
|
|
10388
10936
|
try {
|
|
10389
|
-
const current = await
|
|
10937
|
+
const current = await readFile10(filePath, "utf-8");
|
|
10390
10938
|
content = applyEdit(current, oldStr, newStr);
|
|
10391
10939
|
} catch {
|
|
10392
10940
|
return;
|
|
@@ -10591,7 +11139,7 @@ ${summary}${truncated}`
|
|
|
10591
11139
|
var lint_gate_default = plugin32;
|
|
10592
11140
|
|
|
10593
11141
|
// src/llm-cache/index.ts
|
|
10594
|
-
import { createHash } from "node:crypto";
|
|
11142
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
10595
11143
|
var state30 = {
|
|
10596
11144
|
cache: /* @__PURE__ */ new Map(),
|
|
10597
11145
|
hits: 0,
|
|
@@ -10641,7 +11189,7 @@ function fingerprintRequest(request) {
|
|
|
10641
11189
|
topK: request["topK"] ?? null,
|
|
10642
11190
|
topP: request["topP"] ?? null
|
|
10643
11191
|
};
|
|
10644
|
-
const fingerprint2 =
|
|
11192
|
+
const fingerprint2 = createHash2("sha256").update(JSON.stringify(subset)).digest("hex");
|
|
10645
11193
|
fingerprintCache.set(request, fingerprint2);
|
|
10646
11194
|
return fingerprint2;
|
|
10647
11195
|
}
|
|
@@ -10920,16 +11468,26 @@ function canonicalize(value) {
|
|
|
10920
11468
|
return String(value);
|
|
10921
11469
|
}
|
|
10922
11470
|
}
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
if (value
|
|
11471
|
+
var CANONICALIZE_MAX_DEPTH = 12;
|
|
11472
|
+
function sortKeys(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
11473
|
+
if (value === null || typeof value !== "object") return value;
|
|
11474
|
+
if (seen.has(value)) return "[circular]";
|
|
11475
|
+
if (depth >= CANONICALIZE_MAX_DEPTH) {
|
|
11476
|
+
return Array.isArray(value) ? `[array:${value.length}]` : "[deep-object]";
|
|
11477
|
+
}
|
|
11478
|
+
seen.add(value);
|
|
11479
|
+
try {
|
|
11480
|
+
if (Array.isArray(value)) {
|
|
11481
|
+
return value.map((v) => sortKeys(v, depth + 1, seen));
|
|
11482
|
+
}
|
|
10926
11483
|
const out = {};
|
|
10927
11484
|
for (const key of Object.keys(value).sort()) {
|
|
10928
|
-
out[key] = sortKeys(value[key]);
|
|
11485
|
+
out[key] = sortKeys(value[key], depth + 1, seen);
|
|
10929
11486
|
}
|
|
10930
11487
|
return out;
|
|
11488
|
+
} finally {
|
|
11489
|
+
seen.delete(value);
|
|
10931
11490
|
}
|
|
10932
|
-
return value;
|
|
10933
11491
|
}
|
|
10934
11492
|
function fingerprint(toolName, toolInput) {
|
|
10935
11493
|
return `${toolName}\0${canonicalize(toolInput)}`;
|
|
@@ -10955,7 +11513,7 @@ function hashString2(value) {
|
|
|
10955
11513
|
}
|
|
10956
11514
|
async function gitDiffFingerprint(cwd, signal) {
|
|
10957
11515
|
try {
|
|
10958
|
-
const diff = await new Promise((
|
|
11516
|
+
const diff = await new Promise((resolve28, reject) => {
|
|
10959
11517
|
execFile9(
|
|
10960
11518
|
"git",
|
|
10961
11519
|
["diff", "--no-ext-diff", "--"],
|
|
@@ -10972,7 +11530,7 @@ async function gitDiffFingerprint(cwd, signal) {
|
|
|
10972
11530
|
},
|
|
10973
11531
|
(error, stdout) => {
|
|
10974
11532
|
if (error) reject(error);
|
|
10975
|
-
else
|
|
11533
|
+
else resolve28(stdout);
|
|
10976
11534
|
}
|
|
10977
11535
|
);
|
|
10978
11536
|
});
|
|
@@ -11322,7 +11880,7 @@ var plugin34 = {
|
|
|
11322
11880
|
var loop_breaker_default = plugin34;
|
|
11323
11881
|
|
|
11324
11882
|
// src/migration-planner/index.ts
|
|
11325
|
-
import { existsSync as existsSync4, readFileSync as
|
|
11883
|
+
import { existsSync as existsSync4, readFileSync as readFileSync10 } from "node:fs";
|
|
11326
11884
|
var API_VERSION24 = "^0.1.10";
|
|
11327
11885
|
var state32 = {
|
|
11328
11886
|
plansGenerated: 0,
|
|
@@ -11362,7 +11920,7 @@ function readChangelog(packageName, cfg) {
|
|
|
11362
11920
|
if (!withinProject(candidate)) continue;
|
|
11363
11921
|
if (existsSync4(candidate)) {
|
|
11364
11922
|
try {
|
|
11365
|
-
const content =
|
|
11923
|
+
const content = readFileSync10(candidate, "utf-8");
|
|
11366
11924
|
return { source: candidate, content: content.slice(0, cfg.maxChars) };
|
|
11367
11925
|
} catch {
|
|
11368
11926
|
}
|
|
@@ -11570,7 +12128,7 @@ var plugin35 = {
|
|
|
11570
12128
|
state32.llmAnalysisCount = 0;
|
|
11571
12129
|
state32.llmFallbackCount = 0;
|
|
11572
12130
|
state32.lastPlan = null;
|
|
11573
|
-
state32.hookUnregister =
|
|
12131
|
+
state32.hookUnregister = releaseHandle(state32.hookUnregister);
|
|
11574
12132
|
const cfg = readConfig30(api.config.extensions?.["migration-planner"]);
|
|
11575
12133
|
const hook = (input) => {
|
|
11576
12134
|
if (!cfg.enabled) return;
|
|
@@ -12189,13 +12747,21 @@ async function deliver(event, payload) {
|
|
|
12189
12747
|
}
|
|
12190
12748
|
const result = await deliverViaChannel(ch, event, {
|
|
12191
12749
|
title: typeof payload.title === "string" ? payload.title : event,
|
|
12192
|
-
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error :
|
|
12750
|
+
body: typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : safeJsonStringify(payload),
|
|
12193
12751
|
level: event === "tool.error" || event === "budget.threshold" ? "warning" : "info",
|
|
12194
12752
|
source: event,
|
|
12195
12753
|
metadata: payload
|
|
12196
12754
|
});
|
|
12197
12755
|
return result.ok;
|
|
12198
12756
|
}
|
|
12757
|
+
function deliverDetached(event, payload) {
|
|
12758
|
+
deliver(event, payload).catch((err) => {
|
|
12759
|
+
_pluginLog?.warn("notify-hub: notification delivery failed", {
|
|
12760
|
+
event,
|
|
12761
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12762
|
+
});
|
|
12763
|
+
});
|
|
12764
|
+
}
|
|
12199
12765
|
async function deliverViaChannel(ch, event, msg) {
|
|
12200
12766
|
const result = await ch.deliver(msg);
|
|
12201
12767
|
if (result.ok) {
|
|
@@ -12304,7 +12870,7 @@ var plugin37 = {
|
|
|
12304
12870
|
}
|
|
12305
12871
|
if (active && cfg.events.includes("session.stop")) {
|
|
12306
12872
|
const stopHook = (input) => {
|
|
12307
|
-
|
|
12873
|
+
deliverDetached("session.stop", {
|
|
12308
12874
|
sessionId: input.sessionId ?? null,
|
|
12309
12875
|
cwd: input.cwd ?? null
|
|
12310
12876
|
});
|
|
@@ -12315,7 +12881,7 @@ var plugin37 = {
|
|
|
12315
12881
|
const off = api.onPattern("tool.*", (eventName, payload) => {
|
|
12316
12882
|
if (!/error|failed/.test(eventName)) return;
|
|
12317
12883
|
const p = payload;
|
|
12318
|
-
|
|
12884
|
+
deliverDetached("tool.error", {
|
|
12319
12885
|
tool: p?.tool ?? p?.name ?? "unknown",
|
|
12320
12886
|
busEvent: eventName,
|
|
12321
12887
|
error: truncateText(
|
|
@@ -12329,7 +12895,7 @@ var plugin37 = {
|
|
|
12329
12895
|
if (active && cfg.events.includes("budget.threshold")) {
|
|
12330
12896
|
const off = api.onPattern("budget.*", (eventName, payload) => {
|
|
12331
12897
|
if (!eventName.includes("threshold")) return;
|
|
12332
|
-
|
|
12898
|
+
deliverDetached("budget.threshold", { busEvent: eventName, detail: payload });
|
|
12333
12899
|
});
|
|
12334
12900
|
state34.eventUnsubscribers.push(off);
|
|
12335
12901
|
}
|
|
@@ -12692,8 +13258,8 @@ var plugin38 = {
|
|
|
12692
13258
|
var path_guard_default = plugin38;
|
|
12693
13259
|
|
|
12694
13260
|
// src/performance-regression-gate/index.ts
|
|
12695
|
-
import { existsSync as existsSync5, readFileSync as
|
|
12696
|
-
import { isAbsolute as
|
|
13261
|
+
import { existsSync as existsSync5, readFileSync as readFileSync11 } from "node:fs";
|
|
13262
|
+
import { isAbsolute as isAbsolute17, relative as relative17, resolve as resolve18 } from "node:path";
|
|
12697
13263
|
var API_VERSION25 = "^0.1.10";
|
|
12698
13264
|
var state36 = {
|
|
12699
13265
|
invocationCount: 0,
|
|
@@ -12718,18 +13284,18 @@ function readConfig34(raw) {
|
|
|
12718
13284
|
}
|
|
12719
13285
|
function withinProject4(p, cwd = process.cwd()) {
|
|
12720
13286
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
12721
|
-
const root =
|
|
12722
|
-
const resolved =
|
|
12723
|
-
const rel =
|
|
13287
|
+
const root = resolve18(cwd);
|
|
13288
|
+
const resolved = isAbsolute17(p) ? resolve18(p) : resolve18(root, p);
|
|
13289
|
+
const rel = relative17(root, resolved);
|
|
12724
13290
|
if (rel === "" || rel === ".") return true;
|
|
12725
13291
|
if (rel.startsWith("..")) return false;
|
|
12726
|
-
if (
|
|
13292
|
+
if (isAbsolute17(rel)) return false;
|
|
12727
13293
|
return true;
|
|
12728
13294
|
}
|
|
12729
13295
|
function resolveProjectPath6(rawPath, cwd = process.cwd()) {
|
|
12730
13296
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
12731
|
-
const root =
|
|
12732
|
-
const resolved =
|
|
13297
|
+
const root = resolve18(cwd);
|
|
13298
|
+
const resolved = isAbsolute17(rawPath) ? resolve18(rawPath) : resolve18(root, rawPath);
|
|
12733
13299
|
if (!withinProject4(resolved, cwd)) return null;
|
|
12734
13300
|
return resolved;
|
|
12735
13301
|
}
|
|
@@ -12760,7 +13326,7 @@ function flattenResults(results) {
|
|
|
12760
13326
|
function loadResults(path) {
|
|
12761
13327
|
if (!path || !existsSync5(path)) return null;
|
|
12762
13328
|
try {
|
|
12763
|
-
const raw = JSON.parse(
|
|
13329
|
+
const raw = JSON.parse(readFileSync11(path, "utf-8"));
|
|
12764
13330
|
return raw;
|
|
12765
13331
|
} catch {
|
|
12766
13332
|
return null;
|
|
@@ -13144,7 +13710,7 @@ var plugin_stack_observer_default = PLUGIN;
|
|
|
13144
13710
|
// src/pr-drafter/index.ts
|
|
13145
13711
|
import { execFile as execFile10 } from "node:child_process";
|
|
13146
13712
|
import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
|
|
13147
|
-
import { dirname as
|
|
13713
|
+
import { dirname as dirname7, isAbsolute as isAbsolute18, relative as relative18, resolve as resolve19 } from "node:path";
|
|
13148
13714
|
var API_VERSION26 = "^0.1.10";
|
|
13149
13715
|
var state38 = {
|
|
13150
13716
|
commits: [],
|
|
@@ -13183,10 +13749,10 @@ function readConfig36(raw) {
|
|
|
13183
13749
|
}
|
|
13184
13750
|
function resolveProjectPath7(rawPath, cwd = process.cwd()) {
|
|
13185
13751
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
13186
|
-
const root =
|
|
13187
|
-
const resolved =
|
|
13188
|
-
const rel =
|
|
13189
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
13752
|
+
const root = resolve19(cwd);
|
|
13753
|
+
const resolved = isAbsolute18(rawPath) ? resolve19(rawPath) : resolve19(root, rawPath);
|
|
13754
|
+
const rel = relative18(root, resolved);
|
|
13755
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute18(rel)) return resolved;
|
|
13190
13756
|
return null;
|
|
13191
13757
|
}
|
|
13192
13758
|
function runGit4(args, timeout) {
|
|
@@ -13272,7 +13838,7 @@ async function writeDraft(cfg, llm) {
|
|
|
13272
13838
|
}
|
|
13273
13839
|
const draft = await buildDraft(cfg, llm);
|
|
13274
13840
|
try {
|
|
13275
|
-
await mkdir2(
|
|
13841
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
13276
13842
|
await writeFile3(resolved, draft.body);
|
|
13277
13843
|
state38.draftsWritten += 1;
|
|
13278
13844
|
} catch {
|
|
@@ -13336,7 +13902,7 @@ var plugin40 = {
|
|
|
13336
13902
|
state38.draftsWritten = 0;
|
|
13337
13903
|
state38.draftErrors = 0;
|
|
13338
13904
|
state38.stopInvocations = 0;
|
|
13339
|
-
state38.stopHookUnregister =
|
|
13905
|
+
state38.stopHookUnregister = releaseHandle(state38.stopHookUnregister);
|
|
13340
13906
|
for (const off of state38.eventUnsubscribers) {
|
|
13341
13907
|
try {
|
|
13342
13908
|
off();
|
|
@@ -13399,7 +13965,7 @@ var plugin40 = {
|
|
|
13399
13965
|
const resolved = resolveProjectPath7(cfg.outputPath);
|
|
13400
13966
|
if (!resolved) return { ok: false, error: "outputPath resolves outside project" };
|
|
13401
13967
|
try {
|
|
13402
|
-
await mkdir2(
|
|
13968
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
13403
13969
|
await writeFile3(resolved, draft.body);
|
|
13404
13970
|
state38.draftsWritten += 1;
|
|
13405
13971
|
return {
|
|
@@ -13620,26 +14186,155 @@ var plugin41 = {
|
|
|
13620
14186
|
};
|
|
13621
14187
|
var process_guard_default = plugin41;
|
|
13622
14188
|
|
|
14189
|
+
// src/runtime/credential-patterns.ts
|
|
14190
|
+
var CREDENTIAL_PATTERNS = [
|
|
14191
|
+
// LLM provider keys
|
|
14192
|
+
{
|
|
14193
|
+
type: "anthropic_key",
|
|
14194
|
+
regex: /(?<![A-Za-z0-9])sk-ant-api\d+-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g
|
|
14195
|
+
},
|
|
14196
|
+
{ type: "openai_key", regex: /(?<![A-Za-z0-9])sk-(?!ant)(?:proj-)?[A-Za-z0-9_-]{20,}(?![A-Za-z0-9])/g },
|
|
14197
|
+
// GitHub. `ghp_` is only the personal-access-token prefix — the OAuth
|
|
14198
|
+
// (`gho_`), user-to-server (`ghu_`), server-to-server (`ghs_`) and
|
|
14199
|
+
// refresh (`ghr_`) tokens grant the same or broader access and were
|
|
14200
|
+
// previously not detected at all.
|
|
14201
|
+
{ type: "github_pat", regex: /(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g },
|
|
14202
|
+
{
|
|
14203
|
+
type: "github_oauth_token",
|
|
14204
|
+
regex: /(?<![A-Za-z0-9])gh[ousr]_[A-Za-z0-9]{36,}(?![A-Za-z0-9])/g
|
|
14205
|
+
},
|
|
14206
|
+
{ type: "github_pat_v2", regex: /(?<![A-Za-z0-9])github_pat_[A-Za-z0-9_]{50,}(?![A-Za-z0-9])/g },
|
|
14207
|
+
// GitLab
|
|
14208
|
+
{ type: "gitlab_pat", regex: /(?<![A-Za-z0-9])glpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14209
|
+
{
|
|
14210
|
+
type: "gitlab_runner_token",
|
|
14211
|
+
regex: /(?<![A-Za-z0-9])glrt-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14212
|
+
},
|
|
14213
|
+
// npm — a leaked publish token is a supply-chain compromise.
|
|
14214
|
+
{ type: "npm_token", regex: /(?<![A-Za-z0-9])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g },
|
|
14215
|
+
// AWS
|
|
14216
|
+
{ type: "aws_access_key", regex: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{16}(?![A-Za-z0-9])/g },
|
|
14217
|
+
// GCP
|
|
14218
|
+
{ type: "gcp_key", regex: /(?<![A-Za-z0-9])AIza[0-9A-Za-z_-]{35}(?![A-Za-z0-9])/g },
|
|
14219
|
+
// Slack. `xoxe` (token-rotation) and `xapp` (app-level) were missing;
|
|
14220
|
+
// both are as sensitive as the bot/user tokens already covered.
|
|
14221
|
+
{
|
|
14222
|
+
type: "slack_token",
|
|
14223
|
+
regex: /(?<![A-Za-z0-9-])xox[abposer]-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g
|
|
14224
|
+
},
|
|
14225
|
+
{ type: "slack_app_token", regex: /(?<![A-Za-z0-9-])xapp-\d-[A-Za-z0-9-]{10,}(?![A-Za-z0-9-])/g },
|
|
14226
|
+
{
|
|
14227
|
+
type: "slack_webhook",
|
|
14228
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9_-]+\/B[A-Za-z0-9_-]+\/[A-Za-z0-9]{16,}/g
|
|
14229
|
+
},
|
|
14230
|
+
// Stripe
|
|
14231
|
+
{
|
|
14232
|
+
type: "stripe_key",
|
|
14233
|
+
regex: /(?<![A-Za-z0-9])sk_(?:live|test)_[A-Za-z0-9]{24,}(?![A-Za-z0-9])/g
|
|
14234
|
+
},
|
|
14235
|
+
// Twilio
|
|
14236
|
+
{ type: "twilio_sid", regex: /(?<![A-Za-z0-9])AC[a-f0-9]{32}(?![A-Za-z0-9])/g },
|
|
14237
|
+
// Telegram
|
|
14238
|
+
{
|
|
14239
|
+
type: "telegram_bot_token",
|
|
14240
|
+
regex: /(?:(?<![A-Za-z0-9_])|(?<=(?:^|[^A-Za-z0-9_])bot))\d+:[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14241
|
+
},
|
|
14242
|
+
// JWT
|
|
14243
|
+
{
|
|
14244
|
+
type: "jwt",
|
|
14245
|
+
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
|
|
14246
|
+
},
|
|
14247
|
+
// Private keys
|
|
14248
|
+
{
|
|
14249
|
+
type: "private_key",
|
|
14250
|
+
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
|
|
14251
|
+
},
|
|
14252
|
+
// AI/ML provider tokens
|
|
14253
|
+
{ type: "huggingface_token", regex: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])/g },
|
|
14254
|
+
{ type: "replicate_token", regex: /(?<![A-Za-z0-9])r8_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14255
|
+
{ type: "perplexity_key", regex: /(?<![A-Za-z0-9])pplx-[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14256
|
+
{ type: "groq_key", regex: /(?<![A-Za-z0-9])gsk_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14257
|
+
// SaaS / infrastructure tokens — each grants API access on the user's
|
|
14258
|
+
// account, and each was previously invisible to this gate.
|
|
14259
|
+
{ type: "sendgrid_key", regex: /(?<![A-Za-z0-9])SG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14260
|
+
{ type: "digitalocean_token", regex: /(?<![A-Za-z0-9])dop_v1_[a-f0-9]{64}(?![A-Za-z0-9])/g },
|
|
14261
|
+
{ type: "doppler_token", regex: /(?<![A-Za-z0-9])dp\.(?:pt|st|sa|scim|audit)\.[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14262
|
+
{ type: "shopify_token", regex: /(?<![A-Za-z0-9])shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}(?![A-Za-z0-9])/g },
|
|
14263
|
+
{ type: "docker_pat", regex: /(?<![A-Za-z0-9])dckr_pat_[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14264
|
+
{ type: "linear_key", regex: /(?<![A-Za-z0-9])lin_api_[A-Za-z0-9]{40,}(?![A-Za-z0-9])/g },
|
|
14265
|
+
{ type: "atlassian_token", regex: /(?<![A-Za-z0-9])ATATT3[A-Za-z0-9_\-=]{40,}(?![A-Za-z0-9_\-=])/g },
|
|
14266
|
+
{ type: "square_token", regex: /(?<![A-Za-z0-9])(?:sq0(?:atp|csp)-|EAAA)[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g },
|
|
14267
|
+
{
|
|
14268
|
+
type: "azure_storage_key",
|
|
14269
|
+
regex: /AccountKey=[A-Za-z0-9+/]{80,}={0,2}/g
|
|
14270
|
+
},
|
|
14271
|
+
{
|
|
14272
|
+
type: "google_oauth_client_secret",
|
|
14273
|
+
regex: /(?<![A-Za-z0-9_-])GOCSPX-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
|
|
14274
|
+
},
|
|
14275
|
+
// Bearer tokens
|
|
14276
|
+
{
|
|
14277
|
+
type: "bearer_token",
|
|
14278
|
+
regex: /(?<![A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{12,512}=*(?![A-Za-z0-9._~+/-])/g
|
|
14279
|
+
},
|
|
14280
|
+
// Database URIs. Require password-bearing user-info; credential-free values stay scannable.
|
|
14281
|
+
{ type: "mongodb_uri", regex: /mongodb(?:\+srv)?:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
14282
|
+
{
|
|
14283
|
+
type: "postgres_uri",
|
|
14284
|
+
// Query parsers decode percent-encoded parameter names. Recognize each
|
|
14285
|
+
// encoded character in `password` so mixed forms such as `pass%77ord`
|
|
14286
|
+
// cannot bypass detection while keeping the scan strictly bounded.
|
|
14287
|
+
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
|
|
14288
|
+
},
|
|
14289
|
+
{ type: "mysql_uri", regex: /mysql:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g },
|
|
14290
|
+
{ type: "redis_uri", regex: /redis:\/\/[^\s:/@"'`]*:[^\s/@"'`]+@[^\s"'`]+/g }
|
|
14291
|
+
];
|
|
14292
|
+
function cloneCredentialPatterns() {
|
|
14293
|
+
return CREDENTIAL_PATTERNS.map((p) => ({
|
|
14294
|
+
type: p.type,
|
|
14295
|
+
regex: new RegExp(p.regex.source, p.regex.flags)
|
|
14296
|
+
}));
|
|
14297
|
+
}
|
|
14298
|
+
|
|
13623
14299
|
// src/prompt-firewall/index.ts
|
|
13624
|
-
var
|
|
13625
|
-
|
|
14300
|
+
var KIND_ALIASES = {
|
|
14301
|
+
aws_access_key: "aws-access-key",
|
|
14302
|
+
private_key: "private-key-block",
|
|
14303
|
+
github_pat: "github-token",
|
|
14304
|
+
github_oauth_token: "github-token",
|
|
14305
|
+
openai_key: "openai-key",
|
|
14306
|
+
anthropic_key: "anthropic-key",
|
|
14307
|
+
slack_token: "slack-token",
|
|
14308
|
+
gcp_key: "google-api-key",
|
|
14309
|
+
bearer_token: "bearer-token"
|
|
14310
|
+
};
|
|
14311
|
+
var EXTRA_PATTERNS = [
|
|
13626
14312
|
{
|
|
14313
|
+
// AWS secret access keys have no prefix — only a 40-char base64-ish
|
|
14314
|
+
// shape — so they need a nearby `aws`/`secret` mention to be worth
|
|
14315
|
+
// acting on.
|
|
14316
|
+
//
|
|
14317
|
+
// The previous spelling required the word "aws" to appear AFTER the
|
|
14318
|
+
// key and wrapped the run in `\b`. Both are wrong: the real layout is
|
|
14319
|
+
// `AWS_SECRET_ACCESS_KEY=<key>` (context first), and a `\b` cannot
|
|
14320
|
+
// hold next to the `+` or `/` that base64 keys routinely end with. The
|
|
14321
|
+
// pattern therefore never fired on a real key. Anchor on the context
|
|
14322
|
+
// token instead and let the key follow it.
|
|
13627
14323
|
kind: "aws-secret-key",
|
|
13628
|
-
re:
|
|
14324
|
+
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
14325
|
},
|
|
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
14326
|
{
|
|
13639
14327
|
kind: "generic-secret-assignment",
|
|
13640
14328
|
re: /\b(?:api[_-]?key|secret|password|passwd|token)\s*[:=]\s*['"]?[A-Za-z0-9._/+-]{12,}['"]?/gi
|
|
13641
14329
|
}
|
|
13642
14330
|
];
|
|
14331
|
+
var PATTERNS2 = [
|
|
14332
|
+
...cloneCredentialPatterns().map((p) => ({
|
|
14333
|
+
kind: KIND_ALIASES[p.type] ?? p.type,
|
|
14334
|
+
re: p.regex
|
|
14335
|
+
})),
|
|
14336
|
+
...EXTRA_PATTERNS
|
|
14337
|
+
];
|
|
13643
14338
|
function detectSecrets(text, allow) {
|
|
13644
14339
|
const counts = /* @__PURE__ */ new Map();
|
|
13645
14340
|
for (const p of PATTERNS2) {
|
|
@@ -13915,9 +14610,10 @@ var plugin42 = {
|
|
|
13915
14610
|
var prompt_firewall_default = plugin42;
|
|
13916
14611
|
|
|
13917
14612
|
// src/refactor-suggester/index.ts
|
|
13918
|
-
import { readFile as
|
|
13919
|
-
import { isAbsolute as
|
|
14613
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
14614
|
+
import { isAbsolute as isAbsolute19, relative as relative19, resolve as resolve20 } from "node:path";
|
|
13920
14615
|
var API_VERSION27 = "^0.1.10";
|
|
14616
|
+
var HOOK_WARNING_COOLDOWN_MS2 = 6e4;
|
|
13921
14617
|
var state41 = {
|
|
13922
14618
|
scanCount: 0,
|
|
13923
14619
|
suggestionCount: 0,
|
|
@@ -13925,7 +14621,7 @@ var state41 = {
|
|
|
13925
14621
|
warningCount: 0,
|
|
13926
14622
|
errorCount: 0,
|
|
13927
14623
|
hookUnregister: null,
|
|
13928
|
-
lastHookWarning:
|
|
14624
|
+
lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS2 })
|
|
13929
14625
|
};
|
|
13930
14626
|
var DEFAULTS36 = {
|
|
13931
14627
|
enabled: false,
|
|
@@ -13959,7 +14655,7 @@ function toPosix6(p) {
|
|
|
13959
14655
|
return p.replace(/\\/g, "/");
|
|
13960
14656
|
}
|
|
13961
14657
|
function relativePath6(p) {
|
|
13962
|
-
return toPosix6(
|
|
14658
|
+
return toPosix6(relative19(process.cwd(), p));
|
|
13963
14659
|
}
|
|
13964
14660
|
function leadingIndentLevel(line) {
|
|
13965
14661
|
const leading = line.match(/^(\s*)/)?.[1] ?? "";
|
|
@@ -14046,19 +14742,30 @@ function detectSmells(filePath, content, rules) {
|
|
|
14046
14742
|
}
|
|
14047
14743
|
async function scanPath4(rawPath, cfg) {
|
|
14048
14744
|
const root = process.cwd();
|
|
14049
|
-
const resolved =
|
|
14745
|
+
const resolved = isAbsolute19(rawPath) ? resolve20(rawPath) : resolve20(root, rawPath);
|
|
14050
14746
|
const exts = normalizeExtensions5(cfg.extensions);
|
|
14051
14747
|
const files = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
14052
14748
|
const suggestions = [];
|
|
14749
|
+
let scannedFiles = 0;
|
|
14750
|
+
let truncated = false;
|
|
14053
14751
|
for (const p of files) {
|
|
14054
14752
|
try {
|
|
14055
|
-
const content = await
|
|
14753
|
+
const content = await readFile11(p, "utf-8");
|
|
14754
|
+
scannedFiles += 1;
|
|
14056
14755
|
suggestions.push(...detectSmells(p, content, cfg.rules));
|
|
14057
|
-
if (suggestions.length >= cfg.maxSuggestions)
|
|
14756
|
+
if (suggestions.length >= cfg.maxSuggestions) {
|
|
14757
|
+
truncated = scannedFiles < files.length;
|
|
14758
|
+
break;
|
|
14759
|
+
}
|
|
14058
14760
|
} catch {
|
|
14059
14761
|
}
|
|
14060
14762
|
}
|
|
14061
|
-
return {
|
|
14763
|
+
return {
|
|
14764
|
+
suggestions: suggestions.slice(0, cfg.maxSuggestions),
|
|
14765
|
+
scannedFiles,
|
|
14766
|
+
discoveredFiles: files.length,
|
|
14767
|
+
truncated
|
|
14768
|
+
};
|
|
14062
14769
|
}
|
|
14063
14770
|
var plugin43 = {
|
|
14064
14771
|
name: "refactor-suggester",
|
|
@@ -14121,11 +14828,11 @@ var plugin43 = {
|
|
|
14121
14828
|
state41.hookInvocationCount += 1;
|
|
14122
14829
|
const now = Date.now();
|
|
14123
14830
|
const lastWarning = state41.lastHookWarning.get(sourcePath);
|
|
14124
|
-
if (lastWarning !== void 0 && now - lastWarning <
|
|
14125
|
-
const resolved =
|
|
14831
|
+
if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS2) return;
|
|
14832
|
+
const resolved = resolve20(process.cwd(), sourcePath);
|
|
14126
14833
|
let content;
|
|
14127
14834
|
try {
|
|
14128
|
-
content = await
|
|
14835
|
+
content = await readFile11(resolved, "utf-8");
|
|
14129
14836
|
} catch {
|
|
14130
14837
|
state41.errorCount += 1;
|
|
14131
14838
|
return;
|
|
@@ -14169,8 +14876,12 @@ var plugin43 = {
|
|
|
14169
14876
|
state41.suggestionCount += result.suggestions.length;
|
|
14170
14877
|
return {
|
|
14171
14878
|
ok: true,
|
|
14172
|
-
path: relativePath6(
|
|
14879
|
+
path: relativePath6(resolve20(process.cwd(), rawPath)),
|
|
14173
14880
|
scannedFiles: result.scannedFiles,
|
|
14881
|
+
discoveredFiles: result.discoveredFiles,
|
|
14882
|
+
// Say so when the cap stopped the walk early: a partial scan
|
|
14883
|
+
// that reports few findings must not read as a clean result.
|
|
14884
|
+
truncated: result.truncated,
|
|
14174
14885
|
suggestions: result.suggestions,
|
|
14175
14886
|
rules: cfg.rules
|
|
14176
14887
|
};
|
|
@@ -14579,7 +15290,7 @@ var plugin44 = {
|
|
|
14579
15290
|
var release_notes_generator_default = plugin44;
|
|
14580
15291
|
|
|
14581
15292
|
// src/schema-evolution-guard/index.ts
|
|
14582
|
-
import { readFileSync as
|
|
15293
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
14583
15294
|
import { basename as basename5 } from "node:path";
|
|
14584
15295
|
var API_VERSION29 = "^0.1.10";
|
|
14585
15296
|
var state43 = {
|
|
@@ -14782,7 +15493,7 @@ var plugin45 = {
|
|
|
14782
15493
|
content = toolInput["content"];
|
|
14783
15494
|
} else if (withinProject(filePath)) {
|
|
14784
15495
|
try {
|
|
14785
|
-
content =
|
|
15496
|
+
content = readFileSync12(filePath, "utf-8");
|
|
14786
15497
|
} catch {
|
|
14787
15498
|
content = void 0;
|
|
14788
15499
|
}
|
|
@@ -14886,71 +15597,43 @@ ${body}${suffix}`;
|
|
|
14886
15597
|
var schema_evolution_guard_default = plugin45;
|
|
14887
15598
|
|
|
14888
15599
|
// 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
|
-
];
|
|
15600
|
+
var BASE_PATTERNS = cloneCredentialPatterns();
|
|
14943
15601
|
var PATTERNS3 = [...BASE_PATTERNS];
|
|
14944
15602
|
var patternCacheKey = "";
|
|
15603
|
+
var GROUP_INDEX_OF_PATTERN = [];
|
|
14945
15604
|
var COMBINED_REGEX = buildCombinedRegex(PATTERNS3);
|
|
14946
|
-
var
|
|
15605
|
+
var SCAN_WINDOW_LENGTH = 1e5;
|
|
15606
|
+
var SCAN_WINDOW_OVERLAP = 4096;
|
|
15607
|
+
var MAX_TOTAL_SCAN_LENGTH = 8 * 1024 * 1024;
|
|
15608
|
+
var TOO_LARGE_MARKER = "unscannable_oversized_input";
|
|
14947
15609
|
var RE_DOS_TIMEOUT_MS = 100;
|
|
15610
|
+
function countCaptureGroups(source) {
|
|
15611
|
+
try {
|
|
15612
|
+
return new RegExp(`${source}|`).exec("").length - 1;
|
|
15613
|
+
} catch {
|
|
15614
|
+
return 0;
|
|
15615
|
+
}
|
|
15616
|
+
}
|
|
15617
|
+
function patternTypeForGroups(groups) {
|
|
15618
|
+
for (let i = 0; i < PATTERNS3.length; i++) {
|
|
15619
|
+
const at = GROUP_INDEX_OF_PATTERN[i];
|
|
15620
|
+
if (at !== void 0 && groups[at] !== void 0) return PATTERNS3[i].type;
|
|
15621
|
+
}
|
|
15622
|
+
return void 0;
|
|
15623
|
+
}
|
|
14948
15624
|
function buildCombinedRegex(patterns) {
|
|
14949
|
-
const newCacheKey = JSON.stringify(patterns.map((p) => p.type));
|
|
15625
|
+
const newCacheKey = JSON.stringify(patterns.map((p) => [p.type, p.regex.source]));
|
|
14950
15626
|
if (newCacheKey === patternCacheKey && COMBINED_REGEX) {
|
|
14951
15627
|
return COMBINED_REGEX;
|
|
14952
15628
|
}
|
|
14953
15629
|
patternCacheKey = newCacheKey;
|
|
15630
|
+
const offsets = [];
|
|
15631
|
+
let cursor = 0;
|
|
15632
|
+
for (const p of patterns) {
|
|
15633
|
+
offsets.push(cursor);
|
|
15634
|
+
cursor += 1 + countCaptureGroups(p.regex.source);
|
|
15635
|
+
}
|
|
15636
|
+
GROUP_INDEX_OF_PATTERN = offsets;
|
|
14954
15637
|
return new RegExp(patterns.map((p) => `(${p.regex.source})`).join("|"), "g");
|
|
14955
15638
|
}
|
|
14956
15639
|
var state44 = {
|
|
@@ -14968,29 +15651,37 @@ var state44 = {
|
|
|
14968
15651
|
/** PostToolUse hook handle so teardown can unregister. */
|
|
14969
15652
|
postHookUnregister: null
|
|
14970
15653
|
};
|
|
14971
|
-
function
|
|
14972
|
-
if (!text) return [];
|
|
14973
|
-
if (text.length > RE_DOS_MAX_SCAN_LENGTH) return [];
|
|
14974
|
-
const found = /* @__PURE__ */ new Set();
|
|
15654
|
+
function scanWindow(window, found, startTime) {
|
|
14975
15655
|
COMBINED_REGEX.lastIndex = 0;
|
|
14976
15656
|
let m;
|
|
14977
|
-
|
|
14978
|
-
while ((m = COMBINED_REGEX.exec(text)) !== null) {
|
|
15657
|
+
while ((m = COMBINED_REGEX.exec(window)) !== null) {
|
|
14979
15658
|
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
14980
15659
|
throw new Error(
|
|
14981
|
-
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${
|
|
15660
|
+
`secret-scanner: ReDoS timeout \u2014 regex scan exceeded ${RE_DOS_TIMEOUT_MS}ms on ${window.length}-char window`
|
|
14982
15661
|
);
|
|
14983
15662
|
}
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
found.add(PATTERNS3[i].type);
|
|
14987
|
-
break;
|
|
14988
|
-
}
|
|
14989
|
-
}
|
|
15663
|
+
const type = patternTypeForGroups(m.slice(1));
|
|
15664
|
+
if (type !== void 0) found.add(type);
|
|
14990
15665
|
if (m.index === COMBINED_REGEX.lastIndex) {
|
|
14991
15666
|
COMBINED_REGEX.lastIndex += 1;
|
|
14992
15667
|
}
|
|
14993
15668
|
}
|
|
15669
|
+
}
|
|
15670
|
+
function findMatches(text) {
|
|
15671
|
+
if (!text) return [];
|
|
15672
|
+
const found = /* @__PURE__ */ new Set();
|
|
15673
|
+
const startTime = performance.now();
|
|
15674
|
+
if (text.length <= SCAN_WINDOW_LENGTH) {
|
|
15675
|
+
scanWindow(text, found, startTime);
|
|
15676
|
+
return Array.from(found).sort();
|
|
15677
|
+
}
|
|
15678
|
+
if (text.length > MAX_TOTAL_SCAN_LENGTH) {
|
|
15679
|
+
return [TOO_LARGE_MARKER];
|
|
15680
|
+
}
|
|
15681
|
+
const stride = SCAN_WINDOW_LENGTH - SCAN_WINDOW_OVERLAP;
|
|
15682
|
+
for (let offset = 0; offset < text.length; offset += stride) {
|
|
15683
|
+
scanWindow(text.slice(offset, offset + SCAN_WINDOW_LENGTH), found, startTime);
|
|
15684
|
+
}
|
|
14994
15685
|
return Array.from(found).sort();
|
|
14995
15686
|
}
|
|
14996
15687
|
function scanInput(input, depth = 0) {
|
|
@@ -15016,30 +15707,55 @@ function scanInput(input, depth = 0) {
|
|
|
15016
15707
|
}
|
|
15017
15708
|
return null;
|
|
15018
15709
|
}
|
|
15710
|
+
function redactString(text) {
|
|
15711
|
+
if (text.length > SCAN_WINDOW_LENGTH) {
|
|
15712
|
+
return { ok: false, reason: "oversized_input" };
|
|
15713
|
+
}
|
|
15714
|
+
const startTime = performance.now();
|
|
15715
|
+
let cursor = 0;
|
|
15716
|
+
let output = "";
|
|
15717
|
+
COMBINED_REGEX.lastIndex = 0;
|
|
15718
|
+
let match;
|
|
15719
|
+
while ((match = COMBINED_REGEX.exec(text)) !== null) {
|
|
15720
|
+
if (performance.now() - startTime > RE_DOS_TIMEOUT_MS) {
|
|
15721
|
+
return { ok: false, reason: "oversized_input" };
|
|
15722
|
+
}
|
|
15723
|
+
const type = patternTypeForGroups(match.slice(1));
|
|
15724
|
+
output += text.slice(cursor, match.index);
|
|
15725
|
+
output += `[REDACTED:${type ?? "unknown"}]`;
|
|
15726
|
+
cursor = COMBINED_REGEX.lastIndex;
|
|
15727
|
+
if (match.index === COMBINED_REGEX.lastIndex) {
|
|
15728
|
+
COMBINED_REGEX.lastIndex += 1;
|
|
15729
|
+
}
|
|
15730
|
+
}
|
|
15731
|
+
if (cursor === 0) return { ok: true, value: text };
|
|
15732
|
+
return { ok: true, value: output + text.slice(cursor) };
|
|
15733
|
+
}
|
|
15019
15734
|
function redactInput(input, depth = 0) {
|
|
15020
|
-
if (input === null || input === void 0) return input;
|
|
15021
|
-
if (depth > 50) return
|
|
15735
|
+
if (input === null || input === void 0) return { ok: true, value: input };
|
|
15736
|
+
if (depth > 50) return { ok: false, reason: "maximum_depth_exceeded" };
|
|
15022
15737
|
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
|
-
});
|
|
15738
|
+
return redactString(input);
|
|
15031
15739
|
}
|
|
15032
15740
|
if (Array.isArray(input)) {
|
|
15033
|
-
|
|
15741
|
+
const out = [];
|
|
15742
|
+
for (const item of input) {
|
|
15743
|
+
const redacted = redactInput(item, depth + 1);
|
|
15744
|
+
if (!redacted.ok) return redacted;
|
|
15745
|
+
out.push(redacted.value);
|
|
15746
|
+
}
|
|
15747
|
+
return { ok: true, value: out };
|
|
15034
15748
|
}
|
|
15035
15749
|
if (typeof input === "object") {
|
|
15036
15750
|
const out = {};
|
|
15037
15751
|
for (const [k, v] of Object.entries(input)) {
|
|
15038
|
-
|
|
15752
|
+
const redacted = redactInput(v, depth + 1);
|
|
15753
|
+
if (!redacted.ok) return redacted;
|
|
15754
|
+
out[k] = redacted.value;
|
|
15039
15755
|
}
|
|
15040
|
-
return out;
|
|
15756
|
+
return { ok: true, value: out };
|
|
15041
15757
|
}
|
|
15042
|
-
return input;
|
|
15758
|
+
return { ok: true, value: input };
|
|
15043
15759
|
}
|
|
15044
15760
|
var DEFAULTS39 = {
|
|
15045
15761
|
matcher: "bash|write|edit",
|
|
@@ -15099,20 +15815,21 @@ function buildHook(cfg, log) {
|
|
|
15099
15815
|
}
|
|
15100
15816
|
if (cfg.mode === "redact") {
|
|
15101
15817
|
const redacted = redactInput(input.toolInput);
|
|
15102
|
-
if (redacted !== null && typeof redacted === "object" && !Array.isArray(redacted)) {
|
|
15818
|
+
if (redacted.ok && redacted.value !== null && typeof redacted.value === "object" && !Array.isArray(redacted.value)) {
|
|
15103
15819
|
state44.redactCount += 1;
|
|
15104
15820
|
log.info(`[secret-scanner] redacted ${toolName} \u2014 matched: ${summary}`);
|
|
15105
15821
|
return {
|
|
15106
15822
|
decision: "allow",
|
|
15107
|
-
modifiedInput: redacted,
|
|
15823
|
+
modifiedInput: redacted.value,
|
|
15108
15824
|
additionalContext: `secret-scanner: redacted ${matched.length} credential pattern(s) from the ${toolName} arguments before execution.`
|
|
15109
15825
|
};
|
|
15110
15826
|
}
|
|
15111
15827
|
state44.blockCount += 1;
|
|
15112
15828
|
state44.lastBlock = { toolName, matchedTypes: matched, when };
|
|
15829
|
+
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
15830
|
return {
|
|
15114
15831
|
decision: "block",
|
|
15115
|
-
reason: `secret-scanner: cannot safely redact '${toolName}'
|
|
15832
|
+
reason: `secret-scanner: cannot safely redact '${toolName}' because ${detail}; refusing to run.`
|
|
15116
15833
|
};
|
|
15117
15834
|
}
|
|
15118
15835
|
state44.allowCount += 1;
|
|
@@ -15130,10 +15847,21 @@ function buildPostHook(cfg, log) {
|
|
|
15130
15847
|
const matched = findMatches(result.content);
|
|
15131
15848
|
if (matched.length === 0) return;
|
|
15132
15849
|
const toolName = input.toolName ?? "unknown";
|
|
15133
|
-
const
|
|
15850
|
+
const oversized = matched.includes(TOO_LARGE_MARKER);
|
|
15851
|
+
const credentialMatches = matched.filter((type) => type !== TOO_LARGE_MARKER);
|
|
15852
|
+
if (oversized && credentialMatches.length === 0) {
|
|
15853
|
+
log.warn(
|
|
15854
|
+
`[secret-scanner] POST-TOOL UNSCANNABLE: ${toolName} output exceeds ${MAX_TOTAL_SCAN_LENGTH} characters`
|
|
15855
|
+
);
|
|
15856
|
+
return {
|
|
15857
|
+
additionalContext: `
|
|
15858
|
+
\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.`
|
|
15859
|
+
};
|
|
15860
|
+
}
|
|
15861
|
+
const summary = credentialMatches.join(", ");
|
|
15134
15862
|
const when = (/* @__PURE__ */ new Date()).toISOString();
|
|
15135
15863
|
state44.leakCount += 1;
|
|
15136
|
-
state44.lastLeak = { toolName, matchedTypes:
|
|
15864
|
+
state44.lastLeak = { toolName, matchedTypes: credentialMatches, when };
|
|
15137
15865
|
log.warn(`[secret-scanner] POST-TOOL LEAK: ${toolName} output matched ${summary}`);
|
|
15138
15866
|
return {
|
|
15139
15867
|
additionalContext: `
|
|
@@ -15195,8 +15923,8 @@ var plugin46 = {
|
|
|
15195
15923
|
state44.leakCount = 0;
|
|
15196
15924
|
state44.lastBlock = null;
|
|
15197
15925
|
state44.lastLeak = null;
|
|
15198
|
-
state44.hookUnregister =
|
|
15199
|
-
state44.postHookUnregister =
|
|
15926
|
+
state44.hookUnregister = releaseHandle(state44.hookUnregister);
|
|
15927
|
+
state44.postHookUnregister = releaseHandle(state44.postHookUnregister);
|
|
15200
15928
|
const cfg = readConfig42(api.config.extensions?.["secret-scanner"]);
|
|
15201
15929
|
PATTERNS3 = [...BASE_PATTERNS];
|
|
15202
15930
|
for (const cp of cfg.customPatterns) {
|
|
@@ -15326,8 +16054,8 @@ var plugin46 = {
|
|
|
15326
16054
|
var secret_scanner_default = plugin46;
|
|
15327
16055
|
|
|
15328
16056
|
// src/security-hotspot-scanner/index.ts
|
|
15329
|
-
import { readdir as readdir2, readFile as
|
|
15330
|
-
import { isAbsolute as
|
|
16057
|
+
import { readdir as readdir2, readFile as readFile12, stat as stat5 } from "node:fs/promises";
|
|
16058
|
+
import { isAbsolute as isAbsolute20, relative as relative20, resolve as resolve21 } from "node:path";
|
|
15331
16059
|
var API_VERSION30 = "^0.1.10";
|
|
15332
16060
|
var state45 = {
|
|
15333
16061
|
scanCount: 0,
|
|
@@ -15337,7 +16065,7 @@ var state45 = {
|
|
|
15337
16065
|
skippedCount: 0,
|
|
15338
16066
|
blockedCount: 0,
|
|
15339
16067
|
lastResult: null,
|
|
15340
|
-
knownHotspots:
|
|
16068
|
+
knownHotspots: new BoundedSet({ max: 5e3 }),
|
|
15341
16069
|
hookUnregister: null
|
|
15342
16070
|
};
|
|
15343
16071
|
var DEFAULTS40 = {
|
|
@@ -15418,7 +16146,7 @@ function isSourceFile2(filePath, extensions) {
|
|
|
15418
16146
|
async function scanPath5(inputPath, cfg) {
|
|
15419
16147
|
const start = Date.now();
|
|
15420
16148
|
const root = process.cwd();
|
|
15421
|
-
const resolved =
|
|
16149
|
+
const resolved = isAbsolute20(inputPath) ? resolve21(inputPath) : resolve21(root, inputPath);
|
|
15422
16150
|
if (!withinProject(inputPath)) {
|
|
15423
16151
|
return {
|
|
15424
16152
|
path: inputPath,
|
|
@@ -15435,11 +16163,11 @@ async function scanPath5(inputPath, cfg) {
|
|
|
15435
16163
|
const scanFile2 = async (filePath) => {
|
|
15436
16164
|
if (!isSourceFile2(filePath, cfg.scanOnChange)) return;
|
|
15437
16165
|
try {
|
|
15438
|
-
const content = await
|
|
16166
|
+
const content = await readFile12(filePath, "utf-8");
|
|
15439
16167
|
filesScanned += 1;
|
|
15440
16168
|
const findings = scanSource(content, maxPerFile);
|
|
15441
16169
|
for (const f of findings) {
|
|
15442
|
-
allFindings.push({ ...f, snippet: `${
|
|
16170
|
+
allFindings.push({ ...f, snippet: `${relative20(root, filePath)}:${f.line}: ${f.snippet}` });
|
|
15443
16171
|
if (allFindings.length >= cfg.maxFindings) return;
|
|
15444
16172
|
}
|
|
15445
16173
|
} catch {
|
|
@@ -15454,7 +16182,7 @@ async function scanPath5(inputPath, cfg) {
|
|
|
15454
16182
|
}
|
|
15455
16183
|
for (const entry of entries) {
|
|
15456
16184
|
if (allFindings.length >= cfg.maxFindings) return;
|
|
15457
|
-
const full =
|
|
16185
|
+
const full = resolve21(dir, entry);
|
|
15458
16186
|
try {
|
|
15459
16187
|
const st = await stat5(full);
|
|
15460
16188
|
if (st.isDirectory()) {
|
|
@@ -15723,8 +16451,10 @@ var security_hotspot_scanner_default = plugin47;
|
|
|
15723
16451
|
|
|
15724
16452
|
// src/semantic-search-indexer/index.ts
|
|
15725
16453
|
import * as fs2 from "node:fs/promises";
|
|
15726
|
-
import { isAbsolute as
|
|
16454
|
+
import { isAbsolute as isAbsolute21, relative as relative21, resolve as resolve22 } from "node:path";
|
|
16455
|
+
import { DEFAULT_WALK_IGNORE_DIRS } from "@wrongstack/core/utils";
|
|
15727
16456
|
var API_VERSION31 = "^0.1.10";
|
|
16457
|
+
var escapeRegex2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15728
16458
|
var state46 = {
|
|
15729
16459
|
index: null,
|
|
15730
16460
|
cachedPath: null,
|
|
@@ -15768,7 +16498,11 @@ var DEFAULTS41 = {
|
|
|
15768
16498
|
".scss",
|
|
15769
16499
|
".html"
|
|
15770
16500
|
],
|
|
15771
|
-
excludePatterns: [
|
|
16501
|
+
excludePatterns: [
|
|
16502
|
+
...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex2),
|
|
16503
|
+
"\\.wrongstack",
|
|
16504
|
+
"\\.temp_files"
|
|
16505
|
+
],
|
|
15772
16506
|
maxFileBytes: 1e6,
|
|
15773
16507
|
defaultLimit: 10,
|
|
15774
16508
|
minTokenLength: 2,
|
|
@@ -15798,18 +16532,18 @@ function normalizeSlashes2(p) {
|
|
|
15798
16532
|
function withinProject5(p) {
|
|
15799
16533
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
15800
16534
|
const root = normalizeSlashes2(process.cwd());
|
|
15801
|
-
const resolved = normalizeSlashes2(
|
|
15802
|
-
const rel = normalizeSlashes2(
|
|
16535
|
+
const resolved = normalizeSlashes2(isAbsolute21(p) ? resolve22(p) : resolve22(root, p));
|
|
16536
|
+
const rel = normalizeSlashes2(relative21(root, resolved));
|
|
15803
16537
|
if (rel === "" || rel === ".") return true;
|
|
15804
16538
|
if (rel.startsWith("..")) return false;
|
|
15805
|
-
if (
|
|
16539
|
+
if (isAbsolute21(rel)) return false;
|
|
15806
16540
|
return true;
|
|
15807
16541
|
}
|
|
15808
16542
|
function resolveProjectPath8(p) {
|
|
15809
16543
|
const raw = typeof p === "string" && p.length > 0 ? p : ".";
|
|
15810
16544
|
if (!withinProject5(raw)) return null;
|
|
15811
16545
|
const root = normalizeSlashes2(process.cwd());
|
|
15812
|
-
return normalizeSlashes2(
|
|
16546
|
+
return normalizeSlashes2(isAbsolute21(raw) ? resolve22(raw) : resolve22(root, raw));
|
|
15813
16547
|
}
|
|
15814
16548
|
function tokenize(text, minLength) {
|
|
15815
16549
|
const tokens = [];
|
|
@@ -15839,7 +16573,7 @@ function shouldIndexFile(filePath, cfg) {
|
|
|
15839
16573
|
var INDEX_BATCH_SIZE = 32;
|
|
15840
16574
|
var YIELD_EVERY_FILES = 64;
|
|
15841
16575
|
function yieldEventLoop() {
|
|
15842
|
-
return new Promise((
|
|
16576
|
+
return new Promise((resolve28) => setImmediate(resolve28));
|
|
15843
16577
|
}
|
|
15844
16578
|
function addFileToIndex(relPath, content, size, cfg) {
|
|
15845
16579
|
if (!state46.index || content.includes("\0")) return;
|
|
@@ -15893,8 +16627,8 @@ async function walkDirectory(absPath, cfg, excludes, fileBatch) {
|
|
|
15893
16627
|
state46.truncated = true;
|
|
15894
16628
|
return;
|
|
15895
16629
|
}
|
|
15896
|
-
const absChild = normalizeSlashes2(
|
|
15897
|
-
const relChild = normalizeSlashes2(
|
|
16630
|
+
const absChild = normalizeSlashes2(resolve22(absPath, ent.name));
|
|
16631
|
+
const relChild = normalizeSlashes2(relative21(root, absChild));
|
|
15898
16632
|
if (relChild === "" || relChild === ".") continue;
|
|
15899
16633
|
if (excludes.some((re) => re.test(relChild))) continue;
|
|
15900
16634
|
if (ent.isDirectory()) {
|
|
@@ -15936,7 +16670,7 @@ async function buildIndex(rootPath, cfg) {
|
|
|
15936
16670
|
return;
|
|
15937
16671
|
}
|
|
15938
16672
|
if (rootStats.isFile()) {
|
|
15939
|
-
const relPath = normalizeSlashes2(
|
|
16673
|
+
const relPath = normalizeSlashes2(relative21(normalizeSlashes2(process.cwd()), rootPath));
|
|
15940
16674
|
await indexFileFromStats(rootPath, relPath === "" ? "." : relPath, rootStats, cfg);
|
|
15941
16675
|
state46.fileCount = state46.index.files.size;
|
|
15942
16676
|
} else if (rootStats.isDirectory()) {
|
|
@@ -16232,15 +16966,15 @@ var semantic_search_indexer_default = plugin48;
|
|
|
16232
16966
|
import { expectDefined as expectDefined2 } from "@wrongstack/core/utils";
|
|
16233
16967
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
16234
16968
|
import { execFile as execFile12 } from "node:child_process";
|
|
16235
|
-
import { access as access3, readFile as
|
|
16236
|
-
import { isAbsolute as
|
|
16969
|
+
import { access as access3, readFile as readFile14, readdir as readdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
16970
|
+
import { isAbsolute as isAbsolute22, join as join5, relative as relative22, resolve as resolve23 } from "node:path";
|
|
16237
16971
|
var API_VERSION32 = "^0.1.10";
|
|
16238
16972
|
function resolveProjectRoot(rawCwd, root = process.cwd()) {
|
|
16239
16973
|
if (typeof rawCwd !== "string" || rawCwd.length === 0) return root;
|
|
16240
|
-
const base =
|
|
16241
|
-
const resolved =
|
|
16242
|
-
const rel =
|
|
16243
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
16974
|
+
const base = resolve23(root);
|
|
16975
|
+
const resolved = isAbsolute22(rawCwd) ? resolve23(rawCwd) : resolve23(base, rawCwd);
|
|
16976
|
+
const rel = relative22(base, resolved);
|
|
16977
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute22(rel)) return resolved;
|
|
16244
16978
|
return null;
|
|
16245
16979
|
}
|
|
16246
16980
|
var state47 = {
|
|
@@ -16252,7 +16986,7 @@ var state47 = {
|
|
|
16252
16986
|
lastBump: null
|
|
16253
16987
|
};
|
|
16254
16988
|
function runCommand3(command, args, cwd) {
|
|
16255
|
-
return new Promise((
|
|
16989
|
+
return new Promise((resolve28, reject) => {
|
|
16256
16990
|
execFile12(command, args, {
|
|
16257
16991
|
encoding: "utf-8",
|
|
16258
16992
|
cwd,
|
|
@@ -16260,7 +16994,7 @@ function runCommand3(command, args, cwd) {
|
|
|
16260
16994
|
windowsHide: true
|
|
16261
16995
|
}, (err, stdout, stderr) => {
|
|
16262
16996
|
if (!err) {
|
|
16263
|
-
|
|
16997
|
+
resolve28(stdout.trim());
|
|
16264
16998
|
return;
|
|
16265
16999
|
}
|
|
16266
17000
|
const failure = err;
|
|
@@ -16281,21 +17015,21 @@ async function getPackageJson(cwd) {
|
|
|
16281
17015
|
const path = cwd ? `${cwd}/package.json` : "package.json";
|
|
16282
17016
|
try {
|
|
16283
17017
|
await access3(path);
|
|
16284
|
-
return JSON.parse(await
|
|
17018
|
+
return JSON.parse(await readFile14(path, "utf-8"));
|
|
16285
17019
|
} catch {
|
|
16286
17020
|
return null;
|
|
16287
17021
|
}
|
|
16288
17022
|
}
|
|
16289
17023
|
async function collectManifests(root) {
|
|
16290
17024
|
const paths = [];
|
|
16291
|
-
const rootPkg =
|
|
17025
|
+
const rootPkg = join5(root, "package.json");
|
|
16292
17026
|
try {
|
|
16293
17027
|
await access3(rootPkg);
|
|
16294
17028
|
paths.push(rootPkg);
|
|
16295
17029
|
} catch {
|
|
16296
17030
|
}
|
|
16297
17031
|
for (const group of ["packages", "apps"]) {
|
|
16298
|
-
const groupDir =
|
|
17032
|
+
const groupDir = join5(root, group);
|
|
16299
17033
|
let entries;
|
|
16300
17034
|
try {
|
|
16301
17035
|
entries = await readdir4(groupDir, { withFileTypes: true });
|
|
@@ -16304,7 +17038,7 @@ async function collectManifests(root) {
|
|
|
16304
17038
|
}
|
|
16305
17039
|
for (const entry of entries) {
|
|
16306
17040
|
if (!entry.isDirectory()) continue;
|
|
16307
|
-
const candidate =
|
|
17041
|
+
const candidate = join5(groupDir, entry.name, "package.json");
|
|
16308
17042
|
try {
|
|
16309
17043
|
await access3(candidate);
|
|
16310
17044
|
paths.push(candidate);
|
|
@@ -16499,7 +17233,7 @@ var plugin49 = {
|
|
|
16499
17233
|
};
|
|
16500
17234
|
}
|
|
16501
17235
|
const root = cwd ?? process.cwd();
|
|
16502
|
-
const bumpScript =
|
|
17236
|
+
const bumpScript = join5(root, "scripts", "bump-version.mjs");
|
|
16503
17237
|
const changed = await collectManifests(root);
|
|
16504
17238
|
let hasBumpScript = true;
|
|
16505
17239
|
try {
|
|
@@ -16515,7 +17249,7 @@ var plugin49 = {
|
|
|
16515
17249
|
return { ok: false, error: `bump script failed: ${msg}` };
|
|
16516
17250
|
}
|
|
16517
17251
|
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
16518
|
-
const p =
|
|
17252
|
+
const p = join5(root, "website", rel);
|
|
16519
17253
|
try {
|
|
16520
17254
|
await access3(p);
|
|
16521
17255
|
changed.push(p);
|
|
@@ -16523,10 +17257,29 @@ var plugin49 = {
|
|
|
16523
17257
|
}
|
|
16524
17258
|
}
|
|
16525
17259
|
} else {
|
|
17260
|
+
const pending = [];
|
|
16526
17261
|
for (const manifest of changed) {
|
|
16527
|
-
|
|
17262
|
+
let pkgData;
|
|
17263
|
+
try {
|
|
17264
|
+
pkgData = JSON.parse(await readFile14(manifest, "utf-8"));
|
|
17265
|
+
} catch (err) {
|
|
17266
|
+
return {
|
|
17267
|
+
ok: false,
|
|
17268
|
+
error: `cannot bump: ${manifest} is not readable as JSON (${toErrorMessage(err)}). No manifests were modified.`
|
|
17269
|
+
};
|
|
17270
|
+
}
|
|
17271
|
+
if (!pkgData || typeof pkgData !== "object") {
|
|
17272
|
+
return {
|
|
17273
|
+
ok: false,
|
|
17274
|
+
error: `cannot bump: ${manifest} does not contain a JSON object. No manifests were modified.`
|
|
17275
|
+
};
|
|
17276
|
+
}
|
|
16528
17277
|
pkgData.version = newVersion;
|
|
16529
|
-
|
|
17278
|
+
pending.push({ path: manifest, contents: `${JSON.stringify(pkgData, null, 2)}
|
|
17279
|
+
` });
|
|
17280
|
+
}
|
|
17281
|
+
for (const { path, contents } of pending) {
|
|
17282
|
+
await writeFile4(path, contents, "utf-8");
|
|
16530
17283
|
}
|
|
16531
17284
|
}
|
|
16532
17285
|
try {
|
|
@@ -16864,8 +17617,8 @@ async function readTranscriptTail(transcriptPath, n) {
|
|
|
16864
17617
|
if (!transcriptPath || n <= 0) return [];
|
|
16865
17618
|
let raw;
|
|
16866
17619
|
try {
|
|
16867
|
-
const { readFile:
|
|
16868
|
-
raw = await
|
|
17620
|
+
const { readFile: readFile18 } = await import("node:fs/promises");
|
|
17621
|
+
raw = await readFile18(transcriptPath, "utf-8");
|
|
16869
17622
|
} catch {
|
|
16870
17623
|
return [];
|
|
16871
17624
|
}
|
|
@@ -16939,7 +17692,7 @@ var plugin50 = {
|
|
|
16939
17692
|
state48.commitCount = 0;
|
|
16940
17693
|
state48.startedAt = null;
|
|
16941
17694
|
state48.lastActivityAt = null;
|
|
16942
|
-
state48.stopHookUnregister =
|
|
17695
|
+
state48.stopHookUnregister = releaseHandle(state48.stopHookUnregister);
|
|
16943
17696
|
for (const off of state48.eventUnsubscribers) {
|
|
16944
17697
|
try {
|
|
16945
17698
|
off();
|
|
@@ -17206,15 +17959,15 @@ var session_recap_default = plugin50;
|
|
|
17206
17959
|
// src/shell-check/index.ts
|
|
17207
17960
|
import { execFile as execFile13 } from "node:child_process";
|
|
17208
17961
|
import { readdir as readdir5 } from "node:fs/promises";
|
|
17209
|
-
import { isAbsolute as
|
|
17962
|
+
import { isAbsolute as isAbsolute23, join as join6, relative as relative23, resolve as resolve24 } from "node:path";
|
|
17210
17963
|
var API_VERSION33 = "^0.1.10";
|
|
17211
17964
|
function withinProject6(p) {
|
|
17212
17965
|
const root = process.cwd();
|
|
17213
|
-
const resolved =
|
|
17214
|
-
const rel =
|
|
17966
|
+
const resolved = isAbsolute23(p) ? resolve24(p) : resolve24(root, p);
|
|
17967
|
+
const rel = relative23(root, resolved);
|
|
17215
17968
|
if (rel === "" || rel === ".") return true;
|
|
17216
17969
|
if (rel.startsWith("..")) return false;
|
|
17217
|
-
if (
|
|
17970
|
+
if (isAbsolute23(rel)) return false;
|
|
17218
17971
|
return true;
|
|
17219
17972
|
}
|
|
17220
17973
|
var MAX_PATH_LEN = 4096;
|
|
@@ -17307,7 +18060,7 @@ async function findShellFiles(dir, pattern) {
|
|
|
17307
18060
|
return results;
|
|
17308
18061
|
}
|
|
17309
18062
|
for (const entry of entries) {
|
|
17310
|
-
const full =
|
|
18063
|
+
const full = join6(dir, entry.name);
|
|
17311
18064
|
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
|
|
17312
18065
|
results.push(...await findShellFiles(full, pattern));
|
|
17313
18066
|
} else if (entry.isFile() && (entry.name.endsWith(".sh") || entry.name === "Dockerfile")) {
|
|
@@ -17506,8 +18259,8 @@ var plugin51 = {
|
|
|
17506
18259
|
var shell_check_default = plugin51;
|
|
17507
18260
|
|
|
17508
18261
|
// src/smart-rename/index.ts
|
|
17509
|
-
import { readFileSync as
|
|
17510
|
-
import { extname as
|
|
18262
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "node:fs";
|
|
18263
|
+
import { extname as extname6, isAbsolute as isAbsolute24, relative as relative24, resolve as resolve25 } from "node:path";
|
|
17511
18264
|
var API_VERSION34 = "^0.1.10";
|
|
17512
18265
|
var state50 = {
|
|
17513
18266
|
renameCount: 0,
|
|
@@ -17529,24 +18282,31 @@ function readConfig46(raw) {
|
|
|
17529
18282
|
function withinProject7(p) {
|
|
17530
18283
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
17531
18284
|
const root = process.cwd();
|
|
17532
|
-
const resolved =
|
|
17533
|
-
const rel =
|
|
18285
|
+
const resolved = isAbsolute24(p) ? resolve25(p) : resolve25(root, p);
|
|
18286
|
+
const rel = relative24(root, resolved);
|
|
17534
18287
|
if (rel === "" || rel === ".") return true;
|
|
17535
18288
|
if (rel.startsWith("..")) return false;
|
|
17536
|
-
if (
|
|
18289
|
+
if (isAbsolute24(rel)) return false;
|
|
17537
18290
|
return true;
|
|
17538
18291
|
}
|
|
17539
18292
|
function toPosix7(p) {
|
|
17540
18293
|
return p.replace(/\\/g, "/");
|
|
17541
18294
|
}
|
|
17542
18295
|
function relativePath7(p) {
|
|
17543
|
-
return toPosix7(
|
|
18296
|
+
return toPosix7(relative24(process.cwd(), p));
|
|
17544
18297
|
}
|
|
17545
|
-
function
|
|
18298
|
+
function escapeRegex3(s) {
|
|
17546
18299
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17547
18300
|
}
|
|
18301
|
+
var IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
18302
|
+
function isIdentifier(name) {
|
|
18303
|
+
return IDENTIFIER_RE.test(name);
|
|
18304
|
+
}
|
|
17548
18305
|
function renameInContent(content, oldName, newName) {
|
|
17549
|
-
const re = new RegExp(
|
|
18306
|
+
const re = new RegExp(
|
|
18307
|
+
`(?<![A-Za-z0-9_$])${escapeRegex3(oldName)}(?![A-Za-z0-9_$])`,
|
|
18308
|
+
"g"
|
|
18309
|
+
);
|
|
17550
18310
|
let replacements = 0;
|
|
17551
18311
|
const preview = content.replace(re, () => {
|
|
17552
18312
|
replacements++;
|
|
@@ -17608,17 +18368,23 @@ var plugin52 = {
|
|
|
17608
18368
|
if (!newName || typeof newName !== "string" || newName.length === 0) {
|
|
17609
18369
|
return { ok: false, error: "newName is required" };
|
|
17610
18370
|
}
|
|
18371
|
+
if (!isIdentifier(oldName)) {
|
|
18372
|
+
return { ok: false, error: `oldName "${oldName}" is not a valid identifier` };
|
|
18373
|
+
}
|
|
18374
|
+
if (!isIdentifier(newName)) {
|
|
18375
|
+
return { ok: false, error: `newName "${newName}" is not a valid identifier` };
|
|
18376
|
+
}
|
|
17611
18377
|
if (!withinProject7(rawPath)) {
|
|
17612
18378
|
return { ok: false, error: "path is outside the project root" };
|
|
17613
18379
|
}
|
|
17614
|
-
const ext =
|
|
18380
|
+
const ext = extname6(rawPath).toLowerCase();
|
|
17615
18381
|
if (!cfg.extensions.includes(ext)) {
|
|
17616
18382
|
return { ok: false, error: `extension ${ext} is not allowed for rename` };
|
|
17617
18383
|
}
|
|
17618
|
-
const resolved =
|
|
18384
|
+
const resolved = resolve25(process.cwd(), rawPath);
|
|
17619
18385
|
let content;
|
|
17620
18386
|
try {
|
|
17621
|
-
content =
|
|
18387
|
+
content = readFileSync13(resolved, "utf-8");
|
|
17622
18388
|
} catch (err) {
|
|
17623
18389
|
state50.errorCount += 1;
|
|
17624
18390
|
return { ok: false, error: String(err) };
|
|
@@ -17628,7 +18394,7 @@ var plugin52 = {
|
|
|
17628
18394
|
state50.replacementCount += replacements;
|
|
17629
18395
|
if (input.apply) {
|
|
17630
18396
|
try {
|
|
17631
|
-
|
|
18397
|
+
writeFileSync2(resolved, preview, "utf-8");
|
|
17632
18398
|
} catch (err) {
|
|
17633
18399
|
state50.errorCount += 1;
|
|
17634
18400
|
return { ok: false, error: String(err) };
|
|
@@ -18005,8 +18771,8 @@ var plugin53 = {
|
|
|
18005
18771
|
state51.skippedNonMd = 0;
|
|
18006
18772
|
state51.readErrorCount = 0;
|
|
18007
18773
|
state51.autoFixApplied = 0;
|
|
18008
|
-
state51.postHookUnregister =
|
|
18009
|
-
state51.preHookUnregister =
|
|
18774
|
+
state51.postHookUnregister = releaseHandle(state51.postHookUnregister);
|
|
18775
|
+
state51.preHookUnregister = releaseHandle(state51.preHookUnregister);
|
|
18010
18776
|
const cfg = readConfig47(api.config.extensions?.["spec-linker"]);
|
|
18011
18777
|
const postHook = async (input) => {
|
|
18012
18778
|
if (!cfg.enabled) return;
|
|
@@ -18159,10 +18925,11 @@ ${lines}${overflowNote}`
|
|
|
18159
18925
|
var spec_linker_default = plugin53;
|
|
18160
18926
|
|
|
18161
18927
|
// src/template-engine/index.ts
|
|
18162
|
-
import { readFile as
|
|
18163
|
-
import { isAbsolute as
|
|
18928
|
+
import { readFile as readFile16, writeFile as writeFile5 } from "node:fs/promises";
|
|
18929
|
+
import { isAbsolute as isAbsolute25 } from "node:path";
|
|
18164
18930
|
var API_VERSION35 = "^0.1.10";
|
|
18165
18931
|
var templates = /* @__PURE__ */ new Map();
|
|
18932
|
+
var contributorUnregister = null;
|
|
18166
18933
|
function expandTemplate(template, variables) {
|
|
18167
18934
|
let result = template;
|
|
18168
18935
|
result = result.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
@@ -18207,9 +18974,12 @@ function renderTemplateRaw(template, variables) {
|
|
|
18207
18974
|
return result;
|
|
18208
18975
|
}
|
|
18209
18976
|
function validateRelativeTemplatePath(field, value) {
|
|
18210
|
-
if (
|
|
18977
|
+
if (isAbsolute25(value) || value.split(/[\\/]+/).includes("..")) {
|
|
18211
18978
|
return `${field} must be a relative path without ".." components`;
|
|
18212
18979
|
}
|
|
18980
|
+
if (!withinProject(value)) {
|
|
18981
|
+
return `${field} must resolve inside the project directory`;
|
|
18982
|
+
}
|
|
18213
18983
|
return null;
|
|
18214
18984
|
}
|
|
18215
18985
|
var plugin54 = {
|
|
@@ -18333,7 +19103,7 @@ var plugin54 = {
|
|
|
18333
19103
|
}
|
|
18334
19104
|
let content;
|
|
18335
19105
|
try {
|
|
18336
|
-
content = await
|
|
19106
|
+
content = await readFile16(template_path, "utf-8");
|
|
18337
19107
|
} catch (err) {
|
|
18338
19108
|
return { ok: false, error: `Could not read template file: ${err}` };
|
|
18339
19109
|
}
|
|
@@ -18432,7 +19202,8 @@ var plugin54 = {
|
|
|
18432
19202
|
};
|
|
18433
19203
|
}
|
|
18434
19204
|
});
|
|
18435
|
-
|
|
19205
|
+
contributorUnregister = releaseHandle(contributorUnregister);
|
|
19206
|
+
contributorUnregister = api.registerSystemPromptContributor(async () => [
|
|
18436
19207
|
{
|
|
18437
19208
|
type: "text",
|
|
18438
19209
|
text: `Template engine available:
|
|
@@ -18447,6 +19218,7 @@ var plugin54 = {
|
|
|
18447
19218
|
teardown(api) {
|
|
18448
19219
|
const count = templates.size;
|
|
18449
19220
|
templates.clear();
|
|
19221
|
+
contributorUnregister = releaseHandle(contributorUnregister);
|
|
18450
19222
|
api.log.info("template-engine: teardown complete", { cleared: count });
|
|
18451
19223
|
},
|
|
18452
19224
|
async health() {
|
|
@@ -18465,7 +19237,7 @@ var plugin54 = {
|
|
|
18465
19237
|
var template_engine_default = plugin54;
|
|
18466
19238
|
|
|
18467
19239
|
// src/test-coverage-gate/index.ts
|
|
18468
|
-
import { readFileSync as
|
|
19240
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
18469
19241
|
var API_VERSION36 = "^0.1.10";
|
|
18470
19242
|
var state52 = {
|
|
18471
19243
|
invocationCount: 0,
|
|
@@ -18506,7 +19278,7 @@ function readConfig48(raw) {
|
|
|
18506
19278
|
}
|
|
18507
19279
|
function readCoverageSummary(coveragePath) {
|
|
18508
19280
|
try {
|
|
18509
|
-
const raw =
|
|
19281
|
+
const raw = readFileSync14(coveragePath, "utf-8");
|
|
18510
19282
|
return JSON.parse(raw);
|
|
18511
19283
|
} catch {
|
|
18512
19284
|
return null;
|
|
@@ -18576,7 +19348,7 @@ var plugin55 = {
|
|
|
18576
19348
|
state52.skippedCount = 0;
|
|
18577
19349
|
state52.lastOverallPct = null;
|
|
18578
19350
|
state52.lastResult = null;
|
|
18579
|
-
state52.hookUnregister =
|
|
19351
|
+
state52.hookUnregister = releaseHandle(state52.hookUnregister);
|
|
18580
19352
|
const cfg = readConfig48(api.config.extensions?.["test-coverage-gate"]);
|
|
18581
19353
|
const hook = (input) => {
|
|
18582
19354
|
if (!cfg.enabled) return;
|
|
@@ -18722,9 +19494,9 @@ var test_coverage_gate_default = plugin55;
|
|
|
18722
19494
|
|
|
18723
19495
|
// src/test-flake-detector/index.ts
|
|
18724
19496
|
import { execFile as execFile14 } from "node:child_process";
|
|
18725
|
-
import { readFileSync as
|
|
18726
|
-
import { createRequire as
|
|
18727
|
-
import { dirname as
|
|
19497
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
19498
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
19499
|
+
import { dirname as dirname8, isAbsolute as isAbsolute26, relative as relative25, resolve as resolve26 } from "node:path";
|
|
18728
19500
|
var API_VERSION37 = "^0.1.10";
|
|
18729
19501
|
var state53 = {
|
|
18730
19502
|
invocationCount: 0,
|
|
@@ -18795,15 +19567,15 @@ var ALLOWED_RUNNER_FLAGS = /* @__PURE__ */ new Set([
|
|
|
18795
19567
|
]);
|
|
18796
19568
|
function withinProject8(p) {
|
|
18797
19569
|
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("..") && !
|
|
19570
|
+
const root = resolve26(process.cwd());
|
|
19571
|
+
const resolved = isAbsolute26(p) ? resolve26(p) : resolve26(root, p);
|
|
19572
|
+
const rel = relative25(root, resolved);
|
|
19573
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute26(rel);
|
|
18802
19574
|
}
|
|
18803
|
-
function
|
|
19575
|
+
function isInside3(parent, child) {
|
|
18804
19576
|
if (parent === child) return true;
|
|
18805
|
-
const rel =
|
|
18806
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
19577
|
+
const rel = relative25(parent, child);
|
|
19578
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute26(rel);
|
|
18807
19579
|
}
|
|
18808
19580
|
function tokenizeCommand(command) {
|
|
18809
19581
|
const trimmed = command.trim();
|
|
@@ -18840,14 +19612,14 @@ function resolveTestCommand(baseCommand, testPattern) {
|
|
|
18840
19612
|
if (runnerArgs.some((arg) => !ALLOWED_RUNNER_FLAGS.has(arg))) return null;
|
|
18841
19613
|
let resolvedEntry;
|
|
18842
19614
|
try {
|
|
18843
|
-
const requireFromProject =
|
|
19615
|
+
const requireFromProject = createRequire3(resolve26(process.cwd(), "package.json"));
|
|
18844
19616
|
const packagePath = requireFromProject.resolve(`${runner}/package.json`);
|
|
18845
|
-
const packageJson = JSON.parse(
|
|
19617
|
+
const packageJson = JSON.parse(readFileSync15(packagePath, "utf8"));
|
|
18846
19618
|
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[runner] ?? Object.values(packageJson.bin ?? {})[0];
|
|
18847
19619
|
if (!relativeBin) return null;
|
|
18848
|
-
const packageDir =
|
|
18849
|
-
const candidate =
|
|
18850
|
-
if (
|
|
19620
|
+
const packageDir = dirname8(packagePath);
|
|
19621
|
+
const candidate = resolve26(packageDir, relativeBin);
|
|
19622
|
+
if (isAbsolute26(relativeBin) || !isInside3(packageDir, candidate)) {
|
|
18851
19623
|
return null;
|
|
18852
19624
|
}
|
|
18853
19625
|
resolvedEntry = candidate;
|
|
@@ -19089,8 +19861,8 @@ var plugin56 = {
|
|
|
19089
19861
|
var test_flake_detector_default = plugin56;
|
|
19090
19862
|
|
|
19091
19863
|
// src/test-generator/index.ts
|
|
19092
|
-
import { readFileSync as
|
|
19093
|
-
import { isAbsolute as
|
|
19864
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
19865
|
+
import { isAbsolute as isAbsolute27, relative as relative26, resolve as resolve27 } from "node:path";
|
|
19094
19866
|
var API_VERSION38 = "^0.1.10";
|
|
19095
19867
|
var state54 = {
|
|
19096
19868
|
generateCount: 0,
|
|
@@ -19125,18 +19897,18 @@ function readConfig50(raw) {
|
|
|
19125
19897
|
function withinProject9(p) {
|
|
19126
19898
|
if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
|
|
19127
19899
|
const root = process.cwd();
|
|
19128
|
-
const resolved =
|
|
19129
|
-
const rel =
|
|
19900
|
+
const resolved = isAbsolute27(p) ? resolve27(p) : resolve27(root, p);
|
|
19901
|
+
const rel = relative26(root, resolved);
|
|
19130
19902
|
if (rel === "" || rel === ".") return true;
|
|
19131
19903
|
if (rel.startsWith("..")) return false;
|
|
19132
|
-
if (
|
|
19904
|
+
if (isAbsolute27(rel)) return false;
|
|
19133
19905
|
return true;
|
|
19134
19906
|
}
|
|
19135
19907
|
function toPosix8(p) {
|
|
19136
19908
|
return p.replace(/\\/g, "/");
|
|
19137
19909
|
}
|
|
19138
19910
|
function relativePath8(p) {
|
|
19139
|
-
return toPosix8(
|
|
19911
|
+
return toPosix8(relative26(process.cwd(), p));
|
|
19140
19912
|
}
|
|
19141
19913
|
function detectExports(content) {
|
|
19142
19914
|
const exports = [];
|
|
@@ -19230,7 +20002,7 @@ function generateTestContent(sourcePath, sourceModule, detected, cfg) {
|
|
|
19230
20002
|
return lines.join("\n");
|
|
19231
20003
|
}
|
|
19232
20004
|
function generateForFile(filePath, cfg) {
|
|
19233
|
-
const sourceContent =
|
|
20005
|
+
const sourceContent = readFileSync16(filePath, "utf-8");
|
|
19234
20006
|
const detected = detectExports(sourceContent);
|
|
19235
20007
|
const sourceFile = relativePath8(filePath);
|
|
19236
20008
|
const sourceParts = sourceFile.split("/");
|
|
@@ -19349,7 +20121,7 @@ var plugin57 = {
|
|
|
19349
20121
|
if (!withinProject9(rawPath)) {
|
|
19350
20122
|
return { ok: false, error: "path is outside the project root" };
|
|
19351
20123
|
}
|
|
19352
|
-
const resolved =
|
|
20124
|
+
const resolved = resolve27(process.cwd(), rawPath);
|
|
19353
20125
|
state54.generateCount += 1;
|
|
19354
20126
|
let result;
|
|
19355
20127
|
try {
|
|
@@ -19435,7 +20207,17 @@ var test_generator_default = plugin57;
|
|
|
19435
20207
|
// src/test-runner-gate/index.ts
|
|
19436
20208
|
import { execFile as execFile15 } from "node:child_process";
|
|
19437
20209
|
import { access as access4 } from "node:fs/promises";
|
|
19438
|
-
import { basename as basename6, dirname as
|
|
20210
|
+
import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute28, join as join7 } from "node:path";
|
|
20211
|
+
import { buildWin32CmdShimInvocation as buildWin32CmdShimInvocation2, resolveWin32Command as resolveWin32Command2 } from "@wrongstack/tools/win32";
|
|
20212
|
+
function resolveExec(command, args) {
|
|
20213
|
+
const resolved = resolveWin32Command2(command);
|
|
20214
|
+
const needsShell = process.platform === "win32" && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
20215
|
+
if (needsShell) {
|
|
20216
|
+
const shim = buildWin32CmdShimInvocation2(resolved, args);
|
|
20217
|
+
return { cmd: shim.command, args: shim.args, windowsVerbatimArguments: true };
|
|
20218
|
+
}
|
|
20219
|
+
return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
|
|
20220
|
+
}
|
|
19439
20221
|
var API_VERSION39 = "^0.1.10";
|
|
19440
20222
|
var state55 = {
|
|
19441
20223
|
invocationCount: 0,
|
|
@@ -19500,7 +20282,7 @@ function pathContentHash(content) {
|
|
|
19500
20282
|
}
|
|
19501
20283
|
return h >>> 0;
|
|
19502
20284
|
}
|
|
19503
|
-
var lastPassedHash =
|
|
20285
|
+
var lastPassedHash = new BoundedMap({ max: 1024 });
|
|
19504
20286
|
var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
19505
20287
|
"npx",
|
|
19506
20288
|
"pnpm",
|
|
@@ -19518,7 +20300,7 @@ var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
19518
20300
|
function resolveTestFiles(sourcePath, patterns) {
|
|
19519
20301
|
const name = basename6(sourcePath).replace(/\.[^.]+$/, "");
|
|
19520
20302
|
const pathNoExt = sourcePath.replace(/\.[^.]+$/, "");
|
|
19521
|
-
const dir =
|
|
20303
|
+
const dir = dirname9(sourcePath);
|
|
19522
20304
|
const candidates = [];
|
|
19523
20305
|
for (const pattern of patterns) {
|
|
19524
20306
|
const candidate = pattern.replace(/\{name\}/g, name).replace(/\{path\}/g, pathNoExt).replace(/\{dir\}/g, dir);
|
|
@@ -19527,7 +20309,7 @@ function resolveTestFiles(sourcePath, patterns) {
|
|
|
19527
20309
|
candidates.push(candidate);
|
|
19528
20310
|
} else {
|
|
19529
20311
|
candidates.push(candidate);
|
|
19530
|
-
candidates.push(
|
|
20312
|
+
candidates.push(join7(dir, candidate));
|
|
19531
20313
|
}
|
|
19532
20314
|
}
|
|
19533
20315
|
}
|
|
@@ -19554,12 +20336,15 @@ async function detectRunner(requested) {
|
|
|
19554
20336
|
const match = candidates.find((c) => c.name === requested);
|
|
19555
20337
|
if (!match) return null;
|
|
19556
20338
|
try {
|
|
19557
|
-
await new Promise((
|
|
19558
|
-
|
|
20339
|
+
await new Promise((resolve28, reject) => {
|
|
20340
|
+
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
20341
|
+
execFile15(ex.cmd, ex.args, {
|
|
19559
20342
|
encoding: "utf-8",
|
|
19560
20343
|
timeout: 5e3,
|
|
19561
|
-
cwd: process.cwd()
|
|
19562
|
-
|
|
20344
|
+
cwd: process.cwd(),
|
|
20345
|
+
windowsHide: true,
|
|
20346
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20347
|
+
}, (err) => err ? reject(err) : resolve28());
|
|
19563
20348
|
});
|
|
19564
20349
|
return match;
|
|
19565
20350
|
} catch {
|
|
@@ -19568,12 +20353,15 @@ async function detectRunner(requested) {
|
|
|
19568
20353
|
}
|
|
19569
20354
|
for (const candidate of candidates) {
|
|
19570
20355
|
try {
|
|
19571
|
-
await new Promise((
|
|
19572
|
-
|
|
20356
|
+
await new Promise((resolve28, reject) => {
|
|
20357
|
+
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
20358
|
+
execFile15(ex.cmd, ex.args, {
|
|
19573
20359
|
encoding: "utf-8",
|
|
19574
20360
|
timeout: 5e3,
|
|
19575
|
-
cwd: process.cwd()
|
|
19576
|
-
|
|
20361
|
+
cwd: process.cwd(),
|
|
20362
|
+
windowsHide: true,
|
|
20363
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20364
|
+
}, (err) => err ? reject(err) : resolve28());
|
|
19577
20365
|
});
|
|
19578
20366
|
return candidate;
|
|
19579
20367
|
} catch {
|
|
@@ -19588,7 +20376,7 @@ function resolveAllowedCommand2(customCommand) {
|
|
|
19588
20376
|
if (ALLOWED_COMMAND_TOKENS.has(head)) {
|
|
19589
20377
|
return { cmd: head, args: tokens.slice(1) };
|
|
19590
20378
|
}
|
|
19591
|
-
if (
|
|
20379
|
+
if (isAbsolute28(head)) {
|
|
19592
20380
|
if (!withinProject(head)) return null;
|
|
19593
20381
|
const base = basename6(head);
|
|
19594
20382
|
if (ALLOWED_COMMAND_TOKENS.has(base)) {
|
|
@@ -19619,14 +20407,21 @@ async function runTests(testFile, runner, customCommand, timeoutMs) {
|
|
|
19619
20407
|
let stdout = "";
|
|
19620
20408
|
try {
|
|
19621
20409
|
const { stdout: out } = await new Promise(
|
|
19622
|
-
(
|
|
20410
|
+
(resolve28, reject) => {
|
|
20411
|
+
const ex = resolveExec(cmd, fullArgs);
|
|
19623
20412
|
execFile15(
|
|
19624
|
-
cmd,
|
|
19625
|
-
|
|
19626
|
-
{
|
|
20413
|
+
ex.cmd,
|
|
20414
|
+
ex.args,
|
|
20415
|
+
{
|
|
20416
|
+
encoding: "utf-8",
|
|
20417
|
+
timeout: timeoutMs,
|
|
20418
|
+
cwd: process.cwd(),
|
|
20419
|
+
windowsHide: true,
|
|
20420
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
20421
|
+
},
|
|
19627
20422
|
(err, out2, stderr) => {
|
|
19628
20423
|
if (err) reject(Object.assign(err, { stdout: out2, stderr }));
|
|
19629
|
-
else
|
|
20424
|
+
else resolve28({ stdout: out2, stderr });
|
|
19630
20425
|
}
|
|
19631
20426
|
);
|
|
19632
20427
|
}
|
|
@@ -19743,7 +20538,7 @@ var plugin58 = {
|
|
|
19743
20538
|
state55.errorCount = 0;
|
|
19744
20539
|
state55.extensionSkippedCount = 0;
|
|
19745
20540
|
state55.cachedSkipCount = 0;
|
|
19746
|
-
state55.hookUnregister =
|
|
20541
|
+
state55.hookUnregister = releaseHandle(state55.hookUnregister);
|
|
19747
20542
|
state55.lastResult = null;
|
|
19748
20543
|
lastPassedHash.clear();
|
|
19749
20544
|
const cfg = readConfig51(api.config.extensions?.["test-runner-gate"]);
|
|
@@ -19994,7 +20789,7 @@ var plugin59 = {
|
|
|
19994
20789
|
state56.lastMessageId = null;
|
|
19995
20790
|
state56.lastPayloadHash = "";
|
|
19996
20791
|
state56.lastBroadcastAt = 0;
|
|
19997
|
-
state56.hookUnregister =
|
|
20792
|
+
state56.hookUnregister = releaseHandle(state56.hookUnregister);
|
|
19998
20793
|
const cfg = readConfig52(api.config.extensions?.["todo-listener"]);
|
|
19999
20794
|
const mailbox = api.mailbox;
|
|
20000
20795
|
const hook = async (input) => {
|
|
@@ -20035,7 +20830,7 @@ var plugin59 = {
|
|
|
20035
20830
|
0,
|
|
20036
20831
|
200
|
|
20037
20832
|
);
|
|
20038
|
-
const body =
|
|
20833
|
+
const body = safeJsonStringify(payload, 2);
|
|
20039
20834
|
const sendInput = {
|
|
20040
20835
|
from: `plugin:todo-listener`,
|
|
20041
20836
|
to: "*",
|
|
@@ -20139,6 +20934,7 @@ var todo_listener_default = plugin59;
|
|
|
20139
20934
|
// src/todo-tracker/index.ts
|
|
20140
20935
|
import * as fsp from "node:fs/promises";
|
|
20141
20936
|
import { randomUUID } from "node:crypto";
|
|
20937
|
+
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
20142
20938
|
function deriveFilePath(api) {
|
|
20143
20939
|
const raw = api.config.extensions?.["todo-tracker"];
|
|
20144
20940
|
const explicit = typeof raw?.["filePath"] === "string" ? raw["filePath"] : null;
|
|
@@ -20168,10 +20964,8 @@ async function loadFile(filePath) {
|
|
|
20168
20964
|
}
|
|
20169
20965
|
}
|
|
20170
20966
|
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);
|
|
20967
|
+
await ensureDir3(filePath.replace(/[/\\][^/\\]+$/, ""));
|
|
20968
|
+
await atomicWrite3(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
20175
20969
|
}
|
|
20176
20970
|
var state57 = {
|
|
20177
20971
|
filePath: null,
|
|
@@ -20611,16 +21405,36 @@ function modelMatches(pattern, model) {
|
|
|
20611
21405
|
}
|
|
20612
21406
|
return model.toLowerCase() === pattern.toLowerCase();
|
|
20613
21407
|
}
|
|
21408
|
+
function readBoundedNumber(value, min, max, fallback) {
|
|
21409
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
21410
|
+
if (value < min || value > max) return fallback;
|
|
21411
|
+
return value;
|
|
21412
|
+
}
|
|
20614
21413
|
function readConfig53(raw) {
|
|
20615
21414
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS50 };
|
|
20616
21415
|
const r = raw;
|
|
21416
|
+
const warnPercent = readBoundedNumber(r["warnPercent"], 1, 100, DEFAULTS50.warnPercent);
|
|
21417
|
+
const stopPercent = readBoundedNumber(r["stopPercent"], 1, 100, DEFAULTS50.stopPercent);
|
|
20617
21418
|
return {
|
|
20618
|
-
limit:
|
|
20619
|
-
warnPercent
|
|
20620
|
-
|
|
21419
|
+
limit: readBoundedNumber(r["limit"], 0, Number.MAX_SAFE_INTEGER, DEFAULTS50.limit),
|
|
21420
|
+
warnPercent,
|
|
21421
|
+
// A warn threshold above the stop threshold can never fire — the run
|
|
21422
|
+
// stops first. Clamp so the pair always describes a reachable window.
|
|
21423
|
+
stopPercent: Math.max(stopPercent, warnPercent),
|
|
20621
21424
|
model: typeof r["model"] === "string" ? r["model"] : ""
|
|
20622
21425
|
};
|
|
20623
21426
|
}
|
|
21427
|
+
function clearRegistrations2() {
|
|
21428
|
+
for (const key of ["hookUnregister", "postHookUnregister"]) {
|
|
21429
|
+
const off = state58[key];
|
|
21430
|
+
if (!off) continue;
|
|
21431
|
+
try {
|
|
21432
|
+
off();
|
|
21433
|
+
} catch {
|
|
21434
|
+
}
|
|
21435
|
+
state58[key] = null;
|
|
21436
|
+
}
|
|
21437
|
+
}
|
|
20624
21438
|
var plugin61 = {
|
|
20625
21439
|
name: "token-budget",
|
|
20626
21440
|
version: "0.1.0",
|
|
@@ -20667,9 +21481,8 @@ var plugin61 = {
|
|
|
20667
21481
|
state58.stopFired = false;
|
|
20668
21482
|
state58.warnContextInjected = false;
|
|
20669
21483
|
state58.stopContextInjected = false;
|
|
20670
|
-
state58.hookUnregister = null;
|
|
20671
|
-
state58.postHookUnregister = null;
|
|
20672
21484
|
state58.lastRequest = null;
|
|
21485
|
+
clearRegistrations2();
|
|
20673
21486
|
const cfg = readConfig53(api.config.extensions?.["token-budget"]);
|
|
20674
21487
|
api.onEvent("provider.response", (payload) => {
|
|
20675
21488
|
const p = payload;
|
|
@@ -20766,6 +21579,12 @@ var plugin61 = {
|
|
|
20766
21579
|
remaining,
|
|
20767
21580
|
percent,
|
|
20768
21581
|
requestCount: state58.requestCount,
|
|
21582
|
+
// The EFFECTIVE thresholds, after out-of-range values fall back to
|
|
21583
|
+
// the defaults and warn/stop are ordered. Without these the user
|
|
21584
|
+
// cannot tell that a rejected or clamped setting is not in force.
|
|
21585
|
+
warnPercent: cfg.warnPercent,
|
|
21586
|
+
stopPercent: cfg.stopPercent,
|
|
21587
|
+
model: cfg.model === "" ? null : cfg.model,
|
|
20769
21588
|
breakdown: {
|
|
20770
21589
|
prompt: state58.totalPromptTokens,
|
|
20771
21590
|
completion: state58.totalCompletionTokens
|
|
@@ -20784,20 +21603,7 @@ var plugin61 = {
|
|
|
20784
21603
|
});
|
|
20785
21604
|
},
|
|
20786
21605
|
teardown(api) {
|
|
20787
|
-
|
|
20788
|
-
try {
|
|
20789
|
-
state58.hookUnregister();
|
|
20790
|
-
} catch {
|
|
20791
|
-
}
|
|
20792
|
-
state58.hookUnregister = null;
|
|
20793
|
-
}
|
|
20794
|
-
if (state58.postHookUnregister) {
|
|
20795
|
-
try {
|
|
20796
|
-
state58.postHookUnregister();
|
|
20797
|
-
} catch {
|
|
20798
|
-
}
|
|
20799
|
-
state58.postHookUnregister = null;
|
|
20800
|
-
}
|
|
21606
|
+
clearRegistrations2();
|
|
20801
21607
|
const final = {
|
|
20802
21608
|
totalTokens: state58.totalTokens,
|
|
20803
21609
|
requestCount: state58.requestCount,
|
|
@@ -20890,7 +21696,21 @@ function estimateRequestTokens(request, charsPerToken) {
|
|
|
20890
21696
|
walk(request["messages"]);
|
|
20891
21697
|
return Math.ceil(chars / charsPerToken);
|
|
20892
21698
|
}
|
|
20893
|
-
|
|
21699
|
+
function sleep(ms, signal) {
|
|
21700
|
+
if (signal?.aborted) return Promise.resolve();
|
|
21701
|
+
return new Promise((resolve28) => {
|
|
21702
|
+
const timer = setTimeout(() => {
|
|
21703
|
+
signal?.removeEventListener("abort", onAbort);
|
|
21704
|
+
resolve28();
|
|
21705
|
+
}, ms);
|
|
21706
|
+
timer.unref?.();
|
|
21707
|
+
function onAbort() {
|
|
21708
|
+
clearTimeout(timer);
|
|
21709
|
+
resolve28();
|
|
21710
|
+
}
|
|
21711
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
21712
|
+
});
|
|
21713
|
+
}
|
|
20894
21714
|
var plugin62 = {
|
|
20895
21715
|
name: "token-throttle",
|
|
20896
21716
|
version: "0.1.0",
|
|
@@ -20949,6 +21769,7 @@ var plugin62 = {
|
|
|
20949
21769
|
name: "token-throttle",
|
|
20950
21770
|
owner: "token-throttle",
|
|
20951
21771
|
async wrapProviderRunner(_ctx, request, inner) {
|
|
21772
|
+
const signal = _ctx?.signal;
|
|
20952
21773
|
const req = request ?? {};
|
|
20953
21774
|
state59.invocations += 1;
|
|
20954
21775
|
const now = Date.now();
|
|
@@ -20962,7 +21783,7 @@ var plugin62 = {
|
|
|
20962
21783
|
api.metrics.counter("throttled");
|
|
20963
21784
|
api.metrics.histogram("delay_ms", delay);
|
|
20964
21785
|
api.log.info("token-throttle: delaying provider call", { delayMs: delay, projected });
|
|
20965
|
-
await sleep(delay);
|
|
21786
|
+
await sleep(delay, signal);
|
|
20966
21787
|
}
|
|
20967
21788
|
const response = await inner(_ctx, request);
|
|
20968
21789
|
const used = (response?.usage?.input ?? 0) + (response?.usage?.output ?? 0) || projected;
|
|
@@ -21110,7 +21931,9 @@ async function runTypeCheck(cfg) {
|
|
|
21110
21931
|
if (!resolved) return null;
|
|
21111
21932
|
argv = [resolved.cmd, ...resolved.args];
|
|
21112
21933
|
} else {
|
|
21113
|
-
|
|
21934
|
+
const tscFlags = ["--noEmit", "--incremental"];
|
|
21935
|
+
const localTsc = resolveNodeBin("typescript", "tsc", process.cwd(), tscFlags);
|
|
21936
|
+
argv = localTsc ? [localTsc.cmd, ...localTsc.args] : ["npx", "tsc", ...tscFlags];
|
|
21114
21937
|
if (tsConfig && tsConfig !== "tsconfig.json") {
|
|
21115
21938
|
argv = [...argv, "-p", tsConfig];
|
|
21116
21939
|
}
|
|
@@ -21206,7 +22029,7 @@ var plugin63 = {
|
|
|
21206
22029
|
state60.errorCount = 0;
|
|
21207
22030
|
state60.skippedCount = 0;
|
|
21208
22031
|
state60.lastResult = null;
|
|
21209
|
-
state60.hookUnregister =
|
|
22032
|
+
state60.hookUnregister = releaseHandle(state60.hookUnregister);
|
|
21210
22033
|
const cfg = readConfig55(api.config.extensions?.["type-gate"]);
|
|
21211
22034
|
const hook = async (input) => {
|
|
21212
22035
|
if (!cfg.enabled) return;
|