@wrongstack/plugins 0.308.6 → 0.309.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessibility-auditor.js +26 -82
- package/dist/agent-handoff.js +16 -26
- package/dist/auto-i18n-extractor.js +19 -23
- package/dist/branch-guard.js +19 -111
- package/dist/changelog-writer.js +20 -133
- package/dist/code-metrics.js +26 -71
- package/dist/commit-validator.js +16 -14
- package/dist/config-validator.js +18 -22
- package/dist/cost-tracker.js +15 -96
- package/dist/dead-code-detector.js +27 -31
- package/dist/dependency-vulnerability-gate.js +18 -15
- package/dist/diff-summary.js +19 -128
- package/dist/doc-sync-guard.js +24 -39
- package/dist/duplicate-code-detector.js +30 -169
- package/dist/feature-flag-tracker.js +26 -71
- package/dist/file-watcher.js +19 -23
- package/dist/format-on-save.js +25 -214
- package/dist/import-organizer.js +31 -106
- package/dist/index.js +452 -1236
- package/dist/interface-contract-guard.js +26 -71
- package/dist/lint-gate.js +19 -111
- package/dist/migration-planner.js +28 -120
- package/dist/notify-hub.js +18 -28
- package/dist/path-guard.js +27 -102
- package/dist/pr-drafter.js +18 -16
- package/dist/prompt-firewall.js +8 -205
- package/dist/refactor-suggester.js +27 -166
- package/dist/release-notes-generator.js +6 -35
- package/dist/runtime/bounded-map.d.ts +2 -85
- package/dist/runtime/credential-patterns.d.ts +2 -41
- package/dist/runtime/h1-state.d.ts +2 -61
- package/dist/runtime/handles.d.ts +2 -45
- package/dist/runtime/index.d.ts +8 -180
- package/dist/runtime/llm.d.ts +2 -43
- package/dist/runtime/local-bin.d.ts +2 -119
- package/dist/runtime/redos-guard.d.ts +2 -68
- package/dist/runtime/safe-json.d.ts +2 -24
- package/dist/runtime/sandbox.d.ts +2 -58
- package/dist/runtime.js +1 -868
- package/dist/schema-evolution-guard.js +20 -24
- package/dist/secret-scanner.js +22 -146
- package/dist/security-hotspot-scanner.js +24 -154
- package/dist/session-recap.js +16 -14
- package/dist/spec-linker.js +19 -17
- package/dist/template-engine.js +22 -37
- package/dist/test-coverage-gate.js +19 -34
- package/dist/test-generator.js +6 -35
- package/dist/test-runner-gate.js +34 -143
- package/dist/todo-listener.js +17 -38
- package/dist/type-gate.js +23 -311
- package/package.json +4 -3
package/dist/diff-summary.js
CHANGED
|
@@ -1,133 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// src/runtime/bounded-map.ts
|
|
11
|
-
var BoundedMap = class {
|
|
12
|
-
map = /* @__PURE__ */ new Map();
|
|
13
|
-
max;
|
|
14
|
-
ttlMs;
|
|
15
|
-
now;
|
|
16
|
-
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
17
|
-
evictions = 0;
|
|
18
|
-
constructor(options) {
|
|
19
|
-
const normalizedMax = Math.floor(options.max);
|
|
20
|
-
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
21
|
-
this.ttlMs = options.ttlMs;
|
|
22
|
-
this.now = options.now ?? Date.now;
|
|
23
|
-
}
|
|
24
|
-
expired(entry) {
|
|
25
|
-
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
26
|
-
}
|
|
27
|
-
get(key) {
|
|
28
|
-
const entry = this.map.get(key);
|
|
29
|
-
if (entry === void 0) return void 0;
|
|
30
|
-
if (this.expired(entry)) {
|
|
31
|
-
this.map.delete(key);
|
|
32
|
-
return void 0;
|
|
33
|
-
}
|
|
34
|
-
this.map.delete(key);
|
|
35
|
-
this.map.set(key, entry);
|
|
36
|
-
return entry.value;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Read without promoting the key to most-recently-used. Use for
|
|
40
|
-
* diagnostics that must not perturb the eviction order.
|
|
41
|
-
*/
|
|
42
|
-
peek(key) {
|
|
43
|
-
const entry = this.map.get(key);
|
|
44
|
-
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
45
|
-
return entry.value;
|
|
46
|
-
}
|
|
47
|
-
has(key) {
|
|
48
|
-
const entry = this.map.get(key);
|
|
49
|
-
if (entry === void 0) return false;
|
|
50
|
-
if (this.expired(entry)) {
|
|
51
|
-
this.map.delete(key);
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
set(key, value) {
|
|
57
|
-
this.map.delete(key);
|
|
58
|
-
this.map.set(key, { value, storedAt: this.now() });
|
|
59
|
-
while (this.map.size > this.max) {
|
|
60
|
-
const coldest = this.map.keys().next().value;
|
|
61
|
-
if (coldest === void 0) break;
|
|
62
|
-
this.map.delete(coldest);
|
|
63
|
-
this.evictions += 1;
|
|
64
|
-
}
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
|
-
delete(key) {
|
|
68
|
-
return this.map.delete(key);
|
|
69
|
-
}
|
|
70
|
-
clear() {
|
|
71
|
-
this.map.clear();
|
|
72
|
-
this.evictions = 0;
|
|
73
|
-
}
|
|
74
|
-
get size() {
|
|
75
|
-
return this.map.size;
|
|
76
|
-
}
|
|
77
|
-
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
78
|
-
get evictionCount() {
|
|
79
|
-
return this.evictions;
|
|
80
|
-
}
|
|
81
|
-
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
82
|
-
prune() {
|
|
83
|
-
if (this.ttlMs === void 0) return 0;
|
|
84
|
-
let removed = 0;
|
|
85
|
-
for (const [key, entry] of this.map) {
|
|
86
|
-
if (this.expired(entry)) {
|
|
87
|
-
this.map.delete(key);
|
|
88
|
-
removed += 1;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return removed;
|
|
92
|
-
}
|
|
93
|
-
/** Live (non-expired) entries, coldest first. */
|
|
94
|
-
*entries() {
|
|
95
|
-
for (const [key, entry] of this.map) {
|
|
96
|
-
if (!this.expired(entry)) yield [key, entry.value];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
[Symbol.iterator]() {
|
|
100
|
-
return this.entries();
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
101
10
|
}
|
|
11
|
+
return to;
|
|
102
12
|
};
|
|
13
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
103
14
|
|
|
104
|
-
// src/
|
|
105
|
-
|
|
106
|
-
if (off) {
|
|
107
|
-
try {
|
|
108
|
-
off();
|
|
109
|
-
} catch {
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
15
|
+
// src/diff-summary/index.ts
|
|
16
|
+
import { execFile } from "node:child_process";
|
|
114
17
|
|
|
115
18
|
// src/runtime/index.ts
|
|
116
|
-
var
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
function withinProjectPath(projectRoot, candidate) {
|
|
121
|
-
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
122
|
-
if (hasLeadingDash(candidate)) return false;
|
|
123
|
-
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
124
|
-
const rel = relative(projectRoot, resolved);
|
|
125
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
126
|
-
}
|
|
127
|
-
function withinProject(p) {
|
|
128
|
-
const cwd = process.cwd();
|
|
129
|
-
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
130
|
-
}
|
|
19
|
+
var runtime_exports = {};
|
|
20
|
+
__reExport(runtime_exports, runtime_star);
|
|
21
|
+
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
131
22
|
|
|
132
23
|
// src/diff-summary/index.ts
|
|
133
24
|
var API_VERSION = "^0.1.10";
|
|
@@ -174,7 +65,7 @@ function contentHash(s) {
|
|
|
174
65
|
}
|
|
175
66
|
return h >>> 0;
|
|
176
67
|
}
|
|
177
|
-
var pathMemo = new BoundedMap({ max: 512 });
|
|
68
|
+
var pathMemo = new runtime_exports.BoundedMap({ max: 512 });
|
|
178
69
|
function runGit(args, cwd) {
|
|
179
70
|
return new Promise((resolveCommand) => {
|
|
180
71
|
execFile(
|
|
@@ -289,7 +180,7 @@ var plugin = {
|
|
|
289
180
|
state.fallbackCount = 0;
|
|
290
181
|
state.throttledCount = 0;
|
|
291
182
|
state.duplicateContentCount = 0;
|
|
292
|
-
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
183
|
+
state.hookUnregister = (0, runtime_exports.releaseHandle)(state.hookUnregister);
|
|
293
184
|
state.lastSummary = null;
|
|
294
185
|
pathMemo.clear();
|
|
295
186
|
const cfg = readConfig(api.config.extensions?.["diff-summary"]);
|
|
@@ -302,7 +193,7 @@ var plugin = {
|
|
|
302
193
|
const filePath = inp["path"];
|
|
303
194
|
if (!filePath || typeof filePath !== "string") return;
|
|
304
195
|
state.invocationCount += 1;
|
|
305
|
-
if (!withinProject(filePath)) {
|
|
196
|
+
if (!(0, runtime_exports.withinProject)(filePath)) {
|
|
306
197
|
state.fallbackCount += 1;
|
|
307
198
|
return;
|
|
308
199
|
}
|
package/dist/doc-sync-guard.js
CHANGED
|
@@ -1,39 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// src/runtime/handles.ts
|
|
11
|
-
function releaseHandle(off) {
|
|
12
|
-
if (off) {
|
|
13
|
-
try {
|
|
14
|
-
off();
|
|
15
|
-
} catch {
|
|
16
|
-
}
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
10
|
}
|
|
18
|
-
return
|
|
19
|
-
}
|
|
11
|
+
return to;
|
|
12
|
+
};
|
|
13
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
|
+
|
|
15
|
+
// src/doc-sync-guard/index.ts
|
|
16
|
+
import { basename, extname } from "node:path";
|
|
20
17
|
|
|
21
18
|
// src/runtime/index.ts
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
function withinProjectPath(projectRoot, candidate) {
|
|
27
|
-
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
28
|
-
if (hasLeadingDash(candidate)) return false;
|
|
29
|
-
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
30
|
-
const rel = relative(projectRoot, resolved);
|
|
31
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
32
|
-
}
|
|
33
|
-
function withinProject(p) {
|
|
34
|
-
const cwd = process.cwd();
|
|
35
|
-
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
36
|
-
}
|
|
19
|
+
var runtime_exports = {};
|
|
20
|
+
__reExport(runtime_exports, runtime_star);
|
|
21
|
+
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
37
22
|
|
|
38
23
|
// src/doc-sync-guard/index.ts
|
|
39
24
|
var API_VERSION = "^0.1.10";
|
|
@@ -64,21 +49,21 @@ function normalizeSlashes(p) {
|
|
|
64
49
|
return p.replace(/\\/g, "/");
|
|
65
50
|
}
|
|
66
51
|
function isSourceFile(p, extensions) {
|
|
67
|
-
const ext =
|
|
52
|
+
const ext = extname(p).toLowerCase();
|
|
68
53
|
return extensions.includes(ext);
|
|
69
54
|
}
|
|
70
55
|
function isPublicSource(p, extensions) {
|
|
71
56
|
if (!isSourceFile(p, extensions)) return false;
|
|
72
57
|
const norm = normalizeSlashes(p);
|
|
73
58
|
if (norm.includes("/node_modules/") || norm.startsWith("node_modules/")) return false;
|
|
74
|
-
const base =
|
|
59
|
+
const base = basename(norm).toLowerCase();
|
|
75
60
|
if (/\.(test|spec)\./.test(base)) return false;
|
|
76
61
|
if (base.startsWith("_")) return false;
|
|
77
62
|
return true;
|
|
78
63
|
}
|
|
79
64
|
function isDocFile(p, docNames) {
|
|
80
65
|
const norm = normalizeSlashes(p);
|
|
81
|
-
const base =
|
|
66
|
+
const base = basename(norm);
|
|
82
67
|
const lowerBase = base.toLowerCase();
|
|
83
68
|
if (docNames.some((name) => lowerBase === name.toLowerCase())) return true;
|
|
84
69
|
if (norm.includes("/docs/") || norm.startsWith("docs/")) return true;
|
|
@@ -96,7 +81,7 @@ function extractDocContent(toolInput) {
|
|
|
96
81
|
return void 0;
|
|
97
82
|
}
|
|
98
83
|
function referenceTokens(p) {
|
|
99
|
-
const base =
|
|
84
|
+
const base = basename(p);
|
|
100
85
|
const withoutExt = base.replace(/\.[^.]+$/, "");
|
|
101
86
|
const tokens = [base];
|
|
102
87
|
if (withoutExt && withoutExt !== base) tokens.push(withoutExt);
|
|
@@ -154,13 +139,13 @@ var plugin = {
|
|
|
154
139
|
state.sourceWrites = 0;
|
|
155
140
|
state.docWrites = 0;
|
|
156
141
|
state.warningsIssued = 0;
|
|
157
|
-
state.hookUnregister = releaseHandle(state.hookUnregister);
|
|
142
|
+
state.hookUnregister = (0, runtime_exports.releaseHandle)(state.hookUnregister);
|
|
158
143
|
const cfg = readConfig(api.config.extensions?.["doc-sync-guard"]);
|
|
159
144
|
const hook = (input) => {
|
|
160
145
|
if (!cfg.enabled) return;
|
|
161
146
|
if (input.toolResult?.isError) return;
|
|
162
147
|
const path = extractPath(input.toolInput);
|
|
163
|
-
if (!path || !withinProject(path)) return;
|
|
148
|
+
if (!path || !(0, runtime_exports.withinProject)(path)) return;
|
|
164
149
|
if (isPublicSource(path, cfg.sourceExtensions)) {
|
|
165
150
|
trackChangedFile(path, cfg.maxTrackedFiles);
|
|
166
151
|
state.sourceWrites += 1;
|
|
@@ -1,164 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// src/runtime/bounded-map.ts
|
|
12
|
-
var BoundedMap = class {
|
|
13
|
-
map = /* @__PURE__ */ new Map();
|
|
14
|
-
max;
|
|
15
|
-
ttlMs;
|
|
16
|
-
now;
|
|
17
|
-
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
18
|
-
evictions = 0;
|
|
19
|
-
constructor(options) {
|
|
20
|
-
const normalizedMax = Math.floor(options.max);
|
|
21
|
-
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
22
|
-
this.ttlMs = options.ttlMs;
|
|
23
|
-
this.now = options.now ?? Date.now;
|
|
24
|
-
}
|
|
25
|
-
expired(entry) {
|
|
26
|
-
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
27
|
-
}
|
|
28
|
-
get(key) {
|
|
29
|
-
const entry = this.map.get(key);
|
|
30
|
-
if (entry === void 0) return void 0;
|
|
31
|
-
if (this.expired(entry)) {
|
|
32
|
-
this.map.delete(key);
|
|
33
|
-
return void 0;
|
|
34
|
-
}
|
|
35
|
-
this.map.delete(key);
|
|
36
|
-
this.map.set(key, entry);
|
|
37
|
-
return entry.value;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Read without promoting the key to most-recently-used. Use for
|
|
41
|
-
* diagnostics that must not perturb the eviction order.
|
|
42
|
-
*/
|
|
43
|
-
peek(key) {
|
|
44
|
-
const entry = this.map.get(key);
|
|
45
|
-
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
46
|
-
return entry.value;
|
|
47
|
-
}
|
|
48
|
-
has(key) {
|
|
49
|
-
const entry = this.map.get(key);
|
|
50
|
-
if (entry === void 0) return false;
|
|
51
|
-
if (this.expired(entry)) {
|
|
52
|
-
this.map.delete(key);
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
set(key, value) {
|
|
58
|
-
this.map.delete(key);
|
|
59
|
-
this.map.set(key, { value, storedAt: this.now() });
|
|
60
|
-
while (this.map.size > this.max) {
|
|
61
|
-
const coldest = this.map.keys().next().value;
|
|
62
|
-
if (coldest === void 0) break;
|
|
63
|
-
this.map.delete(coldest);
|
|
64
|
-
this.evictions += 1;
|
|
65
|
-
}
|
|
66
|
-
return this;
|
|
67
|
-
}
|
|
68
|
-
delete(key) {
|
|
69
|
-
return this.map.delete(key);
|
|
70
|
-
}
|
|
71
|
-
clear() {
|
|
72
|
-
this.map.clear();
|
|
73
|
-
this.evictions = 0;
|
|
74
|
-
}
|
|
75
|
-
get size() {
|
|
76
|
-
return this.map.size;
|
|
77
|
-
}
|
|
78
|
-
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
79
|
-
get evictionCount() {
|
|
80
|
-
return this.evictions;
|
|
81
|
-
}
|
|
82
|
-
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
83
|
-
prune() {
|
|
84
|
-
if (this.ttlMs === void 0) return 0;
|
|
85
|
-
let removed = 0;
|
|
86
|
-
for (const [key, entry] of this.map) {
|
|
87
|
-
if (this.expired(entry)) {
|
|
88
|
-
this.map.delete(key);
|
|
89
|
-
removed += 1;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return removed;
|
|
93
|
-
}
|
|
94
|
-
/** Live (non-expired) entries, coldest first. */
|
|
95
|
-
*entries() {
|
|
96
|
-
for (const [key, entry] of this.map) {
|
|
97
|
-
if (!this.expired(entry)) yield [key, entry.value];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
[Symbol.iterator]() {
|
|
101
|
-
return this.entries();
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
102
10
|
}
|
|
11
|
+
return to;
|
|
103
12
|
};
|
|
13
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
14
|
+
|
|
15
|
+
// src/duplicate-code-detector/index.ts
|
|
16
|
+
import { readFile, realpath, stat } from "node:fs/promises";
|
|
17
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
104
18
|
|
|
105
19
|
// src/runtime/index.ts
|
|
106
|
-
var
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
function withinProjectPath(projectRoot, candidate) {
|
|
111
|
-
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
112
|
-
if (hasLeadingDash(candidate)) return false;
|
|
113
|
-
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
114
|
-
const rel = relative(projectRoot, resolved);
|
|
115
|
-
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
116
|
-
}
|
|
117
|
-
function withinProject(p) {
|
|
118
|
-
const cwd = process.cwd();
|
|
119
|
-
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
120
|
-
}
|
|
121
|
-
var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
|
|
122
|
-
async function collectSourceFilesAsync(root, opts) {
|
|
123
|
-
const { readdir, stat: stat2 } = await import("node:fs/promises");
|
|
124
|
-
const files = [];
|
|
125
|
-
try {
|
|
126
|
-
const s = await stat2(root);
|
|
127
|
-
if (s.isFile()) {
|
|
128
|
-
if (matchesExtension(root, opts.extensions)) files.push(root);
|
|
129
|
-
return files;
|
|
130
|
-
}
|
|
131
|
-
if (!s.isDirectory()) return files;
|
|
132
|
-
} catch {
|
|
133
|
-
return files;
|
|
134
|
-
}
|
|
135
|
-
const exclude = opts.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
|
|
136
|
-
const excludeSet = new Set(exclude);
|
|
137
|
-
async function walk(dir, depth) {
|
|
138
|
-
if (opts.maxDepth !== void 0 && depth > opts.maxDepth) return;
|
|
139
|
-
let entries;
|
|
140
|
-
try {
|
|
141
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
142
|
-
} catch {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
146
|
-
for (const entry of entries) {
|
|
147
|
-
if (excludeSet.has(entry.name)) continue;
|
|
148
|
-
const full = resolve(dir, entry.name);
|
|
149
|
-
if (entry.isDirectory()) {
|
|
150
|
-
await walk(full, depth + 1);
|
|
151
|
-
} else if (entry.isFile() && matchesExtension(full, opts.extensions)) {
|
|
152
|
-
files.push(full);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
await walk(root, 0);
|
|
157
|
-
return files;
|
|
158
|
-
}
|
|
159
|
-
function matchesExtension(p, exts) {
|
|
160
|
-
return exts.includes(extname(p).toLowerCase());
|
|
161
|
-
}
|
|
20
|
+
var runtime_exports = {};
|
|
21
|
+
__reExport(runtime_exports, runtime_star);
|
|
22
|
+
import * as runtime_star from "@wrongstack/plugin-sdk/runtime";
|
|
162
23
|
|
|
163
24
|
// src/duplicate-code-detector/index.ts
|
|
164
25
|
var API_VERSION = "^0.1.10";
|
|
@@ -170,7 +31,7 @@ var state = {
|
|
|
170
31
|
warningCount: 0,
|
|
171
32
|
errorCount: 0,
|
|
172
33
|
hookUnregister: null,
|
|
173
|
-
lastHookWarning: new BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS }),
|
|
34
|
+
lastHookWarning: new runtime_exports.BoundedMap({ max: 512, ttlMs: HOOK_WARNING_COOLDOWN_MS }),
|
|
174
35
|
fileIndex: /* @__PURE__ */ new Map(),
|
|
175
36
|
inFlightFingerprintReads: /* @__PURE__ */ new Map(),
|
|
176
37
|
indexFingerprintCount: 0,
|
|
@@ -217,14 +78,14 @@ function readConfig(raw) {
|
|
|
217
78
|
};
|
|
218
79
|
}
|
|
219
80
|
function isWithinRoot(projectRoot, candidate) {
|
|
220
|
-
const rel =
|
|
221
|
-
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !
|
|
81
|
+
const rel = relative(projectRoot, candidate);
|
|
82
|
+
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
222
83
|
}
|
|
223
84
|
function toPosix(p) {
|
|
224
85
|
return p.replace(/\\/g, "/");
|
|
225
86
|
}
|
|
226
87
|
function relativePath(p) {
|
|
227
|
-
return toPosix(
|
|
88
|
+
return toPosix(relative(process.cwd(), p));
|
|
228
89
|
}
|
|
229
90
|
function removeInlineComments(line) {
|
|
230
91
|
return line.replace(/\/\/.*$/, "").replace(/\/\*[\s\S]*?\*\//, "");
|
|
@@ -316,8 +177,8 @@ function findDuplicates(files, minLines, maxFindings) {
|
|
|
316
177
|
}
|
|
317
178
|
async function scanPath(rawPath, cfg) {
|
|
318
179
|
const root = process.cwd();
|
|
319
|
-
const resolved =
|
|
320
|
-
const filePaths = await collectSourceFilesAsync(resolved, {
|
|
180
|
+
const resolved = isAbsolute(rawPath) ? resolve(rawPath) : resolve(root, rawPath);
|
|
181
|
+
const filePaths = await (0, runtime_exports.collectSourceFilesAsync)(resolved, {
|
|
321
182
|
extensions: cfg.extensions,
|
|
322
183
|
excludeDirs: cfg.excludeDirs
|
|
323
184
|
});
|
|
@@ -444,8 +305,8 @@ var plugin = {
|
|
|
444
305
|
const inp = input.toolInput ?? {};
|
|
445
306
|
const sourcePath = inp["path"];
|
|
446
307
|
if (!sourcePath || typeof sourcePath !== "string") return;
|
|
447
|
-
const projectRoot =
|
|
448
|
-
const resolvedFile =
|
|
308
|
+
const projectRoot = resolve(process.cwd());
|
|
309
|
+
const resolvedFile = isAbsolute(sourcePath) ? resolve(sourcePath) : resolve(projectRoot, sourcePath);
|
|
449
310
|
if (!isWithinRoot(projectRoot, resolvedFile)) return;
|
|
450
311
|
let changedFile;
|
|
451
312
|
try {
|
|
@@ -469,7 +330,7 @@ var plugin = {
|
|
|
469
330
|
if (changedFps.size === 0) return;
|
|
470
331
|
let otherFilePaths;
|
|
471
332
|
try {
|
|
472
|
-
otherFilePaths = await collectSourceFilesAsync(projectRoot, {
|
|
333
|
+
otherFilePaths = await (0, runtime_exports.collectSourceFilesAsync)(projectRoot, {
|
|
473
334
|
extensions: cfg.extensions,
|
|
474
335
|
excludeDirs: cfg.excludeDirs
|
|
475
336
|
});
|
|
@@ -479,7 +340,7 @@ var plugin = {
|
|
|
479
340
|
}
|
|
480
341
|
const matched = /* @__PURE__ */ new Set();
|
|
481
342
|
for (const p of otherFilePaths) {
|
|
482
|
-
if (
|
|
343
|
+
if (resolve(p) === resolve(changedFile)) continue;
|
|
483
344
|
const otherFps = await readCachedFingerprints(p, cfg.minLines);
|
|
484
345
|
if (otherFps === null || otherFps.size === 0) continue;
|
|
485
346
|
for (const fp of changedFps) {
|
|
@@ -511,7 +372,7 @@ var plugin = {
|
|
|
511
372
|
async execute(input) {
|
|
512
373
|
if (!cfg.enabled) return { ok: false, error: "duplicate-code-detector is disabled" };
|
|
513
374
|
const rawPath = typeof input.path === "string" ? input.path : ".";
|
|
514
|
-
if (!withinProject(rawPath)) {
|
|
375
|
+
if (!(0, runtime_exports.withinProject)(rawPath)) {
|
|
515
376
|
return { ok: false, error: "scan path is outside the project root" };
|
|
516
377
|
}
|
|
517
378
|
state.scanCount += 1;
|
|
@@ -525,7 +386,7 @@ var plugin = {
|
|
|
525
386
|
state.findingCount += result.findings.length;
|
|
526
387
|
return {
|
|
527
388
|
ok: true,
|
|
528
|
-
path: relativePath(
|
|
389
|
+
path: relativePath(resolve(process.cwd(), rawPath)),
|
|
529
390
|
scannedFiles: result.scannedFiles,
|
|
530
391
|
minLines: cfg.minLines,
|
|
531
392
|
findings: result.findings
|