@wrongstack/plugins 0.318.0 → 0.319.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor.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/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 +342 -121
- 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/path-guard.js +8 -2
- package/dist/pr-drafter.js +3 -1
- package/dist/process-guard.js +3 -1
- package/dist/prompt-firewall.js +14 -4
- package/dist/refactor-suggester.js +3 -1
- package/dist/security-hotspot-scanner.js +21 -3
- package/dist/semantic-search-indexer/index.d.ts +26 -0
- package/dist/semantic-search-indexer.js +100 -12
- 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 +3 -1
- 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");
|
|
@@ -3403,7 +3425,9 @@ var plugin10 = {
|
|
|
3403
3425
|
\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
3426
|
};
|
|
3405
3427
|
};
|
|
3406
|
-
state10.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
3428
|
+
state10.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
3429
|
+
background: true
|
|
3430
|
+
});
|
|
3407
3431
|
api.tools.register({
|
|
3408
3432
|
name: "measure_code_metrics",
|
|
3409
3433
|
description: "Measure lines, comments, blank lines, function count, and cyclomatic-complexity-like score for a source file or directory.",
|
|
@@ -3920,7 +3944,9 @@ function readConfig11(raw) {
|
|
|
3920
3944
|
const rawMax = r["maxFileBytes"] ?? r["max_file_bytes"] ?? r["maxBytes"] ?? r["max_bytes"];
|
|
3921
3945
|
return {
|
|
3922
3946
|
enabled: r["enabled"] !== false,
|
|
3923
|
-
extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map(
|
|
3947
|
+
extensions: Array.isArray(rawExts) ? rawExts.filter((e) => typeof e === "string" && e.trim().length > 0).map(
|
|
3948
|
+
(e) => e.trim().startsWith(".") ? e.trim().toLowerCase() : `.${e.trim().toLowerCase()}`
|
|
3949
|
+
) : [...DEFAULT_EXTENSIONS],
|
|
3924
3950
|
maxFileBytes: typeof rawMax === "number" && rawMax >= 1024 ? rawMax : DEFAULTS11.maxFileBytes
|
|
3925
3951
|
};
|
|
3926
3952
|
}
|
|
@@ -4214,7 +4240,9 @@ var plugin12 = {
|
|
|
4214
4240
|
\u2026 and ${problems.length - 10} more` : "") + "\nFix these before moving on \u2014 downstream tools will fail on this file."
|
|
4215
4241
|
};
|
|
4216
4242
|
};
|
|
4217
|
-
state12.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
4243
|
+
state12.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
4244
|
+
background: true
|
|
4245
|
+
});
|
|
4218
4246
|
api.tools.register({
|
|
4219
4247
|
name: "config_validator_status",
|
|
4220
4248
|
description: "Reports config-validator state: watched extensions and counters (files checked, problems found).",
|
|
@@ -4335,7 +4363,10 @@ async function persistPins(filePath) {
|
|
|
4335
4363
|
if (!filePath) return true;
|
|
4336
4364
|
try {
|
|
4337
4365
|
await ensureDir(dirname3(filePath));
|
|
4338
|
-
await atomicWrite(
|
|
4366
|
+
await atomicWrite(
|
|
4367
|
+
filePath,
|
|
4368
|
+
JSON.stringify({ pins: state13.pins, nextId: state13.nextId }, null, 2)
|
|
4369
|
+
);
|
|
4339
4370
|
return true;
|
|
4340
4371
|
} catch {
|
|
4341
4372
|
state13.persistErrors += 1;
|
|
@@ -4707,7 +4738,9 @@ var plugin14 = {
|
|
|
4707
4738
|
const rawCacheWrite = Number(u["cacheWrite"] ?? u["cache_creation_input_tokens"] ?? 0) || 0;
|
|
4708
4739
|
const freshTokens = rawInput + rawCacheWrite;
|
|
4709
4740
|
const promptTokens = freshTokens + cachedTokens;
|
|
4710
|
-
const completionTokens = Number(
|
|
4741
|
+
const completionTokens = Number(
|
|
4742
|
+
u["output"] ?? u["completion_tokens"] ?? u["outputTokens"] ?? u["completionTokens"] ?? 0
|
|
4743
|
+
) || 0;
|
|
4711
4744
|
const totalTokens = promptTokens + completionTokens;
|
|
4712
4745
|
const costUsd = estimateCost(model, freshTokens, completionTokens, cachedTokens);
|
|
4713
4746
|
const record = {
|
|
@@ -5073,8 +5106,14 @@ var plugin15 = {
|
|
|
5073
5106
|
type: "object",
|
|
5074
5107
|
properties: {
|
|
5075
5108
|
name: { type: "string", description: "Unique name for this cron job" },
|
|
5076
|
-
intervalMs: {
|
|
5077
|
-
|
|
5109
|
+
intervalMs: {
|
|
5110
|
+
type: "number",
|
|
5111
|
+
description: "Interval between runs in milliseconds (minimum 1000)"
|
|
5112
|
+
},
|
|
5113
|
+
action: {
|
|
5114
|
+
type: "string",
|
|
5115
|
+
description: "Action identifier or description of what to run"
|
|
5116
|
+
},
|
|
5078
5117
|
enabled: { type: "boolean", default: true }
|
|
5079
5118
|
},
|
|
5080
5119
|
required: ["name", "intervalMs", "action"]
|
|
@@ -5602,7 +5641,9 @@ function parseInstallCommands(command) {
|
|
|
5602
5641
|
if (!cleaned) continue;
|
|
5603
5642
|
let name = cleaned;
|
|
5604
5643
|
let version = null;
|
|
5605
|
-
const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
|
|
5644
|
+
const pipMatch = /^([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(==|>=|<=|~=|!=|>|<)\s*(.+)$/.exec(
|
|
5645
|
+
cleaned
|
|
5646
|
+
);
|
|
5606
5647
|
if (pipMatch?.[1]) {
|
|
5607
5648
|
name = pipMatch[1];
|
|
5608
5649
|
const op = pipMatch[2] ?? "";
|
|
@@ -6520,8 +6561,12 @@ var plugin19 = {
|
|
|
6520
6561
|
return;
|
|
6521
6562
|
}
|
|
6522
6563
|
const oldStr = String(inp["old_string"] ?? inp["TargetContent"] ?? inp["oldContent"] ?? "");
|
|
6523
|
-
const newStr = String(
|
|
6524
|
-
|
|
6564
|
+
const newStr = String(
|
|
6565
|
+
inp["new_string"] ?? inp["ReplacementContent"] ?? inp["newContent"] ?? ""
|
|
6566
|
+
);
|
|
6567
|
+
const contentStr = String(
|
|
6568
|
+
inp["content"] ?? inp["CodeContent"] ?? inp["code"] ?? inp["text"] ?? inp["contents"] ?? inp["body"] ?? ""
|
|
6569
|
+
);
|
|
6525
6570
|
const toolInputForHash = oldStr || newStr ? `${oldStr}:::${newStr}` : contentStr;
|
|
6526
6571
|
const now = Date.now();
|
|
6527
6572
|
const memo = pathMemo.get(filePath);
|
|
@@ -6576,7 +6621,9 @@ var plugin19 = {
|
|
|
6576
6621
|
additionalContext: header + summary
|
|
6577
6622
|
};
|
|
6578
6623
|
};
|
|
6579
|
-
state18.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6624
|
+
state18.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6625
|
+
background: true
|
|
6626
|
+
});
|
|
6580
6627
|
api.tools.register({
|
|
6581
6628
|
name: "diff_summary_status",
|
|
6582
6629
|
description: "Reports diff-summary state: mode, maxLines, and per-session invocation/injected/fallback counters.",
|
|
@@ -6804,7 +6851,9 @@ var plugin20 = {
|
|
|
6804
6851
|
}
|
|
6805
6852
|
}
|
|
6806
6853
|
if (!content || state19.changedFiles.length === 0) return;
|
|
6807
|
-
const missing = state19.changedFiles.filter(
|
|
6854
|
+
const missing = state19.changedFiles.filter(
|
|
6855
|
+
(changedPath) => !isReferenced(changedPath, content)
|
|
6856
|
+
);
|
|
6808
6857
|
if (missing.length === 0) return;
|
|
6809
6858
|
state19.warningsIssued += 1;
|
|
6810
6859
|
const missingList = missing.map((p) => ` - ${p}`).join("\n");
|
|
@@ -6815,7 +6864,9 @@ Consider mentioning these changes in the documentation.`;
|
|
|
6815
6864
|
return { additionalContext: message };
|
|
6816
6865
|
}
|
|
6817
6866
|
};
|
|
6818
|
-
state19.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6867
|
+
state19.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
6868
|
+
background: true
|
|
6869
|
+
});
|
|
6819
6870
|
api.tools.register({
|
|
6820
6871
|
name: "doc_sync_status",
|
|
6821
6872
|
description: "Reports doc-sync-guard state: tracked changed files, doc-write count, and warning count.",
|
|
@@ -7908,7 +7959,9 @@ var plugin23 = {
|
|
|
7908
7959
|
Make sure flag behavior is intentional and consider updating flag inventory/docs.`
|
|
7909
7960
|
};
|
|
7910
7961
|
};
|
|
7911
|
-
state22.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
7962
|
+
state22.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
7963
|
+
background: true
|
|
7964
|
+
});
|
|
7912
7965
|
api.tools.register({
|
|
7913
7966
|
name: "scan_feature_flags",
|
|
7914
7967
|
description: "Scan source files for feature-flag-like expressions (isFeatureEnabled, featureFlags.*, useFeatureFlag, flags.*, plus custom patterns).",
|
|
@@ -8678,7 +8731,9 @@ var plugin25 = {
|
|
|
8678
8731
|
state23.cleanCount += 1;
|
|
8679
8732
|
return;
|
|
8680
8733
|
};
|
|
8681
|
-
state23.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
8734
|
+
state23.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
8735
|
+
background: true
|
|
8736
|
+
});
|
|
8682
8737
|
state23.patternUnregister = api.onPattern(
|
|
8683
8738
|
"import-organizer:done",
|
|
8684
8739
|
(_eventName, payload) => {
|
|
@@ -10187,7 +10242,9 @@ ${result.stderr.trim()}`
|
|
|
10187
10242
|
}
|
|
10188
10243
|
return;
|
|
10189
10244
|
};
|
|
10190
|
-
state25.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10245
|
+
state25.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10246
|
+
background: true
|
|
10247
|
+
});
|
|
10191
10248
|
api.tools.register({
|
|
10192
10249
|
name: "import_organizer_status",
|
|
10193
10250
|
description: "Reports import-organizer state: linter availability, config, and per-session organized/clean/error counters.",
|
|
@@ -10678,7 +10735,9 @@ var plugin30 = {
|
|
|
10678
10735
|
If you changed member shapes, search the project for implementers/\`satisfies\`/\`as\` usages and update them accordingly.`
|
|
10679
10736
|
};
|
|
10680
10737
|
};
|
|
10681
|
-
state27.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10738
|
+
state27.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
10739
|
+
background: true
|
|
10740
|
+
});
|
|
10682
10741
|
api.tools.register({
|
|
10683
10742
|
name: "check_interface_contracts",
|
|
10684
10743
|
description: "Scan TypeScript files for interface declarations that have no visible implementer (implements / as / satisfies).",
|
|
@@ -11030,9 +11089,12 @@ var plugin31 = {
|
|
|
11030
11089
|
const hasMatch = f.subject.toLowerCase().includes(q) || f.relation.toLowerCase().includes(q) || f.object.toLowerCase().includes(q);
|
|
11031
11090
|
if (!hasMatch) return false;
|
|
11032
11091
|
}
|
|
11033
|
-
if (input.subject && !f.subject.toLowerCase().includes(input.subject.toLowerCase()))
|
|
11034
|
-
|
|
11035
|
-
if (input.
|
|
11092
|
+
if (input.subject && !f.subject.toLowerCase().includes(input.subject.toLowerCase()))
|
|
11093
|
+
return false;
|
|
11094
|
+
if (input.relation && !f.relation.toLowerCase().includes(input.relation.toLowerCase()))
|
|
11095
|
+
return false;
|
|
11096
|
+
if (input.object && !f.object.toLowerCase().includes(input.object.toLowerCase()))
|
|
11097
|
+
return false;
|
|
11036
11098
|
if (filterConf && f.confidence.toLowerCase() !== filterConf) return false;
|
|
11037
11099
|
return true;
|
|
11038
11100
|
});
|
|
@@ -11064,7 +11126,9 @@ var plugin31 = {
|
|
|
11064
11126
|
const raw = input ?? {};
|
|
11065
11127
|
const rawId = String(input.id ?? raw["factId"] ?? raw["fact_id"] ?? "").trim();
|
|
11066
11128
|
const normalized = rawId.toLowerCase().startsWith("kg-") ? rawId.toLowerCase() : `kg-${rawId.toLowerCase()}`;
|
|
11067
|
-
state28.facts = state28.facts.filter(
|
|
11129
|
+
state28.facts = state28.facts.filter(
|
|
11130
|
+
(f) => f.id.toLowerCase() !== normalized && f.id !== rawId
|
|
11131
|
+
);
|
|
11068
11132
|
const removed = before - state28.facts.length;
|
|
11069
11133
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id ?? rawId}"` };
|
|
11070
11134
|
state28.removals += removed;
|
|
@@ -11160,7 +11224,15 @@ var state29 = {
|
|
|
11160
11224
|
};
|
|
11161
11225
|
var DEFAULTS27 = {
|
|
11162
11226
|
enabled: true,
|
|
11163
|
-
allowedLicenses: [
|
|
11227
|
+
allowedLicenses: [
|
|
11228
|
+
"MIT",
|
|
11229
|
+
"Apache-2.0",
|
|
11230
|
+
"BSD-2-Clause",
|
|
11231
|
+
"BSD-3-Clause",
|
|
11232
|
+
"ISC",
|
|
11233
|
+
"0BSD",
|
|
11234
|
+
"Unlicense"
|
|
11235
|
+
],
|
|
11164
11236
|
block: true
|
|
11165
11237
|
};
|
|
11166
11238
|
function normalizeStrings(v) {
|
|
@@ -11199,7 +11271,9 @@ function extractLicenseStrings(pkg) {
|
|
|
11199
11271
|
}
|
|
11200
11272
|
function parsePackageNames(command) {
|
|
11201
11273
|
return [
|
|
11202
|
-
...new Set(
|
|
11274
|
+
...new Set(
|
|
11275
|
+
parseInstallCommands(command).flatMap((entry) => entry.packages.map((pkg) => pkg.name))
|
|
11276
|
+
)
|
|
11203
11277
|
];
|
|
11204
11278
|
}
|
|
11205
11279
|
function splitTopLevel(expr, separator) {
|
|
@@ -15409,9 +15483,15 @@ var plugin39 = {
|
|
|
15409
15483
|
kind: isRootPathScope(path) && deletesImplicitScope || isUnresolvedPathScope(path) || recursivelyDeletes && (isDirectoryAmbiguousPath(path) || hasConfiguredProtectedDescendant(path, cfg.protect)) ? "deletion-scope" : "file"
|
|
15410
15484
|
};
|
|
15411
15485
|
if (targetFullyAllowed(target, cfg.allow, allowRes)) return null;
|
|
15412
|
-
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
15486
|
+
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
15413
15487
|
onTimeout: bumpRedos
|
|
15414
|
-
})
|
|
15488
|
+
}) || await matchesAnyGuarded(
|
|
15489
|
+
`${target.path.replace(/\/$/, "")}/.path-guard-probe`,
|
|
15490
|
+
protectRes,
|
|
15491
|
+
{
|
|
15492
|
+
onTimeout: bumpRedos
|
|
15493
|
+
}
|
|
15494
|
+
);
|
|
15415
15495
|
return protectedShellTarget ? target : null;
|
|
15416
15496
|
})
|
|
15417
15497
|
);
|
|
@@ -16257,7 +16337,9 @@ var plugin41 = {
|
|
|
16257
16337
|
async execute(input = {}) {
|
|
16258
16338
|
if (!cfg.enabled) return { ok: false, error: "pr-drafter is disabled" };
|
|
16259
16339
|
const raw = input ?? {};
|
|
16260
|
-
const preview = Boolean(
|
|
16340
|
+
const preview = Boolean(
|
|
16341
|
+
input?.preview ?? raw["dryRun"] ?? raw["dry_run"] ?? raw["dry"] ?? raw["previewOnly"]
|
|
16342
|
+
);
|
|
16261
16343
|
const rawOutputPath = raw["outputPath"] ?? raw["output_path"] ?? raw["path"] ?? raw["filePath"] ?? raw["file"] ?? raw["TargetFile"] ?? raw["targetFile"] ?? cfg.outputPath;
|
|
16262
16344
|
const outputPathStr = typeof rawOutputPath === "string" && rawOutputPath.trim().length > 0 ? rawOutputPath.trim() : cfg.outputPath;
|
|
16263
16345
|
const draft = await buildDraft(cfg, api.llm);
|
|
@@ -16406,7 +16488,9 @@ var plugin42 = {
|
|
|
16406
16488
|
const rawCmd = ti["command"] ?? ti["CommandLine"] ?? ti["cmd"] ?? ti["script"] ?? ti["input"];
|
|
16407
16489
|
const command = typeof rawCmd === "string" ? rawCmd : "";
|
|
16408
16490
|
if (!command) return;
|
|
16409
|
-
const isKillRelated = /\b(?:kill|taskkill|stop-process|tskill|pkill|killall|wmic)\b/i.test(
|
|
16491
|
+
const isKillRelated = /\b(?:kill|taskkill|stop-process|tskill|pkill|killall|wmic)\b/i.test(
|
|
16492
|
+
command
|
|
16493
|
+
);
|
|
16410
16494
|
if (!isKillRelated) return;
|
|
16411
16495
|
state39.detections += 1;
|
|
16412
16496
|
state39.lastDetection = {
|
|
@@ -16772,9 +16856,12 @@ function surfaceScanTrips(api, tripped) {
|
|
|
16772
16856
|
}
|
|
16773
16857
|
state40.timeoutCount += 1;
|
|
16774
16858
|
api.metrics.counter("redos_skips", 1);
|
|
16775
|
-
api.log.warn(
|
|
16776
|
-
|
|
16777
|
-
|
|
16859
|
+
api.log.warn(
|
|
16860
|
+
"prompt-firewall: scan-pass budget exceeded \u2014 patterns skipped mid-pass (issue #370)",
|
|
16861
|
+
{
|
|
16862
|
+
skipped: [...tripped]
|
|
16863
|
+
}
|
|
16864
|
+
);
|
|
16778
16865
|
}
|
|
16779
16866
|
var plugin43 = {
|
|
16780
16867
|
name: "prompt-firewall",
|
|
@@ -16876,7 +16963,14 @@ var plugin43 = {
|
|
|
16876
16963
|
if (cfg.mode === "redact") {
|
|
16877
16964
|
const counter = { n: 0 };
|
|
16878
16965
|
const deadline = createScanDeadline();
|
|
16879
|
-
const redactedReq = redactDeep(
|
|
16966
|
+
const redactedReq = redactDeep(
|
|
16967
|
+
req,
|
|
16968
|
+
cfg.allow,
|
|
16969
|
+
counter,
|
|
16970
|
+
skipSet,
|
|
16971
|
+
void 0,
|
|
16972
|
+
deadline
|
|
16973
|
+
);
|
|
16880
16974
|
state40.requestRedactions += counter.n;
|
|
16881
16975
|
api.metrics.counter("request_redactions", counter.n);
|
|
16882
16976
|
if (deadline.tripped.size > 0) surfaceScanTrips(api, deadline.tripped);
|
|
@@ -17273,7 +17367,9 @@ var plugin44 = {
|
|
|
17273
17367
|
contextAs: "separate"
|
|
17274
17368
|
};
|
|
17275
17369
|
};
|
|
17276
|
-
state41.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
17370
|
+
state41.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
17371
|
+
background: true
|
|
17372
|
+
});
|
|
17277
17373
|
api.tools.register({
|
|
17278
17374
|
name: "suggest_refactors",
|
|
17279
17375
|
description: "Scan source files for refactoring smells: long functions, deep nesting, many parameters, magic numbers, and console logging.",
|
|
@@ -18600,7 +18696,19 @@ var DEFAULTS42 = {
|
|
|
18600
18696
|
enabled: false,
|
|
18601
18697
|
severity: "warn",
|
|
18602
18698
|
maxFindings: 10,
|
|
18603
|
-
scanOnChange: [
|
|
18699
|
+
scanOnChange: [
|
|
18700
|
+
".js",
|
|
18701
|
+
".jsx",
|
|
18702
|
+
".ts",
|
|
18703
|
+
".tsx",
|
|
18704
|
+
".mjs",
|
|
18705
|
+
".cjs",
|
|
18706
|
+
".py",
|
|
18707
|
+
".java",
|
|
18708
|
+
".go",
|
|
18709
|
+
".rb",
|
|
18710
|
+
".php"
|
|
18711
|
+
]
|
|
18604
18712
|
};
|
|
18605
18713
|
var scanOnChangeSet = new Set(DEFAULTS42.scanOnChange);
|
|
18606
18714
|
function readConfig44(raw) {
|
|
@@ -18623,7 +18731,11 @@ function readConfig44(raw) {
|
|
|
18623
18731
|
}
|
|
18624
18732
|
var PATTERNS4 = [
|
|
18625
18733
|
{ type: "eval_call", severity: "high", regex: /\beval\s*\(/i },
|
|
18626
|
-
{
|
|
18734
|
+
{
|
|
18735
|
+
type: "function_constructor",
|
|
18736
|
+
severity: "high",
|
|
18737
|
+
regex: /\bnew\s+Function\s*\(|\bFunction\s*\(/i
|
|
18738
|
+
},
|
|
18627
18739
|
{
|
|
18628
18740
|
type: "unsafe_html",
|
|
18629
18741
|
severity: "high",
|
|
@@ -18861,7 +18973,9 @@ Review or remove the risky pattern(s).`;
|
|
|
18861
18973
|
}
|
|
18862
18974
|
return { additionalContext: message };
|
|
18863
18975
|
};
|
|
18864
|
-
state44.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
18976
|
+
state44.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
18977
|
+
background: true
|
|
18978
|
+
});
|
|
18865
18979
|
api.tools.register({
|
|
18866
18980
|
name: "security_hotspot_scan",
|
|
18867
18981
|
description: "Scan a file or directory for security anti-patterns (eval, Function constructor, innerHTML, SQL concatenation, http URLs, credential logging, variable exec commands).",
|
|
@@ -19000,7 +19114,10 @@ var state45 = {
|
|
|
19000
19114
|
buildPromise: null,
|
|
19001
19115
|
buildGeneration: 0,
|
|
19002
19116
|
publishedGeneration: 0,
|
|
19003
|
-
hookUnregister: null
|
|
19117
|
+
hookUnregister: null,
|
|
19118
|
+
deleteHookUnregister: null,
|
|
19119
|
+
lastPruneAt: 0,
|
|
19120
|
+
pruneInFlight: null
|
|
19004
19121
|
};
|
|
19005
19122
|
var DEFAULTS43 = {
|
|
19006
19123
|
enabled: true,
|
|
@@ -19033,11 +19150,7 @@ var DEFAULTS43 = {
|
|
|
19033
19150
|
".scss",
|
|
19034
19151
|
".html"
|
|
19035
19152
|
],
|
|
19036
|
-
excludePatterns: [
|
|
19037
|
-
...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex),
|
|
19038
|
-
"\\.wrongstack",
|
|
19039
|
-
"\\.temp_files"
|
|
19040
|
-
],
|
|
19153
|
+
excludePatterns: [...DEFAULT_WALK_IGNORE_DIRS.map(escapeRegex), "\\.wrongstack", "\\.temp_files"],
|
|
19041
19154
|
maxFileBytes: 1e6,
|
|
19042
19155
|
defaultLimit: 10,
|
|
19043
19156
|
minTokenLength: 2,
|
|
@@ -19045,7 +19158,12 @@ var DEFAULTS43 = {
|
|
|
19045
19158
|
maxFiles: 5e3
|
|
19046
19159
|
};
|
|
19047
19160
|
function readConfig45(raw) {
|
|
19048
|
-
if (!raw || typeof raw !== "object")
|
|
19161
|
+
if (!raw || typeof raw !== "object")
|
|
19162
|
+
return {
|
|
19163
|
+
...DEFAULTS43,
|
|
19164
|
+
includeExtensions: [...DEFAULTS43.includeExtensions],
|
|
19165
|
+
excludePatterns: [...DEFAULTS43.excludePatterns]
|
|
19166
|
+
};
|
|
19049
19167
|
const r = raw;
|
|
19050
19168
|
const rawExts = r["includeExtensions"] ?? r["include_extensions"] ?? r["extensions"] ?? r["file_extensions"];
|
|
19051
19169
|
const includeExtensions = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : [...DEFAULTS43.includeExtensions];
|
|
@@ -19115,11 +19233,11 @@ var YIELD_EVERY_FILES = 64;
|
|
|
19115
19233
|
function yieldEventLoop() {
|
|
19116
19234
|
return new Promise((resolve28) => setImmediate(resolve28));
|
|
19117
19235
|
}
|
|
19118
|
-
function addFileToIndex(relPath, content, size, cfg) {
|
|
19236
|
+
function addFileToIndex(relPath, absPath, content, size, cfg) {
|
|
19119
19237
|
if (!state45.index || content.includes("\0")) return;
|
|
19120
19238
|
state45.bytesIndexed += content.length;
|
|
19121
19239
|
const lines = content.split(/\r?\n/);
|
|
19122
|
-
state45.index.files.set(relPath, { lines, size });
|
|
19240
|
+
state45.index.files.set(relPath, { lines, size, absPath });
|
|
19123
19241
|
for (let i = 0; i < lines.length; i += 1) {
|
|
19124
19242
|
const terms = tokenize(lines[i], cfg.minTokenLength);
|
|
19125
19243
|
for (const term of terms) {
|
|
@@ -19145,7 +19263,7 @@ async function indexFileFromStats(absPath, relPath, stats, cfg) {
|
|
|
19145
19263
|
} catch {
|
|
19146
19264
|
return;
|
|
19147
19265
|
}
|
|
19148
|
-
addFileToIndex(relPath, content, stats.size, cfg);
|
|
19266
|
+
addFileToIndex(relPath, absPath, content, stats.size, cfg);
|
|
19149
19267
|
}
|
|
19150
19268
|
async function flushFileBatch(batch, cfg) {
|
|
19151
19269
|
if (batch.length === 0) return;
|
|
@@ -19238,6 +19356,51 @@ async function ensureIndex(rootPath, cfg) {
|
|
|
19238
19356
|
state45.cachedPath = null;
|
|
19239
19357
|
}
|
|
19240
19358
|
}
|
|
19359
|
+
var PRUNE_MIN_INTERVAL_MS = 3e4;
|
|
19360
|
+
function removeFileFromIndex(relPath, cfg) {
|
|
19361
|
+
const index = state45.index;
|
|
19362
|
+
if (!index) return;
|
|
19363
|
+
const entry = index.files.get(relPath);
|
|
19364
|
+
if (!entry) return;
|
|
19365
|
+
const terms = /* @__PURE__ */ new Set();
|
|
19366
|
+
for (const line of entry.lines) {
|
|
19367
|
+
for (const term of tokenize(line, cfg.minTokenLength)) terms.add(term);
|
|
19368
|
+
}
|
|
19369
|
+
for (const term of terms) {
|
|
19370
|
+
const postings = index.terms.get(term);
|
|
19371
|
+
if (!postings) continue;
|
|
19372
|
+
postings.delete(relPath);
|
|
19373
|
+
if (postings.size === 0) index.terms.delete(term);
|
|
19374
|
+
}
|
|
19375
|
+
index.files.delete(relPath);
|
|
19376
|
+
state45.fileCount = Math.max(0, state45.fileCount - 1);
|
|
19377
|
+
state45.bytesIndexed = Math.max(0, state45.bytesIndexed - entry.size);
|
|
19378
|
+
state45.termCount = index.terms.size;
|
|
19379
|
+
}
|
|
19380
|
+
async function pruneDeletedFiles(rootPath, cfg, opts) {
|
|
19381
|
+
const index = state45.index;
|
|
19382
|
+
if (!index || state45.cachedPath !== rootPath) return 0;
|
|
19383
|
+
if (state45.pruneInFlight) return state45.pruneInFlight;
|
|
19384
|
+
const now = Date.now();
|
|
19385
|
+
if (!opts?.force && now - state45.lastPruneAt < PRUNE_MIN_INTERVAL_MS) return 0;
|
|
19386
|
+
state45.lastPruneAt = now;
|
|
19387
|
+
const pass = (async () => {
|
|
19388
|
+
const missing = [];
|
|
19389
|
+
for (const [relPath, entry] of index.files) {
|
|
19390
|
+
try {
|
|
19391
|
+
await fs2.stat(entry.absPath);
|
|
19392
|
+
} catch {
|
|
19393
|
+
missing.push(relPath);
|
|
19394
|
+
}
|
|
19395
|
+
}
|
|
19396
|
+
for (const relPath of missing) removeFileFromIndex(relPath, cfg);
|
|
19397
|
+
return missing.length;
|
|
19398
|
+
})();
|
|
19399
|
+
state45.pruneInFlight = pass.finally(() => {
|
|
19400
|
+
state45.pruneInFlight = null;
|
|
19401
|
+
});
|
|
19402
|
+
return pass;
|
|
19403
|
+
}
|
|
19241
19404
|
function compareRankedCandidates(a, b) {
|
|
19242
19405
|
return b.score - a.score || a.path.localeCompare(b.path);
|
|
19243
19406
|
}
|
|
@@ -19311,7 +19474,11 @@ var plugin49 = {
|
|
|
19311
19474
|
description: "Builds an in-memory keyword index over project source files and answers ranked search queries",
|
|
19312
19475
|
apiVersion: API_VERSION32,
|
|
19313
19476
|
capabilities: { tools: true },
|
|
19314
|
-
defaultConfig: {
|
|
19477
|
+
defaultConfig: {
|
|
19478
|
+
...DEFAULTS43,
|
|
19479
|
+
includeExtensions: [...DEFAULTS43.includeExtensions],
|
|
19480
|
+
excludePatterns: [...DEFAULTS43.excludePatterns]
|
|
19481
|
+
},
|
|
19315
19482
|
configSchema: {
|
|
19316
19483
|
type: "object",
|
|
19317
19484
|
properties: {
|
|
@@ -19384,6 +19551,15 @@ var plugin49 = {
|
|
|
19384
19551
|
}
|
|
19385
19552
|
state45.hookUnregister = null;
|
|
19386
19553
|
}
|
|
19554
|
+
if (state45.deleteHookUnregister) {
|
|
19555
|
+
try {
|
|
19556
|
+
state45.deleteHookUnregister();
|
|
19557
|
+
} catch {
|
|
19558
|
+
}
|
|
19559
|
+
state45.deleteHookUnregister = null;
|
|
19560
|
+
}
|
|
19561
|
+
state45.lastPruneAt = 0;
|
|
19562
|
+
state45.pruneInFlight = null;
|
|
19387
19563
|
const cfg = readConfig45(api.config.extensions?.["semantic-search-indexer"]);
|
|
19388
19564
|
api.tools.register({
|
|
19389
19565
|
name: "semantic_search",
|
|
@@ -19493,6 +19669,17 @@ var plugin49 = {
|
|
|
19493
19669
|
{ background: true }
|
|
19494
19670
|
);
|
|
19495
19671
|
}
|
|
19672
|
+
if (typeof api.registerHook === "function") {
|
|
19673
|
+
state45.deleteHookUnregister = api.registerHook(
|
|
19674
|
+
"PostToolUse",
|
|
19675
|
+
"bash|exec|pwsh|delete_file|remove_file",
|
|
19676
|
+
(() => {
|
|
19677
|
+
const root = state45.cachedPath;
|
|
19678
|
+
if (root) void pruneDeletedFiles(root, cfg);
|
|
19679
|
+
}),
|
|
19680
|
+
{ background: true }
|
|
19681
|
+
);
|
|
19682
|
+
}
|
|
19496
19683
|
api.log.info("semantic-search-indexer plugin loaded", {
|
|
19497
19684
|
version: "0.1.0",
|
|
19498
19685
|
defaultLimit: cfg.defaultLimit,
|
|
@@ -19507,6 +19694,13 @@ var plugin49 = {
|
|
|
19507
19694
|
}
|
|
19508
19695
|
state45.hookUnregister = null;
|
|
19509
19696
|
}
|
|
19697
|
+
if (state45.deleteHookUnregister) {
|
|
19698
|
+
try {
|
|
19699
|
+
state45.deleteHookUnregister();
|
|
19700
|
+
} catch {
|
|
19701
|
+
}
|
|
19702
|
+
state45.deleteHookUnregister = null;
|
|
19703
|
+
}
|
|
19510
19704
|
const final = {
|
|
19511
19705
|
fileCount: state45.fileCount,
|
|
19512
19706
|
termCount: state45.termCount,
|
|
@@ -19524,6 +19718,8 @@ var plugin49 = {
|
|
|
19524
19718
|
state45.buildPromise = null;
|
|
19525
19719
|
state45.buildGeneration = 0;
|
|
19526
19720
|
state45.publishedGeneration = 0;
|
|
19721
|
+
state45.lastPruneAt = 0;
|
|
19722
|
+
state45.pruneInFlight = null;
|
|
19527
19723
|
api.log.info("semantic-search-indexer: teardown complete", { final });
|
|
19528
19724
|
},
|
|
19529
19725
|
async health() {
|
|
@@ -19567,19 +19763,24 @@ var state46 = {
|
|
|
19567
19763
|
};
|
|
19568
19764
|
function runCommand3(command, args, cwd) {
|
|
19569
19765
|
return new Promise((resolve28, reject) => {
|
|
19570
|
-
execFile11(
|
|
19571
|
-
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
|
|
19766
|
+
execFile11(
|
|
19767
|
+
command,
|
|
19768
|
+
args,
|
|
19769
|
+
{
|
|
19770
|
+
encoding: "utf-8",
|
|
19771
|
+
cwd,
|
|
19772
|
+
timeout: 3e4,
|
|
19773
|
+
windowsHide: true
|
|
19774
|
+
},
|
|
19775
|
+
(err, stdout, stderr) => {
|
|
19776
|
+
if (!err) {
|
|
19777
|
+
resolve28(stdout.trim());
|
|
19778
|
+
return;
|
|
19779
|
+
}
|
|
19780
|
+
const failure = err;
|
|
19781
|
+
reject(Object.assign(failure, { stderr: stderr || void 0 }));
|
|
19579
19782
|
}
|
|
19580
|
-
|
|
19581
|
-
reject(Object.assign(failure, { stderr: stderr || void 0 }));
|
|
19582
|
-
});
|
|
19783
|
+
);
|
|
19583
19784
|
});
|
|
19584
19785
|
}
|
|
19585
19786
|
async function runGit6(args, cwd) {
|
|
@@ -20627,15 +20828,10 @@ var state48 = {
|
|
|
20627
20828
|
async function runShellCheck(files, severity, cwd) {
|
|
20628
20829
|
try {
|
|
20629
20830
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
20630
|
-
execFile12(
|
|
20631
|
-
|
|
20632
|
-
|
|
20633
|
-
|
|
20634
|
-
(err) => {
|
|
20635
|
-
if (err) rejectPromise(err);
|
|
20636
|
-
else resolvePromise();
|
|
20637
|
-
}
|
|
20638
|
-
);
|
|
20831
|
+
execFile12("shellcheck", ["--version"], { encoding: "utf-8", windowsHide: true }, (err) => {
|
|
20832
|
+
if (err) rejectPromise(err);
|
|
20833
|
+
else resolvePromise();
|
|
20834
|
+
});
|
|
20639
20835
|
});
|
|
20640
20836
|
} catch {
|
|
20641
20837
|
throw new Error(
|
|
@@ -20796,7 +20992,9 @@ var plugin52 = {
|
|
|
20796
20992
|
if (typeof rawFiles === "string" && rawFiles.trim().length > 0) {
|
|
20797
20993
|
files = [rawFiles.trim()];
|
|
20798
20994
|
} else if (Array.isArray(rawFiles)) {
|
|
20799
|
-
files = rawFiles.filter(
|
|
20995
|
+
files = rawFiles.filter(
|
|
20996
|
+
(f) => typeof f === "string" && f.trim().length > 0
|
|
20997
|
+
);
|
|
20800
20998
|
}
|
|
20801
20999
|
}
|
|
20802
21000
|
const rawDirectory = inp.directory ?? input["dir"] ?? input["SearchDirectory"];
|
|
@@ -20941,7 +21139,8 @@ function normalizeExtensions6(exts) {
|
|
|
20941
21139
|
return exts.map((e) => e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`);
|
|
20942
21140
|
}
|
|
20943
21141
|
function readConfig47(raw) {
|
|
20944
|
-
if (!raw || typeof raw !== "object")
|
|
21142
|
+
if (!raw || typeof raw !== "object")
|
|
21143
|
+
return { ...DEFAULTS45, extensions: normalizeExtensions6(DEFAULTS45.extensions) };
|
|
20945
21144
|
const r = raw;
|
|
20946
21145
|
const rawExts = r["extensions"] ?? r["file_extensions"] ?? r["fileExtensions"];
|
|
20947
21146
|
const exts = Array.isArray(rawExts) ? rawExts.filter((x) => typeof x === "string") : DEFAULTS45.extensions;
|
|
@@ -20974,10 +21173,7 @@ function isIdentifier(name) {
|
|
|
20974
21173
|
return IDENTIFIER_RE2.test(name);
|
|
20975
21174
|
}
|
|
20976
21175
|
function renameInContent(content, oldName, newName) {
|
|
20977
|
-
const re = new RegExp(
|
|
20978
|
-
`(?<![A-Za-z0-9_$])${escapeRegex2(oldName)}(?![A-Za-z0-9_$])`,
|
|
20979
|
-
"g"
|
|
20980
|
-
);
|
|
21176
|
+
const re = new RegExp(`(?<![A-Za-z0-9_$])${escapeRegex2(oldName)}(?![A-Za-z0-9_$])`, "g");
|
|
20981
21177
|
let replacements = 0;
|
|
20982
21178
|
const preview = content.replace(re, () => {
|
|
20983
21179
|
replacements++;
|
|
@@ -21018,7 +21214,11 @@ var plugin53 = {
|
|
|
21018
21214
|
path: { type: "string", description: "Source file path (relative to project root)." },
|
|
21019
21215
|
oldName: { type: "string", description: "Identifier to replace." },
|
|
21020
21216
|
newName: { type: "string", description: "New identifier." },
|
|
21021
|
-
apply: {
|
|
21217
|
+
apply: {
|
|
21218
|
+
type: "boolean",
|
|
21219
|
+
default: false,
|
|
21220
|
+
description: "When true, write the preview back to disk."
|
|
21221
|
+
}
|
|
21022
21222
|
},
|
|
21023
21223
|
required: ["path", "oldName", "newName"]
|
|
21024
21224
|
},
|
|
@@ -21535,7 +21735,9 @@ var plugin54 = {
|
|
|
21535
21735
|
${lines}${overflowNote}`
|
|
21536
21736
|
};
|
|
21537
21737
|
};
|
|
21538
|
-
state50.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, {
|
|
21738
|
+
state50.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, {
|
|
21739
|
+
background: true
|
|
21740
|
+
});
|
|
21539
21741
|
if (cfg.autoFix) {
|
|
21540
21742
|
const preHook = async (input) => {
|
|
21541
21743
|
if (!cfg.enabled) return;
|
|
@@ -21679,21 +21881,27 @@ function expandTemplate(template, variables) {
|
|
|
21679
21881
|
return result;
|
|
21680
21882
|
}
|
|
21681
21883
|
function expandConditionals(template, variables) {
|
|
21682
|
-
return template.replace(
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21884
|
+
return template.replace(
|
|
21885
|
+
/\{\{#if\s+([\w.-]+)\s*\}\}([\s\S]*?)\{\{\/if\}\}/g,
|
|
21886
|
+
(_, key, content) => {
|
|
21887
|
+
const val = variables[key];
|
|
21888
|
+
return val !== void 0 && val !== "" && val !== "false" && val !== "0" ? content : "";
|
|
21889
|
+
}
|
|
21890
|
+
);
|
|
21686
21891
|
}
|
|
21687
21892
|
function expandLoops(template, variables) {
|
|
21688
|
-
return template.replace(
|
|
21689
|
-
|
|
21690
|
-
|
|
21691
|
-
|
|
21692
|
-
|
|
21693
|
-
|
|
21694
|
-
|
|
21695
|
-
|
|
21696
|
-
|
|
21893
|
+
return template.replace(
|
|
21894
|
+
/\{\{#each\s+([\w.-]+)\s*\}\}([\s\S]*?)\{\{\/each\}\}/g,
|
|
21895
|
+
(_, key, content) => {
|
|
21896
|
+
const val = variables[key];
|
|
21897
|
+
if (!val) return "";
|
|
21898
|
+
if (typeof val === "string" && val.includes(",")) {
|
|
21899
|
+
const items = val.split(",").map((s) => s.trim());
|
|
21900
|
+
return items.map((item) => expandTemplate(content, { ...variables, [key]: item, item })).join("\n");
|
|
21901
|
+
}
|
|
21902
|
+
return expandTemplate(content, variables);
|
|
21903
|
+
}
|
|
21904
|
+
);
|
|
21697
21905
|
}
|
|
21698
21906
|
function renderTemplate(template, variables, escapeHtml = true) {
|
|
21699
21907
|
let result = template;
|
|
@@ -22584,10 +22792,7 @@ var plugin57 = {
|
|
|
22584
22792
|
const commandString = typeof rawCommand === "string" && rawCommand.trim().length > 0 ? rawCommand.trim() : cfg.defaultCommand;
|
|
22585
22793
|
const rawRuns = input.runs ?? raw["runsRequested"] ?? raw["count"] ?? raw["repeat"] ?? raw["times"];
|
|
22586
22794
|
const requestedRuns = typeof rawRuns === "number" && rawRuns >= 1 ? Math.min(Math.floor(rawRuns), cfg.maxRuns) : 5;
|
|
22587
|
-
const command = resolveTestCommand(
|
|
22588
|
-
commandString,
|
|
22589
|
-
testPattern
|
|
22590
|
-
);
|
|
22795
|
+
const command = resolveTestCommand(commandString, testPattern);
|
|
22591
22796
|
if (!command) {
|
|
22592
22797
|
return {
|
|
22593
22798
|
ok: false,
|
|
@@ -22876,7 +23081,9 @@ function generateTestContent(sourcePath, sourceModule, detected, cfg) {
|
|
|
22876
23081
|
}
|
|
22877
23082
|
if (detected.length === 0) {
|
|
22878
23083
|
lines.push(` it('has no exported symbols to test', () => {`);
|
|
22879
|
-
lines.push(
|
|
23084
|
+
lines.push(
|
|
23085
|
+
cfg.framework === "node:test" ? ` assert.ok(true);` : ` expect(true).toBe(true);`
|
|
23086
|
+
);
|
|
22880
23087
|
lines.push(` });`);
|
|
22881
23088
|
}
|
|
22882
23089
|
lines.push(`});`);
|
|
@@ -23234,13 +23441,18 @@ async function detectRunner(requested) {
|
|
|
23234
23441
|
try {
|
|
23235
23442
|
await new Promise((resolve28, reject) => {
|
|
23236
23443
|
const ex = resolveExec("npx", [`${match.name}`, "--version"]);
|
|
23237
|
-
execFile14(
|
|
23238
|
-
|
|
23239
|
-
|
|
23240
|
-
|
|
23241
|
-
|
|
23242
|
-
|
|
23243
|
-
|
|
23444
|
+
execFile14(
|
|
23445
|
+
ex.cmd,
|
|
23446
|
+
ex.args,
|
|
23447
|
+
{
|
|
23448
|
+
encoding: "utf-8",
|
|
23449
|
+
timeout: 5e3,
|
|
23450
|
+
cwd: process.cwd(),
|
|
23451
|
+
windowsHide: true,
|
|
23452
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
23453
|
+
},
|
|
23454
|
+
(err) => err ? reject(err) : resolve28()
|
|
23455
|
+
);
|
|
23244
23456
|
});
|
|
23245
23457
|
return match;
|
|
23246
23458
|
} catch {
|
|
@@ -23251,13 +23463,18 @@ async function detectRunner(requested) {
|
|
|
23251
23463
|
try {
|
|
23252
23464
|
await new Promise((resolve28, reject) => {
|
|
23253
23465
|
const ex = resolveExec("npx", [`${candidate.name}`, "--version"]);
|
|
23254
|
-
execFile14(
|
|
23255
|
-
|
|
23256
|
-
|
|
23257
|
-
|
|
23258
|
-
|
|
23259
|
-
|
|
23260
|
-
|
|
23466
|
+
execFile14(
|
|
23467
|
+
ex.cmd,
|
|
23468
|
+
ex.args,
|
|
23469
|
+
{
|
|
23470
|
+
encoding: "utf-8",
|
|
23471
|
+
timeout: 5e3,
|
|
23472
|
+
cwd: process.cwd(),
|
|
23473
|
+
windowsHide: true,
|
|
23474
|
+
...ex.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}
|
|
23475
|
+
},
|
|
23476
|
+
(err) => err ? reject(err) : resolve28()
|
|
23477
|
+
);
|
|
23261
23478
|
});
|
|
23262
23479
|
return candidate;
|
|
23263
23480
|
} catch {
|
|
@@ -23525,7 +23742,9 @@ var plugin59 = {
|
|
|
23525
23742
|
Fix the failing tests or revert the change if it broke something.`
|
|
23526
23743
|
};
|
|
23527
23744
|
};
|
|
23528
|
-
state54.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
23745
|
+
state54.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
23746
|
+
background: true
|
|
23747
|
+
});
|
|
23529
23748
|
api.tools.register({
|
|
23530
23749
|
name: "test_gate_status",
|
|
23531
23750
|
description: "Reports test-runner-gate state: command, patterns, and per-session pass/fail/error/no-test counters.",
|
|
@@ -24993,7 +25212,9 @@ Fix the type error(s) or adjust the change.`;
|
|
|
24993
25212
|
}
|
|
24994
25213
|
return { additionalContext: message };
|
|
24995
25214
|
};
|
|
24996
|
-
state59.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
25215
|
+
state59.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
25216
|
+
background: true
|
|
25217
|
+
});
|
|
24997
25218
|
api.tools.register({
|
|
24998
25219
|
name: "type_gate_status",
|
|
24999
25220
|
description: "Reports type-gate state: command, tsconfig, severity, and per-session pass/fail/error counters.",
|