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,370 @@
1
+ /**
2
+ * Cross-File Semantic Analysis Patterns
3
+ * Detection patterns for multi-file consistency and alignment
4
+ *
5
+ * Cross-platform compatible: Works with Claude Code, OpenCode, and Codex
6
+ *
7
+ * @author Avi Fenesh
8
+ * @license MIT
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { getStateDir, getPlatformName } = require('../platform/state-dir');
14
+
15
+ /**
16
+ * Platform-specific default tools
17
+ * These are used when no tools.json config is found
18
+ */
19
+ const PLATFORM_TOOLS = {
20
+ claude: [
21
+ 'Task', 'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash',
22
+ 'WebFetch', 'WebSearch', 'AskUserQuestion', 'NotebookEdit',
23
+ 'LSP', 'Skill', 'EnterPlanMode', 'ExitPlanMode',
24
+ 'TaskCreate', 'TaskUpdate', 'TaskList', 'TaskGet', 'TaskOutput', 'TaskStop'
25
+ ],
26
+ opencode: [
27
+ 'Task', 'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash',
28
+ 'WebFetch', 'WebSearch', 'AskUser', 'Notebook',
29
+ 'LSP', 'Skill', 'Plan'
30
+ ],
31
+ codex: [
32
+ 'Task', 'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash',
33
+ 'WebFetch', 'Ask', 'Shell'
34
+ ],
35
+ // Superset for unknown platforms
36
+ unknown: [
37
+ 'Task', 'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash',
38
+ 'WebFetch', 'WebSearch', 'AskUserQuestion', 'AskUser', 'Ask',
39
+ 'NotebookEdit', 'Notebook', 'LSP', 'Skill', 'Plan',
40
+ 'EnterPlanMode', 'ExitPlanMode', 'Shell',
41
+ 'TaskCreate', 'TaskUpdate', 'TaskList', 'TaskGet', 'TaskOutput', 'TaskStop'
42
+ ]
43
+ };
44
+
45
+ /** Maximum size for tools.json config file (prevents DoS via large files) */
46
+ const MAX_CONFIG_SIZE = 64 * 1024; // 64KB
47
+
48
+ /**
49
+ * Load tools configuration from state directory or use platform defaults
50
+ * @param {string} [basePath=process.cwd()] - Base path to check
51
+ * @returns {string[]} Array of known tool names
52
+ */
53
+ function loadKnownTools(basePath = process.cwd()) {
54
+ const stateDir = getStateDir(basePath);
55
+ const toolsConfigPath = path.join(basePath, stateDir, 'tools.json');
56
+
57
+ // Try to load from config file (without race condition)
58
+ try {
59
+ const content = fs.readFileSync(toolsConfigPath, 'utf8');
60
+
61
+ // Size limit check
62
+ if (content.length > MAX_CONFIG_SIZE) {
63
+ if (process.env.DEBUG) {
64
+ console.error('[cross-file-patterns] tools.json exceeds size limit, using defaults');
65
+ }
66
+ throw new Error('Config file too large');
67
+ }
68
+
69
+ const config = JSON.parse(content);
70
+
71
+ // Validate config structure
72
+ if (Array.isArray(config.tools)) {
73
+ return config.tools;
74
+ }
75
+ if (config.knownTools && Array.isArray(config.knownTools)) {
76
+ return config.knownTools;
77
+ }
78
+
79
+ if (process.env.DEBUG) {
80
+ console.error('[cross-file-patterns] tools.json missing tools array, using defaults');
81
+ }
82
+ } catch (err) {
83
+ // ENOENT (file not found) is expected, don't log
84
+ // Other errors should be logged for debugging
85
+ if (err.code !== 'ENOENT' && process.env.DEBUG) {
86
+ console.error('[cross-file-patterns] Failed to load tools.json:', err.message);
87
+ }
88
+ }
89
+
90
+ // Fall back to platform-specific defaults
91
+ const platform = getPlatformName(basePath);
92
+ return PLATFORM_TOOLS[platform] || PLATFORM_TOOLS.unknown;
93
+ }
94
+
95
+ /**
96
+ * Cross-file semantic analysis patterns
97
+ * All patterns use MEDIUM certainty since cross-file analysis requires human review
98
+ */
99
+ const crossFilePatterns = {
100
+ /**
101
+ * Tool mentioned in prompt body not in frontmatter tools list
102
+ */
103
+ tool_not_in_allowed_list: {
104
+ id: 'tool_not_in_allowed_list',
105
+ category: 'tool-consistency',
106
+ certainty: 'MEDIUM',
107
+ autoFix: false,
108
+ description: 'Prompt mentions tools not declared in frontmatter',
109
+ check: (data) => {
110
+ const { declaredTools, usedTools, agentName } = data;
111
+ if (!declaredTools || declaredTools.length === 0) return null;
112
+ if (!usedTools || usedTools.length === 0) return null;
113
+
114
+ // Normalize declared tools (handle Bash(git:*) -> Bash)
115
+ const normalizedDeclared = declaredTools.map(t => t.split('(')[0].trim());
116
+
117
+ const undeclared = usedTools.filter(tool =>
118
+ !normalizedDeclared.includes(tool) &&
119
+ !normalizedDeclared.includes('*')
120
+ );
121
+
122
+ if (undeclared.length > 0) {
123
+ return {
124
+ issue: `Agent "${agentName}" uses ${undeclared.join(', ')} but not declared in tools frontmatter`,
125
+ fix: `Add ${undeclared.join(', ')} to tools field or remove usage from prompt`
126
+ };
127
+ }
128
+ return null;
129
+ }
130
+ },
131
+
132
+ /**
133
+ * Workflow references an agent that does not exist
134
+ */
135
+ missing_workflow_agent: {
136
+ id: 'missing_workflow_agent',
137
+ category: 'workflow',
138
+ certainty: 'MEDIUM',
139
+ autoFix: false,
140
+ description: 'Workflow references non-existent agent',
141
+ check: (data) => {
142
+ const { referencedAgent, existingAgents, sourceFile } = data;
143
+ if (!referencedAgent || !existingAgents) return null;
144
+
145
+ // Extract plugin:agent format
146
+ const [plugin, agentName] = referencedAgent.includes(':')
147
+ ? referencedAgent.split(':')
148
+ : [null, referencedAgent];
149
+
150
+ // Check if agent exists
151
+ const exists = existingAgents.some(a => {
152
+ if (plugin) {
153
+ return a.plugin === plugin && a.name === agentName;
154
+ }
155
+ return a.name === agentName;
156
+ });
157
+
158
+ if (!exists) {
159
+ return {
160
+ issue: `Referenced agent "${referencedAgent}" does not exist`,
161
+ fix: `Create agent "${referencedAgent}" or fix the reference in ${sourceFile}`
162
+ };
163
+ }
164
+ return null;
165
+ }
166
+ },
167
+
168
+ /**
169
+ * Workflow phases not fully connected
170
+ */
171
+ incomplete_phase_transition: {
172
+ id: 'incomplete_phase_transition',
173
+ category: 'workflow',
174
+ certainty: 'MEDIUM',
175
+ autoFix: false,
176
+ description: 'Workflow phase transitions are incomplete',
177
+ check: (data) => {
178
+ const { phases, transitions, workflowFile } = data;
179
+ if (!phases || !transitions || phases.length === 0) return null;
180
+
181
+ // Check each phase has a transition (except last)
182
+ const missingTransitions = [];
183
+ for (let i = 0; i < phases.length - 1; i++) {
184
+ const currentPhase = phases[i];
185
+ const hasTransition = transitions.some(t =>
186
+ t.from === currentPhase || t.to === phases[i + 1]
187
+ );
188
+ if (!hasTransition) {
189
+ missingTransitions.push(`${currentPhase} -> ${phases[i + 1]}`);
190
+ }
191
+ }
192
+
193
+ if (missingTransitions.length > 0) {
194
+ return {
195
+ issue: `Missing phase transitions: ${missingTransitions.join(', ')}`,
196
+ fix: `Add transition logic for ${missingTransitions[0]} in ${workflowFile}`
197
+ };
198
+ }
199
+ return null;
200
+ }
201
+ },
202
+
203
+ /**
204
+ * Duplicate instructions across multiple agents
205
+ */
206
+ duplicate_instructions: {
207
+ id: 'duplicate_instructions',
208
+ category: 'consistency',
209
+ certainty: 'MEDIUM',
210
+ autoFix: false,
211
+ description: 'Identical critical instructions across agents',
212
+ check: (data) => {
213
+ const { instruction, files } = data;
214
+ if (!instruction || !files || files.length < 2) return null;
215
+
216
+ return {
217
+ issue: `Duplicate instruction found in ${files.length} files: "${instruction.substring(0, 50)}..."`,
218
+ fix: `Extract shared instruction to a common include or ensure intentional duplication`
219
+ };
220
+ }
221
+ },
222
+
223
+ /**
224
+ * Contradictory rules across agents
225
+ */
226
+ contradictory_rules: {
227
+ id: 'contradictory_rules',
228
+ category: 'consistency',
229
+ certainty: 'MEDIUM',
230
+ autoFix: false,
231
+ description: 'Conflicting rules across agents (always vs never)',
232
+ check: (data) => {
233
+ const { rule1, rule2, file1, file2 } = data;
234
+ if (!rule1 || !rule2) return null;
235
+
236
+ return {
237
+ issue: `Contradictory rules: "${rule1.substring(0, 40)}..." vs "${rule2.substring(0, 40)}..."`,
238
+ fix: `Resolve conflict between ${file1} and ${file2}`
239
+ };
240
+ }
241
+ },
242
+
243
+ /**
244
+ * Prompt not referenced by any workflow or skill
245
+ */
246
+ orphaned_prompt: {
247
+ id: 'orphaned_prompt',
248
+ category: 'consistency',
249
+ certainty: 'MEDIUM',
250
+ autoFix: false,
251
+ description: 'Agent/prompt not referenced anywhere',
252
+ check: (data) => {
253
+ const { promptFile, referencedBy } = data;
254
+ if (!promptFile) return null;
255
+
256
+ if (!referencedBy || referencedBy.length === 0) {
257
+ return {
258
+ issue: `Orphaned prompt: ${promptFile} is not referenced by any workflow or skill`,
259
+ fix: `Add reference to ${promptFile} or remove if unused`
260
+ };
261
+ }
262
+ return null;
263
+ }
264
+ },
265
+
266
+ /**
267
+ * Skill allowed-tools differs from what prompt uses
268
+ */
269
+ skill_tool_mismatch: {
270
+ id: 'skill_tool_mismatch',
271
+ category: 'skill-alignment',
272
+ certainty: 'MEDIUM',
273
+ autoFix: false,
274
+ description: 'Skill allowed-tools differs from prompt tool usage',
275
+ check: (data) => {
276
+ const { skillName, skillAllowedTools, promptUsedTools } = data;
277
+ if (!skillAllowedTools || !promptUsedTools) return null;
278
+
279
+ // Normalize skill tools
280
+ const normalizedSkill = skillAllowedTools.map(t => t.split('(')[0].trim());
281
+
282
+ const mismatches = promptUsedTools.filter(tool =>
283
+ !normalizedSkill.includes(tool) &&
284
+ !normalizedSkill.includes('*')
285
+ );
286
+
287
+ if (mismatches.length > 0) {
288
+ return {
289
+ issue: `Skill "${skillName}" prompt uses ${mismatches.join(', ')} not in allowed-tools`,
290
+ fix: `Add ${mismatches.join(', ')} to skill allowed-tools or update prompt`
291
+ };
292
+ }
293
+ return null;
294
+ }
295
+ },
296
+
297
+ /**
298
+ * Skill description does not match actual behavior
299
+ */
300
+ skill_description_mismatch: {
301
+ id: 'skill_description_mismatch',
302
+ category: 'skill-alignment',
303
+ certainty: 'MEDIUM',
304
+ autoFix: false,
305
+ description: 'Skill description mentions capabilities not found in body',
306
+ check: (data) => {
307
+ const { skillName, description, bodyCapabilities, descriptionCapabilities } = data;
308
+ if (!description || !bodyCapabilities) return null;
309
+
310
+ const missingInBody = descriptionCapabilities.filter(cap =>
311
+ !bodyCapabilities.some(bc => bc.toLowerCase().includes(cap.toLowerCase()))
312
+ );
313
+
314
+ if (missingInBody.length > 0) {
315
+ return {
316
+ issue: `Skill "${skillName}" description mentions "${missingInBody[0]}" not found in body`,
317
+ fix: `Update description to match actual capabilities or add missing functionality`
318
+ };
319
+ }
320
+ return null;
321
+ }
322
+ }
323
+ };
324
+
325
+ /**
326
+ * Get all cross-file patterns
327
+ * @returns {Object} All patterns
328
+ */
329
+ function getAllPatterns() {
330
+ return crossFilePatterns;
331
+ }
332
+
333
+ /**
334
+ * Get patterns by category
335
+ * @param {string} category - tool-consistency, workflow, consistency, skill-alignment
336
+ * @returns {Object} Filtered patterns
337
+ */
338
+ function getPatternsByCategory(category) {
339
+ const result = {};
340
+ for (const [name, pattern] of Object.entries(crossFilePatterns)) {
341
+ if (pattern.category === category) {
342
+ result[name] = pattern;
343
+ }
344
+ }
345
+ return result;
346
+ }
347
+
348
+ /**
349
+ * Get patterns by certainty
350
+ * @param {string} certainty - HIGH, MEDIUM, LOW
351
+ * @returns {Object} Filtered patterns
352
+ */
353
+ function getPatternsByCertainty(certainty) {
354
+ const result = {};
355
+ for (const [name, pattern] of Object.entries(crossFilePatterns)) {
356
+ if (pattern.certainty === certainty) {
357
+ result[name] = pattern;
358
+ }
359
+ }
360
+ return result;
361
+ }
362
+
363
+ module.exports = {
364
+ PLATFORM_TOOLS,
365
+ loadKnownTools,
366
+ crossFilePatterns,
367
+ getAllPatterns,
368
+ getPatternsByCategory,
369
+ getPatternsByCertainty
370
+ };
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Documentation Analyzer
3
+ * @author Avi Fenesh
4
+ * @license MIT
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const { getPatternsForMode, estimateTokens } = require('./docs-patterns');
10
+
11
+ function analyzeDoc(docPath, options = {}) {
12
+ const { mode = 'both', verbose = false, existingFiles = [] } = options;
13
+
14
+ const results = {
15
+ docName: path.basename(docPath, '.md'),
16
+ docPath,
17
+ mode,
18
+ tokenCount: 0,
19
+ linkIssues: [],
20
+ structureIssues: [],
21
+ codeIssues: [],
22
+ efficiencyIssues: [],
23
+ ragIssues: [],
24
+ balanceIssues: []
25
+ };
26
+
27
+ // Read file
28
+ if (!fs.existsSync(docPath)) {
29
+ results.structureIssues.push({
30
+ issue: 'File not found',
31
+ file: docPath,
32
+ certainty: 'HIGH',
33
+ patternId: 'file_not_found'
34
+ });
35
+ return results;
36
+ }
37
+
38
+ let content;
39
+ try {
40
+ content = fs.readFileSync(docPath, 'utf8');
41
+ } catch (err) {
42
+ results.structureIssues.push({
43
+ issue: `Failed to read file: ${err.message}`,
44
+ file: docPath,
45
+ certainty: 'HIGH',
46
+ patternId: 'read_error'
47
+ });
48
+ return results;
49
+ }
50
+
51
+ // Calculate token count
52
+ results.tokenCount = estimateTokens(content);
53
+
54
+ // Get patterns applicable to this mode
55
+ const patterns = getPatternsForMode(mode);
56
+
57
+ // Context for pattern checks
58
+ const context = { existingFiles };
59
+
60
+ // Run each pattern check
61
+ for (const [patternName, pattern] of Object.entries(patterns)) {
62
+ // Skip LOW certainty unless verbose
63
+ if (pattern.certainty === 'LOW' && !verbose) {
64
+ continue;
65
+ }
66
+
67
+ // Run the check
68
+ const result = pattern.check(content, context);
69
+
70
+ if (result) {
71
+ const issue = {
72
+ ...result,
73
+ file: docPath,
74
+ certainty: pattern.certainty,
75
+ patternId: pattern.id,
76
+ autoFix: pattern.autoFix
77
+ };
78
+
79
+ // Route to appropriate issue category
80
+ switch (pattern.category) {
81
+ case 'link':
82
+ results.linkIssues.push(issue);
83
+ break;
84
+ case 'structure':
85
+ results.structureIssues.push(issue);
86
+ break;
87
+ case 'code':
88
+ results.codeIssues.push(issue);
89
+ break;
90
+ case 'efficiency':
91
+ results.efficiencyIssues.push(issue);
92
+ break;
93
+ case 'rag':
94
+ results.ragIssues.push(issue);
95
+ break;
96
+ case 'balance':
97
+ results.balanceIssues.push(issue);
98
+ break;
99
+ default:
100
+ results.structureIssues.push(issue);
101
+ }
102
+ }
103
+ }
104
+
105
+ return results;
106
+ }
107
+
108
+ function analyzeAllDocs(docsDir, options = {}) {
109
+ const { recursive = true, ...analyzeOptions } = options;
110
+ const results = [];
111
+
112
+ if (!fs.existsSync(docsDir)) {
113
+ return results;
114
+ }
115
+
116
+ // Collect all markdown files
117
+ const mdFiles = [];
118
+
119
+ function findMdFiles(dir) {
120
+ let entries;
121
+ try {
122
+ entries = fs.readdirSync(dir, { withFileTypes: true });
123
+ } catch (err) {
124
+ return;
125
+ }
126
+
127
+ for (const entry of entries) {
128
+ const fullPath = path.join(dir, entry.name);
129
+
130
+ if (entry.isDirectory() && recursive) {
131
+ // Skip common non-doc directories
132
+ if (!['node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
133
+ findMdFiles(fullPath);
134
+ }
135
+ } else if (entry.isFile() && entry.name.endsWith('.md')) {
136
+ // Skip README files in nested directories for agent-docs mode
137
+ if (options.mode === 'ai' && entry.name === 'README.md') {
138
+ continue;
139
+ }
140
+ mdFiles.push(fullPath);
141
+ }
142
+ }
143
+ }
144
+
145
+ findMdFiles(docsDir);
146
+
147
+ // Get relative paths for link validation
148
+ const existingFiles = mdFiles.map(f => path.relative(docsDir, f).replace(/\\/g, '/'));
149
+
150
+ // Analyze each file
151
+ for (const mdFile of mdFiles) {
152
+ const result = analyzeDoc(mdFile, { ...analyzeOptions, existingFiles });
153
+ results.push(result);
154
+ }
155
+
156
+ return results;
157
+ }
158
+
159
+ function analyze(options = {}) {
160
+ const {
161
+ doc,
162
+ docsDir = 'docs',
163
+ mode = 'both',
164
+ verbose = false
165
+ } = options;
166
+
167
+ if (doc) {
168
+ // Check if doc is a directory or file
169
+ try {
170
+ const stats = fs.statSync(doc);
171
+ if (stats.isDirectory()) {
172
+ // Analyze all docs in directory
173
+ return analyzeAllDocs(doc, { mode, verbose });
174
+ } else {
175
+ // Analyze single doc
176
+ return analyzeDoc(doc, { mode, verbose });
177
+ }
178
+ } catch (err) {
179
+ // If file doesn't exist, let analyzeDoc handle the error
180
+ return analyzeDoc(doc, { mode, verbose });
181
+ }
182
+ } else {
183
+ // Analyze all docs in directory
184
+ return analyzeAllDocs(docsDir, { mode, verbose });
185
+ }
186
+ }
187
+
188
+ function applyFixes(results, options = {}) {
189
+ // Collect all issues
190
+ let allIssues = [];
191
+
192
+ if (Array.isArray(results)) {
193
+ for (const r of results) {
194
+ allIssues.push(...(r.linkIssues || []));
195
+ allIssues.push(...(r.structureIssues || []));
196
+ allIssues.push(...(r.codeIssues || []));
197
+ allIssues.push(...(r.efficiencyIssues || []));
198
+ allIssues.push(...(r.ragIssues || []));
199
+ allIssues.push(...(r.balanceIssues || []));
200
+ }
201
+ } else {
202
+ allIssues.push(...(results.linkIssues || []));
203
+ allIssues.push(...(results.structureIssues || []));
204
+ allIssues.push(...(results.codeIssues || []));
205
+ allIssues.push(...(results.efficiencyIssues || []));
206
+ allIssues.push(...(results.ragIssues || []));
207
+ allIssues.push(...(results.balanceIssues || []));
208
+ }
209
+
210
+ // Filter to auto-fixable docs issues
211
+ const docsFixablePatternIds = [
212
+ 'inconsistent_heading_levels',
213
+ 'verbose_explanations'
214
+ ];
215
+
216
+ const fixableIssues = allIssues.filter(i =>
217
+ i.certainty === 'HIGH' &&
218
+ i.autoFix &&
219
+ docsFixablePatternIds.includes(i.patternId)
220
+ );
221
+
222
+ // Apply fixes using the fixer module's pattern
223
+ return applyDocsFixes(fixableIssues, options);
224
+ }
225
+
226
+ function applyDocsFixes(issues, options = {}) {
227
+ const { dryRun = false, backup = true } = options;
228
+ const fixer = require('./fixer');
229
+
230
+ const results = {
231
+ applied: [],
232
+ skipped: [],
233
+ errors: []
234
+ };
235
+
236
+ // Group by file
237
+ const byFile = new Map();
238
+ for (const issue of issues) {
239
+ const fp = issue.file;
240
+ if (!byFile.has(fp)) {
241
+ byFile.set(fp, []);
242
+ }
243
+ byFile.get(fp).push(issue);
244
+ }
245
+
246
+ // Process each file
247
+ for (const [filePath, fileIssues] of byFile) {
248
+ try {
249
+ if (!fs.existsSync(filePath)) {
250
+ results.errors.push({ filePath, error: 'File not found' });
251
+ continue;
252
+ }
253
+
254
+ let content = fs.readFileSync(filePath, 'utf8');
255
+ const appliedToFile = [];
256
+
257
+ for (const issue of fileIssues) {
258
+ try {
259
+ if (issue.patternId === 'inconsistent_heading_levels') {
260
+ content = fixer.fixInconsistentHeadings(content);
261
+ appliedToFile.push({
262
+ issue: issue.issue,
263
+ fix: 'Fixed heading levels',
264
+ filePath
265
+ });
266
+ } else if (issue.patternId === 'verbose_explanations') {
267
+ content = fixer.fixVerboseExplanations(content);
268
+ appliedToFile.push({
269
+ issue: issue.issue,
270
+ fix: 'Simplified verbose phrases',
271
+ filePath
272
+ });
273
+ }
274
+ } catch (err) {
275
+ results.errors.push({
276
+ issue: issue.issue,
277
+ filePath,
278
+ error: err.message
279
+ });
280
+ }
281
+ }
282
+
283
+ // Write changes
284
+ if (!dryRun && appliedToFile.length > 0) {
285
+ if (backup) {
286
+ fs.writeFileSync(`${filePath}.backup`, fs.readFileSync(filePath, 'utf8'), 'utf8');
287
+ }
288
+ fs.writeFileSync(filePath, content, 'utf8');
289
+ }
290
+
291
+ results.applied.push(...appliedToFile);
292
+
293
+ } catch (err) {
294
+ results.errors.push({
295
+ filePath,
296
+ error: err.message
297
+ });
298
+ }
299
+ }
300
+
301
+ return results;
302
+ }
303
+
304
+ function generateReport(results, options = {}) {
305
+ const reporter = require('./reporter');
306
+
307
+ if (Array.isArray(results)) {
308
+ return reporter.generateDocsSummaryReport(results, options);
309
+ } else {
310
+ return reporter.generateDocsReport(results, options);
311
+ }
312
+ }
313
+
314
+ const fixer = require('./fixer');
315
+
316
+ module.exports = {
317
+ analyzeDoc,
318
+ analyzeAllDocs,
319
+ analyze,
320
+ applyFixes,
321
+ applyDocsFixes,
322
+ fixInconsistentHeadings: fixer.fixInconsistentHeadings,
323
+ fixVerboseExplanations: fixer.fixVerboseExplanations,
324
+ generateReport
325
+ };