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.
- package/.claude-plugin/marketplace.json +21 -14
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +18 -0
- package/README.md +7 -6
- package/adapters/codex/skills/agnix/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
- package/adapters/codex/skills/consult/SKILL.md +132 -57
- package/adapters/codex/skills/debate/SKILL.md +214 -0
- package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
- package/adapters/codex/skills/deslop/SKILL.md +0 -1
- package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
- package/adapters/codex/skills/enhance/SKILL.md +0 -1
- package/adapters/codex/skills/learn/SKILL.md +0 -1
- package/adapters/codex/skills/next-task/SKILL.md +0 -1
- package/adapters/codex/skills/perf/SKILL.md +0 -1
- package/adapters/codex/skills/repo-map/SKILL.md +0 -1
- package/adapters/codex/skills/ship/SKILL.md +0 -1
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
- package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
- package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
- package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
- package/adapters/opencode/agents/agent-enhancer.md +0 -1
- package/adapters/opencode/agents/agnix-agent.md +0 -1
- package/adapters/opencode/agents/ci-fixer.md +0 -1
- package/adapters/opencode/agents/ci-monitor.md +0 -1
- package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
- package/adapters/opencode/agents/consult-agent.md +122 -30
- package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
- package/adapters/opencode/agents/debate-orchestrator.md +169 -0
- package/adapters/opencode/agents/delivery-validator.md +0 -1
- package/adapters/opencode/agents/deslop-agent.md +0 -1
- package/adapters/opencode/agents/docs-enhancer.md +0 -1
- package/adapters/opencode/agents/exploration-agent.md +0 -1
- package/adapters/opencode/agents/hooks-enhancer.md +0 -1
- package/adapters/opencode/agents/implementation-agent.md +0 -1
- package/adapters/opencode/agents/learn-agent.md +0 -1
- package/adapters/opencode/agents/map-validator.md +0 -1
- package/adapters/opencode/agents/perf-analyzer.md +0 -1
- package/adapters/opencode/agents/perf-code-paths.md +0 -1
- package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
- package/adapters/opencode/agents/perf-orchestrator.md +0 -1
- package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
- package/adapters/opencode/agents/perf-theory-tester.md +0 -1
- package/adapters/opencode/agents/plan-synthesizer.md +0 -1
- package/adapters/opencode/agents/planning-agent.md +0 -1
- package/adapters/opencode/agents/plugin-enhancer.md +0 -1
- package/adapters/opencode/agents/prompt-enhancer.md +0 -1
- package/adapters/opencode/agents/simple-fixer.md +0 -1
- package/adapters/opencode/agents/skills-enhancer.md +0 -1
- package/adapters/opencode/agents/sync-docs-agent.md +0 -1
- package/adapters/opencode/agents/task-discoverer.md +0 -1
- package/adapters/opencode/agents/test-coverage-checker.md +0 -1
- package/adapters/opencode/agents/worktree-manager.md +0 -1
- package/adapters/opencode/commands/agnix.md +0 -1
- package/adapters/opencode/commands/audit-project-agents.md +0 -1
- package/adapters/opencode/commands/audit-project-github.md +0 -1
- package/adapters/opencode/commands/audit-project.md +0 -1
- package/adapters/opencode/commands/consult.md +133 -57
- package/adapters/opencode/commands/debate.md +224 -0
- package/adapters/opencode/commands/delivery-approval.md +0 -1
- package/adapters/opencode/commands/deslop.md +0 -1
- package/adapters/opencode/commands/drift-detect.md +0 -1
- package/adapters/opencode/commands/enhance.md +0 -1
- package/adapters/opencode/commands/learn.md +0 -1
- package/adapters/opencode/commands/next-task.md +0 -1
- package/adapters/opencode/commands/perf.md +0 -1
- package/adapters/opencode/commands/repo-map.md +0 -1
- package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
- package/adapters/opencode/commands/ship-deployment.md +0 -1
- package/adapters/opencode/commands/ship-error-handling.md +0 -1
- package/adapters/opencode/commands/ship.md +0 -1
- package/adapters/opencode/commands/sync-docs.md +0 -1
- package/adapters/opencode/skills/agnix/SKILL.md +1 -2
- package/adapters/opencode/skills/consult/SKILL.md +33 -23
- package/adapters/opencode/skills/debate/SKILL.md +245 -0
- package/adapters/opencode/skills/deslop/SKILL.md +1 -2
- package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
- package/adapters/opencode/skills/learn/SKILL.md +1 -2
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
- package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
- package/lib/adapter-transforms.js +24 -4
- package/package.json +1 -1
- package/plugins/agnix/.claude-plugin/plugin.json +1 -1
- package/plugins/agnix/skills/agnix/SKILL.md +1 -1
- package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
- package/plugins/audit-project/lib/adapter-transforms.js +24 -4
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/agents/consult-agent.md +122 -29
- package/plugins/consult/commands/consult.md +135 -58
- package/plugins/consult/skills/consult/SKILL.md +31 -20
- package/plugins/debate/.claude-plugin/plugin.json +21 -0
- package/plugins/debate/agents/debate-orchestrator.md +175 -0
- package/plugins/debate/commands/debate.md +221 -0
- package/plugins/debate/lib/adapter-transforms.js +298 -0
- package/plugins/debate/lib/collectors/codebase.js +392 -0
- package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
- package/plugins/debate/lib/collectors/documentation.js +219 -0
- package/plugins/debate/lib/collectors/github.js +330 -0
- package/plugins/debate/lib/collectors/index.js +126 -0
- package/plugins/debate/lib/config/index.js +14 -0
- package/plugins/debate/lib/cross-platform/index.js +539 -0
- package/plugins/debate/lib/discovery/index.js +352 -0
- package/plugins/debate/lib/drift-detect/collectors.js +37 -0
- package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
- package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
- package/plugins/debate/lib/enhance/benchmark.js +417 -0
- package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
- package/plugins/debate/lib/enhance/fixer.js +721 -0
- package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
- package/plugins/debate/lib/enhance/index.js +127 -0
- package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/debate/lib/enhance/reporter.js +1348 -0
- package/plugins/debate/lib/enhance/security-patterns.js +284 -0
- package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
- package/plugins/debate/lib/enhance/suppression.js +352 -0
- package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
- package/plugins/debate/lib/index.js +270 -0
- package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/debate/lib/patterns/pipeline.js +948 -0
- package/plugins/debate/lib/patterns/review-patterns.js +558 -0
- package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/debate/lib/perf/analyzer/index.js +22 -0
- package/plugins/debate/lib/perf/argument-parser.js +105 -0
- package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
- package/plugins/debate/lib/perf/baseline-store.js +127 -0
- package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
- package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/debate/lib/perf/checkpoint.js +123 -0
- package/plugins/debate/lib/perf/code-paths.js +86 -0
- package/plugins/debate/lib/perf/consolidation.js +37 -0
- package/plugins/debate/lib/perf/constraint-runner.js +71 -0
- package/plugins/debate/lib/perf/experiment-runner.js +32 -0
- package/plugins/debate/lib/perf/index.js +41 -0
- package/plugins/debate/lib/perf/investigation-state.js +874 -0
- package/plugins/debate/lib/perf/optimization-runner.js +79 -0
- package/plugins/debate/lib/perf/profilers/go.js +22 -0
- package/plugins/debate/lib/perf/profilers/index.js +46 -0
- package/plugins/debate/lib/perf/profilers/java.js +23 -0
- package/plugins/debate/lib/perf/profilers/node.js +27 -0
- package/plugins/debate/lib/perf/profilers/python.js +23 -0
- package/plugins/debate/lib/perf/profilers/rust.js +23 -0
- package/plugins/debate/lib/perf/profiling-runner.js +75 -0
- package/plugins/debate/lib/perf/schemas.js +140 -0
- package/plugins/debate/lib/platform/detect-platform.js +413 -0
- package/plugins/debate/lib/platform/detection-configs.js +93 -0
- package/plugins/debate/lib/platform/state-dir.js +132 -0
- package/plugins/debate/lib/platform/verify-tools.js +182 -0
- package/plugins/debate/lib/repo-map/cache.js +152 -0
- package/plugins/debate/lib/repo-map/concurrency.js +29 -0
- package/plugins/debate/lib/repo-map/index.js +222 -0
- package/plugins/debate/lib/repo-map/installer.js +212 -0
- package/plugins/debate/lib/repo-map/queries/go.js +27 -0
- package/plugins/debate/lib/repo-map/queries/index.js +100 -0
- package/plugins/debate/lib/repo-map/queries/java.js +38 -0
- package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/debate/lib/repo-map/queries/python.js +24 -0
- package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
- package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/debate/lib/repo-map/runner.js +1364 -0
- package/plugins/debate/lib/repo-map/updater.js +562 -0
- package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/debate/lib/schemas/validator.js +247 -0
- package/plugins/debate/lib/sources/custom-handler.js +199 -0
- package/plugins/debate/lib/sources/policy-questions.js +246 -0
- package/plugins/debate/lib/sources/source-cache.js +165 -0
- package/plugins/debate/lib/state/workflow-state.js +576 -0
- package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/debate/lib/types/index.d.ts +84 -0
- package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/debate/lib/utils/atomic-write.js +94 -0
- package/plugins/debate/lib/utils/cache-manager.js +159 -0
- package/plugins/debate/lib/utils/command-parser.js +0 -0
- package/plugins/debate/lib/utils/context-optimizer.js +300 -0
- package/plugins/debate/lib/utils/deprecation.js +37 -0
- package/plugins/debate/lib/utils/shell-escape.js +88 -0
- package/plugins/debate/lib/utils/state-helpers.js +61 -0
- package/plugins/debate/skills/debate/SKILL.md +264 -0
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/adapter-transforms.js +24 -4
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/adapter-transforms.js +24 -4
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
- package/plugins/learn/.claude-plugin/plugin.json +1 -1
- package/plugins/learn/agents/learn-agent.md +1 -1
- package/plugins/learn/lib/adapter-transforms.js +24 -4
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/exploration-agent.md +1 -1
- package/plugins/next-task/lib/adapter-transforms.js +24 -4
- package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
- package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/adapter-transforms.js +24 -4
- package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
- package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
- package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
- package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
- package/plugins/repo-map/lib/adapter-transforms.js +24 -4
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/gen-adapters.js +6 -7
- package/scripts/generate-docs.js +4 -2
- package/scripts/plugins.txt +1 -0
- 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
|
+
};
|