@wrongstack/plugins 0.319.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor.js +21 -4
- package/dist/api-compatibility-gate.js +3 -1
- package/dist/auto-i18n-extractor.js +9 -3
- package/dist/changelog-writer.js +1 -4
- package/dist/checkpoint.js +40 -7
- package/dist/code-metrics.js +3 -1
- package/dist/config-validator.js +6 -2
- package/dist/context-pins.js +4 -1
- package/dist/cost-tracker.js +3 -1
- package/dist/cron.js +8 -2
- package/dist/dep-guard.js +3 -1
- package/dist/dependency-vulnerability-gate.js +3 -1
- package/dist/diff-summary.js +9 -3
- package/dist/doc-sync-guard.js +6 -2
- package/dist/feature-flag-tracker.js +3 -1
- package/dist/format-on-save.js +3 -1
- package/dist/import-organizer.js +3 -1
- package/dist/index.js +351 -152
- package/dist/interface-contract-guard.js +3 -1
- package/dist/knowledge-graph.js +9 -4
- package/dist/license-audit-gate.js +15 -3
- package/dist/migration-planner.js +1 -1
- package/dist/path-guard/index.d.ts +8 -1
- package/dist/path-guard.js +42 -16
- package/dist/pr-drafter.js +3 -1
- package/dist/process-guard.js +3 -1
- package/dist/prompt-firewall.js +16 -6
- package/dist/refactor-suggester.js +3 -1
- package/dist/release-notes-generator.js +1 -1
- package/dist/runtime/credential-patterns.d.ts +2 -2
- package/dist/runtime/h1-state.d.ts +2 -2
- package/dist/runtime/handles.d.ts +2 -2
- package/dist/runtime/index.d.ts +19 -2
- package/dist/runtime/llm.d.ts +2 -2
- package/dist/runtime/redos-guard.d.ts +2 -2
- package/dist/runtime/sandbox.d.ts +2 -2
- package/dist/secret-scanner.js +1 -1
- package/dist/security-hotspot-scanner.js +21 -3
- package/dist/semantic-search-indexer.js +12 -7
- package/dist/semver-bump.js +17 -12
- package/dist/shell-check.js +7 -10
- package/dist/smart-rename.js +8 -6
- package/dist/spec-linker.js +3 -1
- package/dist/template-engine.js +18 -12
- package/dist/test-flake-detector.js +1 -4
- package/dist/test-generator.js +4 -2
- package/dist/test-runner-gate.js +27 -15
- package/dist/type-gate.js +3 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -175,7 +175,12 @@ async function auditFile(filePath, projectRoot) {
|
|
|
175
175
|
);
|
|
176
176
|
}
|
|
177
177
|
if (!hasPrimaryLabel && ATTR_PLACEHOLDER.test(tag)) {
|
|
178
|
-
add(
|
|
178
|
+
add(
|
|
179
|
+
lineNo,
|
|
180
|
+
"low-contrast-placeholder",
|
|
181
|
+
"warning",
|
|
182
|
+
"<input> uses placeholder text (often low contrast and disappears on input)"
|
|
183
|
+
);
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
TAG_INPUT.lastIndex = 0;
|
|
@@ -186,14 +191,24 @@ async function auditFile(filePath, projectRoot) {
|
|
|
186
191
|
const hasAriaLabel = ATTR_ARIA_LABEL.test(tag);
|
|
187
192
|
const hasTitle = ATTR_TITLE.test(tag);
|
|
188
193
|
if (!hasText && !hasAriaLabel && !hasTitle) {
|
|
189
|
-
add(
|
|
194
|
+
add(
|
|
195
|
+
lineNo,
|
|
196
|
+
"missing-button-text",
|
|
197
|
+
"error",
|
|
198
|
+
"<button> has no visible text or accessible label"
|
|
199
|
+
);
|
|
190
200
|
}
|
|
191
201
|
}
|
|
192
202
|
TAG_BUTTON.lastIndex = 0;
|
|
193
203
|
for (const inputButtonMatch of line.matchAll(INPUT_BUTTON)) {
|
|
194
204
|
const tag = inputButtonMatch[0];
|
|
195
205
|
if (!ATTR_VALUE.test(tag) && !ATTR_ARIA_LABEL.test(tag) && !ATTR_TITLE.test(tag)) {
|
|
196
|
-
add(
|
|
206
|
+
add(
|
|
207
|
+
lineNo,
|
|
208
|
+
"missing-button-text",
|
|
209
|
+
"error",
|
|
210
|
+
`<input type="${inputButtonMatch[1]}"> is missing value/aria-label/title`
|
|
211
|
+
);
|
|
197
212
|
}
|
|
198
213
|
}
|
|
199
214
|
INPUT_BUTTON.lastIndex = 0;
|
|
@@ -328,7 +343,9 @@ var plugin = {
|
|
|
328
343
|
}
|
|
329
344
|
return { additionalContext: summary };
|
|
330
345
|
};
|
|
331
|
-
state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
346
|
+
state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
347
|
+
background: true
|
|
348
|
+
});
|
|
332
349
|
api.tools.register({
|
|
333
350
|
name: "a11y_audit",
|
|
334
351
|
description: "Audit a file or directory for accessibility issues. Scans .tsx/.jsx/.html/.vue files for missing alt text, missing labels, low-contrast placeholders, missing button text, and duplicate ids.",
|
|
@@ -1058,7 +1075,9 @@ var plugin3 = {
|
|
|
1058
1075
|
}
|
|
1059
1076
|
return { additionalContext: message };
|
|
1060
1077
|
};
|
|
1061
|
-
state3.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
1078
|
+
state3.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
1079
|
+
background: true
|
|
1080
|
+
});
|
|
1062
1081
|
api.tools.register({
|
|
1063
1082
|
name: "api_compat_status",
|
|
1064
1083
|
description: "Reports api-compatibility-gate state: severity, entry-point patterns, and per-session counters.",
|
|
@@ -1760,7 +1779,9 @@ function looksLikeUserText(value, minLength) {
|
|
|
1760
1779
|
if (value.length < minLength) return false;
|
|
1761
1780
|
if (/^\s*$/.test(value)) return false;
|
|
1762
1781
|
if (/^[0-9\s\W_]+$/.test(value)) return false;
|
|
1763
|
-
if (/^(https?:|ftp:|www\.|\/|\.\/|@|#[0-9a-f]{3,8}$|\.?(jsx?|tsx?|vue|css|scss|json|png|svg|jpg)$)/i.test(
|
|
1782
|
+
if (/^(https?:|ftp:|www\.|\/|\.\/|@|#[0-9a-f]{3,8}$|\.?(jsx?|tsx?|vue|css|scss|json|png|svg|jpg)$)/i.test(
|
|
1783
|
+
value
|
|
1784
|
+
)) {
|
|
1764
1785
|
return false;
|
|
1765
1786
|
}
|
|
1766
1787
|
return true;
|
|
@@ -1768,7 +1789,9 @@ function looksLikeUserText(value, minLength) {
|
|
|
1768
1789
|
function isExcludedContext(line, quoteIndex, excludeAttributes) {
|
|
1769
1790
|
const before = line.slice(0, quoteIndex);
|
|
1770
1791
|
for (const attr of excludeAttributes) {
|
|
1771
|
-
const re = new RegExp(
|
|
1792
|
+
const re = new RegExp(
|
|
1793
|
+
`\\b${attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=\\s*(?:\\{\\s*)?["']?$`
|
|
1794
|
+
);
|
|
1772
1795
|
if (re.test(before)) return true;
|
|
1773
1796
|
}
|
|
1774
1797
|
return false;
|
|
@@ -1900,7 +1923,9 @@ var plugin6 = {
|
|
|
1900
1923
|
${lines.join("\n")}${more}`;
|
|
1901
1924
|
return { additionalContext: context };
|
|
1902
1925
|
};
|
|
1903
|
-
state6.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
1926
|
+
state6.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
1927
|
+
background: true
|
|
1928
|
+
});
|
|
1904
1929
|
api.tools.register({
|
|
1905
1930
|
name: "i18n_extract",
|
|
1906
1931
|
description: "Scan a UI source file (.tsx/.jsx/.vue) for hardcoded user-facing string literals and return suggested i18n keys.",
|
|
@@ -2710,10 +2735,7 @@ var plugin8 = {
|
|
|
2710
2735
|
}
|
|
2711
2736
|
const rawInput = input ?? {};
|
|
2712
2737
|
const shouldPolish = input.polish === true || rawInput["use_llm"] === true || rawInput["useLlm"] === true || rawInput["ai"] === true || rawInput["use_ai"] === true;
|
|
2713
|
-
const block = await maybePolish(
|
|
2714
|
-
renderUnreleasedBlock(state8.entries),
|
|
2715
|
-
shouldPolish
|
|
2716
|
-
);
|
|
2738
|
+
const block = await maybePolish(renderUnreleasedBlock(state8.entries), shouldPolish);
|
|
2717
2739
|
let existing = null;
|
|
2718
2740
|
try {
|
|
2719
2741
|
existing = readFileSync3(cfg.filePath, "utf-8");
|
|
@@ -2783,7 +2805,7 @@ var plugin8 = {
|
|
|
2783
2805
|
var changelog_writer_default = plugin8;
|
|
2784
2806
|
|
|
2785
2807
|
// src/checkpoint/index.ts
|
|
2786
|
-
import { mkdir, readFile as readFile3, stat, writeFile } from "node:fs/promises";
|
|
2808
|
+
import { mkdir, readFile as readFile3, realpath, stat, writeFile } from "node:fs/promises";
|
|
2787
2809
|
import { dirname as dirname2, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve5 } from "node:path";
|
|
2788
2810
|
var state9 = {
|
|
2789
2811
|
snapshots: [],
|
|
@@ -2812,13 +2834,46 @@ function readConfig8(raw) {
|
|
|
2812
2834
|
maxFileBytes: typeof r["maxFileBytes"] === "number" && r["maxFileBytes"] >= 1024 ? r["maxFileBytes"] : DEFAULTS8.maxFileBytes
|
|
2813
2835
|
};
|
|
2814
2836
|
}
|
|
2815
|
-
function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2837
|
+
async function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2816
2838
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
2817
2839
|
const root = resolve5(cwd);
|
|
2818
2840
|
const resolved = isAbsolute5(rawPath) ? resolve5(rawPath) : resolve5(root, rawPath);
|
|
2819
2841
|
const rel = relative5(root, resolved);
|
|
2820
|
-
|
|
2821
|
-
return null;
|
|
2842
|
+
const lexicallyInside = rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
|
|
2843
|
+
if (!lexicallyInside) return null;
|
|
2844
|
+
if (await realResolutionEscapes(resolved, root)) return null;
|
|
2845
|
+
return resolved;
|
|
2846
|
+
}
|
|
2847
|
+
async function realResolutionEscapes(absPath, root) {
|
|
2848
|
+
let real;
|
|
2849
|
+
try {
|
|
2850
|
+
real = await realpath(absPath);
|
|
2851
|
+
} catch {
|
|
2852
|
+
let current = dirname2(absPath);
|
|
2853
|
+
let hops = 0;
|
|
2854
|
+
while (hops < 64 && !await pathExists(current)) {
|
|
2855
|
+
const parent = dirname2(current);
|
|
2856
|
+
if (parent === current) return false;
|
|
2857
|
+
current = parent;
|
|
2858
|
+
hops++;
|
|
2859
|
+
}
|
|
2860
|
+
if (!await pathExists(current)) return false;
|
|
2861
|
+
try {
|
|
2862
|
+
real = await realpath(current);
|
|
2863
|
+
} catch {
|
|
2864
|
+
return false;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
const realRel = relative5(root, real);
|
|
2868
|
+
return realRel !== "" && realRel !== "." && (realRel.startsWith("..") || isAbsolute5(realRel));
|
|
2869
|
+
}
|
|
2870
|
+
async function pathExists(p) {
|
|
2871
|
+
try {
|
|
2872
|
+
await stat(p);
|
|
2873
|
+
return true;
|
|
2874
|
+
} catch {
|
|
2875
|
+
return false;
|
|
2876
|
+
}
|
|
2822
2877
|
}
|
|
2823
2878
|
function hashContent(s) {
|
|
2824
2879
|
const cap = Math.min(s.length, 65536);
|
|
@@ -2919,7 +2974,7 @@ var plugin9 = {
|
|
|
2919
2974
|
const ti = input.toolInput ?? {};
|
|
2920
2975
|
const raw = ti["path"] ?? ti["file_path"] ?? ti["filePath"] ?? ti["TargetFile"] ?? ti["targetFile"] ?? ti["file"];
|
|
2921
2976
|
if (typeof raw !== "string" || raw.length === 0) return;
|
|
2922
|
-
const safePath = resolveProjectPath3(raw);
|
|
2977
|
+
const safePath = await resolveProjectPath3(raw);
|
|
2923
2978
|
if (!safePath) return;
|
|
2924
2979
|
const captured = await captureFileForHook(safePath, cfg.maxFileBytes, runtime.signal);
|
|
2925
2980
|
if (captured === "too-large") {
|
|
@@ -2990,7 +3045,7 @@ var plugin9 = {
|
|
|
2990
3045
|
const rejectedOutsideProject = [];
|
|
2991
3046
|
let skipped = 0;
|
|
2992
3047
|
for (const p of paths) {
|
|
2993
|
-
const safePath = resolveProjectPath3(p);
|
|
3048
|
+
const safePath = await resolveProjectPath3(p);
|
|
2994
3049
|
if (!safePath) {
|
|
2995
3050
|
rejectedOutsideProject.push(p);
|
|
2996
3051
|
continue;
|
|
@@ -3097,7 +3152,7 @@ var plugin9 = {
|
|
|
3097
3152
|
error: rawId ? `no snapshot with id "${rawId}"` : "no snapshots captured yet"
|
|
3098
3153
|
};
|
|
3099
3154
|
}
|
|
3100
|
-
const targetPath = rawPath ? resolveProjectPath3(rawPath) ?? rawPath : null;
|
|
3155
|
+
const targetPath = rawPath ? await resolveProjectPath3(rawPath) ?? rawPath : null;
|
|
3101
3156
|
const targets = targetPath ? snapshot.files.filter((f) => f.path === targetPath || f.path === rawPath) : snapshot.files;
|
|
3102
3157
|
if (targets.length === 0) {
|
|
3103
3158
|
return { ok: false, error: `snapshot ${snapshot.id} has no entry for "${rawPath}"` };
|
|
@@ -3403,7 +3458,9 @@ var plugin10 = {
|
|
|
3403
3458
|
\u{1F4CA} code-metrics: ${relativePath(resolved)} \u2014 ${metrics.lines} lines (${metrics.codeLines} code, ${metrics.commentLines} comments, ${metrics.blankLines} blank), ${metrics.functionCount} function(s), complexity ${metrics.complexity}.`
|
|
3404
3459
|
};
|
|
3405
3460
|
};
|
|
3406
|
-
state10.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
3461
|
+
state10.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
3462
|
+
background: true
|
|
3463
|
+
});
|
|
3407
3464
|
api.tools.register({
|
|
3408
3465
|
name: "measure_code_metrics",
|
|
3409
3466
|
description: "Measure lines, comments, blank lines, function count, and cyclomatic-complexity-like score for a source file or directory.",
|
|
@@ -3920,7 +3977,9 @@ function readConfig11(raw) {
|
|
|
3920
3977
|
const rawMax = r["maxFileBytes"] ?? r["max_file_bytes"] ?? r["maxBytes"] ?? r["max_bytes"];
|
|
3921
3978
|
return {
|
|
3922
3979
|
enabled: r["enabled"] !== false,
|
|
3923
|
-
extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map(
|
|
3980
|
+
extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map(
|
|
3981
|
+
(e) => e.trim().startsWith(".") ? e.trim().toLowerCase() : `.${e.trim().toLowerCase()}`
|
|
3982
|
+
) : [...DEFAULT_EXTENSIONS],
|
|
3924
3983
|
maxFileBytes: typeof rawMax === "number" && rawMax >= 1024 ? rawMax : DEFAULTS11.maxFileBytes
|
|
3925
3984
|
};
|
|
3926
3985
|
}
|
|
@@ -4214,7 +4273,9 @@ var plugin12 = {
|
|
|
4214
4273
|
\u2026 and ${problems.length - 10} more` : "") + "\nFix these before moving on \u2014 downstream tools will fail on this file."
|
|
4215
4274
|
};
|
|
4216
4275
|
};
|
|
4217
|
-
state12.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
4276
|
+
state12.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
4277
|
+
background: true
|
|
4278
|
+
});
|
|
4218
4279
|
api.tools.register({
|
|
4219
4280
|
name: "config_validator_status",
|
|
4220
4281
|
description: "Reports config-validator state: watched extensions and counters (files checked, problems found).",
|
|
@@ -4335,7 +4396,10 @@ async function persistPins(filePath) {
|
|
|
4335
4396
|
if (!filePath) return true;
|
|
4336
4397
|
try {
|
|
4337
4398
|
await ensureDir(dirname3(filePath));
|
|
4338
|
-
await atomicWrite(
|
|
4399
|
+
await atomicWrite(
|
|
4400
|
+
filePath,
|
|
4401
|
+
JSON.stringify({ pins: state13.pins, nextId: state13.nextId }, null, 2)
|
|
4402
|
+
);
|
|
4339
4403
|
return true;
|
|
4340
4404
|
} catch {
|
|
4341
4405
|
state13.persistErrors += 1;
|
|
@@ -4707,7 +4771,9 @@ var plugin14 = {
|
|
|
4707
4771
|
const rawCacheWrite = Number(u["cacheWrite"] ?? u["cache_creation_input_tokens"] ?? 0) || 0;
|
|
4708
4772
|
const freshTokens = rawInput + rawCacheWrite;
|
|
4709
4773
|
const promptTokens = freshTokens + cachedTokens;
|
|
4710
|
-
const completionTokens = Number(
|
|
4774
|
+
const completionTokens = Number(
|
|
4775
|
+
u["output"] ?? u["completion_tokens"] ?? u["outputTokens"] ?? u["completionTokens"] ?? 0
|
|
4776
|
+
) || 0;
|
|
4711
4777
|
const totalTokens = promptTokens + completionTokens;
|
|
4712
4778
|
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
4713
4779
|
const record = {
|
|
@@ -5073,8 +5139,14 @@ var plugin15 = {
|
|
|
5073
5139
|
type: "object",
|
|
5074
5140
|
properties: {
|
|
5075
5141
|
name: { type: "string", description: "Unique name for this cron job" },
|
|
5076
|
-
intervalMs: {
|
|
5077
|
-
|
|
5142
|
+
intervalMs: {
|
|
5143
|
+
type: "number",
|
|
5144
|
+
description: "Interval between runs in milliseconds (minimum 1000)"
|
|
5145
|
+
},
|
|
5146
|
+
action: {
|
|
5147
|
+
type: "string",
|
|
5148
|
+
description: "Action identifier or description of what to run"
|
|
5149
|
+
},
|
|
5078
5150
|
enabled: { type: "boolean", default: true }
|
|
5079
5151
|
},
|
|
5080
5152
|
required: ["name", "intervalMs", "action"]
|
|
@@ -5602,7 +5674,9 @@ function parseInstallCommands(command) {
|
|
|
5602
5674
|
if (!cleaned) continue;
|
|
5603
5675
|
let name = cleaned;
|
|
5604
5676
|
let version = null;
|
|
5605
|
-
const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
|
|
5677
|
+
const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
|
|
5678
|
+
cleaned
|
|
5679
|
+
);
|
|
5606
5680
|
if (pipMatch?.[1]) {
|
|
5607
5681
|
name = pipMatch[1];
|
|
5608
5682
|
const op = pipMatch[2] ?? "";
|
|
@@ -6520,8 +6594,12 @@ var plugin19 = {
|
|
|
6520
6594
|
return;
|
|
6521
6595
|
}
|
|
6522
6596
|
const oldStr = String(inp["old_string"] ?? inp["TargetContent"] ?? inp["oldContent"] ?? "");
|
|
6523
|
-
const newStr = String(
|
|
6524
|
-
|
|
6597
|
+
const newStr = String(
|
|
6598
|
+
inp["new_string"] ?? inp["ReplacementContent"] ?? inp["newContent"] ?? ""
|
|
6599
|
+
);
|
|
6600
|
+
const contentStr = String(
|
|
6601
|
+
inp["content"] ?? inp["CodeContent"] ?? inp["code"] ?? inp["text"] ?? inp["contents"] ?? inp["body"] ?? ""
|
|
6602
|
+
);
|
|
6525
6603
|
const toolInputForHash = oldStr || newStr ? `${oldStr}:::${newStr}` : contentStr;
|
|
6526
6604
|
const now = Date.now();
|
|
6527
6605
|
const memo = pathMemo.get(filePath);
|
|
@@ -6576,7 +6654,9 @@ var plugin19 = {
|
|
|
6576
6654
|
additionalContext: header + summary
|
|
6577
6655
|
};
|
|
6578
6656
|
};
|
|
6579
|
-
state18.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6657
|
+
state18.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6658
|
+
background: true
|
|
6659
|
+
});
|
|
6580
6660
|
api.tools.register({
|
|
6581
6661
|
name: "diff_summary_status",
|
|
6582
6662
|
description: "Reports diff-summary state: mode, maxLines, and per-session invocation/injected/fallback counters.",
|
|
@@ -6804,7 +6884,9 @@ var plugin20 = {
|
|
|
6804
6884
|
}
|
|
6805
6885
|
}
|
|
6806
6886
|
if (!content || state19.changedFiles.length === 0) return;
|
|
6807
|
-
const missing = state19.changedFiles.filter(
|
|
6887
|
+
const missing = state19.changedFiles.filter(
|
|
6888
|
+
(changedPath) => !isReferenced(changedPath, content)
|
|
6889
|
+
);
|
|
6808
6890
|
if (missing.length === 0) return;
|
|
6809
6891
|
state19.warningsIssued += 1;
|
|
6810
6892
|
const missingList = missing.map((p) => ` - ${p}`).join("\n");
|
|
@@ -6815,7 +6897,9 @@ Consider mentioning these changes in the documentation.`;
|
|
|
6815
6897
|
return { additionalContext: message };
|
|
6816
6898
|
}
|
|
6817
6899
|
};
|
|
6818
|
-
state19.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6900
|
+
state19.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6901
|
+
background: true
|
|
6902
|
+
});
|
|
6819
6903
|
api.tools.register({
|
|
6820
6904
|
name: "doc_sync_status",
|
|
6821
6905
|
description: "Reports doc-sync-guard state: tracked changed files, doc-write count, and warning count.",
|
|
@@ -6880,7 +6964,7 @@ Consider mentioning these changes in the documentation.`;
|
|
|
6880
6964
|
var doc_sync_guard_default = plugin20;
|
|
6881
6965
|
|
|
6882
6966
|
// src/duplicate-code-detector/index.ts
|
|
6883
|
-
import { readFile as readFile6, realpath, stat as stat3 } from "node:fs/promises";
|
|
6967
|
+
import { readFile as readFile6, realpath as realpath2, stat as stat3 } from "node:fs/promises";
|
|
6884
6968
|
import { extname as extname4, isAbsolute as isAbsolute8, relative as relative9, resolve as resolve9, sep } from "node:path";
|
|
6885
6969
|
var API_VERSION14 = "^0.1.10";
|
|
6886
6970
|
var HOOK_WARNING_COOLDOWN_MS = 6e4;
|
|
@@ -7239,7 +7323,7 @@ var plugin21 = {
|
|
|
7239
7323
|
if (!isWithinRoot(projectRoot, resolvedFile)) return;
|
|
7240
7324
|
let changedFile;
|
|
7241
7325
|
try {
|
|
7242
|
-
changedFile = await
|
|
7326
|
+
changedFile = await realpath2(resolvedFile);
|
|
7243
7327
|
} catch {
|
|
7244
7328
|
state20.errorCount += 1;
|
|
7245
7329
|
return;
|
|
@@ -7908,7 +7992,9 @@ var plugin23 = {
|
|
|
7908
7992
|
Make sure flag behavior is intentional and consider updating flag inventory/docs.`
|
|
7909
7993
|
};
|
|
7910
7994
|
};
|
|
7911
|
-
state22.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
7995
|
+
state22.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
7996
|
+
background: true
|
|
7997
|
+
});
|
|
7912
7998
|
api.tools.register({
|
|
7913
7999
|
name: "scan_feature_flags",
|
|
7914
8000
|
description: "Scan source files for feature-flag-like expressions (isFeatureEnabled, featureFlags.*, useFeatureFlag, flags.*, plus custom patterns).",
|
|
@@ -8678,7 +8764,9 @@ var plugin25 = {
|
|
|
8678
8764
|
state23.cleanCount += 1;
|
|
8679
8765
|
return;
|
|
8680
8766
|
};
|
|
8681
|
-
state23.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
8767
|
+
state23.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
8768
|
+
background: true
|
|
8769
|
+
});
|
|
8682
8770
|
state23.patternUnregister = api.onPattern(
|
|
8683
8771
|
"import-organizer:done",
|
|
8684
8772
|
(_eventName, payload) => {
|
|
@@ -9475,7 +9563,7 @@ function classifyArtifact(relPath, patterns) {
|
|
|
9475
9563
|
}
|
|
9476
9564
|
return null;
|
|
9477
9565
|
}
|
|
9478
|
-
async function
|
|
9566
|
+
async function pathExists2(p) {
|
|
9479
9567
|
try {
|
|
9480
9568
|
await access3(p);
|
|
9481
9569
|
return true;
|
|
@@ -9484,7 +9572,7 @@ async function pathExists(p) {
|
|
|
9484
9572
|
}
|
|
9485
9573
|
}
|
|
9486
9574
|
async function readGitignoreLines(file) {
|
|
9487
|
-
if (!await
|
|
9575
|
+
if (!await pathExists2(file)) return [];
|
|
9488
9576
|
try {
|
|
9489
9577
|
const content = await readFile9(file, "utf8");
|
|
9490
9578
|
return content.split(/\r?\n/);
|
|
@@ -9516,7 +9604,7 @@ function relDirOf(rel) {
|
|
|
9516
9604
|
}
|
|
9517
9605
|
async function firstExistingGitignore(candidates) {
|
|
9518
9606
|
for (const c of candidates) {
|
|
9519
|
-
if (await
|
|
9607
|
+
if (await pathExists2(c)) return c;
|
|
9520
9608
|
}
|
|
9521
9609
|
return null;
|
|
9522
9610
|
}
|
|
@@ -9527,7 +9615,7 @@ async function appendPatterns(target, patterns, limit) {
|
|
|
9527
9615
|
);
|
|
9528
9616
|
const missing = patterns.filter((p) => !seen.has(p)).slice(0, limit);
|
|
9529
9617
|
if (missing.length === 0) return { appended: [] };
|
|
9530
|
-
const current = await
|
|
9618
|
+
const current = await pathExists2(target) ? await readFile9(target, "utf8") : "";
|
|
9531
9619
|
const base = current.length === 0 ? "" : current.endsWith("\n") ? current : `${current}
|
|
9532
9620
|
`;
|
|
9533
9621
|
const next = `${base}${missing.map((p) => `${p}
|
|
@@ -10187,7 +10275,9 @@ ${result.stderr.trim()}`
|
|
|
10187
10275
|
}
|
|
10188
10276
|
return;
|
|
10189
10277
|
};
|
|
10190
|
-
state25.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10278
|
+
state25.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10279
|
+
background: true
|
|
10280
|
+
});
|
|
10191
10281
|
api.tools.register({
|
|
10192
10282
|
name: "import_organizer_status",
|
|
10193
10283
|
description: "Reports import-organizer state: linter availability, config, and per-session organized/clean/error counters.",
|
|
@@ -10678,7 +10768,9 @@ var plugin30 = {
|
|
|
10678
10768
|
If you changed member shapes, search the project for implementers/\`satisfies\`/\`as\` usages and update them accordingly.`
|
|
10679
10769
|
};
|
|
10680
10770
|
};
|
|
10681
|
-
state27.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10771
|
+
state27.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10772
|
+
background: true
|
|
10773
|
+
});
|
|
10682
10774
|
api.tools.register({
|
|
10683
10775
|
name: "check_interface_contracts",
|
|
10684
10776
|
description: "Scan TypeScript files for interface declarations that have no visible implementer (implements / as / satisfies).",
|
|
@@ -11030,9 +11122,12 @@ var plugin31 = {
|
|
|
11030
11122
|
const hasMatch = f.subject.toLowerCase().includes(q) || f.relation.toLowerCase().includes(q) || f.object.toLowerCase().includes(q);
|
|
11031
11123
|
if (!hasMatch) return false;
|
|
11032
11124
|
}
|
|
11033
|
-
if (input.subject && !f.subject.toLowerCase().includes(input.subject.toLowerCase()))
|
|
11034
|
-
|
|
11035
|
-
if (input.
|
|
11125
|
+
if (input.subject && !f.subject.toLowerCase().includes(input.subject.toLowerCase()))
|
|
11126
|
+
return false;
|
|
11127
|
+
if (input.relation && !f.relation.toLowerCase().includes(input.relation.toLowerCase()))
|
|
11128
|
+
return false;
|
|
11129
|
+
if (input.object && !f.object.toLowerCase().includes(input.object.toLowerCase()))
|
|
11130
|
+
return false;
|
|
11036
11131
|
if (filterConf && f.confidence.toLowerCase() !== filterConf) return false;
|
|
11037
11132
|
return true;
|
|
11038
11133
|
});
|
|
@@ -11064,7 +11159,9 @@ var plugin31 = {
|
|
|
11064
11159
|
const raw = input ?? {};
|
|
11065
11160
|
const rawId = String(input.id ?? raw["factId"] ?? raw["fact_id"] ?? "").trim();
|
|
11066
11161
|
const normalized = rawId.toLowerCase().startsWith("kg-") ? rawId.toLowerCase() : `kg-${rawId.toLowerCase()}`;
|
|
11067
|
-
state28.facts = state28.facts.filter(
|
|
11162
|
+
state28.facts = state28.facts.filter(
|
|
11163
|
+
(f) => f.id.toLowerCase() !== normalized && f.id !== rawId
|
|
11164
|
+
);
|
|
11068
11165
|
const removed = before - state28.facts.length;
|
|
11069
11166
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id ?? rawId}"` };
|
|
11070
11167
|
state28.removals += removed;
|
|
@@ -11160,7 +11257,15 @@ var state29 = {
|
|
|
11160
11257
|
};
|
|
11161
11258
|
var DEFAULTS27 = {
|
|
11162
11259
|
enabled: true,
|
|
11163
|
-
allowedLicenses: [
|
|
11260
|
+
allowedLicenses: [
|
|
11261
|
+
"MIT",
|
|
11262
|
+
"Apache-2.0",
|
|
11263
|
+
"BSD-2-Clause",
|
|
11264
|
+
"BSD-3-Clause",
|
|
11265
|
+
"ISC",
|
|
11266
|
+
"0BSD",
|
|
11267
|
+
"Unlicense"
|
|
11268
|
+
],
|
|
11164
11269
|
block: true
|
|
11165
11270
|
};
|
|
11166
11271
|
function normalizeStrings(v) {
|
|
@@ -11199,7 +11304,9 @@ function extractLicenseStrings(pkg) {
|
|
|
11199
11304
|
}
|
|
11200
11305
|
function parsePackageNames(command) {
|
|
11201
11306
|
return [
|
|
11202
|
-
...new Set(
|
|
11307
|
+
...new Set(
|
|
11308
|
+
parseInstallCommands(command).flatMap((entry) => entry.packages.map((pkg) => pkg.name))
|
|
11309
|
+
)
|
|
11203
11310
|
];
|
|
11204
11311
|
}
|
|
11205
11312
|
function splitTopLevel(expr, separator) {
|
|
@@ -12707,7 +12814,7 @@ import {
|
|
|
12707
12814
|
runOptionalPluginCouncil,
|
|
12708
12815
|
runOptionalPluginLlm,
|
|
12709
12816
|
stripOuterMarkdownFence
|
|
12710
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
12817
|
+
} from "@wrongstack/plugin-sdk/runtime/llm";
|
|
12711
12818
|
|
|
12712
12819
|
// src/migration-planner/index.ts
|
|
12713
12820
|
var API_VERSION25 = "^0.1.10";
|
|
@@ -13959,11 +14066,15 @@ var plugin38 = {
|
|
|
13959
14066
|
};
|
|
13960
14067
|
var notify_hub_default = plugin38;
|
|
13961
14068
|
|
|
14069
|
+
// src/path-guard/index.ts
|
|
14070
|
+
import { existsSync as existsSync6, realpathSync } from "node:fs";
|
|
14071
|
+
import { dirname as dirname6, resolve as resolve17 } from "node:path";
|
|
14072
|
+
|
|
13962
14073
|
// src/runtime/redos-guard.ts
|
|
13963
14074
|
import {
|
|
13964
14075
|
withReDoSGuard,
|
|
13965
14076
|
guardedMatcher
|
|
13966
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
14077
|
+
} from "@wrongstack/plugin-sdk/runtime/redos-guard";
|
|
13967
14078
|
|
|
13968
14079
|
// src/path-guard/glob.ts
|
|
13969
14080
|
var GLOB_REDOS_BUDGET_MS = 250;
|
|
@@ -15249,17 +15360,32 @@ function operationLabel(toolName) {
|
|
|
15249
15360
|
}
|
|
15250
15361
|
|
|
15251
15362
|
// src/path-guard/index.ts
|
|
15252
|
-
import { realpathSync } from "node:fs";
|
|
15253
|
-
import { resolve as resolve17 } from "node:path";
|
|
15254
15363
|
function isSymlinkEscape(path, cwd) {
|
|
15255
15364
|
if (!(0, runtime_exports.withinProject)(path)) return false;
|
|
15365
|
+
const abs = resolve17(cwd ?? process.cwd(), path);
|
|
15366
|
+
let real;
|
|
15256
15367
|
try {
|
|
15257
|
-
|
|
15258
|
-
const real = realpathSync(abs);
|
|
15259
|
-
return !(0, runtime_exports.withinProject)(real);
|
|
15368
|
+
real = realpathSync(abs);
|
|
15260
15369
|
} catch {
|
|
15261
|
-
|
|
15370
|
+
const ancestor = nearestExistingAncestor(abs);
|
|
15371
|
+
if (ancestor === null) return false;
|
|
15372
|
+
try {
|
|
15373
|
+
real = realpathSync(ancestor);
|
|
15374
|
+
} catch {
|
|
15375
|
+
return false;
|
|
15376
|
+
}
|
|
15262
15377
|
}
|
|
15378
|
+
return !(0, runtime_exports.withinProject)(real);
|
|
15379
|
+
}
|
|
15380
|
+
function nearestExistingAncestor(abs) {
|
|
15381
|
+
let current = dirname6(abs);
|
|
15382
|
+
for (let hops = 0; hops < 64; hops++) {
|
|
15383
|
+
if (existsSync6(current)) return current;
|
|
15384
|
+
const parent = dirname6(current);
|
|
15385
|
+
if (parent === current) return null;
|
|
15386
|
+
current = parent;
|
|
15387
|
+
}
|
|
15388
|
+
return null;
|
|
15263
15389
|
}
|
|
15264
15390
|
function createState() {
|
|
15265
15391
|
return {
|
|
@@ -15408,10 +15534,19 @@ var plugin39 = {
|
|
|
15408
15534
|
path: relativeToInvocationCwd(resolveTargetPath(path, effectiveCwd), input.cwd),
|
|
15409
15535
|
kind: isRootPathScope(path) && deletesImplicitScope || isUnresolvedPathScope(path) || recursivelyDeletes && (isDirectoryAmbiguousPath(path) || hasConfiguredProtectedDescendant(path, cfg.protect)) ? "deletion-scope" : "file"
|
|
15410
15536
|
};
|
|
15537
|
+
if (target.kind === "file" && isSymlinkEscape(target.path, input.cwd)) {
|
|
15538
|
+
return target;
|
|
15539
|
+
}
|
|
15411
15540
|
if (targetFullyAllowed(target, cfg.allow, allowRes)) return null;
|
|
15412
|
-
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
15541
|
+
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
15413
15542
|
onTimeout: bumpRedos
|
|
15414
|
-
})
|
|
15543
|
+
}) || await matchesAnyGuarded(
|
|
15544
|
+
`${target.path.replace(/\/$/, "")}/.path-guard-probe`,
|
|
15545
|
+
protectRes,
|
|
15546
|
+
{
|
|
15547
|
+
onTimeout: bumpRedos
|
|
15548
|
+
}
|
|
15549
|
+
);
|
|
15415
15550
|
return protectedShellTarget ? target : null;
|
|
15416
15551
|
})
|
|
15417
15552
|
);
|
|
@@ -15529,7 +15664,7 @@ var plugin39 = {
|
|
|
15529
15664
|
var path_guard_default = plugin39;
|
|
15530
15665
|
|
|
15531
15666
|
// src/performance-regression-gate/index.ts
|
|
15532
|
-
import { existsSync as
|
|
15667
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11 } from "node:fs";
|
|
15533
15668
|
import { isAbsolute as isAbsolute16, relative as relative16, resolve as resolve18 } from "node:path";
|
|
15534
15669
|
var API_VERSION26 = "^0.1.10";
|
|
15535
15670
|
var state36 = {
|
|
@@ -15595,7 +15730,7 @@ function flattenResults(results) {
|
|
|
15595
15730
|
return flat;
|
|
15596
15731
|
}
|
|
15597
15732
|
function loadResults(path) {
|
|
15598
|
-
if (!path || !
|
|
15733
|
+
if (!path || !existsSync7(path)) return null;
|
|
15599
15734
|
try {
|
|
15600
15735
|
const raw = JSON.parse(readFileSync11(path, "utf-8"));
|
|
15601
15736
|
return raw;
|
|
@@ -15993,7 +16128,7 @@ var plugin_stack_observer_default = PLUGIN;
|
|
|
15993
16128
|
// src/pr-drafter/index.ts
|
|
15994
16129
|
import { execFile as execFile9 } from "node:child_process";
|
|
15995
16130
|
import { mkdir as mkdir2, writeFile as writeFile4 } from "node:fs/promises";
|
|
15996
|
-
import { dirname as
|
|
16131
|
+
import { dirname as dirname7, isAbsolute as isAbsolute17, relative as relative17, resolve as resolve19 } from "node:path";
|
|
15997
16132
|
var API_VERSION27 = "^0.1.10";
|
|
15998
16133
|
var state38 = {
|
|
15999
16134
|
commits: [],
|
|
@@ -16125,7 +16260,7 @@ async function writeDraft(cfg, llm) {
|
|
|
16125
16260
|
}
|
|
16126
16261
|
const draft = await buildDraft(cfg, llm);
|
|
16127
16262
|
try {
|
|
16128
|
-
await mkdir2(
|
|
16263
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
16129
16264
|
await writeFile4(resolved, draft.body);
|
|
16130
16265
|
state38.draftsWritten += 1;
|
|
16131
16266
|
} catch {
|
|
@@ -16257,7 +16392,9 @@ var plugin41 = {
|
|
|
16257
16392
|
async execute(input = {}) {
|
|
16258
16393
|
if (!cfg.enabled) return { ok: false, error: "pr-drafter is disabled" };
|
|
16259
16394
|
const raw = input ?? {};
|
|
16260
|
-
const preview = Boolean(
|
|
16395
|
+
const preview = Boolean(
|
|
16396
|
+
input?.preview ?? raw["dryRun"] ?? raw["dry_run"] ?? raw["dry"] ?? raw["previewOnly"]
|
|
16397
|
+
);
|
|
16261
16398
|
const rawOutputPath = raw["outputPath"] ?? raw["output_path"] ?? raw["path"] ?? raw["filePath"] ?? raw["file"] ?? raw["TargetFile"] ?? raw["targetFile"] ?? cfg.outputPath;
|
|
16262
16399
|
const outputPathStr = typeof rawOutputPath === "string" && rawOutputPath.trim().length > 0 ? rawOutputPath.trim() : cfg.outputPath;
|
|
16263
16400
|
const draft = await buildDraft(cfg, api.llm);
|
|
@@ -16267,7 +16404,7 @@ var plugin41 = {
|
|
|
16267
16404
|
const resolved = resolveProjectPath7(outputPathStr);
|
|
16268
16405
|
if (!resolved) return { ok: false, error: "outputPath resolves outside project" };
|
|
16269
16406
|
try {
|
|
16270
|
-
await mkdir2(
|
|
16407
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
16271
16408
|
await writeFile4(resolved, draft.body);
|
|
16272
16409
|
state38.draftsWritten += 1;
|
|
16273
16410
|
return {
|
|
@@ -16406,7 +16543,9 @@ var plugin42 = {
|
|
|
16406
16543
|
const rawCmd = ti["command"] ?? ti["CommandLine"] ?? ti["cmd"] ?? ti["script"] ?? ti["input"];
|
|
16407
16544
|
const command = typeof rawCmd === "string" ? rawCmd : "";
|
|
16408
16545
|
if (!command) return;
|
|
16409
|
-
const isKillRelated = /\b(?:kill|taskkill|stop-process|tskill|pkill|killall|wmic)\b/i.test(
|
|
16546
|
+
const isKillRelated = /\b(?:kill|taskkill|stop-process|tskill|pkill|killall|wmic)\b/i.test(
|
|
16547
|
+
command
|
|
16548
|
+
);
|
|
16410
16549
|
if (!isKillRelated) return;
|
|
16411
16550
|
state39.detections += 1;
|
|
16412
16551
|
state39.lastDetection = {
|
|
@@ -16495,7 +16634,7 @@ import { performance as performance2 } from "node:perf_hooks";
|
|
|
16495
16634
|
import {
|
|
16496
16635
|
cloneCredentialPatterns,
|
|
16497
16636
|
CREDENTIAL_PATTERNS
|
|
16498
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
16637
|
+
} from "@wrongstack/plugin-sdk/runtime/credential-patterns";
|
|
16499
16638
|
|
|
16500
16639
|
// src/prompt-firewall/index.ts
|
|
16501
16640
|
var KIND_ALIASES = {
|
|
@@ -16772,9 +16911,12 @@ function surfaceScanTrips(api, tripped) {
|
|
|
16772
16911
|
}
|
|
16773
16912
|
state40.timeoutCount += 1;
|
|
16774
16913
|
api.metrics.counter("redos_skips", 1);
|
|
16775
|
-
api.log.warn(
|
|
16776
|
-
|
|
16777
|
-
|
|
16914
|
+
api.log.warn(
|
|
16915
|
+
"prompt-firewall: scan-pass budget exceeded \u2014 patterns skipped mid-pass (issue #370)",
|
|
16916
|
+
{
|
|
16917
|
+
skipped: [...tripped]
|
|
16918
|
+
}
|
|
16919
|
+
);
|
|
16778
16920
|
}
|
|
16779
16921
|
var plugin43 = {
|
|
16780
16922
|
name: "prompt-firewall",
|
|
@@ -16876,7 +17018,14 @@ var plugin43 = {
|
|
|
16876
17018
|
if (cfg.mode === "redact") {
|
|
16877
17019
|
const counter = { n: 0 };
|
|
16878
17020
|
const deadline = createScanDeadline();
|
|
16879
|
-
const redactedReq = redactDeep(
|
|
17021
|
+
const redactedReq = redactDeep(
|
|
17022
|
+
req,
|
|
17023
|
+
cfg.allow,
|
|
17024
|
+
counter,
|
|
17025
|
+
skipSet,
|
|
17026
|
+
void 0,
|
|
17027
|
+
deadline
|
|
17028
|
+
);
|
|
16880
17029
|
state40.requestRedactions += counter.n;
|
|
16881
17030
|
api.metrics.counter("request_redactions", counter.n);
|
|
16882
17031
|
if (deadline.tripped.size > 0) surfaceScanTrips(api, deadline.tripped);
|
|
@@ -17273,7 +17422,9 @@ var plugin44 = {
|
|
|
17273
17422
|
contextAs: "separate"
|
|
17274
17423
|
};
|
|
17275
17424
|
};
|
|
17276
|
-
state41.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
17425
|
+
state41.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
17426
|
+
background: true
|
|
17427
|
+
});
|
|
17277
17428
|
api.tools.register({
|
|
17278
17429
|
name: "suggest_refactors",
|
|
17279
17430
|
description: "Scan source files for refactoring smells: long functions, deep nesting, many parameters, magic numbers, and console logging.",
|
|
@@ -18600,7 +18751,19 @@ var DEFAULTS42 = {
|
|
|
18600
18751
|
enabled: false,
|
|
18601
18752
|
severity: "warn",
|
|
18602
18753
|
maxFindings: 10,
|
|
18603
|
-
scanOnChange: [
|
|
18754
|
+
scanOnChange: [
|
|
18755
|
+
".js",
|
|
18756
|
+
".jsx",
|
|
18757
|
+
".ts",
|
|
18758
|
+
".tsx",
|
|
18759
|
+
".mjs",
|
|
18760
|
+
".cjs",
|
|
18761
|
+
".py",
|
|
18762
|
+
".java",
|
|
18763
|
+
".go",
|
|
18764
|
+
".rb",
|
|
18765
|
+
".php"
|
|
18766
|
+
]
|
|
18604
18767
|
};
|
|
18605
18768
|
var scanOnChangeSet = new Set(DEFAULTS42.scanOnChange);
|
|
18606
18769
|
function readConfig44(raw) {
|
|
@@ -18623,7 +18786,11 @@ function readConfig44(raw) {
|
|
|
18623
18786
|
}
|
|
18624
18787
|
var PATTERNS4 = [
|
|
18625
18788
|
{ type: "eval_call", severity: "high", regex: /\beval\s*\(/i },
|
|
18626
|
-
{
|
|
18789
|
+
{
|
|
18790
|
+
type: "function_constructor",
|
|
18791
|
+
severity: "high",
|
|
18792
|
+
regex: /\bnew\s+Function\s*\(|\bFunction\s*\(/i
|
|
18793
|
+
},
|
|
18627
18794
|
{
|
|
18628
18795
|
type: "unsafe_html",
|
|
18629
18796
|
severity: "high",
|
|
@@ -18861,7 +19028,9 @@ Review or remove the risky pattern(s).`;
|
|
|
18861
19028
|
}
|
|
18862
19029
|
return { additionalContext: message };
|
|
18863
19030
|
};
|
|
18864
|
-
state44.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
19031
|
+
state44.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
19032
|
+
background: true
|
|
19033
|
+
});
|
|
18865
19034
|
api.tools.register({
|
|
18866
19035
|
name: "security_hotspot_scan",
|
|
18867
19036
|
description: "Scan a file or directory for security anti-patterns (eval, Function constructor, innerHTML, SQL concatenation, http URLs, credential logging, variable exec commands).",
|
|
@@ -19036,11 +19205,7 @@ var DEFAULTS43 = {
|
|
|
19036
19205
|
".scss",
|
|
19037
19206
|
".html"
|
|
19038
19207
|
],
|
|
19039
|
-
excludePatterns: [
|
|
19040
|
-
...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex),
|
|
19041
|
-
"\\.wrongstack",
|
|
19042
|
-
"\\.temp_files"
|
|
19043
|
-
],
|
|
19208
|
+
excludePatterns: [...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex), "\\.wrongstack", "\\.temp_files"],
|
|
19044
19209
|
maxFileBytes: 1e6,
|
|
19045
19210
|
defaultLimit: 10,
|
|
19046
19211
|
minTokenLength: 2,
|
|
@@ -19048,7 +19213,12 @@ var DEFAULTS43 = {
|
|
|
19048
19213
|
maxFiles: 5e3
|
|
19049
19214
|
};
|
|
19050
19215
|
function readConfig45(raw) {
|
|
19051
|
-
if (!raw || typeof raw !== "object")
|
|
19216
|
+
if (!raw || typeof raw !== "object")
|
|
19217
|
+
return {
|
|
19218
|
+
...DEFAULTS43,
|
|
19219
|
+
includeExtensions: [...DEFAULTS43.includeExtensions],
|
|
19220
|
+
excludePatterns: [...DEFAULTS43.excludePatterns]
|
|
19221
|
+
};
|
|
19052
19222
|
const r = raw;
|
|
19053
19223
|
const rawExts = r["includeExtensions"] ?? r["include_extensions"] ?? r["extensions"] ?? r["file_extensions"];
|
|
19054
19224
|
const includeExtensions = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : [...DEFAULTS43.includeExtensions];
|
|
@@ -19359,7 +19529,11 @@ var plugin49 = {
|
|
|
19359
19529
|
description: "Builds an in-memory keyword index over project source files and answers ranked search queries",
|
|
19360
19530
|
apiVersion: API_VERSION32,
|
|
19361
19531
|
capabilities: { tools: true },
|
|
19362
|
-
defaultConfig: {
|
|
19532
|
+
defaultConfig: {
|
|
19533
|
+
...DEFAULTS43,
|
|
19534
|
+
includeExtensions: [...DEFAULTS43.includeExtensions],
|
|
19535
|
+
excludePatterns: [...DEFAULTS43.excludePatterns]
|
|
19536
|
+
},
|
|
19363
19537
|
configSchema: {
|
|
19364
19538
|
type: "object",
|
|
19365
19539
|
properties: {
|
|
@@ -19644,19 +19818,24 @@ var state46 = {
|
|
|
19644
19818
|
};
|
|
19645
19819
|
function runCommand3(command, args, cwd) {
|
|
19646
19820
|
return new Promise((resolve28, reject) => {
|
|
19647
|
-
execFile11(
|
|
19648
|
-
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19653
|
-
|
|
19654
|
-
|
|
19655
|
-
|
|
19821
|
+
execFile11(
|
|
19822
|
+
command,
|
|
19823
|
+
args,
|
|
19824
|
+
{
|
|
19825
|
+
encoding: "utf-8",
|
|
19826
|
+
cwd,
|
|
19827
|
+
timeout: 3e4,
|
|
19828
|
+
windowsHide: true
|
|
19829
|
+
},
|
|
19830
|
+
(err, stdout, stderr) => {
|
|
19831
|
+
if (!err) {
|
|
19832
|
+
resolve28(stdout.trim());
|
|
19833
|
+
return;
|
|
19834
|
+
}
|
|
19835
|
+
const failure = err;
|
|
19836
|
+
reject(Object.assign(failure, { stderr: stderr || void 0 }));
|
|
19656
19837
|
}
|
|
19657
|
-
|
|
19658
|
-
reject(Object.assign(failure, { stderr: stderr || void 0 }));
|
|
19659
|
-
});
|
|
19838
|
+
);
|
|
19660
19839
|
});
|
|
19661
19840
|
}
|
|
19662
19841
|
async function runGit6(args, cwd) {
|
|
@@ -20704,15 +20883,10 @@ var state48 = {
|
|
|
20704
20883
|
async function runShellCheck(files, severity, cwd) {
|
|
20705
20884
|
try {
|
|
20706
20885
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
20707
|
-
execFile12(
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
(err) => {
|
|
20712
|
-
if (err) rejectPromise(err);
|
|
20713
|
-
else resolvePromise();
|
|
20714
|
-
}
|
|
20715
|
-
);
|
|
20886
|
+
execFile12("shellcheck", ["--version"], { encoding: "utf-8", windowsHide: true }, (err) => {
|
|
20887
|
+
if (err) rejectPromise(err);
|
|
20888
|
+
else resolvePromise();
|
|
20889
|
+
});
|
|
20716
20890
|
});
|
|
20717
20891
|
} catch {
|
|
20718
20892
|
throw new Error(
|
|
@@ -20873,7 +21047,9 @@ var plugin52 = {
|
|
|
20873
21047
|
if (typeof rawFiles === "string" && rawFiles.trim().length > 0) {
|
|
20874
21048
|
files = [rawFiles.trim()];
|
|
20875
21049
|
} else if (Array.isArray(rawFiles)) {
|
|
20876
|
-
files = rawFiles.filter(
|
|
21050
|
+
files = rawFiles.filter(
|
|
21051
|
+
(f) => typeof f === "string" && f.trim().length > 0
|
|
21052
|
+
);
|
|
20877
21053
|
}
|
|
20878
21054
|
}
|
|
20879
21055
|
const rawDirectory = inp.directory ?? input["dir"] ?? input["SearchDirectory"];
|
|
@@ -21018,7 +21194,8 @@ function normalizeExtensions6(exts) {
|
|
|
21018
21194
|
return exts.map((e) => e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`);
|
|
21019
21195
|
}
|
|
21020
21196
|
function readConfig47(raw) {
|
|
21021
|
-
if (!raw || typeof raw !== "object")
|
|
21197
|
+
if (!raw || typeof raw !== "object")
|
|
21198
|
+
return { ...DEFAULTS45, extensions: normalizeExtensions6(DEFAULTS45.extensions) };
|
|
21022
21199
|
const r = raw;
|
|
21023
21200
|
const rawExts = r["extensions"] ?? r["file_extensions"] ?? r["fileExtensions"];
|
|
21024
21201
|
const exts = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : DEFAULTS45.extensions;
|
|
@@ -21051,10 +21228,7 @@ function isIdentifier(name) {
|
|
|
21051
21228
|
return IDENTIFIER_RE2.test(name);
|
|
21052
21229
|
}
|
|
21053
21230
|
function renameInContent(content, oldName, newName) {
|
|
21054
|
-
const re = new RegExp(
|
|
21055
|
-
`(?<![A-Za-z0-9_$])${escapeRegex2(oldName)}(?![A-Za-z0-9_$])`,
|
|
21056
|
-
"g"
|
|
21057
|
-
);
|
|
21231
|
+
const re = new RegExp(`(?<![A-Za-z0-9_$])${escapeRegex2(oldName)}(?![A-Za-z0-9_$])`, "g");
|
|
21058
21232
|
let replacements = 0;
|
|
21059
21233
|
const preview = content.replace(re, () => {
|
|
21060
21234
|
replacements++;
|
|
@@ -21095,7 +21269,11 @@ var plugin53 = {
|
|
|
21095
21269
|
path: { type: "string", description: "Source file path (relative to project root)." },
|
|
21096
21270
|
oldName: { type: "string", description: "Identifier to replace." },
|
|
21097
21271
|
newName: { type: "string", description: "New identifier." },
|
|
21098
|
-
apply: {
|
|
21272
|
+
apply: {
|
|
21273
|
+
type: "boolean",
|
|
21274
|
+
default: false,
|
|
21275
|
+
description: "When true, write the preview back to disk."
|
|
21276
|
+
}
|
|
21099
21277
|
},
|
|
21100
21278
|
required: ["path", "oldName", "newName"]
|
|
21101
21279
|
},
|
|
@@ -21612,7 +21790,9 @@ var plugin54 = {
|
|
|
21612
21790
|
${lines}${overflowNote}`
|
|
21613
21791
|
};
|
|
21614
21792
|
};
|
|
21615
|
-
state50.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, {
|
|
21793
|
+
state50.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, {
|
|
21794
|
+
background: true
|
|
21795
|
+
});
|
|
21616
21796
|
if (cfg.autoFix) {
|
|
21617
21797
|
const preHook = async (input) => {
|
|
21618
21798
|
if (!cfg.enabled) return;
|
|
@@ -21756,21 +21936,27 @@ function expandTemplate(template, variables) {
|
|
|
21756
21936
|
return result;
|
|
21757
21937
|
}
|
|
21758
21938
|
function expandConditionals(template, variables) {
|
|
21759
|
-
return template.replace(
|
|
21760
|
-
|
|
21761
|
-
|
|
21762
|
-
|
|
21939
|
+
return template.replace(
|
|
21940
|
+
/\{\{#if\s+([\w.-]+)\s*\}\}([\s\S]*?)\{\{\/if\}\}/g,
|
|
21941
|
+
(_, key, content) => {
|
|
21942
|
+
const val = variables[key];
|
|
21943
|
+
return val !== void 0 && val !== "" && val !== "false" && val !== "0" ? content : "";
|
|
21944
|
+
}
|
|
21945
|
+
);
|
|
21763
21946
|
}
|
|
21764
21947
|
function expandLoops(template, variables) {
|
|
21765
|
-
return template.replace(
|
|
21766
|
-
|
|
21767
|
-
|
|
21768
|
-
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
|
|
21772
|
-
|
|
21773
|
-
|
|
21948
|
+
return template.replace(
|
|
21949
|
+
/\{\{#each\s+([\w.-]+)\s*\}\}([\s\S]*?)\{\{\/each\}\}/g,
|
|
21950
|
+
(_, key, content) => {
|
|
21951
|
+
const val = variables[key];
|
|
21952
|
+
if (!val) return "";
|
|
21953
|
+
if (typeof val === "string" && val.includes(",")) {
|
|
21954
|
+
const items = val.split(",").map((s) => s.trim());
|
|
21955
|
+
return items.map((item) => expandTemplate(content, { ...variables, [key]: item, item })).join("\n");
|
|
21956
|
+
}
|
|
21957
|
+
return expandTemplate(content, variables);
|
|
21958
|
+
}
|
|
21959
|
+
);
|
|
21774
21960
|
}
|
|
21775
21961
|
function renderTemplate(template, variables, escapeHtml = true) {
|
|
21776
21962
|
let result = template;
|
|
@@ -22401,7 +22587,7 @@ var test_coverage_gate_default = plugin56;
|
|
|
22401
22587
|
import { execFile as execFile13 } from "node:child_process";
|
|
22402
22588
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
22403
22589
|
import { createRequire as createRequire2 } from "node:module";
|
|
22404
|
-
import { dirname as
|
|
22590
|
+
import { dirname as dirname8, isAbsolute as isAbsolute25, relative as relative24, resolve as resolve26 } from "node:path";
|
|
22405
22591
|
var API_VERSION37 = "^0.1.10";
|
|
22406
22592
|
var state52 = {
|
|
22407
22593
|
invocationCount: 0,
|
|
@@ -22532,7 +22718,7 @@ function resolveTestCommand(baseCommand, testPattern) {
|
|
|
22532
22718
|
const packageJson = JSON.parse(readFileSync15(packagePath, "utf8"));
|
|
22533
22719
|
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[runner] ?? Object.values(packageJson.bin ?? {})[0];
|
|
22534
22720
|
if (!relativeBin) return null;
|
|
22535
|
-
const packageDir =
|
|
22721
|
+
const packageDir = dirname8(packagePath);
|
|
22536
22722
|
const candidate = resolve26(packageDir, relativeBin);
|
|
22537
22723
|
if (isAbsolute25(relativeBin) || !isInside2(packageDir, candidate)) {
|
|
22538
22724
|
return null;
|
|
@@ -22661,10 +22847,7 @@ var plugin57 = {
|
|
|
22661
22847
|
const commandString = typeof rawCommand === "string" && rawCommand.trim().length > 0 ? rawCommand.trim() : cfg.defaultCommand;
|
|
22662
22848
|
const rawRuns = input.runs ?? raw["runsRequested"] ?? raw["count"] ?? raw["repeat"] ?? raw["times"];
|
|
22663
22849
|
const requestedRuns = typeof rawRuns === "number" && rawRuns >= 1 ? Math.min(Math.floor(rawRuns), cfg.maxRuns) : 5;
|
|
22664
|
-
const command = resolveTestCommand(
|
|
22665
|
-
commandString,
|
|
22666
|
-
testPattern
|
|
22667
|
-
);
|
|
22850
|
+
const command = resolveTestCommand(commandString, testPattern);
|
|
22668
22851
|
if (!command) {
|
|
22669
22852
|
return {
|
|
22670
22853
|
ok: false,
|
|
@@ -22953,7 +23136,9 @@ function generateTestContent(sourcePath, sourceModule, detected, cfg) {
|
|
|
22953
23136
|
}
|
|
22954
23137
|
if (detected.length === 0) {
|
|
22955
23138
|
lines.push(` it('has no exported symbols to test', () => {`);
|
|
22956
|
-
lines.push(
|
|
23139
|
+
lines.push(
|
|
23140
|
+
cfg.framework === "node:test" ? ` assert.ok(true);` : ` expect(true).toBe(true);`
|
|
23141
|
+
);
|
|
22957
23142
|
lines.push(` });`);
|
|
22958
23143
|
}
|
|
22959
23144
|
lines.push(`});`);
|
|
@@ -23180,7 +23365,7 @@ var test_generator_default = plugin58;
|
|
|
23180
23365
|
// src/test-runner-gate/index.ts
|
|
23181
23366
|
import { execFile as execFile14 } from "node:child_process";
|
|
23182
23367
|
import { access as access5 } from "node:fs/promises";
|
|
23183
|
-
import { basename as basename6, dirname as
|
|
23368
|
+
import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute27, join as join7 } from "node:path";
|
|
23184
23369
|
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
23185
23370
|
function resolveExec(command, args) {
|
|
23186
23371
|
const resolved = resolveWin32Command(command);
|
|
@@ -23273,7 +23458,7 @@ var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
23273
23458
|
function resolveTestFiles(sourcePath, patterns) {
|
|
23274
23459
|
const name = basename6(sourcePath).replace(/\.[^.]+$/, "");
|
|
23275
23460
|
const pathNoExt = sourcePath.replace(/\.[^.]+$/, "");
|
|
23276
|
-
const dir =
|
|
23461
|
+
const dir = dirname9(sourcePath);
|
|
23277
23462
|
const candidates = [];
|
|
23278
23463
|
for (const pattern of patterns) {
|
|
23279
23464
|
const candidate = pattern.replace(/\{name\}/g, name).replace(/\{path\}/g, pathNoExt).replace(/\{dir\}/g, dir);
|
|
@@ -23311,13 +23496,18 @@ async function detectRunner(requested) {
|
|
|
23311
23496
|
try {
|
|
23312
23497
|
await new Promise((resolve28, reject) => {
|
|
23313
23498
|
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
23314
|
-
execFile14(
|
|
23315
|
-
|
|
23316
|
-
|
|
23317
|
-
|
|
23318
|
-
|
|
23319
|
-
|
|
23320
|
-
|
|
23499
|
+
execFile14(
|
|
23500
|
+
ex.cmd,
|
|
23501
|
+
ex.args,
|
|
23502
|
+
{
|
|
23503
|
+
encoding: "utf-8",
|
|
23504
|
+
timeout: 5e3,
|
|
23505
|
+
cwd: process.cwd(),
|
|
23506
|
+
windowsHide: true,
|
|
23507
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
23508
|
+
},
|
|
23509
|
+
(err) => err ? reject(err) : resolve28()
|
|
23510
|
+
);
|
|
23321
23511
|
});
|
|
23322
23512
|
return match;
|
|
23323
23513
|
} catch {
|
|
@@ -23328,13 +23518,18 @@ async function detectRunner(requested) {
|
|
|
23328
23518
|
try {
|
|
23329
23519
|
await new Promise((resolve28, reject) => {
|
|
23330
23520
|
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
23331
|
-
execFile14(
|
|
23332
|
-
|
|
23333
|
-
|
|
23334
|
-
|
|
23335
|
-
|
|
23336
|
-
|
|
23337
|
-
|
|
23521
|
+
execFile14(
|
|
23522
|
+
ex.cmd,
|
|
23523
|
+
ex.args,
|
|
23524
|
+
{
|
|
23525
|
+
encoding: "utf-8",
|
|
23526
|
+
timeout: 5e3,
|
|
23527
|
+
cwd: process.cwd(),
|
|
23528
|
+
windowsHide: true,
|
|
23529
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
23530
|
+
},
|
|
23531
|
+
(err) => err ? reject(err) : resolve28()
|
|
23532
|
+
);
|
|
23338
23533
|
});
|
|
23339
23534
|
return candidate;
|
|
23340
23535
|
} catch {
|
|
@@ -23602,7 +23797,9 @@ var plugin59 = {
|
|
|
23602
23797
|
Fix the failing tests or revert the change if it broke something.`
|
|
23603
23798
|
};
|
|
23604
23799
|
};
|
|
23605
|
-
state54.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
23800
|
+
state54.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
23801
|
+
background: true
|
|
23802
|
+
});
|
|
23606
23803
|
api.tools.register({
|
|
23607
23804
|
name: "test_gate_status",
|
|
23608
23805
|
description: "Reports test-runner-gate state: command, patterns, and per-session pass/fail/error/no-test counters.",
|
|
@@ -23908,7 +24105,7 @@ var todo_listener_default = plugin60;
|
|
|
23908
24105
|
// src/todo-tracker/index.ts
|
|
23909
24106
|
import { randomUUID } from "node:crypto";
|
|
23910
24107
|
import * as fsp from "node:fs/promises";
|
|
23911
|
-
import { dirname as
|
|
24108
|
+
import { dirname as dirname10 } from "node:path";
|
|
23912
24109
|
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
23913
24110
|
import { nowIso } from "@wrongstack/primitives";
|
|
23914
24111
|
function deriveFilePath(api) {
|
|
@@ -23941,7 +24138,7 @@ async function loadFile(filePath) {
|
|
|
23941
24138
|
}
|
|
23942
24139
|
}
|
|
23943
24140
|
async function saveFile(filePath, file) {
|
|
23944
|
-
await ensureDir3(
|
|
24141
|
+
await ensureDir3(dirname10(filePath));
|
|
23945
24142
|
await atomicWrite3(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
23946
24143
|
}
|
|
23947
24144
|
var state56 = {
|
|
@@ -24848,7 +25045,7 @@ var plugin63 = {
|
|
|
24848
25045
|
var token_throttle_default = plugin63;
|
|
24849
25046
|
|
|
24850
25047
|
// src/type-gate/index.ts
|
|
24851
|
-
import { existsSync as
|
|
25048
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
24852
25049
|
var API_VERSION41 = "^0.1.10";
|
|
24853
25050
|
var state59 = {
|
|
24854
25051
|
invocationCount: 0,
|
|
@@ -24932,7 +25129,7 @@ async function runTypeCheck(cfg) {
|
|
|
24932
25129
|
argv = [...argv, "-p", tsConfig];
|
|
24933
25130
|
}
|
|
24934
25131
|
}
|
|
24935
|
-
if (!cfg.command && tsConfig && !
|
|
25132
|
+
if (!cfg.command && tsConfig && !existsSync8(tsConfig)) {
|
|
24936
25133
|
return null;
|
|
24937
25134
|
}
|
|
24938
25135
|
const result = await (0, runtime_exports.runRunnerCommand)([argv[0], ...argv.slice(1)], {
|
|
@@ -25070,7 +25267,9 @@ Fix the type error(s) or adjust the change.`;
|
|
|
25070
25267
|
}
|
|
25071
25268
|
return { additionalContext: message };
|
|
25072
25269
|
};
|
|
25073
|
-
state59.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
25270
|
+
state59.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
25271
|
+
background: true
|
|
25272
|
+
});
|
|
25074
25273
|
api.tools.register({
|
|
25075
25274
|
name: "type_gate_status",
|
|
25076
25275
|
description: "Reports type-gate state: command, tsconfig, severity, and per-session pass/fail/error counters.",
|