@wrongstack/plugins 0.297.0 → 0.298.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/audit/index.d.ts +6 -6
- package/dist/audit.js +7 -7
- package/dist/dead-code-detector.js +31 -30
- package/dist/factories/index.d.ts +1 -1
- package/dist/factories.js +1 -1
- package/dist/file-watcher.js +37 -4
- package/dist/index.js +232 -111
- package/dist/loop-breaker.js +19 -7
- package/dist/manifest.js +1 -1
- package/dist/plugin-audit-catalog/index.d.ts +20 -0
- package/dist/plugin-audit-catalog.d.ts +1 -0
- package/dist/plugin-audit-catalog.js +526 -0
- package/dist/runtime/index.d.ts +2 -2
- package/dist/session-recap.js +47 -13
- package/dist/spec-linker.js +1 -1
- package/dist/template-engine.js +42 -1
- package/package.json +14 -9
- package/dist/accessibility-auditor/index.d.ts.map +0 -1
- package/dist/agent-handoff/index.d.ts.map +0 -1
- package/dist/api-compatibility-gate/index.d.ts.map +0 -1
- package/dist/audit/index.d.ts.map +0 -1
- package/dist/auto-doc/index.d.ts.map +0 -1
- package/dist/auto-escalate/index.d.ts.map +0 -1
- package/dist/auto-i18n-extractor/index.d.ts.map +0 -1
- package/dist/branch-guard/index.d.ts.map +0 -1
- package/dist/catalog.d.ts.map +0 -1
- package/dist/changelog-writer/index.d.ts.map +0 -1
- package/dist/checkpoint/index.d.ts.map +0 -1
- package/dist/code-metrics/index.d.ts.map +0 -1
- package/dist/commit-validator/index.d.ts.map +0 -1
- package/dist/config-validator/index.d.ts.map +0 -1
- package/dist/context-pins/index.d.ts.map +0 -1
- package/dist/cost-tracker/index.d.ts.map +0 -1
- package/dist/cron/index.d.ts.map +0 -1
- package/dist/dead-code-detector/index.d.ts.map +0 -1
- package/dist/dep-guard/index.d.ts.map +0 -1
- package/dist/dependency-vulnerability-gate/index.d.ts.map +0 -1
- package/dist/diff-summary/index.d.ts.map +0 -1
- package/dist/doc-sync-guard/index.d.ts.map +0 -1
- package/dist/duplicate-code-detector/index.d.ts.map +0 -1
- package/dist/error-lens/index.d.ts.map +0 -1
- package/dist/factories/index.d.ts.map +0 -1
- package/dist/feature-flag-tracker/index.d.ts.map +0 -1
- package/dist/file-watcher/index.d.ts.map +0 -1
- package/dist/format-on-save/index.d.ts.map +0 -1
- package/dist/generated-plugin-exports.d.ts.map +0 -1
- package/dist/git-autocommit/index.d.ts.map +0 -1
- package/dist/import-organizer/index.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/injection-shield/index.d.ts.map +0 -1
- package/dist/interface-contract-guard/index.d.ts.map +0 -1
- package/dist/knowledge-graph/index.d.ts.map +0 -1
- package/dist/license-audit-gate/index.d.ts.map +0 -1
- package/dist/lint-gate/index.d.ts.map +0 -1
- package/dist/llm-cache/index.d.ts.map +0 -1
- package/dist/loop-breaker/index.d.ts.map +0 -1
- package/dist/manifest/index.d.ts.map +0 -1
- package/dist/migration-planner/index.d.ts.map +0 -1
- package/dist/model-router/index.d.ts.map +0 -1
- package/dist/notify-hub/index.d.ts.map +0 -1
- package/dist/notify-hub/webhook-channel.d.ts.map +0 -1
- package/dist/path-guard/index.d.ts.map +0 -1
- package/dist/performance-regression-gate/index.d.ts.map +0 -1
- package/dist/plugin-stack-observer/index.d.ts.map +0 -1
- package/dist/pr-drafter/index.d.ts.map +0 -1
- package/dist/process-guard/index.d.ts.map +0 -1
- package/dist/prompt-firewall/index.d.ts.map +0 -1
- package/dist/refactor-suggester/index.d.ts.map +0 -1
- package/dist/release-notes-generator/index.d.ts.map +0 -1
- package/dist/runtime/bounded-map.d.ts.map +0 -1
- package/dist/runtime/credential-patterns.d.ts.map +0 -1
- package/dist/runtime/handles.d.ts.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/llm.d.ts.map +0 -1
- package/dist/runtime/local-bin.d.ts.map +0 -1
- package/dist/runtime/safe-json.d.ts.map +0 -1
- package/dist/schema-evolution-guard/index.d.ts.map +0 -1
- package/dist/secret-scanner/index.d.ts.map +0 -1
- package/dist/security-hotspot-scanner/index.d.ts.map +0 -1
- package/dist/semantic-search-indexer/index.d.ts.map +0 -1
- package/dist/semver-bump/index.d.ts.map +0 -1
- package/dist/session-recap/index.d.ts.map +0 -1
- package/dist/shell-check/index.d.ts.map +0 -1
- package/dist/smart-rename/index.d.ts.map +0 -1
- package/dist/spec-linker/index.d.ts.map +0 -1
- package/dist/template-engine/index.d.ts.map +0 -1
- package/dist/test-coverage-gate/index.d.ts.map +0 -1
- package/dist/test-flake-detector/index.d.ts.map +0 -1
- package/dist/test-generator/index.d.ts.map +0 -1
- package/dist/test-runner-gate/index.d.ts.map +0 -1
- package/dist/todo-listener/index.d.ts.map +0 -1
- package/dist/todo-tracker/index.d.ts.map +0 -1
- package/dist/token-budget/index.d.ts.map +0 -1
- package/dist/token-throttle/index.d.ts.map +0 -1
- package/dist/type-gate/index.d.ts.map +0 -1
package/dist/audit/index.d.ts
CHANGED
|
@@ -256,12 +256,6 @@ export declare const OFFICIAL_PLUGIN_AUDIT_ENTRIES: readonly [{
|
|
|
256
256
|
readonly summary: 'Observes the wrapProviderRunner stack and exposes it to operators (plugin_stack_status) and, optionally, to the LLM (system-prompt contributor).';
|
|
257
257
|
readonly defaultState: 'inactive';
|
|
258
258
|
readonly canDisable: true;
|
|
259
|
-
}, {
|
|
260
|
-
readonly name: 'dead-code-detector';
|
|
261
|
-
readonly risk: 'low';
|
|
262
|
-
readonly summary: 'Lightweight regex-based scan for exported identifiers that appear unused anywhere in the project';
|
|
263
|
-
readonly defaultState: 'inactive';
|
|
264
|
-
readonly canDisable: true;
|
|
265
259
|
}, {
|
|
266
260
|
readonly name: 'dependency-vulnerability-gate';
|
|
267
261
|
readonly risk: 'high';
|
|
@@ -334,6 +328,12 @@ export declare const OFFICIAL_PLUGIN_AUDIT_ENTRIES: readonly [{
|
|
|
334
328
|
readonly summary: 'Scans source code for security anti-patterns and warns after writes/edits that introduce new hotspots';
|
|
335
329
|
readonly defaultState: 'inactive';
|
|
336
330
|
readonly canDisable: true;
|
|
331
|
+
}, {
|
|
332
|
+
readonly name: 'dead-code-detector';
|
|
333
|
+
readonly risk: 'low';
|
|
334
|
+
readonly summary: 'Lightweight regex-based scan for exported identifiers that appear unused anywhere in the project';
|
|
335
|
+
readonly defaultState: 'inactive';
|
|
336
|
+
readonly canDisable: true;
|
|
337
337
|
}, {
|
|
338
338
|
readonly name: 'duplicate-code-detector';
|
|
339
339
|
readonly risk: 'low';
|
package/dist/audit.js
CHANGED
|
@@ -301,13 +301,6 @@ var OFFICIAL_PLUGIN_AUDIT_ENTRIES = [
|
|
|
301
301
|
defaultState: "inactive",
|
|
302
302
|
canDisable: true
|
|
303
303
|
},
|
|
304
|
-
{
|
|
305
|
-
name: "dead-code-detector",
|
|
306
|
-
risk: "low",
|
|
307
|
-
summary: "Lightweight regex-based scan for exported identifiers that appear unused anywhere in the project",
|
|
308
|
-
defaultState: "inactive",
|
|
309
|
-
canDisable: true
|
|
310
|
-
},
|
|
311
304
|
{
|
|
312
305
|
name: "dependency-vulnerability-gate",
|
|
313
306
|
risk: "high",
|
|
@@ -392,6 +385,13 @@ var OFFICIAL_PLUGIN_AUDIT_ENTRIES = [
|
|
|
392
385
|
defaultState: "inactive",
|
|
393
386
|
canDisable: true
|
|
394
387
|
},
|
|
388
|
+
{
|
|
389
|
+
name: "dead-code-detector",
|
|
390
|
+
risk: "low",
|
|
391
|
+
summary: "Lightweight regex-based scan for exported identifiers that appear unused anywhere in the project",
|
|
392
|
+
defaultState: "inactive",
|
|
393
|
+
canDisable: true
|
|
394
|
+
},
|
|
395
395
|
{
|
|
396
396
|
name: "duplicate-code-detector",
|
|
397
397
|
risk: "low",
|
|
@@ -84,18 +84,12 @@ async function gatherFiles(root, depth, cfg) {
|
|
|
84
84
|
function stripNoise(content) {
|
|
85
85
|
let stripped = content.replace(/\/\/.*$/gm, " ");
|
|
86
86
|
stripped = stripped.replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
87
|
-
stripped = stripped.replace(
|
|
88
|
-
/'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`/g,
|
|
89
|
-
" "
|
|
90
|
-
);
|
|
87
|
+
stripped = stripped.replace(/'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`/g, " ");
|
|
91
88
|
return stripped;
|
|
92
89
|
}
|
|
93
90
|
function lineNumber(content, index) {
|
|
94
91
|
return content.slice(0, index).split(/\r?\n/).length;
|
|
95
92
|
}
|
|
96
|
-
function escapeRegex(s) {
|
|
97
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
98
|
-
}
|
|
99
93
|
var DECLARATION_EXPORT_RE = /export\s+(?:async\s+|abstract\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g;
|
|
100
94
|
var NAMED_EXPORT_RE = /export\s*\{([^}]+)\}/g;
|
|
101
95
|
function extractExports(content, filePath) {
|
|
@@ -128,26 +122,33 @@ function extractExports(content, filePath) {
|
|
|
128
122
|
}
|
|
129
123
|
return exports;
|
|
130
124
|
}
|
|
131
|
-
function findUnusedSymbols(files) {
|
|
125
|
+
async function findUnusedSymbols(files) {
|
|
132
126
|
const suspicious = [];
|
|
127
|
+
const exportedNames = new Set(files.flatMap((file) => file.exports.map((exp) => exp.identifier)));
|
|
128
|
+
const filesContainingIdentifier = /* @__PURE__ */ new Map();
|
|
129
|
+
const identifierPattern = /[A-Za-z_$][A-Za-z0-9_$]*/g;
|
|
133
130
|
for (const file of files) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
131
|
+
let content;
|
|
132
|
+
try {
|
|
133
|
+
content = await readFile(file.path, "utf-8");
|
|
134
|
+
} catch {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const seenInFile = /* @__PURE__ */ new Set();
|
|
138
|
+
for (const match of stripNoise(content).matchAll(identifierPattern)) {
|
|
139
|
+
const identifier = match[0];
|
|
140
|
+
if (exportedNames.has(identifier)) seenInFile.add(identifier);
|
|
141
|
+
}
|
|
142
|
+
for (const identifier of seenInFile) {
|
|
143
|
+
filesContainingIdentifier.set(
|
|
144
|
+
identifier,
|
|
145
|
+
(filesContainingIdentifier.get(identifier) ?? 0) + 1
|
|
139
146
|
);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (!usedElsewhere) {
|
|
149
|
-
suspicious.push(exp);
|
|
150
|
-
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
for (const exp of file.exports) {
|
|
151
|
+
if ((filesContainingIdentifier.get(exp.identifier) ?? 0) <= 1) suspicious.push(exp);
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
suspicious.sort((a, b) => {
|
|
@@ -163,11 +164,11 @@ async function scan(root, depth, cfg) {
|
|
|
163
164
|
for (const p of filePaths) {
|
|
164
165
|
try {
|
|
165
166
|
const content = await readFile(p, "utf-8");
|
|
166
|
-
files.push({ path: p,
|
|
167
|
+
files.push({ path: p, exports: extractExports(content, p) });
|
|
167
168
|
} catch {
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
|
-
return { findings: findUnusedSymbols(files), scannedFiles: files.length };
|
|
171
|
+
return { findings: await findUnusedSymbols(files), scannedFiles: files.length };
|
|
171
172
|
}
|
|
172
173
|
async function resolveScanRoot(rawPath) {
|
|
173
174
|
const resolved = resolve2(process.cwd(), rawPath);
|
|
@@ -263,16 +264,16 @@ var plugin = {
|
|
|
263
264
|
}
|
|
264
265
|
state.hitCount += 1;
|
|
265
266
|
state.warningCount += relevant.length;
|
|
266
|
-
const list = relevant.map(
|
|
267
|
-
(f) => ` - ${f.identifier} (${f.exportType}) at ${relativePath(f.file)}:${f.line}`
|
|
268
|
-
).join("\n");
|
|
267
|
+
const list = relevant.map((f) => ` - ${f.identifier} (${f.exportType}) at ${relativePath(f.file)}:${f.line}`).join("\n");
|
|
269
268
|
const message = `
|
|
270
269
|
\u26A0\uFE0F dead-code-detector: ${relevant.length} exported symbol(s) in ${sourcePath} look unused:
|
|
271
270
|
${list}
|
|
272
271
|
Consider removing the export if it is not part of the public API.`;
|
|
273
272
|
return { additionalContext: message };
|
|
274
273
|
};
|
|
275
|
-
state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
274
|
+
state.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, {
|
|
275
|
+
background: true
|
|
276
|
+
});
|
|
276
277
|
api.tools.register({
|
|
277
278
|
name: "dead_code_scan",
|
|
278
279
|
description: "Scan TypeScript/JavaScript source files for exported symbols that appear unused anywhere in the project.",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Plugin } from '@wrongstack/core/types';
|
|
2
|
-
export declare const OFFICIAL_PLUGIN_SPECIFIERS: readonly ['@wrongstack/plugins/agent-handoff', '@wrongstack/plugins/cost-tracker', '@wrongstack/plugins/file-watcher', '@wrongstack/plugins/git-autocommit', '@wrongstack/plugins/auto-doc', '@wrongstack/plugins/shell-check', '@wrongstack/plugins/cron', '@wrongstack/plugins/template-engine', '@wrongstack/plugins/semver-bump', '@wrongstack/plugins/secret-scanner', '@wrongstack/plugins/todo-tracker', '@wrongstack/plugins/token-budget', '@wrongstack/plugins/lint-gate', '@wrongstack/plugins/branch-guard', '@wrongstack/plugins/diff-summary', '@wrongstack/plugins/commit-validator', '@wrongstack/plugins/format-on-save', '@wrongstack/plugins/test-runner-gate', '@wrongstack/plugins/import-organizer', '@wrongstack/plugins/knowledge-graph', '@wrongstack/plugins/todo-listener', '@wrongstack/plugins/session-recap', '@wrongstack/plugins/spec-linker', '@wrongstack/plugins/loop-breaker', '@wrongstack/plugins/path-guard', '@wrongstack/plugins/process-guard', '@wrongstack/plugins/context-pins', '@wrongstack/plugins/checkpoint', '@wrongstack/plugins/error-lens', '@wrongstack/plugins/dep-guard', '@wrongstack/plugins/config-validator', '@wrongstack/plugins/notify-hub', '@wrongstack/plugins/changelog-writer', '@wrongstack/plugins/injection-shield', '@wrongstack/plugins/llm-cache', '@wrongstack/plugins/model-router', '@wrongstack/plugins/pr-drafter', '@wrongstack/plugins/prompt-firewall', '@wrongstack/plugins/auto-escalate', '@wrongstack/plugins/test-coverage-gate', '@wrongstack/plugins/type-gate', '@wrongstack/plugins/token-throttle', '@wrongstack/plugins/plugin-stack-observer', '@wrongstack/plugins/
|
|
2
|
+
export declare const OFFICIAL_PLUGIN_SPECIFIERS: readonly ['@wrongstack/plugins/agent-handoff', '@wrongstack/plugins/cost-tracker', '@wrongstack/plugins/file-watcher', '@wrongstack/plugins/git-autocommit', '@wrongstack/plugins/auto-doc', '@wrongstack/plugins/shell-check', '@wrongstack/plugins/cron', '@wrongstack/plugins/template-engine', '@wrongstack/plugins/semver-bump', '@wrongstack/plugins/secret-scanner', '@wrongstack/plugins/todo-tracker', '@wrongstack/plugins/token-budget', '@wrongstack/plugins/lint-gate', '@wrongstack/plugins/branch-guard', '@wrongstack/plugins/diff-summary', '@wrongstack/plugins/commit-validator', '@wrongstack/plugins/format-on-save', '@wrongstack/plugins/test-runner-gate', '@wrongstack/plugins/import-organizer', '@wrongstack/plugins/knowledge-graph', '@wrongstack/plugins/todo-listener', '@wrongstack/plugins/session-recap', '@wrongstack/plugins/spec-linker', '@wrongstack/plugins/loop-breaker', '@wrongstack/plugins/path-guard', '@wrongstack/plugins/process-guard', '@wrongstack/plugins/context-pins', '@wrongstack/plugins/checkpoint', '@wrongstack/plugins/error-lens', '@wrongstack/plugins/dep-guard', '@wrongstack/plugins/config-validator', '@wrongstack/plugins/notify-hub', '@wrongstack/plugins/changelog-writer', '@wrongstack/plugins/injection-shield', '@wrongstack/plugins/llm-cache', '@wrongstack/plugins/model-router', '@wrongstack/plugins/pr-drafter', '@wrongstack/plugins/prompt-firewall', '@wrongstack/plugins/auto-escalate', '@wrongstack/plugins/test-coverage-gate', '@wrongstack/plugins/type-gate', '@wrongstack/plugins/token-throttle', '@wrongstack/plugins/plugin-stack-observer', '@wrongstack/plugins/dependency-vulnerability-gate', '@wrongstack/plugins/migration-planner', '@wrongstack/plugins/semantic-search-indexer', '@wrongstack/plugins/auto-i18n-extractor', '@wrongstack/plugins/doc-sync-guard', '@wrongstack/plugins/api-compatibility-gate', '@wrongstack/plugins/performance-regression-gate', '@wrongstack/plugins/test-flake-detector', '@wrongstack/plugins/schema-evolution-guard', '@wrongstack/plugins/license-audit-gate', '@wrongstack/plugins/accessibility-auditor', '@wrongstack/plugins/security-hotspot-scanner', '@wrongstack/plugins/dead-code-detector', '@wrongstack/plugins/duplicate-code-detector', '@wrongstack/plugins/code-metrics', '@wrongstack/plugins/refactor-suggester', '@wrongstack/plugins/test-generator', '@wrongstack/plugins/release-notes-generator', '@wrongstack/plugins/smart-rename', '@wrongstack/plugins/feature-flag-tracker', '@wrongstack/plugins/interface-contract-guard'];
|
|
3
3
|
export declare const OFFICIAL_PLUGIN_FACTORIES: readonly (() => Promise<Plugin>)[];
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/factories.js
CHANGED
|
@@ -43,7 +43,6 @@ var OFFICIAL_PLUGIN_SPECIFIERS = [
|
|
|
43
43
|
"@wrongstack/plugins/type-gate",
|
|
44
44
|
"@wrongstack/plugins/token-throttle",
|
|
45
45
|
"@wrongstack/plugins/plugin-stack-observer",
|
|
46
|
-
"@wrongstack/plugins/dead-code-detector",
|
|
47
46
|
"@wrongstack/plugins/dependency-vulnerability-gate",
|
|
48
47
|
"@wrongstack/plugins/migration-planner",
|
|
49
48
|
"@wrongstack/plugins/semantic-search-indexer",
|
|
@@ -56,6 +55,7 @@ var OFFICIAL_PLUGIN_SPECIFIERS = [
|
|
|
56
55
|
"@wrongstack/plugins/license-audit-gate",
|
|
57
56
|
"@wrongstack/plugins/accessibility-auditor",
|
|
58
57
|
"@wrongstack/plugins/security-hotspot-scanner",
|
|
58
|
+
"@wrongstack/plugins/dead-code-detector",
|
|
59
59
|
"@wrongstack/plugins/duplicate-code-detector",
|
|
60
60
|
"@wrongstack/plugins/code-metrics",
|
|
61
61
|
"@wrongstack/plugins/refactor-suggester",
|
package/dist/file-watcher.js
CHANGED
|
@@ -18,6 +18,9 @@ function nextId() {
|
|
|
18
18
|
}
|
|
19
19
|
var watches = /* @__PURE__ */ new Map();
|
|
20
20
|
var debounceTimers = /* @__PURE__ */ new Map();
|
|
21
|
+
var MAX_WATCH_GROUPS = 32;
|
|
22
|
+
var MAX_PATHS_PER_WATCH = 16;
|
|
23
|
+
var MAX_FILESYSTEM_WATCHERS = 64;
|
|
21
24
|
var plugin = {
|
|
22
25
|
name: "file-watcher",
|
|
23
26
|
version: "0.1.0",
|
|
@@ -155,8 +158,10 @@ var plugin = {
|
|
|
155
158
|
api.log.warn(`file-watcher: error on ${dirPath}: ${err}`);
|
|
156
159
|
});
|
|
157
160
|
handle.watchers.push(watcher);
|
|
161
|
+
return true;
|
|
158
162
|
} catch (err) {
|
|
159
163
|
api.log.warn(`file-watcher: could not watch ${dirPath}: ${err}`);
|
|
164
|
+
return false;
|
|
160
165
|
}
|
|
161
166
|
}
|
|
162
167
|
api.tools.register({
|
|
@@ -168,6 +173,7 @@ var plugin = {
|
|
|
168
173
|
paths: {
|
|
169
174
|
type: "array",
|
|
170
175
|
items: { type: "string" },
|
|
176
|
+
maxItems: MAX_PATHS_PER_WATCH,
|
|
171
177
|
description: "File or directory paths to watch"
|
|
172
178
|
},
|
|
173
179
|
events: {
|
|
@@ -196,7 +202,7 @@ var plugin = {
|
|
|
196
202
|
watch_id: null
|
|
197
203
|
};
|
|
198
204
|
}
|
|
199
|
-
const paths = rawPaths;
|
|
205
|
+
const paths = [...new Set(rawPaths)];
|
|
200
206
|
if (paths.length === 0) {
|
|
201
207
|
return {
|
|
202
208
|
ok: false,
|
|
@@ -204,6 +210,31 @@ var plugin = {
|
|
|
204
210
|
watch_id: null
|
|
205
211
|
};
|
|
206
212
|
}
|
|
213
|
+
if (paths.length > MAX_PATHS_PER_WATCH) {
|
|
214
|
+
return {
|
|
215
|
+
ok: false,
|
|
216
|
+
error: `a watch may contain at most ${MAX_PATHS_PER_WATCH} unique paths`,
|
|
217
|
+
watch_id: null
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (watches.size >= MAX_WATCH_GROUPS) {
|
|
221
|
+
return {
|
|
222
|
+
ok: false,
|
|
223
|
+
error: `active watch group limit reached (${MAX_WATCH_GROUPS})`,
|
|
224
|
+
watch_id: null
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const activeFilesystemWatchers = [...watches.values()].reduce(
|
|
228
|
+
(total, handle2) => total + handle2.watchers.length,
|
|
229
|
+
0
|
|
230
|
+
);
|
|
231
|
+
if (activeFilesystemWatchers + paths.length > MAX_FILESYSTEM_WATCHERS) {
|
|
232
|
+
return {
|
|
233
|
+
ok: false,
|
|
234
|
+
error: `filesystem watcher limit reached (${MAX_FILESYSTEM_WATCHERS})`,
|
|
235
|
+
watch_id: null
|
|
236
|
+
};
|
|
237
|
+
}
|
|
207
238
|
const events = input["events"] ?? ["change", "add", "delete"];
|
|
208
239
|
const recursive = input["recursive"] ?? true;
|
|
209
240
|
const bad = paths.find((p) => !withinProject(p));
|
|
@@ -224,18 +255,20 @@ var plugin = {
|
|
|
224
255
|
watchers: [],
|
|
225
256
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
226
257
|
};
|
|
258
|
+
const watchedPaths = [];
|
|
227
259
|
for (const p of paths) {
|
|
228
|
-
safeWatchDir(p, recursive, handle);
|
|
260
|
+
if (safeWatchDir(p, recursive, handle)) watchedPaths.push(p);
|
|
229
261
|
}
|
|
262
|
+
handle.paths = watchedPaths;
|
|
230
263
|
watches.set(id, handle);
|
|
231
264
|
api.metrics.gauge("active_watches", watches.size);
|
|
232
265
|
return {
|
|
233
266
|
ok: true,
|
|
234
267
|
watch_id: id,
|
|
235
|
-
paths,
|
|
268
|
+
paths: watchedPaths,
|
|
236
269
|
events,
|
|
237
270
|
recursive,
|
|
238
|
-
message: `Started watching ${
|
|
271
|
+
message: `Started watching ${watchedPaths.length} path(s). Use watch_stop to cancel.`
|
|
239
272
|
};
|
|
240
273
|
}
|
|
241
274
|
});
|