@tmddev/tmd 0.1.0 → 0.3.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/README.md +197 -5
- package/dist/cli.js +70 -10
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +60 -0
- package/dist/commands/pipeline.d.ts +26 -0
- package/dist/commands/pipeline.js +168 -0
- package/dist/commands/schemas.d.ts +4 -0
- package/dist/commands/schemas.js +57 -0
- package/dist/commands/skills.d.ts +1 -1
- package/dist/commands/skills.js +247 -162
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.js +179 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +65 -0
- package/dist/tmd-skills +0 -0
- package/dist/types.d.ts +21 -1
- package/dist/utils/github.d.ts +18 -0
- package/dist/utils/github.js +165 -0
- package/dist/utils/paths.d.ts +1 -0
- package/dist/utils/paths.js +5 -1
- package/dist/utils/pipeline-config.d.ts +37 -0
- package/dist/utils/pipeline-config.js +117 -0
- package/dist/utils/pipeline.d.ts +81 -0
- package/dist/utils/pipeline.js +580 -0
- package/dist/utils/skills.d.ts +10 -2
- package/dist/utils/skills.js +152 -150
- package/dist/utils/skillssh.d.ts +1 -1
- package/dist/utils/skillssh.js +39 -27
- package/dist/utils/step-executor.d.ts +58 -0
- package/dist/utils/step-executor.js +374 -0
- package/dist/utils/templates.d.ts +1 -0
- package/dist/utils/templates.js +30 -0
- package/package.json +22 -21
- package/scripts/postinstall.js +11 -8
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import yaml from 'js-yaml';
|
|
5
|
+
import { getSchemasDir } from '../utils/paths.js';
|
|
6
|
+
function getBase() {
|
|
7
|
+
return process.cwd();
|
|
8
|
+
}
|
|
9
|
+
export function schemasCommand(opts) {
|
|
10
|
+
const base = getBase();
|
|
11
|
+
const schemasRoot = join(base, getSchemasDir());
|
|
12
|
+
const asJson = opts?.json ?? false;
|
|
13
|
+
if (!existsSync(schemasRoot)) {
|
|
14
|
+
if (asJson) {
|
|
15
|
+
console.log(JSON.stringify([]));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.log(chalk.dim('No schemas found.'));
|
|
19
|
+
}
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const entries = readdirSync(schemasRoot, { withFileTypes: true })
|
|
23
|
+
.filter((d) => d.isDirectory())
|
|
24
|
+
.map((d) => d.name);
|
|
25
|
+
const result = [];
|
|
26
|
+
for (const name of entries) {
|
|
27
|
+
const schemaPath = join(schemasRoot, name, 'schema.yaml');
|
|
28
|
+
if (!existsSync(schemaPath))
|
|
29
|
+
continue;
|
|
30
|
+
let desc = '';
|
|
31
|
+
try {
|
|
32
|
+
const data = yaml.load(readFileSync(schemaPath, 'utf-8'));
|
|
33
|
+
const d = data != null && typeof data === 'object' ? data : null;
|
|
34
|
+
desc = d ? (d.description ?? d.name ?? name) : name;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
desc = name;
|
|
38
|
+
}
|
|
39
|
+
result.push({ name, description: desc, path: join(schemasRoot, name) });
|
|
40
|
+
}
|
|
41
|
+
if (asJson) {
|
|
42
|
+
console.log(JSON.stringify(result));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (result.length === 0) {
|
|
46
|
+
console.log(chalk.dim('No schemas found.'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
console.log(chalk.bold('Schemas'));
|
|
50
|
+
console.log('─'.repeat(60));
|
|
51
|
+
for (const r of result) {
|
|
52
|
+
console.log(` ${chalk.cyan(r.name)}`);
|
|
53
|
+
console.log(` ${chalk.dim(r.description)}`);
|
|
54
|
+
}
|
|
55
|
+
console.log('─'.repeat(60));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { SkillsCommandOptions } from '../types.js';
|
|
2
|
-
export declare function skillsCommand(action?: string, name?: string, options?: SkillsCommandOptions): void
|
|
2
|
+
export declare function skillsCommand(action?: string, name?: string, options?: SkillsCommandOptions): Promise<void>;
|
|
3
3
|
//# sourceMappingURL=skills.d.ts.map
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,23 +1,151 @@
|
|
|
1
|
-
import { existsSync,
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
import { spawnSync } from 'child_process';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
2
5
|
import { getSkillsDir, getSkillDir } from '../utils/paths.js';
|
|
3
|
-
import { join } from 'path';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
4
7
|
import chalk from 'chalk';
|
|
5
8
|
import yaml from 'js-yaml';
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
const _dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const TMD_SKILLS_BIN = join(_dirname, '..', process.platform === 'win32' ? 'tmd-skills.exe' : 'tmd-skills');
|
|
11
|
+
function runTmdSkills(args) {
|
|
12
|
+
if (!existsSync(TMD_SKILLS_BIN)) {
|
|
13
|
+
console.error(chalk.red('✗ tmd-skills binary not found. Run pnpm build.'));
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const r = spawnSync(TMD_SKILLS_BIN, args, {
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
19
|
+
});
|
|
20
|
+
if (r.status !== 0) {
|
|
21
|
+
process.exit(r.status ?? 1);
|
|
22
|
+
}
|
|
23
|
+
return r.stdout;
|
|
24
|
+
}
|
|
25
|
+
function runTmdSkillsRemove(skillName, all) {
|
|
26
|
+
if (!existsSync(TMD_SKILLS_BIN)) {
|
|
27
|
+
console.error(chalk.red('✗ tmd-skills binary not found. Run pnpm build.'));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const args = ['remove', skillName, '--project-root', process.cwd()];
|
|
31
|
+
if (all)
|
|
32
|
+
args.push('--all');
|
|
33
|
+
const r = spawnSync(TMD_SKILLS_BIN, args, { stdio: 'inherit' });
|
|
34
|
+
if (r.status !== 0) {
|
|
35
|
+
process.exit(r.status ?? 1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function parseTags(tagsOpt) {
|
|
39
|
+
if (tagsOpt == null || tagsOpt === '')
|
|
40
|
+
return [];
|
|
41
|
+
return tagsOpt.split(',').map((s) => s.trim()).filter(Boolean);
|
|
42
|
+
}
|
|
43
|
+
function tagArgs(tag) {
|
|
44
|
+
if (!tag || tag.length === 0)
|
|
45
|
+
return [];
|
|
46
|
+
return tag.flatMap((t) => ['--tag', t]);
|
|
47
|
+
}
|
|
48
|
+
export async function skillsCommand(action, name, options) {
|
|
8
49
|
const skillsDir = getSkillsDir();
|
|
50
|
+
const cwd = process.cwd();
|
|
51
|
+
const base = () => ['--project-root', cwd];
|
|
9
52
|
if (!action || action === 'list') {
|
|
10
|
-
|
|
53
|
+
const out = runTmdSkills(['list', ...base(), ...tagArgs(options?.tag)]);
|
|
54
|
+
const skills = JSON.parse(out || '[]');
|
|
55
|
+
if (skills.length === 0) {
|
|
56
|
+
console.log(chalk.yellow('No skills found. Create one with: tmd plan "description" --skill'));
|
|
57
|
+
console.log(chalk.gray('Or add from skills.sh: tmd skills add <owner/repo>'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.bold('\nAvailable Skills:'));
|
|
61
|
+
console.log('─'.repeat(60));
|
|
62
|
+
for (const s of skills) {
|
|
63
|
+
let sourceTag = '';
|
|
64
|
+
if (s.source === 'skillssh')
|
|
65
|
+
sourceTag = chalk.magenta(' [skills.sh]');
|
|
66
|
+
else if (s.source === 'github')
|
|
67
|
+
sourceTag = chalk.blue(' [github]');
|
|
68
|
+
const repoInfo = s.repo ? chalk.gray(` (${s.repo})`) : '';
|
|
69
|
+
console.log(` ${chalk.cyan(s.name)}${sourceTag}${repoInfo}`);
|
|
70
|
+
console.log(` ${chalk.gray(s.description || 'No description')}`);
|
|
71
|
+
}
|
|
72
|
+
console.log('─'.repeat(60));
|
|
73
|
+
console.log(chalk.gray(`Total: ${String(skills.length)} skill(s)`));
|
|
11
74
|
}
|
|
12
75
|
else if (action === 'search') {
|
|
13
|
-
|
|
76
|
+
const out = runTmdSkills(['search', name ?? '', ...base(), ...tagArgs(options?.tag)]);
|
|
77
|
+
const skills = JSON.parse(out || '[]');
|
|
78
|
+
if (skills.length === 0) {
|
|
79
|
+
console.log(chalk.yellow(`No skills found matching: ${name ?? ''}`));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log(chalk.bold(`\nSearch Results for "${name ?? ''}":`));
|
|
83
|
+
console.log('─'.repeat(60));
|
|
84
|
+
for (const s of skills)
|
|
85
|
+
console.log(` ${chalk.cyan(s.name)}`);
|
|
86
|
+
console.log('─'.repeat(60));
|
|
87
|
+
console.log(chalk.gray(`Found: ${String(skills.length)} skill(s)`));
|
|
14
88
|
}
|
|
15
89
|
else if (action === 'show') {
|
|
16
90
|
if (!name) {
|
|
17
91
|
console.error(chalk.red('✗ Skill name required'));
|
|
18
92
|
process.exit(1);
|
|
19
93
|
}
|
|
20
|
-
|
|
94
|
+
const out = runTmdSkills(['get', name, ...base()]);
|
|
95
|
+
const { skill, skillMd } = JSON.parse(out);
|
|
96
|
+
console.log(chalk.bold(`\nSkill: ${chalk.cyan(skill.name)}`));
|
|
97
|
+
console.log('─'.repeat(60));
|
|
98
|
+
if (skillMd) {
|
|
99
|
+
console.log(chalk.bold('\nDescription:'));
|
|
100
|
+
console.log(skillMd);
|
|
101
|
+
}
|
|
102
|
+
console.log(chalk.bold('\nMetadata:'));
|
|
103
|
+
console.log(` Version: ${skill.version ?? 'N/A'}`);
|
|
104
|
+
if (skill.source === 'skillssh') {
|
|
105
|
+
console.log(` Source: ${chalk.magenta('skills.sh')}`);
|
|
106
|
+
console.log(` Repository: ${skill.repo ?? 'N/A'}`);
|
|
107
|
+
if (skill.imported_at)
|
|
108
|
+
console.log(` Imported: ${skill.imported_at}`);
|
|
109
|
+
}
|
|
110
|
+
else if (skill.source === 'github') {
|
|
111
|
+
console.log(` Source: ${chalk.blue('GitHub')}`);
|
|
112
|
+
console.log(` Repository: ${skill.repo ?? 'N/A'}`);
|
|
113
|
+
if (skill.branch)
|
|
114
|
+
console.log(` Branch: ${skill.branch}`);
|
|
115
|
+
if (skill.imported_at)
|
|
116
|
+
console.log(` Imported: ${skill.imported_at}`);
|
|
117
|
+
if (skill.repo)
|
|
118
|
+
console.log(` View on GitHub: ${chalk.underline(`https://github.com/${skill.repo}`)}`);
|
|
119
|
+
}
|
|
120
|
+
if (skill.tags && skill.tags.length > 0)
|
|
121
|
+
console.log(` Tags: ${skill.tags.join(', ')}`);
|
|
122
|
+
// Interface: tmd-skills get does not return it; try to read from metadata.yaml for compatibility
|
|
123
|
+
const skillDir = getSkillDir(skill.name);
|
|
124
|
+
const metaPath = join(skillDir, 'metadata.yaml');
|
|
125
|
+
if (existsSync(metaPath)) {
|
|
126
|
+
try {
|
|
127
|
+
const meta = yaml.load(readFileSync(metaPath, 'utf-8'));
|
|
128
|
+
if (meta.interface) {
|
|
129
|
+
console.log(chalk.bold('\nInterface:'));
|
|
130
|
+
if (meta.interface.input?.length) {
|
|
131
|
+
console.log(' Input:');
|
|
132
|
+
meta.interface.input.forEach((input) => {
|
|
133
|
+
console.log(` - ${input.name} (${input.type})${input.required ? ' [required]' : ''}`);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (meta.interface.output && Object.keys(meta.interface.output).length > 0) {
|
|
137
|
+
console.log(' Output:');
|
|
138
|
+
Object.entries(meta.interface.output).forEach(([k, v]) => {
|
|
139
|
+
console.log(` - ${k}: ${typeof v === 'string' ? v : String(v)}`);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
/* ignore */
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
console.log('─'.repeat(60));
|
|
21
149
|
}
|
|
22
150
|
else if (action === 'invoke') {
|
|
23
151
|
if (!name) {
|
|
@@ -31,162 +159,126 @@ export function skillsCommand(action, name, options) {
|
|
|
31
159
|
console.error(chalk.red('✗ Repository required (format: owner/repo)'));
|
|
32
160
|
process.exit(1);
|
|
33
161
|
}
|
|
34
|
-
|
|
162
|
+
if (options?.github) {
|
|
163
|
+
console.log(chalk.blue(`\nAdding skill from GitHub: ${name}`));
|
|
164
|
+
if (options.skill)
|
|
165
|
+
console.log(chalk.gray(` Skill: ${options.skill}`));
|
|
166
|
+
if (options.branch)
|
|
167
|
+
console.log(chalk.gray(` Branch: ${options.branch}`));
|
|
168
|
+
console.log('─'.repeat(60));
|
|
169
|
+
const args = ['import-github', name, ...base(), ...(options.skill ? ['--skill', options.skill] : []), ...(options.branch ? ['--branch', options.branch] : []), ...(options.force ? ['--force'] : []), ...(options.all ? ['--all'] : [])];
|
|
170
|
+
const out = runTmdSkills(args);
|
|
171
|
+
const skill = JSON.parse(out);
|
|
172
|
+
console.log(chalk.green(`✓ Skill added: ${skill.name}`));
|
|
173
|
+
console.log(chalk.gray(` Location: ${getSkillDir(skill.name)}`));
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(chalk.blue(`\nAdding skill from skills.sh: ${name}${options?.skill != null ? ` (skill: ${options.skill})` : ''}`));
|
|
177
|
+
console.log('─'.repeat(60));
|
|
178
|
+
const args = ['import-skillssh', name, ...base(), ...(options?.skill ? ['--skill', options.skill] : []), ...(options?.all ? ['--all'] : [])];
|
|
179
|
+
const out = runTmdSkills(args);
|
|
180
|
+
const skill = JSON.parse(out);
|
|
181
|
+
console.log(chalk.green(`✓ Skill added: ${skill.name}`));
|
|
182
|
+
console.log(chalk.gray(` Location: ${getSkillDir(skill.name)}`));
|
|
183
|
+
}
|
|
35
184
|
}
|
|
36
|
-
else {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
185
|
+
else if (action === 'create') {
|
|
186
|
+
if (!name) {
|
|
187
|
+
console.error(chalk.red('✗ Skill name required for create'));
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
const args = ['create', '--name', name, ...base(), ...(options?.description ? ['--description', options.description] : []), ...(options?.tags ? ['--tags', parseTags(options.tags).join(',')] : []), ...(options?.all ? ['--all'] : [])];
|
|
191
|
+
runTmdSkills(args);
|
|
192
|
+
console.log(chalk.green(`✓ Skill created: ${name}`));
|
|
193
|
+
console.log(chalk.gray(` Location: ${getSkillDir(name)}`));
|
|
40
194
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
195
|
+
else if (action === 'update') {
|
|
196
|
+
if (!name) {
|
|
197
|
+
console.error(chalk.red('✗ Skill name required for update'));
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
const o = options ?? {};
|
|
201
|
+
const hasDesc = o.description != null;
|
|
202
|
+
const hasTags = o.tags != null;
|
|
203
|
+
if (!hasDesc && !hasTags) {
|
|
204
|
+
console.error(chalk.red('✗ Provide at least --description or --tags for update'));
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
const args = [
|
|
208
|
+
'update',
|
|
209
|
+
'--name',
|
|
210
|
+
name,
|
|
211
|
+
...base(),
|
|
212
|
+
...(hasDesc && typeof o.description === 'string' ? ['--description', o.description] : []),
|
|
213
|
+
...(hasTags && typeof o.tags === 'string' ? ['--tags', parseTags(o.tags).join(',')] : []),
|
|
214
|
+
...(o.all ? ['--all'] : []),
|
|
215
|
+
];
|
|
216
|
+
runTmdSkills(args);
|
|
217
|
+
console.log(chalk.green(`✓ Skill updated: ${name}`));
|
|
218
|
+
}
|
|
219
|
+
else if (action === 'remove') {
|
|
220
|
+
if (!name) {
|
|
221
|
+
console.error(chalk.red('✗ Skill name required for remove'));
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
const opts = options ?? {};
|
|
225
|
+
if (opts.all) {
|
|
226
|
+
await removeSkillsByPattern(name, options);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
await removeSkillFromCli(name, options);
|
|
230
|
+
}
|
|
51
231
|
}
|
|
52
232
|
else {
|
|
53
|
-
|
|
54
|
-
console.
|
|
233
|
+
console.error(chalk.red(`✗ Unknown action: ${action}`));
|
|
234
|
+
console.log(chalk.gray('Available actions: list, search, show, invoke, add, create, update, remove'));
|
|
55
235
|
process.exit(1);
|
|
56
236
|
}
|
|
57
237
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
238
|
+
async function removeSkillsByPattern(pattern, options) {
|
|
239
|
+
const cwd = process.cwd();
|
|
240
|
+
const out = runTmdSkills(['list', '--project-root', cwd]);
|
|
241
|
+
const skills = JSON.parse(out || '[]');
|
|
242
|
+
const matches = skills.filter((s) => s.name.includes(pattern));
|
|
243
|
+
if (matches.length === 0) {
|
|
244
|
+
console.error(chalk.red(`✗ No skills matching '${pattern}'`));
|
|
245
|
+
process.exit(1);
|
|
63
246
|
}
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
console.log(chalk.
|
|
69
|
-
console.log(chalk.gray('Or add from skills.sh: tmd skills add <owner/repo>'));
|
|
247
|
+
const opts = options ?? {};
|
|
248
|
+
if (opts.force) {
|
|
249
|
+
for (const s of matches)
|
|
250
|
+
runTmdSkillsRemove(s.name, true);
|
|
251
|
+
console.log(chalk.green(`✓ Removed ${String(matches.length)} skill(s) matching '${pattern}'`));
|
|
70
252
|
return;
|
|
71
253
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const sourceTag = metadata.source === 'skillssh' ? chalk.magenta(' [skills.sh]') : '';
|
|
82
|
-
const repoInfo = metadata.repo ? chalk.gray(` (${metadata.repo})`) : '';
|
|
83
|
-
console.log(` ${chalk.cyan(skillName)}${sourceTag}${repoInfo}`);
|
|
84
|
-
console.log(` ${chalk.gray(description)}`);
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
console.log(` ${chalk.cyan(skillName)}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
console.log(` ${chalk.cyan(skillName)}`);
|
|
92
|
-
}
|
|
254
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
255
|
+
const answer = await new Promise((resolve) => {
|
|
256
|
+
rl.question(`Remove ${String(matches.length)} skill(s) matching ${chalk.cyan(`'${pattern}'`)}? [y/N] `, resolve);
|
|
257
|
+
});
|
|
258
|
+
rl.close();
|
|
259
|
+
if (answer.trim().toLowerCase() === 'y') {
|
|
260
|
+
for (const s of matches)
|
|
261
|
+
runTmdSkillsRemove(s.name, true);
|
|
262
|
+
console.log(chalk.green(`✓ Removed ${String(matches.length)} skill(s) matching '${pattern}'`));
|
|
93
263
|
}
|
|
94
|
-
console.log('─'.repeat(60));
|
|
95
|
-
console.log(chalk.gray(`Total: ${String(skills.length)} skill(s)`));
|
|
96
264
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
265
|
+
async function removeSkillFromCli(skillName, options) {
|
|
266
|
+
const opts = options ?? {};
|
|
267
|
+
const all = opts.all ?? false;
|
|
268
|
+
if (opts.force) {
|
|
269
|
+
runTmdSkillsRemove(skillName, all);
|
|
270
|
+
console.log(chalk.green(`✓ Skill removed: ${skillName}`));
|
|
100
271
|
return;
|
|
101
272
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
.
|
|
105
|
-
const results = skills.filter(skillName => {
|
|
106
|
-
const skillDir = getSkillDir(skillName);
|
|
107
|
-
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
108
|
-
const skillPath = join(skillDir, 'skill.md');
|
|
109
|
-
if (existsSync(metadataPath)) {
|
|
110
|
-
try {
|
|
111
|
-
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
112
|
-
const text = `${skillName} ${metadata.description ?? ''} ${metadata.tags?.join(' ') ?? ''}`.toLowerCase();
|
|
113
|
-
return text.includes(query.toLowerCase());
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
return skillName.toLowerCase().includes(query.toLowerCase());
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (existsSync(skillPath)) {
|
|
120
|
-
const content = readFileSync(skillPath, 'utf-8').toLowerCase();
|
|
121
|
-
return content.includes(query.toLowerCase());
|
|
122
|
-
}
|
|
123
|
-
return skillName.toLowerCase().includes(query.toLowerCase());
|
|
273
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
274
|
+
const answer = await new Promise((resolve) => {
|
|
275
|
+
rl.question(`Remove skill ${chalk.cyan(skillName)}? [y/N] `, resolve);
|
|
124
276
|
});
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
console.log(chalk.bold(`\nSearch Results for "${query}":`));
|
|
130
|
-
console.log('─'.repeat(60));
|
|
131
|
-
for (const skillName of results) {
|
|
132
|
-
console.log(` ${chalk.cyan(skillName)}`);
|
|
133
|
-
}
|
|
134
|
-
console.log('─'.repeat(60));
|
|
135
|
-
console.log(chalk.gray(`Found: ${String(results.length)} skill(s)`));
|
|
136
|
-
}
|
|
137
|
-
function showSkill(skillName, _skillsDir) {
|
|
138
|
-
const skillDir = getSkillDir(skillName);
|
|
139
|
-
if (!existsSync(skillDir)) {
|
|
140
|
-
console.error(chalk.red(`✗ Skill not found: ${skillName}`));
|
|
141
|
-
process.exit(1);
|
|
277
|
+
rl.close();
|
|
278
|
+
if (answer.trim().toLowerCase() === 'y') {
|
|
279
|
+
runTmdSkillsRemove(skillName, all);
|
|
280
|
+
console.log(chalk.green(`✓ Skill removed: ${skillName}`));
|
|
142
281
|
}
|
|
143
|
-
console.log(chalk.bold(`\nSkill: ${chalk.cyan(skillName)}`));
|
|
144
|
-
console.log('─'.repeat(60));
|
|
145
|
-
// Read skill.md
|
|
146
|
-
const skillPath = join(skillDir, 'skill.md');
|
|
147
|
-
if (existsSync(skillPath)) {
|
|
148
|
-
const content = readFileSync(skillPath, 'utf-8');
|
|
149
|
-
console.log(chalk.bold('\nDescription:'));
|
|
150
|
-
console.log(content);
|
|
151
|
-
}
|
|
152
|
-
// Read metadata.yaml
|
|
153
|
-
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
154
|
-
if (existsSync(metadataPath)) {
|
|
155
|
-
try {
|
|
156
|
-
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
157
|
-
console.log(chalk.bold('\nMetadata:'));
|
|
158
|
-
console.log(` Version: ${metadata.version ?? 'N/A'}`);
|
|
159
|
-
if (metadata.source === 'skillssh') {
|
|
160
|
-
console.log(` Source: ${chalk.magenta('skills.sh')}`);
|
|
161
|
-
console.log(` Repository: ${metadata.repo ?? 'N/A'}`);
|
|
162
|
-
if (metadata.importedAt) {
|
|
163
|
-
console.log(` Imported: ${metadata.importedAt}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (metadata.tags && metadata.tags.length > 0) {
|
|
167
|
-
console.log(` Tags: ${metadata.tags.join(', ')}`);
|
|
168
|
-
}
|
|
169
|
-
if (metadata.interface) {
|
|
170
|
-
console.log(chalk.bold('\nInterface:'));
|
|
171
|
-
if (metadata.interface.input && metadata.interface.input.length > 0) {
|
|
172
|
-
console.log(' Input:');
|
|
173
|
-
metadata.interface.input.forEach((input) => {
|
|
174
|
-
console.log(` - ${input.name} (${input.type})${input.required ? ' [required]' : ''}`);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
if (metadata.interface.output && Object.keys(metadata.interface.output).length > 0) {
|
|
178
|
-
console.log(' Output:');
|
|
179
|
-
Object.entries(metadata.interface.output).forEach(([key, value]) => {
|
|
180
|
-
console.log(` - ${key}: ${String(value)}`);
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
console.log(chalk.yellow(' Could not parse metadata'));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
console.log('─'.repeat(60));
|
|
190
282
|
}
|
|
191
283
|
async function invokeSkill(skillName, inputParams, _skillsDir) {
|
|
192
284
|
const skillDir = getSkillDir(skillName);
|
|
@@ -196,47 +288,40 @@ async function invokeSkill(skillName, inputParams, _skillsDir) {
|
|
|
196
288
|
}
|
|
197
289
|
console.log(chalk.bold(`\nInvoking skill: ${chalk.cyan(skillName)}`));
|
|
198
290
|
console.log('─'.repeat(60));
|
|
199
|
-
// Parse input parameters
|
|
200
291
|
const params = {};
|
|
201
292
|
if (inputParams) {
|
|
202
|
-
inputParams.split(',').forEach(param => {
|
|
203
|
-
const [key, value] = param.split('=').map(s => s.trim());
|
|
204
|
-
if (key && value)
|
|
293
|
+
inputParams.split(',').forEach((param) => {
|
|
294
|
+
const [key, value] = param.split('=').map((s) => s.trim());
|
|
295
|
+
if (key && value)
|
|
205
296
|
params[key] = value;
|
|
206
|
-
}
|
|
207
297
|
});
|
|
208
298
|
}
|
|
209
|
-
// Load skill metadata to validate inputs
|
|
210
299
|
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
211
300
|
if (existsSync(metadataPath)) {
|
|
212
301
|
try {
|
|
213
302
|
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
214
|
-
if (metadata.interface?.input) {
|
|
303
|
+
if (metadata.interface?.input?.length) {
|
|
215
304
|
console.log(chalk.bold('\nInput Parameters:'));
|
|
216
305
|
metadata.interface.input.forEach((input) => {
|
|
217
306
|
const value = params[input.name] ?? (input.required ? chalk.red('MISSING') : 'not provided');
|
|
218
|
-
|
|
219
|
-
console.log(` ${input.name}: ${valueStr}`);
|
|
307
|
+
console.log(` ${input.name}: ${value}`);
|
|
220
308
|
});
|
|
221
309
|
}
|
|
222
310
|
}
|
|
223
311
|
catch {
|
|
224
|
-
|
|
312
|
+
/* ignore */
|
|
225
313
|
}
|
|
226
314
|
}
|
|
227
|
-
// Execute skill in isolated context
|
|
228
315
|
console.log(chalk.bold('\nExecution Context:'));
|
|
229
316
|
console.log(chalk.gray(' Isolated execution context'));
|
|
230
317
|
console.log(chalk.gray(' Cross-agent invocation'));
|
|
231
|
-
// Import and use executeSkill function
|
|
232
318
|
const { executeSkill } = await import('../utils/skills.js');
|
|
233
319
|
try {
|
|
234
|
-
await executeSkill(skillName, `invoke-${String(Date.now())}
|
|
320
|
+
await executeSkill(skillName, `invoke-${String(Date.now())}`, false, Infinity, params);
|
|
235
321
|
console.log(chalk.green('\n✓ Skill invocation completed'));
|
|
236
322
|
}
|
|
237
323
|
catch (e) {
|
|
238
|
-
|
|
239
|
-
console.error(chalk.red(`\n✗ Skill invocation failed: ${errorMessage}`));
|
|
324
|
+
console.error(chalk.red(`\n✗ Skill invocation failed: ${String(e)}`));
|
|
240
325
|
process.exit(1);
|
|
241
326
|
}
|
|
242
327
|
}
|