@wrongstack/plugins 1.0.7 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor/index.d.ts +1 -1
- package/dist/accessibility-auditor.js +15 -3
- package/dist/agent-handoff.js +6 -6
- package/dist/auto-doc/index.d.ts +1 -1
- package/dist/auto-doc.js +31 -20
- package/dist/auto-i18n-extractor/index.d.ts +1 -1
- package/dist/auto-i18n-extractor.js +12 -8
- package/dist/branch-guard.js +3 -3
- package/dist/changelog-writer/index.d.ts +1 -1
- package/dist/changelog-writer.js +19 -10
- package/dist/checkpoint/index.d.ts +1 -1
- package/dist/checkpoint.js +38 -24
- package/dist/code-metrics/index.d.ts +1 -1
- package/dist/code-metrics.js +12 -4
- package/dist/commit-validator.js +5 -5
- package/dist/context-pins/index.d.ts +1 -1
- package/dist/context-pins.js +12 -9
- package/dist/cost-tracker.js +21 -9
- package/dist/cron/index.d.ts +1 -1
- package/dist/cron.js +18 -5
- package/dist/dead-code-detector/index.d.ts +1 -1
- package/dist/dead-code-detector.js +14 -12
- package/dist/duplicate-code-detector/index.d.ts +1 -1
- package/dist/duplicate-code-detector.js +11 -3
- package/dist/feature-flag-tracker/index.d.ts +1 -1
- package/dist/feature-flag-tracker.js +12 -4
- package/dist/file-watcher/index.d.ts +1 -1
- package/dist/file-watcher.js +37 -38
- package/dist/git-autocommit/index.d.ts +1 -1
- package/dist/git-autocommit.js +44 -39
- package/dist/gitignore-guard/index.d.ts +1 -1
- package/dist/gitignore-guard.js +12 -6
- package/dist/index.js +1534 -1080
- package/dist/interface-contract-guard/index.d.ts +1 -1
- package/dist/interface-contract-guard.js +12 -4
- package/dist/knowledge-graph/index.d.ts +1 -1
- package/dist/knowledge-graph.js +11 -9
- package/dist/migration-planner/index.d.ts +1 -1
- package/dist/migration-planner.js +6 -2
- package/dist/notify-hub/index.d.ts +1 -1
- package/dist/notify-hub.js +12 -11
- package/dist/performance-regression-gate/index.d.ts +1 -1
- package/dist/performance-regression-gate.js +33 -13
- package/dist/pr-drafter/index.d.ts +10 -1
- package/dist/pr-drafter.js +57 -26
- package/dist/refactor-suggester/index.d.ts +1 -1
- package/dist/refactor-suggester.js +17 -4
- package/dist/release-notes-generator.js +2 -2
- package/dist/secret-scanner/index.d.ts +1 -1
- package/dist/secret-scanner.js +11 -3
- package/dist/security-hotspot-scanner/index.d.ts +1 -1
- package/dist/security-hotspot-scanner.js +6 -2
- package/dist/semantic-search-indexer/index.d.ts +1 -1
- package/dist/semantic-search-indexer.js +19 -3
- package/dist/semver-bump/index.d.ts +1 -1
- package/dist/semver-bump.js +57 -37
- package/dist/session-recap.js +4 -2
- package/dist/shell-check/index.d.ts +1 -1
- package/dist/shell-check.js +30 -39
- package/dist/smart-rename/index.d.ts +1 -1
- package/dist/smart-rename.js +23 -10
- package/dist/template-engine/index.d.ts +1 -1
- package/dist/template-engine.js +51 -38
- package/dist/test-flake-detector/index.d.ts +1 -1
- package/dist/test-flake-detector.js +11 -5
- package/dist/test-generator/index.d.ts +1 -1
- package/dist/test-generator.js +12 -8
- package/dist/todo-tracker/index.d.ts +68 -1
- package/dist/todo-tracker.js +579 -395
- package/dist/token-budget.js +7 -4
- package/dist/token-throttle.js +6 -3
- package/package.json +7 -7
|
@@ -13,8 +13,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
15
|
// src/interface-contract-guard/index.ts
|
|
16
|
-
import { readFile } from "node:fs/promises";
|
|
16
|
+
import { readFile, stat } from "node:fs/promises";
|
|
17
17
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
18
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
18
19
|
|
|
19
20
|
// src/runtime/index.ts
|
|
20
21
|
var runtime_exports = {};
|
|
@@ -216,19 +217,26 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
216
217
|
category: "Diagnostics",
|
|
217
218
|
mutating: false,
|
|
218
219
|
async execute(input) {
|
|
219
|
-
if (!cfg.enabled)
|
|
220
|
+
if (!cfg.enabled) throw new Error("interface-contract-guard is disabled");
|
|
220
221
|
const raw = input ?? {};
|
|
221
222
|
const rawPath = (typeof input.path === "string" && input.path.trim().length > 0 ? input.path.trim() : void 0) ?? (typeof raw["directory"] === "string" ? raw["directory"] : void 0) ?? (typeof raw["dir"] === "string" ? raw["dir"] : void 0) ?? (typeof raw["SearchDirectory"] === "string" ? raw["SearchDirectory"] : void 0) ?? (typeof raw["TargetFile"] === "string" ? raw["TargetFile"] : void 0) ?? (typeof raw["filePath"] === "string" ? raw["filePath"] : void 0) ?? (typeof raw["targetFile"] === "string" ? raw["targetFile"] : void 0) ?? (typeof raw["file"] === "string" ? raw["file"] : void 0) ?? ".";
|
|
222
223
|
if (!(0, runtime_exports.withinProject)(rawPath)) {
|
|
223
|
-
|
|
224
|
+
throw new ToolValidationError({
|
|
225
|
+
message: "path is outside the project root",
|
|
226
|
+
field: "path"
|
|
227
|
+
});
|
|
224
228
|
}
|
|
225
229
|
state.scanCount += 1;
|
|
226
230
|
let result;
|
|
227
231
|
try {
|
|
232
|
+
await stat(resolve(process.cwd(), rawPath));
|
|
228
233
|
result = await scanPath(rawPath, cfg);
|
|
229
234
|
} catch (err) {
|
|
230
235
|
state.errorCount += 1;
|
|
231
|
-
|
|
236
|
+
throw new Error(
|
|
237
|
+
`check_interface_contracts failed for ${rawPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
238
|
+
{ cause: err }
|
|
239
|
+
);
|
|
232
240
|
}
|
|
233
241
|
state.findingCount += result.findings.length;
|
|
234
242
|
return {
|
package/dist/knowledge-graph.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/knowledge-graph/index.ts
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
4
5
|
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
5
6
|
var API_VERSION = "^0.1.10";
|
|
6
7
|
var state = {
|
|
@@ -171,12 +172,9 @@ var plugin = {
|
|
|
171
172
|
category: "Memory",
|
|
172
173
|
mutating: true,
|
|
173
174
|
async execute(input) {
|
|
174
|
-
if (!cfg.enabled)
|
|
175
|
+
if (!cfg.enabled) throw new Error("knowledge-graph is disabled");
|
|
175
176
|
if (state.facts.length >= cfg.maxFacts) {
|
|
176
|
-
|
|
177
|
-
ok: false,
|
|
178
|
-
error: `fact limit reached (${cfg.maxFacts}). Remove old facts first.`
|
|
179
|
-
};
|
|
177
|
+
throw new Error(`fact limit reached (${cfg.maxFacts}). Remove old facts first.`);
|
|
180
178
|
}
|
|
181
179
|
const trim = (s) => String(s ?? "").trim().slice(0, cfg.maxFactChars);
|
|
182
180
|
const raw = input;
|
|
@@ -190,7 +188,10 @@ var plugin = {
|
|
|
190
188
|
input.object ?? raw["target"] ?? raw["val"] ?? raw["value"] ?? raw["obj"] ?? raw["targetEntity"]
|
|
191
189
|
);
|
|
192
190
|
if (!subject || !relation || !object) {
|
|
193
|
-
|
|
191
|
+
throw new ToolValidationError({
|
|
192
|
+
message: "subject, relation, and object are required",
|
|
193
|
+
field: !subject ? "subject" : !relation ? "relation" : "object"
|
|
194
|
+
});
|
|
194
195
|
}
|
|
195
196
|
const rawConf = typeof input.confidence === "string" ? input.confidence.trim().toLowerCase() : "";
|
|
196
197
|
const confidence = rawConf === "low" || rawConf === "high" || rawConf === "medium" ? rawConf : "medium";
|
|
@@ -227,7 +228,7 @@ var plugin = {
|
|
|
227
228
|
category: "Memory",
|
|
228
229
|
mutating: false,
|
|
229
230
|
async execute(input) {
|
|
230
|
-
if (!cfg.enabled)
|
|
231
|
+
if (!cfg.enabled) throw new Error("knowledge-graph is disabled");
|
|
231
232
|
state.queries += 1;
|
|
232
233
|
const raw = input;
|
|
233
234
|
const rawQ = (typeof raw["query"] === "string" ? raw["query"] : void 0) ?? (typeof raw["q"] === "string" ? raw["q"] : void 0);
|
|
@@ -272,16 +273,17 @@ var plugin = {
|
|
|
272
273
|
category: "Memory",
|
|
273
274
|
mutating: true,
|
|
274
275
|
async execute(input) {
|
|
275
|
-
if (!cfg.enabled)
|
|
276
|
+
if (!cfg.enabled) throw new Error("knowledge-graph is disabled");
|
|
276
277
|
const before = state.facts.length;
|
|
277
278
|
const raw = input ?? {};
|
|
278
279
|
const rawId = String(input.id ?? raw["factId"] ?? raw["fact_id"] ?? "").trim();
|
|
280
|
+
if (!rawId) throw new ToolValidationError({ message: "id is required", field: "id" });
|
|
279
281
|
const normalized = rawId.toLowerCase().startsWith("kg-") ? rawId.toLowerCase() : `kg-${rawId.toLowerCase()}`;
|
|
280
282
|
state.facts = state.facts.filter(
|
|
281
283
|
(f) => f.id.toLowerCase() !== normalized && f.id !== rawId
|
|
282
284
|
);
|
|
283
285
|
const removed = before - state.facts.length;
|
|
284
|
-
if (removed === 0)
|
|
286
|
+
if (removed === 0) throw new Error(`no fact matches "${input.id ?? rawId}"`);
|
|
285
287
|
state.removals += removed;
|
|
286
288
|
api.metrics.counter("removals", removed);
|
|
287
289
|
const persisted = await persistFacts(resolved);
|
|
@@ -14,6 +14,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
14
14
|
|
|
15
15
|
// src/migration-planner/index.ts
|
|
16
16
|
import { existsSync, readFileSync } from "node:fs";
|
|
17
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
17
18
|
|
|
18
19
|
// src/runtime/index.ts
|
|
19
20
|
var runtime_exports = {};
|
|
@@ -392,7 +393,7 @@ var plugin = {
|
|
|
392
393
|
category: "Planning",
|
|
393
394
|
mutating: false,
|
|
394
395
|
async execute(input, _ctx, execOpts) {
|
|
395
|
-
if (!cfg.enabled)
|
|
396
|
+
if (!cfg.enabled) throw new Error("migration-planner is disabled");
|
|
396
397
|
execOpts?.signal?.throwIfAborted();
|
|
397
398
|
const raw = input ?? {};
|
|
398
399
|
const rawPackage = input.packageName || raw["package"] || raw["pkg"] || raw["name"] || raw["package_name"] || raw["packageName"] || raw["dependency"] || raw["dep"] || raw["module"];
|
|
@@ -403,7 +404,10 @@ var plugin = {
|
|
|
403
404
|
const fromVersion = String(rawFrom ?? "").trim();
|
|
404
405
|
const toVersion = String(rawTo ?? "").trim();
|
|
405
406
|
if (!packageName || !fromVersion || !toVersion) {
|
|
406
|
-
|
|
407
|
+
throw new ToolValidationError({
|
|
408
|
+
message: "packageName, fromVersion, and toVersion are required",
|
|
409
|
+
field: !packageName ? "packageName" : !fromVersion ? "fromVersion" : "toVersion"
|
|
410
|
+
});
|
|
407
411
|
}
|
|
408
412
|
const changelog = readChangelog(packageName, cfg);
|
|
409
413
|
let breakingChanges;
|
package/dist/notify-hub.js
CHANGED
|
@@ -14,6 +14,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
14
14
|
|
|
15
15
|
// src/notify-hub/index.ts
|
|
16
16
|
import { lookup } from "node:dns/promises";
|
|
17
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
17
18
|
|
|
18
19
|
// src/runtime/index.ts
|
|
19
20
|
var runtime_exports = {};
|
|
@@ -421,18 +422,19 @@ var plugin = {
|
|
|
421
422
|
category: "Notifications",
|
|
422
423
|
mutating: true,
|
|
423
424
|
async execute(input) {
|
|
424
|
-
if (!cfg.enabled)
|
|
425
|
+
if (!cfg.enabled) throw new Error("notify-hub is disabled");
|
|
425
426
|
const ch = state.channel;
|
|
426
427
|
if (!ch) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
};
|
|
428
|
+
throw new Error(
|
|
429
|
+
'no webhookUrl configured \u2014 set config.extensions["notify-hub"].webhookUrl to enable deliveries'
|
|
430
|
+
);
|
|
431
431
|
}
|
|
432
432
|
const inp = input ?? {};
|
|
433
433
|
const rawMsg = inp["message"] ?? inp["body"] ?? inp["text"] ?? inp["content"] ?? inp["msg"];
|
|
434
434
|
const message = typeof rawMsg === "string" && rawMsg.trim().length > 0 ? rawMsg.trim() : "";
|
|
435
|
-
if (!message)
|
|
435
|
+
if (!message) {
|
|
436
|
+
throw new ToolValidationError({ message: "message is required", field: "message" });
|
|
437
|
+
}
|
|
436
438
|
const rawTitle = inp["title"] ?? inp["subject"] ?? inp["header"];
|
|
437
439
|
const title = typeof rawTitle === "string" && rawTitle.trim() ? rawTitle.trim() : "WrongStack notification";
|
|
438
440
|
const result = await deliverViaChannel(ch, "manual", {
|
|
@@ -441,11 +443,10 @@ var plugin = {
|
|
|
441
443
|
level: input.level === "warning" || input.level === "critical" ? input.level : "info",
|
|
442
444
|
source: "manual"
|
|
443
445
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
};
|
|
446
|
+
if (!result.ok) {
|
|
447
|
+
throw new Error(`notification delivery failed: ${result.error ?? "unknown error"}`);
|
|
448
|
+
}
|
|
449
|
+
return { ok: true, circuitOpen: ch.circuitStatus().open };
|
|
449
450
|
}
|
|
450
451
|
});
|
|
451
452
|
api.tools.register({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/performance-regression-gate/index.ts
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
4
5
|
var API_VERSION = "^0.1.10";
|
|
5
6
|
var state = {
|
|
6
7
|
invocationCount: 0,
|
|
@@ -67,10 +68,11 @@ function flattenResults(results) {
|
|
|
67
68
|
function loadResults(path) {
|
|
68
69
|
if (!path || !existsSync(path)) return null;
|
|
69
70
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
72
|
+
} catch (err) {
|
|
73
|
+
throw new Error(`Could not read benchmark results at ${path}: ${String(err)}`, {
|
|
74
|
+
cause: err
|
|
75
|
+
});
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
78
|
function stripVariantSuffix(name) {
|
|
@@ -197,7 +199,7 @@ var plugin = {
|
|
|
197
199
|
mutating: false,
|
|
198
200
|
async execute(input) {
|
|
199
201
|
if (!cfg.enabled) {
|
|
200
|
-
|
|
202
|
+
throw new Error("performance-regression-gate is disabled");
|
|
201
203
|
}
|
|
202
204
|
state.invocationCount += 1;
|
|
203
205
|
const raw = input ?? {};
|
|
@@ -208,11 +210,23 @@ var plugin = {
|
|
|
208
210
|
const resultsPath = resolveProjectPath(resultsPathStr) ?? "";
|
|
209
211
|
if (!resultsPath) {
|
|
210
212
|
state.errorCount += 1;
|
|
211
|
-
|
|
213
|
+
throw new ToolValidationError({
|
|
214
|
+
message: "invalid results path (must be inside project)",
|
|
215
|
+
field: "resultsPath"
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
let results;
|
|
219
|
+
try {
|
|
220
|
+
results = loadResults(resultsPath);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
state.errorCount += 1;
|
|
223
|
+
throw err;
|
|
212
224
|
}
|
|
213
|
-
const results = loadResults(resultsPath);
|
|
214
225
|
if (!results) {
|
|
215
226
|
state.missingResultsCount += 1;
|
|
227
|
+
if (resultsPathStr !== "bench-results.json" || rawResultsPath !== "bench-results.json") {
|
|
228
|
+
throw new Error(`No benchmark results found at ${resultsPathStr}.`);
|
|
229
|
+
}
|
|
216
230
|
return {
|
|
217
231
|
ok: true,
|
|
218
232
|
hasResults: false,
|
|
@@ -241,15 +255,21 @@ var plugin = {
|
|
|
241
255
|
const baselineResolved = resolveProjectPath(baselinePathStr) ?? "";
|
|
242
256
|
if (!baselineResolved) {
|
|
243
257
|
state.errorCount += 1;
|
|
244
|
-
|
|
258
|
+
throw new ToolValidationError({
|
|
259
|
+
message: "invalid baseline path (must be inside project)",
|
|
260
|
+
field: "baselinePath"
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
let baselineResults;
|
|
264
|
+
try {
|
|
265
|
+
baselineResults = loadResults(baselineResolved);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
state.errorCount += 1;
|
|
268
|
+
throw err;
|
|
245
269
|
}
|
|
246
|
-
const baselineResults = loadResults(baselineResolved);
|
|
247
270
|
if (!baselineResults) {
|
|
248
271
|
state.errorCount += 1;
|
|
249
|
-
|
|
250
|
-
ok: false,
|
|
251
|
-
error: `Could not read baseline results at ${baselinePathStr}.`
|
|
252
|
-
};
|
|
272
|
+
throw new Error(`Could not read baseline results at ${baselinePathStr}.`);
|
|
253
273
|
}
|
|
254
274
|
const baseline = flattenResults(baselineResults);
|
|
255
275
|
pairs = pairCrossFile(baseline, current);
|
|
@@ -27,7 +27,16 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @public
|
|
29
29
|
*/
|
|
30
|
-
import type
|
|
30
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
31
|
+
/**
|
|
32
|
+
* Extract the commit from git_autocommit's serialized result (`{ok, hash, message, …, diff}`).
|
|
33
|
+
* Regex, not JSON.parse: the trailing diff can push the text past the output budget and
|
|
34
|
+
* truncate it. A dry run carries no `hash`, so it records nothing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseAutocommitResult(content: string): {
|
|
37
|
+
hash: string;
|
|
38
|
+
message: string;
|
|
39
|
+
} | null;
|
|
31
40
|
declare const plugin: Plugin;
|
|
32
41
|
export default plugin;
|
|
33
42
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/pr-drafter.js
CHANGED
|
@@ -16,6 +16,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
16
16
|
import { execFile } from "node:child_process";
|
|
17
17
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
18
18
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
19
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
19
20
|
|
|
20
21
|
// src/runtime/index.ts
|
|
21
22
|
var runtime_exports = {};
|
|
@@ -35,8 +36,23 @@ var state = {
|
|
|
35
36
|
draftErrors: 0,
|
|
36
37
|
stopInvocations: 0,
|
|
37
38
|
stopHookUnregister: null,
|
|
39
|
+
postHookUnregister: null,
|
|
38
40
|
eventUnsubscribers: []
|
|
39
41
|
};
|
|
42
|
+
var TRACKED_FILE_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "write_to_file", "replace_file_content"]);
|
|
43
|
+
function parseAutocommitResult(content) {
|
|
44
|
+
const hash = /"hash":\s*"([0-9a-f]{7,64})"/.exec(content)?.[1];
|
|
45
|
+
if (!hash) return null;
|
|
46
|
+
const rawMessage = /"message":\s*("(?:[^"\\]|\\.)*")/.exec(content)?.[1];
|
|
47
|
+
let message = "commit";
|
|
48
|
+
if (rawMessage) {
|
|
49
|
+
try {
|
|
50
|
+
message = JSON.parse(rawMessage);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { hash, message };
|
|
55
|
+
}
|
|
40
56
|
var DEFAULTS = {
|
|
41
57
|
enabled: true,
|
|
42
58
|
outputPath: ".wrongstack/PR_DRAFT.md",
|
|
@@ -219,6 +235,7 @@ var plugin = {
|
|
|
219
235
|
state.draftErrors = 0;
|
|
220
236
|
state.stopInvocations = 0;
|
|
221
237
|
state.stopHookUnregister = (0, runtime_exports.releaseHandle)(state.stopHookUnregister);
|
|
238
|
+
state.postHookUnregister = (0, runtime_exports.releaseHandle)(state.postHookUnregister);
|
|
222
239
|
for (const off of state.eventUnsubscribers) {
|
|
223
240
|
try {
|
|
224
241
|
off();
|
|
@@ -228,22 +245,24 @@ var plugin = {
|
|
|
228
245
|
state.eventUnsubscribers = [];
|
|
229
246
|
const cfg = readConfig(api.config.extensions?.["pr-drafter"]);
|
|
230
247
|
if (api.onPattern) {
|
|
231
|
-
const offTool = api.onPattern("tool.completed", (
|
|
232
|
-
const p = payload;
|
|
233
|
-
const toolName = p?.tool;
|
|
248
|
+
const offTool = api.onPattern("tool.completed", () => {
|
|
234
249
|
state.toolCalls += 1;
|
|
235
|
-
if (toolName === "git_autocommit" && p?.result?.committed) {
|
|
236
|
-
const msg = p.result.commitMessage ?? p.input?.message ?? "commit";
|
|
237
|
-
state.commits.push(msg);
|
|
238
|
-
}
|
|
239
|
-
const rawInput = p?.input ?? {};
|
|
240
|
-
const filePath = typeof rawInput["path"] === "string" && rawInput["path"] || typeof rawInput["filePath"] === "string" && rawInput["filePath"] || typeof rawInput["file_path"] === "string" && rawInput["file_path"] || typeof rawInput["TargetFile"] === "string" && rawInput["TargetFile"] || typeof rawInput["targetFile"] === "string" && rawInput["targetFile"] || typeof rawInput["file"] === "string" && rawInput["file"];
|
|
241
|
-
if ((toolName === "write" || toolName === "edit" || toolName === "write_to_file" || toolName === "replace_file_content") && filePath) {
|
|
242
|
-
state.files.add(filePath);
|
|
243
|
-
}
|
|
244
250
|
});
|
|
245
251
|
state.eventUnsubscribers.push(offTool);
|
|
246
252
|
}
|
|
253
|
+
const postHook = (input) => {
|
|
254
|
+
if (!input.toolResult || input.toolResult.isError) return;
|
|
255
|
+
const toolName = input.toolName;
|
|
256
|
+
if (toolName === "git_autocommit") {
|
|
257
|
+
const commit = parseAutocommitResult(String(input.toolResult.content ?? ""));
|
|
258
|
+
if (commit) state.commits.push(commit.message);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (!toolName || !TRACKED_FILE_TOOLS.has(toolName)) return;
|
|
262
|
+
const rawInput = input.toolInput ?? {};
|
|
263
|
+
const filePath = ["path", "filePath", "file_path", "TargetFile", "targetFile", "file"].map((key) => rawInput[key]).find((value) => typeof value === "string" && value.length > 0);
|
|
264
|
+
if (filePath) state.files.add(filePath);
|
|
265
|
+
};
|
|
247
266
|
if (api.onEvent) {
|
|
248
267
|
const offUsage = api.onEvent("provider.response", (payload) => {
|
|
249
268
|
const p = payload;
|
|
@@ -262,6 +281,11 @@ var plugin = {
|
|
|
262
281
|
await writeDraft(cfg, api.llm);
|
|
263
282
|
};
|
|
264
283
|
state.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
|
|
284
|
+
state.postHookUnregister = api.registerHook(
|
|
285
|
+
"PostToolUse",
|
|
286
|
+
"git_autocommit|write|edit|write_to_file|replace_file_content",
|
|
287
|
+
postHook
|
|
288
|
+
);
|
|
265
289
|
api.tools.register({
|
|
266
290
|
name: "pr_draft",
|
|
267
291
|
description: "Generate or refresh the pull-request draft for the current session. Writes the markdown file and returns its path + title.",
|
|
@@ -284,7 +308,7 @@ var plugin = {
|
|
|
284
308
|
mutating: true,
|
|
285
309
|
capabilities: ["fs.write"],
|
|
286
310
|
async execute(input = {}) {
|
|
287
|
-
if (!cfg.enabled)
|
|
311
|
+
if (!cfg.enabled) throw new Error("pr-drafter is disabled");
|
|
288
312
|
const raw = input ?? {};
|
|
289
313
|
const preview = Boolean(
|
|
290
314
|
input?.preview ?? raw["dryRun"] ?? raw["dry_run"] ?? raw["dry"] ?? raw["previewOnly"]
|
|
@@ -296,24 +320,29 @@ var plugin = {
|
|
|
296
320
|
return { ok: true, preview: true, title: draft.title, body: draft.body };
|
|
297
321
|
}
|
|
298
322
|
const resolved = resolveProjectPath(outputPathStr);
|
|
299
|
-
if (!resolved)
|
|
323
|
+
if (!resolved) {
|
|
324
|
+
throw new ToolValidationError({
|
|
325
|
+
message: "outputPath resolves outside project",
|
|
326
|
+
field: "outputPath"
|
|
327
|
+
});
|
|
328
|
+
}
|
|
300
329
|
try {
|
|
301
330
|
await mkdir(dirname(resolved), { recursive: true });
|
|
302
331
|
await writeFile(resolved, draft.body);
|
|
303
|
-
state.draftsWritten += 1;
|
|
304
|
-
return {
|
|
305
|
-
ok: true,
|
|
306
|
-
path: outputPathStr,
|
|
307
|
-
resolvedPath: resolved,
|
|
308
|
-
title: draft.title
|
|
309
|
-
};
|
|
310
332
|
} catch (err) {
|
|
311
333
|
state.draftErrors += 1;
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
334
|
+
throw new Error(
|
|
335
|
+
`Could not write PR draft to ${outputPathStr}: ${err instanceof Error ? err.message : String(err)}`,
|
|
336
|
+
{ cause: err }
|
|
337
|
+
);
|
|
316
338
|
}
|
|
339
|
+
state.draftsWritten += 1;
|
|
340
|
+
return {
|
|
341
|
+
ok: true,
|
|
342
|
+
path: outputPathStr,
|
|
343
|
+
resolvedPath: resolved,
|
|
344
|
+
title: draft.title
|
|
345
|
+
};
|
|
317
346
|
}
|
|
318
347
|
});
|
|
319
348
|
api.log.info("pr-drafter plugin loaded", {
|
|
@@ -330,6 +359,7 @@ var plugin = {
|
|
|
330
359
|
}
|
|
331
360
|
state.stopHookUnregister = null;
|
|
332
361
|
}
|
|
362
|
+
state.postHookUnregister = (0, runtime_exports.releaseHandle)(state.postHookUnregister);
|
|
333
363
|
for (const off of state.eventUnsubscribers) {
|
|
334
364
|
try {
|
|
335
365
|
off();
|
|
@@ -371,5 +401,6 @@ var plugin = {
|
|
|
371
401
|
};
|
|
372
402
|
var pr_drafter_default = plugin;
|
|
373
403
|
export {
|
|
374
|
-
pr_drafter_default as default
|
|
404
|
+
pr_drafter_default as default,
|
|
405
|
+
parseAutocommitResult
|
|
375
406
|
};
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @public
|
|
25
25
|
*/
|
|
26
|
-
import type
|
|
26
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
27
27
|
export type SmellType = 'long-function' | 'deep-nesting' | 'many-parameters' | 'magic-number' | 'console-log';
|
|
28
28
|
export interface RefactorSuggestion {
|
|
29
29
|
file: string;
|
|
@@ -13,8 +13,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
15
|
// src/refactor-suggester/index.ts
|
|
16
|
-
import { readFile } from "node:fs/promises";
|
|
16
|
+
import { readFile, stat } from "node:fs/promises";
|
|
17
17
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
18
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
18
19
|
|
|
19
20
|
// src/runtime/index.ts
|
|
20
21
|
var runtime_exports = {};
|
|
@@ -311,11 +312,23 @@ var plugin = {
|
|
|
311
312
|
category: "Diagnostics",
|
|
312
313
|
mutating: false,
|
|
313
314
|
async execute(input) {
|
|
314
|
-
if (!cfg.enabled)
|
|
315
|
+
if (!cfg.enabled) throw new Error("refactor-suggester is disabled");
|
|
315
316
|
const raw = input ?? {};
|
|
316
317
|
const rawPath = (typeof input.path === "string" && input.path.trim().length > 0 ? input.path.trim() : void 0) ?? (typeof raw["directory"] === "string" ? raw["directory"] : void 0) ?? (typeof raw["dir"] === "string" ? raw["dir"] : void 0) ?? (typeof raw["SearchDirectory"] === "string" ? raw["SearchDirectory"] : void 0) ?? (typeof raw["TargetFile"] === "string" ? raw["TargetFile"] : void 0) ?? (typeof raw["filePath"] === "string" ? raw["filePath"] : void 0) ?? (typeof raw["targetFile"] === "string" ? raw["targetFile"] : void 0) ?? ".";
|
|
317
318
|
if (!(0, runtime_exports.withinProject)(rawPath)) {
|
|
318
|
-
|
|
319
|
+
throw new ToolValidationError({
|
|
320
|
+
message: "path is outside the project root",
|
|
321
|
+
field: "path"
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
await stat(resolve(process.cwd(), rawPath));
|
|
326
|
+
} catch (err) {
|
|
327
|
+
throw new ToolValidationError({
|
|
328
|
+
message: `path does not exist or cannot be read: ${rawPath}`,
|
|
329
|
+
field: "path",
|
|
330
|
+
cause: err
|
|
331
|
+
});
|
|
319
332
|
}
|
|
320
333
|
state.scanCount += 1;
|
|
321
334
|
let result;
|
|
@@ -323,7 +336,7 @@ var plugin = {
|
|
|
323
336
|
result = await scanPath(rawPath, cfg);
|
|
324
337
|
} catch (err) {
|
|
325
338
|
state.errorCount += 1;
|
|
326
|
-
|
|
339
|
+
throw new Error(`refactor scan failed: ${String(err)}`, { cause: err });
|
|
327
340
|
}
|
|
328
341
|
state.suggestionCount += result.suggestions.length;
|
|
329
342
|
return {
|
|
@@ -284,7 +284,7 @@ var plugin = {
|
|
|
284
284
|
category: "Development",
|
|
285
285
|
mutating: false,
|
|
286
286
|
async execute(input, _ctx, execOpts) {
|
|
287
|
-
if (!cfg.enabled)
|
|
287
|
+
if (!cfg.enabled) throw new Error("release-notes-generator is disabled");
|
|
288
288
|
execOpts?.signal?.throwIfAborted();
|
|
289
289
|
const raw = input ?? {};
|
|
290
290
|
const rawTo = input.to ?? raw["to_ref"] ?? raw["toRef"] ?? raw["until"] ?? raw["end"];
|
|
@@ -299,7 +299,7 @@ var plugin = {
|
|
|
299
299
|
commits = await getCommits(fromRef, toRef, execOpts?.signal);
|
|
300
300
|
} catch (err) {
|
|
301
301
|
state.errorCount += 1;
|
|
302
|
-
|
|
302
|
+
throw new Error(`Could not read git history: ${String(err)}`, { cause: err });
|
|
303
303
|
}
|
|
304
304
|
state.commitCount += commits.length;
|
|
305
305
|
execOpts?.signal?.throwIfAborted();
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* They share the same threat model but act at different points in the
|
|
27
27
|
* pipeline.
|
|
28
28
|
*/
|
|
29
|
-
import type
|
|
29
|
+
import { type Plugin } from '@wrongstack/core/types';
|
|
30
30
|
declare const plugin: Plugin;
|
|
31
31
|
export default plugin;
|
|
32
32
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/secret-scanner.js
CHANGED
|
@@ -12,6 +12,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
12
12
|
};
|
|
13
13
|
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
14
|
|
|
15
|
+
// src/secret-scanner/index.ts
|
|
16
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
17
|
+
|
|
15
18
|
// src/runtime/credential-patterns.ts
|
|
16
19
|
import {
|
|
17
20
|
cloneCredentialPatterns,
|
|
@@ -447,9 +450,14 @@ var plugin = {
|
|
|
447
450
|
mutating: false,
|
|
448
451
|
async execute(input) {
|
|
449
452
|
activateRuntime(runtime);
|
|
450
|
-
const rawText = input["text"] ?? input["content"] ?? input["string"] ?? input["input"] ?? input["code"] ?? input["value"]
|
|
451
|
-
|
|
452
|
-
|
|
453
|
+
const rawText = input["text"] ?? input["content"] ?? input["string"] ?? input["input"] ?? input["code"] ?? input["value"];
|
|
454
|
+
if (typeof rawText !== "string") {
|
|
455
|
+
throw new ToolValidationError({
|
|
456
|
+
message: "text is required and must be a string",
|
|
457
|
+
field: "text"
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const matched = findMatches(rawText);
|
|
453
461
|
return {
|
|
454
462
|
ok: true,
|
|
455
463
|
matched,
|
|
@@ -15,6 +15,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
15
15
|
// src/security-hotspot-scanner/index.ts
|
|
16
16
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
17
17
|
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
18
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
18
19
|
|
|
19
20
|
// src/runtime/index.ts
|
|
20
21
|
var runtime_exports = {};
|
|
@@ -335,7 +336,7 @@ Review or remove the risky pattern(s).`;
|
|
|
335
336
|
category: "Security",
|
|
336
337
|
mutating: false,
|
|
337
338
|
async execute(input) {
|
|
338
|
-
if (!cfg.enabled)
|
|
339
|
+
if (!cfg.enabled) throw new Error("security-hotspot-scanner is disabled");
|
|
339
340
|
const raw = input;
|
|
340
341
|
const targetPath = (typeof input.path === "string" ? input.path : void 0) ?? (typeof raw["directory"] === "string" ? raw["directory"] : void 0) ?? (typeof raw["dir"] === "string" ? raw["dir"] : void 0) ?? (typeof raw["SearchDirectory"] === "string" ? raw["SearchDirectory"] : void 0) ?? (typeof raw["TargetFile"] === "string" ? raw["TargetFile"] : void 0) ?? (typeof raw["filePath"] === "string" ? raw["filePath"] : void 0) ?? (typeof raw["targetFile"] === "string" ? raw["targetFile"] : void 0) ?? ".";
|
|
341
342
|
const result = await scanPath(targetPath, cfg);
|
|
@@ -343,7 +344,10 @@ Review or remove the risky pattern(s).`;
|
|
|
343
344
|
state.fileScanCount += result.filesScanned;
|
|
344
345
|
state.findingCount += result.findings.length;
|
|
345
346
|
if (!result.scanned) {
|
|
346
|
-
|
|
347
|
+
throw new ToolValidationError({
|
|
348
|
+
message: `cannot scan ${targetPath}: ${result.error ?? "unknown error"}`,
|
|
349
|
+
field: "path"
|
|
350
|
+
});
|
|
347
351
|
}
|
|
348
352
|
state.lastResult = {
|
|
349
353
|
path: result.path,
|