@wrongstack/plugins 0.293.0 → 0.295.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/README.md +7 -71
- package/dist/accessibility-auditor/index.d.ts +1 -1
- package/dist/accessibility-auditor/index.d.ts.map +1 -1
- package/dist/accessibility-auditor.js +50 -33
- package/dist/agent-handoff/index.d.ts +1 -1
- package/dist/agent-handoff/index.d.ts.map +1 -1
- package/dist/agent-handoff.js +30 -1
- package/dist/api-compatibility-gate/index.d.ts +1 -1
- package/dist/api-compatibility-gate/index.d.ts.map +1 -1
- package/dist/api-compatibility-gate.js +21 -16
- package/dist/audit/index.d.ts +386 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit.d.ts +1 -0
- package/dist/audit.js +454 -0
- package/dist/auto-doc/index.d.ts +1 -1
- package/dist/auto-doc/index.d.ts.map +1 -1
- package/dist/auto-doc.js +3 -1
- package/dist/auto-escalate/index.d.ts +1 -1
- package/dist/auto-escalate/index.d.ts.map +1 -1
- package/dist/auto-i18n-extractor/index.d.ts +1 -1
- package/dist/auto-i18n-extractor/index.d.ts.map +1 -1
- package/dist/auto-i18n-extractor.js +7 -1
- package/dist/branch-guard/index.d.ts +1 -1
- package/dist/branch-guard/index.d.ts.map +1 -1
- package/dist/branch-guard.js +111 -1
- package/dist/catalog.d.ts +5 -30
- package/dist/catalog.d.ts.map +1 -1
- package/dist/changelog-writer/index.d.ts +1 -1
- package/dist/changelog-writer/index.d.ts.map +1 -1
- package/dist/changelog-writer.js +137 -3
- package/dist/checkpoint/index.d.ts +3 -1
- package/dist/checkpoint/index.d.ts.map +1 -1
- package/dist/checkpoint.js +41 -16
- package/dist/code-metrics/index.d.ts +1 -1
- package/dist/code-metrics/index.d.ts.map +1 -1
- package/dist/code-metrics.js +34 -29
- package/dist/commit-validator/index.d.ts +1 -1
- package/dist/commit-validator/index.d.ts.map +1 -1
- package/dist/commit-validator.js +17 -7
- package/dist/config-validator/index.d.ts +1 -1
- package/dist/config-validator/index.d.ts.map +1 -1
- package/dist/context-pins/index.d.ts +1 -1
- package/dist/context-pins/index.d.ts.map +1 -1
- package/dist/context-pins.js +6 -5
- package/dist/cost-tracker/index.d.ts +1 -1
- package/dist/cost-tracker/index.d.ts.map +1 -1
- package/dist/cost-tracker.js +109 -2
- package/dist/cron/index.d.ts +1 -1
- package/dist/cron/index.d.ts.map +1 -1
- package/dist/cron.js +1 -0
- package/dist/dead-code-detector/index.d.ts +1 -1
- package/dist/dead-code-detector/index.d.ts.map +1 -1
- package/dist/dead-code-detector.js +31 -18
- package/dist/dep-guard/index.d.ts +1 -1
- package/dist/dep-guard/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate/index.d.ts +1 -1
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -1
- package/dist/dependency-vulnerability-gate.js +67 -20
- package/dist/diff-summary/index.d.ts +1 -1
- package/dist/diff-summary/index.d.ts.map +1 -1
- package/dist/diff-summary.js +128 -30
- package/dist/doc-sync-guard/index.d.ts +1 -1
- package/dist/doc-sync-guard/index.d.ts.map +1 -1
- package/dist/doc-sync-guard.js +7 -1
- package/dist/duplicate-code-detector/index.d.ts +26 -1
- package/dist/duplicate-code-detector/index.d.ts.map +1 -1
- package/dist/duplicate-code-detector.js +280 -69
- package/dist/error-lens/index.d.ts +1 -1
- package/dist/error-lens/index.d.ts.map +1 -1
- package/dist/factories/index.d.ts +4 -0
- package/dist/factories/index.d.ts.map +1 -0
- package/dist/factories.d.ts +1 -0
- package/dist/factories.js +74 -0
- package/dist/feature-flag-tracker/index.d.ts +1 -1
- package/dist/feature-flag-tracker/index.d.ts.map +1 -1
- package/dist/feature-flag-tracker.js +59 -33
- package/dist/file-watcher/index.d.ts +1 -1
- package/dist/file-watcher/index.d.ts.map +1 -1
- package/dist/file-watcher.js +6 -7
- package/dist/format-on-save/index.d.ts +3 -1
- package/dist/format-on-save/index.d.ts.map +1 -1
- package/dist/format-on-save.js +289 -59
- package/dist/generated-plugin-exports.d.ts +65 -0
- package/dist/generated-plugin-exports.d.ts.map +1 -0
- package/dist/git-autocommit/index.d.ts +1 -1
- package/dist/git-autocommit/index.d.ts.map +1 -1
- package/dist/import-organizer/index.d.ts +1 -1
- package/dist/import-organizer/index.d.ts.map +1 -1
- package/dist/import-organizer.js +141 -20
- package/dist/index.d.ts +4 -183
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18298 -17279
- package/dist/injection-shield/index.d.ts +1 -1
- package/dist/injection-shield/index.d.ts.map +1 -1
- package/dist/interface-contract-guard/index.d.ts +1 -1
- package/dist/interface-contract-guard/index.d.ts.map +1 -1
- package/dist/interface-contract-guard.js +87 -53
- package/dist/knowledge-graph/index.d.ts +1 -1
- package/dist/knowledge-graph/index.d.ts.map +1 -1
- package/dist/knowledge-graph.js +7 -6
- package/dist/license-audit-gate/index.d.ts +1 -1
- package/dist/license-audit-gate/index.d.ts.map +1 -1
- package/dist/lint-gate/index.d.ts +1 -1
- package/dist/lint-gate/index.d.ts.map +1 -1
- package/dist/lint-gate.js +112 -1
- package/dist/llm-cache/index.d.ts +5 -1
- package/dist/llm-cache/index.d.ts.map +1 -1
- package/dist/llm-cache.js +16 -8
- package/dist/loop-breaker/index.d.ts +1 -1
- package/dist/loop-breaker/index.d.ts.map +1 -1
- package/dist/loop-breaker.js +25 -9
- package/dist/manifest/index.d.ts +16 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest.d.ts +1 -0
- package/dist/manifest.js +152 -0
- package/dist/migration-planner/index.d.ts +1 -1
- package/dist/migration-planner/index.d.ts.map +1 -1
- package/dist/migration-planner.js +5 -1
- package/dist/model-router/index.d.ts +1 -1
- package/dist/model-router/index.d.ts.map +1 -1
- package/dist/notify-hub/index.d.ts +1 -1
- package/dist/notify-hub/index.d.ts.map +1 -1
- package/dist/notify-hub/webhook-channel.d.ts +1 -1
- package/dist/notify-hub/webhook-channel.d.ts.map +1 -1
- package/dist/notify-hub.js +41 -4
- package/dist/path-guard/index.d.ts +1 -1
- package/dist/path-guard/index.d.ts.map +1 -1
- package/dist/performance-regression-gate/index.d.ts +1 -1
- package/dist/performance-regression-gate/index.d.ts.map +1 -1
- package/dist/plugin-stack-observer/index.d.ts +1 -1
- package/dist/plugin-stack-observer/index.d.ts.map +1 -1
- package/dist/pr-drafter/index.d.ts +1 -1
- package/dist/pr-drafter/index.d.ts.map +1 -1
- package/dist/pr-drafter.js +28 -29
- package/dist/process-guard/index.d.ts +1 -1
- package/dist/process-guard/index.d.ts.map +1 -1
- package/dist/prompt-firewall/index.d.ts +1 -1
- package/dist/prompt-firewall/index.d.ts.map +1 -1
- package/dist/prompt-firewall.js +140 -11
- package/dist/refactor-suggester/index.d.ts +1 -1
- package/dist/refactor-suggester/index.d.ts.map +1 -1
- package/dist/refactor-suggester.js +148 -33
- package/dist/release-notes-generator/index.d.ts +1 -1
- package/dist/release-notes-generator/index.d.ts.map +1 -1
- package/dist/release-notes-generator.js +29 -22
- package/dist/runtime/bounded-map.d.ts +86 -0
- package/dist/runtime/bounded-map.d.ts.map +1 -0
- package/dist/runtime/credential-patterns.d.ts +42 -0
- package/dist/runtime/credential-patterns.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +18 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/llm.d.ts +1 -1
- package/dist/runtime/llm.d.ts.map +1 -1
- package/dist/runtime/local-bin.d.ts +120 -0
- package/dist/runtime/local-bin.d.ts.map +1 -0
- package/dist/runtime/safe-json.d.ts +25 -0
- package/dist/runtime/safe-json.d.ts.map +1 -0
- package/dist/runtime.js +332 -22
- package/dist/schema-evolution-guard/index.d.ts +1 -1
- package/dist/schema-evolution-guard/index.d.ts.map +1 -1
- package/dist/schema-evolution-guard.js +7 -1
- package/dist/secret-scanner/index.d.ts +1 -1
- package/dist/secret-scanner/index.d.ts.map +1 -1
- package/dist/secret-scanner.js +181 -48
- package/dist/security-hotspot-scanner/index.d.ts +1 -1
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -1
- package/dist/security-hotspot-scanner.js +158 -20
- package/dist/semantic-search-indexer/index.d.ts +1 -1
- package/dist/semantic-search-indexer/index.d.ts.map +1 -1
- package/dist/semantic-search-indexer.js +7 -1
- package/dist/semver-bump/index.d.ts +1 -1
- package/dist/semver-bump/index.d.ts.map +1 -1
- package/dist/semver-bump.js +97 -43
- package/dist/session-recap/index.d.ts +1 -1
- package/dist/session-recap/index.d.ts.map +1 -1
- package/dist/shell-check/index.d.ts +1 -1
- package/dist/shell-check/index.d.ts.map +1 -1
- package/dist/smart-rename/index.d.ts +1 -1
- package/dist/smart-rename/index.d.ts.map +1 -1
- package/dist/spec-linker/index.d.ts +1 -1
- package/dist/spec-linker/index.d.ts.map +1 -1
- package/dist/spec-linker.js +222 -20772
- package/dist/template-engine/index.d.ts +1 -1
- package/dist/template-engine/index.d.ts.map +1 -1
- package/dist/template-engine.js +34 -8
- package/dist/test-coverage-gate/index.d.ts +1 -1
- package/dist/test-coverage-gate/index.d.ts.map +1 -1
- package/dist/test-coverage-gate.js +34 -14
- package/dist/test-flake-detector/index.d.ts +1 -1
- package/dist/test-flake-detector/index.d.ts.map +1 -1
- package/dist/test-flake-detector.js +31 -20
- package/dist/test-generator/index.d.ts +1 -1
- package/dist/test-generator/index.d.ts.map +1 -1
- package/dist/test-runner-gate/index.d.ts +1 -1
- package/dist/test-runner-gate/index.d.ts.map +1 -1
- package/dist/test-runner-gate.js +132 -9
- package/dist/todo-listener/index.d.ts +1 -32
- package/dist/todo-listener/index.d.ts.map +1 -1
- package/dist/todo-listener.js +30 -1
- package/dist/todo-tracker/index.d.ts +1 -1
- package/dist/todo-tracker/index.d.ts.map +1 -1
- package/dist/todo-tracker.js +3 -4
- package/dist/token-budget/index.d.ts +1 -1
- package/dist/token-budget/index.d.ts.map +1 -1
- package/dist/token-throttle/index.d.ts +1 -1
- package/dist/token-throttle/index.d.ts.map +1 -1
- package/dist/token-throttle.js +17 -2
- package/dist/type-gate/index.d.ts +1 -1
- package/dist/type-gate/index.d.ts.map +1 -1
- package/dist/type-gate.js +106 -19
- package/package.json +80 -68
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injection-shield/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injection-shield/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA6GrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMvD;AAMD,QAAA,MAAM,MAAM,EAAE,MAwJb,CAAC;eAEa,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interface-contract-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAqLD,QAAA,MAAM,MAAM,EAAE,MAyNb,CAAC;eAEa,MAAM"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
// src/interface-contract-guard/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/runtime/index.ts
|
|
6
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
7
6
|
import { basename, extname, isAbsolute, relative, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/runtime/local-bin.ts
|
|
9
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
10
|
+
|
|
11
|
+
// src/runtime/index.ts
|
|
8
12
|
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
9
13
|
function hasLeadingDash(arg) {
|
|
10
14
|
return arg.length > 0 && arg.startsWith("-");
|
|
@@ -17,44 +21,45 @@ function withinProjectPath(projectRoot, candidate) {
|
|
|
17
21
|
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
18
22
|
}
|
|
19
23
|
function withinProject(p) {
|
|
20
|
-
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
return withinProjectPath(cwd, p) || relative(cwd, p) === ".";
|
|
21
26
|
}
|
|
22
27
|
var DEFAULT_EXCLUDE_DIRS = ["node_modules", "dist", ".git", "coverage"];
|
|
23
|
-
function
|
|
28
|
+
async function collectSourceFilesAsync(root, opts) {
|
|
29
|
+
const { readdir, stat } = await import("node:fs/promises");
|
|
24
30
|
const files = [];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
try {
|
|
32
|
+
const s = await stat(root);
|
|
33
|
+
if (s.isFile()) {
|
|
34
|
+
if (matchesExtension(root, opts.extensions)) files.push(root);
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
if (!s.isDirectory()) return files;
|
|
38
|
+
} catch {
|
|
29
39
|
return files;
|
|
30
40
|
}
|
|
31
|
-
if (!s.isDirectory()) return files;
|
|
32
41
|
const exclude = opts.excludeDirs ?? DEFAULT_EXCLUDE_DIRS;
|
|
33
|
-
|
|
42
|
+
const excludeSet = new Set(exclude);
|
|
43
|
+
async function walk(dir, depth) {
|
|
34
44
|
if (opts.maxDepth !== void 0 && depth > opts.maxDepth) return;
|
|
35
45
|
let entries;
|
|
36
46
|
try {
|
|
37
|
-
entries =
|
|
47
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
38
48
|
} catch {
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
51
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
41
52
|
for (const entry of entries) {
|
|
42
|
-
if (
|
|
43
|
-
const full = resolve(dir, entry);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} catch {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (st.isDirectory()) {
|
|
51
|
-
walk(full, depth + 1);
|
|
52
|
-
} else if (st.isFile() && matchesExtension(full, opts.extensions)) {
|
|
53
|
+
if (excludeSet.has(entry.name)) continue;
|
|
54
|
+
const full = resolve(dir, entry.name);
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
await walk(full, depth + 1);
|
|
57
|
+
} else if (entry.isFile() && matchesExtension(full, opts.extensions)) {
|
|
53
58
|
files.push(full);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
|
-
walk(root, 0);
|
|
62
|
+
await walk(root, 0);
|
|
58
63
|
return files;
|
|
59
64
|
}
|
|
60
65
|
function matchesExtension(p, exts) {
|
|
@@ -74,7 +79,8 @@ var state = {
|
|
|
74
79
|
var DEFAULTS = {
|
|
75
80
|
enabled: false,
|
|
76
81
|
extensions: [".ts", ".tsx"],
|
|
77
|
-
maxFindings: 50
|
|
82
|
+
maxFindings: 50,
|
|
83
|
+
maxFiles: 2e3
|
|
78
84
|
};
|
|
79
85
|
function readConfig(raw) {
|
|
80
86
|
if (!raw || typeof raw !== "object") return { ...DEFAULTS };
|
|
@@ -82,7 +88,8 @@ function readConfig(raw) {
|
|
|
82
88
|
return {
|
|
83
89
|
enabled: r["enabled"] !== false,
|
|
84
90
|
extensions: Array.isArray(r["extensions"]) ? r["extensions"].filter((x) => typeof x === "string") : DEFAULTS.extensions,
|
|
85
|
-
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS.maxFindings
|
|
91
|
+
maxFindings: typeof r["maxFindings"] === "number" && r["maxFindings"] >= 1 && r["maxFindings"] <= 500 ? r["maxFindings"] : DEFAULTS.maxFindings,
|
|
92
|
+
maxFiles: typeof r["maxFiles"] === "number" && r["maxFiles"] >= 1 && r["maxFiles"] <= 5e4 ? Math.floor(r["maxFiles"]) : DEFAULTS.maxFiles
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
function normalizeExtensions(exts) {
|
|
@@ -98,47 +105,60 @@ var INTERFACE_RE = /(?:export\s+)?interface\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
|
98
105
|
function extractInterfaceNames(content) {
|
|
99
106
|
const names = [];
|
|
100
107
|
INTERFACE_RE.lastIndex = 0;
|
|
108
|
+
let searchedUpTo = 0;
|
|
109
|
+
let line = 1;
|
|
101
110
|
for (const m of content.matchAll(INTERFACE_RE)) {
|
|
102
|
-
|
|
111
|
+
const index = m.index ?? 0;
|
|
112
|
+
for (let i = searchedUpTo; i < index; i++) {
|
|
113
|
+
if (content.charCodeAt(i) === 10) line += 1;
|
|
114
|
+
}
|
|
115
|
+
searchedUpTo = index;
|
|
116
|
+
names.push({ name: m[1], line });
|
|
103
117
|
}
|
|
104
118
|
return names;
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
var IMPLEMENTER_RE = /(?:implements|satisfies|\bas)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
121
|
+
function collectImplementedNames(content, into) {
|
|
122
|
+
IMPLEMENTER_RE.lastIndex = 0;
|
|
123
|
+
for (const m of content.matchAll(IMPLEMENTER_RE)) {
|
|
124
|
+
const name = m[1];
|
|
125
|
+
if (name) into.add(name);
|
|
110
126
|
}
|
|
111
|
-
return false;
|
|
112
127
|
}
|
|
113
|
-
function scanPath(rawPath, cfg) {
|
|
128
|
+
async function scanPath(rawPath, cfg) {
|
|
114
129
|
const root = process.cwd();
|
|
115
130
|
const resolved = isAbsolute2(rawPath) ? resolve2(rawPath) : resolve2(root, rawPath);
|
|
116
131
|
const exts = normalizeExtensions(cfg.extensions);
|
|
117
|
-
const
|
|
118
|
-
const
|
|
132
|
+
const allFiles = await collectSourceFilesAsync(resolved, { extensions: exts });
|
|
133
|
+
const files = allFiles.slice(0, cfg.maxFiles);
|
|
134
|
+
const implemented = /* @__PURE__ */ new Set();
|
|
135
|
+
const declarations = [];
|
|
136
|
+
let scannedFiles = 0;
|
|
119
137
|
for (const p of files) {
|
|
138
|
+
let content;
|
|
120
139
|
try {
|
|
121
|
-
|
|
140
|
+
content = await readFile(p, "utf-8");
|
|
122
141
|
} catch {
|
|
142
|
+
continue;
|
|
123
143
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const findings = [];
|
|
127
|
-
for (const { path, content } of contents) {
|
|
144
|
+
scannedFiles += 1;
|
|
145
|
+
collectImplementedNames(content, implemented);
|
|
128
146
|
for (const { name, line } of extractInterfaceNames(content)) {
|
|
129
|
-
|
|
130
|
-
findings.push({
|
|
131
|
-
interfaceName: name,
|
|
132
|
-
file: relativePath(path),
|
|
133
|
-
line,
|
|
134
|
-
message: `interface "${name}" is declared but has no visible implementer`
|
|
135
|
-
});
|
|
136
|
-
if (findings.length >= cfg.maxFindings) break;
|
|
137
|
-
}
|
|
147
|
+
declarations.push({ name, line, file: p });
|
|
138
148
|
}
|
|
149
|
+
}
|
|
150
|
+
const findings = [];
|
|
151
|
+
for (const { name, line, file } of declarations) {
|
|
152
|
+
if (implemented.has(name)) continue;
|
|
153
|
+
findings.push({
|
|
154
|
+
interfaceName: name,
|
|
155
|
+
file: relativePath(file),
|
|
156
|
+
line,
|
|
157
|
+
message: `interface "${name}" is declared but has no visible implementer`
|
|
158
|
+
});
|
|
139
159
|
if (findings.length >= cfg.maxFindings) break;
|
|
140
160
|
}
|
|
141
|
-
return { findings, scannedFiles:
|
|
161
|
+
return { findings, scannedFiles, truncated: allFiles.length > files.length };
|
|
142
162
|
}
|
|
143
163
|
var plugin = {
|
|
144
164
|
name: "interface-contract-guard",
|
|
@@ -157,6 +177,13 @@ var plugin = {
|
|
|
157
177
|
default: [".ts", ".tsx"],
|
|
158
178
|
description: "File extensions to scan."
|
|
159
179
|
},
|
|
180
|
+
maxFiles: {
|
|
181
|
+
type: "number",
|
|
182
|
+
minimum: 1,
|
|
183
|
+
maximum: 5e4,
|
|
184
|
+
default: 2e3,
|
|
185
|
+
description: "Upper bound on files read per scan."
|
|
186
|
+
},
|
|
160
187
|
maxFindings: {
|
|
161
188
|
type: "number",
|
|
162
189
|
minimum: 1,
|
|
@@ -180,7 +207,7 @@ var plugin = {
|
|
|
180
207
|
state.hookUnregister = null;
|
|
181
208
|
}
|
|
182
209
|
const cfg = readConfig(api.config.extensions?.["interface-contract-guard"]);
|
|
183
|
-
const hook = (input) => {
|
|
210
|
+
const hook = async (input) => {
|
|
184
211
|
if (!cfg.enabled) return;
|
|
185
212
|
if (input.toolResult?.isError) return;
|
|
186
213
|
const inp = input.toolInput ?? {};
|
|
@@ -193,7 +220,7 @@ var plugin = {
|
|
|
193
220
|
const resolved = resolve2(process.cwd(), sourcePath);
|
|
194
221
|
let content;
|
|
195
222
|
try {
|
|
196
|
-
content =
|
|
223
|
+
content = await readFile(resolved, "utf-8");
|
|
197
224
|
} catch {
|
|
198
225
|
state.errorCount += 1;
|
|
199
226
|
return;
|
|
@@ -230,7 +257,7 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
230
257
|
state.scanCount += 1;
|
|
231
258
|
let result;
|
|
232
259
|
try {
|
|
233
|
-
result = scanPath(rawPath, cfg);
|
|
260
|
+
result = await scanPath(rawPath, cfg);
|
|
234
261
|
} catch (err) {
|
|
235
262
|
state.errorCount += 1;
|
|
236
263
|
return { ok: false, error: String(err) };
|
|
@@ -240,7 +267,14 @@ If you changed member shapes, search the project for implementers/\`satisfies\`/
|
|
|
240
267
|
ok: true,
|
|
241
268
|
path: relativePath(resolve2(process.cwd(), rawPath)),
|
|
242
269
|
scannedFiles: result.scannedFiles,
|
|
243
|
-
findings: result.findings
|
|
270
|
+
findings: result.findings,
|
|
271
|
+
// Say so when the corpus was cut short. A partial scan that
|
|
272
|
+
// reports "no findings" is not the same as a clean result, and
|
|
273
|
+
// the caller has no other way to tell the difference.
|
|
274
|
+
truncated: result.truncated,
|
|
275
|
+
...result.truncated ? {
|
|
276
|
+
note: `Scan stopped at the maxFiles limit (${cfg.maxFiles}); results are partial. Raise \`maxFiles\` or scan a narrower path for full coverage.`
|
|
277
|
+
} : {}
|
|
244
278
|
};
|
|
245
279
|
}
|
|
246
280
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/knowledge-graph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/knowledge-graph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AASrD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB;AAiID,QAAA,MAAM,MAAM,EAAE,MA2Sb,CAAC;eAEa,MAAM"}
|
package/dist/knowledge-graph.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/knowledge-graph/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core/utils";
|
|
4
5
|
var API_VERSION = "^0.1.10";
|
|
5
6
|
var state = {
|
|
6
7
|
facts: [],
|
|
@@ -52,11 +53,11 @@ function loadFacts(filePath) {
|
|
|
52
53
|
return { facts: [], nextId: 1 };
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
|
-
function persistFacts(filePath) {
|
|
56
|
+
async function persistFacts(filePath) {
|
|
56
57
|
if (!filePath) return true;
|
|
57
58
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
await ensureDir(dirname(filePath));
|
|
60
|
+
await atomicWrite(
|
|
60
61
|
filePath,
|
|
61
62
|
JSON.stringify({ facts: state.facts, nextId: state.nextId }, null, 2)
|
|
62
63
|
);
|
|
@@ -187,7 +188,7 @@ var plugin = {
|
|
|
187
188
|
state.facts.push(fact);
|
|
188
189
|
state.adds += 1;
|
|
189
190
|
api.metrics.counter("adds");
|
|
190
|
-
const persisted = persistFacts(resolved);
|
|
191
|
+
const persisted = await persistFacts(resolved);
|
|
191
192
|
return { ok: true, fact, persisted, totalFacts: state.facts.length };
|
|
192
193
|
}
|
|
193
194
|
});
|
|
@@ -247,7 +248,7 @@ var plugin = {
|
|
|
247
248
|
if (removed === 0) return { ok: false, error: `no fact matches "${input.id}"` };
|
|
248
249
|
state.removals += removed;
|
|
249
250
|
api.metrics.counter("removals", removed);
|
|
250
|
-
const persisted = persistFacts(resolved);
|
|
251
|
+
const persisted = await persistFacts(resolved);
|
|
251
252
|
return { ok: true, removed, persisted, totalFacts: state.facts.length };
|
|
252
253
|
}
|
|
253
254
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/license-audit-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/license-audit-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAkKrD,QAAA,MAAM,MAAM,EAAE,MAqMb,CAAC;eAEa,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lint-gate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AA+VrD,QAAA,MAAM,MAAM,EAAE,MA2Wb,CAAC;eAEa,MAAM"}
|
package/dist/lint-gate.js
CHANGED
|
@@ -5,6 +5,108 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
8
|
+
|
|
9
|
+
// src/runtime/local-bin.ts
|
|
10
|
+
import { buildWin32CmdShimInvocation, resolveWin32Command } from "@wrongstack/tools/win32";
|
|
11
|
+
|
|
12
|
+
// src/runtime/bounded-map.ts
|
|
13
|
+
var BoundedMap = class {
|
|
14
|
+
map = /* @__PURE__ */ new Map();
|
|
15
|
+
max;
|
|
16
|
+
ttlMs;
|
|
17
|
+
now;
|
|
18
|
+
/** Entries dropped to stay under `max`. Surfaced by plugin health(). */
|
|
19
|
+
evictions = 0;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
const normalizedMax = Math.floor(options.max);
|
|
22
|
+
this.max = Number.isSafeInteger(normalizedMax) ? Math.max(1, normalizedMax) : 1;
|
|
23
|
+
this.ttlMs = options.ttlMs;
|
|
24
|
+
this.now = options.now ?? Date.now;
|
|
25
|
+
}
|
|
26
|
+
expired(entry) {
|
|
27
|
+
return this.ttlMs !== void 0 && this.now() - entry.storedAt > this.ttlMs;
|
|
28
|
+
}
|
|
29
|
+
get(key) {
|
|
30
|
+
const entry = this.map.get(key);
|
|
31
|
+
if (entry === void 0) return void 0;
|
|
32
|
+
if (this.expired(entry)) {
|
|
33
|
+
this.map.delete(key);
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
this.map.delete(key);
|
|
37
|
+
this.map.set(key, entry);
|
|
38
|
+
return entry.value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Read without promoting the key to most-recently-used. Use for
|
|
42
|
+
* diagnostics that must not perturb the eviction order.
|
|
43
|
+
*/
|
|
44
|
+
peek(key) {
|
|
45
|
+
const entry = this.map.get(key);
|
|
46
|
+
if (entry === void 0 || this.expired(entry)) return void 0;
|
|
47
|
+
return entry.value;
|
|
48
|
+
}
|
|
49
|
+
has(key) {
|
|
50
|
+
const entry = this.map.get(key);
|
|
51
|
+
if (entry === void 0) return false;
|
|
52
|
+
if (this.expired(entry)) {
|
|
53
|
+
this.map.delete(key);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
set(key, value) {
|
|
59
|
+
this.map.delete(key);
|
|
60
|
+
this.map.set(key, { value, storedAt: this.now() });
|
|
61
|
+
while (this.map.size > this.max) {
|
|
62
|
+
const coldest = this.map.keys().next().value;
|
|
63
|
+
if (coldest === void 0) break;
|
|
64
|
+
this.map.delete(coldest);
|
|
65
|
+
this.evictions += 1;
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
delete(key) {
|
|
70
|
+
return this.map.delete(key);
|
|
71
|
+
}
|
|
72
|
+
clear() {
|
|
73
|
+
this.map.clear();
|
|
74
|
+
this.evictions = 0;
|
|
75
|
+
}
|
|
76
|
+
get size() {
|
|
77
|
+
return this.map.size;
|
|
78
|
+
}
|
|
79
|
+
/** How many entries have been dropped to respect `max`, since the last clear. */
|
|
80
|
+
get evictionCount() {
|
|
81
|
+
return this.evictions;
|
|
82
|
+
}
|
|
83
|
+
/** Drop every expired entry. Cheap enough to call from a status tool. */
|
|
84
|
+
prune() {
|
|
85
|
+
if (this.ttlMs === void 0) return 0;
|
|
86
|
+
let removed = 0;
|
|
87
|
+
for (const [key, entry] of this.map) {
|
|
88
|
+
if (this.expired(entry)) {
|
|
89
|
+
this.map.delete(key);
|
|
90
|
+
removed += 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return removed;
|
|
94
|
+
}
|
|
95
|
+
/** Live (non-expired) entries, coldest first. */
|
|
96
|
+
*entries() {
|
|
97
|
+
for (const [key, entry] of this.map) {
|
|
98
|
+
if (!this.expired(entry)) yield [key, entry.value];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
[Symbol.iterator]() {
|
|
102
|
+
return this.entries();
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/runtime/index.ts
|
|
107
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
108
|
+
|
|
109
|
+
// src/lint-gate/index.ts
|
|
8
110
|
var API_VERSION = "^0.1.10";
|
|
9
111
|
var state = {
|
|
10
112
|
/** Total PreToolUse invocations. */
|
|
@@ -42,6 +144,7 @@ var LINTER_PACKAGES = {
|
|
|
42
144
|
biome: "@biomejs/biome",
|
|
43
145
|
eslint: "eslint"
|
|
44
146
|
};
|
|
147
|
+
var linterCache = new BoundedMap({ max: 32, ttlMs: 3e5 });
|
|
45
148
|
function isInside(parent, candidate) {
|
|
46
149
|
const rel = relative(parent, candidate);
|
|
47
150
|
return rel === "" || !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel);
|
|
@@ -89,13 +192,20 @@ function runCommand(command, args, timeoutMs, cwd, signal) {
|
|
|
89
192
|
});
|
|
90
193
|
}
|
|
91
194
|
async function detectLinter(requested, cwd) {
|
|
195
|
+
const cacheKey = `${requested}:${cwd}`;
|
|
196
|
+
const cached = linterCache.get(cacheKey);
|
|
197
|
+
if (cached !== void 0) return cached;
|
|
92
198
|
const candidates = requested === "auto" ? ["biome", "eslint"] : [requested];
|
|
93
199
|
for (const name of candidates) {
|
|
94
200
|
const linter = resolveLocalLinter(name, cwd);
|
|
95
201
|
if (!linter) continue;
|
|
96
202
|
const probe = await runCommand(linter.cmd, [linter.args[0], "--version"], 5e3, cwd);
|
|
97
|
-
if (!probe.error)
|
|
203
|
+
if (!probe.error) {
|
|
204
|
+
linterCache.set(cacheKey, linter);
|
|
205
|
+
return linter;
|
|
206
|
+
}
|
|
98
207
|
}
|
|
208
|
+
linterCache.set(cacheKey, null);
|
|
99
209
|
return null;
|
|
100
210
|
}
|
|
101
211
|
async function lintContent(content, filePath, linter, timeoutMs, cwd, signal) {
|
|
@@ -223,6 +333,7 @@ var plugin = {
|
|
|
223
333
|
state.linterErrorCount = 0;
|
|
224
334
|
state.hookUnregister = null;
|
|
225
335
|
state.lastResult = null;
|
|
336
|
+
linterCache.clear();
|
|
226
337
|
const cfg = readConfig(api.config.extensions?.["lint-gate"]);
|
|
227
338
|
const cwd = resolve(api.config.cwd ?? process.cwd());
|
|
228
339
|
const linterReady = detectLinter(cfg.linter, cwd).then((linter) => {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
*
|
|
38
38
|
* @public
|
|
39
39
|
*/
|
|
40
|
-
import type { Plugin } from '@wrongstack/core';
|
|
40
|
+
import type { Plugin } from '@wrongstack/core/types';
|
|
41
41
|
/**
|
|
42
42
|
* Whether a request is safe to cache under `onlyDeterministic`. Sampled
|
|
43
43
|
* requests (temperature > 0) return different content each call, so
|
|
@@ -47,6 +47,10 @@ export declare function isDeterministic(request: Record<string, unknown>): boole
|
|
|
47
47
|
/**
|
|
48
48
|
* Stable fingerprint of the request fields that affect the response.
|
|
49
49
|
* Excludes anything cosmetic (user id, etc.). Same inputs → same key.
|
|
50
|
+
*
|
|
51
|
+
* Determinism: uses canonical JSON key ordering (alphabetical) so
|
|
52
|
+
* identical semantic requests produce identical fingerprints regardless
|
|
53
|
+
* of property insertion order.
|
|
50
54
|
*/
|
|
51
55
|
export declare function fingerprintRequest(request: Record<string, unknown>): string;
|
|
52
56
|
declare const plugin: Plugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/llm-cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAa,MAAM,wBAAwB,CAAC;AAwFhE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAGzE;AAeD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAsB3E;AA6CD,QAAA,MAAM,MAAM,EAAE,MAkNb,CAAC;eAEa,MAAM"}
|
package/dist/llm-cache.js
CHANGED
|
@@ -32,21 +32,26 @@ function isDeterministic(request) {
|
|
|
32
32
|
const t = request["temperature"];
|
|
33
33
|
return t === void 0 || t === 0;
|
|
34
34
|
}
|
|
35
|
+
var fingerprintCache = /* @__PURE__ */ new WeakMap();
|
|
35
36
|
function fingerprintRequest(request) {
|
|
37
|
+
const cached = fingerprintCache.get(request);
|
|
38
|
+
if (cached) return cached;
|
|
36
39
|
const subset = {
|
|
40
|
+
maxTokens: request["maxTokens"] ?? null,
|
|
41
|
+
messages: request["messages"] ?? null,
|
|
37
42
|
model: request["model"] ?? null,
|
|
43
|
+
reasoning: request["reasoning"] ?? null,
|
|
44
|
+
responseFormat: request["responseFormat"] ?? null,
|
|
45
|
+
stopSequences: request["stopSequences"] ?? null,
|
|
38
46
|
system: request["system"] ?? null,
|
|
39
|
-
messages: request["messages"] ?? null,
|
|
40
|
-
tools: Array.isArray(request["tools"]) ? request["tools"].map((t) => t?.name ?? t) : null,
|
|
41
47
|
temperature: request["temperature"] ?? null,
|
|
42
|
-
|
|
48
|
+
tools: Array.isArray(request["tools"]) ? request["tools"].map((t) => t?.name ?? t) : null,
|
|
43
49
|
topK: request["topK"] ?? null,
|
|
44
|
-
|
|
45
|
-
stopSequences: request["stopSequences"] ?? null,
|
|
46
|
-
responseFormat: request["responseFormat"] ?? null,
|
|
47
|
-
reasoning: request["reasoning"] ?? null
|
|
50
|
+
topP: request["topP"] ?? null
|
|
48
51
|
};
|
|
49
|
-
|
|
52
|
+
const fingerprint = createHash("sha256").update(JSON.stringify(subset)).digest("hex");
|
|
53
|
+
fingerprintCache.set(request, fingerprint);
|
|
54
|
+
return fingerprint;
|
|
50
55
|
}
|
|
51
56
|
function lruGet(key, ttlMs) {
|
|
52
57
|
const entry = state.cache.get(key);
|
|
@@ -60,6 +65,9 @@ function lruGet(key, ttlMs) {
|
|
|
60
65
|
return entry;
|
|
61
66
|
}
|
|
62
67
|
function lruSet(key, response, maxEntries) {
|
|
68
|
+
if (state.cache.has(key)) {
|
|
69
|
+
state.cache.delete(key);
|
|
70
|
+
}
|
|
63
71
|
state.cache.set(key, { response, storedAt: Date.now(), hits: 0 });
|
|
64
72
|
while (state.cache.size > maxEntries) {
|
|
65
73
|
const oldest = state.cache.keys().next().value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loop-breaker/index.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/loop-breaker/index.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAmSrD,QAAA,MAAM,MAAM,EAAE,MA+Yb,CAAC;eAEa,MAAM"}
|