wogiflow 1.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/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- package/templates/trace.md +69 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Skill Creation Wizard
|
|
5
|
+
*
|
|
6
|
+
* Creates new skills from templates with interactive prompts.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* flow skill-create # Interactive mode
|
|
10
|
+
* flow skill-create <name> # Create with name
|
|
11
|
+
* flow skill-create <name> --from-patterns # Create from feedback patterns
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const readline = require('readline');
|
|
17
|
+
const { getProjectRoot, colors } = require('./flow-utils');
|
|
18
|
+
|
|
19
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
20
|
+
const SKILLS_DIR = path.join(PROJECT_ROOT, '.claude', 'skills');
|
|
21
|
+
const TEMPLATE_DIR = path.join(SKILLS_DIR, '_template');
|
|
22
|
+
|
|
23
|
+
function log(color, ...args) {
|
|
24
|
+
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function prompt(question, defaultValue = '') {
|
|
28
|
+
const rl = readline.createInterface({
|
|
29
|
+
input: process.stdin,
|
|
30
|
+
output: process.stdout
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const defaultHint = defaultValue ? ` (${defaultValue})` : '';
|
|
34
|
+
|
|
35
|
+
return new Promise(resolve => {
|
|
36
|
+
rl.question(`${question}${defaultHint}: `, answer => {
|
|
37
|
+
rl.close();
|
|
38
|
+
resolve(answer.trim() || defaultValue);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function confirm(question) {
|
|
44
|
+
const answer = await prompt(`${question} (y/N)`);
|
|
45
|
+
return answer.toLowerCase() === 'y';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function copyDirectory(src, dest, replacements = {}) {
|
|
49
|
+
if (!fs.existsSync(src)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
54
|
+
|
|
55
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
56
|
+
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const srcPath = path.join(src, entry.name);
|
|
59
|
+
const destPath = path.join(dest, entry.name);
|
|
60
|
+
|
|
61
|
+
if (entry.isDirectory()) {
|
|
62
|
+
copyDirectory(srcPath, destPath, replacements);
|
|
63
|
+
} else {
|
|
64
|
+
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
65
|
+
|
|
66
|
+
// Apply replacements
|
|
67
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
68
|
+
content = content.replace(new RegExp(`{{${key}}}`, 'g'), value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fs.writeFileSync(destPath, content);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function createSkill(name, options = {}) {
|
|
79
|
+
const skillPath = path.join(SKILLS_DIR, name);
|
|
80
|
+
|
|
81
|
+
if (fs.existsSync(skillPath)) {
|
|
82
|
+
log('red', `Skill '${name}' already exists at ${skillPath}`);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
log('cyan', `\nš¦ Creating skill: ${name}\n`);
|
|
87
|
+
|
|
88
|
+
// Gather information
|
|
89
|
+
const description = options.description || await prompt('Short description');
|
|
90
|
+
const filePatterns = options.filePatterns || await prompt('File patterns (comma-separated)', '*.ts');
|
|
91
|
+
const useCases = options.useCases || await prompt('Use cases (comma-separated)', 'General development');
|
|
92
|
+
|
|
93
|
+
const today = new Date().toISOString().split('T')[0];
|
|
94
|
+
|
|
95
|
+
const replacements = {
|
|
96
|
+
SKILL_NAME: name,
|
|
97
|
+
SHORT_DESCRIPTION: description,
|
|
98
|
+
DATE: today,
|
|
99
|
+
FILE_PATTERN_1: filePatterns.split(',')[0]?.trim() || '*.ts',
|
|
100
|
+
FILE_PATTERN_2: filePatterns.split(',')[1]?.trim() || '*.tsx',
|
|
101
|
+
USE_CASE_1: useCases.split(',')[0]?.trim() || 'General development',
|
|
102
|
+
USE_CASE_2: useCases.split(',')[1]?.trim() || 'Code generation'
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Copy template
|
|
106
|
+
if (!fs.existsSync(TEMPLATE_DIR)) {
|
|
107
|
+
log('yellow', 'Template directory not found, creating basic structure...');
|
|
108
|
+
|
|
109
|
+
fs.mkdirSync(skillPath, { recursive: true });
|
|
110
|
+
fs.mkdirSync(path.join(skillPath, 'knowledge'));
|
|
111
|
+
fs.mkdirSync(path.join(skillPath, 'rules'));
|
|
112
|
+
fs.mkdirSync(path.join(skillPath, 'commands'));
|
|
113
|
+
fs.mkdirSync(path.join(skillPath, 'templates'));
|
|
114
|
+
|
|
115
|
+
// Create minimal skill.md
|
|
116
|
+
const skillMd = `---
|
|
117
|
+
name: ${name}
|
|
118
|
+
version: 1.0.0
|
|
119
|
+
description: ${description}
|
|
120
|
+
scope: project
|
|
121
|
+
lastUpdated: ${today}
|
|
122
|
+
learningCount: 0
|
|
123
|
+
successRate: 0
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
# ${name} Skill
|
|
127
|
+
|
|
128
|
+
## When to Use
|
|
129
|
+
|
|
130
|
+
- ${replacements.USE_CASE_1}
|
|
131
|
+
- ${replacements.USE_CASE_2}
|
|
132
|
+
|
|
133
|
+
## File Patterns
|
|
134
|
+
|
|
135
|
+
- \`${replacements.FILE_PATTERN_1}\`
|
|
136
|
+
- \`${replacements.FILE_PATTERN_2}\`
|
|
137
|
+
|
|
138
|
+
## Quick Reference
|
|
139
|
+
|
|
140
|
+
_Add key patterns here._
|
|
141
|
+
|
|
142
|
+
## Progressive Content
|
|
143
|
+
|
|
144
|
+
| File | When to Load |
|
|
145
|
+
|------|--------------|
|
|
146
|
+
| \`knowledge/learnings.md\` | Starting a task |
|
|
147
|
+
| \`knowledge/patterns.md\` | Looking for examples |
|
|
148
|
+
| \`rules/conventions.md\` | Writing code |
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
fs.writeFileSync(path.join(skillPath, 'skill.md'), skillMd);
|
|
152
|
+
|
|
153
|
+
// Create empty knowledge files
|
|
154
|
+
fs.writeFileSync(path.join(skillPath, 'knowledge', 'learnings.md'), '# Learnings Log\n\n_No learnings yet._\n');
|
|
155
|
+
fs.writeFileSync(path.join(skillPath, 'knowledge', 'patterns.md'), '# Successful Patterns\n\n_No patterns yet._\n');
|
|
156
|
+
fs.writeFileSync(path.join(skillPath, 'knowledge', 'anti-patterns.md'), '# Anti-Patterns\n\n_No anti-patterns yet._\n');
|
|
157
|
+
|
|
158
|
+
} else {
|
|
159
|
+
copyDirectory(TEMPLATE_DIR, skillPath, replacements);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
log('green', `\nā
Skill created: ${skillPath}\n`);
|
|
163
|
+
|
|
164
|
+
log('white', 'Next steps:');
|
|
165
|
+
log('dim', ` 1. Edit ${path.join(skillPath, 'skill.md')} to customize`);
|
|
166
|
+
log('dim', ` 2. Add rules to ${path.join(skillPath, 'rules/')}`);
|
|
167
|
+
log('dim', ` 3. Add commands to ${path.join(skillPath, 'commands/')}`);
|
|
168
|
+
log('dim', ` 4. Install with: /wogi-skills add ${name}`);
|
|
169
|
+
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function createFromPatterns() {
|
|
174
|
+
const feedbackPath = path.join(PROJECT_ROOT, '.workflow', 'state', 'feedback-patterns.md');
|
|
175
|
+
|
|
176
|
+
if (!fs.existsSync(feedbackPath)) {
|
|
177
|
+
log('yellow', 'No feedback-patterns.md found');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const content = fs.readFileSync(feedbackPath, 'utf-8');
|
|
182
|
+
|
|
183
|
+
// Find entries with #needs-skill tag
|
|
184
|
+
const lines = content.split('\n');
|
|
185
|
+
const needsSkill = lines.filter(line => line.includes('#needs-skill'));
|
|
186
|
+
|
|
187
|
+
if (needsSkill.length === 0) {
|
|
188
|
+
log('dim', 'No patterns flagged with #needs-skill');
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
log('cyan', `\nFound ${needsSkill.length} patterns needing skills:\n`);
|
|
193
|
+
|
|
194
|
+
for (const line of needsSkill.slice(0, 5)) {
|
|
195
|
+
log('dim', ` ${line}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
console.log('');
|
|
199
|
+
|
|
200
|
+
// Extract common file extensions
|
|
201
|
+
const extensions = new Set();
|
|
202
|
+
for (const line of needsSkill) {
|
|
203
|
+
const extMatch = line.match(/\.(ts|tsx|js|jsx|py|go|rs|java|rb|vue|svelte)/g);
|
|
204
|
+
if (extMatch) {
|
|
205
|
+
extMatch.forEach(ext => extensions.add('*' + ext));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (extensions.size > 0) {
|
|
210
|
+
const suggestedPatterns = Array.from(extensions).join(', ');
|
|
211
|
+
const shouldCreate = await confirm(`Create skill for patterns: ${suggestedPatterns}?`);
|
|
212
|
+
|
|
213
|
+
if (shouldCreate) {
|
|
214
|
+
const name = await prompt('Skill name');
|
|
215
|
+
await createSkill(name, { filePatterns: suggestedPatterns });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function showHelp() {
|
|
221
|
+
console.log(`
|
|
222
|
+
Wogi Flow Skill Creator
|
|
223
|
+
|
|
224
|
+
Usage:
|
|
225
|
+
flow skill-create # Interactive mode
|
|
226
|
+
flow skill-create <name> # Create skill with name
|
|
227
|
+
flow skill-create --from-patterns # Create from feedback patterns
|
|
228
|
+
flow skill-create --list # List existing skills
|
|
229
|
+
|
|
230
|
+
Options:
|
|
231
|
+
--from-patterns Analyze feedback-patterns.md for skill candidates
|
|
232
|
+
--list List existing skills
|
|
233
|
+
--help, -h Show this help
|
|
234
|
+
|
|
235
|
+
Examples:
|
|
236
|
+
flow skill-create react # Create 'react' skill
|
|
237
|
+
flow skill-create --from-patterns # Create from accumulated patterns
|
|
238
|
+
`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function listSkills() {
|
|
242
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
243
|
+
log('dim', 'No skills directory found');
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const dirs = fs.readdirSync(SKILLS_DIR);
|
|
248
|
+
const skills = dirs.filter(d => {
|
|
249
|
+
if (d.startsWith('_')) return false;
|
|
250
|
+
const skillPath = path.join(SKILLS_DIR, d);
|
|
251
|
+
return fs.statSync(skillPath).isDirectory();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (skills.length === 0) {
|
|
255
|
+
log('dim', 'No skills found');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
log('cyan', '\nInstalled Skills:\n');
|
|
260
|
+
|
|
261
|
+
for (const skill of skills) {
|
|
262
|
+
const skillPath = path.join(SKILLS_DIR, skill);
|
|
263
|
+
const hasKnowledge = fs.existsSync(path.join(skillPath, 'knowledge'));
|
|
264
|
+
const knowledgeIcon = hasKnowledge ? 'š' : 'š¦';
|
|
265
|
+
|
|
266
|
+
log('white', ` ${knowledgeIcon} ${skill}`);
|
|
267
|
+
|
|
268
|
+
// Try to read description
|
|
269
|
+
const mdPath = path.join(skillPath, 'skill.md');
|
|
270
|
+
const legacyPath = path.join(skillPath, 'SKILL.md');
|
|
271
|
+
const actualPath = fs.existsSync(mdPath) ? mdPath : legacyPath;
|
|
272
|
+
|
|
273
|
+
if (fs.existsSync(actualPath)) {
|
|
274
|
+
const content = fs.readFileSync(actualPath, 'utf-8');
|
|
275
|
+
const descMatch = content.match(/description:\s*["']?([^"'\n]+)/);
|
|
276
|
+
if (descMatch) {
|
|
277
|
+
log('dim', ` ${descMatch[1].trim()}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
console.log('');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function main() {
|
|
286
|
+
const args = process.argv.slice(2);
|
|
287
|
+
|
|
288
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
289
|
+
showHelp();
|
|
290
|
+
process.exit(0);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (args.includes('--list')) {
|
|
294
|
+
listSkills();
|
|
295
|
+
process.exit(0);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (args.includes('--from-patterns')) {
|
|
299
|
+
await createFromPatterns();
|
|
300
|
+
process.exit(0);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Get skill name from args or prompt
|
|
304
|
+
let name = args.find(a => !a.startsWith('-'));
|
|
305
|
+
|
|
306
|
+
if (!name) {
|
|
307
|
+
log('cyan', '\nš ļø Skill Creation Wizard\n');
|
|
308
|
+
name = await prompt('Skill name (lowercase, no spaces)');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!name) {
|
|
312
|
+
log('red', 'Skill name is required');
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Validate name
|
|
317
|
+
const validName = /^[a-z][a-z0-9-]*$/;
|
|
318
|
+
if (!validName.test(name)) {
|
|
319
|
+
log('red', 'Skill name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens');
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
await createSkill(name);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
main().catch(e => {
|
|
327
|
+
log('red', `Error: ${e.message}`);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
});
|