@wrongstack/plugins 0.319.1 → 1.0.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/checkpoint.js +40 -7
- package/dist/index.js +90 -35
- package/dist/migration-planner.js +1 -1
- package/dist/path-guard/index.d.ts +8 -1
- package/dist/path-guard.js +34 -14
- package/dist/prompt-firewall.js +2 -2
- package/dist/release-notes-generator.js +1 -1
- package/dist/runtime/credential-patterns.d.ts +2 -2
- package/dist/runtime/h1-state.d.ts +2 -2
- package/dist/runtime/handles.d.ts +2 -2
- package/dist/runtime/index.d.ts +19 -2
- package/dist/runtime/llm.d.ts +2 -2
- package/dist/runtime/redos-guard.d.ts +2 -2
- package/dist/runtime/sandbox.d.ts +2 -2
- package/dist/secret-scanner.js +1 -1
- package/dist/test-generator.js +1 -1
- package/package.json +5 -5
package/dist/checkpoint.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/checkpoint/index.ts
|
|
2
|
-
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile, realpath, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
4
|
var state = {
|
|
5
5
|
snapshots: [],
|
|
@@ -28,13 +28,46 @@ function readConfig(raw) {
|
|
|
28
28
|
maxFileBytes: typeof r["maxFileBytes"] === "number" && r["maxFileBytes"] >= 1024 ? r["maxFileBytes"] : DEFAULTS.maxFileBytes
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
function resolveProjectPath(rawPath, cwd = process.cwd()) {
|
|
31
|
+
async function resolveProjectPath(rawPath, cwd = process.cwd()) {
|
|
32
32
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
33
33
|
const root = resolve(cwd);
|
|
34
34
|
const resolved = isAbsolute(rawPath) ? resolve(rawPath) : resolve(root, rawPath);
|
|
35
35
|
const rel = relative(root, resolved);
|
|
36
|
-
|
|
37
|
-
return null;
|
|
36
|
+
const lexicallyInside = rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
37
|
+
if (!lexicallyInside) return null;
|
|
38
|
+
if (await realResolutionEscapes(resolved, root)) return null;
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
async function realResolutionEscapes(absPath, root) {
|
|
42
|
+
let real;
|
|
43
|
+
try {
|
|
44
|
+
real = await realpath(absPath);
|
|
45
|
+
} catch {
|
|
46
|
+
let current = dirname(absPath);
|
|
47
|
+
let hops = 0;
|
|
48
|
+
while (hops < 64 && !await pathExists(current)) {
|
|
49
|
+
const parent = dirname(current);
|
|
50
|
+
if (parent === current) return false;
|
|
51
|
+
current = parent;
|
|
52
|
+
hops++;
|
|
53
|
+
}
|
|
54
|
+
if (!await pathExists(current)) return false;
|
|
55
|
+
try {
|
|
56
|
+
real = await realpath(current);
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const realRel = relative(root, real);
|
|
62
|
+
return realRel !== "" && realRel !== "." && (realRel.startsWith("..") || isAbsolute(realRel));
|
|
63
|
+
}
|
|
64
|
+
async function pathExists(p) {
|
|
65
|
+
try {
|
|
66
|
+
await stat(p);
|
|
67
|
+
return true;
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
38
71
|
}
|
|
39
72
|
function hashContent(s) {
|
|
40
73
|
const cap = Math.min(s.length, 65536);
|
|
@@ -135,7 +168,7 @@ var plugin = {
|
|
|
135
168
|
const ti = input.toolInput ?? {};
|
|
136
169
|
const raw = ti["path"] ?? ti["file_path"] ?? ti["filePath"] ?? ti["TargetFile"] ?? ti["targetFile"] ?? ti["file"];
|
|
137
170
|
if (typeof raw !== "string" || raw.length === 0) return;
|
|
138
|
-
const safePath = resolveProjectPath(raw);
|
|
171
|
+
const safePath = await resolveProjectPath(raw);
|
|
139
172
|
if (!safePath) return;
|
|
140
173
|
const captured = await captureFileForHook(safePath, cfg.maxFileBytes, runtime.signal);
|
|
141
174
|
if (captured === "too-large") {
|
|
@@ -206,7 +239,7 @@ var plugin = {
|
|
|
206
239
|
const rejectedOutsideProject = [];
|
|
207
240
|
let skipped = 0;
|
|
208
241
|
for (const p of paths) {
|
|
209
|
-
const safePath = resolveProjectPath(p);
|
|
242
|
+
const safePath = await resolveProjectPath(p);
|
|
210
243
|
if (!safePath) {
|
|
211
244
|
rejectedOutsideProject.push(p);
|
|
212
245
|
continue;
|
|
@@ -313,7 +346,7 @@ var plugin = {
|
|
|
313
346
|
error: rawId ? `no snapshot with id "${rawId}"` : "no snapshots captured yet"
|
|
314
347
|
};
|
|
315
348
|
}
|
|
316
|
-
const targetPath = rawPath ? resolveProjectPath(rawPath) ?? rawPath : null;
|
|
349
|
+
const targetPath = rawPath ? await resolveProjectPath(rawPath) ?? rawPath : null;
|
|
317
350
|
const targets = targetPath ? snapshot.files.filter((f) => f.path === targetPath || f.path === rawPath) : snapshot.files;
|
|
318
351
|
if (targets.length === 0) {
|
|
319
352
|
return { ok: false, error: `snapshot ${snapshot.id} has no entry for "${rawPath}"` };
|
package/dist/index.js
CHANGED
|
@@ -2805,7 +2805,7 @@ var plugin8 = {
|
|
|
2805
2805
|
var changelog_writer_default = plugin8;
|
|
2806
2806
|
|
|
2807
2807
|
// src/checkpoint/index.ts
|
|
2808
|
-
import { mkdir, readFile as readFile3, stat, writeFile } from "node:fs/promises";
|
|
2808
|
+
import { mkdir, readFile as readFile3, realpath, stat, writeFile } from "node:fs/promises";
|
|
2809
2809
|
import { dirname as dirname2, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve5 } from "node:path";
|
|
2810
2810
|
var state9 = {
|
|
2811
2811
|
snapshots: [],
|
|
@@ -2834,13 +2834,46 @@ function readConfig8(raw) {
|
|
|
2834
2834
|
maxFileBytes: typeof r["maxFileBytes"] === "number" && r["maxFileBytes"] >= 1024 ? r["maxFileBytes"] : DEFAULTS8.maxFileBytes
|
|
2835
2835
|
};
|
|
2836
2836
|
}
|
|
2837
|
-
function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2837
|
+
async function resolveProjectPath3(rawPath, cwd = process.cwd()) {
|
|
2838
2838
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
2839
2839
|
const root = resolve5(cwd);
|
|
2840
2840
|
const resolved = isAbsolute5(rawPath) ? resolve5(rawPath) : resolve5(root, rawPath);
|
|
2841
2841
|
const rel = relative5(root, resolved);
|
|
2842
|
-
|
|
2843
|
-
return null;
|
|
2842
|
+
const lexicallyInside = rel === "" || !rel.startsWith("..") && !isAbsolute5(rel);
|
|
2843
|
+
if (!lexicallyInside) return null;
|
|
2844
|
+
if (await realResolutionEscapes(resolved, root)) return null;
|
|
2845
|
+
return resolved;
|
|
2846
|
+
}
|
|
2847
|
+
async function realResolutionEscapes(absPath, root) {
|
|
2848
|
+
let real;
|
|
2849
|
+
try {
|
|
2850
|
+
real = await realpath(absPath);
|
|
2851
|
+
} catch {
|
|
2852
|
+
let current = dirname2(absPath);
|
|
2853
|
+
let hops = 0;
|
|
2854
|
+
while (hops < 64 && !await pathExists(current)) {
|
|
2855
|
+
const parent = dirname2(current);
|
|
2856
|
+
if (parent === current) return false;
|
|
2857
|
+
current = parent;
|
|
2858
|
+
hops++;
|
|
2859
|
+
}
|
|
2860
|
+
if (!await pathExists(current)) return false;
|
|
2861
|
+
try {
|
|
2862
|
+
real = await realpath(current);
|
|
2863
|
+
} catch {
|
|
2864
|
+
return false;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
const realRel = relative5(root, real);
|
|
2868
|
+
return realRel !== "" && realRel !== "." && (realRel.startsWith("..") || isAbsolute5(realRel));
|
|
2869
|
+
}
|
|
2870
|
+
async function pathExists(p) {
|
|
2871
|
+
try {
|
|
2872
|
+
await stat(p);
|
|
2873
|
+
return true;
|
|
2874
|
+
} catch {
|
|
2875
|
+
return false;
|
|
2876
|
+
}
|
|
2844
2877
|
}
|
|
2845
2878
|
function hashContent(s) {
|
|
2846
2879
|
const cap = Math.min(s.length, 65536);
|
|
@@ -2941,7 +2974,7 @@ var plugin9 = {
|
|
|
2941
2974
|
const ti = input.toolInput ?? {};
|
|
2942
2975
|
const raw = ti["path"] ?? ti["file_path"] ?? ti["filePath"] ?? ti["TargetFile"] ?? ti["targetFile"] ?? ti["file"];
|
|
2943
2976
|
if (typeof raw !== "string" || raw.length === 0) return;
|
|
2944
|
-
const safePath = resolveProjectPath3(raw);
|
|
2977
|
+
const safePath = await resolveProjectPath3(raw);
|
|
2945
2978
|
if (!safePath) return;
|
|
2946
2979
|
const captured = await captureFileForHook(safePath, cfg.maxFileBytes, runtime.signal);
|
|
2947
2980
|
if (captured === "too-large") {
|
|
@@ -3012,7 +3045,7 @@ var plugin9 = {
|
|
|
3012
3045
|
const rejectedOutsideProject = [];
|
|
3013
3046
|
let skipped = 0;
|
|
3014
3047
|
for (const p of paths) {
|
|
3015
|
-
const safePath = resolveProjectPath3(p);
|
|
3048
|
+
const safePath = await resolveProjectPath3(p);
|
|
3016
3049
|
if (!safePath) {
|
|
3017
3050
|
rejectedOutsideProject.push(p);
|
|
3018
3051
|
continue;
|
|
@@ -3119,7 +3152,7 @@ var plugin9 = {
|
|
|
3119
3152
|
error: rawId ? `no snapshot with id "${rawId}"` : "no snapshots captured yet"
|
|
3120
3153
|
};
|
|
3121
3154
|
}
|
|
3122
|
-
const targetPath = rawPath ? resolveProjectPath3(rawPath) ?? rawPath : null;
|
|
3155
|
+
const targetPath = rawPath ? await resolveProjectPath3(rawPath) ?? rawPath : null;
|
|
3123
3156
|
const targets = targetPath ? snapshot.files.filter((f) => f.path === targetPath || f.path === rawPath) : snapshot.files;
|
|
3124
3157
|
if (targets.length === 0) {
|
|
3125
3158
|
return { ok: false, error: `snapshot ${snapshot.id} has no entry for "${rawPath}"` };
|
|
@@ -6931,7 +6964,7 @@ Consider mentioning these changes in the documentation.`;
|
|
|
6931
6964
|
var doc_sync_guard_default = plugin20;
|
|
6932
6965
|
|
|
6933
6966
|
// src/duplicate-code-detector/index.ts
|
|
6934
|
-
import { readFile as readFile6, realpath, stat as stat3 } from "node:fs/promises";
|
|
6967
|
+
import { readFile as readFile6, realpath as realpath2, stat as stat3 } from "node:fs/promises";
|
|
6935
6968
|
import { extname as extname4, isAbsolute as isAbsolute8, relative as relative9, resolve as resolve9, sep } from "node:path";
|
|
6936
6969
|
var API_VERSION14 = "^0.1.10";
|
|
6937
6970
|
var HOOK_WARNING_COOLDOWN_MS = 6e4;
|
|
@@ -7290,7 +7323,7 @@ var plugin21 = {
|
|
|
7290
7323
|
if (!isWithinRoot(projectRoot, resolvedFile)) return;
|
|
7291
7324
|
let changedFile;
|
|
7292
7325
|
try {
|
|
7293
|
-
changedFile = await
|
|
7326
|
+
changedFile = await realpath2(resolvedFile);
|
|
7294
7327
|
} catch {
|
|
7295
7328
|
state20.errorCount += 1;
|
|
7296
7329
|
return;
|
|
@@ -9530,7 +9563,7 @@ function classifyArtifact(relPath, patterns) {
|
|
|
9530
9563
|
}
|
|
9531
9564
|
return null;
|
|
9532
9565
|
}
|
|
9533
|
-
async function
|
|
9566
|
+
async function pathExists2(p) {
|
|
9534
9567
|
try {
|
|
9535
9568
|
await access3(p);
|
|
9536
9569
|
return true;
|
|
@@ -9539,7 +9572,7 @@ async function pathExists(p) {
|
|
|
9539
9572
|
}
|
|
9540
9573
|
}
|
|
9541
9574
|
async function readGitignoreLines(file) {
|
|
9542
|
-
if (!await
|
|
9575
|
+
if (!await pathExists2(file)) return [];
|
|
9543
9576
|
try {
|
|
9544
9577
|
const content = await readFile9(file, "utf8");
|
|
9545
9578
|
return content.split(/\r?\n/);
|
|
@@ -9571,7 +9604,7 @@ function relDirOf(rel) {
|
|
|
9571
9604
|
}
|
|
9572
9605
|
async function firstExistingGitignore(candidates) {
|
|
9573
9606
|
for (const c of candidates) {
|
|
9574
|
-
if (await
|
|
9607
|
+
if (await pathExists2(c)) return c;
|
|
9575
9608
|
}
|
|
9576
9609
|
return null;
|
|
9577
9610
|
}
|
|
@@ -9582,7 +9615,7 @@ async function appendPatterns(target, patterns, limit) {
|
|
|
9582
9615
|
);
|
|
9583
9616
|
const missing = patterns.filter((p) => !seen.has(p)).slice(0, limit);
|
|
9584
9617
|
if (missing.length === 0) return { appended: [] };
|
|
9585
|
-
const current = await
|
|
9618
|
+
const current = await pathExists2(target) ? await readFile9(target, "utf8") : "";
|
|
9586
9619
|
const base = current.length === 0 ? "" : current.endsWith("\n") ? current : `${current}
|
|
9587
9620
|
`;
|
|
9588
9621
|
const next = `${base}${missing.map((p) => `${p}
|
|
@@ -12781,7 +12814,7 @@ import {
|
|
|
12781
12814
|
runOptionalPluginCouncil,
|
|
12782
12815
|
runOptionalPluginLlm,
|
|
12783
12816
|
stripOuterMarkdownFence
|
|
12784
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
12817
|
+
} from "@wrongstack/plugin-sdk/runtime/llm";
|
|
12785
12818
|
|
|
12786
12819
|
// src/migration-planner/index.ts
|
|
12787
12820
|
var API_VERSION25 = "^0.1.10";
|
|
@@ -14033,11 +14066,15 @@ var plugin38 = {
|
|
|
14033
14066
|
};
|
|
14034
14067
|
var notify_hub_default = plugin38;
|
|
14035
14068
|
|
|
14069
|
+
// src/path-guard/index.ts
|
|
14070
|
+
import { existsSync as existsSync6, realpathSync } from "node:fs";
|
|
14071
|
+
import { dirname as dirname6, resolve as resolve17 } from "node:path";
|
|
14072
|
+
|
|
14036
14073
|
// src/runtime/redos-guard.ts
|
|
14037
14074
|
import {
|
|
14038
14075
|
withReDoSGuard,
|
|
14039
14076
|
guardedMatcher
|
|
14040
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
14077
|
+
} from "@wrongstack/plugin-sdk/runtime/redos-guard";
|
|
14041
14078
|
|
|
14042
14079
|
// src/path-guard/glob.ts
|
|
14043
14080
|
var GLOB_REDOS_BUDGET_MS = 250;
|
|
@@ -15323,17 +15360,32 @@ function operationLabel(toolName) {
|
|
|
15323
15360
|
}
|
|
15324
15361
|
|
|
15325
15362
|
// src/path-guard/index.ts
|
|
15326
|
-
import { realpathSync } from "node:fs";
|
|
15327
|
-
import { resolve as resolve17 } from "node:path";
|
|
15328
15363
|
function isSymlinkEscape(path, cwd) {
|
|
15329
15364
|
if (!(0, runtime_exports.withinProject)(path)) return false;
|
|
15365
|
+
const abs = resolve17(cwd ?? process.cwd(), path);
|
|
15366
|
+
let real;
|
|
15330
15367
|
try {
|
|
15331
|
-
|
|
15332
|
-
const real = realpathSync(abs);
|
|
15333
|
-
return !(0, runtime_exports.withinProject)(real);
|
|
15368
|
+
real = realpathSync(abs);
|
|
15334
15369
|
} catch {
|
|
15335
|
-
|
|
15370
|
+
const ancestor = nearestExistingAncestor(abs);
|
|
15371
|
+
if (ancestor === null) return false;
|
|
15372
|
+
try {
|
|
15373
|
+
real = realpathSync(ancestor);
|
|
15374
|
+
} catch {
|
|
15375
|
+
return false;
|
|
15376
|
+
}
|
|
15377
|
+
}
|
|
15378
|
+
return !(0, runtime_exports.withinProject)(real);
|
|
15379
|
+
}
|
|
15380
|
+
function nearestExistingAncestor(abs) {
|
|
15381
|
+
let current = dirname6(abs);
|
|
15382
|
+
for (let hops = 0; hops < 64; hops++) {
|
|
15383
|
+
if (existsSync6(current)) return current;
|
|
15384
|
+
const parent = dirname6(current);
|
|
15385
|
+
if (parent === current) return null;
|
|
15386
|
+
current = parent;
|
|
15336
15387
|
}
|
|
15388
|
+
return null;
|
|
15337
15389
|
}
|
|
15338
15390
|
function createState() {
|
|
15339
15391
|
return {
|
|
@@ -15482,6 +15534,9 @@ var plugin39 = {
|
|
|
15482
15534
|
path: relativeToInvocationCwd(resolveTargetPath(path, effectiveCwd), input.cwd),
|
|
15483
15535
|
kind: isRootPathScope(path) && deletesImplicitScope || isUnresolvedPathScope(path) || recursivelyDeletes && (isDirectoryAmbiguousPath(path) || hasConfiguredProtectedDescendant(path, cfg.protect)) ? "deletion-scope" : "file"
|
|
15484
15536
|
};
|
|
15537
|
+
if (target.kind === "file" && isSymlinkEscape(target.path, input.cwd)) {
|
|
15538
|
+
return target;
|
|
15539
|
+
}
|
|
15485
15540
|
if (targetFullyAllowed(target, cfg.allow, allowRes)) return null;
|
|
15486
15541
|
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
15487
15542
|
onTimeout: bumpRedos
|
|
@@ -15609,7 +15664,7 @@ var plugin39 = {
|
|
|
15609
15664
|
var path_guard_default = plugin39;
|
|
15610
15665
|
|
|
15611
15666
|
// src/performance-regression-gate/index.ts
|
|
15612
|
-
import { existsSync as
|
|
15667
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11 } from "node:fs";
|
|
15613
15668
|
import { isAbsolute as isAbsolute16, relative as relative16, resolve as resolve18 } from "node:path";
|
|
15614
15669
|
var API_VERSION26 = "^0.1.10";
|
|
15615
15670
|
var state36 = {
|
|
@@ -15675,7 +15730,7 @@ function flattenResults(results) {
|
|
|
15675
15730
|
return flat;
|
|
15676
15731
|
}
|
|
15677
15732
|
function loadResults(path) {
|
|
15678
|
-
if (!path || !
|
|
15733
|
+
if (!path || !existsSync7(path)) return null;
|
|
15679
15734
|
try {
|
|
15680
15735
|
const raw = JSON.parse(readFileSync11(path, "utf-8"));
|
|
15681
15736
|
return raw;
|
|
@@ -16073,7 +16128,7 @@ var plugin_stack_observer_default = PLUGIN;
|
|
|
16073
16128
|
// src/pr-drafter/index.ts
|
|
16074
16129
|
import { execFile as execFile9 } from "node:child_process";
|
|
16075
16130
|
import { mkdir as mkdir2, writeFile as writeFile4 } from "node:fs/promises";
|
|
16076
|
-
import { dirname as
|
|
16131
|
+
import { dirname as dirname7, isAbsolute as isAbsolute17, relative as relative17, resolve as resolve19 } from "node:path";
|
|
16077
16132
|
var API_VERSION27 = "^0.1.10";
|
|
16078
16133
|
var state38 = {
|
|
16079
16134
|
commits: [],
|
|
@@ -16205,7 +16260,7 @@ async function writeDraft(cfg, llm) {
|
|
|
16205
16260
|
}
|
|
16206
16261
|
const draft = await buildDraft(cfg, llm);
|
|
16207
16262
|
try {
|
|
16208
|
-
await mkdir2(
|
|
16263
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
16209
16264
|
await writeFile4(resolved, draft.body);
|
|
16210
16265
|
state38.draftsWritten += 1;
|
|
16211
16266
|
} catch {
|
|
@@ -16349,7 +16404,7 @@ var plugin41 = {
|
|
|
16349
16404
|
const resolved = resolveProjectPath7(outputPathStr);
|
|
16350
16405
|
if (!resolved) return { ok: false, error: "outputPath resolves outside project" };
|
|
16351
16406
|
try {
|
|
16352
|
-
await mkdir2(
|
|
16407
|
+
await mkdir2(dirname7(resolved), { recursive: true });
|
|
16353
16408
|
await writeFile4(resolved, draft.body);
|
|
16354
16409
|
state38.draftsWritten += 1;
|
|
16355
16410
|
return {
|
|
@@ -16579,7 +16634,7 @@ import { performance as performance2 } from "node:perf_hooks";
|
|
|
16579
16634
|
import {
|
|
16580
16635
|
cloneCredentialPatterns,
|
|
16581
16636
|
CREDENTIAL_PATTERNS
|
|
16582
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
16637
|
+
} from "@wrongstack/plugin-sdk/runtime/credential-patterns";
|
|
16583
16638
|
|
|
16584
16639
|
// src/prompt-firewall/index.ts
|
|
16585
16640
|
var KIND_ALIASES = {
|
|
@@ -22532,7 +22587,7 @@ var test_coverage_gate_default = plugin56;
|
|
|
22532
22587
|
import { execFile as execFile13 } from "node:child_process";
|
|
22533
22588
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
22534
22589
|
import { createRequire as createRequire2 } from "node:module";
|
|
22535
|
-
import { dirname as
|
|
22590
|
+
import { dirname as dirname8, isAbsolute as isAbsolute25, relative as relative24, resolve as resolve26 } from "node:path";
|
|
22536
22591
|
var API_VERSION37 = "^0.1.10";
|
|
22537
22592
|
var state52 = {
|
|
22538
22593
|
invocationCount: 0,
|
|
@@ -22663,7 +22718,7 @@ function resolveTestCommand(baseCommand, testPattern) {
|
|
|
22663
22718
|
const packageJson = JSON.parse(readFileSync15(packagePath, "utf8"));
|
|
22664
22719
|
const relativeBin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.[runner] ?? Object.values(packageJson.bin ?? {})[0];
|
|
22665
22720
|
if (!relativeBin) return null;
|
|
22666
|
-
const packageDir =
|
|
22721
|
+
const packageDir = dirname8(packagePath);
|
|
22667
22722
|
const candidate = resolve26(packageDir, relativeBin);
|
|
22668
22723
|
if (isAbsolute25(relativeBin) || !isInside2(packageDir, candidate)) {
|
|
22669
22724
|
return null;
|
|
@@ -23310,7 +23365,7 @@ var test_generator_default = plugin58;
|
|
|
23310
23365
|
// src/test-runner-gate/index.ts
|
|
23311
23366
|
import { execFile as execFile14 } from "node:child_process";
|
|
23312
23367
|
import { access as access5 } from "node:fs/promises";
|
|
23313
|
-
import { basename as basename6, dirname as
|
|
23368
|
+
import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute27, join as join7 } from "node:path";
|
|
23314
23369
|
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
23315
23370
|
function resolveExec(command, args) {
|
|
23316
23371
|
const resolved = resolveWin32Command(command);
|
|
@@ -23403,7 +23458,7 @@ var ALLOWED_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
23403
23458
|
function resolveTestFiles(sourcePath, patterns) {
|
|
23404
23459
|
const name = basename6(sourcePath).replace(/\.[^.]+$/, "");
|
|
23405
23460
|
const pathNoExt = sourcePath.replace(/\.[^.]+$/, "");
|
|
23406
|
-
const dir =
|
|
23461
|
+
const dir = dirname9(sourcePath);
|
|
23407
23462
|
const candidates = [];
|
|
23408
23463
|
for (const pattern of patterns) {
|
|
23409
23464
|
const candidate = pattern.replace(/\{name\}/g, name).replace(/\{path\}/g, pathNoExt).replace(/\{dir\}/g, dir);
|
|
@@ -24050,7 +24105,7 @@ var todo_listener_default = plugin60;
|
|
|
24050
24105
|
// src/todo-tracker/index.ts
|
|
24051
24106
|
import { randomUUID } from "node:crypto";
|
|
24052
24107
|
import * as fsp from "node:fs/promises";
|
|
24053
|
-
import { dirname as
|
|
24108
|
+
import { dirname as dirname10 } from "node:path";
|
|
24054
24109
|
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core/utils";
|
|
24055
24110
|
import { nowIso } from "@wrongstack/primitives";
|
|
24056
24111
|
function deriveFilePath(api) {
|
|
@@ -24083,7 +24138,7 @@ async function loadFile(filePath) {
|
|
|
24083
24138
|
}
|
|
24084
24139
|
}
|
|
24085
24140
|
async function saveFile(filePath, file) {
|
|
24086
|
-
await ensureDir3(
|
|
24141
|
+
await ensureDir3(dirname10(filePath));
|
|
24087
24142
|
await atomicWrite3(filePath, JSON.stringify(file, null, 2), { mode: 384 });
|
|
24088
24143
|
}
|
|
24089
24144
|
var state56 = {
|
|
@@ -24990,7 +25045,7 @@ var plugin63 = {
|
|
|
24990
25045
|
var token_throttle_default = plugin63;
|
|
24991
25046
|
|
|
24992
25047
|
// src/type-gate/index.ts
|
|
24993
|
-
import { existsSync as
|
|
25048
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
24994
25049
|
var API_VERSION41 = "^0.1.10";
|
|
24995
25050
|
var state59 = {
|
|
24996
25051
|
invocationCount: 0,
|
|
@@ -25074,7 +25129,7 @@ async function runTypeCheck(cfg) {
|
|
|
25074
25129
|
argv = [...argv, "-p", tsConfig];
|
|
25075
25130
|
}
|
|
25076
25131
|
}
|
|
25077
|
-
if (!cfg.command && tsConfig && !
|
|
25132
|
+
if (!cfg.command && tsConfig && !existsSync8(tsConfig)) {
|
|
25078
25133
|
return null;
|
|
25079
25134
|
}
|
|
25080
25135
|
const result = await (0, runtime_exports.runRunnerCommand)([argv[0], ...argv.slice(1)], {
|
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
import type { Plugin } from '@wrongstack/core/types';
|
|
8
8
|
export { compilePathGlob } from './glob.js';
|
|
9
9
|
export { destructiveTargets } from './shell-targets.js';
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* True when `path` is a project-local path whose canonical resolution
|
|
12
|
+
* escaped the project — including when the leaf does not exist yet (e.g. a
|
|
13
|
+
* `write` of a brand-new file): the nearest EXISTING ancestor is
|
|
14
|
+
* canonicalized instead, so a new file created THROUGH an escaped symlink
|
|
15
|
+
* is still detected. A brand-new path under ordinary project directories
|
|
16
|
+
* resolves to an ancestor inside the project and returns false.
|
|
17
|
+
*/
|
|
11
18
|
export declare function isSymlinkEscape(path: string, cwd?: string): boolean;
|
|
12
19
|
declare const plugin: Plugin;
|
|
13
20
|
export default plugin;
|
package/dist/path-guard.js
CHANGED
|
@@ -12,11 +12,20 @@ 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/path-guard/index.ts
|
|
16
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
17
|
+
import { dirname, resolve } from "node:path";
|
|
18
|
+
|
|
19
|
+
// src/runtime/index.ts
|
|
20
|
+
var runtime_exports = {};
|
|
21
|
+
__reExport(runtime_exports, runtime_star);
|
|
22
|
+
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
23
|
+
|
|
15
24
|
// src/runtime/redos-guard.ts
|
|
16
25
|
import {
|
|
17
26
|
withReDoSGuard,
|
|
18
27
|
guardedMatcher
|
|
19
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
28
|
+
} from "@wrongstack/plugin-sdk/runtime/redos-guard";
|
|
20
29
|
|
|
21
30
|
// src/path-guard/glob.ts
|
|
22
31
|
var GLOB_REDOS_BUDGET_MS = 250;
|
|
@@ -1301,25 +1310,33 @@ function operationLabel(toolName) {
|
|
|
1301
1310
|
return `write via "${toolName}"`;
|
|
1302
1311
|
}
|
|
1303
1312
|
|
|
1304
|
-
// src/path-guard/index.ts
|
|
1305
|
-
import { realpathSync } from "node:fs";
|
|
1306
|
-
import { resolve } from "node:path";
|
|
1307
|
-
|
|
1308
|
-
// src/runtime/index.ts
|
|
1309
|
-
var runtime_exports = {};
|
|
1310
|
-
__reExport(runtime_exports, runtime_star);
|
|
1311
|
-
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
1312
|
-
|
|
1313
1313
|
// src/path-guard/index.ts
|
|
1314
1314
|
function isSymlinkEscape(path, cwd) {
|
|
1315
1315
|
if (!(0, runtime_exports.withinProject)(path)) return false;
|
|
1316
|
+
const abs = resolve(cwd ?? process.cwd(), path);
|
|
1317
|
+
let real;
|
|
1316
1318
|
try {
|
|
1317
|
-
|
|
1318
|
-
const real = realpathSync(abs);
|
|
1319
|
-
return !(0, runtime_exports.withinProject)(real);
|
|
1319
|
+
real = realpathSync(abs);
|
|
1320
1320
|
} catch {
|
|
1321
|
-
|
|
1321
|
+
const ancestor = nearestExistingAncestor(abs);
|
|
1322
|
+
if (ancestor === null) return false;
|
|
1323
|
+
try {
|
|
1324
|
+
real = realpathSync(ancestor);
|
|
1325
|
+
} catch {
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1322
1328
|
}
|
|
1329
|
+
return !(0, runtime_exports.withinProject)(real);
|
|
1330
|
+
}
|
|
1331
|
+
function nearestExistingAncestor(abs) {
|
|
1332
|
+
let current = dirname(abs);
|
|
1333
|
+
for (let hops = 0; hops < 64; hops++) {
|
|
1334
|
+
if (existsSync(current)) return current;
|
|
1335
|
+
const parent = dirname(current);
|
|
1336
|
+
if (parent === current) return null;
|
|
1337
|
+
current = parent;
|
|
1338
|
+
}
|
|
1339
|
+
return null;
|
|
1323
1340
|
}
|
|
1324
1341
|
function createState() {
|
|
1325
1342
|
return {
|
|
@@ -1468,6 +1485,9 @@ var plugin = {
|
|
|
1468
1485
|
path: relativeToInvocationCwd(resolveTargetPath(path, effectiveCwd), input.cwd),
|
|
1469
1486
|
kind: isRootPathScope(path) && deletesImplicitScope || isUnresolvedPathScope(path) || recursivelyDeletes && (isDirectoryAmbiguousPath(path) || hasConfiguredProtectedDescendant(path, cfg.protect)) ? "deletion-scope" : "file"
|
|
1470
1487
|
};
|
|
1488
|
+
if (target.kind === "file" && isSymlinkEscape(target.path, input.cwd)) {
|
|
1489
|
+
return target;
|
|
1490
|
+
}
|
|
1471
1491
|
if (targetFullyAllowed(target, cfg.allow, allowRes)) return null;
|
|
1472
1492
|
const protectedShellTarget = await targetIntersectsPatternsGuarded(target, cfg.protect, protectRes, {
|
|
1473
1493
|
onTimeout: bumpRedos
|
package/dist/prompt-firewall.js
CHANGED
|
@@ -5,13 +5,13 @@ import { performance } from "node:perf_hooks";
|
|
|
5
5
|
import {
|
|
6
6
|
cloneCredentialPatterns,
|
|
7
7
|
CREDENTIAL_PATTERNS
|
|
8
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
8
|
+
} from "@wrongstack/plugin-sdk/runtime/credential-patterns";
|
|
9
9
|
|
|
10
10
|
// src/runtime/redos-guard.ts
|
|
11
11
|
import {
|
|
12
12
|
withReDoSGuard,
|
|
13
13
|
guardedMatcher
|
|
14
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
14
|
+
} from "@wrongstack/plugin-sdk/runtime/redos-guard";
|
|
15
15
|
|
|
16
16
|
// src/prompt-firewall/index.ts
|
|
17
17
|
var KIND_ALIASES = {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { cloneCredentialPatterns, CREDENTIAL_PATTERNS, type CredentialPattern, } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/credential-patterns (granular). */
|
|
2
|
+
export { cloneCredentialPatterns, CREDENTIAL_PATTERNS, type CredentialPattern, } from '@wrongstack/plugin-sdk/runtime/credential-patterns';
|
|
3
3
|
//# sourceMappingURL=credential-patterns.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { createH1State, type H1State } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/h1-state (granular). */
|
|
2
|
+
export { createH1State, type H1State } from '@wrongstack/plugin-sdk/runtime/h1-state';
|
|
3
3
|
//# sourceMappingURL=h1-state.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { releaseHandle, releaseHandles, type Unregister } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/handles (granular). */
|
|
2
|
+
export { releaseHandle, releaseHandles, type Unregister } from '@wrongstack/plugin-sdk/runtime/handles';
|
|
3
3
|
//# sourceMappingURL=handles.d.ts.map
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Backwards-compatible re-export: the runtime helpers moved to
|
|
3
3
|
* `@wrongstack/plugin-sdk/runtime` so third-party plugin authors get the
|
|
4
|
-
* same audit-hardened helpers first-party plugins use, without depending
|
|
5
|
-
*
|
|
4
|
+
* same audit-hardened helpers first-party plugins use, without depending on
|
|
5
|
+
* the whole @wrongstack/plugins package. This shim keeps the
|
|
6
6
|
* `@wrongstack/plugins/runtime` subpath (and every in-repo relative
|
|
7
7
|
* import) working unchanged.
|
|
8
|
+
*
|
|
9
|
+
* Why this one still imports the BARREL while the six leaf shims
|
|
10
|
+
* (`redos-guard`, `sandbox`, `llm`, …) import granular
|
|
11
|
+
* `@wrongstack/plugin-sdk/runtime/*` entries: the language-runner helpers
|
|
12
|
+
* (`resolveRunnerCommand`, `sanitizeRunnerPath`, `runRunnerCommand`,
|
|
13
|
+
* `probeRunnerCommand`), `withinProject`, `collectSourceFiles(Async)` and
|
|
14
|
+
* `matchesExtension` are defined in the sdk's runtime barrel module itself.
|
|
15
|
+
*
|
|
16
|
+
* The runner-extraction unlock LANDED 2026-09-06 (round core-utils-r1):
|
|
17
|
+
* `@wrongstack/core/utils/child-env` imports in ~4.5ms and the plugin-sdk
|
|
18
|
+
* barrel uses it. The extraction was re-attempted as round sdk-runner-r2
|
|
19
|
+
* and REVERTED on measurement: the primary arm's win landed inside the
|
|
20
|
+
* noise band (path-guard 12.33 -> 11.46ms, band ~5.4ms) because the
|
|
21
|
+
* child-env entry already banked the barrel's cost, and the granular
|
|
22
|
+
* 10-resolution shim measurably regressed multi-symbol consumers
|
|
23
|
+
* (branch-guard 10.87 -> 16.95ms). Do not re-attempt without a new
|
|
24
|
+
* hypothesis; see PERF_LOG round sdk-runner-r2.
|
|
8
25
|
*/
|
|
9
26
|
export * from '@wrongstack/plugin-sdk/runtime';
|
|
10
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/runtime/llm.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { parseLlmJsonObject, runOptionalPluginCouncil, runOptionalPluginLlm, stripOuterMarkdownFence, type OptionalCouncilRequest, type OptionalLlmRequest, type OptionalLlmResult, } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/llm (granular). */
|
|
2
|
+
export { parseLlmJsonObject, runOptionalPluginCouncil, runOptionalPluginLlm, stripOuterMarkdownFence, type OptionalCouncilRequest, type OptionalLlmRequest, type OptionalLlmResult, } from '@wrongstack/plugin-sdk/runtime/llm';
|
|
3
3
|
//# sourceMappingURL=llm.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { withReDoSGuard, guardedMatcher, type ReDoSResult, type ReDoSOptions, } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/redos-guard (granular). */
|
|
2
|
+
export { withReDoSGuard, guardedMatcher, type ReDoSResult, type ReDoSOptions, } from '@wrongstack/plugin-sdk/runtime/redos-guard';
|
|
3
3
|
//# sourceMappingURL=redos-guard.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime. */
|
|
2
|
-
export { safePath, isInsideProject, type SafePathOptions, } from '@wrongstack/plugin-sdk/runtime';
|
|
1
|
+
/** Shim: implementation moved to @wrongstack/plugin-sdk/runtime/sandbox (granular). */
|
|
2
|
+
export { safePath, isInsideProject, type SafePathOptions, } from '@wrongstack/plugin-sdk/runtime/sandbox';
|
|
3
3
|
//# sourceMappingURL=sandbox.d.ts.map
|
package/dist/secret-scanner.js
CHANGED
|
@@ -16,7 +16,7 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
|
|
|
16
16
|
import {
|
|
17
17
|
cloneCredentialPatterns,
|
|
18
18
|
CREDENTIAL_PATTERNS
|
|
19
|
-
} from "@wrongstack/plugin-sdk/runtime";
|
|
19
|
+
} from "@wrongstack/plugin-sdk/runtime/credential-patterns";
|
|
20
20
|
|
|
21
21
|
// src/runtime/index.ts
|
|
22
22
|
var runtime_exports = {};
|
package/dist/test-generator.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Official WrongStack collection of focused plugins for code quality, security, observability, planning, and agent coordination",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -303,10 +303,10 @@
|
|
|
303
303
|
"vitest": "^4.1.11"
|
|
304
304
|
},
|
|
305
305
|
"dependencies": {
|
|
306
|
-
"@wrongstack/core": "0.
|
|
307
|
-
"@wrongstack/primitives": "0.
|
|
308
|
-
"@wrongstack/plugin-sdk": "0.
|
|
309
|
-
"@wrongstack/tools": "0.
|
|
306
|
+
"@wrongstack/core": "1.0.1",
|
|
307
|
+
"@wrongstack/primitives": "1.0.1",
|
|
308
|
+
"@wrongstack/plugin-sdk": "1.0.1",
|
|
309
|
+
"@wrongstack/tools": "1.0.1"
|
|
310
310
|
},
|
|
311
311
|
"scripts": {
|
|
312
312
|
"build": "node ../../scripts/build-package.mjs",
|