@wrongstack/plugins 1.0.8 → 1.0.11
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 +1553 -1086
- 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/loop-breaker.js +11 -4
- 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 +19 -12
- 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);
|
package/dist/loop-breaker.js
CHANGED
|
@@ -24,7 +24,10 @@ var state = {
|
|
|
24
24
|
};
|
|
25
25
|
var DEFAULTS = {
|
|
26
26
|
enabled: true,
|
|
27
|
-
|
|
27
|
+
// Documented contract (feature matrix, plugin description): warn, then
|
|
28
|
+
// block. A warn-only default meant an agent stuck re-issuing the same call
|
|
29
|
+
// was never actually stopped unless the user happened to set any option.
|
|
30
|
+
mode: "block",
|
|
28
31
|
warnAfter: 3,
|
|
29
32
|
blockAfter: 5,
|
|
30
33
|
oscillationWindow: 8,
|
|
@@ -50,7 +53,7 @@ function readConfig(raw) {
|
|
|
50
53
|
const ignoreTools = Array.isArray(rawIgnore) ? rawIgnore.filter((t) => typeof t === "string") : [];
|
|
51
54
|
ignoreToolsSet = new Set(ignoreTools);
|
|
52
55
|
const rawMode = typeof (r["mode"] ?? r["action"] ?? r["behavior"]) === "string" ? String(r["mode"] ?? r["action"] ?? r["behavior"]).trim().toLowerCase() : void 0;
|
|
53
|
-
const mode = rawMode === "warn"
|
|
56
|
+
const mode = rawMode === "warn" || rawMode === "block" ? rawMode : DEFAULTS.mode;
|
|
54
57
|
const rawOsc = r["oscillationWindow"] ?? r["oscillation_window"] ?? r["window"];
|
|
55
58
|
const rawMaxSteps = r["maxSteps"] ?? r["max_steps"] ?? r["stepLimit"] ?? r["step_limit"];
|
|
56
59
|
return {
|
|
@@ -79,7 +82,11 @@ function sortKeys(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
|
79
82
|
if (value === null || typeof value !== "object") return value;
|
|
80
83
|
if (seen.has(value)) return "[circular]";
|
|
81
84
|
if (depth >= CANONICALIZE_MAX_DEPTH) {
|
|
82
|
-
|
|
85
|
+
try {
|
|
86
|
+
return `[deep:${JSON.stringify(value)}]`;
|
|
87
|
+
} catch {
|
|
88
|
+
return Array.isArray(value) ? `[array:${value.length}]` : "[deep-object]";
|
|
89
|
+
}
|
|
83
90
|
}
|
|
84
91
|
seen.add(value);
|
|
85
92
|
try {
|
|
@@ -167,7 +174,7 @@ var plugin = {
|
|
|
167
174
|
mode: {
|
|
168
175
|
type: "string",
|
|
169
176
|
enum: ["warn", "block"],
|
|
170
|
-
default: "
|
|
177
|
+
default: "block",
|
|
171
178
|
description: "block = refuse the repeated call; warn = only inject context."
|
|
172
179
|
},
|
|
173
180
|
warnAfter: {
|
|
@@ -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 = {};
|
|
@@ -181,7 +182,13 @@ var DEFAULTS = {
|
|
|
181
182
|
maxConsecutiveFailures: 5
|
|
182
183
|
};
|
|
183
184
|
function isPrivateIPv4(hostname) {
|
|
184
|
-
const
|
|
185
|
+
const hexMapped = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(hostname);
|
|
186
|
+
const normalised = hexMapped ? [
|
|
187
|
+
Number.parseInt(hexMapped[1], 16) >> 8,
|
|
188
|
+
Number.parseInt(hexMapped[1], 16) & 255,
|
|
189
|
+
Number.parseInt(hexMapped[2], 16) >> 8,
|
|
190
|
+
Number.parseInt(hexMapped[2], 16) & 255
|
|
191
|
+
].join(".") : hostname.replace(/^::ffff:/i, "");
|
|
185
192
|
const parts = normalised.split(".").map((p) => Number(p));
|
|
186
193
|
if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255)) {
|
|
187
194
|
return false;
|
|
@@ -421,18 +428,19 @@ var plugin = {
|
|
|
421
428
|
category: "Notifications",
|
|
422
429
|
mutating: true,
|
|
423
430
|
async execute(input) {
|
|
424
|
-
if (!cfg.enabled)
|
|
431
|
+
if (!cfg.enabled) throw new Error("notify-hub is disabled");
|
|
425
432
|
const ch = state.channel;
|
|
426
433
|
if (!ch) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
};
|
|
434
|
+
throw new Error(
|
|
435
|
+
'no webhookUrl configured \u2014 set config.extensions["notify-hub"].webhookUrl to enable deliveries'
|
|
436
|
+
);
|
|
431
437
|
}
|
|
432
438
|
const inp = input ?? {};
|
|
433
439
|
const rawMsg = inp["message"] ?? inp["body"] ?? inp["text"] ?? inp["content"] ?? inp["msg"];
|
|
434
440
|
const message = typeof rawMsg === "string" && rawMsg.trim().length > 0 ? rawMsg.trim() : "";
|
|
435
|
-
if (!message)
|
|
441
|
+
if (!message) {
|
|
442
|
+
throw new ToolValidationError({ message: "message is required", field: "message" });
|
|
443
|
+
}
|
|
436
444
|
const rawTitle = inp["title"] ?? inp["subject"] ?? inp["header"];
|
|
437
445
|
const title = typeof rawTitle === "string" && rawTitle.trim() ? rawTitle.trim() : "WrongStack notification";
|
|
438
446
|
const result = await deliverViaChannel(ch, "manual", {
|
|
@@ -441,11 +449,10 @@ var plugin = {
|
|
|
441
449
|
level: input.level === "warning" || input.level === "critical" ? input.level : "info",
|
|
442
450
|
source: "manual"
|
|
443
451
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
};
|
|
452
|
+
if (!result.ok) {
|
|
453
|
+
throw new Error(`notification delivery failed: ${result.error ?? "unknown error"}`);
|
|
454
|
+
}
|
|
455
|
+
return { ok: true, circuitOpen: ch.circuitStatus().open };
|
|
449
456
|
}
|
|
450
457
|
});
|
|
451
458
|
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
|