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,284 @@
1
+ /**
2
+ * Security Patterns
3
+ * Detection patterns for security vulnerabilities in plugins
4
+ *
5
+ * @author Avi Fenesh
6
+ * @license MIT
7
+ */
8
+
9
+ /**
10
+ * Security patterns with certainty levels
11
+ */
12
+ const securityPatterns = {
13
+ /**
14
+ * Unrestricted Bash tool access
15
+ * HIGH certainty - security risk
16
+ */
17
+ unrestricted_bash: {
18
+ id: 'unrestricted_bash',
19
+ category: 'security',
20
+ certainty: 'HIGH',
21
+ autoFix: false,
22
+ description: 'Agent has unrestricted Bash tool access',
23
+ pattern: /^tools:\s*.*\bBash\b(?!\s*\()/m,
24
+ check: (content, filePath) => {
25
+ // Check for Bash without restrictions in agent frontmatter
26
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
27
+ if (!frontmatterMatch) return null;
28
+
29
+ const frontmatter = frontmatterMatch[1];
30
+ const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
31
+ if (!toolsMatch) return null;
32
+
33
+ const tools = toolsMatch[1];
34
+ // Bash without parentheses means unrestricted
35
+ if (/\bBash\b(?!\s*\()/.test(tools)) {
36
+ return {
37
+ issue: 'Unrestricted Bash access',
38
+ fix: 'Add restrictions like Bash(git:*) or Bash(npm:*)',
39
+ line: content.substring(0, frontmatterMatch.index + frontmatterMatch[0].indexOf(toolsMatch[0])).split('\n').length
40
+ };
41
+ }
42
+ return null;
43
+ }
44
+ },
45
+
46
+ /**
47
+ * Command injection via string interpolation
48
+ * HIGH certainty - dangerous pattern
49
+ */
50
+ command_injection: {
51
+ id: 'command_injection',
52
+ category: 'security',
53
+ certainty: 'HIGH',
54
+ autoFix: false,
55
+ description: 'Potential command injection via string interpolation',
56
+ pattern: /\$\{[^}]*\}/,
57
+ check: (content, filePath) => {
58
+ const issues = [];
59
+ const lines = content.split('\n');
60
+
61
+ for (let i = 0; i < lines.length; i++) {
62
+ const line = lines[i];
63
+ // Look for shell commands with interpolation (string checks avoid ReDoS)
64
+ if (/\b(?:exec|spawn|system|shell)\b|`|Bash/i.test(line) && /[(`]/.test(line) && line.includes('${')) {
65
+ issues.push({
66
+ issue: 'Command injection risk via string interpolation',
67
+ fix: 'Validate and escape user input before shell execution',
68
+ line: i + 1
69
+ });
70
+ }
71
+ }
72
+
73
+ return issues.length > 0 ? issues : null;
74
+ }
75
+ },
76
+
77
+ /**
78
+ * Path traversal patterns
79
+ * HIGH certainty - security risk
80
+ */
81
+ path_traversal: {
82
+ id: 'path_traversal',
83
+ category: 'security',
84
+ certainty: 'HIGH',
85
+ autoFix: false,
86
+ description: 'Potential path traversal vulnerability',
87
+ pattern: /\.\.\//,
88
+ check: (content, filePath) => {
89
+ const issues = [];
90
+ const lines = content.split('\n');
91
+
92
+ for (let i = 0; i < lines.length; i++) {
93
+ const line = lines[i];
94
+ // Look for user-controlled paths with ../ (string checks avoid ReDoS)
95
+ if (/\b(?:path|file|dir)\b/i.test(line) && line.includes('$') && line.includes('../')) {
96
+ issues.push({
97
+ issue: 'Path traversal risk - user input may contain ../',
98
+ fix: 'Validate paths and use path.resolve() with base directory check',
99
+ line: i + 1
100
+ });
101
+ }
102
+ }
103
+
104
+ return issues.length > 0 ? issues : null;
105
+ }
106
+ },
107
+
108
+ /**
109
+ * Hardcoded secrets in agent files
110
+ * HIGH certainty - critical
111
+ */
112
+ hardcoded_secrets: {
113
+ id: 'hardcoded_secrets',
114
+ category: 'security',
115
+ certainty: 'HIGH',
116
+ autoFix: false,
117
+ description: 'Potential hardcoded secrets',
118
+ pattern: /(api[_-]?key|secret|token|password|credential)\s*[:=]\s*["'`][^"'`\s]{8,}["'`]/i,
119
+ check: (content, filePath) => {
120
+ const issues = [];
121
+ const lines = content.split('\n');
122
+ const secretPattern = /(api[_-]?key|secret|token|password|credential)\s*[:=]\s*["'`](?!\$\{)(?!\{\{)[^"'`\s]{8,}["'`]/i;
123
+
124
+ for (let i = 0; i < lines.length; i++) {
125
+ const line = lines[i];
126
+ if (secretPattern.test(line)) {
127
+ issues.push({
128
+ issue: 'Potential hardcoded secret',
129
+ fix: 'Use environment variables instead',
130
+ line: i + 1
131
+ });
132
+ }
133
+ }
134
+
135
+ return issues.length > 0 ? issues : null;
136
+ }
137
+ },
138
+
139
+ /**
140
+ * Missing input validation
141
+ * MEDIUM certainty - may be intentional
142
+ */
143
+ missing_input_validation: {
144
+ id: 'missing_input_validation',
145
+ category: 'security',
146
+ certainty: 'MEDIUM',
147
+ autoFix: false,
148
+ description: 'User input used without validation',
149
+ check: (content, filePath) => {
150
+ const issues = [];
151
+ const lines = content.split('\n');
152
+
153
+ for (let i = 0; i < lines.length; i++) {
154
+ const line = lines[i];
155
+ // Look for direct use of ARGUMENTS without validation
156
+ if (/\$ARGUMENTS/.test(line) && !/validate|check|verify|sanitize/.test(lines.slice(Math.max(0, i - 5), i + 1).join('\n').toLowerCase())) {
157
+ issues.push({
158
+ issue: 'User input ($ARGUMENTS) used without apparent validation',
159
+ fix: 'Add input validation before using user-provided arguments',
160
+ line: i + 1
161
+ });
162
+ }
163
+ }
164
+
165
+ return issues.length > 0 ? issues : null;
166
+ }
167
+ },
168
+
169
+ /**
170
+ * Broad file access patterns
171
+ * MEDIUM certainty - may be required
172
+ */
173
+ broad_file_access: {
174
+ id: 'broad_file_access',
175
+ category: 'security',
176
+ certainty: 'MEDIUM',
177
+ autoFix: false,
178
+ description: 'Agent requests broad file system access',
179
+ check: (content, filePath) => {
180
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
181
+ if (!frontmatterMatch) return null;
182
+
183
+ const frontmatter = frontmatterMatch[1];
184
+ const toolsMatch = frontmatter.match(/^tools:[ \t]*(\S.*)?$/m);
185
+ if (!toolsMatch) return null;
186
+
187
+ const tools = toolsMatch[1];
188
+ // Check for Write or Edit without restrictions
189
+ if (/\b(Write|Edit)\b(?!\s*\()/.test(tools)) {
190
+ return {
191
+ issue: 'Broad file write access',
192
+ fix: 'Consider restricting to specific directories',
193
+ line: content.substring(0, frontmatterMatch.index + frontmatterMatch[0].indexOf(toolsMatch[0])).split('\n').length
194
+ };
195
+ }
196
+ return null;
197
+ }
198
+ },
199
+
200
+ /**
201
+ * Unsafe eval patterns
202
+ * HIGH certainty - dangerous
203
+ */
204
+ unsafe_eval: {
205
+ id: 'unsafe_eval',
206
+ category: 'security',
207
+ certainty: 'HIGH',
208
+ autoFix: false,
209
+ description: 'Unsafe eval() or Function() usage',
210
+ pattern: /\b(?:eval|Function)\s*\(/,
211
+ check: (content, filePath) => {
212
+ const issues = [];
213
+ const lines = content.split('\n');
214
+
215
+ for (let i = 0; i < lines.length; i++) {
216
+ const line = lines[i];
217
+ if (/\b(?:eval|Function)\s*\(/.test(line)) {
218
+ issues.push({
219
+ issue: 'Unsafe eval() or Function() usage',
220
+ fix: 'Avoid dynamic code execution - use safer alternatives',
221
+ line: i + 1
222
+ });
223
+ }
224
+ }
225
+
226
+ return issues.length > 0 ? issues : null;
227
+ }
228
+ }
229
+ };
230
+
231
+ /**
232
+ * Get all security patterns
233
+ * @returns {Object} All security patterns
234
+ */
235
+ function getAllPatterns() {
236
+ return securityPatterns;
237
+ }
238
+
239
+ /**
240
+ * Get patterns by certainty level
241
+ * @param {string} certainty - HIGH, MEDIUM, or LOW
242
+ * @returns {Object} Filtered patterns
243
+ */
244
+ function getPatternsByCertainty(certainty) {
245
+ const result = {};
246
+ for (const [name, pattern] of Object.entries(securityPatterns)) {
247
+ if (pattern.certainty === certainty) {
248
+ result[name] = pattern;
249
+ }
250
+ }
251
+ return result;
252
+ }
253
+
254
+ /**
255
+ * Run all security checks on content
256
+ * @param {string} content - File content
257
+ * @param {string} filePath - File path
258
+ * @returns {Array} Array of issues found
259
+ */
260
+ function checkSecurity(content, filePath) {
261
+ const issues = [];
262
+
263
+ for (const [name, pattern] of Object.entries(securityPatterns)) {
264
+ if (pattern.check) {
265
+ const result = pattern.check(content, filePath);
266
+ if (result) {
267
+ if (Array.isArray(result)) {
268
+ issues.push(...result.map(r => ({ ...r, patternId: pattern.id, certainty: pattern.certainty })));
269
+ } else {
270
+ issues.push({ ...result, patternId: pattern.id, certainty: pattern.certainty });
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ return issues;
277
+ }
278
+
279
+ module.exports = {
280
+ securityPatterns,
281
+ getAllPatterns,
282
+ getPatternsByCertainty,
283
+ checkSecurity
284
+ };
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Skill analyzer for /enhance.
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { skillPatterns } = require('./skill-patterns');
8
+ const { parseMarkdownFrontmatter } = require('./agent-analyzer');
9
+
10
+ function analyzeSkill(skillPath) {
11
+ const results = {
12
+ skillName: path.basename(path.dirname(skillPath)),
13
+ skillPath,
14
+ structureIssues: [],
15
+ triggerIssues: []
16
+ };
17
+
18
+ if (!fs.existsSync(skillPath)) {
19
+ results.structureIssues.push({
20
+ issue: 'File not found',
21
+ file: skillPath,
22
+ certainty: 'HIGH',
23
+ patternId: 'file_not_found'
24
+ });
25
+ return results;
26
+ }
27
+
28
+ let content = '';
29
+ try {
30
+ content = fs.readFileSync(skillPath, 'utf8');
31
+ } catch (err) {
32
+ results.structureIssues.push({
33
+ issue: `Failed to read file: ${err.message}`,
34
+ file: skillPath,
35
+ certainty: 'HIGH',
36
+ patternId: 'read_error'
37
+ });
38
+ return results;
39
+ }
40
+
41
+ const missingFm = skillPatterns.missing_frontmatter.check(content);
42
+ if (missingFm) {
43
+ results.structureIssues.push({
44
+ ...missingFm,
45
+ file: skillPath,
46
+ certainty: skillPatterns.missing_frontmatter.certainty,
47
+ patternId: skillPatterns.missing_frontmatter.id
48
+ });
49
+ }
50
+
51
+ const { frontmatter } = parseMarkdownFrontmatter(content);
52
+ const missingName = skillPatterns.missing_name.check(frontmatter);
53
+ if (missingName) {
54
+ results.structureIssues.push({
55
+ ...missingName,
56
+ file: skillPath,
57
+ certainty: skillPatterns.missing_name.certainty,
58
+ patternId: skillPatterns.missing_name.id
59
+ });
60
+ }
61
+
62
+ const missingDescription = skillPatterns.missing_description.check(frontmatter);
63
+ if (missingDescription) {
64
+ results.structureIssues.push({
65
+ ...missingDescription,
66
+ file: skillPath,
67
+ certainty: skillPatterns.missing_description.certainty,
68
+ patternId: skillPatterns.missing_description.id
69
+ });
70
+ }
71
+
72
+ const missingTrigger = skillPatterns.missing_trigger_phrase.check(frontmatter);
73
+ if (missingTrigger) {
74
+ results.triggerIssues.push({
75
+ ...missingTrigger,
76
+ file: skillPath,
77
+ certainty: skillPatterns.missing_trigger_phrase.certainty,
78
+ patternId: skillPatterns.missing_trigger_phrase.id,
79
+ autoFix: skillPatterns.missing_trigger_phrase.autoFix
80
+ });
81
+ }
82
+
83
+ // Check new patterns from Claude Code Best Practices
84
+ if (skillPatterns.side_effect_without_disable) {
85
+ const sideEffect = skillPatterns.side_effect_without_disable.check(frontmatter, content);
86
+ if (sideEffect) {
87
+ results.structureIssues.push({
88
+ ...sideEffect,
89
+ file: skillPath,
90
+ certainty: skillPatterns.side_effect_without_disable.certainty,
91
+ patternId: skillPatterns.side_effect_without_disable.id
92
+ });
93
+ }
94
+ }
95
+
96
+ if (skillPatterns.missing_context_fork) {
97
+ const missingFork = skillPatterns.missing_context_fork.check(frontmatter, content);
98
+ if (missingFork) {
99
+ results.structureIssues.push({
100
+ ...missingFork,
101
+ file: skillPath,
102
+ certainty: skillPatterns.missing_context_fork.certainty,
103
+ patternId: skillPatterns.missing_context_fork.id
104
+ });
105
+ }
106
+ }
107
+
108
+ if (skillPatterns.missing_allowed_tools) {
109
+ const missingTools = skillPatterns.missing_allowed_tools.check(frontmatter);
110
+ if (missingTools) {
111
+ results.structureIssues.push({
112
+ ...missingTools,
113
+ file: skillPath,
114
+ certainty: skillPatterns.missing_allowed_tools.certainty,
115
+ patternId: skillPatterns.missing_allowed_tools.id
116
+ });
117
+ }
118
+ }
119
+
120
+ return results;
121
+ }
122
+
123
+ function analyzeAllSkills(skillsDir) {
124
+ const results = [];
125
+ if (!fs.existsSync(skillsDir)) return results;
126
+
127
+ const skillFiles = [];
128
+ const skipDirs = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'target']);
129
+
130
+ function walk(dir) {
131
+ let entries;
132
+ try {
133
+ entries = fs.readdirSync(dir, { withFileTypes: true });
134
+ } catch (err) {
135
+ return;
136
+ }
137
+
138
+ for (const entry of entries) {
139
+ const fullPath = path.join(dir, entry.name);
140
+ if (entry.isDirectory()) {
141
+ if (!skipDirs.has(entry.name)) {
142
+ walk(fullPath);
143
+ }
144
+ continue;
145
+ }
146
+
147
+ if (entry.isFile() && entry.name === 'SKILL.md') {
148
+ skillFiles.push(fullPath);
149
+ }
150
+ }
151
+ }
152
+
153
+ walk(skillsDir);
154
+
155
+ for (const skillPath of skillFiles) {
156
+ results.push(analyzeSkill(skillPath));
157
+ }
158
+
159
+ return results;
160
+ }
161
+
162
+ function analyze(options = {}) {
163
+ const {
164
+ skill,
165
+ skillsDir = 'plugins/enhance/skills'
166
+ } = options;
167
+
168
+ if (skill) {
169
+ const skillPath = skill.endsWith('SKILL.md')
170
+ ? skill
171
+ : path.join(skillsDir, skill, 'SKILL.md');
172
+ return analyzeSkill(skillPath);
173
+ }
174
+
175
+ return analyzeAllSkills(skillsDir);
176
+ }
177
+
178
+ module.exports = {
179
+ analyzeSkill,
180
+ analyzeAllSkills,
181
+ analyze
182
+ };
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Skill patterns for /enhance.
3
+ */
4
+
5
+ const skillPatterns = {
6
+ missing_frontmatter: {
7
+ id: 'missing_frontmatter',
8
+ certainty: 'HIGH',
9
+ check(content) {
10
+ if (!content || !content.trim().startsWith('---')) {
11
+ return { issue: 'Missing YAML frontmatter in SKILL.md' };
12
+ }
13
+ return null;
14
+ }
15
+ },
16
+ missing_name: {
17
+ id: 'missing_name',
18
+ certainty: 'HIGH',
19
+ check(frontmatter) {
20
+ if (!frontmatter || !frontmatter.name) {
21
+ return { issue: 'Missing name in SKILL.md frontmatter' };
22
+ }
23
+ return null;
24
+ }
25
+ },
26
+ missing_description: {
27
+ id: 'missing_description',
28
+ certainty: 'HIGH',
29
+ check(frontmatter) {
30
+ if (!frontmatter || !frontmatter.description) {
31
+ return { issue: 'Missing description in SKILL.md frontmatter' };
32
+ }
33
+ return null;
34
+ }
35
+ },
36
+ missing_trigger_phrase: {
37
+ id: 'missing_trigger_phrase',
38
+ certainty: 'MEDIUM',
39
+ autoFix: true,
40
+ check(frontmatter) {
41
+ if (!frontmatter || !frontmatter.description) return null;
42
+ if (!/use when user asks/i.test(frontmatter.description)) {
43
+ return { issue: 'Description missing "Use when user asks" trigger phrase' };
44
+ }
45
+ return null;
46
+ }
47
+ },
48
+
49
+ // ============================================
50
+ // PATTERNS FROM CLAUDE CODE BEST PRACTICES
51
+ // Source: https://code.claude.com/docs/en/best-practices
52
+ // ============================================
53
+
54
+ /**
55
+ * Side-effect skill without disable-model-invocation
56
+ * HIGH certainty - skills with side effects should be manual-only
57
+ */
58
+ side_effect_without_disable: {
59
+ id: 'side_effect_without_disable',
60
+ certainty: 'HIGH',
61
+ check(frontmatter, content) {
62
+ if (!frontmatter) return null;
63
+
64
+ // Check if skill has side effects indicators
65
+ const sideEffectPatterns = [
66
+ /\b(?:deploy|ship|push|merge|commit|delete|remove|publish)\b/i,
67
+ /\bgit\s+(?:push|commit|reset)\b/i,
68
+ /\bcreate\s+(?:PR|pull\s+request|issue)\b/i,
69
+ /\bsend\s+(?:email|notification|message)\b/i,
70
+ /\brun\s+(?:migration|deploy)\b/i
71
+ ];
72
+
73
+ const hasSideEffects = sideEffectPatterns.some(p => {
74
+ return p.test(frontmatter.name || '') ||
75
+ p.test(frontmatter.description || '') ||
76
+ (content && p.test(content));
77
+ });
78
+
79
+ if (hasSideEffects && frontmatter['disable-model-invocation'] !== true) {
80
+ return {
81
+ issue: 'Skill with side effects should have disable-model-invocation: true',
82
+ fix: 'Add "disable-model-invocation: true" to frontmatter for manual-only invocation'
83
+ };
84
+ }
85
+ return null;
86
+ }
87
+ },
88
+
89
+ /**
90
+ * Missing context: fork for isolated execution
91
+ * MEDIUM certainty - skills that read many files should fork context
92
+ */
93
+ missing_context_fork: {
94
+ id: 'missing_context_fork',
95
+ certainty: 'MEDIUM',
96
+ check(frontmatter, content) {
97
+ if (!frontmatter) return null;
98
+
99
+ // Check if skill does extensive exploration
100
+ const explorationPatterns = [
101
+ /\b(?:search|explore|analyze|scan)\s+(?:the\s+)?(?:codebase|repo|project)\b/i,
102
+ /\bread\s+(?:all|many|multiple)\s+files\b/i,
103
+ /\b(?:deep|thorough)\s+(?:analysis|review|investigation)\b/i
104
+ ];
105
+
106
+ const doesExploration = explorationPatterns.some(p => {
107
+ return p.test(frontmatter.description || '') ||
108
+ (content && p.test(content));
109
+ });
110
+
111
+ if (doesExploration && frontmatter.context !== 'fork') {
112
+ return {
113
+ issue: 'Exploration skill should use context: fork to keep main context clean',
114
+ fix: 'Add "context: fork" to run in isolated subagent context'
115
+ };
116
+ }
117
+ return null;
118
+ }
119
+ },
120
+
121
+ /**
122
+ * Missing allowed-tools restriction
123
+ * MEDIUM certainty - skills should specify allowed tools
124
+ */
125
+ missing_allowed_tools: {
126
+ id: 'missing_allowed_tools',
127
+ certainty: 'MEDIUM',
128
+ check(frontmatter) {
129
+ if (!frontmatter) return null;
130
+
131
+ // Only flag if skill has context: fork (subagent execution)
132
+ if (frontmatter.context !== 'fork') return null;
133
+
134
+ if (!frontmatter['allowed-tools']) {
135
+ return {
136
+ issue: 'Forked skill missing allowed-tools restriction',
137
+ fix: 'Add "allowed-tools: Read, Grep, Glob" to scope subagent capabilities'
138
+ };
139
+ }
140
+ return null;
141
+ }
142
+ }
143
+ };
144
+
145
+ module.exports = {
146
+ skillPatterns
147
+ };