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,107 @@
1
+ /**
2
+ * Command Frontmatter Type Definitions
3
+ * Defines the structure of YAML frontmatter in command markdown files
4
+ *
5
+ * @module lib/types/command-frontmatter
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Command argument definition
12
+ */
13
+ export interface CommandArgument {
14
+ /** Argument name */
15
+ name: string;
16
+ /** Argument description */
17
+ description: string;
18
+ /** Whether argument is required */
19
+ required?: boolean;
20
+ /** Default value if not provided */
21
+ default?: string | number | boolean;
22
+ /** Allowed values (enum) */
23
+ enum?: string[];
24
+ }
25
+
26
+ /**
27
+ * Command frontmatter structure
28
+ * YAML metadata at the top of command markdown files
29
+ */
30
+ export interface CommandFrontmatter {
31
+ /** Command name (should match filename without extension) */
32
+ command: string;
33
+
34
+ /** Short description shown in help */
35
+ description: string;
36
+
37
+ /** Argument hint shown in autocomplete (e.g., "[options]", "<file>") */
38
+ 'argument-hint'?: string;
39
+
40
+ /** Detailed usage examples */
41
+ usage?: string[];
42
+
43
+ /** Command arguments definition */
44
+ arguments?: CommandArgument[];
45
+
46
+ /** Command aliases (alternative names) */
47
+ aliases?: string[];
48
+
49
+ /** Command category for grouping */
50
+ category?: string;
51
+
52
+ /** Whether command requires git repository */
53
+ requiresGit?: boolean;
54
+
55
+ /** Whether command requires network access */
56
+ requiresNetwork?: boolean;
57
+
58
+ /** Preferred model for this command (sonnet, opus, haiku) */
59
+ model?: 'sonnet' | 'opus' | 'haiku';
60
+
61
+ /** Maximum number of turns for multi-turn commands */
62
+ maxTurns?: number;
63
+
64
+ /** Tags for searchability */
65
+ tags?: string[];
66
+ }
67
+
68
+ /**
69
+ * Type guard to check if an object is valid CommandFrontmatter
70
+ */
71
+ export function isCommandFrontmatter(obj: unknown): obj is CommandFrontmatter {
72
+ if (typeof obj !== 'object' || obj === null) return false;
73
+ const fm = obj as Partial<CommandFrontmatter>;
74
+
75
+ return (
76
+ typeof fm.command === 'string' &&
77
+ fm.command.length > 0 &&
78
+ typeof fm.description === 'string' &&
79
+ fm.description.length > 0
80
+ );
81
+ }
82
+
83
+ /**
84
+ * Validates command frontmatter
85
+ * @throws {Error} If frontmatter is invalid
86
+ */
87
+ export function validateCommandFrontmatter(
88
+ frontmatter: unknown
89
+ ): asserts frontmatter is CommandFrontmatter {
90
+ if (!isCommandFrontmatter(frontmatter)) {
91
+ throw new Error('Invalid command frontmatter: missing required fields');
92
+ }
93
+
94
+ // Additional validations
95
+ if (frontmatter.arguments && !Array.isArray(frontmatter.arguments)) {
96
+ throw new Error('Invalid command frontmatter: arguments must be an array');
97
+ }
98
+
99
+ if (frontmatter.model && !['sonnet', 'opus', 'haiku'].includes(frontmatter.model)) {
100
+ throw new Error('Invalid command frontmatter: model must be sonnet, opus, or haiku');
101
+ }
102
+
103
+ if (frontmatter.maxTurns !== undefined &&
104
+ (typeof frontmatter.maxTurns !== 'number' || frontmatter.maxTurns < 1)) {
105
+ throw new Error('Invalid command frontmatter: maxTurns must be a positive number');
106
+ }
107
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Hook Frontmatter Type Definitions
3
+ * Defines the structure of YAML frontmatter in hook markdown files
4
+ *
5
+ * @module lib/types/hook-frontmatter
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Hook event types
12
+ */
13
+ export type HookEvent =
14
+ | 'PreToolUse'
15
+ | 'PostToolUse'
16
+ | 'Stop'
17
+ | 'SubagentStop'
18
+ | 'SessionStart'
19
+ | 'SessionEnd'
20
+ | 'UserPromptSubmit'
21
+ | 'PreCompact'
22
+ | 'Notification';
23
+
24
+ /**
25
+ * Hook frontmatter structure
26
+ * YAML metadata at the top of hook markdown files
27
+ */
28
+ export interface HookFrontmatter {
29
+ /** Hook unique identifier (kebab-case) */
30
+ hook: string;
31
+
32
+ /** Event that triggers this hook */
33
+ event: HookEvent;
34
+
35
+ /** Short description of hook purpose */
36
+ description: string;
37
+
38
+ /** Tool name this hook applies to (for PreToolUse/PostToolUse) */
39
+ tool?: string;
40
+
41
+ /** Hook priority (higher = runs first, default: 0) */
42
+ priority?: number;
43
+
44
+ /** Whether hook is enabled by default */
45
+ enabled?: boolean;
46
+
47
+ /** Hook category for organization */
48
+ category?: string;
49
+
50
+ /** Tags for searchability */
51
+ tags?: string[];
52
+
53
+ /** Related hooks */
54
+ related?: string[];
55
+ }
56
+
57
+ /**
58
+ * Type guard to check if an object is valid HookFrontmatter
59
+ */
60
+ export function isHookFrontmatter(obj: unknown): obj is HookFrontmatter {
61
+ if (typeof obj !== 'object' || obj === null) return false;
62
+ const fm = obj as Partial<HookFrontmatter>;
63
+
64
+ const validEvents: HookEvent[] = [
65
+ 'PreToolUse',
66
+ 'PostToolUse',
67
+ 'Stop',
68
+ 'SubagentStop',
69
+ 'SessionStart',
70
+ 'SessionEnd',
71
+ 'UserPromptSubmit',
72
+ 'PreCompact',
73
+ 'Notification'
74
+ ];
75
+
76
+ return (
77
+ typeof fm.hook === 'string' &&
78
+ fm.hook.length > 0 &&
79
+ typeof fm.event === 'string' &&
80
+ validEvents.includes(fm.event as HookEvent) &&
81
+ typeof fm.description === 'string' &&
82
+ fm.description.length > 0
83
+ );
84
+ }
85
+
86
+ /**
87
+ * Validates hook frontmatter
88
+ * @throws {Error} If frontmatter is invalid
89
+ */
90
+ export function validateHookFrontmatter(
91
+ frontmatter: unknown
92
+ ): asserts frontmatter is HookFrontmatter {
93
+ if (!isHookFrontmatter(frontmatter)) {
94
+ throw new Error('Invalid hook frontmatter: missing required fields or invalid event type');
95
+ }
96
+
97
+ // Tool-specific hooks must specify tool
98
+ if ((frontmatter.event === 'PreToolUse' || frontmatter.event === 'PostToolUse') &&
99
+ !frontmatter.tool) {
100
+ throw new Error('Invalid hook frontmatter: PreToolUse and PostToolUse hooks must specify tool');
101
+ }
102
+
103
+ if (frontmatter.priority !== undefined &&
104
+ (typeof frontmatter.priority !== 'number' || !Number.isInteger(frontmatter.priority))) {
105
+ throw new Error('Invalid hook frontmatter: priority must be an integer');
106
+ }
107
+
108
+ if (frontmatter.tags && !Array.isArray(frontmatter.tags)) {
109
+ throw new Error('Invalid hook frontmatter: tags must be an array');
110
+ }
111
+
112
+ if (frontmatter.related && !Array.isArray(frontmatter.related)) {
113
+ throw new Error('Invalid hook frontmatter: related must be an array');
114
+ }
115
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Plugin Interface Type Definitions
3
+ * Centralized type definitions for all plugin components
4
+ *
5
+ * @module lib/types
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ // Re-export all types
11
+ export * from './plugin-manifest';
12
+ export * from './command-frontmatter';
13
+ export * from './agent-frontmatter';
14
+ export * from './skill-frontmatter';
15
+ export * from './hook-frontmatter';
16
+
17
+ /**
18
+ * Plugin component types union
19
+ */
20
+ export type PluginComponentType = 'command' | 'agent' | 'skill' | 'hook';
21
+
22
+ /**
23
+ * Plugin directory structure
24
+ */
25
+ export interface PluginStructure {
26
+ /** Plugin root directory */
27
+ root: string;
28
+
29
+ /** Plugin manifest (plugin.json) */
30
+ manifest: string;
31
+
32
+ /** Commands directory */
33
+ commands?: string;
34
+
35
+ /** Agents directory */
36
+ agents?: string;
37
+
38
+ /** Skills directory */
39
+ skills?: string;
40
+
41
+ /** Hooks directory */
42
+ hooks?: string;
43
+
44
+ /** Shared library directory */
45
+ lib?: string;
46
+
47
+ /** Tests directory */
48
+ tests?: string;
49
+ }
50
+
51
+ /**
52
+ * Plugin validation result
53
+ */
54
+ export interface PluginValidationResult {
55
+ /** Whether plugin is valid */
56
+ valid: boolean;
57
+
58
+ /** Validation errors (if any) */
59
+ errors: string[];
60
+
61
+ /** Validation warnings (if any) */
62
+ warnings: string[];
63
+
64
+ /** Detected components */
65
+ components: {
66
+ commands: number;
67
+ agents: number;
68
+ skills: number;
69
+ hooks: number;
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Standard plugin directory structure
75
+ */
76
+ export const PLUGIN_STRUCTURE: Readonly<Record<string, string>> = {
77
+ MANIFEST: '.claude-plugin/plugin.json',
78
+ COMMANDS: 'commands',
79
+ AGENTS: 'agents',
80
+ SKILLS: 'skills',
81
+ HOOKS: 'hooks',
82
+ LIB: 'lib',
83
+ TESTS: 'tests'
84
+ } as const;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Plugin Manifest Type Definitions
3
+ * Defines the structure of plugin.json files
4
+ *
5
+ * @module lib/types/plugin-manifest
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Author information for plugin manifest
12
+ */
13
+ export interface PluginAuthor {
14
+ /** Author's full name */
15
+ name: string;
16
+ /** Author's email address (optional) */
17
+ email?: string;
18
+ /** Author's website or GitHub profile URL (optional) */
19
+ url?: string;
20
+ }
21
+
22
+ /**
23
+ * Plugin manifest structure
24
+ * Required fields for all Claude Code plugins
25
+ */
26
+ export interface PluginManifest {
27
+ /** Unique plugin identifier (kebab-case, lowercase) */
28
+ name: string;
29
+
30
+ /** Semantic version (MAJOR.MINOR.PATCH) */
31
+ version: string;
32
+
33
+ /** Short description of plugin functionality */
34
+ description: string;
35
+
36
+ /** Author information */
37
+ author: PluginAuthor;
38
+
39
+ /** Plugin homepage URL (optional) */
40
+ homepage?: string;
41
+
42
+ /** Repository URL (optional) */
43
+ repository?: string;
44
+
45
+ /** License identifier (SPDX format, e.g., "MIT", "Apache-2.0") */
46
+ license: string;
47
+
48
+ /** Search keywords for discoverability (optional) */
49
+ keywords?: string[];
50
+
51
+ /** Minimum Claude Code version required (optional) */
52
+ minClaudeVersion?: string;
53
+
54
+ /** Plugin dependencies (optional) */
55
+ dependencies?: {
56
+ [pluginName: string]: string; // version constraint
57
+ };
58
+
59
+ /** Plugin configuration schema (optional) */
60
+ config?: {
61
+ [key: string]: unknown;
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Type guard to check if an object is a valid PluginManifest
67
+ */
68
+ export function isPluginManifest(obj: unknown): obj is PluginManifest {
69
+ if (typeof obj !== 'object' || obj === null) return false;
70
+ const manifest = obj as Partial<PluginManifest>;
71
+
72
+ return (
73
+ typeof manifest.name === 'string' &&
74
+ /^[a-z0-9-]+$/.test(manifest.name) &&
75
+ typeof manifest.version === 'string' &&
76
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(manifest.version) &&
77
+ typeof manifest.description === 'string' &&
78
+ typeof manifest.author === 'object' &&
79
+ manifest.author !== null &&
80
+ typeof manifest.author.name === 'string' &&
81
+ typeof manifest.license === 'string'
82
+ );
83
+ }
84
+
85
+ /**
86
+ * Validates a plugin manifest against the schema
87
+ * @throws {Error} If manifest is invalid
88
+ */
89
+ export function validatePluginManifest(manifest: unknown): asserts manifest is PluginManifest {
90
+ if (!isPluginManifest(manifest)) {
91
+ throw new Error('Invalid plugin manifest: missing required fields or invalid format');
92
+ }
93
+
94
+ // Additional validations
95
+ if (manifest.keywords && !Array.isArray(manifest.keywords)) {
96
+ throw new Error('Invalid plugin manifest: keywords must be an array');
97
+ }
98
+
99
+ if (manifest.dependencies && typeof manifest.dependencies !== 'object') {
100
+ throw new Error('Invalid plugin manifest: dependencies must be an object');
101
+ }
102
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Skill Frontmatter Type Definitions
3
+ * Defines the structure of YAML frontmatter in skill markdown files
4
+ *
5
+ * @module lib/types/skill-frontmatter
6
+ * @author Avi Fenesh
7
+ * @license MIT
8
+ */
9
+
10
+ /**
11
+ * Skill frontmatter structure
12
+ * YAML metadata at the top of skill markdown files
13
+ */
14
+ export interface SkillFrontmatter {
15
+ /** Skill unique identifier (kebab-case) */
16
+ skill: string;
17
+
18
+ /** Short description of skill purpose */
19
+ description: string;
20
+
21
+ /** Skill category for organization */
22
+ category?: string;
23
+
24
+ /** When this skill should be invoked (triggering conditions) */
25
+ 'when-to-use'?: string[];
26
+
27
+ /** Example usage scenarios */
28
+ examples?: string[];
29
+
30
+ /** Preferred model for this skill (sonnet, opus, haiku) */
31
+ model?: 'sonnet' | 'opus' | 'haiku';
32
+
33
+ /** Whether skill requires user approval before running */
34
+ requiresApproval?: boolean;
35
+
36
+ /** Tags for searchability */
37
+ tags?: string[];
38
+
39
+ /** Related commands or skills */
40
+ related?: string[];
41
+ }
42
+
43
+ /**
44
+ * Type guard to check if an object is valid SkillFrontmatter
45
+ */
46
+ export function isSkillFrontmatter(obj: unknown): obj is SkillFrontmatter {
47
+ if (typeof obj !== 'object' || obj === null) return false;
48
+ const fm = obj as Partial<SkillFrontmatter>;
49
+
50
+ return (
51
+ typeof fm.skill === 'string' &&
52
+ fm.skill.length > 0 &&
53
+ typeof fm.description === 'string' &&
54
+ fm.description.length > 0
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Validates skill frontmatter
60
+ * @throws {Error} If frontmatter is invalid
61
+ */
62
+ export function validateSkillFrontmatter(
63
+ frontmatter: unknown
64
+ ): asserts frontmatter is SkillFrontmatter {
65
+ if (!isSkillFrontmatter(frontmatter)) {
66
+ throw new Error('Invalid skill frontmatter: missing required fields');
67
+ }
68
+
69
+ // Additional validations
70
+ if (frontmatter.model && !['sonnet', 'opus', 'haiku'].includes(frontmatter.model)) {
71
+ throw new Error('Invalid skill frontmatter: model must be sonnet, opus, or haiku');
72
+ }
73
+
74
+ if (frontmatter['when-to-use'] && !Array.isArray(frontmatter['when-to-use'])) {
75
+ throw new Error('Invalid skill frontmatter: when-to-use must be an array');
76
+ }
77
+
78
+ if (frontmatter.examples && !Array.isArray(frontmatter.examples)) {
79
+ throw new Error('Invalid skill frontmatter: examples must be an array');
80
+ }
81
+
82
+ if (frontmatter.tags && !Array.isArray(frontmatter.tags)) {
83
+ throw new Error('Invalid skill frontmatter: tags must be an array');
84
+ }
85
+
86
+ if (frontmatter.related && !Array.isArray(frontmatter.related)) {
87
+ throw new Error('Invalid skill frontmatter: related must be an array');
88
+ }
89
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Atomic File Write Utility
3
+ *
4
+ * Provides crash-safe file writes using the write-to-temp-then-rename pattern.
5
+ * Prevents data corruption from partial writes during concurrent operations.
6
+ *
7
+ * @module utils/atomic-write
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const crypto = require('crypto');
13
+
14
+ /**
15
+ * Generate a unique temporary filename
16
+ * @param {string} targetPath - Target file path
17
+ * @returns {string} Temporary file path
18
+ */
19
+ function getTempPath(targetPath) {
20
+ const dir = path.dirname(targetPath);
21
+ const basename = path.basename(targetPath);
22
+ const randomSuffix = crypto.randomBytes(6).toString('hex');
23
+ return path.join(dir, `.${basename}.${randomSuffix}.tmp`);
24
+ }
25
+
26
+ /**
27
+ * Write file atomically using write-to-temp-then-rename pattern
28
+ *
29
+ * This ensures:
30
+ * - File is never partially written (atomic rename)
31
+ * - Concurrent reads see either old or new content, never partial
32
+ * - Crash-safe: interrupted writes don't corrupt existing file
33
+ *
34
+ * @param {string} filePath - Target file path
35
+ * @param {string} content - Content to write
36
+ * @param {Object} options - Options
37
+ * @param {string} options.encoding - File encoding (default: 'utf8')
38
+ * @param {number} options.mode - File mode (default: 0o644)
39
+ * @returns {boolean} True on success
40
+ * @throws {Error} On write or rename failure
41
+ */
42
+ function writeFileAtomic(filePath, content, options = {}) {
43
+ const { encoding = 'utf8', mode = 0o644 } = options;
44
+
45
+ // Ensure directory exists
46
+ const dir = path.dirname(filePath);
47
+ if (!fs.existsSync(dir)) {
48
+ fs.mkdirSync(dir, { recursive: true });
49
+ }
50
+
51
+ const tempPath = getTempPath(filePath);
52
+
53
+ try {
54
+ // Write to temp file
55
+ fs.writeFileSync(tempPath, content, { encoding, mode });
56
+
57
+ // Atomic rename (overwrites existing file)
58
+ fs.renameSync(tempPath, filePath);
59
+
60
+ return true;
61
+ } catch (error) {
62
+ // Cleanup temp file on failure
63
+ try {
64
+ if (fs.existsSync(tempPath)) {
65
+ fs.unlinkSync(tempPath);
66
+ }
67
+ } catch {
68
+ // Ignore cleanup errors
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Write JSON file atomically
76
+ *
77
+ * @param {string} filePath - Target file path
78
+ * @param {*} data - Data to serialize as JSON
79
+ * @param {Object} options - Options
80
+ * @param {number} options.indent - JSON indentation (default: 2)
81
+ * @param {string} options.encoding - File encoding (default: 'utf8')
82
+ * @returns {boolean} True on success
83
+ */
84
+ function writeJsonAtomic(filePath, data, options = {}) {
85
+ const { indent = 2, ...writeOptions } = options;
86
+ const content = JSON.stringify(data, null, indent);
87
+ return writeFileAtomic(filePath, content, writeOptions);
88
+ }
89
+
90
+ module.exports = {
91
+ writeFileAtomic,
92
+ writeJsonAtomic,
93
+ getTempPath
94
+ };