@xagent-ai/cli 1.0.1 → 1.1.1
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/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/README.md +280 -280
- package/README_CN.md +3 -3
- package/dist/ai-client.d.ts.map +1 -1
- package/dist/ai-client.js +84 -82
- package/dist/ai-client.js.map +1 -1
- package/dist/auth.d.ts +0 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +75 -105
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +166 -13
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +48 -7
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts +5 -5
- package/dist/context-compressor.js +8 -8
- package/dist/context-compressor.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts +7 -0
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +6 -3
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/action-parser/constants.d.ts +6 -0
- package/dist/gui-subagent/action-parser/constants.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/constants.js +5 -3
- package/dist/gui-subagent/action-parser/constants.js.map +1 -1
- package/dist/gui-subagent/action-parser/index.d.ts +6 -0
- package/dist/gui-subagent/action-parser/index.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/index.js +5 -3
- package/dist/gui-subagent/action-parser/index.js.map +1 -1
- package/dist/gui-subagent/action-parser/types.d.ts +4 -0
- package/dist/gui-subagent/action-parser/types.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/types.js +3 -3
- package/dist/gui-subagent/agent/gui-agent.d.ts +39 -0
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +164 -89
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/agent/index.d.ts +1 -1
- package/dist/gui-subagent/agent/index.d.ts.map +1 -1
- package/dist/gui-subagent/agent/index.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +27 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +6 -0
- package/dist/gui-subagent/index.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +140 -29
- package/dist/mcp.js.map +1 -1
- package/dist/remote-ai-client.d.ts +111 -0
- package/dist/remote-ai-client.d.ts.map +1 -0
- package/dist/remote-ai-client.js +558 -0
- package/dist/remote-ai-client.js.map +1 -0
- package/dist/sdk-output-adapter.d.ts +232 -0
- package/dist/sdk-output-adapter.d.ts.map +1 -0
- package/dist/sdk-output-adapter.js +636 -0
- package/dist/sdk-output-adapter.js.map +1 -0
- package/dist/sdk-session-v2.d.ts +13 -0
- package/dist/sdk-session-v2.d.ts.map +1 -0
- package/dist/sdk-session-v2.js +46 -0
- package/dist/sdk-session-v2.js.map +1 -0
- package/dist/sdk-session.d.ts +13 -0
- package/dist/sdk-session.d.ts.map +1 -0
- package/dist/sdk-session.js +48 -0
- package/dist/sdk-session.js.map +1 -0
- package/dist/session-manager.js +3 -3
- package/dist/session-manager.js.map +1 -1
- package/dist/session.d.ts +46 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +564 -117
- package/dist/session.js.map +1 -1
- package/dist/skill-invoker.d.ts +40 -4
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +310 -1184
- package/dist/skill-invoker.js.map +1 -1
- package/dist/skill-loader.d.ts +15 -1
- package/dist/skill-loader.d.ts.map +1 -1
- package/dist/skill-loader.js +49 -32
- package/dist/skill-loader.js.map +1 -1
- package/dist/slash-commands.d.ts +4 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +149 -15
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts +2 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +29 -3
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts +4 -5
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +131 -81
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/tools.d.ts +17 -6
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +264 -211
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/docs/architecture/mcp-integration-guide.md +194 -131
- package/docs/architecture/overview.md +169 -93
- package/docs/architecture/tool-system-design.md +56 -11
- package/docs/cli/commands.md +238 -189
- package/docs/smart-mode.md +281 -257
- package/docs/third-party-models.md +247 -256
- package/package.json +6 -2
- package/src/ai-client.ts +107 -105
- package/src/auth.ts +82 -116
- package/src/cancellation.ts +1 -1
- package/src/cli.ts +178 -13
- package/src/config.ts +57 -8
- package/src/context-compressor.ts +8 -8
- package/src/gui-subagent/action-parser/actionParser.ts +6 -3
- package/src/gui-subagent/action-parser/constants.ts +5 -3
- package/src/gui-subagent/action-parser/index.ts +5 -3
- package/src/gui-subagent/action-parser/types.ts +3 -3
- package/src/gui-subagent/agent/gui-agent.ts +210 -103
- package/src/gui-subagent/agent/index.ts +1 -1
- package/src/gui-subagent/index.ts +26 -2
- package/src/index.ts +18 -18
- package/src/logger.ts +1 -1
- package/src/mcp.ts +149 -30
- package/src/remote-ai-client.ts +671 -0
- package/src/session-manager.ts +3 -3
- package/src/session.ts +742 -178
- package/src/skill-invoker.ts +340 -1293
- package/src/skill-loader.ts +55 -34
- package/src/slash-commands.ts +165 -15
- package/src/smart-approval.ts +34 -3
- package/src/system-prompt-generator.ts +145 -88
- package/src/tools.ts +309 -224
- package/src/types.ts +0 -1
- package/scripts/init-skills-path.js +0 -58
package/src/skill-invoker.ts
CHANGED
|
@@ -333,138 +333,139 @@ export async function readSkillContent(skillPath: string, keywords: string[], ma
|
|
|
333
333
|
// SKILL Trigger Keywords Mapping
|
|
334
334
|
// ============================================================
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
336
|
+
// NOTE: SKILL_TRIGGERS is disabled for experiment purposes.
|
|
337
|
+
// Let the LLM decide which skill to use based on system prompt information.
|
|
338
|
+
|
|
339
|
+
// interface SkillTrigger {
|
|
340
|
+
// skillId: string;
|
|
341
|
+
// keywords: string[];
|
|
342
|
+
// category: string;
|
|
343
|
+
// }
|
|
344
|
+
|
|
345
|
+
// export const SKILL_TRIGGERS: Record<string, SkillTrigger> = {
|
|
346
|
+
// docx: {
|
|
347
|
+
// skillId: 'docx',
|
|
348
|
+
// keywords: [
|
|
349
|
+
// 'word document', 'docx', 'microsoft word', 'create word', 'edit word',
|
|
350
|
+
// 'create .docx', '.docx file', 'word file', 'document creation',
|
|
351
|
+
// 'word editing', 'tracked changes', 'comments'
|
|
352
|
+
// ],
|
|
353
|
+
// category: 'Document Processing'
|
|
354
|
+
// },
|
|
355
|
+
// pdf: {
|
|
356
|
+
// skillId: 'pdf',
|
|
357
|
+
// keywords: [
|
|
358
|
+
// 'pdf', 'create pdf', 'edit pdf', 'pdf document', 'pdf file',
|
|
359
|
+
// 'extract pdf', 'merge pdf', 'split pdf', 'pdf form', 'manipulate pdf'
|
|
360
|
+
// ],
|
|
361
|
+
// category: 'Document Processing'
|
|
362
|
+
// },
|
|
363
|
+
// pptx: {
|
|
364
|
+
// skillId: 'pptx',
|
|
365
|
+
// keywords: [
|
|
366
|
+
// 'powerpoint', 'ppt', 'pptx', 'presentation', 'slide',
|
|
367
|
+
// 'create presentation', 'edit powerpoint', 'create slides',
|
|
368
|
+
// 'powerpoint file', 'presentation file'
|
|
369
|
+
// ],
|
|
370
|
+
// category: 'Document Processing'
|
|
371
|
+
// },
|
|
372
|
+
// xlsx: {
|
|
373
|
+
// skillId: 'xlsx',
|
|
374
|
+
// keywords: [
|
|
375
|
+
// 'excel', 'spreadsheet', 'xlsx', 'create excel', 'edit spreadsheet',
|
|
376
|
+
// 'excel file', 'spreadsheet file', 'formulas', 'data analysis'
|
|
377
|
+
// ],
|
|
378
|
+
// category: 'Spreadsheet & Data'
|
|
379
|
+
// },
|
|
380
|
+
// frontend_design: {
|
|
381
|
+
// skillId: 'frontend-design',
|
|
382
|
+
// keywords: [
|
|
383
|
+
// 'web page', 'website', 'web app', 'frontend', 'ui', 'user interface',
|
|
384
|
+
// 'create website', 'build website', 'web component', 'html css',
|
|
385
|
+
// 'landing page', 'dashboard', 'react', 'vue', 'web interface'
|
|
386
|
+
// ],
|
|
387
|
+
// category: 'Frontend & Web Development'
|
|
388
|
+
// },
|
|
389
|
+
// web_artifacts_builder: {
|
|
390
|
+
// skillId: 'web-artifacts-builder',
|
|
391
|
+
// keywords: [
|
|
392
|
+
// 'complex react', 'react artifact', 'stateful artifact', 'routing',
|
|
393
|
+
// 'web artifact', 'interactive artifact', 'web-based tool'
|
|
394
|
+
// ],
|
|
395
|
+
// category: 'Frontend & Web Development'
|
|
396
|
+
// },
|
|
397
|
+
// webapp_testing: {
|
|
398
|
+
// skillId: 'webapp-testing',
|
|
399
|
+
// keywords: [
|
|
400
|
+
// 'test web', 'web testing', 'browser test', 'playwright', 'e2e test',
|
|
401
|
+
// 'frontend test', 'capture screenshot', 'verify web'
|
|
402
|
+
// ],
|
|
403
|
+
// category: 'Frontend & Web Development'
|
|
404
|
+
// },
|
|
405
|
+
// canvas_design: {
|
|
406
|
+
// skillId: 'canvas-design',
|
|
407
|
+
// keywords: [
|
|
408
|
+
// 'poster', 'artwork', 'visual art', 'canvas', 'design art',
|
|
409
|
+
// 'create poster', 'create artwork', 'visual design', 'graphic art'
|
|
410
|
+
// ],
|
|
411
|
+
// category: 'Visual & Creative Design'
|
|
412
|
+
// },
|
|
413
|
+
// algorithmic_art: {
|
|
414
|
+
// skillId: 'algorithmic-art',
|
|
415
|
+
// keywords: [
|
|
416
|
+
// 'generative art', 'algorithmic art', 'p5.js', 'particle system',
|
|
417
|
+
// 'flow field', 'creative coding', 'code art'
|
|
418
|
+
// ],
|
|
419
|
+
// category: 'Visual & Creative Design'
|
|
420
|
+
// },
|
|
421
|
+
// theme_factory: {
|
|
422
|
+
// skillId: 'theme-factory',
|
|
423
|
+
// keywords: [
|
|
424
|
+
// 'theme', 'color scheme', 'font theme', 'styling theme',
|
|
425
|
+
// 'consistent theme', 'apply theme', 'theme colors'
|
|
426
|
+
// ],
|
|
427
|
+
// category: 'Visual & Creative Design'
|
|
428
|
+
// },
|
|
429
|
+
// brand_guidelines: {
|
|
430
|
+
// skillId: 'brand-guidelines',
|
|
431
|
+
// keywords: [
|
|
432
|
+
// 'brand colors', 'brand guidelines', 'anthropic brand',
|
|
433
|
+
// 'official brand', 'brand styling'
|
|
434
|
+
// ],
|
|
435
|
+
// category: 'Visual & Creative Design'
|
|
436
|
+
// },
|
|
437
|
+
// slack_gif_creator: {
|
|
438
|
+
// skillId: 'slack-gif-creator',
|
|
439
|
+
// keywords: [
|
|
440
|
+
// 'slack gif', 'animated gif', 'gif for slack', 'slack animation'
|
|
441
|
+
// ],
|
|
442
|
+
// category: 'Visual & Creative Design'
|
|
443
|
+
// },
|
|
444
|
+
// mcp_builder: {
|
|
445
|
+
// skillId: 'mcp-builder',
|
|
446
|
+
// keywords: [
|
|
447
|
+
// 'mcp server', 'model context protocol', 'create mcp',
|
|
448
|
+
// 'mcp integration', 'external api integration'
|
|
449
|
+
// ],
|
|
450
|
+
// category: 'Development & Integration'
|
|
451
|
+
// },
|
|
452
|
+
// skill_creator: {
|
|
453
|
+
// skillId: 'skill-creator',
|
|
454
|
+
// keywords: [
|
|
455
|
+
// 'create skill', 'new skill', 'skill development',
|
|
456
|
+
// 'extend capabilities', 'custom skill'
|
|
457
|
+
// ],
|
|
458
|
+
// category: 'Development & Integration'
|
|
459
|
+
// },
|
|
460
|
+
// doc_coauthoring: {
|
|
461
|
+
// skillId: 'doc-coauthoring',
|
|
462
|
+
// keywords: [
|
|
463
|
+
// 'documentation', 'technical docs', 'write documentation',
|
|
464
|
+
// 'coauthor', 'doc writing', 'technical writing'
|
|
465
|
+
// ],
|
|
466
|
+
// category: 'Communication & Documentation'
|
|
467
|
+
// }
|
|
468
|
+
// };
|
|
468
469
|
|
|
469
470
|
// ============================================================
|
|
470
471
|
// SkillInvoker Main Class
|
|
@@ -473,7 +474,8 @@ const SKILL_TRIGGERS: Record<string, { skillId: string; keywords: string[]; cate
|
|
|
473
474
|
export class SkillInvoker {
|
|
474
475
|
private skillLoader: SkillLoader;
|
|
475
476
|
private initialized: boolean = false;
|
|
476
|
-
private skillCache: Map<string, SkillInfo> = new Map();
|
|
477
|
+
private skillCache: Map<string, SkillInfo> = new Map(); // Stores metadata only
|
|
478
|
+
private skillContentCache: Map<string, string> = new Map(); // Stores full SKILL.md content
|
|
477
479
|
|
|
478
480
|
constructor(skillLoader?: SkillLoader) {
|
|
479
481
|
this.skillLoader = skillLoader || getSkillLoader();
|
|
@@ -482,55 +484,90 @@ export class SkillInvoker {
|
|
|
482
484
|
async initialize(): Promise<void> {
|
|
483
485
|
if (this.initialized) return;
|
|
484
486
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
487
|
+
// Use discoverSkills to only discover directories without loading full content
|
|
488
|
+
const skillIds = await this.skillLoader.discoverSkills();
|
|
489
|
+
|
|
490
|
+
// Create minimal SkillInfo objects with metadata only
|
|
491
|
+
for (const skillId of skillIds) {
|
|
492
|
+
const skillPath = this.skillLoader.getSkillDirectory?.(skillId) || '';
|
|
493
|
+
const skillInfo: SkillInfo = {
|
|
494
|
+
id: skillId,
|
|
495
|
+
name: skillId,
|
|
496
|
+
description: '', // Will be loaded lazily
|
|
497
|
+
license: 'Unknown',
|
|
498
|
+
version: '1.0.0',
|
|
499
|
+
author: 'Anonymous',
|
|
500
|
+
category: '',
|
|
501
|
+
markdown: '', // Full content loaded lazily
|
|
502
|
+
skillsPath: skillPath
|
|
503
|
+
};
|
|
504
|
+
this.skillCache.set(skillId, skillInfo);
|
|
488
505
|
}
|
|
489
506
|
|
|
490
507
|
this.initialized = true;
|
|
491
508
|
}
|
|
492
509
|
|
|
493
510
|
/**
|
|
494
|
-
*
|
|
511
|
+
* Load skill metadata (name, description, category) from SKILL.md frontmatter
|
|
512
|
+
* This is called lazily when skill details are needed
|
|
495
513
|
*/
|
|
496
|
-
async
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
514
|
+
async loadSkillMetadata(skillId: string): Promise<void> {
|
|
515
|
+
const skill = this.skillCache.get(skillId);
|
|
516
|
+
if (!skill) return;
|
|
500
517
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
*/
|
|
504
|
-
async matchSkill(userInput: string): Promise<SkillMatcherResult | null> {
|
|
505
|
-
await this.initialize();
|
|
518
|
+
// Check if metadata already loaded
|
|
519
|
+
if (skill.description && skill.category) return;
|
|
506
520
|
|
|
507
|
-
const
|
|
508
|
-
|
|
521
|
+
const skillPath = skill.skillsPath;
|
|
522
|
+
const skillMdPath = path.join(skillPath, 'SKILL.md');
|
|
509
523
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const
|
|
524
|
+
try {
|
|
525
|
+
const content = await fs.readFile(skillMdPath, 'utf-8');
|
|
526
|
+
const parsed = this.skillLoader.parseSkillMarkdown(content);
|
|
527
|
+
|
|
528
|
+
skill.name = parsed.name || skillId;
|
|
529
|
+
skill.description = parsed.description || '';
|
|
530
|
+
skill.license = parsed.license || 'Unknown';
|
|
531
|
+
skill.version = parsed.version || '1.0.0';
|
|
532
|
+
skill.author = parsed.author || 'Anonymous';
|
|
533
|
+
|
|
534
|
+
// Extract category from path
|
|
535
|
+
const pathParts = skillPath.split(path.sep);
|
|
536
|
+
const skillsIndex = pathParts.findIndex(p => p === 'skills');
|
|
537
|
+
if (skillsIndex >= 0 && pathParts.length > skillsIndex + 1) {
|
|
538
|
+
skill.category = pathParts[skillsIndex + 1];
|
|
539
|
+
}
|
|
513
540
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
541
|
+
skill.markdown = content; // Now we have the full content
|
|
542
|
+
this.skillContentCache.set(skillId, content);
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.warn(`[SkillInvoker] Failed to load metadata for skill ${skillId}:`, error);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
517
547
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
category: trigger.category
|
|
524
|
-
};
|
|
548
|
+
/**
|
|
549
|
+
* Get list of all available skills (with metadata)
|
|
550
|
+
*/
|
|
551
|
+
async listAvailableSkills(): Promise<SkillInfo[]> {
|
|
552
|
+
await this.initialize();
|
|
525
553
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
}
|
|
554
|
+
// Load metadata for all skills if not already loaded
|
|
555
|
+
for (const skillId of this.skillCache.keys()) {
|
|
556
|
+
await this.loadSkillMetadata(skillId);
|
|
531
557
|
}
|
|
532
558
|
|
|
533
|
-
return
|
|
559
|
+
return Array.from(this.skillCache.values());
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Match the most relevant skill based on user input
|
|
564
|
+
* NOTE: SKILL_TRIGGERS disabled. Let LLM decide based on system prompt.
|
|
565
|
+
* Returns null to indicate no explicit match - LLM should use its own judgment.
|
|
566
|
+
*/
|
|
567
|
+
async matchSkill(userInput: string): Promise<SkillMatcherResult | null> {
|
|
568
|
+
// SKILL_TRIGGERS is disabled for experiment purposes.
|
|
569
|
+
// The LLM should decide which skill to use based on system prompt information.
|
|
570
|
+
return null;
|
|
534
571
|
}
|
|
535
572
|
|
|
536
573
|
/**
|
|
@@ -545,6 +582,12 @@ export class SkillInvoker {
|
|
|
545
582
|
* Execute skill
|
|
546
583
|
*/
|
|
547
584
|
async executeSkill(params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
585
|
+
// Ensure initialized
|
|
586
|
+
await this.initialize();
|
|
587
|
+
|
|
588
|
+
// Load skill metadata if not already loaded
|
|
589
|
+
await this.loadSkillMetadata(params.skillId);
|
|
590
|
+
|
|
548
591
|
const skill = this.skillCache.get(params.skillId);
|
|
549
592
|
|
|
550
593
|
if (!skill) {
|
|
@@ -620,61 +663,93 @@ export class SkillInvoker {
|
|
|
620
663
|
|
|
621
664
|
/**
|
|
622
665
|
* Get executor for skill
|
|
623
|
-
*
|
|
666
|
+
* Unified dynamic approach - all skills use GenericSkillExecutor
|
|
624
667
|
*/
|
|
625
668
|
private getSkillExecutor(skillId: string): SkillExecutor {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const visualDesignSkills = ['canvas-design', 'algorithmic-art', 'theme-factory', 'brand-guidelines', 'slack-gif-creator'];
|
|
629
|
-
const docSkills = ['doc-coauthoring', 'internal-comms'];
|
|
669
|
+
return new GenericSkillExecutor();
|
|
670
|
+
}
|
|
630
671
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if
|
|
641
|
-
|
|
672
|
+
// ============================================================================
|
|
673
|
+
// Remote Mode Tool Support Methods
|
|
674
|
+
// ============================================================================
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Check if it's a Skill tool
|
|
678
|
+
* Used for remote mode tool execution
|
|
679
|
+
*/
|
|
680
|
+
isSkillTool(toolName: string): boolean {
|
|
681
|
+
// Check if it's a skill ID in cache
|
|
682
|
+
return this.skillCache.has(toolName);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Get all Skill definitions (for syncing to remote server)
|
|
687
|
+
* NOTE: triggers field is empty since SKILL_TRIGGERS is disabled
|
|
688
|
+
*/
|
|
689
|
+
getAllSkillDefinitions(): Array<{
|
|
690
|
+
id: string;
|
|
691
|
+
name: string;
|
|
692
|
+
description: string;
|
|
693
|
+
category: string;
|
|
694
|
+
triggers: string[];
|
|
695
|
+
}> {
|
|
696
|
+
const definitions: Array<{
|
|
697
|
+
id: string;
|
|
698
|
+
name: string;
|
|
699
|
+
description: string;
|
|
700
|
+
category: string;
|
|
701
|
+
triggers: string[];
|
|
702
|
+
}> = [];
|
|
703
|
+
|
|
704
|
+
for (const skill of this.skillCache.values()) {
|
|
705
|
+
definitions.push({
|
|
706
|
+
id: skill.id,
|
|
707
|
+
name: skill.name,
|
|
708
|
+
description: skill.description,
|
|
709
|
+
category: skill.category,
|
|
710
|
+
triggers: [] // SKILL_TRIGGERS disabled - LLM decides based on description
|
|
711
|
+
});
|
|
642
712
|
}
|
|
643
|
-
|
|
713
|
+
|
|
714
|
+
return definitions;
|
|
644
715
|
}
|
|
645
716
|
|
|
646
717
|
/**
|
|
647
|
-
*
|
|
718
|
+
* Execute Skill tool (for remote mode tool execution)
|
|
719
|
+
* @param toolName - Tool name (skillId)
|
|
720
|
+
* @param params - Tool parameters
|
|
721
|
+
* @returns Execution result
|
|
648
722
|
*/
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
existing.push({
|
|
657
|
-
skillId: trigger.skillId,
|
|
658
|
-
name: skill.name,
|
|
659
|
-
description: skill.description
|
|
660
|
-
});
|
|
661
|
-
categories.set(trigger.category, existing);
|
|
662
|
-
}
|
|
723
|
+
async executeSkillTool(
|
|
724
|
+
toolName: string,
|
|
725
|
+
params: Record<string, any>
|
|
726
|
+
): Promise<{ success: boolean; result?: any; error?: string }> {
|
|
727
|
+
// Check if skill exists in cache
|
|
728
|
+
if (!this.skillCache.has(toolName)) {
|
|
729
|
+
return { success: false, error: `Skill not found: ${toolName}` };
|
|
663
730
|
}
|
|
664
731
|
|
|
665
|
-
|
|
666
|
-
|
|
732
|
+
try {
|
|
733
|
+
const result = await this.executeSkill({
|
|
734
|
+
skillId: toolName,
|
|
735
|
+
taskDescription: params.taskDescription || params.description || '',
|
|
736
|
+
inputFile: params.inputFile,
|
|
737
|
+
outputFile: params.outputFile,
|
|
738
|
+
options: params.options || {}
|
|
739
|
+
});
|
|
667
740
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
instructions += `**${skill.name}** (${skill.skillId}): ${skill.description}\n`;
|
|
672
|
-
instructions += ` �?Use: InvokeSkill(skillId="${skill.skillId}", taskDescription="...")\n`;
|
|
673
|
-
}
|
|
674
|
-
instructions += '\n';
|
|
741
|
+
return { success: result.success, result };
|
|
742
|
+
} catch (error: any) {
|
|
743
|
+
return { success: false, error: error.message };
|
|
675
744
|
}
|
|
745
|
+
}
|
|
676
746
|
|
|
677
|
-
|
|
747
|
+
/**
|
|
748
|
+
* Get all available Skill ID list
|
|
749
|
+
* NOTE: SKILL_TRIGGERS disabled - return all skill IDs from cache
|
|
750
|
+
*/
|
|
751
|
+
getAvailableSkillIds(): string[] {
|
|
752
|
+
return Array.from(this.skillCache.keys());
|
|
678
753
|
}
|
|
679
754
|
}
|
|
680
755
|
|
|
@@ -687,16 +762,15 @@ interface SkillExecutor {
|
|
|
687
762
|
}
|
|
688
763
|
|
|
689
764
|
/**
|
|
690
|
-
*
|
|
765
|
+
* Generic Skill Executor - Unified dynamic approach for all skills
|
|
691
766
|
*/
|
|
692
|
-
class
|
|
767
|
+
class GenericSkillExecutor implements SkillExecutor {
|
|
693
768
|
async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
694
769
|
const outputMessages: string[] = [];
|
|
695
770
|
const files: string[] = [];
|
|
696
771
|
const nextSteps: ExecutionStep[] = [];
|
|
697
772
|
|
|
698
|
-
outputMessages.push(`##
|
|
699
|
-
|
|
773
|
+
outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
|
|
700
774
|
outputMessages.push(`**Task**: ${params.taskDescription}\n`);
|
|
701
775
|
|
|
702
776
|
try {
|
|
@@ -735,7 +809,7 @@ class DocumentSkillExecutor implements SkillExecutor {
|
|
|
735
809
|
}
|
|
736
810
|
|
|
737
811
|
/**
|
|
738
|
-
* Extract relevant skill content
|
|
812
|
+
* Extract relevant skill content dynamically
|
|
739
813
|
*/
|
|
740
814
|
private async extractRelevantContent(
|
|
741
815
|
skill: SkillInfo,
|
|
@@ -744,82 +818,60 @@ class DocumentSkillExecutor implements SkillExecutor {
|
|
|
744
818
|
nextSteps: ExecutionStep[],
|
|
745
819
|
taskId: string
|
|
746
820
|
): Promise<string> {
|
|
747
|
-
const taskLower = params.taskDescription.toLowerCase();
|
|
748
821
|
const workspaceBase = getWorkspaceDescription();
|
|
749
822
|
const taskWorkspace = `${workspaceBase}/${taskId}`;
|
|
750
823
|
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
requiredFiles = ['skills/webapp-testing/SKILL.md', 'skills/webapp-testing/examples/'];
|
|
775
|
-
break;
|
|
776
|
-
case 'canvas-design':
|
|
777
|
-
requiredFiles = ['skills/canvas-design/SKILL.md'];
|
|
778
|
-
break;
|
|
779
|
-
case 'algorithmic-art':
|
|
780
|
-
requiredFiles = ['skills/algorithmic-art/SKILL.md', 'skills/algorithmic-art/templates/generator_template.js'];
|
|
781
|
-
break;
|
|
782
|
-
case 'theme-factory':
|
|
783
|
-
requiredFiles = ['skills/theme-factory/SKILL.md', 'skills/theme-factory/themes/'];
|
|
784
|
-
break;
|
|
785
|
-
case 'brand-guidelines':
|
|
786
|
-
requiredFiles = ['skills/brand-guidelines/SKILL.md'];
|
|
787
|
-
break;
|
|
788
|
-
case 'internal-comms':
|
|
789
|
-
requiredFiles = ['skills/internal-comms/SKILL.md', 'skills/internal-comms/examples/'];
|
|
790
|
-
break;
|
|
791
|
-
case 'doc-coauthoring':
|
|
792
|
-
requiredFiles = ['skills/doc-coauthoring/SKILL.md'];
|
|
793
|
-
break;
|
|
794
|
-
case 'mcp-builder':
|
|
795
|
-
requiredFiles = ['skills/mcp-builder/SKILL.md', 'skills/mcp-builder/reference/'];
|
|
796
|
-
break;
|
|
797
|
-
case 'skill-creator':
|
|
798
|
-
requiredFiles = ['skills/skill-creator/SKILL.md'];
|
|
799
|
-
break;
|
|
800
|
-
case 'slack-gif-creator':
|
|
801
|
-
requiredFiles = ['skills/slack-gif-creator/SKILL.md', 'skills/slack-gif-creator/core/'];
|
|
802
|
-
break;
|
|
803
|
-
default:
|
|
804
|
-
requiredFiles = [`skills/${skill.id}/SKILL.md`];
|
|
824
|
+
// Dynamically discover files in skill directory
|
|
825
|
+
const skillPath = skill.skillsPath;
|
|
826
|
+
let allFiles: string[] = [];
|
|
827
|
+
|
|
828
|
+
try {
|
|
829
|
+
const entries = await fs.readdir(skillPath, { withFileTypes: true });
|
|
830
|
+
for (const entry of entries) {
|
|
831
|
+
const fullPath = path.join(skillPath, entry.name);
|
|
832
|
+
if (entry.isFile()) {
|
|
833
|
+
allFiles.push(fullPath);
|
|
834
|
+
} else if (entry.isDirectory()) {
|
|
835
|
+
// Recursively list files in subdirectories (limited depth)
|
|
836
|
+
const subEntries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
837
|
+
for (const subEntry of subEntries) {
|
|
838
|
+
if (subEntry.isFile()) {
|
|
839
|
+
allFiles.push(path.join(fullPath, subEntry.name));
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
} catch {
|
|
845
|
+
// Fallback to just SKILL.md if directory can't be read
|
|
846
|
+
allFiles = [path.join(skillPath, 'SKILL.md')];
|
|
805
847
|
}
|
|
806
848
|
|
|
849
|
+
// Step 1: Read SKILL.md first
|
|
850
|
+
const skillMdPathOnly = path.join(skillPath, 'SKILL.md');
|
|
807
851
|
nextSteps.push({
|
|
808
852
|
step: 1,
|
|
809
|
-
action: 'Read skill
|
|
810
|
-
description: `Read: ${
|
|
811
|
-
reason: 'Understand the skill workflow and best practices'
|
|
853
|
+
action: 'Read SKILL.md to understand the skill workflow',
|
|
854
|
+
description: `Read: ${skillMdPathOnly}`,
|
|
855
|
+
reason: 'Understand the skill workflow and best practices from the main documentation'
|
|
812
856
|
});
|
|
813
857
|
|
|
858
|
+
// Step 2: Explore skill directory and read reference files if needed (optional)
|
|
814
859
|
nextSteps.push({
|
|
815
860
|
step: 2,
|
|
816
|
-
action: '
|
|
817
|
-
description: `
|
|
818
|
-
reason: '
|
|
861
|
+
action: 'Explore skill directory and read reference files (if needed)',
|
|
862
|
+
description: `Explore: ${skillPath}`,
|
|
863
|
+
reason: 'Discover available reference files and read them based on SKILL.md guidance'
|
|
819
864
|
});
|
|
820
865
|
|
|
821
866
|
nextSteps.push({
|
|
822
867
|
step: 3,
|
|
868
|
+
action: 'Analyze documentation, verify data/content completeness, and design approach',
|
|
869
|
+
description: `For content creation: ensure all info/materials collected. For info retrieval: ensure all required data retrieved. Then design execution plan for: ${taskWorkspace}`,
|
|
870
|
+
reason: 'Review requirements, verify data/content completeness, fill gaps if needed, then plan execution based on the documentation'
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
nextSteps.push({
|
|
874
|
+
step: 4,
|
|
823
875
|
action: 'Execute your plan',
|
|
824
876
|
description: 'Create workspace, write code, run scripts, verify output',
|
|
825
877
|
reason: 'Execute the task using your own understanding'
|
|
@@ -827,1036 +879,31 @@ class DocumentSkillExecutor implements SkillExecutor {
|
|
|
827
879
|
|
|
828
880
|
return `### Skill Execution\n\n` +
|
|
829
881
|
`**Your task**: ${params.taskDescription}\n\n` +
|
|
830
|
-
`**Read
|
|
831
|
-
|
|
882
|
+
`**Step 1**: Read SKILL.md to understand the skill workflow\n` +
|
|
883
|
+
` - read_file: ${skillMdPathOnly}\n\n` +
|
|
884
|
+
`**Step 2**: Explore skill directory and read reference files (if needed)\n` +
|
|
885
|
+
` - ListDirectory(path="${skillPath}")\n` +
|
|
886
|
+
` - read_file relevant .md and script files as needed\n\n` +
|
|
832
887
|
`Then analyze the documentation and create your own execution plan.\n\n` +
|
|
833
888
|
`**Workspace**: \`${taskWorkspace}\`\n\n` +
|
|
834
889
|
`**⚠️ Windows Path Execution**: Use absolute paths, NOT \`cd && command\`:\n` +
|
|
835
890
|
` - ✅ Correct: \`node "${taskWorkspace}/script.js"\`\n` +
|
|
836
891
|
` - ❌ Wrong: \`cd "${taskWorkspace}" && node script.js\` (fails in PowerShell 5.1)\n` +
|
|
837
892
|
` - ✅ Correct: \`python "${taskWorkspace}/script.py"\`\n\n` +
|
|
838
|
-
`**📦 Dependency
|
|
839
|
-
` -
|
|
840
|
-
` -
|
|
841
|
-
` -
|
|
842
|
-
` -
|
|
893
|
+
`**📦 Dependency Management**:\n` +
|
|
894
|
+
` - BashTool automatically sets NODE_PATH when executing, scripts can use require() directly\n` +
|
|
895
|
+
` - ✅ Correct: Bash(command="node script.js", cwd="${taskWorkspace}")\n` +
|
|
896
|
+
` - ❌ Wrong: cd "${taskWorkspace}" && node script.js (loses NODE_PATH!)\n` +
|
|
897
|
+
` - If script needs to run by user manually, pass NODE_PATH in command:\n` +
|
|
898
|
+
` Windows: set NODE_PATH=xAgent/node_modules/path && node script.js\n` +
|
|
899
|
+
` Linux/Mac: NODE_PATH=xAgent/node_modules/path node script.js\n\n` +
|
|
843
900
|
`**🧹 Cleanup**: Delete all intermediate/temporary files when task completes:\n` +
|
|
844
901
|
` - Remove: all files generated during the task\n` +
|
|
845
902
|
` - Keep: Only the final output file (output.pptx/docx/xlsx/pdf)\n\n` +
|
|
846
903
|
`**Instructions**: read_file the documentation, understand the API, and create your own execution plan.\n` +
|
|
847
904
|
`**If you encounter issues**: Explain what went wrong and suggest a different approach.\n`;
|
|
848
905
|
}
|
|
849
|
-
|
|
850
|
-
/**
|
|
851
|
-
* Extract PPTX-related content and generate steps
|
|
852
|
-
*/
|
|
853
|
-
private extractPptxContent(taskLower: string, fullContent: string, nextSteps: ExecutionStep[], skillPath: string, taskWorkspace: string): string {
|
|
854
|
-
const content = fullContent.replace(/^---\n[\s\S]*?\n---/, '').trim();
|
|
855
|
-
const html2pptxPath = `${skillPath}/scripts/html2pptx.js`;
|
|
856
|
-
const scriptsPath = `${skillPath}/scripts`;
|
|
857
|
-
|
|
858
|
-
// Check if using template
|
|
859
|
-
const useTemplate = taskLower.includes('template') || taskLower.includes('template');
|
|
860
|
-
|
|
861
|
-
if (useTemplate) {
|
|
862
|
-
// Add template usage steps
|
|
863
|
-
nextSteps.push({
|
|
864
|
-
step: 1,
|
|
865
|
-
action: 'Read documentation and script',
|
|
866
|
-
description: `Read pptx/html2pptx.md and ${html2pptxPath} - CRITICAL: Read the USAGE section at the top of html2pptx.js to understand the correct API: const { slide, placeholders } = await html2pptx('slide.html', pptx);`,
|
|
867
|
-
file: html2pptxPath,
|
|
868
|
-
reason: 'Understand html2pptx API - MUST read the usage example in the file header'
|
|
869
|
-
});
|
|
870
|
-
nextSteps.push({
|
|
871
|
-
step: 2,
|
|
872
|
-
action: 'Create workspace directory',
|
|
873
|
-
description: `Create directory: ${taskWorkspace}`,
|
|
874
|
-
reason: 'Create workspace directory for this task'
|
|
875
|
-
});
|
|
876
|
-
nextSteps.push({
|
|
877
|
-
step: 3,
|
|
878
|
-
action: 'Create HTML slide file in workspace',
|
|
879
|
-
description: `Create slide.html inside ${taskWorkspace}/ (720pt × 405pt for 16:9)`,
|
|
880
|
-
reason: 'Create slide HTML file in workspace to avoid polluting target directory'
|
|
881
|
-
});
|
|
882
|
-
nextSteps.push({
|
|
883
|
-
step: 4,
|
|
884
|
-
action: 'Create PPTX conversion script in workspace',
|
|
885
|
-
description: `Create convert.js inside ${taskWorkspace}/ using CommonJS: const { slide, placeholders } = await html2pptx('slide.html', pptx); // slide is already added, use slide.addChart()/addText() for content`,
|
|
886
|
-
reason: 'Write Node.js script - MUST use destructured { slide, placeholders } from html2pptx()'
|
|
887
|
-
});
|
|
888
|
-
nextSteps.push({
|
|
889
|
-
step: 5,
|
|
890
|
-
action: 'Run the script',
|
|
891
|
-
description: `node "${taskWorkspace.replace(/\\/g, '/')}/convert.js"`,
|
|
892
|
-
reason: 'Generate PPTX file using html2pptx (use absolute path for Windows compatibility)'
|
|
893
|
-
});
|
|
894
|
-
nextSteps.push({
|
|
895
|
-
step: 6,
|
|
896
|
-
action: 'Generate thumbnail grid for visual validation',
|
|
897
|
-
description: `Run: python "${scriptsPath}/thumbnail.py" ${taskWorkspace}/output.pptx ${taskWorkspace}/thumbnails --cols 4`,
|
|
898
|
-
reason: 'Create thumbnail grid to verify slide layout and visual quality'
|
|
899
|
-
});
|
|
900
|
-
nextSteps.push({
|
|
901
|
-
step: 7,
|
|
902
|
-
action: 'Copy output to target directory',
|
|
903
|
-
description: `Copy ${taskWorkspace}/output.pptx to target directory`,
|
|
904
|
-
reason: 'Only save final file to specified path, keep workspace clean'
|
|
905
|
-
});
|
|
906
|
-
|
|
907
|
-
const patterns = [
|
|
908
|
-
/##\s*Creating\s*a\s*new\s*PowerPoint\s*presentation\s*\*\*using\s*a\s*template\*\*[\s\S]*?(?=##\s+)/i,
|
|
909
|
-
/##\s*Using\s*a\s*template[\s\S]*?(?=##\s+)/i
|
|
910
|
-
];
|
|
911
|
-
|
|
912
|
-
for (const pattern of patterns) {
|
|
913
|
-
const match = content.match(pattern);
|
|
914
|
-
if (match) {
|
|
915
|
-
return `### Using a Template\n\n${match[0].trim()}`;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// Not using template
|
|
921
|
-
nextSteps.push({
|
|
922
|
-
step: 1,
|
|
923
|
-
action: 'Read documentation and script',
|
|
924
|
-
description: `Read pptx/html2pptx.md and ${html2pptxPath} - CRITICAL: Read the USAGE section at the top of html2pptx.js to understand the correct API: const { slide, placeholders } = await html2pptx('slide.html', pptx);`,
|
|
925
|
-
file: html2pptxPath,
|
|
926
|
-
reason: 'Understand html2pptx API - MUST read the usage example in the file header'
|
|
927
|
-
});
|
|
928
|
-
nextSteps.push({
|
|
929
|
-
step: 2,
|
|
930
|
-
action: 'Create workspace directory',
|
|
931
|
-
description: `Create directory: ${taskWorkspace}`,
|
|
932
|
-
reason: 'Create workspace directory for this task'
|
|
933
|
-
});
|
|
934
|
-
nextSteps.push({
|
|
935
|
-
step: 3,
|
|
936
|
-
action: 'Create HTML slide file in workspace',
|
|
937
|
-
description: `Create slide.html inside ${taskWorkspace}/ (720pt × 405pt for 16:9)`,
|
|
938
|
-
reason: 'Create slide HTML file in workspace to avoid polluting target directory'
|
|
939
|
-
});
|
|
940
|
-
nextSteps.push({
|
|
941
|
-
step: 4,
|
|
942
|
-
action: 'Create PPTX conversion script in workspace',
|
|
943
|
-
description: `Create convert.js inside ${taskWorkspace}/ using CommonJS: const { slide, placeholders } = await html2pptx('slide.html', pptx); // slide is already added, use slide.addChart()/addText() for content`,
|
|
944
|
-
reason: 'Write Node.js script - MUST use destructured { slide, placeholders } from html2pptx()'
|
|
945
|
-
});
|
|
946
|
-
nextSteps.push({
|
|
947
|
-
step: 5,
|
|
948
|
-
action: 'Run the script',
|
|
949
|
-
description: `node "${taskWorkspace.replace(/\\/g, '/')}/convert.js"`,
|
|
950
|
-
reason: 'Generate PPTX file using html2pptx (use absolute path for Windows compatibility)'
|
|
951
|
-
});
|
|
952
|
-
nextSteps.push({
|
|
953
|
-
step: 6,
|
|
954
|
-
action: 'Generate thumbnail grid for visual validation',
|
|
955
|
-
description: `Run: python "${scriptsPath}/thumbnail.py" ${taskWorkspace}/output.pptx ${taskWorkspace}/thumbnails --cols 4`,
|
|
956
|
-
reason: 'Create thumbnail grid to verify slide layout and visual quality'
|
|
957
|
-
});
|
|
958
|
-
nextSteps.push({
|
|
959
|
-
step: 7,
|
|
960
|
-
action: 'Copy output to target directory',
|
|
961
|
-
description: `Copy ${taskWorkspace}/output.pptx to target directory`,
|
|
962
|
-
reason: 'Only save final file to specified path, keep workspace clean'
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
const patterns = [
|
|
966
|
-
/##\s*Creating\s*a\s*new\s*PowerPoint[\s\S]*?(?=##\s+)/i,
|
|
967
|
-
/###\s*Workflow[\s\S]*?(?=###\s+|$)/i
|
|
968
|
-
];
|
|
969
|
-
|
|
970
|
-
for (const pattern of patterns) {
|
|
971
|
-
const match = content.match(pattern);
|
|
972
|
-
if (match) {
|
|
973
|
-
return `### Creating New Presentation\n\n${match[0].trim()}`;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
return extractContent(content, ['html2pptx', 'Creating', 'Workflow']);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
/**
|
|
981
|
-
* Extract DOCX-related content and generate steps
|
|
982
|
-
*/
|
|
983
|
-
private extractDocxContent(
|
|
984
|
-
taskLower: string,
|
|
985
|
-
fullContent: string,
|
|
986
|
-
nextSteps: ExecutionStep[],
|
|
987
|
-
params: SkillExecutionParams,
|
|
988
|
-
skillPath: string,
|
|
989
|
-
taskWorkspace: string
|
|
990
|
-
): string {
|
|
991
|
-
const content = fullContent.replace(/^---\n[\s\S]*?\n---/, '').trim();
|
|
992
|
-
const unpackScript = `${skillPath}/ooxml/scripts/unpack.py`;
|
|
993
|
-
const packScript = `${skillPath}/ooxml/scripts/pack.py`;
|
|
994
|
-
const scriptsPath = `${skillPath}/scripts`;
|
|
995
|
-
|
|
996
|
-
const isNew = taskLower.includes('create') || taskLower.includes('new');
|
|
997
|
-
const isEditing = taskLower.includes('edit') || taskLower.includes('modify') || taskLower.includes('modify');
|
|
998
|
-
|
|
999
|
-
if (isNew) {
|
|
1000
|
-
// Create new document
|
|
1001
|
-
nextSteps.push({
|
|
1002
|
-
step: 1,
|
|
1003
|
-
action: 'Read documentation',
|
|
1004
|
-
description: 'Read docx-js.md for API reference',
|
|
1005
|
-
file: `${skillPath}/docx-js.md`,
|
|
1006
|
-
reason: 'Understand how to use docx-js library to create Word documents'
|
|
1007
|
-
});
|
|
1008
|
-
nextSteps.push({
|
|
1009
|
-
step: 2,
|
|
1010
|
-
action: 'Create script in workspace',
|
|
1011
|
-
description: `Create create_doc.js in ${taskWorkspace}: const { Document, Paragraph, TextRun, Packer } = await import("docx");`,
|
|
1012
|
-
reason: 'Create Word document code using docx library with dynamic import'
|
|
1013
|
-
});
|
|
1014
|
-
nextSteps.push({
|
|
1015
|
-
step: 3,
|
|
1016
|
-
action: 'Run the script',
|
|
1017
|
-
description: `node "${taskWorkspace.replace(/\\/g, '/')}/create_doc.js"`,
|
|
1018
|
-
reason: 'Generate DOCX file in workspace (use absolute path for Windows compatibility)'
|
|
1019
|
-
});
|
|
1020
|
-
nextSteps.push({ step: 4,
|
|
1021
|
-
action: 'Copy output to target directory',
|
|
1022
|
-
description: `Copy ${taskWorkspace}/output.docx to target directory`,
|
|
1023
|
-
reason: 'Only save final file to specified path, keep workspace clean'
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
return extractContent(content, ['Creating', 'docx-js', 'Workflow']);
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
if (isEditing) {
|
|
1030
|
-
// Edit existing document - use existing scripts
|
|
1031
|
-
nextSteps.push({
|
|
1032
|
-
step: 1,
|
|
1033
|
-
action: 'Read documentation',
|
|
1034
|
-
description: 'Read ooxml.md for editing API',
|
|
1035
|
-
file: `${skillPath}/ooxml.md`,
|
|
1036
|
-
reason: 'Understand how to edit existing Word documents'
|
|
1037
|
-
});
|
|
1038
|
-
|
|
1039
|
-
nextSteps.push({
|
|
1040
|
-
step: 2,
|
|
1041
|
-
action: 'Create workspace directory',
|
|
1042
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1043
|
-
reason: 'Create workspace directory for intermediate files'
|
|
1044
|
-
});
|
|
1045
|
-
|
|
1046
|
-
if (params.inputFile) {
|
|
1047
|
-
nextSteps.push({
|
|
1048
|
-
step: 3,
|
|
1049
|
-
action: 'Unpack document in workspace',
|
|
1050
|
-
description: `Run: python "${unpackScript}" "${params.inputFile}" ${taskWorkspace}/docx_input`,
|
|
1051
|
-
reason: 'Unpack DOCX file using existing unpack.py script'
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
nextSteps.push({
|
|
1056
|
-
step: 4,
|
|
1057
|
-
action: 'Create editing script in workspace',
|
|
1058
|
-
description: `Create edit_doc.py in ${taskWorkspace}: from scripts.document import Document; doc = Document("${taskWorkspace}/docx_input");`,
|
|
1059
|
-
reason: 'Create Python editing script using existing Document library'
|
|
1060
|
-
});
|
|
1061
|
-
|
|
1062
|
-
if (params.inputFile || params.outputFile) {
|
|
1063
|
-
nextSteps.push({
|
|
1064
|
-
step: 5,
|
|
1065
|
-
action: 'Pack document',
|
|
1066
|
-
description: `Run: python "${packScript}" ${taskWorkspace}/docx_input ${taskWorkspace}/output.docx`,
|
|
1067
|
-
reason: 'Repack DOCX using existing pack.py script'
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
nextSteps.push({
|
|
1072
|
-
step: 6,
|
|
1073
|
-
action: 'Copy output to target directory',
|
|
1074
|
-
description: `Copy ${taskWorkspace}/output.docx to target directory`,
|
|
1075
|
-
reason: 'Only save final file to specified path'
|
|
1076
|
-
});
|
|
1077
|
-
|
|
1078
|
-
return extractContent(content, ['Editing', 'redlining', 'ooxml']);
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
// Default case
|
|
1082
|
-
nextSteps.push({
|
|
1083
|
-
step: 1,
|
|
1084
|
-
action: 'Read documentation',
|
|
1085
|
-
description: 'Read ooxml.md or docx-js.md',
|
|
1086
|
-
reason: 'Understand document processing methods'
|
|
1087
|
-
});
|
|
1088
|
-
nextSteps.push({
|
|
1089
|
-
step: 2,
|
|
1090
|
-
action: 'Create or edit document',
|
|
1091
|
-
description: 'Write code using appropriate library',
|
|
1092
|
-
reason: 'Perform document operations'
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
return extractContent(content, ['Creating', 'Editing', 'document', 'docx']);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
/**
|
|
1099
|
-
* Extract PDF-related content and generate steps
|
|
1100
|
-
*/
|
|
1101
|
-
private extractPdfContent(
|
|
1102
|
-
taskLower: string,
|
|
1103
|
-
fullContent: string,
|
|
1104
|
-
nextSteps: ExecutionStep[],
|
|
1105
|
-
params: SkillExecutionParams,
|
|
1106
|
-
skillPath: string,
|
|
1107
|
-
taskWorkspace: string
|
|
1108
|
-
): string {
|
|
1109
|
-
const content = fullContent.replace(/^---\n[\s\S]*?\n---/, '').trim();
|
|
1110
|
-
const scriptsPath = `${skillPath}/scripts`;
|
|
1111
|
-
|
|
1112
|
-
const isForm = taskLower.includes('form') || taskLower.includes('form');
|
|
1113
|
-
const isExtract = taskLower.includes('extract') || taskLower.includes('extract');
|
|
1114
|
-
const isMerge = taskLower.includes('merge') || taskLower.includes('merge');
|
|
1115
|
-
const isConvert = taskLower.includes('convert') || taskLower.includes('image');
|
|
1116
|
-
|
|
1117
|
-
nextSteps.push({
|
|
1118
|
-
step: 1,
|
|
1119
|
-
action: 'Read documentation',
|
|
1120
|
-
description: 'Read reference.md for PDF operations',
|
|
1121
|
-
file: `${skillPath}/reference.md`,
|
|
1122
|
-
reason: 'Understand PDF operation methods'
|
|
1123
|
-
});
|
|
1124
|
-
|
|
1125
|
-
nextSteps.push({
|
|
1126
|
-
step: 2,
|
|
1127
|
-
action: 'Create workspace directory',
|
|
1128
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1129
|
-
reason: 'Create workspace directory for intermediate files'
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
if (isForm) {
|
|
1133
|
-
// Check for fillable fields first
|
|
1134
|
-
nextSteps.push({
|
|
1135
|
-
step: 3,
|
|
1136
|
-
action: 'Check form fields',
|
|
1137
|
-
description: `Run: python "${scriptsPath}/check_fillable_fields.py" <input_pdf>`,
|
|
1138
|
-
reason: 'Check if PDF has fillable form fields'
|
|
1139
|
-
});
|
|
1140
|
-
nextSteps.push({
|
|
1141
|
-
step: 4,
|
|
1142
|
-
action: 'Create PDF form script in workspace',
|
|
1143
|
-
description: `Create form_script.py in ${taskWorkspace}: use "${scriptsPath}/fill_fillable_fields.py" or "${scriptsPath}/fill_pdf_form_with_annotations.py"`,
|
|
1144
|
-
reason: 'Create PDF form processing script using existing scripts'
|
|
1145
|
-
});
|
|
1146
|
-
} else if (isExtract) {
|
|
1147
|
-
nextSteps.push({
|
|
1148
|
-
step: 3,
|
|
1149
|
-
action: 'Create extraction script in workspace',
|
|
1150
|
-
description: `Create extract_script.py in ${taskWorkspace}: use pypdf or pdfplumber for text extraction`,
|
|
1151
|
-
reason: 'Create PDF content extraction script'
|
|
1152
|
-
});
|
|
1153
|
-
} else if (isMerge) {
|
|
1154
|
-
nextSteps.push({
|
|
1155
|
-
step: 3,
|
|
1156
|
-
action: 'Create merge script in workspace',
|
|
1157
|
-
description: `Create merge_script.py in ${taskWorkspace}: use pypdf to combine PDF files`,
|
|
1158
|
-
reason: 'Create PDF merge script'
|
|
1159
|
-
});
|
|
1160
|
-
} else if (isConvert) {
|
|
1161
|
-
nextSteps.push({
|
|
1162
|
-
step: 3,
|
|
1163
|
-
action: 'Convert PDF to images',
|
|
1164
|
-
description: `Run: python "${scriptsPath}/convert_pdf_to_images.py" <input_pdf> ${taskWorkspace}/images`,
|
|
1165
|
-
reason: 'Convert PDF to images using existing script'
|
|
1166
|
-
});
|
|
1167
|
-
} else {
|
|
1168
|
-
nextSteps.push({
|
|
1169
|
-
step: 3,
|
|
1170
|
-
action: 'Create PDF processing script in workspace',
|
|
1171
|
-
description: `Create pdf_script.py in ${taskWorkspace}: use pypdf for desired operations`,
|
|
1172
|
-
reason: 'Create PDF processing script'
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
nextSteps.push({
|
|
1177
|
-
step: 5,
|
|
1178
|
-
action: 'Run the script',
|
|
1179
|
-
description: `python "${taskWorkspace.replace(/\\/g, '/')}/pdf_script.py"`,
|
|
1180
|
-
reason: 'Execute PDF operation script in workspace (use absolute path for Windows compatibility)'
|
|
1181
|
-
});
|
|
1182
|
-
|
|
1183
|
-
nextSteps.push({
|
|
1184
|
-
step: 6,
|
|
1185
|
-
action: 'Copy output to target directory',
|
|
1186
|
-
description: `Copy ${taskWorkspace}/output.pdf to target directory`,
|
|
1187
|
-
reason: 'Only save final file to specified path'
|
|
1188
|
-
});
|
|
1189
|
-
|
|
1190
|
-
return extractContent(content, ['Creating', 'pdf', 'PDF']);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/**
|
|
1194
|
-
* Extract XLSX relevant content and generate steps
|
|
1195
|
-
*/
|
|
1196
|
-
private extractXlsxContent(taskLower: string, fullContent: string, nextSteps: ExecutionStep[], skillPath: string, taskWorkspace: string): string {
|
|
1197
|
-
const content = fullContent.replace(/^---\n[\s\S]*?\n---/, '').trim();
|
|
1198
|
-
|
|
1199
|
-
const hasFormulas = taskLower.includes('formula') || taskLower.includes('公式');
|
|
1200
|
-
const hasData = taskLower.includes('data') || taskLower.includes('数据分析');
|
|
1201
|
-
|
|
1202
|
-
nextSteps.push({
|
|
1203
|
-
step: 1,
|
|
1204
|
-
action: 'Read documentation',
|
|
1205
|
-
description: 'Read SKILL.md for Excel operations',
|
|
1206
|
-
file: `${skillPath}/SKILL.md`,
|
|
1207
|
-
reason: 'Understand Excel operation methods'
|
|
1208
|
-
});
|
|
1209
|
-
|
|
1210
|
-
nextSteps.push({
|
|
1211
|
-
step: 2,
|
|
1212
|
-
action: 'Create workspace directory',
|
|
1213
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1214
|
-
reason: 'Create workspace directory for intermediate files'
|
|
1215
|
-
});
|
|
1216
|
-
|
|
1217
|
-
if (hasFormulas || hasData) {
|
|
1218
|
-
nextSteps.push({
|
|
1219
|
-
step: 3,
|
|
1220
|
-
action: 'Create spreadsheet script in workspace',
|
|
1221
|
-
description: `Create create_xlsx.py in ${taskWorkspace}: use openpyxl to create workbook with formulas`,
|
|
1222
|
-
reason: 'Create spreadsheet script with formulas in workspace'
|
|
1223
|
-
});
|
|
1224
|
-
} else {
|
|
1225
|
-
nextSteps.push({
|
|
1226
|
-
step: 3,
|
|
1227
|
-
action: 'Create spreadsheet script in workspace',
|
|
1228
|
-
description: `Create create_xlsx.py in ${taskWorkspace}: use openpyxl to create workbook`,
|
|
1229
|
-
reason: 'Create spreadsheet script in workspace'
|
|
1230
|
-
});
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
nextSteps.push({
|
|
1234
|
-
step: 4,
|
|
1235
|
-
action: 'Run the script',
|
|
1236
|
-
description: `python "${taskWorkspace.replace(/\\/g, '/')}/create_xlsx.py"`,
|
|
1237
|
-
reason: 'Generate XLSX file in workspace (use absolute path for Windows compatibility)'
|
|
1238
|
-
});
|
|
1239
|
-
|
|
1240
|
-
if (hasFormulas) {
|
|
1241
|
-
nextSteps.push({
|
|
1242
|
-
step: 5,
|
|
1243
|
-
action: 'Recalculate formulas',
|
|
1244
|
-
description: `Run: python "${skillPath}/recalc.py" ${taskWorkspace}/output.xlsx to recalculate all formulas and check for errors`,
|
|
1245
|
-
reason: 'Recalculate formulas and verify no formula errors (#REF!, #DIV/0!, etc.)'
|
|
1246
|
-
});
|
|
1247
|
-
nextSteps.push({
|
|
1248
|
-
step: 6,
|
|
1249
|
-
action: 'Fix formula errors if any',
|
|
1250
|
-
description: `Check recalc.py output JSON for error locations and fix formula errors in ${taskWorkspace}`,
|
|
1251
|
-
reason: 'Ensure ZERO formula errors before final output'
|
|
1252
|
-
});
|
|
1253
|
-
nextSteps.push({
|
|
1254
|
-
step: 7,
|
|
1255
|
-
action: 'Copy output to target directory',
|
|
1256
|
-
description: `Copy ${taskWorkspace}/output.xlsx to target directory`,
|
|
1257
|
-
reason: 'Only save final file to specified path'
|
|
1258
|
-
});
|
|
1259
|
-
} else {
|
|
1260
|
-
nextSteps.push({
|
|
1261
|
-
step: 5,
|
|
1262
|
-
action: 'Copy output to target directory',
|
|
1263
|
-
description: `Copy ${taskWorkspace}/output.xlsx to target directory`,
|
|
1264
|
-
reason: 'Only save final file to specified path'
|
|
1265
|
-
});
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
return extractContent(content, ['Excel', 'xlsx', 'spreadsheet']);
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
/**
|
|
1272
|
-
* Extract default content
|
|
1273
|
-
*/
|
|
1274
|
-
private extractDefaultContent(skill: SkillInfo, fullContent: string, nextSteps: ExecutionStep[]): string {
|
|
1275
|
-
const content = fullContent.replace(/^---\n[\s\S]*?\n---/, '').trim();
|
|
1276
|
-
const firstLines = content.split('\n').slice(0, 100).join('\n');
|
|
1277
|
-
|
|
1278
|
-
nextSteps.push({
|
|
1279
|
-
step: 1,
|
|
1280
|
-
action: 'Read SKILL.md',
|
|
1281
|
-
description: `Read ${skill.id}/SKILL.md for full instructions`,
|
|
1282
|
-
file: `${skill.skillsPath}/SKILL.md`,
|
|
1283
|
-
reason: 'Understand complete execution workflow'
|
|
1284
|
-
});
|
|
1285
|
-
|
|
1286
|
-
return `### ${skill.name}\n\n${firstLines}\n\n(See ${skill.skillsPath}/SKILL.md for full instructions)`;
|
|
1287
|
-
}
|
|
1288
906
|
}
|
|
1289
|
-
|
|
1290
|
-
/**
|
|
1291
|
-
* Frontend Development Skill Executor
|
|
1292
|
-
*/
|
|
1293
|
-
class FrontendSkillExecutor implements SkillExecutor {
|
|
1294
|
-
async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
1295
|
-
const outputMessages: string[] = [];
|
|
1296
|
-
const files: string[] = [];
|
|
1297
|
-
const nextSteps: ExecutionStep[] = [];
|
|
1298
|
-
|
|
1299
|
-
outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
|
|
1300
|
-
outputMessages.push(`**Task**: ${params.taskDescription}\n`);
|
|
1301
|
-
|
|
1302
|
-
// Get or generate task ID
|
|
1303
|
-
const taskId = params.taskId || `${skill.id}-${Date.now()}`;
|
|
1304
|
-
|
|
1305
|
-
try {
|
|
1306
|
-
// Read SKILL.md content
|
|
1307
|
-
const skillMdPath = path.join(skill.skillsPath, 'SKILL.md');
|
|
1308
|
-
files.push(skillMdPath);
|
|
1309
|
-
const skillContent = await fs.readFile(skillMdPath, 'utf-8');
|
|
1310
|
-
|
|
1311
|
-
// Generate execution steps
|
|
1312
|
-
const taskContent = await this.extractFrontendContent(skill, params, skillContent, nextSteps, taskId);
|
|
1313
|
-
outputMessages.push(taskContent);
|
|
1314
|
-
|
|
1315
|
-
// Add input/output files to list if they exist
|
|
1316
|
-
if (params.inputFile) files.push(params.inputFile);
|
|
1317
|
-
if (params.outputFile) files.push(params.outputFile);
|
|
1318
|
-
|
|
1319
|
-
return {
|
|
1320
|
-
success: true,
|
|
1321
|
-
output: outputMessages.join('\n'),
|
|
1322
|
-
files: files,
|
|
1323
|
-
nextSteps: nextSteps,
|
|
1324
|
-
requiresManualExecution: true
|
|
1325
|
-
};
|
|
1326
|
-
} catch (error: any) {
|
|
1327
|
-
return {
|
|
1328
|
-
success: false,
|
|
1329
|
-
error: error.message
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
/**
|
|
1335
|
-
* Extract relevant content based on frontend skill type and generate steps
|
|
1336
|
-
*/
|
|
1337
|
-
private async extractFrontendContent(
|
|
1338
|
-
skill: SkillInfo,
|
|
1339
|
-
params: SkillExecutionParams,
|
|
1340
|
-
fullContent: string,
|
|
1341
|
-
nextSteps: ExecutionStep[],
|
|
1342
|
-
taskId: string
|
|
1343
|
-
): Promise<string> {
|
|
1344
|
-
const taskLower = params.taskDescription.toLowerCase();
|
|
1345
|
-
const workspaceBase = getWorkspaceDescription();
|
|
1346
|
-
const taskWorkspace = `${workspaceBase}/${taskId}`;
|
|
1347
|
-
|
|
1348
|
-
// Add common steps
|
|
1349
|
-
nextSteps.push({
|
|
1350
|
-
step: 1,
|
|
1351
|
-
action: 'Design Thinking',
|
|
1352
|
-
description: 'Understand requirements, define aesthetic direction',
|
|
1353
|
-
reason: 'Clarify design direction and goals'
|
|
1354
|
-
});
|
|
1355
|
-
nextSteps.push({
|
|
1356
|
-
step: 2,
|
|
1357
|
-
action: 'Create implementation',
|
|
1358
|
-
description: 'Write production-grade HTML/CSS/JS or React code',
|
|
1359
|
-
reason: 'Implement frontend interface'
|
|
1360
|
-
});
|
|
1361
|
-
|
|
1362
|
-
switch (skill.id) {
|
|
1363
|
-
case 'frontend-design':
|
|
1364
|
-
nextSteps.push({
|
|
1365
|
-
step: 3,
|
|
1366
|
-
action: 'Create workspace directory',
|
|
1367
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1368
|
-
reason: 'Create workspace directory for frontend files'
|
|
1369
|
-
});
|
|
1370
|
-
nextSteps.push({
|
|
1371
|
-
step: 4,
|
|
1372
|
-
action: 'Create frontend files in workspace',
|
|
1373
|
-
description: `Create index.html, styles.css, app.js in ${taskWorkspace}`,
|
|
1374
|
-
reason: 'Create frontend files in workspace'
|
|
1375
|
-
});
|
|
1376
|
-
if (taskLower.includes('landing')) {
|
|
1377
|
-
nextSteps.push({
|
|
1378
|
-
step: 5,
|
|
1379
|
-
action: 'Focus areas',
|
|
1380
|
-
description: 'Hero section, features, pricing, testimonials, footer',
|
|
1381
|
-
reason: 'Implement landing page sections'
|
|
1382
|
-
});
|
|
1383
|
-
} else if (taskLower.includes('dashboard')) {
|
|
1384
|
-
nextSteps.push({
|
|
1385
|
-
step: 5,
|
|
1386
|
-
action: 'Focus areas',
|
|
1387
|
-
description: 'Charts, data visualization, navigation panels',
|
|
1388
|
-
reason: 'Implement dashboard functionality'
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
nextSteps.push({
|
|
1392
|
-
step: 6,
|
|
1393
|
-
action: 'Verify in browser',
|
|
1394
|
-
description: `Open files in ${taskWorkspace} to verify`,
|
|
1395
|
-
reason: 'Verify in browser'
|
|
1396
|
-
});
|
|
1397
|
-
nextSteps.push({
|
|
1398
|
-
step: 7,
|
|
1399
|
-
action: 'Copy files to target directory',
|
|
1400
|
-
description: `Copy frontend files from ${taskWorkspace} to target directory`,
|
|
1401
|
-
reason: 'Only save final files to specified path'
|
|
1402
|
-
});
|
|
1403
|
-
return extractContent(fullContent, ['frontend', 'design', 'web', 'interface']);
|
|
1404
|
-
|
|
1405
|
-
case 'web-artifacts-builder':
|
|
1406
|
-
nextSteps.push({
|
|
1407
|
-
step: 3,
|
|
1408
|
-
action: 'Create workspace directory',
|
|
1409
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1410
|
-
reason: 'Create workspace directory for component files'
|
|
1411
|
-
});
|
|
1412
|
-
nextSteps.push({
|
|
1413
|
-
step: 4,
|
|
1414
|
-
action: 'Build React artifact in workspace',
|
|
1415
|
-
description: `Create React component files in ${taskWorkspace} using shadcn/ui`,
|
|
1416
|
-
reason: 'Build React component in workspace'
|
|
1417
|
-
});
|
|
1418
|
-
nextSteps.push({
|
|
1419
|
-
step: 5,
|
|
1420
|
-
action: 'Test artifact',
|
|
1421
|
-
description: `Test the artifact in ${taskWorkspace}`,
|
|
1422
|
-
reason: 'Test component functionality'
|
|
1423
|
-
});
|
|
1424
|
-
nextSteps.push({
|
|
1425
|
-
step: 6,
|
|
1426
|
-
action: 'Copy artifact to target directory',
|
|
1427
|
-
description: `Copy component files from ${taskWorkspace} to target directory`,
|
|
1428
|
-
reason: 'Only save final files to specified path'
|
|
1429
|
-
});
|
|
1430
|
-
return extractContent(fullContent, ['Web Artifacts Builder', 'React', 'Quick Start']);
|
|
1431
|
-
|
|
1432
|
-
case 'webapp-testing':
|
|
1433
|
-
const scriptsPath = `${skill.skillsPath}/scripts`;
|
|
1434
|
-
nextSteps.push({
|
|
1435
|
-
step: 3,
|
|
1436
|
-
action: 'Read documentation and helper script',
|
|
1437
|
-
description: 'Read SKILL.md and scripts/with_server.py',
|
|
1438
|
-
file: `${scriptsPath}/with_server.py`,
|
|
1439
|
-
reason: 'Understand webapp testing workflow and with_server.py usage'
|
|
1440
|
-
});
|
|
1441
|
-
nextSteps.push({
|
|
1442
|
-
step: 4,
|
|
1443
|
-
action: 'Create workspace directory',
|
|
1444
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1445
|
-
reason: 'Create workspace directory for test files'
|
|
1446
|
-
});
|
|
1447
|
-
nextSteps.push({
|
|
1448
|
-
step: 5,
|
|
1449
|
-
action: 'Write Playwright tests in workspace',
|
|
1450
|
-
description: `Create test.py in ${taskWorkspace} for web application testing`,
|
|
1451
|
-
reason: 'Write test scripts in workspace'
|
|
1452
|
-
});
|
|
1453
|
-
nextSteps.push({
|
|
1454
|
-
step: 6,
|
|
1455
|
-
action: 'Run tests with server',
|
|
1456
|
-
description: `Run: python "${scriptsPath}/with_server.py" --server "<start_command>" --port <port> -- python ${taskWorkspace}/test.py`,
|
|
1457
|
-
reason: 'Run tests with server using existing with_server.py helper'
|
|
1458
|
-
});
|
|
1459
|
-
nextSteps.push({
|
|
1460
|
-
step: 7,
|
|
1461
|
-
action: 'Copy test reports to target directory',
|
|
1462
|
-
description: `Copy test reports from ${taskWorkspace} to target directory`,
|
|
1463
|
-
reason: 'Only save test reports to specified path'
|
|
1464
|
-
});
|
|
1465
|
-
return extractContent(fullContent, ['test', 'web', 'playwright', 'testing']);
|
|
1466
|
-
|
|
1467
|
-
default:
|
|
1468
|
-
return extractContent(fullContent, ['frontend', 'design', 'web']);
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
/**
|
|
1474
|
-
* Visual Design Skill Executor
|
|
1475
|
-
*/
|
|
1476
|
-
class VisualDesignSkillExecutor implements SkillExecutor {
|
|
1477
|
-
async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
1478
|
-
const outputMessages: string[] = [];
|
|
1479
|
-
const files: string[] = [];
|
|
1480
|
-
const nextSteps: ExecutionStep[] = [];
|
|
1481
|
-
|
|
1482
|
-
outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
|
|
1483
|
-
outputMessages.push(`**Task**: ${params.taskDescription}\n`);
|
|
1484
|
-
|
|
1485
|
-
// Get or generate task ID
|
|
1486
|
-
const taskId = params.taskId || `${skill.id}-${Date.now()}`;
|
|
1487
|
-
|
|
1488
|
-
try {
|
|
1489
|
-
// Read SKILL.md content
|
|
1490
|
-
const skillMdPath = path.join(skill.skillsPath, 'SKILL.md');
|
|
1491
|
-
files.push(skillMdPath);
|
|
1492
|
-
const skillContent = await fs.readFile(skillMdPath, 'utf-8');
|
|
1493
|
-
|
|
1494
|
-
// Generate execution steps
|
|
1495
|
-
const taskContent = await this.extractVisualContent(skill, params, skillContent, nextSteps, taskId);
|
|
1496
|
-
outputMessages.push(taskContent);
|
|
1497
|
-
|
|
1498
|
-
// Add input/output files to list if they exist
|
|
1499
|
-
if (params.inputFile) files.push(params.inputFile);
|
|
1500
|
-
if (params.outputFile) files.push(params.outputFile);
|
|
1501
|
-
|
|
1502
|
-
return {
|
|
1503
|
-
success: true,
|
|
1504
|
-
output: outputMessages.join('\n'),
|
|
1505
|
-
files: files,
|
|
1506
|
-
nextSteps: nextSteps,
|
|
1507
|
-
requiresManualExecution: true
|
|
1508
|
-
};
|
|
1509
|
-
} catch (error: any) {
|
|
1510
|
-
return {
|
|
1511
|
-
success: false,
|
|
1512
|
-
error: error.message
|
|
1513
|
-
};
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
/**
|
|
1518
|
-
* Extract relevant content based on visual design skill type and generate steps
|
|
1519
|
-
*/
|
|
1520
|
-
private async extractVisualContent(
|
|
1521
|
-
skill: SkillInfo,
|
|
1522
|
-
params: SkillExecutionParams,
|
|
1523
|
-
fullContent: string,
|
|
1524
|
-
nextSteps: ExecutionStep[],
|
|
1525
|
-
taskId: string
|
|
1526
|
-
): Promise<string> {
|
|
1527
|
-
const taskLower = params.taskDescription.toLowerCase();
|
|
1528
|
-
const workspaceBase = getWorkspaceDescription();
|
|
1529
|
-
const taskWorkspace = `${workspaceBase}/${taskId}`;
|
|
1530
|
-
|
|
1531
|
-
switch (skill.id) {
|
|
1532
|
-
case 'canvas-design':
|
|
1533
|
-
// Canvas Design: Two-step process
|
|
1534
|
-
nextSteps.push({
|
|
1535
|
-
step: 1,
|
|
1536
|
-
action: 'Create workspace directory',
|
|
1537
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1538
|
-
reason: 'Create workspace directory for design files'
|
|
1539
|
-
});
|
|
1540
|
-
nextSteps.push({
|
|
1541
|
-
step: 2,
|
|
1542
|
-
action: 'Design Philosophy Creation',
|
|
1543
|
-
description: `Create manifesto/md file in ${taskWorkspace} defining aesthetic movement`,
|
|
1544
|
-
reason: 'Create design philosophy document in workspace'
|
|
1545
|
-
});
|
|
1546
|
-
nextSteps.push({
|
|
1547
|
-
step: 3,
|
|
1548
|
-
action: 'Canvas Creation',
|
|
1549
|
-
description: `Express philosophy visually using PDF/PNG output in ${taskWorkspace}`,
|
|
1550
|
-
reason: 'Express philosophy visually on canvas in workspace'
|
|
1551
|
-
});
|
|
1552
|
-
nextSteps.push({
|
|
1553
|
-
step: 4,
|
|
1554
|
-
action: 'Copy output to target directory',
|
|
1555
|
-
description: `Copy output files from ${taskWorkspace} to target directory`,
|
|
1556
|
-
reason: 'Only save final files to specified path'
|
|
1557
|
-
});
|
|
1558
|
-
return extractContent(fullContent, ['design', 'art', 'visual', 'philosophy']);
|
|
1559
|
-
|
|
1560
|
-
case 'algorithmic-art':
|
|
1561
|
-
// Algorithmic Art
|
|
1562
|
-
nextSteps.push({
|
|
1563
|
-
step: 1,
|
|
1564
|
-
action: 'Create workspace directory',
|
|
1565
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1566
|
-
reason: 'Create workspace directory for generative art files'
|
|
1567
|
-
});
|
|
1568
|
-
nextSteps.push({
|
|
1569
|
-
step: 2,
|
|
1570
|
-
action: 'Algorithmic Philosophy',
|
|
1571
|
-
description: `Define generative art philosophy in ${taskWorkspace}`,
|
|
1572
|
-
reason: 'Create generative art philosophy in workspace'
|
|
1573
|
-
});
|
|
1574
|
-
nextSteps.push({
|
|
1575
|
-
step: 3,
|
|
1576
|
-
action: 'P5.js Implementation',
|
|
1577
|
-
description: `Write p5.js code in ${taskWorkspace} for generative art`,
|
|
1578
|
-
reason: 'Implement generative art code in workspace'
|
|
1579
|
-
});
|
|
1580
|
-
nextSteps.push({
|
|
1581
|
-
step: 4,
|
|
1582
|
-
action: 'Generate artwork',
|
|
1583
|
-
description: `Run p5.js code in ${taskWorkspace} to generate artwork`,
|
|
1584
|
-
reason: 'Run generative art code'
|
|
1585
|
-
});
|
|
1586
|
-
nextSteps.push({
|
|
1587
|
-
step: 5,
|
|
1588
|
-
action: 'Copy output to target directory',
|
|
1589
|
-
description: `Copy output files from ${taskWorkspace} to target directory`,
|
|
1590
|
-
reason: 'Only save final files to specified path'
|
|
1591
|
-
});
|
|
1592
|
-
return extractContent(fullContent, ['generative', 'algorithmic', 'art']);
|
|
1593
|
-
|
|
1594
|
-
case 'theme-factory':
|
|
1595
|
-
// Theme Factory
|
|
1596
|
-
nextSteps.push({
|
|
1597
|
-
step: 1,
|
|
1598
|
-
action: 'Create workspace directory',
|
|
1599
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1600
|
-
reason: 'Create workspace directory for theme files'
|
|
1601
|
-
});
|
|
1602
|
-
nextSteps.push({
|
|
1603
|
-
step: 2,
|
|
1604
|
-
action: 'Select theme',
|
|
1605
|
-
description: `Choose from available themes or create custom in ${taskWorkspace}`,
|
|
1606
|
-
reason: 'Select or create theme in workspace'
|
|
1607
|
-
});
|
|
1608
|
-
nextSteps.push({
|
|
1609
|
-
step: 3,
|
|
1610
|
-
action: 'Apply theme',
|
|
1611
|
-
description: `Apply colors, fonts to design in ${taskWorkspace}`,
|
|
1612
|
-
reason: 'Apply theme to design in workspace'
|
|
1613
|
-
});
|
|
1614
|
-
nextSteps.push({
|
|
1615
|
-
step: 4,
|
|
1616
|
-
action: 'Copy output to target directory',
|
|
1617
|
-
description: `Copy theme files from ${taskWorkspace} to target directory`,
|
|
1618
|
-
reason: 'Only save final files to specified path'
|
|
1619
|
-
});
|
|
1620
|
-
return extractContent(fullContent, ['Theme Factory', 'Themes', 'apply']);
|
|
1621
|
-
|
|
1622
|
-
case 'brand-guidelines':
|
|
1623
|
-
// Brand Guidelines
|
|
1624
|
-
nextSteps.push({
|
|
1625
|
-
step: 1,
|
|
1626
|
-
action: 'Create workspace directory',
|
|
1627
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1628
|
-
reason: 'Create workspace directory for brand files'
|
|
1629
|
-
});
|
|
1630
|
-
nextSteps.push({
|
|
1631
|
-
step: 2,
|
|
1632
|
-
action: 'Apply brand colors',
|
|
1633
|
-
description: `Use Anthropic brand colors and typography in ${taskWorkspace}`,
|
|
1634
|
-
reason: 'Apply brand colors in workspace'
|
|
1635
|
-
});
|
|
1636
|
-
nextSteps.push({
|
|
1637
|
-
step: 3,
|
|
1638
|
-
action: 'Follow guidelines',
|
|
1639
|
-
description: `Apply brand styling consistently in ${taskWorkspace}`,
|
|
1640
|
-
reason: 'Follow brand guidelines in workspace'
|
|
1641
|
-
});
|
|
1642
|
-
nextSteps.push({
|
|
1643
|
-
step: 4,
|
|
1644
|
-
action: 'Copy output to target directory',
|
|
1645
|
-
description: `Copy brand files from ${taskWorkspace} to target directory`,
|
|
1646
|
-
reason: 'Only save final files to specified path'
|
|
1647
|
-
});
|
|
1648
|
-
return extractContent(fullContent, ['Brand Guidelines', 'Colors', 'Typography']);
|
|
1649
|
-
|
|
1650
|
-
default:
|
|
1651
|
-
nextSteps.push({
|
|
1652
|
-
step: 1,
|
|
1653
|
-
action: 'Create workspace directory',
|
|
1654
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1655
|
-
reason: 'Create workspace directory for design files'
|
|
1656
|
-
});
|
|
1657
|
-
nextSteps.push({
|
|
1658
|
-
step: 2,
|
|
1659
|
-
action: 'Create visual design',
|
|
1660
|
-
description: `Write design code or use canvas in ${taskWorkspace}`,
|
|
1661
|
-
reason: 'Create visual design in workspace'
|
|
1662
|
-
});
|
|
1663
|
-
nextSteps.push({
|
|
1664
|
-
step: 3,
|
|
1665
|
-
action: 'Copy output to target directory',
|
|
1666
|
-
description: `Copy output files from ${taskWorkspace} to target directory`,
|
|
1667
|
-
reason: 'Only save final files to specified path'
|
|
1668
|
-
});
|
|
1669
|
-
return extractContent(fullContent, ['design', 'art', 'visual']);
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
/**
|
|
1675
|
-
* Documentation Skill Executor
|
|
1676
|
-
*/
|
|
1677
|
-
class DocumentationSkillExecutor implements SkillExecutor {
|
|
1678
|
-
async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
1679
|
-
const outputMessages: string[] = [];
|
|
1680
|
-
const files: string[] = [];
|
|
1681
|
-
const nextSteps: ExecutionStep[] = [];
|
|
1682
|
-
|
|
1683
|
-
outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
|
|
1684
|
-
outputMessages.push(`**Task**: ${params.taskDescription}\n`);
|
|
1685
|
-
|
|
1686
|
-
// Get or generate task ID
|
|
1687
|
-
const taskId = params.taskId || `${skill.id}-${Date.now()}`;
|
|
1688
|
-
|
|
1689
|
-
try {
|
|
1690
|
-
// Read SKILL.md content
|
|
1691
|
-
const skillMdPath = path.join(skill.skillsPath, 'SKILL.md');
|
|
1692
|
-
files.push(skillMdPath);
|
|
1693
|
-
const skillContent = await fs.readFile(skillMdPath, 'utf-8');
|
|
1694
|
-
|
|
1695
|
-
// Generate execution steps
|
|
1696
|
-
const taskContent = await this.extractDocContent(skill, params, skillContent, nextSteps, taskId);
|
|
1697
|
-
outputMessages.push(taskContent);
|
|
1698
|
-
|
|
1699
|
-
// Add input/output files to list if they exist
|
|
1700
|
-
if (params.inputFile) files.push(params.inputFile);
|
|
1701
|
-
if (params.outputFile) files.push(params.outputFile);
|
|
1702
|
-
|
|
1703
|
-
return {
|
|
1704
|
-
success: true,
|
|
1705
|
-
output: outputMessages.join('\n'),
|
|
1706
|
-
files: files,
|
|
1707
|
-
nextSteps: nextSteps,
|
|
1708
|
-
requiresManualExecution: true
|
|
1709
|
-
};
|
|
1710
|
-
} catch (error: any) {
|
|
1711
|
-
return {
|
|
1712
|
-
success: false,
|
|
1713
|
-
error: error.message
|
|
1714
|
-
};
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
/**
|
|
1719
|
-
* Extract relevant content based on documentation skill type and generate steps
|
|
1720
|
-
*/
|
|
1721
|
-
private async extractDocContent(
|
|
1722
|
-
skill: SkillInfo,
|
|
1723
|
-
params: SkillExecutionParams,
|
|
1724
|
-
fullContent: string,
|
|
1725
|
-
nextSteps: ExecutionStep[],
|
|
1726
|
-
taskId: string
|
|
1727
|
-
): Promise<string> {
|
|
1728
|
-
const taskLower = params.taskDescription.toLowerCase();
|
|
1729
|
-
const workspaceBase = getWorkspaceDescription();
|
|
1730
|
-
const taskWorkspace = `${workspaceBase}/${taskId}`;
|
|
1731
|
-
|
|
1732
|
-
switch (skill.id) {
|
|
1733
|
-
case 'internal-comms':
|
|
1734
|
-
// Internal Comms
|
|
1735
|
-
if (taskLower.includes('status') || taskLower.includes('report')) {
|
|
1736
|
-
nextSteps.push({
|
|
1737
|
-
step: 1,
|
|
1738
|
-
action: 'Gather information',
|
|
1739
|
-
description: 'Collect progress, plans, problems',
|
|
1740
|
-
reason: 'Gather status information'
|
|
1741
|
-
});
|
|
1742
|
-
nextSteps.push({
|
|
1743
|
-
step: 2,
|
|
1744
|
-
action: 'Write update',
|
|
1745
|
-
description: 'Draft 3P update format',
|
|
1746
|
-
reason: 'Write status update'
|
|
1747
|
-
});
|
|
1748
|
-
} else if (taskLower.includes('newsletter')) {
|
|
1749
|
-
nextSteps.push({
|
|
1750
|
-
step: 1,
|
|
1751
|
-
action: 'Create newsletter',
|
|
1752
|
-
description: 'Write company newsletter content',
|
|
1753
|
-
reason: 'Create company newsletter'
|
|
1754
|
-
});
|
|
1755
|
-
}
|
|
1756
|
-
return extractContent(fullContent, ['documentation', 'writing', 'internal']);
|
|
1757
|
-
|
|
1758
|
-
case 'doc-coauthoring':
|
|
1759
|
-
// Doc Co-Authoring: Three-stage process
|
|
1760
|
-
nextSteps.push({
|
|
1761
|
-
step: 1,
|
|
1762
|
-
action: 'Create workspace directory',
|
|
1763
|
-
description: `Create workspace directory: ${taskWorkspace}/`,
|
|
1764
|
-
reason: 'Create workspace directory for document drafts'
|
|
1765
|
-
});
|
|
1766
|
-
nextSteps.push({
|
|
1767
|
-
step: 2,
|
|
1768
|
-
action: 'Stage 1: Context Gathering',
|
|
1769
|
-
description: 'Gather requirements and initial questions',
|
|
1770
|
-
reason: 'Gather document background and requirements'
|
|
1771
|
-
});
|
|
1772
|
-
nextSteps.push({
|
|
1773
|
-
step: 3,
|
|
1774
|
-
action: 'Stage 2: Refinement',
|
|
1775
|
-
description: `Structure and draft content in ${taskWorkspace}`,
|
|
1776
|
-
reason: 'Structure and draft document in workspace'
|
|
1777
|
-
});
|
|
1778
|
-
nextSteps.push({
|
|
1779
|
-
step: 4,
|
|
1780
|
-
action: 'Stage 3: Reader Testing',
|
|
1781
|
-
description: `Test with fresh Claude and refine in ${taskWorkspace}`,
|
|
1782
|
-
reason: 'Test and refine document in workspace'
|
|
1783
|
-
});
|
|
1784
|
-
nextSteps.push({
|
|
1785
|
-
step: 5,
|
|
1786
|
-
action: 'Copy final document to target directory',
|
|
1787
|
-
description: `Copy final document from ${taskWorkspace} to target directory`,
|
|
1788
|
-
reason: 'Only save final document to specified path'
|
|
1789
|
-
});
|
|
1790
|
-
return extractContent(fullContent, ['documentation', 'coauthor', 'workflow']);
|
|
1791
|
-
|
|
1792
|
-
default:
|
|
1793
|
-
return extractContent(fullContent, ['documentation', 'writing', 'guide']);
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
}
|
|
1797
|
-
|
|
1798
|
-
/**
|
|
1799
|
-
* Default Skill Executor
|
|
1800
|
-
*/
|
|
1801
|
-
class DefaultSkillExecutor implements SkillExecutor {
|
|
1802
|
-
async execute(skill: SkillInfo, params: SkillExecutionParams): Promise<SkillExecutionResult> {
|
|
1803
|
-
const outputMessages: string[] = [];
|
|
1804
|
-
const files: string[] = [];
|
|
1805
|
-
const nextSteps: ExecutionStep[] = [];
|
|
1806
|
-
|
|
1807
|
-
outputMessages.push(`## ${skill.name} Skill - Execution Guide\n`);
|
|
1808
|
-
outputMessages.push(`**Task**: ${params.taskDescription}\n`);
|
|
1809
|
-
|
|
1810
|
-
try {
|
|
1811
|
-
// Read SKILL.md content
|
|
1812
|
-
const skillMdPath = path.join(skill.skillsPath, 'SKILL.md');
|
|
1813
|
-
files.push(skillMdPath);
|
|
1814
|
-
const skillContent = await fs.readFile(skillMdPath, 'utf-8');
|
|
1815
|
-
|
|
1816
|
-
// Generate execution steps
|
|
1817
|
-
const taskContent = this.extractDefaultContent(skill, skillContent, nextSteps);
|
|
1818
|
-
outputMessages.push(taskContent);
|
|
1819
|
-
|
|
1820
|
-
// Add input/output files to list if they exist
|
|
1821
|
-
if (params.inputFile) files.push(params.inputFile);
|
|
1822
|
-
if (params.outputFile) files.push(params.outputFile);
|
|
1823
|
-
|
|
1824
|
-
return {
|
|
1825
|
-
success: true,
|
|
1826
|
-
output: outputMessages.join('\n'),
|
|
1827
|
-
files: files,
|
|
1828
|
-
nextSteps: nextSteps,
|
|
1829
|
-
requiresManualExecution: true
|
|
1830
|
-
};
|
|
1831
|
-
} catch (error: any) {
|
|
1832
|
-
return {
|
|
1833
|
-
success: false,
|
|
1834
|
-
error: error.message
|
|
1835
|
-
};
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
/**
|
|
1840
|
-
* Extract default skill content and generate steps
|
|
1841
|
-
*/
|
|
1842
|
-
private extractDefaultContent(skill: SkillInfo, fullContent: string, nextSteps: ExecutionStep[]): string {
|
|
1843
|
-
nextSteps.push({
|
|
1844
|
-
step: 1,
|
|
1845
|
-
action: 'Read SKILL.md',
|
|
1846
|
-
description: `Read ${skill.skillsPath}/SKILL.md for full instructions`,
|
|
1847
|
-
reason: 'Understand complete execution workflow'
|
|
1848
|
-
});
|
|
1849
|
-
nextSteps.push({
|
|
1850
|
-
step: 2,
|
|
1851
|
-
action: 'Follow workflow',
|
|
1852
|
-
description: 'Execute according to SKILL.md instructions',
|
|
1853
|
-
reason: 'Follow SKILL.md guidance for execution'
|
|
1854
|
-
});
|
|
1855
|
-
|
|
1856
|
-
return extractContent(fullContent, ['skill', 'guide', 'how to', skill.name]);
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
907
|
// ============================================================
|
|
1861
908
|
// ============================================================
|
|
1862
909
|
|
|
@@ -1870,7 +917,7 @@ export async function executeSkill(
|
|
|
1870
917
|
skill: SkillInfo,
|
|
1871
918
|
params: SkillExecutionParams
|
|
1872
919
|
): Promise<SkillExecutionResult> {
|
|
1873
|
-
const executor = new
|
|
920
|
+
const executor = new GenericSkillExecutor();
|
|
1874
921
|
return executor.execute(skill, params);
|
|
1875
922
|
}
|
|
1876
923
|
|