stigmergy 1.2.12 → 1.3.1-beta
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/README.md +39 -3
- package/STIGMERGY.md +3 -0
- package/config/builtin-skills.json +43 -0
- package/config/enhanced-cli-config.json +438 -0
- package/docs/CLI_TOOLS_AGENT_SKILL_ANALYSIS.md +463 -0
- package/docs/DESIGN_CLI_HELP_ANALYZER_REFACTOR.md +726 -0
- package/docs/ENHANCED_CLI_AGENT_SKILL_CONFIG.md +285 -0
- package/docs/IMPLEMENTATION_CHECKLIST_CLI_HELP_ANALYZER_REFACTOR.md +1268 -0
- package/docs/INSTALLER_ARCHITECTURE.md +257 -0
- package/docs/LESSONS_LEARNED.md +252 -0
- package/docs/SPECS_CLI_HELP_ANALYZER_REFACTOR.md +287 -0
- package/docs/SUDO_PROBLEM_AND_SOLUTION.md +529 -0
- package/docs/correct-skillsio-implementation.md +368 -0
- package/docs/development_guidelines.md +276 -0
- package/docs/independent-resume-implementation.md +198 -0
- package/docs/resumesession-final-implementation.md +195 -0
- package/docs/resumesession-usage.md +87 -0
- package/package.json +19 -9
- package/scripts/analyze-router.js +168 -0
- package/scripts/run-comprehensive-tests.js +230 -0
- package/scripts/run-quick-tests.js +90 -0
- package/scripts/test-runner.js +344 -0
- package/skills/resumesession/INDEPENDENT_SKILL.md +171 -0
- package/skills/resumesession/SKILL.md +127 -0
- package/skills/resumesession/__init__.py +33 -0
- package/skills/resumesession/implementations/simple-resume.js +13 -0
- package/src/adapters/claude/install_claude_integration.js +9 -1
- package/src/adapters/codebuddy/install_codebuddy_integration.js +3 -1
- package/src/adapters/codex/install_codex_integration.js +15 -5
- package/src/adapters/gemini/install_gemini_integration.js +3 -1
- package/src/adapters/qwen/install_qwen_integration.js +3 -1
- package/src/cli/commands/autoinstall.js +65 -0
- package/src/cli/commands/errors.js +190 -0
- package/src/cli/commands/independent-resume.js +395 -0
- package/src/cli/commands/install.js +179 -0
- package/src/cli/commands/permissions.js +108 -0
- package/src/cli/commands/project.js +485 -0
- package/src/cli/commands/scan.js +97 -0
- package/src/cli/commands/simple-resume.js +377 -0
- package/src/cli/commands/skills.js +158 -0
- package/src/cli/commands/status.js +113 -0
- package/src/cli/commands/stigmergy-resume.js +775 -0
- package/src/cli/commands/system.js +301 -0
- package/src/cli/commands/universal-resume.js +394 -0
- package/src/cli/router-beta.js +471 -0
- package/src/cli/utils/environment.js +75 -0
- package/src/cli/utils/formatters.js +47 -0
- package/src/cli/utils/skills_cache.js +92 -0
- package/src/core/cache_cleaner.js +1 -0
- package/src/core/cli_adapters.js +345 -0
- package/src/core/cli_help_analyzer.js +582 -26
- package/src/core/cli_path_detector.js +702 -709
- package/src/core/cli_tools.js +515 -160
- package/src/core/coordination/nodejs/CLIIntegrationManager.js +18 -0
- package/src/core/coordination/nodejs/HookDeploymentManager.js +242 -412
- package/src/core/coordination/nodejs/HookDeploymentManager.refactored.js +323 -0
- package/src/core/coordination/nodejs/generators/CLIAdapterGenerator.js +363 -0
- package/src/core/coordination/nodejs/generators/ResumeSessionGenerator.js +932 -0
- package/src/core/coordination/nodejs/generators/SkillsIntegrationGenerator.js +1395 -0
- package/src/core/coordination/nodejs/generators/index.js +12 -0
- package/src/core/enhanced_cli_installer.js +1208 -608
- package/src/core/enhanced_cli_parameter_handler.js +402 -0
- package/src/core/execution_mode_detector.js +222 -0
- package/src/core/installer.js +151 -106
- package/src/core/local_skill_scanner.js +732 -0
- package/src/core/multilingual/language-pattern-manager.js +1 -1
- package/src/core/skills/BuiltinSkillsDeployer.js +188 -0
- package/src/core/skills/StigmergySkillManager.js +123 -16
- package/src/core/skills/embedded-openskills/SkillParser.js +7 -3
- package/src/core/smart_router.js +291 -2
- package/src/index.js +10 -4
- package/src/utils.js +66 -7
- package/test/cli-integration.test.js +304 -0
- package/test/direct_smart_router_test.js +88 -0
- package/test/enhanced-cli-agent-skill-test.js +485 -0
- package/test/simple_test.js +82 -0
- package/test/smart_router_test_runner.js +123 -0
- package/test/smart_routing_edge_cases.test.js +284 -0
- package/test/smart_routing_simple_verification.js +139 -0
- package/test/smart_routing_verification.test.js +346 -0
- package/test/specific-cli-agent-skill-analysis.js +385 -0
- package/test/unit/smart_router.test.js +295 -0
- package/test/very_simple_test.js +54 -0
- package/src/cli/router.js +0 -1737
|
@@ -179,7 +179,7 @@ class LanguagePatternManager {
|
|
|
179
179
|
|
|
180
180
|
// Validate that the target CLI is supported
|
|
181
181
|
const supportedCLIs = [
|
|
182
|
-
'claude', 'gemini', 'qwen', 'iflow', 'qodercli', 'codebuddy', 'codex', 'copilot'
|
|
182
|
+
'claude', 'gemini', 'qwen', 'iflow', 'qodercli', 'codebuddy', 'codex', 'copilot', 'kode'
|
|
183
183
|
];
|
|
184
184
|
|
|
185
185
|
if (supportedCLIs.includes(targetCLI)) {
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BuiltinSkillsDeployer - Deploy built-in skills to CLI tools
|
|
3
|
+
* Automatically deploys stigmergy built-in skills during installation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
|
|
10
|
+
class BuiltinSkillsDeployer {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.configPath = path.join(process.cwd(), 'config', 'builtin-skills.json');
|
|
13
|
+
this.skillsBaseDir = process.cwd();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Load built-in skills configuration
|
|
18
|
+
*/
|
|
19
|
+
loadConfig() {
|
|
20
|
+
try {
|
|
21
|
+
if (!fs.existsSync(this.configPath)) {
|
|
22
|
+
console.warn('[BUILTIN_SKILLS] No built-in skills configuration found');
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const content = fs.readFileSync(this.configPath, 'utf8');
|
|
27
|
+
return JSON.parse(content);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('[BUILTIN_SKILLS] Failed to load configuration:', error.message);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Deploy built-in skills to all CLI tools
|
|
36
|
+
*/
|
|
37
|
+
async deployAll() {
|
|
38
|
+
const config = this.loadConfig();
|
|
39
|
+
if (!config) {
|
|
40
|
+
return { success: false, message: 'No built-in skills configuration found' };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(`[BUILTIN_SKILLS] Found ${config.skills.length} built-in skill(s)`);
|
|
44
|
+
|
|
45
|
+
const results = [];
|
|
46
|
+
for (const skill of config.skills) {
|
|
47
|
+
if (skill.deployment && skill.deployment.autoDeploy) {
|
|
48
|
+
const result = await this.deploySkill(skill);
|
|
49
|
+
results.push(result);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const successCount = results.filter(r => r.success).length;
|
|
54
|
+
console.log(`[BUILTIN_SKILLS] Deployed ${successCount}/${results.length} skill(s)`);
|
|
55
|
+
|
|
56
|
+
return { success: true, results };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Deploy a single built-in skill to target CLIs
|
|
61
|
+
*/
|
|
62
|
+
async deploySkill(skill) {
|
|
63
|
+
const targetCLIs = skill.deployment.targetCLIs || [];
|
|
64
|
+
const results = [];
|
|
65
|
+
|
|
66
|
+
for (const cliName of targetCLIs) {
|
|
67
|
+
const result = await this.deployToCLI(skill, cliName);
|
|
68
|
+
results.push(result);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const successCount = results.filter(r => r.success).length;
|
|
72
|
+
return {
|
|
73
|
+
success: successCount === results.length,
|
|
74
|
+
skillName: skill.name,
|
|
75
|
+
targetCLIs: targetCLIs,
|
|
76
|
+
deployedCount: successCount,
|
|
77
|
+
results
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Deploy skill to a specific CLI
|
|
83
|
+
*/
|
|
84
|
+
async deployToCLI(skill, cliName) {
|
|
85
|
+
try {
|
|
86
|
+
const cliHomeDir = path.join(os.homedir(), `.${cliName}`);
|
|
87
|
+
|
|
88
|
+
// Check if CLI exists
|
|
89
|
+
if (!fs.existsSync(cliHomeDir)) {
|
|
90
|
+
console.warn(`[BUILTIN_SKILLS] CLI not found: ${cliName} (${cliHomeDir})`);
|
|
91
|
+
return { success: false, cliName, skillName: skill.name, error: 'CLI not installed' };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Ensure skills directory exists
|
|
95
|
+
const cliSkillsRootDir = path.join(cliHomeDir, 'skills');
|
|
96
|
+
if (!fs.existsSync(cliSkillsRootDir)) {
|
|
97
|
+
try {
|
|
98
|
+
fs.mkdirSync(cliSkillsRootDir, { recursive: true });
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`[BUILTIN_SKILLS] Failed to create skills root directory for ${cliName}:`, error.message);
|
|
101
|
+
return { success: false, cliName, skillName: skill.name, error: error.message };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const cliSkillsDir = path.join(cliSkillsRootDir, skill.name);
|
|
106
|
+
|
|
107
|
+
// Create skills directory
|
|
108
|
+
if (!fs.existsSync(cliSkillsDir)) {
|
|
109
|
+
try {
|
|
110
|
+
fs.mkdirSync(cliSkillsDir, { recursive: true });
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error(`[BUILTIN_SKILLS] Failed to create skills directory for ${cliName}:`, error.message);
|
|
113
|
+
return { success: false, cliName, skillName: skill.name, error: error.message };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Get actual Stigmergy installation path for placeholder replacement
|
|
118
|
+
const stigmergyPath = process.cwd();
|
|
119
|
+
|
|
120
|
+
// Copy skill files
|
|
121
|
+
const files = skill.deployment.files || [];
|
|
122
|
+
for (const file of files) {
|
|
123
|
+
const sourcePath = path.join(this.skillsBaseDir, file.source);
|
|
124
|
+
const destPath = path.join(cliSkillsDir, path.basename(file.destination));
|
|
125
|
+
|
|
126
|
+
if (!fs.existsSync(sourcePath)) {
|
|
127
|
+
console.warn(`[BUILTIN_SKILLS] Source file not found: ${sourcePath}`);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
let content = fs.readFileSync(sourcePath, 'utf8');
|
|
133
|
+
// Replace placeholders with actual paths
|
|
134
|
+
content = content.replace(/\{stigmergy_path\}/g, stigmergyPath);
|
|
135
|
+
fs.writeFileSync(destPath, content);
|
|
136
|
+
console.log(`[BUILTIN_SKILLS] Deployed ${file.source} to ${cliName}`);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error(`[BUILTIN_SKILLS] Failed to copy ${file.source} to ${cliName}:`, error.message);
|
|
139
|
+
return { success: false, cliName, skillName: skill.name, error: error.message };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { success: true, cliName, skillName: skill.name };
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(`[BUILTIN_SKILLS] Failed to deploy ${skill.name} to ${cliName}:`, error.message);
|
|
146
|
+
return { success: false, cliName, skillName: skill.name, error: error.message };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if a skill is deployed to a CLI
|
|
152
|
+
*/
|
|
153
|
+
isDeployed(skillName, cliName) {
|
|
154
|
+
const cliSkillsDir = path.join(os.homedir(), `.${cliName}`, 'skills', skillName);
|
|
155
|
+
return fs.existsSync(cliSkillsDir);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Get deployment status for all built-in skills
|
|
160
|
+
*/
|
|
161
|
+
getDeploymentStatus() {
|
|
162
|
+
const config = this.loadConfig();
|
|
163
|
+
if (!config) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const status = [];
|
|
168
|
+
for (const skill of config.skills) {
|
|
169
|
+
const skillStatus = {
|
|
170
|
+
name: skill.name,
|
|
171
|
+
displayName: skill.displayName,
|
|
172
|
+
version: skill.version,
|
|
173
|
+
deployment: {}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const targetCLIs = skill.deployment.targetCLIs || [];
|
|
177
|
+
for (const cliName of targetCLIs) {
|
|
178
|
+
skillStatus.deployment[cliName] = this.isDeployed(skill.name, cliName);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
status.push(skillStatus);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return status;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export default BuiltinSkillsDeployer;
|
|
@@ -121,23 +121,45 @@ export class StigmergySkillManager {
|
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* Sync skills to CLI configuration files
|
|
124
|
+
* Also copies skills to CLI-specific directories and refreshes cache
|
|
124
125
|
* @returns {Promise<void>}
|
|
125
126
|
*/
|
|
126
127
|
async sync() {
|
|
127
|
-
console.log('[INFO] Syncing skills to CLI
|
|
128
|
-
|
|
128
|
+
console.log('[INFO] Syncing skills to CLI directories...');
|
|
129
|
+
|
|
129
130
|
try {
|
|
131
|
+
// Refresh the LocalSkillScanner cache
|
|
132
|
+
try {
|
|
133
|
+
// Import LocalSkillScanner (it's a CommonJS module)
|
|
134
|
+
const { createRequire } = await import('module');
|
|
135
|
+
const require = createRequire(import.meta.url);
|
|
136
|
+
const LocalSkillScanner = require('./local_skill_scanner.js');
|
|
137
|
+
|
|
138
|
+
const scanner = new LocalSkillScanner();
|
|
139
|
+
await scanner.initialize(true); // Force refresh
|
|
140
|
+
console.log('[INFO] Refreshed skills/agents cache');
|
|
141
|
+
} catch (err) {
|
|
142
|
+
// LocalSkillScanner might not be available, ignore
|
|
143
|
+
if (process.env.DEBUG === 'true') {
|
|
144
|
+
console.log('[DEBUG] LocalSkillScanner not available:', err.message);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
130
148
|
const skills = await this.reader.listSkills();
|
|
131
|
-
|
|
149
|
+
|
|
132
150
|
if (skills.length === 0) {
|
|
133
151
|
console.log('[INFO] No skills to sync');
|
|
134
152
|
return;
|
|
135
153
|
}
|
|
136
|
-
|
|
137
|
-
//
|
|
154
|
+
|
|
155
|
+
// Step 1: Copy skills to CLI-specific directories
|
|
156
|
+
console.log('[INFO] Copying skills to CLI directories...');
|
|
157
|
+
const copyResults = await this.syncSkillFiles(skills);
|
|
158
|
+
|
|
159
|
+
// Step 2: Generate <available_skills> XML
|
|
138
160
|
const skillsXml = this.generateSkillsXml(skills);
|
|
139
|
-
|
|
140
|
-
// All CLI configuration files to update
|
|
161
|
+
|
|
162
|
+
// Step 3: All CLI configuration files to update
|
|
141
163
|
const cliFiles = [
|
|
142
164
|
'AGENTS.md', // Universal config
|
|
143
165
|
'claude.md', // Claude CLI
|
|
@@ -147,17 +169,19 @@ export class StigmergySkillManager {
|
|
|
147
169
|
'qodercli.md', // Qoder CLI
|
|
148
170
|
'codebuddy.md', // CodeBuddy CLI
|
|
149
171
|
'copilot.md', // Copilot CLI
|
|
150
|
-
'codex.md'
|
|
172
|
+
'codex.md', // Codex CLI
|
|
173
|
+
'opencode.md', // OpenCode CLI
|
|
174
|
+
'oh-my-opencode.md' // Oh-My-OpenCode Plugin Manager
|
|
151
175
|
];
|
|
152
|
-
|
|
176
|
+
|
|
153
177
|
let syncedCount = 0;
|
|
154
178
|
let createdCount = 0;
|
|
155
179
|
let skippedCount = 0;
|
|
156
|
-
|
|
180
|
+
|
|
157
181
|
// Iterate through all CLI configuration files
|
|
158
182
|
for (const fileName of cliFiles) {
|
|
159
183
|
const filePath = path.join(process.cwd(), fileName);
|
|
160
|
-
|
|
184
|
+
|
|
161
185
|
try {
|
|
162
186
|
const result = await this.syncToFile(filePath, fileName, skillsXml);
|
|
163
187
|
if (result === 'synced') {
|
|
@@ -170,22 +194,105 @@ export class StigmergySkillManager {
|
|
|
170
194
|
skippedCount++;
|
|
171
195
|
}
|
|
172
196
|
}
|
|
173
|
-
|
|
197
|
+
|
|
174
198
|
// Output sync result summary
|
|
175
199
|
console.log(`\n[OK] Sync completed:`);
|
|
176
|
-
console.log(` -
|
|
200
|
+
console.log(` - Skills copied: ${copyResults.copied} to ${copyResults.targets} CLI directory(ies)`);
|
|
201
|
+
console.log(` - Config updated: ${syncedCount} file(s)`);
|
|
177
202
|
if (createdCount > 0) {
|
|
178
|
-
console.log(` -
|
|
203
|
+
console.log(` - Config created: ${createdCount} file(s)`);
|
|
179
204
|
}
|
|
180
205
|
if (skippedCount > 0) {
|
|
181
|
-
console.log(` -
|
|
206
|
+
console.log(` - Config skipped: ${skippedCount} file(s)`);
|
|
182
207
|
}
|
|
183
|
-
console.log(` -
|
|
208
|
+
console.log(` - Total skills: ${skills.length}`);
|
|
184
209
|
} catch (err) {
|
|
185
210
|
console.error(`[X] Sync failed: ${err.message}`);
|
|
186
211
|
throw err;
|
|
187
212
|
}
|
|
188
213
|
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Copy skill files to CLI-specific directories
|
|
217
|
+
* @private
|
|
218
|
+
* @param {Array} skills - List of skills to copy
|
|
219
|
+
* @returns {Promise<Object>} Copy results
|
|
220
|
+
*/
|
|
221
|
+
async syncSkillFiles(skills) {
|
|
222
|
+
const fsPromises = await import('fs/promises');
|
|
223
|
+
|
|
224
|
+
// Define CLI skill directories
|
|
225
|
+
const cliSkillDirs = [
|
|
226
|
+
{ name: 'Claude', path: path.join(os.homedir(), '.claude', 'skills') },
|
|
227
|
+
{ name: 'Universal', path: path.join(process.cwd(), '.agent', 'skills') },
|
|
228
|
+
{ name: 'Universal (global)', path: path.join(os.homedir(), '.agent', 'skills') }
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
let copiedCount = 0;
|
|
232
|
+
let targets = 0;
|
|
233
|
+
|
|
234
|
+
for (const cliDir of cliSkillDirs) {
|
|
235
|
+
try {
|
|
236
|
+
// Ensure CLI directory exists
|
|
237
|
+
await fsPromises.mkdir(cliDir.path, { recursive: true });
|
|
238
|
+
|
|
239
|
+
// Copy each skill
|
|
240
|
+
for (const skill of skills) {
|
|
241
|
+
const skillName = skill.name;
|
|
242
|
+
const sourceDir = path.join(this.skillsDir, skillName);
|
|
243
|
+
const targetDir = path.join(cliDir.path, skillName);
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
// Check if source exists
|
|
247
|
+
await fsPromises.access(sourceDir);
|
|
248
|
+
|
|
249
|
+
// Remove existing if present
|
|
250
|
+
await fsPromises.rm(targetDir, { recursive: true, force: true });
|
|
251
|
+
|
|
252
|
+
// Copy directory
|
|
253
|
+
await this.copyDirectoryRecursive(sourceDir, targetDir);
|
|
254
|
+
copiedCount++;
|
|
255
|
+
} catch (err) {
|
|
256
|
+
// Skip if source doesn't exist or copy fails
|
|
257
|
+
if (process.env.DEBUG === 'true') {
|
|
258
|
+
console.log(`[DEBUG] Skipped ${skillName} for ${cliDir.name}: ${err.message}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
targets++;
|
|
264
|
+
console.log(` [OK] Synced to ${cliDir.name}: ${cliDir.path}`);
|
|
265
|
+
} catch (err) {
|
|
266
|
+
console.log(` [INFO] Skipped ${cliDir.name}: ${err.message}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return { copied: copiedCount, targets: targets };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Recursively copy a directory
|
|
275
|
+
* @private
|
|
276
|
+
* @param {string} src - Source directory
|
|
277
|
+
* @param {string} dest - Destination directory
|
|
278
|
+
*/
|
|
279
|
+
async copyDirectoryRecursive(src, dest) {
|
|
280
|
+
const fsPromises = await import('fs/promises');
|
|
281
|
+
|
|
282
|
+
await fsPromises.mkdir(dest, { recursive: true });
|
|
283
|
+
const entries = await fsPromises.readdir(src, { withFileTypes: true });
|
|
284
|
+
|
|
285
|
+
for (const entry of entries) {
|
|
286
|
+
const srcPath = path.join(src, entry.name);
|
|
287
|
+
const destPath = path.join(dest, entry.name);
|
|
288
|
+
|
|
289
|
+
if (entry.isDirectory()) {
|
|
290
|
+
await this.copyDirectoryRecursive(srcPath, destPath);
|
|
291
|
+
} else {
|
|
292
|
+
await fsPromises.copyFile(srcPath, destPath);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
189
296
|
|
|
190
297
|
/**
|
|
191
298
|
* Sync skills to a single file
|
|
@@ -13,7 +13,9 @@ export class SkillParser {
|
|
|
13
13
|
* @returns {Object} Parsed metadata
|
|
14
14
|
*/
|
|
15
15
|
parseMetadata(content) {
|
|
16
|
-
|
|
16
|
+
// Normalize line endings to LF
|
|
17
|
+
const normalizedContent = content.replace(/\r\n/g, '\n');
|
|
18
|
+
const match = normalizedContent.match(/^---\n(.*?)\n---/s);
|
|
17
19
|
if (!match) {
|
|
18
20
|
return {};
|
|
19
21
|
}
|
|
@@ -78,8 +80,10 @@ export class SkillParser {
|
|
|
78
80
|
* @returns {string} Content without frontmatter
|
|
79
81
|
*/
|
|
80
82
|
extractContent(content) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
// Normalize line endings to LF
|
|
84
|
+
const normalizedContent = content.replace(/\r\n/g, '\n');
|
|
85
|
+
const match = normalizedContent.match(/^---\n.*?\n---\n(.*)$/s);
|
|
86
|
+
return match ? match[1].trim() : normalizedContent;
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/**
|