@wrongstack/plugins 0.297.0 → 0.298.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.
Files changed (92) hide show
  1. package/dist/audit/index.d.ts +6 -6
  2. package/dist/audit.js +7 -7
  3. package/dist/dead-code-detector.js +31 -30
  4. package/dist/factories/index.d.ts +1 -1
  5. package/dist/factories.js +1 -1
  6. package/dist/file-watcher.js +37 -4
  7. package/dist/index.js +232 -111
  8. package/dist/loop-breaker.js +19 -7
  9. package/dist/manifest.js +1 -1
  10. package/dist/runtime/index.d.ts +2 -2
  11. package/dist/session-recap.js +47 -13
  12. package/dist/spec-linker.js +1 -1
  13. package/dist/template-engine.js +42 -1
  14. package/package.json +9 -8
  15. package/dist/accessibility-auditor/index.d.ts.map +0 -1
  16. package/dist/agent-handoff/index.d.ts.map +0 -1
  17. package/dist/api-compatibility-gate/index.d.ts.map +0 -1
  18. package/dist/audit/index.d.ts.map +0 -1
  19. package/dist/auto-doc/index.d.ts.map +0 -1
  20. package/dist/auto-escalate/index.d.ts.map +0 -1
  21. package/dist/auto-i18n-extractor/index.d.ts.map +0 -1
  22. package/dist/branch-guard/index.d.ts.map +0 -1
  23. package/dist/catalog.d.ts.map +0 -1
  24. package/dist/changelog-writer/index.d.ts.map +0 -1
  25. package/dist/checkpoint/index.d.ts.map +0 -1
  26. package/dist/code-metrics/index.d.ts.map +0 -1
  27. package/dist/commit-validator/index.d.ts.map +0 -1
  28. package/dist/config-validator/index.d.ts.map +0 -1
  29. package/dist/context-pins/index.d.ts.map +0 -1
  30. package/dist/cost-tracker/index.d.ts.map +0 -1
  31. package/dist/cron/index.d.ts.map +0 -1
  32. package/dist/dead-code-detector/index.d.ts.map +0 -1
  33. package/dist/dep-guard/index.d.ts.map +0 -1
  34. package/dist/dependency-vulnerability-gate/index.d.ts.map +0 -1
  35. package/dist/diff-summary/index.d.ts.map +0 -1
  36. package/dist/doc-sync-guard/index.d.ts.map +0 -1
  37. package/dist/duplicate-code-detector/index.d.ts.map +0 -1
  38. package/dist/error-lens/index.d.ts.map +0 -1
  39. package/dist/factories/index.d.ts.map +0 -1
  40. package/dist/feature-flag-tracker/index.d.ts.map +0 -1
  41. package/dist/file-watcher/index.d.ts.map +0 -1
  42. package/dist/format-on-save/index.d.ts.map +0 -1
  43. package/dist/generated-plugin-exports.d.ts.map +0 -1
  44. package/dist/git-autocommit/index.d.ts.map +0 -1
  45. package/dist/import-organizer/index.d.ts.map +0 -1
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/injection-shield/index.d.ts.map +0 -1
  48. package/dist/interface-contract-guard/index.d.ts.map +0 -1
  49. package/dist/knowledge-graph/index.d.ts.map +0 -1
  50. package/dist/license-audit-gate/index.d.ts.map +0 -1
  51. package/dist/lint-gate/index.d.ts.map +0 -1
  52. package/dist/llm-cache/index.d.ts.map +0 -1
  53. package/dist/loop-breaker/index.d.ts.map +0 -1
  54. package/dist/manifest/index.d.ts.map +0 -1
  55. package/dist/migration-planner/index.d.ts.map +0 -1
  56. package/dist/model-router/index.d.ts.map +0 -1
  57. package/dist/notify-hub/index.d.ts.map +0 -1
  58. package/dist/notify-hub/webhook-channel.d.ts.map +0 -1
  59. package/dist/path-guard/index.d.ts.map +0 -1
  60. package/dist/performance-regression-gate/index.d.ts.map +0 -1
  61. package/dist/plugin-stack-observer/index.d.ts.map +0 -1
  62. package/dist/pr-drafter/index.d.ts.map +0 -1
  63. package/dist/process-guard/index.d.ts.map +0 -1
  64. package/dist/prompt-firewall/index.d.ts.map +0 -1
  65. package/dist/refactor-suggester/index.d.ts.map +0 -1
  66. package/dist/release-notes-generator/index.d.ts.map +0 -1
  67. package/dist/runtime/bounded-map.d.ts.map +0 -1
  68. package/dist/runtime/credential-patterns.d.ts.map +0 -1
  69. package/dist/runtime/handles.d.ts.map +0 -1
  70. package/dist/runtime/index.d.ts.map +0 -1
  71. package/dist/runtime/llm.d.ts.map +0 -1
  72. package/dist/runtime/local-bin.d.ts.map +0 -1
  73. package/dist/runtime/safe-json.d.ts.map +0 -1
  74. package/dist/schema-evolution-guard/index.d.ts.map +0 -1
  75. package/dist/secret-scanner/index.d.ts.map +0 -1
  76. package/dist/security-hotspot-scanner/index.d.ts.map +0 -1
  77. package/dist/semantic-search-indexer/index.d.ts.map +0 -1
  78. package/dist/semver-bump/index.d.ts.map +0 -1
  79. package/dist/session-recap/index.d.ts.map +0 -1
  80. package/dist/shell-check/index.d.ts.map +0 -1
  81. package/dist/smart-rename/index.d.ts.map +0 -1
  82. package/dist/spec-linker/index.d.ts.map +0 -1
  83. package/dist/template-engine/index.d.ts.map +0 -1
  84. package/dist/test-coverage-gate/index.d.ts.map +0 -1
  85. package/dist/test-flake-detector/index.d.ts.map +0 -1
  86. package/dist/test-generator/index.d.ts.map +0 -1
  87. package/dist/test-runner-gate/index.d.ts.map +0 -1
  88. package/dist/todo-listener/index.d.ts.map +0 -1
  89. package/dist/todo-tracker/index.d.ts.map +0 -1
  90. package/dist/token-budget/index.d.ts.map +0 -1
  91. package/dist/token-throttle/index.d.ts.map +0 -1
  92. package/dist/type-gate/index.d.ts.map +0 -1
@@ -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
- const fileExports = extractExports(file.content, file.path);
135
- for (const exp of fileExports) {
136
- const pattern = new RegExp(
137
- `(?<![A-Za-z0-9_$])${escapeRegex(exp.identifier)}(?![A-Za-z0-9_$])`,
138
- "g"
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
- let usedElsewhere = false;
141
- for (const other of files) {
142
- if (other.path === file.path) continue;
143
- if (pattern.test(other.stripped)) {
144
- usedElsewhere = true;
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, content, stripped: stripNoise(content) });
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, { background: true });
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/dead-code-detector', '@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/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'];
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",
@@ -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 ${paths.length} path(s). Use watch_stop to cancel.`
271
+ message: `Started watching ${watchedPaths.length} path(s). Use watch_stop to cancel.`
239
272
  };
240
273
  }
241
274
  });