@cleocode/skills 2.0.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/dispatch-config.json +404 -0
- package/index.d.ts +178 -0
- package/index.js +405 -0
- package/package.json +14 -0
- package/profiles/core.json +7 -0
- package/profiles/full.json +10 -0
- package/profiles/minimal.json +7 -0
- package/profiles/recommended.json +7 -0
- package/provider-skills-map.json +97 -0
- package/skills/_shared/cleo-style-guide.md +84 -0
- package/skills/_shared/manifest-operations.md +810 -0
- package/skills/_shared/placeholders.json +433 -0
- package/skills/_shared/skill-chaining-patterns.md +237 -0
- package/skills/_shared/subagent-protocol-base.md +223 -0
- package/skills/_shared/task-system-integration.md +232 -0
- package/skills/_shared/testing-framework-config.md +110 -0
- package/skills/ct-cleo/SKILL.md +490 -0
- package/skills/ct-cleo/references/anti-patterns.md +19 -0
- package/skills/ct-cleo/references/loom-lifecycle.md +136 -0
- package/skills/ct-cleo/references/orchestrator-constraints.md +55 -0
- package/skills/ct-cleo/references/session-protocol.md +162 -0
- package/skills/ct-codebase-mapper/SKILL.md +82 -0
- package/skills/ct-contribution/SKILL.md +521 -0
- package/skills/ct-contribution/templates/contribution-init.json +21 -0
- package/skills/ct-dev-workflow/SKILL.md +423 -0
- package/skills/ct-docs-lookup/SKILL.md +66 -0
- package/skills/ct-docs-review/SKILL.md +175 -0
- package/skills/ct-docs-write/SKILL.md +108 -0
- package/skills/ct-documentor/SKILL.md +231 -0
- package/skills/ct-epic-architect/SKILL.md +305 -0
- package/skills/ct-epic-architect/references/bug-epic-example.md +172 -0
- package/skills/ct-epic-architect/references/commands.md +201 -0
- package/skills/ct-epic-architect/references/feature-epic-example.md +210 -0
- package/skills/ct-epic-architect/references/migration-epic-example.md +244 -0
- package/skills/ct-epic-architect/references/output-format.md +92 -0
- package/skills/ct-epic-architect/references/patterns.md +284 -0
- package/skills/ct-epic-architect/references/refactor-epic-example.md +412 -0
- package/skills/ct-epic-architect/references/research-epic-example.md +226 -0
- package/skills/ct-epic-architect/references/shell-escaping.md +86 -0
- package/skills/ct-epic-architect/references/skill-aware-execution.md +195 -0
- package/skills/ct-grade/SKILL.md +230 -0
- package/skills/ct-grade/agents/analysis-reporter.md +203 -0
- package/skills/ct-grade/agents/blind-comparator.md +157 -0
- package/skills/ct-grade/agents/scenario-runner.md +134 -0
- package/skills/ct-grade/eval-viewer/__pycache__/generate_grade_review.cpython-314.pyc +0 -0
- package/skills/ct-grade/eval-viewer/generate_grade_review.py +1138 -0
- package/skills/ct-grade/eval-viewer/generate_grade_viewer.py +544 -0
- package/skills/ct-grade/eval-viewer/generate_review.py +283 -0
- package/skills/ct-grade/eval-viewer/grade-review.html +1574 -0
- package/skills/ct-grade/eval-viewer/viewer.html +219 -0
- package/skills/ct-grade/evals/evals.json +94 -0
- package/skills/ct-grade/references/ab-test-methodology.md +150 -0
- package/skills/ct-grade/references/domains.md +137 -0
- package/skills/ct-grade/references/grade-spec.md +236 -0
- package/skills/ct-grade/references/scenario-playbook.md +234 -0
- package/skills/ct-grade/references/token-tracking.md +120 -0
- package/skills/ct-grade/scripts/__pycache__/audit_analyzer.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/run_ab_test.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/run_all.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/__pycache__/token_tracker.cpython-314.pyc +0 -0
- package/skills/ct-grade/scripts/audit_analyzer.py +279 -0
- package/skills/ct-grade/scripts/generate_report.py +283 -0
- package/skills/ct-grade/scripts/run_ab_test.py +504 -0
- package/skills/ct-grade/scripts/run_all.py +287 -0
- package/skills/ct-grade/scripts/setup_run.py +183 -0
- package/skills/ct-grade/scripts/token_tracker.py +630 -0
- package/skills/ct-grade-v2-1/SKILL.md +237 -0
- package/skills/ct-grade-v2-1/agents/analysis-reporter.md +203 -0
- package/skills/ct-grade-v2-1/agents/blind-comparator.md +157 -0
- package/skills/ct-grade-v2-1/agents/scenario-runner.md +179 -0
- package/skills/ct-grade-v2-1/evals/evals.json +74 -0
- package/skills/ct-grade-v2-1/grade-viewer/__pycache__/build_op_stats.cpython-314.pyc +0 -0
- package/skills/ct-grade-v2-1/grade-viewer/__pycache__/generate_grade_review.cpython-314.pyc +0 -0
- package/skills/ct-grade-v2-1/grade-viewer/build_op_stats.py +174 -0
- package/skills/ct-grade-v2-1/grade-viewer/eval-analysis.json +41 -0
- package/skills/ct-grade-v2-1/grade-viewer/eval-report.md +34 -0
- package/skills/ct-grade-v2-1/grade-viewer/generate_grade_review.py +1023 -0
- package/skills/ct-grade-v2-1/grade-viewer/generate_grade_viewer.py +548 -0
- package/skills/ct-grade-v2-1/grade-viewer/grade-review-eval.html +613 -0
- package/skills/ct-grade-v2-1/grade-viewer/grade-review.html +1532 -0
- package/skills/ct-grade-v2-1/grade-viewer/viewer.html +620 -0
- package/skills/ct-grade-v2-1/manifest-entry.json +31 -0
- package/skills/ct-grade-v2-1/references/ab-testing.md +233 -0
- package/skills/ct-grade-v2-1/references/domains-ssot.md +156 -0
- package/skills/ct-grade-v2-1/references/grade-spec-v2.md +167 -0
- package/skills/ct-grade-v2-1/references/playbook-v2.md +393 -0
- package/skills/ct-grade-v2-1/references/token-tracking.md +202 -0
- package/skills/ct-grade-v2-1/scripts/generate_report.py +419 -0
- package/skills/ct-grade-v2-1/scripts/run_ab_test.py +493 -0
- package/skills/ct-grade-v2-1/scripts/run_scenario.py +396 -0
- package/skills/ct-grade-v2-1/scripts/setup_run.py +207 -0
- package/skills/ct-grade-v2-1/scripts/token_tracker.py +175 -0
- package/skills/ct-memory/SKILL.md +84 -0
- package/skills/ct-orchestrator/INSTALL.md +61 -0
- package/skills/ct-orchestrator/README.md +69 -0
- package/skills/ct-orchestrator/SKILL.md +380 -0
- package/skills/ct-orchestrator/manifest-entry.json +19 -0
- package/skills/ct-orchestrator/orchestrator-prompt.txt +17 -0
- package/skills/ct-orchestrator/references/SUBAGENT-PROTOCOL-BLOCK.md +66 -0
- package/skills/ct-orchestrator/references/autonomous-operation.md +167 -0
- package/skills/ct-orchestrator/references/lifecycle-gates.md +98 -0
- package/skills/ct-orchestrator/references/orchestrator-compliance.md +271 -0
- package/skills/ct-orchestrator/references/orchestrator-handoffs.md +85 -0
- package/skills/ct-orchestrator/references/orchestrator-patterns.md +164 -0
- package/skills/ct-orchestrator/references/orchestrator-recovery.md +113 -0
- package/skills/ct-orchestrator/references/orchestrator-spawning.md +271 -0
- package/skills/ct-orchestrator/references/orchestrator-tokens.md +180 -0
- package/skills/ct-research-agent/SKILL.md +226 -0
- package/skills/ct-skill-creator/.cleo/.context-state.json +13 -0
- package/skills/ct-skill-creator/.cleo/logs/cleo.2026-03-07.1.log +24 -0
- package/skills/ct-skill-creator/.cleo/tasks.db +0 -0
- package/skills/ct-skill-creator/SKILL.md +356 -0
- package/skills/ct-skill-creator/agents/analyzer.md +276 -0
- package/skills/ct-skill-creator/agents/comparator.md +204 -0
- package/skills/ct-skill-creator/agents/grader.md +225 -0
- package/skills/ct-skill-creator/assets/eval_review.html +146 -0
- package/skills/ct-skill-creator/eval-viewer/__pycache__/generate_review.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/ct-skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/ct-skill-creator/manifest-entry.json +17 -0
- package/skills/ct-skill-creator/references/dynamic-context.md +228 -0
- package/skills/ct-skill-creator/references/frontmatter.md +83 -0
- package/skills/ct-skill-creator/references/invocation-control.md +165 -0
- package/skills/ct-skill-creator/references/output-patterns.md +86 -0
- package/skills/ct-skill-creator/references/provider-deployment.md +175 -0
- package/skills/ct-skill-creator/references/schemas.md +430 -0
- package/skills/ct-skill-creator/references/workflows.md +28 -0
- package/skills/ct-skill-creator/scripts/__init__.py +1 -0
- package/skills/ct-skill-creator/scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/aggregate_benchmark.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/generate_report.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/improve_description.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/init_skill.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/quick_validate.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/run_eval.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/run_loop.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/__pycache__/utils.cpython-314.pyc +0 -0
- package/skills/ct-skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/ct-skill-creator/scripts/generate_report.py +326 -0
- package/skills/ct-skill-creator/scripts/improve_description.py +247 -0
- package/skills/ct-skill-creator/scripts/init_skill.py +306 -0
- package/skills/ct-skill-creator/scripts/package_skill.py +110 -0
- package/skills/ct-skill-creator/scripts/quick_validate.py +97 -0
- package/skills/ct-skill-creator/scripts/run_eval.py +310 -0
- package/skills/ct-skill-creator/scripts/run_loop.py +328 -0
- package/skills/ct-skill-creator/scripts/utils.py +47 -0
- package/skills/ct-skill-validator/SKILL.md +178 -0
- package/skills/ct-skill-validator/agents/ecosystem-checker.md +151 -0
- package/skills/ct-skill-validator/assets/valid-skill-example.md +13 -0
- package/skills/ct-skill-validator/evals/eval_set.json +14 -0
- package/skills/ct-skill-validator/evals/evals.json +52 -0
- package/skills/ct-skill-validator/manifest-entry.json +20 -0
- package/skills/ct-skill-validator/references/cleo-ecosystem-rules.md +163 -0
- package/skills/ct-skill-validator/references/validation-rules.md +168 -0
- package/skills/ct-skill-validator/scripts/__init__.py +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/audit_body.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/check_ecosystem.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/generate_validation_report.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/__pycache__/validate.cpython-314.pyc +0 -0
- package/skills/ct-skill-validator/scripts/audit_body.py +242 -0
- package/skills/ct-skill-validator/scripts/check_ecosystem.py +169 -0
- package/skills/ct-skill-validator/scripts/check_manifest.py +172 -0
- package/skills/ct-skill-validator/scripts/generate_validation_report.py +442 -0
- package/skills/ct-skill-validator/scripts/validate.py +422 -0
- package/skills/ct-spec-writer/SKILL.md +189 -0
- package/skills/ct-stickynote/README.md +14 -0
- package/skills/ct-stickynote/SKILL.md +46 -0
- package/skills/ct-task-executor/SKILL.md +296 -0
- package/skills/ct-validator/SKILL.md +216 -0
- package/skills/manifest.json +469 -0
- package/skills.json +281 -0
package/index.js
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
const LIBRARY_ROOT = __dirname;
|
|
7
|
+
const SKILLS_ROOT = path.join(LIBRARY_ROOT, 'skills');
|
|
8
|
+
const PROFILES_ROOT = path.join(LIBRARY_ROOT, 'profiles');
|
|
9
|
+
const PROTOCOLS_ROOT = path.join(LIBRARY_ROOT, '..', '..', 'src', 'protocols');
|
|
10
|
+
const SHARED_ROOT = path.join(SKILLS_ROOT, '_shared');
|
|
11
|
+
|
|
12
|
+
// --- Package metadata ---
|
|
13
|
+
|
|
14
|
+
/** Package version from package.json */
|
|
15
|
+
const version = require('./package.json').version;
|
|
16
|
+
|
|
17
|
+
/** Absolute path to the package root directory */
|
|
18
|
+
const libraryRoot = LIBRARY_ROOT;
|
|
19
|
+
|
|
20
|
+
// --- Core data ---
|
|
21
|
+
|
|
22
|
+
/** Parsed skills.json index */
|
|
23
|
+
const skillsIndex = JSON.parse(
|
|
24
|
+
fs.readFileSync(path.join(LIBRARY_ROOT, 'skills.json'), 'utf8')
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/** Parsed manifest.json dispatch registry */
|
|
28
|
+
const manifest = JSON.parse(
|
|
29
|
+
fs.readFileSync(path.join(SKILLS_ROOT, 'manifest.json'), 'utf8')
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/** Parsed _shared/placeholders.json */
|
|
33
|
+
const shared = JSON.parse(
|
|
34
|
+
fs.readFileSync(path.join(SHARED_ROOT, 'placeholders.json'), 'utf8')
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
/** All skill entries from skills.json */
|
|
38
|
+
const skills = skillsIndex.skills;
|
|
39
|
+
|
|
40
|
+
// --- Existing API (preserved) ---
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* List all skill names.
|
|
44
|
+
* @returns {string[]}
|
|
45
|
+
*/
|
|
46
|
+
function listSkills() {
|
|
47
|
+
return skills.map(s => s.name);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get skill metadata from skills.json by name.
|
|
52
|
+
* @param {string} name - Skill name (e.g. "ct-research-agent")
|
|
53
|
+
* @returns {object|undefined}
|
|
54
|
+
*/
|
|
55
|
+
function getSkill(name) {
|
|
56
|
+
return skills.find(s => s.name === name);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve absolute path to a skill's SKILL.md file.
|
|
61
|
+
* @param {string} name - Skill name
|
|
62
|
+
* @returns {string}
|
|
63
|
+
*/
|
|
64
|
+
function getSkillPath(name) {
|
|
65
|
+
return path.join(SKILLS_ROOT, name, 'SKILL.md');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolve absolute path to a skill's directory.
|
|
70
|
+
* @param {string} name - Skill name
|
|
71
|
+
* @returns {string}
|
|
72
|
+
*/
|
|
73
|
+
function getSkillDir(name) {
|
|
74
|
+
return path.join(SKILLS_ROOT, name);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the dispatch matrix from manifest.json.
|
|
79
|
+
* @returns {object}
|
|
80
|
+
*/
|
|
81
|
+
function getDispatchMatrix() {
|
|
82
|
+
return manifest.dispatch_matrix;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Read a skill's SKILL.md content as a string.
|
|
87
|
+
* @param {string} name - Skill name
|
|
88
|
+
* @returns {string}
|
|
89
|
+
*/
|
|
90
|
+
function readSkillContent(name) {
|
|
91
|
+
return fs.readFileSync(getSkillPath(name), 'utf8');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// --- New: Core & Dependency awareness ---
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get all skills marked as core.
|
|
98
|
+
* @returns {object[]} SkillEntry[] where core === true
|
|
99
|
+
*/
|
|
100
|
+
function getCoreSkills() {
|
|
101
|
+
return skills.filter(s => s.core === true);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get skills filtered by category.
|
|
106
|
+
* @param {string} category - One of: core, recommended, specialist, composition, meta
|
|
107
|
+
* @returns {object[]}
|
|
108
|
+
*/
|
|
109
|
+
function getSkillsByCategory(category) {
|
|
110
|
+
return skills.filter(s => s.category === category);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get direct dependency names for a skill.
|
|
115
|
+
* @param {string} name - Skill name
|
|
116
|
+
* @returns {string[]}
|
|
117
|
+
*/
|
|
118
|
+
function getSkillDependencies(name) {
|
|
119
|
+
const skill = getSkill(name);
|
|
120
|
+
if (!skill) return [];
|
|
121
|
+
return skill.dependencies || [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Resolve the full dependency tree for a set of skill names.
|
|
126
|
+
* Returns deduplicated list with transitive deps. _shared is always included conceptually.
|
|
127
|
+
* @param {string[]} names - Initial skill names
|
|
128
|
+
* @returns {string[]} Full list of skills including transitive dependencies
|
|
129
|
+
*/
|
|
130
|
+
function resolveDependencyTree(names) {
|
|
131
|
+
const resolved = new Set();
|
|
132
|
+
const queue = [...names];
|
|
133
|
+
|
|
134
|
+
while (queue.length > 0) {
|
|
135
|
+
const current = queue.shift();
|
|
136
|
+
if (resolved.has(current)) continue;
|
|
137
|
+
resolved.add(current);
|
|
138
|
+
|
|
139
|
+
const deps = getSkillDependencies(current);
|
|
140
|
+
for (const dep of deps) {
|
|
141
|
+
if (!resolved.has(dep)) {
|
|
142
|
+
queue.push(dep);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return Array.from(resolved);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// --- New: Profile-based selection ---
|
|
151
|
+
|
|
152
|
+
/** Cache for loaded profile definitions */
|
|
153
|
+
const _profileCache = new Map();
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* List available profile names.
|
|
157
|
+
* @returns {string[]}
|
|
158
|
+
*/
|
|
159
|
+
function listProfiles() {
|
|
160
|
+
if (!fs.existsSync(PROFILES_ROOT)) return [];
|
|
161
|
+
return fs.readdirSync(PROFILES_ROOT)
|
|
162
|
+
.filter(f => f.endsWith('.json'))
|
|
163
|
+
.map(f => f.replace('.json', ''));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get a profile definition by name.
|
|
168
|
+
* @param {string} name - Profile name (e.g. "minimal", "core", "recommended", "full")
|
|
169
|
+
* @returns {object|undefined}
|
|
170
|
+
*/
|
|
171
|
+
function getProfile(name) {
|
|
172
|
+
if (_profileCache.has(name)) return _profileCache.get(name);
|
|
173
|
+
|
|
174
|
+
const filePath = path.join(PROFILES_ROOT, `${name}.json`);
|
|
175
|
+
if (!fs.existsSync(filePath)) return undefined;
|
|
176
|
+
|
|
177
|
+
const profile = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
178
|
+
_profileCache.set(name, profile);
|
|
179
|
+
return profile;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Resolve a profile to its full skill list, following extends chains
|
|
184
|
+
* and resolving transitive skill dependencies.
|
|
185
|
+
* @param {string} name - Profile name
|
|
186
|
+
* @returns {string[]} Full deduplicated skill list
|
|
187
|
+
*/
|
|
188
|
+
function resolveProfile(name) {
|
|
189
|
+
const allSkills = new Set();
|
|
190
|
+
const visited = new Set();
|
|
191
|
+
|
|
192
|
+
// Walk the extends chain
|
|
193
|
+
let current = name;
|
|
194
|
+
while (current && !visited.has(current)) {
|
|
195
|
+
visited.add(current);
|
|
196
|
+
const profile = getProfile(current);
|
|
197
|
+
if (!profile) break;
|
|
198
|
+
|
|
199
|
+
for (const skill of profile.skills) {
|
|
200
|
+
allSkills.add(skill);
|
|
201
|
+
}
|
|
202
|
+
current = profile.extends || null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Resolve transitive dependencies
|
|
206
|
+
return resolveDependencyTree(Array.from(allSkills));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// --- New: Shared resources ---
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* List available shared resource names (files in _shared/).
|
|
213
|
+
* @returns {string[]}
|
|
214
|
+
*/
|
|
215
|
+
function listSharedResources() {
|
|
216
|
+
if (!fs.existsSync(SHARED_ROOT)) return [];
|
|
217
|
+
return fs.readdirSync(SHARED_ROOT)
|
|
218
|
+
.filter(f => !f.startsWith('.'))
|
|
219
|
+
.map(f => f.replace(/\.[^.]+$/, ''));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get absolute path to a shared resource file.
|
|
224
|
+
* @param {string} name - Resource name (without extension, e.g. "subagent-protocol-base")
|
|
225
|
+
* @returns {string|undefined}
|
|
226
|
+
*/
|
|
227
|
+
function getSharedResourcePath(name) {
|
|
228
|
+
if (!fs.existsSync(SHARED_ROOT)) return undefined;
|
|
229
|
+
const files = fs.readdirSync(SHARED_ROOT);
|
|
230
|
+
const match = files.find(f => f.replace(/\.[^.]+$/, '') === name);
|
|
231
|
+
return match ? path.join(SHARED_ROOT, match) : undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Read a shared resource file content.
|
|
236
|
+
* @param {string} name - Resource name (without extension)
|
|
237
|
+
* @returns {string|undefined}
|
|
238
|
+
*/
|
|
239
|
+
function readSharedResource(name) {
|
|
240
|
+
const filePath = getSharedResourcePath(name);
|
|
241
|
+
if (!filePath || !fs.existsSync(filePath)) return undefined;
|
|
242
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// --- New: Protocols ---
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* List available protocol names.
|
|
249
|
+
* @returns {string[]}
|
|
250
|
+
*/
|
|
251
|
+
function listProtocols() {
|
|
252
|
+
if (!fs.existsSync(PROTOCOLS_ROOT)) return [];
|
|
253
|
+
return fs.readdirSync(PROTOCOLS_ROOT)
|
|
254
|
+
.filter(f => f.endsWith('.md'))
|
|
255
|
+
.map(f => f.replace('.md', ''));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Get absolute path to a protocol file.
|
|
260
|
+
* @param {string} name - Protocol name (e.g. "research", "implementation")
|
|
261
|
+
* @returns {string|undefined}
|
|
262
|
+
*/
|
|
263
|
+
function getProtocolPath(name) {
|
|
264
|
+
const filePath = path.join(PROTOCOLS_ROOT, `${name}.md`);
|
|
265
|
+
return fs.existsSync(filePath) ? filePath : undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Read a protocol file content.
|
|
270
|
+
* @param {string} name - Protocol name
|
|
271
|
+
* @returns {string|undefined}
|
|
272
|
+
*/
|
|
273
|
+
function readProtocol(name) {
|
|
274
|
+
const filePath = getProtocolPath(name);
|
|
275
|
+
if (!filePath) return undefined;
|
|
276
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// --- New: Validation ---
|
|
280
|
+
|
|
281
|
+
const VALID_CATEGORIES = ['core', 'recommended', 'specialist', 'composition', 'meta'];
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Validate a skill's frontmatter fields.
|
|
285
|
+
* @param {string} name - Skill name
|
|
286
|
+
* @returns {{ valid: boolean, issues: { level: string, field: string, message: string }[] }}
|
|
287
|
+
*/
|
|
288
|
+
function validateSkillFrontmatter(name) {
|
|
289
|
+
const skill = getSkill(name);
|
|
290
|
+
const issues = [];
|
|
291
|
+
|
|
292
|
+
if (!skill) {
|
|
293
|
+
return { valid: false, issues: [{ level: 'error', field: 'name', message: `Skill '${name}' not found` }] };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Required fields
|
|
297
|
+
if (!skill.name) issues.push({ level: 'error', field: 'name', message: 'Missing name' });
|
|
298
|
+
if (!skill.description) issues.push({ level: 'error', field: 'description', message: 'Missing description' });
|
|
299
|
+
|
|
300
|
+
// Version format
|
|
301
|
+
if (!skill.version) {
|
|
302
|
+
issues.push({ level: 'warn', field: 'version', message: 'Missing version' });
|
|
303
|
+
} else if (!/^\d+\.\d+\.\d+$/.test(skill.version)) {
|
|
304
|
+
issues.push({ level: 'warn', field: 'version', message: `Invalid semver: ${skill.version}` });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Category validation
|
|
308
|
+
if (skill.category && !VALID_CATEGORIES.includes(skill.category)) {
|
|
309
|
+
issues.push({ level: 'error', field: 'category', message: `Invalid category '${skill.category}', must be one of: ${VALID_CATEGORIES.join(', ')}` });
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Core must be boolean
|
|
313
|
+
if (skill.core !== undefined && typeof skill.core !== 'boolean') {
|
|
314
|
+
issues.push({ level: 'error', field: 'core', message: `core must be boolean, got ${typeof skill.core}` });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Tier must be 0-3
|
|
318
|
+
if (skill.tier !== undefined && (typeof skill.tier !== 'number' || skill.tier < 0 || skill.tier > 3)) {
|
|
319
|
+
issues.push({ level: 'warn', field: 'tier', message: `Tier should be 0-3, got ${skill.tier}` });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Dependencies must reference valid skills
|
|
323
|
+
if (Array.isArray(skill.dependencies)) {
|
|
324
|
+
const allNames = listSkills();
|
|
325
|
+
for (const dep of skill.dependencies) {
|
|
326
|
+
if (!allNames.includes(dep)) {
|
|
327
|
+
issues.push({ level: 'error', field: 'dependencies', message: `Unknown dependency: ${dep}` });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Protocol should reference an existing protocol file
|
|
333
|
+
if (skill.protocol && skill.protocol !== 'null') {
|
|
334
|
+
const protoPath = getProtocolPath(skill.protocol);
|
|
335
|
+
if (!protoPath) {
|
|
336
|
+
issues.push({ level: 'warn', field: 'protocol', message: `Protocol file not found: ${skill.protocol}.md` });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Description length
|
|
341
|
+
if (skill.description && skill.description.length > 1024) {
|
|
342
|
+
issues.push({ level: 'error', field: 'description', message: `Description too long: ${skill.description.length} chars (max 1024)` });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
valid: issues.filter(i => i.level === 'error').length === 0,
|
|
347
|
+
issues
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Validate all skills.
|
|
353
|
+
* @returns {Map<string, { valid: boolean, issues: { level: string, field: string, message: string }[] }>}
|
|
354
|
+
*/
|
|
355
|
+
function validateAll() {
|
|
356
|
+
const results = new Map();
|
|
357
|
+
for (const name of listSkills()) {
|
|
358
|
+
results.set(name, validateSkillFrontmatter(name));
|
|
359
|
+
}
|
|
360
|
+
return results;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// --- Exports ---
|
|
364
|
+
|
|
365
|
+
module.exports = {
|
|
366
|
+
// Existing (preserved)
|
|
367
|
+
skills,
|
|
368
|
+
manifest,
|
|
369
|
+
shared,
|
|
370
|
+
listSkills,
|
|
371
|
+
getSkill,
|
|
372
|
+
getSkillPath,
|
|
373
|
+
getSkillDir,
|
|
374
|
+
getDispatchMatrix,
|
|
375
|
+
readSkillContent,
|
|
376
|
+
|
|
377
|
+
// New: Core & Dependency awareness
|
|
378
|
+
getCoreSkills,
|
|
379
|
+
getSkillsByCategory,
|
|
380
|
+
getSkillDependencies,
|
|
381
|
+
resolveDependencyTree,
|
|
382
|
+
|
|
383
|
+
// New: Profile-based selection
|
|
384
|
+
listProfiles,
|
|
385
|
+
getProfile,
|
|
386
|
+
resolveProfile,
|
|
387
|
+
|
|
388
|
+
// New: Shared resources
|
|
389
|
+
listSharedResources,
|
|
390
|
+
getSharedResourcePath,
|
|
391
|
+
readSharedResource,
|
|
392
|
+
|
|
393
|
+
// New: Protocols
|
|
394
|
+
listProtocols,
|
|
395
|
+
getProtocolPath,
|
|
396
|
+
readProtocol,
|
|
397
|
+
|
|
398
|
+
// New: Validation
|
|
399
|
+
validateSkillFrontmatter,
|
|
400
|
+
validateAll,
|
|
401
|
+
|
|
402
|
+
// New: Package metadata
|
|
403
|
+
version,
|
|
404
|
+
libraryRoot,
|
|
405
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cleocode/skills",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "CLEO skill definitions - bundled with CLEO monorepo",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"skills",
|
|
9
|
+
"profiles",
|
|
10
|
+
"*.json",
|
|
11
|
+
"*.js",
|
|
12
|
+
"*.d.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "full",
|
|
3
|
+
"description": "All skills including execution, documentation, quality, and meta",
|
|
4
|
+
"extends": "recommended",
|
|
5
|
+
"skills": [
|
|
6
|
+
"ct-dev-workflow", "ct-documentor", "ct-docs-lookup", "ct-docs-write", "ct-docs-review",
|
|
7
|
+
"ct-contribution", "ct-grade", "ct-skill-creator"
|
|
8
|
+
],
|
|
9
|
+
"includeProtocols": ["implementation", "contribution", "release", "testing", "artifact-publish", "provenance"]
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "recommended",
|
|
3
|
+
"description": "Full LOOM (RCASD-IVTR+C pipeline) skills for epic-driven development",
|
|
4
|
+
"extends": "core",
|
|
5
|
+
"skills": ["ct-epic-architect", "ct-research-agent", "ct-spec-writer", "ct-validator", "loom"],
|
|
6
|
+
"includeProtocols": ["research", "consensus", "specification", "decomposition", "validation", "adr"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://lafs.dev/schemas/v1/provider-skills-map.schema.json",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Provider skill path discovery and precedence rules for CLEO skill deployment",
|
|
5
|
+
"providers": {
|
|
6
|
+
"claude-code": {
|
|
7
|
+
"globalSkills": "$HOME/.claude/skills",
|
|
8
|
+
"projectSkills": ".claude/skills",
|
|
9
|
+
"agentsGlobal": null,
|
|
10
|
+
"agentsProject": null,
|
|
11
|
+
"readsFromDotAgents": false,
|
|
12
|
+
"precedence": "vendor-only",
|
|
13
|
+
"symlinkSupported": true,
|
|
14
|
+
"notes": "Created Agent Skills standard but uses vendor path exclusively"
|
|
15
|
+
},
|
|
16
|
+
"codex-cli": {
|
|
17
|
+
"globalSkills": "$HOME/.agents/skills",
|
|
18
|
+
"projectSkills": ".agents/skills",
|
|
19
|
+
"agentsGlobal": "$HOME/.agents/skills",
|
|
20
|
+
"agentsProject": ".agents/skills",
|
|
21
|
+
"readsFromDotAgents": true,
|
|
22
|
+
"precedence": "agents-canonical",
|
|
23
|
+
"symlinkSupported": true,
|
|
24
|
+
"notes": "Uses .agents/skills as canonical location"
|
|
25
|
+
},
|
|
26
|
+
"gemini-cli": {
|
|
27
|
+
"globalSkills": "$HOME/.gemini/skills",
|
|
28
|
+
"projectSkills": ".gemini/skills",
|
|
29
|
+
"agentsGlobal": "$HOME/.agents/skills",
|
|
30
|
+
"agentsProject": ".agents/skills",
|
|
31
|
+
"readsFromDotAgents": true,
|
|
32
|
+
"precedence": "agents-first",
|
|
33
|
+
"symlinkSupported": true,
|
|
34
|
+
"notes": ".agents/skills takes precedence over .gemini/skills within same tier"
|
|
35
|
+
},
|
|
36
|
+
"cursor": {
|
|
37
|
+
"globalSkills": "$HOME/.cursor/skills",
|
|
38
|
+
"projectSkills": ".cursor/skills",
|
|
39
|
+
"agentsGlobal": null,
|
|
40
|
+
"agentsProject": ".agents/skills",
|
|
41
|
+
"readsFromDotAgents": "project-only",
|
|
42
|
+
"precedence": "vendor-global-agents-project",
|
|
43
|
+
"symlinkSupported": true,
|
|
44
|
+
"notes": "Global uses vendor path; project supports .agents/skills"
|
|
45
|
+
},
|
|
46
|
+
"github-copilot": {
|
|
47
|
+
"globalSkills": "$HOME/.copilot/skills",
|
|
48
|
+
"projectSkills": ".github/skills",
|
|
49
|
+
"agentsGlobal": "$HOME/.agents/skills",
|
|
50
|
+
"agentsProject": ".agents/skills",
|
|
51
|
+
"readsFromDotAgents": true,
|
|
52
|
+
"precedence": "agents-supported",
|
|
53
|
+
"symlinkSupported": true,
|
|
54
|
+
"notes": "Supports both vendor and .agents paths at all levels"
|
|
55
|
+
},
|
|
56
|
+
"windsurf": {
|
|
57
|
+
"globalSkills": "$HOME/.codeium/windsurf/skills",
|
|
58
|
+
"projectSkills": ".windsurf/skills",
|
|
59
|
+
"agentsGlobal": null,
|
|
60
|
+
"agentsProject": null,
|
|
61
|
+
"readsFromDotAgents": false,
|
|
62
|
+
"precedence": "vendor-only",
|
|
63
|
+
"symlinkSupported": false,
|
|
64
|
+
"notes": "Vendor-specific paths only, no .agents support"
|
|
65
|
+
},
|
|
66
|
+
"opencode": {
|
|
67
|
+
"globalSkills": "$HOME/.config/opencode/skills",
|
|
68
|
+
"projectSkills": ".opencode/skills",
|
|
69
|
+
"agentsGlobal": "$HOME/.agents/skills",
|
|
70
|
+
"agentsProject": ".agents/skills",
|
|
71
|
+
"readsFromDotAgents": true,
|
|
72
|
+
"precedence": "agents-supported",
|
|
73
|
+
"symlinkSupported": true,
|
|
74
|
+
"notes": "User confirms .agents/ support; verify via opencode docs"
|
|
75
|
+
},
|
|
76
|
+
"kimi-coding": {
|
|
77
|
+
"globalSkills": "$HOME/.kimi/skills",
|
|
78
|
+
"projectSkills": ".kimi/skills",
|
|
79
|
+
"agentsGlobal": null,
|
|
80
|
+
"agentsProject": null,
|
|
81
|
+
"readsFromDotAgents": false,
|
|
82
|
+
"precedence": "vendor-only",
|
|
83
|
+
"symlinkSupported": false,
|
|
84
|
+
"notes": "Model-based provider; skill path support uncertain"
|
|
85
|
+
},
|
|
86
|
+
"antigravity": {
|
|
87
|
+
"globalSkills": "$HOME/.antigravity/skills",
|
|
88
|
+
"projectSkills": ".agent/skills",
|
|
89
|
+
"agentsGlobal": null,
|
|
90
|
+
"agentsProject": ".agents/skills",
|
|
91
|
+
"readsFromDotAgents": "project-only",
|
|
92
|
+
"precedence": "vendor-global-agents-project",
|
|
93
|
+
"symlinkSupported": true,
|
|
94
|
+
"notes": "Project-level .agents/skills confirmed in Google codelabs"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# CLEO Writing Style Guide
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
|
|
5
|
+
Write like you're talking to a colleague. Be conversational, not formal. Get people what they need quickly. Know your audience and match the complexity.
|
|
6
|
+
|
|
7
|
+
## Tone and Voice
|
|
8
|
+
|
|
9
|
+
**Do:**
|
|
10
|
+
|
|
11
|
+
- Use contractions ("can't" not "cannot")
|
|
12
|
+
- Say "people" or "companies" instead of "users"
|
|
13
|
+
- Be friendly but not peppy
|
|
14
|
+
- Acknowledge limitations honestly ("that's on us, not them")
|
|
15
|
+
- Jokes and Easter eggs are okay (permit them, don't suggest them)
|
|
16
|
+
|
|
17
|
+
**Don't:**
|
|
18
|
+
|
|
19
|
+
- Use exclamation points excessively
|
|
20
|
+
- Rely on tired tropes about nerdiness
|
|
21
|
+
- Use corporate jargon ("utilize", "offerings", "actionable insights")
|
|
22
|
+
- Tell people something is cool (show them instead)
|
|
23
|
+
|
|
24
|
+
## Structure and Clarity
|
|
25
|
+
|
|
26
|
+
**Lead with the important stuff:**
|
|
27
|
+
|
|
28
|
+
- Most important information first
|
|
29
|
+
- Lead with the ask, then provide context
|
|
30
|
+
- Cut text that adds little value (when in doubt, cut it)
|
|
31
|
+
- Each paragraph should have one clear purpose
|
|
32
|
+
|
|
33
|
+
**Make headings do the work:**
|
|
34
|
+
|
|
35
|
+
- Convey your actual point, not just the topic
|
|
36
|
+
- "Use headings to highlight key points" not "How to write a good heading"
|
|
37
|
+
- Use sentence case, no punctuation except question marks
|
|
38
|
+
- No links in headings unless entire heading is a link
|
|
39
|
+
|
|
40
|
+
## Instructions and Examples
|
|
41
|
+
|
|
42
|
+
**Tell people what to do:**
|
|
43
|
+
|
|
44
|
+
- Give the action before explaining why
|
|
45
|
+
- Put commands in execution order
|
|
46
|
+
- Provide context, steps, and reasoning
|
|
47
|
+
- Don't describe tasks as "easy" or "simple"
|
|
48
|
+
|
|
49
|
+
**Answer unasked questions:**
|
|
50
|
+
|
|
51
|
+
- Include answers to "dumb" questions you had when learning
|
|
52
|
+
- Don't literally include the question, just give the answer
|
|
53
|
+
|
|
54
|
+
## Formatting
|
|
55
|
+
|
|
56
|
+
**Code vs. UI elements:**
|
|
57
|
+
|
|
58
|
+
- Backticks for code, variable names, parameters only
|
|
59
|
+
- **Bold** for UI elements and labels (e.g., "Click the **Save** button")
|
|
60
|
+
- Don't use backticks or quotes for UI elements
|
|
61
|
+
|
|
62
|
+
## Writing Mechanics
|
|
63
|
+
|
|
64
|
+
- Limit pronouns when introducing new terms (repeat the term to reinforce it)
|
|
65
|
+
- Ampersands only in proper nouns, never as substitute for "and"
|
|
66
|
+
|
|
67
|
+
## Terminology Preferences
|
|
68
|
+
|
|
69
|
+
Use familiar terms from tools people already know:
|
|
70
|
+
|
|
71
|
+
- "Summarize" (like Excel) instead of "aggregate"
|
|
72
|
+
- "Take a look at" instead of "reference"
|
|
73
|
+
- "Filter" instead of technical database terms when appropriate
|
|
74
|
+
|
|
75
|
+
## Red Flags
|
|
76
|
+
|
|
77
|
+
Avoid these patterns:
|
|
78
|
+
|
|
79
|
+
- Multiple exclamation points
|
|
80
|
+
- Linking "here"
|
|
81
|
+
- Bullet lists to explain (use prose)
|
|
82
|
+
- Numbers that will change (guard against change)
|
|
83
|
+
- Describing things as "easy" or "simple"
|
|
84
|
+
- Stock photography-worthy content
|