@wrongstack/plugins 0.281.3 → 0.282.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 (78) hide show
  1. package/README.md +29 -3
  2. package/dist/accessibility-auditor.d.ts +40 -0
  3. package/dist/accessibility-auditor.js +411 -0
  4. package/dist/agent-handoff.d.ts +37 -0
  5. package/dist/agent-handoff.js +298 -0
  6. package/dist/api-compatibility-gate.d.ts +38 -0
  7. package/dist/api-compatibility-gate.js +357 -0
  8. package/dist/auto-i18n-extractor.d.ts +36 -0
  9. package/dist/auto-i18n-extractor.js +335 -0
  10. package/dist/checkpoint.js +18 -0
  11. package/dist/code-metrics.d.ts +31 -0
  12. package/dist/code-metrics.js +338 -0
  13. package/dist/commit-validator.js +67 -12
  14. package/dist/cost-tracker.js +58 -16
  15. package/dist/dead-code-detector.d.ts +34 -0
  16. package/dist/dead-code-detector.js +354 -0
  17. package/dist/dep-guard.js +47 -6
  18. package/dist/dependency-vulnerability-gate.d.ts +35 -0
  19. package/dist/dependency-vulnerability-gate.js +308 -0
  20. package/dist/diff-summary.js +97 -10
  21. package/dist/doc-sync-guard.d.ts +33 -0
  22. package/dist/doc-sync-guard.js +223 -0
  23. package/dist/duplicate-code-detector.d.ts +33 -0
  24. package/dist/duplicate-code-detector.js +384 -0
  25. package/dist/feature-flag-tracker.d.ts +38 -0
  26. package/dist/feature-flag-tracker.js +316 -0
  27. package/dist/file-watcher.js +85 -36
  28. package/dist/format-on-save.js +76 -10
  29. package/dist/import-organizer.js +73 -14
  30. package/dist/index.d.ts +27 -0
  31. package/dist/index.js +14067 -5054
  32. package/dist/interface-contract-guard.d.ts +37 -0
  33. package/dist/interface-contract-guard.js +302 -0
  34. package/dist/knowledge-graph.d.ts +45 -0
  35. package/dist/knowledge-graph.js +325 -0
  36. package/dist/license-audit-gate.d.ts +34 -0
  37. package/dist/license-audit-gate.js +260 -0
  38. package/dist/llm-cache.js +5 -0
  39. package/dist/loop-breaker.d.ts +0 -38
  40. package/dist/loop-breaker.js +209 -8
  41. package/dist/migration-planner.d.ts +30 -0
  42. package/dist/migration-planner.js +349 -0
  43. package/dist/model-router.js +5 -0
  44. package/dist/performance-regression-gate.d.ts +33 -0
  45. package/dist/performance-regression-gate.js +315 -0
  46. package/dist/plugin-stack-observer.d.ts +35 -0
  47. package/dist/plugin-stack-observer.js +125 -0
  48. package/dist/pr-drafter.d.ts +35 -0
  49. package/dist/pr-drafter.js +334 -0
  50. package/dist/prompt-firewall.js +5 -0
  51. package/dist/refactor-suggester.d.ts +38 -0
  52. package/dist/refactor-suggester.js +382 -0
  53. package/dist/release-notes-generator.d.ts +27 -0
  54. package/dist/release-notes-generator.js +209 -0
  55. package/dist/schema-evolution-guard.d.ts +42 -0
  56. package/dist/schema-evolution-guard.js +319 -0
  57. package/dist/security-hotspot-scanner.d.ts +30 -0
  58. package/dist/security-hotspot-scanner.js +402 -0
  59. package/dist/semantic-search-indexer.d.ts +38 -0
  60. package/dist/semantic-search-indexer.js +436 -0
  61. package/dist/shell-check.js +38 -3
  62. package/dist/smart-rename.d.ts +26 -0
  63. package/dist/smart-rename.js +170 -0
  64. package/dist/spec-linker.js +273 -133
  65. package/dist/test-coverage-gate.d.ts +37 -0
  66. package/dist/test-coverage-gate.js +263 -0
  67. package/dist/test-flake-detector.d.ts +27 -0
  68. package/dist/test-flake-detector.js +274 -0
  69. package/dist/test-generator.d.ts +32 -0
  70. package/dist/test-generator.js +243 -0
  71. package/dist/test-runner-gate.js +154 -22
  72. package/dist/todo-listener.d.ts +2 -2
  73. package/dist/todo-listener.js +5 -5
  74. package/dist/token-throttle.js +5 -0
  75. package/dist/type-gate.d.ts +37 -0
  76. package/dist/type-gate.js +311 -0
  77. package/package.json +112 -4
  78. package/LICENSE +0 -21
@@ -1,7 +1,48 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { existsSync, statSync } from 'fs';
3
+ import { isAbsolute, resolve, relative, basename } from 'path';
3
4
 
4
5
  // src/import-organizer/index.ts
6
+ function withinProject(p) {
7
+ if (typeof p !== "string" || p.length === 0 || p.length > 4096) return false;
8
+ const root = process.cwd();
9
+ const resolved = isAbsolute(p) ? resolve(p) : resolve(root, p);
10
+ const rel = relative(root, resolved);
11
+ if (rel === "" || rel === ".") return true;
12
+ if (rel.startsWith("..")) return false;
13
+ if (isAbsolute(rel)) return false;
14
+ return true;
15
+ }
16
+ var ALLOWED_FIRST_TOKENS = /* @__PURE__ */ new Set([
17
+ "npx",
18
+ "pnpm",
19
+ "npm",
20
+ "yarn",
21
+ "biome",
22
+ "@biomejs/biome",
23
+ "eslint",
24
+ "node"
25
+ // Recognise a fully-qualified project-local path like
26
+ // "./node_modules/.bin/biome"; basename check kicks in below.
27
+ ]);
28
+ function resolveAllowedCommand(command) {
29
+ const tokens = command.split(/\s+/).filter(Boolean);
30
+ if (tokens.length === 0) return null;
31
+ const head = tokens[0];
32
+ if (ALLOWED_FIRST_TOKENS.has(head)) {
33
+ return { cmd: head, args: tokens.slice(1) };
34
+ }
35
+ if (isAbsolute(head)) {
36
+ if (!withinProject(head)) return null;
37
+ const base = basename(head);
38
+ if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
39
+ }
40
+ if (!isAbsolute(head) && withinProject(head)) {
41
+ const base = basename(head);
42
+ if (ALLOWED_FIRST_TOKENS.has(base)) return { cmd: head, args: tokens.slice(1) };
43
+ }
44
+ return null;
45
+ }
5
46
  var API_VERSION = "^0.1.10";
6
47
  var state = {
7
48
  invocationCount: 0,
@@ -17,7 +58,8 @@ var DEFAULTS = {
17
58
  enabled: true,
18
59
  command: "npx @biomejs/biome check --write --unsafe",
19
60
  fallbackCommand: "npx eslint --fix",
20
- timeoutMs: 1e4
61
+ timeoutMs: 1e4,
62
+ notifyFormatOnSave: true
21
63
  };
22
64
  function readConfig(raw) {
23
65
  if (!raw || typeof raw !== "object") return { ...DEFAULTS };
@@ -26,11 +68,12 @@ function readConfig(raw) {
26
68
  enabled: r["enabled"] !== false,
27
69
  command: typeof r["command"] === "string" && r["command"].length > 0 ? r["command"] : DEFAULTS.command,
28
70
  fallbackCommand: typeof r["fallbackCommand"] === "string" && r["fallbackCommand"].length > 0 ? r["fallbackCommand"] : DEFAULTS.fallbackCommand,
29
- timeoutMs: typeof r["timeoutMs"] === "number" && r["timeoutMs"] > 0 ? r["timeoutMs"] : DEFAULTS.timeoutMs
71
+ timeoutMs: typeof r["timeoutMs"] === "number" && r["timeoutMs"] > 0 ? r["timeoutMs"] : DEFAULTS.timeoutMs,
72
+ notifyFormatOnSave: r["notifyFormatOnSave"] !== false
30
73
  };
31
74
  }
32
75
  function runCommand(command, args, timeoutMs, cwd) {
33
- return new Promise((resolve) => {
76
+ return new Promise((resolve2) => {
34
77
  let timedOut = false;
35
78
  const stdoutChunks = [];
36
79
  const stderrChunks = [];
@@ -42,17 +85,17 @@ function runCommand(command, args, timeoutMs, cwd) {
42
85
  signal: AbortSignal.timeout(timeoutMs)
43
86
  });
44
87
  } catch {
45
- resolve({ code: 127, stdout: "", stderr: "", timedOut: false });
88
+ resolve2({ code: 127, stdout: "", stderr: "", timedOut: false });
46
89
  return;
47
90
  }
48
91
  child.stdout?.on("data", (c) => stdoutChunks.push(c));
49
92
  child.stderr?.on("data", (c) => stderrChunks.push(c));
50
93
  child.on("error", () => {
51
- resolve({ code: 127, stdout: "", stderr: "", timedOut: false });
94
+ resolve2({ code: 127, stdout: "", stderr: "", timedOut: false });
52
95
  });
53
96
  child.on("close", (code) => {
54
97
  if (timedOut) return;
55
- resolve({
98
+ resolve2({
56
99
  code,
57
100
  stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
58
101
  stderr: Buffer.concat(stderrChunks).toString("utf-8"),
@@ -61,11 +104,12 @@ function runCommand(command, args, timeoutMs, cwd) {
61
104
  });
62
105
  child.on("abort", () => {
63
106
  timedOut = true;
64
- resolve({ code: null, stdout: "", stderr: "", timedOut: true });
107
+ resolve2({ code: null, stdout: "", stderr: "", timedOut: true });
65
108
  });
66
109
  });
67
110
  }
68
111
  async function organizeImports(filePath, cfg, cwd) {
112
+ if (!withinProject(filePath)) return null;
69
113
  if (!existsSync(filePath)) return null;
70
114
  let bytesBefore;
71
115
  try {
@@ -73,15 +117,15 @@ async function organizeImports(filePath, cfg, cwd) {
73
117
  } catch {
74
118
  return null;
75
119
  }
76
- const primary = cfg.command.split(/\s+/).filter(Boolean);
77
- if (primary.length === 0) return null;
78
- const [primaryCmd, ...primaryArgs] = primary;
120
+ const primary = resolveAllowedCommand(cfg.command);
121
+ if (!primary) return null;
122
+ const [primaryCmd, ...primaryArgs] = [primary.cmd, ...primary.args];
79
123
  let result = await runCommand(primaryCmd, [...primaryArgs, filePath], cfg.timeoutMs, cwd);
80
124
  let usedCommand = cfg.command;
81
125
  if (result.code === 127 && cfg.fallbackCommand) {
82
- const fallback = cfg.fallbackCommand.split(/\s+/).filter(Boolean);
83
- if (fallback.length > 0) {
84
- const [fbCmd, ...fbArgs] = fallback;
126
+ const fallback = resolveAllowedCommand(cfg.fallbackCommand);
127
+ if (fallback) {
128
+ const [fbCmd, ...fbArgs] = [fallback.cmd, ...fallback.args];
85
129
  result = await runCommand(fbCmd, [...fbArgs, filePath], cfg.timeoutMs, cwd);
86
130
  usedCommand = cfg.fallbackCommand;
87
131
  }
@@ -132,6 +176,11 @@ var plugin = {
132
176
  minimum: 1e3,
133
177
  default: 1e4,
134
178
  description: "Per-invocation linter timeout in milliseconds."
179
+ },
180
+ notifyFormatOnSave: {
181
+ type: "boolean",
182
+ default: true,
183
+ description: "Emit `import-organizer:done` after each successful run so `format-on-save` can skip its redundant `biome format --write` pass on the same file. Set false to keep both running unconditionally."
135
184
  }
136
185
  }
137
186
  },
@@ -160,13 +209,23 @@ var plugin = {
160
209
  if (!state.linterAvailable) {
161
210
  state.linterAvailable = false;
162
211
  state.probeComplete = true;
163
- api.log.warn("import-organizer: no linter available \u2014 hook will be a no-op for the rest of the session");
212
+ api.log.warn(
213
+ "import-organizer: no linter available \u2014 hook will be a no-op for the rest of the session"
214
+ );
164
215
  }
165
216
  state.errorCount += 1;
166
217
  return;
167
218
  }
168
219
  state.linterAvailable = true;
169
220
  state.probeComplete = true;
221
+ if (cfg.notifyFormatOnSave) {
222
+ api.emitCustom("import-organizer:done", {
223
+ path: filePath,
224
+ changed: result.changed,
225
+ command: result.command,
226
+ when: (/* @__PURE__ */ new Date()).toISOString()
227
+ });
228
+ }
170
229
  state.lastResult = {
171
230
  path: filePath,
172
231
  tool: toolName,
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { default as agentHandoffPlugin } from './agent-handoff.js';
1
2
  export { default as autoDocPlugin } from './auto-doc.js';
2
3
  export { default as autoEscalatePlugin } from './auto-escalate.js';
3
4
  export { default as branchGuardPlugin } from './branch-guard.js';
@@ -16,12 +17,15 @@ export { default as formatOnSavePlugin } from './format-on-save.js';
16
17
  export { default as gitAutocommitPlugin } from './git-autocommit.js';
17
18
  export { default as importOrganizerPlugin } from './import-organizer.js';
18
19
  export { default as injectionShieldPlugin } from './injection-shield.js';
20
+ export { default as knowledgeGraphPlugin } from './knowledge-graph.js';
19
21
  export { default as lintGatePlugin } from './lint-gate.js';
20
22
  export { default as llmCachePlugin } from './llm-cache.js';
21
23
  export { default as loopBreakerPlugin } from './loop-breaker.js';
22
24
  export { default as modelRouterPlugin } from './model-router.js';
23
25
  export { default as notifyHubPlugin } from './notify-hub.js';
24
26
  export { default as pathGuardPlugin } from './path-guard.js';
27
+ export { default as pluginStackObserverPlugin } from './plugin-stack-observer.js';
28
+ export { default as prDrafterPlugin } from './pr-drafter.js';
25
29
  export { default as promptFirewallPlugin } from './prompt-firewall.js';
26
30
  export { default as secretScannerPlugin } from './secret-scanner.js';
27
31
  export { default as semverBumpPlugin } from './semver-bump.js';
@@ -29,7 +33,30 @@ export { default as sessionRecapPlugin } from './session-recap.js';
29
33
  export { default as shellCheckPlugin } from './shell-check.js';
30
34
  export { default as specLinkerPlugin } from './spec-linker.js';
31
35
  export { default as templateEnginePlugin } from './template-engine.js';
36
+ export { default as testCoverageGatePlugin } from './test-coverage-gate.js';
32
37
  export { default as testRunnerGatePlugin } from './test-runner-gate.js';
38
+ export { default as typeGatePlugin } from './type-gate.js';
39
+ export { default as accessibilityAuditorPlugin } from './accessibility-auditor.js';
40
+ export { default as apiCompatibilityGatePlugin } from './api-compatibility-gate.js';
41
+ export { default as autoI18nExtractorPlugin } from './auto-i18n-extractor.js';
42
+ export { default as codeMetricsPlugin } from './code-metrics.js';
43
+ export { default as deadCodeDetectorPlugin } from './dead-code-detector.js';
44
+ export { default as dependencyVulnerabilityGatePlugin } from './dependency-vulnerability-gate.js';
45
+ export { default as docSyncGuardPlugin } from './doc-sync-guard.js';
46
+ export { default as duplicateCodeDetectorPlugin } from './duplicate-code-detector.js';
47
+ export { default as featureFlagTrackerPlugin } from './feature-flag-tracker.js';
48
+ export { default as interfaceContractGuardPlugin } from './interface-contract-guard.js';
49
+ export { default as licenseAuditGatePlugin } from './license-audit-gate.js';
50
+ export { default as migrationPlannerPlugin } from './migration-planner.js';
51
+ export { default as performanceRegressionGatePlugin } from './performance-regression-gate.js';
52
+ export { default as refactorSuggesterPlugin } from './refactor-suggester.js';
53
+ export { default as releaseNotesGeneratorPlugin } from './release-notes-generator.js';
54
+ export { default as schemaEvolutionGuardPlugin } from './schema-evolution-guard.js';
55
+ export { default as securityHotspotScannerPlugin } from './security-hotspot-scanner.js';
56
+ export { default as semanticSearchIndexerPlugin } from './semantic-search-indexer.js';
57
+ export { default as smartRenamePlugin } from './smart-rename.js';
58
+ export { default as testFlakeDetectorPlugin } from './test-flake-detector.js';
59
+ export { default as testGeneratorPlugin } from './test-generator.js';
33
60
  export { default as todoListenerPlugin } from './todo-listener.js';
34
61
  export { default as todoTrackerPlugin } from './todo-tracker.js';
35
62
  export { default as tokenBudgetPlugin } from './token-budget.js';