agentsys 5.0.3 → 5.1.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 (264) hide show
  1. package/.claude-plugin/marketplace.json +21 -14
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +2 -1
  4. package/CHANGELOG.md +18 -0
  5. package/README.md +7 -6
  6. package/adapters/codex/skills/agnix/SKILL.md +0 -1
  7. package/adapters/codex/skills/audit-project/SKILL.md +0 -1
  8. package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
  9. package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
  10. package/adapters/codex/skills/consult/SKILL.md +132 -57
  11. package/adapters/codex/skills/debate/SKILL.md +214 -0
  12. package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
  13. package/adapters/codex/skills/deslop/SKILL.md +0 -1
  14. package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
  15. package/adapters/codex/skills/enhance/SKILL.md +0 -1
  16. package/adapters/codex/skills/learn/SKILL.md +0 -1
  17. package/adapters/codex/skills/next-task/SKILL.md +0 -1
  18. package/adapters/codex/skills/perf/SKILL.md +0 -1
  19. package/adapters/codex/skills/repo-map/SKILL.md +0 -1
  20. package/adapters/codex/skills/ship/SKILL.md +0 -1
  21. package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
  22. package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
  23. package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
  24. package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
  25. package/adapters/opencode/agents/agent-enhancer.md +0 -1
  26. package/adapters/opencode/agents/agnix-agent.md +0 -1
  27. package/adapters/opencode/agents/ci-fixer.md +0 -1
  28. package/adapters/opencode/agents/ci-monitor.md +0 -1
  29. package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
  30. package/adapters/opencode/agents/consult-agent.md +122 -30
  31. package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
  32. package/adapters/opencode/agents/debate-orchestrator.md +169 -0
  33. package/adapters/opencode/agents/delivery-validator.md +0 -1
  34. package/adapters/opencode/agents/deslop-agent.md +0 -1
  35. package/adapters/opencode/agents/docs-enhancer.md +0 -1
  36. package/adapters/opencode/agents/exploration-agent.md +0 -1
  37. package/adapters/opencode/agents/hooks-enhancer.md +0 -1
  38. package/adapters/opencode/agents/implementation-agent.md +0 -1
  39. package/adapters/opencode/agents/learn-agent.md +0 -1
  40. package/adapters/opencode/agents/map-validator.md +0 -1
  41. package/adapters/opencode/agents/perf-analyzer.md +0 -1
  42. package/adapters/opencode/agents/perf-code-paths.md +0 -1
  43. package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
  44. package/adapters/opencode/agents/perf-orchestrator.md +0 -1
  45. package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
  46. package/adapters/opencode/agents/perf-theory-tester.md +0 -1
  47. package/adapters/opencode/agents/plan-synthesizer.md +0 -1
  48. package/adapters/opencode/agents/planning-agent.md +0 -1
  49. package/adapters/opencode/agents/plugin-enhancer.md +0 -1
  50. package/adapters/opencode/agents/prompt-enhancer.md +0 -1
  51. package/adapters/opencode/agents/simple-fixer.md +0 -1
  52. package/adapters/opencode/agents/skills-enhancer.md +0 -1
  53. package/adapters/opencode/agents/sync-docs-agent.md +0 -1
  54. package/adapters/opencode/agents/task-discoverer.md +0 -1
  55. package/adapters/opencode/agents/test-coverage-checker.md +0 -1
  56. package/adapters/opencode/agents/worktree-manager.md +0 -1
  57. package/adapters/opencode/commands/agnix.md +0 -1
  58. package/adapters/opencode/commands/audit-project-agents.md +0 -1
  59. package/adapters/opencode/commands/audit-project-github.md +0 -1
  60. package/adapters/opencode/commands/audit-project.md +0 -1
  61. package/adapters/opencode/commands/consult.md +133 -57
  62. package/adapters/opencode/commands/debate.md +224 -0
  63. package/adapters/opencode/commands/delivery-approval.md +0 -1
  64. package/adapters/opencode/commands/deslop.md +0 -1
  65. package/adapters/opencode/commands/drift-detect.md +0 -1
  66. package/adapters/opencode/commands/enhance.md +0 -1
  67. package/adapters/opencode/commands/learn.md +0 -1
  68. package/adapters/opencode/commands/next-task.md +0 -1
  69. package/adapters/opencode/commands/perf.md +0 -1
  70. package/adapters/opencode/commands/repo-map.md +0 -1
  71. package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
  72. package/adapters/opencode/commands/ship-deployment.md +0 -1
  73. package/adapters/opencode/commands/ship-error-handling.md +0 -1
  74. package/adapters/opencode/commands/ship.md +0 -1
  75. package/adapters/opencode/commands/sync-docs.md +0 -1
  76. package/adapters/opencode/skills/agnix/SKILL.md +1 -2
  77. package/adapters/opencode/skills/consult/SKILL.md +33 -23
  78. package/adapters/opencode/skills/debate/SKILL.md +245 -0
  79. package/adapters/opencode/skills/deslop/SKILL.md +1 -2
  80. package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
  81. package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
  82. package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
  83. package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
  84. package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
  85. package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
  86. package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
  87. package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
  88. package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
  89. package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
  90. package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
  91. package/adapters/opencode/skills/learn/SKILL.md +1 -2
  92. package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
  93. package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
  94. package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
  95. package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
  96. package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
  97. package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
  98. package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
  99. package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
  100. package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
  101. package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
  102. package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
  103. package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
  104. package/lib/adapter-transforms.js +24 -4
  105. package/package.json +1 -1
  106. package/plugins/agnix/.claude-plugin/plugin.json +1 -1
  107. package/plugins/agnix/skills/agnix/SKILL.md +1 -1
  108. package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
  109. package/plugins/audit-project/lib/adapter-transforms.js +24 -4
  110. package/plugins/consult/.claude-plugin/plugin.json +1 -1
  111. package/plugins/consult/agents/consult-agent.md +122 -29
  112. package/plugins/consult/commands/consult.md +135 -58
  113. package/plugins/consult/skills/consult/SKILL.md +31 -20
  114. package/plugins/debate/.claude-plugin/plugin.json +21 -0
  115. package/plugins/debate/agents/debate-orchestrator.md +175 -0
  116. package/plugins/debate/commands/debate.md +221 -0
  117. package/plugins/debate/lib/adapter-transforms.js +298 -0
  118. package/plugins/debate/lib/collectors/codebase.js +392 -0
  119. package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
  120. package/plugins/debate/lib/collectors/documentation.js +219 -0
  121. package/plugins/debate/lib/collectors/github.js +330 -0
  122. package/plugins/debate/lib/collectors/index.js +126 -0
  123. package/plugins/debate/lib/config/index.js +14 -0
  124. package/plugins/debate/lib/cross-platform/index.js +539 -0
  125. package/plugins/debate/lib/discovery/index.js +352 -0
  126. package/plugins/debate/lib/drift-detect/collectors.js +37 -0
  127. package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
  128. package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
  129. package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
  130. package/plugins/debate/lib/enhance/benchmark.js +417 -0
  131. package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
  132. package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
  133. package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
  134. package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
  135. package/plugins/debate/lib/enhance/fixer.js +721 -0
  136. package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
  137. package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
  138. package/plugins/debate/lib/enhance/index.js +127 -0
  139. package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
  140. package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
  141. package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
  142. package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
  143. package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
  144. package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
  145. package/plugins/debate/lib/enhance/reporter.js +1348 -0
  146. package/plugins/debate/lib/enhance/security-patterns.js +284 -0
  147. package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
  148. package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
  149. package/plugins/debate/lib/enhance/suppression.js +352 -0
  150. package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
  151. package/plugins/debate/lib/index.js +270 -0
  152. package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
  153. package/plugins/debate/lib/patterns/pipeline.js +948 -0
  154. package/plugins/debate/lib/patterns/review-patterns.js +558 -0
  155. package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
  156. package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
  157. package/plugins/debate/lib/perf/analyzer/index.js +22 -0
  158. package/plugins/debate/lib/perf/argument-parser.js +105 -0
  159. package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
  160. package/plugins/debate/lib/perf/baseline-store.js +127 -0
  161. package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
  162. package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
  163. package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
  164. package/plugins/debate/lib/perf/checkpoint.js +123 -0
  165. package/plugins/debate/lib/perf/code-paths.js +86 -0
  166. package/plugins/debate/lib/perf/consolidation.js +37 -0
  167. package/plugins/debate/lib/perf/constraint-runner.js +71 -0
  168. package/plugins/debate/lib/perf/experiment-runner.js +32 -0
  169. package/plugins/debate/lib/perf/index.js +41 -0
  170. package/plugins/debate/lib/perf/investigation-state.js +874 -0
  171. package/plugins/debate/lib/perf/optimization-runner.js +79 -0
  172. package/plugins/debate/lib/perf/profilers/go.js +22 -0
  173. package/plugins/debate/lib/perf/profilers/index.js +46 -0
  174. package/plugins/debate/lib/perf/profilers/java.js +23 -0
  175. package/plugins/debate/lib/perf/profilers/node.js +27 -0
  176. package/plugins/debate/lib/perf/profilers/python.js +23 -0
  177. package/plugins/debate/lib/perf/profilers/rust.js +23 -0
  178. package/plugins/debate/lib/perf/profiling-runner.js +75 -0
  179. package/plugins/debate/lib/perf/schemas.js +140 -0
  180. package/plugins/debate/lib/platform/detect-platform.js +413 -0
  181. package/plugins/debate/lib/platform/detection-configs.js +93 -0
  182. package/plugins/debate/lib/platform/state-dir.js +132 -0
  183. package/plugins/debate/lib/platform/verify-tools.js +182 -0
  184. package/plugins/debate/lib/repo-map/cache.js +152 -0
  185. package/plugins/debate/lib/repo-map/concurrency.js +29 -0
  186. package/plugins/debate/lib/repo-map/index.js +222 -0
  187. package/plugins/debate/lib/repo-map/installer.js +212 -0
  188. package/plugins/debate/lib/repo-map/queries/go.js +27 -0
  189. package/plugins/debate/lib/repo-map/queries/index.js +100 -0
  190. package/plugins/debate/lib/repo-map/queries/java.js +38 -0
  191. package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
  192. package/plugins/debate/lib/repo-map/queries/python.js +24 -0
  193. package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
  194. package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
  195. package/plugins/debate/lib/repo-map/runner.js +1364 -0
  196. package/plugins/debate/lib/repo-map/updater.js +562 -0
  197. package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
  198. package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
  199. package/plugins/debate/lib/schemas/validator.js +247 -0
  200. package/plugins/debate/lib/sources/custom-handler.js +199 -0
  201. package/plugins/debate/lib/sources/policy-questions.js +246 -0
  202. package/plugins/debate/lib/sources/source-cache.js +165 -0
  203. package/plugins/debate/lib/state/workflow-state.js +576 -0
  204. package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
  205. package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
  206. package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
  207. package/plugins/debate/lib/types/index.d.ts +84 -0
  208. package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
  209. package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
  210. package/plugins/debate/lib/utils/atomic-write.js +94 -0
  211. package/plugins/debate/lib/utils/cache-manager.js +159 -0
  212. package/plugins/debate/lib/utils/command-parser.js +0 -0
  213. package/plugins/debate/lib/utils/context-optimizer.js +300 -0
  214. package/plugins/debate/lib/utils/deprecation.js +37 -0
  215. package/plugins/debate/lib/utils/shell-escape.js +88 -0
  216. package/plugins/debate/lib/utils/state-helpers.js +61 -0
  217. package/plugins/debate/skills/debate/SKILL.md +264 -0
  218. package/plugins/deslop/.claude-plugin/plugin.json +1 -1
  219. package/plugins/deslop/lib/adapter-transforms.js +24 -4
  220. package/plugins/deslop/skills/deslop/SKILL.md +1 -1
  221. package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
  222. package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
  223. package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
  224. package/plugins/enhance/.claude-plugin/plugin.json +1 -1
  225. package/plugins/enhance/lib/adapter-transforms.js +24 -4
  226. package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
  227. package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
  228. package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
  229. package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
  230. package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
  231. package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
  232. package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
  233. package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
  234. package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
  235. package/plugins/learn/.claude-plugin/plugin.json +1 -1
  236. package/plugins/learn/agents/learn-agent.md +1 -1
  237. package/plugins/learn/lib/adapter-transforms.js +24 -4
  238. package/plugins/learn/skills/learn/SKILL.md +1 -1
  239. package/plugins/next-task/.claude-plugin/plugin.json +1 -1
  240. package/plugins/next-task/agents/exploration-agent.md +1 -1
  241. package/plugins/next-task/lib/adapter-transforms.js +24 -4
  242. package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
  243. package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
  244. package/plugins/perf/.claude-plugin/plugin.json +1 -1
  245. package/plugins/perf/lib/adapter-transforms.js +24 -4
  246. package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
  247. package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
  248. package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
  249. package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
  250. package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
  251. package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
  252. package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
  253. package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
  254. package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
  255. package/plugins/repo-map/lib/adapter-transforms.js +24 -4
  256. package/plugins/ship/.claude-plugin/plugin.json +1 -1
  257. package/plugins/ship/lib/adapter-transforms.js +24 -4
  258. package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
  259. package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
  260. package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
  261. package/scripts/gen-adapters.js +6 -7
  262. package/scripts/generate-docs.js +4 -2
  263. package/scripts/plugins.txt +1 -0
  264. package/site/content.json +6 -6
@@ -0,0 +1,721 @@
1
+ /**
2
+ * Plugin Analysis Fixer
3
+ * @author Avi Fenesh
4
+ * @license MIT
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ function applyFixes(issues, options = {}) {
11
+ const { dryRun = false, backup = true } = options;
12
+
13
+ const results = {
14
+ applied: [],
15
+ skipped: [],
16
+ errors: []
17
+ };
18
+
19
+ // Auto-fixable pattern IDs for markdown files
20
+ const markdownAutoFixPatternIds = [
21
+ // Agent patterns
22
+ 'missing_frontmatter',
23
+ 'unrestricted_bash',
24
+ 'missing_role',
25
+ // Prompt patterns
26
+ 'missing_output_format',
27
+ 'missing_examples',
28
+ 'missing_xml_structure',
29
+ 'missing_verification_criteria',
30
+ 'aggressive_emphasis',
31
+ // Skill patterns
32
+ 'missing_trigger_phrase'
33
+ ];
34
+
35
+ // Filter to only HIGH certainty issues that are auto-fixable
36
+ // Includes: JSON issues with autoFixFn OR markdown issues with known pattern IDs
37
+ const fixableIssues = issues.filter(i =>
38
+ i.certainty === 'HIGH' &&
39
+ (i.filePath || i.file) &&
40
+ (i.autoFixFn || markdownAutoFixPatternIds.includes(i.patternId))
41
+ );
42
+
43
+ // Group by file to minimize reads/writes
44
+ const byFile = new Map();
45
+ for (const issue of fixableIssues) {
46
+ const fp = issue.filePath || issue.file;
47
+ if (!byFile.has(fp)) {
48
+ byFile.set(fp, []);
49
+ }
50
+ byFile.get(fp).push(issue);
51
+ }
52
+
53
+ // Process each file
54
+ for (const [filePath, fileIssues] of byFile) {
55
+ try {
56
+ // Read current content
57
+ if (!fs.existsSync(filePath)) {
58
+ results.errors.push({ filePath, error: 'File not found' });
59
+ continue;
60
+ }
61
+
62
+ const content = fs.readFileSync(filePath, 'utf8');
63
+ let data;
64
+
65
+ // Parse based on file type
66
+ if (filePath.endsWith('.json')) {
67
+ data = JSON.parse(content);
68
+ } else if (filePath.endsWith('.md')) {
69
+ // Markdown files - handle specially
70
+ data = content;
71
+ } else {
72
+ // For other files, skip auto-fix
73
+ results.skipped.push(...fileIssues.map(i => ({
74
+ ...i,
75
+ reason: 'Unsupported file type - manual fix required'
76
+ })));
77
+ continue;
78
+ }
79
+
80
+ // Apply each fix
81
+ let modified = data;
82
+ const appliedToFile = [];
83
+
84
+ for (const issue of fileIssues) {
85
+ try {
86
+ // Determine what part of data to fix
87
+ if (filePath.endsWith('.md')) {
88
+ // Markdown-specific fixes
89
+ if (issue.patternId === 'missing_frontmatter') {
90
+ modified = fixMissingFrontmatter(modified);
91
+ } else if (issue.patternId === 'unrestricted_bash') {
92
+ modified = fixUnrestrictedBash(modified);
93
+ } else if (issue.patternId === 'missing_role') {
94
+ modified = fixMissingRole(modified);
95
+ } else if (issue.patternId === 'missing_output_format') {
96
+ modified = fixMissingOutputFormat(modified);
97
+ } else if (issue.patternId === 'missing_examples') {
98
+ modified = fixMissingExamples(modified);
99
+ } else if (issue.patternId === 'missing_xml_structure') {
100
+ modified = fixMissingXmlStructure(modified);
101
+ } else if (issue.patternId === 'missing_verification_criteria') {
102
+ modified = fixMissingVerificationCriteria(modified);
103
+ } else if (issue.patternId === 'aggressive_emphasis') {
104
+ modified = fixAggressiveEmphasis(modified);
105
+ } else if (issue.patternId === 'missing_trigger_phrase') {
106
+ modified = fixMissingTriggerPhrase(modified);
107
+ } else {
108
+ // No auto-fix available for this markdown issue
109
+ continue;
110
+ }
111
+ } else if (issue.schemaPath) {
112
+ // Fix at specific path in the data
113
+ modified = applyAtPath(modified, issue.schemaPath, issue.autoFixFn);
114
+ } else {
115
+ // Apply to root
116
+ modified = issue.autoFixFn(modified);
117
+ }
118
+
119
+ appliedToFile.push({
120
+ issue: issue.issue,
121
+ fix: issue.fix,
122
+ filePath
123
+ });
124
+ } catch (err) {
125
+ results.errors.push({
126
+ issue: issue.issue,
127
+ filePath,
128
+ error: err.message
129
+ });
130
+ }
131
+ }
132
+
133
+ // Write changes
134
+ if (!dryRun && appliedToFile.length > 0) {
135
+ // Create backup
136
+ if (backup) {
137
+ const backupPath = `${filePath}.backup`;
138
+ fs.writeFileSync(backupPath, content, 'utf8');
139
+ }
140
+
141
+ // Write modified content
142
+ let newContent;
143
+ if (filePath.endsWith('.md')) {
144
+ newContent = modified; // Already a string
145
+ } else {
146
+ newContent = JSON.stringify(modified, null, 2);
147
+ }
148
+ fs.writeFileSync(filePath, newContent, 'utf8');
149
+ }
150
+
151
+ results.applied.push(...appliedToFile);
152
+
153
+ } catch (err) {
154
+ results.errors.push({
155
+ filePath,
156
+ error: err.message
157
+ });
158
+ }
159
+ }
160
+
161
+ // Add non-fixable issues to skipped
162
+ const nonFixable = issues.filter(i =>
163
+ i.certainty !== 'HIGH' || !markdownAutoFixPatternIds.includes(i.patternId)
164
+ );
165
+ results.skipped.push(...nonFixable.map(i => ({
166
+ ...i,
167
+ reason: i.certainty !== 'HIGH' ? 'Not HIGH certainty' : 'No auto-fix available for this pattern'
168
+ })));
169
+
170
+ return results;
171
+ }
172
+
173
+ function applyAtPath(obj, pathStr, fixFn) {
174
+ const parts = pathStr.split('.');
175
+ const result = structuredClone(obj);
176
+
177
+ let current = result;
178
+ for (let i = 0; i < parts.length - 1; i++) {
179
+ const part = parts[i];
180
+ if (part.includes('[')) {
181
+ // Array access
182
+ const match = part.match(/^((?!__proto__|constructor|prototype)[a-zA-Z_]\w*)\[(\d{1,10})\]$/);
183
+ if (match) {
184
+ current = current[match[1]][parseInt(match[2], 10)];
185
+ }
186
+ } else {
187
+ current = current[part];
188
+ }
189
+ }
190
+
191
+ const lastPart = parts[parts.length - 1];
192
+ if (lastPart.includes('[')) {
193
+ const match = lastPart.match(/^((?!__proto__|constructor|prototype)[a-zA-Z_]\w*)\[(\d{1,10})\]$/);
194
+ if (match) {
195
+ current[match[1]][parseInt(match[2], 10)] = fixFn(current[match[1]][parseInt(match[2], 10)]);
196
+ }
197
+ } else {
198
+ current[lastPart] = fixFn(current[lastPart]);
199
+ }
200
+
201
+ return result;
202
+ }
203
+
204
+ function fixAdditionalProperties(schema) {
205
+ if (!schema || typeof schema !== 'object') return schema;
206
+
207
+ const fixed = { ...schema };
208
+
209
+ if (fixed.type === 'object' && fixed.properties) {
210
+ fixed.additionalProperties = false;
211
+ }
212
+
213
+ // Recursively fix nested schemas
214
+ if (fixed.properties) {
215
+ fixed.properties = {};
216
+ for (const [key, value] of Object.entries(schema.properties)) {
217
+ fixed.properties[key] = fixAdditionalProperties(value);
218
+ }
219
+ }
220
+
221
+ return fixed;
222
+ }
223
+
224
+ function fixRequiredFields(schema) {
225
+ if (!schema || typeof schema !== 'object') return schema;
226
+
227
+ const fixed = { ...schema };
228
+
229
+ if (fixed.type === 'object' && fixed.properties && !fixed.required) {
230
+ // Add all non-optional fields to required
231
+ fixed.required = Object.entries(fixed.properties)
232
+ .filter(([_, prop]) => {
233
+ // Skip if has default or marked optional in description
234
+ if (prop.default !== undefined) return false;
235
+ if (prop.description && /optional/i.test(prop.description)) return false;
236
+ return true;
237
+ })
238
+ .map(([key]) => key);
239
+ }
240
+
241
+ return fixed;
242
+ }
243
+
244
+ function fixVersionMismatch(pluginJson, targetVersion) {
245
+ return {
246
+ ...pluginJson,
247
+ version: targetVersion
248
+ };
249
+ }
250
+
251
+ function previewFixes(issues) {
252
+ const previews = [];
253
+
254
+ for (const issue of issues) {
255
+ if (issue.certainty === 'HIGH' && issue.autoFixFn) {
256
+ previews.push({
257
+ filePath: issue.filePath,
258
+ issue: issue.issue,
259
+ fix: issue.fix,
260
+ willApply: true
261
+ });
262
+ } else {
263
+ previews.push({
264
+ filePath: issue.filePath,
265
+ issue: issue.issue,
266
+ fix: issue.fix || 'No auto-fix available',
267
+ willApply: false,
268
+ reason: issue.certainty !== 'HIGH' ? 'Not HIGH certainty' : 'No auto-fix function'
269
+ });
270
+ }
271
+ }
272
+
273
+ return previews;
274
+ }
275
+
276
+ function restoreFromBackup(filePath) {
277
+ const backupPath = `${filePath}.backup`;
278
+
279
+ if (!fs.existsSync(backupPath)) {
280
+ return false;
281
+ }
282
+
283
+ const backupContent = fs.readFileSync(backupPath, 'utf8');
284
+ fs.writeFileSync(filePath, backupContent, 'utf8');
285
+ fs.unlinkSync(backupPath);
286
+
287
+ return true;
288
+ }
289
+
290
+ function cleanupBackups(directory) {
291
+ let count = 0;
292
+
293
+ function findBackups(dir) {
294
+ let entries;
295
+ try {
296
+ entries = fs.readdirSync(dir, { withFileTypes: true });
297
+ } catch (err) {
298
+ return;
299
+ }
300
+
301
+ for (const entry of entries) {
302
+ const fullPath = path.join(dir, entry.name);
303
+ if (entry.isDirectory()) {
304
+ findBackups(fullPath);
305
+ } else if (entry.isFile() && entry.name.endsWith('.backup')) {
306
+ try {
307
+ fs.unlinkSync(fullPath);
308
+ count++;
309
+ } catch (err) {
310
+ console.error('[WARN] fixer error:', err.message);
311
+ }
312
+ }
313
+ }
314
+ }
315
+
316
+ findBackups(directory);
317
+ return count;
318
+ }
319
+
320
+ function fixMissingFrontmatter(content) {
321
+ if (!content || typeof content !== 'string') return content;
322
+
323
+ const template = `---
324
+ name: agent-name
325
+ description: Agent description
326
+ tools: Read, Glob, Grep
327
+ model: sonnet
328
+ ---
329
+
330
+ `;
331
+
332
+ return template + content.trim();
333
+ }
334
+
335
+ function fixUnrestrictedBash(content) {
336
+ if (!content || typeof content !== 'string') return content;
337
+
338
+ const lines = content.split('\n');
339
+ let inFrontmatter = false;
340
+
341
+ for (let i = 0; i < lines.length; i++) {
342
+ if (lines[i].trim() === '---') {
343
+ if (!inFrontmatter) {
344
+ inFrontmatter = true;
345
+ } else {
346
+ break;
347
+ }
348
+ } else if (inFrontmatter && lines[i].startsWith('tools:')) {
349
+ lines[i] = lines[i].replace(/\bBash\b(?!\()/g, 'Bash(git:*)');
350
+ }
351
+ }
352
+
353
+ return lines.join('\n');
354
+ }
355
+
356
+ function fixMissingRole(content) {
357
+ if (!content || typeof content !== 'string') return content;
358
+
359
+ const lines = content.split('\n');
360
+ let frontmatterEnd = -1;
361
+ let inFrontmatter = false;
362
+
363
+ for (let i = 0; i < lines.length; i++) {
364
+ if (lines[i].trim() === '---') {
365
+ if (!inFrontmatter) {
366
+ inFrontmatter = true;
367
+ } else {
368
+ frontmatterEnd = i;
369
+ break;
370
+ }
371
+ }
372
+ }
373
+
374
+ const roleSection = `
375
+ ## Your Role
376
+
377
+ You are an agent that [describe agent purpose].
378
+ `;
379
+
380
+ if (frontmatterEnd >= 0) {
381
+ lines.splice(frontmatterEnd + 1, 0, roleSection);
382
+ } else {
383
+ lines.unshift(roleSection);
384
+ }
385
+
386
+ return lines.join('\n');
387
+ }
388
+
389
+ function fixInconsistentHeadings(content) {
390
+ if (!content || typeof content !== 'string') return content;
391
+
392
+ const lines = content.split('\n');
393
+ let lastLevel = 0;
394
+ let inCodeBlock = false;
395
+
396
+ for (let i = 0; i < lines.length; i++) {
397
+ const line = lines[i];
398
+
399
+ if (line.startsWith('```')) {
400
+ inCodeBlock = !inCodeBlock;
401
+ continue;
402
+ }
403
+
404
+ if (inCodeBlock) continue;
405
+
406
+ const headingMatch = line.match(/^(#{1,6})[ \t]+(\S.*)$/);
407
+ if (headingMatch) {
408
+ const currentLevel = headingMatch[1].length;
409
+ const headingText = headingMatch[2];
410
+
411
+ if (lastLevel === 0) {
412
+ lastLevel = currentLevel;
413
+ continue;
414
+ }
415
+
416
+ // If jumping more than one level down, fix it
417
+ if (currentLevel > lastLevel + 1) {
418
+ const fixedLevel = lastLevel + 1;
419
+ lines[i] = '#'.repeat(fixedLevel) + ' ' + headingText;
420
+ lastLevel = fixedLevel;
421
+ } else {
422
+ lastLevel = currentLevel;
423
+ }
424
+ }
425
+ }
426
+
427
+ return lines.join('\n');
428
+ }
429
+
430
+ function fixVerboseExplanations(content) {
431
+ if (!content || typeof content !== 'string') return content;
432
+
433
+ const replacements = [
434
+ { from: /\bin order to\b/gi, to: 'to' },
435
+ { from: /\bfor the purpose of\b/gi, to: 'for' },
436
+ { from: /\bin the event that\b/gi, to: 'if' },
437
+ { from: /\bat this point in time\b/gi, to: 'now' },
438
+ { from: /\bdue to the fact that\b/gi, to: 'because' },
439
+ { from: /\bhas the ability to\b/gi, to: 'can' },
440
+ { from: /\bis able to\b/gi, to: 'can' },
441
+ { from: /\bmake use of\b/gi, to: 'use' },
442
+ { from: /\ba large number of\b/gi, to: 'many' },
443
+ { from: /\ba small number of\b/gi, to: 'few' },
444
+ { from: /\bthe majority of\b/gi, to: 'most' },
445
+ { from: /\bprior to\b/gi, to: 'before' },
446
+ { from: /\bsubsequent to\b/gi, to: 'after' }
447
+ ];
448
+
449
+ let result = content;
450
+
451
+ const codeBlockRegex = /```[\s\S]*?```/g;
452
+ const codeBlocks = [];
453
+ let placeholder = 0;
454
+
455
+ result = result.replace(codeBlockRegex, (match) => {
456
+ codeBlocks.push(match);
457
+ return `__CODE_BLOCK_${placeholder++}__`;
458
+ });
459
+
460
+ for (const { from, to } of replacements) {
461
+ result = result.replace(from, (match) => {
462
+ // Preserve case of first character
463
+ if (match[0] === match[0].toUpperCase()) {
464
+ return to[0].toUpperCase() + to.slice(1);
465
+ }
466
+ return to;
467
+ });
468
+ }
469
+
470
+ for (let i = 0; i < codeBlocks.length; i++) {
471
+ result = result.replace(`__CODE_BLOCK_${i}__`, codeBlocks[i]);
472
+ }
473
+
474
+ return result;
475
+ }
476
+
477
+ // ============================================
478
+ // PROMPT AUTO-FIX FUNCTIONS
479
+ // ============================================
480
+
481
+ /**
482
+ * Add output format section to prompt
483
+ * @param {string} content - Prompt content
484
+ * @returns {string} Fixed content
485
+ */
486
+ function fixMissingOutputFormat(content) {
487
+ if (!content || typeof content !== 'string') return content;
488
+
489
+ // Don't add if already has output format
490
+ if (/##\s*output\s*format/i.test(content) || /<output_format>/i.test(content)) {
491
+ return content;
492
+ }
493
+
494
+ const outputSection = `
495
+
496
+ ## Output Format
497
+
498
+ Respond with:
499
+ - [Describe expected format: JSON, markdown, plain text, etc.]
500
+ - [Include any specific structure requirements]
501
+ `;
502
+
503
+ return content.trim() + outputSection;
504
+ }
505
+
506
+ /**
507
+ * Add example section to prompt
508
+ * @param {string} content - Prompt content
509
+ * @returns {string} Fixed content
510
+ */
511
+ function fixMissingExamples(content) {
512
+ if (!content || typeof content !== 'string') return content;
513
+
514
+ // Don't add if already has examples
515
+ if (/<example>|##\s*example/i.test(content)) {
516
+ return content;
517
+ }
518
+
519
+ const exampleSection = `
520
+
521
+ ## Examples
522
+
523
+ <good-example>
524
+ Input: [example input]
525
+ Output: [example output]
526
+ </good-example>
527
+
528
+ <bad-example>
529
+ Input: [example input]
530
+ Output: [what NOT to do]
531
+ Why bad: [explanation]
532
+ </bad-example>
533
+ `;
534
+
535
+ return content.trim() + exampleSection;
536
+ }
537
+
538
+ /**
539
+ * Wrap a markdown section (heading to next heading/separator) in XML tags.
540
+ * Uses line-by-line scanning to avoid ReDoS from [\s\S]*? with lookaheads.
541
+ */
542
+ function wrapSection(text, headingPattern, tagName) {
543
+ const lines = text.split('\n');
544
+ let sectionStart = -1;
545
+ for (let i = 0; i < lines.length; i++) {
546
+ if (sectionStart === -1) {
547
+ if (headingPattern.test(lines[i])) {
548
+ sectionStart = i;
549
+ }
550
+ } else {
551
+ // End section at next heading or horizontal rule
552
+ if (/^#{1,6}\s/.test(lines[i]) || /^---/.test(lines[i])) {
553
+ const before = lines.slice(0, sectionStart);
554
+ const section = lines.slice(sectionStart, i);
555
+ const after = lines.slice(i);
556
+ return [...before, `<${tagName}>`, ...section, `</${tagName}>`, ...after].join('\n');
557
+ }
558
+ }
559
+ }
560
+ // Section runs to end of content
561
+ if (sectionStart !== -1) {
562
+ const before = lines.slice(0, sectionStart);
563
+ const section = lines.slice(sectionStart);
564
+ return [...before, `<${tagName}>`, ...section, `</${tagName}>`].join('\n');
565
+ }
566
+ return text;
567
+ }
568
+
569
+ /**
570
+ * Add XML structure tags to complex prompt
571
+ * @param {string} content - Prompt content
572
+ * @returns {string} Fixed content
573
+ */
574
+ function fixMissingXmlStructure(content) {
575
+ if (!content || typeof content !== 'string') return content;
576
+
577
+ // Don't add if already has XML
578
+ if (/<[a-z_][a-z0-9_-]*>/i.test(content)) {
579
+ return content;
580
+ }
581
+
582
+ // Wrap role section if exists
583
+ let result = content;
584
+
585
+ // Find and wrap role section (use non-regex approach to avoid ReDoS)
586
+ result = wrapSection(result, /^##[ \t]*(?:your[ \t]+)?role[ \t]*$/im, 'role');
587
+
588
+ // Find and wrap constraints section
589
+ result = wrapSection(result, /^##[ \t]*(?:constraints?|rules?)[ \t]*$/im, 'constraints');
590
+
591
+ return result;
592
+ }
593
+
594
+ /**
595
+ * Add verification criteria to task prompt
596
+ * @param {string} content - Prompt content
597
+ * @returns {string} Fixed content
598
+ */
599
+ function fixMissingVerificationCriteria(content) {
600
+ if (!content || typeof content !== 'string') return content;
601
+
602
+ // Don't add if already has verification
603
+ if (/\bverif|test|validate|expected\s+output/i.test(content)) {
604
+ return content;
605
+ }
606
+
607
+ const verificationSection = `
608
+
609
+ ## Verification
610
+
611
+ After completing this task:
612
+ - [ ] Run relevant tests to verify the change works
613
+ - [ ] Check for regressions in related functionality
614
+ - [ ] Verify expected output matches: [describe expected result]
615
+ `;
616
+
617
+ return content.trim() + verificationSection;
618
+ }
619
+
620
+ /**
621
+ * Add trigger phrase to skill description
622
+ * @param {string} content - SKILL.md content
623
+ * @returns {string} Fixed content
624
+ */
625
+ function fixMissingTriggerPhrase(content) {
626
+ if (!content || typeof content !== 'string') return content;
627
+
628
+ const lines = content.split('\n');
629
+ let inFrontmatter = false;
630
+ let descriptionLineIndex = -1;
631
+
632
+ for (let i = 0; i < lines.length; i++) {
633
+ if (lines[i].trim() === '---') {
634
+ if (!inFrontmatter) {
635
+ inFrontmatter = true;
636
+ } else {
637
+ break;
638
+ }
639
+ } else if (inFrontmatter && lines[i].startsWith('description:')) {
640
+ descriptionLineIndex = i;
641
+ break;
642
+ }
643
+ }
644
+
645
+ if (descriptionLineIndex >= 0) {
646
+ const descLine = lines[descriptionLineIndex];
647
+ // Check if already has trigger phrase
648
+ if (!/use when user asks/i.test(descLine)) {
649
+ // Extract current description
650
+ const match = descLine.match(/^description:[ \t]*(\S.*)$/);
651
+ if (match) {
652
+ const currentDesc = match[1].trim();
653
+ // Add trigger phrase
654
+ lines[descriptionLineIndex] = `description: Use when user asks to ${currentDesc.toLowerCase().replace(/^to\s+/i, '')}`;
655
+ }
656
+ }
657
+ }
658
+
659
+ return lines.join('\n');
660
+ }
661
+
662
+ /**
663
+ * Reduce aggressive emphasis (CAPS, !!)
664
+ * @param {string} content - Prompt content
665
+ * @returns {string} Fixed content
666
+ */
667
+ function fixAggressiveEmphasis(content) {
668
+ if (!content || typeof content !== 'string') return content;
669
+
670
+ let result = content;
671
+
672
+ // Preserve code blocks
673
+ const codeBlocks = [];
674
+ let placeholder = 0;
675
+ result = result.replace(/```[\s\S]*?```/g, (match) => {
676
+ codeBlocks.push(match);
677
+ return `__CODE_BLOCK_${placeholder++}__`;
678
+ });
679
+
680
+ // Acceptable CAPS to preserve
681
+ const acceptableCaps = ['API', 'JSON', 'XML', 'HTML', 'CSS', 'URL', 'HTTP', 'HTTPS', 'SQL', 'CLI', 'SDK', 'JWT', 'UUID', 'REST', 'YAML', 'EOF', 'TODO', 'FIXME', 'NOTE', 'README', 'MCP', 'HIGH', 'MEDIUM', 'LOW'];
682
+
683
+ // Replace aggressive CAPS with normal case (except acceptable ones)
684
+ result = result.replace(/\b[A-Z]{3,}\b/g, (match) => {
685
+ if (acceptableCaps.includes(match)) return match;
686
+ // Convert to sentence case
687
+ return match.charAt(0) + match.slice(1).toLowerCase();
688
+ });
689
+
690
+ // Remove multiple exclamation marks
691
+ result = result.replace(/!{2,}/g, '!');
692
+
693
+ // Restore code blocks
694
+ for (let i = 0; i < codeBlocks.length; i++) {
695
+ result = result.replace(`__CODE_BLOCK_${i}__`, codeBlocks[i]);
696
+ }
697
+
698
+ return result;
699
+ }
700
+
701
+ module.exports = {
702
+ applyFixes,
703
+ fixAdditionalProperties,
704
+ fixRequiredFields,
705
+ fixVersionMismatch,
706
+ fixMissingFrontmatter,
707
+ fixUnrestrictedBash,
708
+ fixMissingRole,
709
+ fixInconsistentHeadings,
710
+ fixVerboseExplanations,
711
+ // New prompt fixes
712
+ fixMissingOutputFormat,
713
+ fixMissingExamples,
714
+ fixMissingXmlStructure,
715
+ fixMissingVerificationCriteria,
716
+ fixMissingTriggerPhrase,
717
+ fixAggressiveEmphasis,
718
+ previewFixes,
719
+ restoreFromBackup,
720
+ cleanupBackups
721
+ };