@deimoscloud/coreai 0.1.16 → 0.1.18

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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import { readFileSync as readFileSync6 } from "fs";
3
- import { dirname as dirname5, join as join8 } from "path";
3
+ import { dirname as dirname6, join as join8 } from "path";
4
4
  import { fileURLToPath } from "url";
5
5
 
6
6
  // src/config/loader.ts
@@ -446,7 +446,7 @@ function resolveAgentDefinition(agent, config, options = {}) {
446
446
 
447
447
  // src/agents/compiler.ts
448
448
  import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
449
- import { join as join3, dirname as dirname2, extname as extname2 } from "path";
449
+ import { join as join3, dirname as dirname2, extname as extname2, isAbsolute } from "path";
450
450
  import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
451
451
  function buildAgentTools(agent, mcpServers) {
452
452
  const tools = agent.tools ? [...agent.tools] : [...DEFAULT_AGENT_TOOLS];
@@ -460,16 +460,44 @@ function buildAgentTools(agent, mcpServers) {
460
460
  }
461
461
  return tools.join(", ");
462
462
  }
463
+ function processIncludes(template, templateDir, depth = 0, maxDepth = 3) {
464
+ if (depth > maxDepth) {
465
+ throw new Error(`Include depth exceeded maximum of ${maxDepth}`);
466
+ }
467
+ const includePattern = /<!--\s*include:\s*(\S+)\s*-->/g;
468
+ return template.replace(includePattern, (_match, includePath) => {
469
+ const resolvedPath = isAbsolute(includePath) ? includePath : join3(templateDir, includePath);
470
+ if (!existsSync3(resolvedPath)) {
471
+ throw new Error(`Include file not found: ${includePath} (resolved to ${resolvedPath})`);
472
+ }
473
+ const includedContent = readFileSync3(resolvedPath, "utf-8");
474
+ return processIncludes(includedContent, dirname2(resolvedPath), depth + 1, maxDepth);
475
+ });
476
+ }
463
477
  function processAgentTemplate(templatePath, agent, config, mcpServers) {
464
478
  const template = readFileSync3(templatePath, "utf-8");
465
- const context = { agent };
479
+ const templateDir = dirname2(templatePath);
480
+ const expandedTemplate = processIncludes(template, templateDir);
481
+ const earlyMatch = expandedTemplate.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
482
+ if (!earlyMatch) {
483
+ throw new Error(`Invalid markdown format in ${templatePath}: no frontmatter found`);
484
+ }
485
+ const earlyFrontmatter = parseYaml3(earlyMatch[1]);
486
+ const reservedKeys = /* @__PURE__ */ new Set(["name", "description", "tools"]);
487
+ const extendedAgent = { ...agent };
488
+ for (const [key, value] of Object.entries(earlyFrontmatter)) {
489
+ if (!reservedKeys.has(key) && !(key in extendedAgent)) {
490
+ extendedAgent[key] = value;
491
+ }
492
+ }
493
+ const context = { agent: extendedAgent };
466
494
  if (config) {
467
495
  context.config = config;
468
496
  }
469
- const resolved = resolveString(template, context);
497
+ const resolved = resolveString(expandedTemplate, context);
470
498
  const frontmatterMatch = resolved.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
471
499
  if (!frontmatterMatch) {
472
- throw new Error(`Invalid markdown format in ${templatePath}: no frontmatter found`);
500
+ throw new Error(`Invalid markdown format after resolution in ${templatePath}`);
473
501
  }
474
502
  const frontmatterYaml = frontmatterMatch[1];
475
503
  const body = frontmatterMatch[2] ?? "";
@@ -2667,469 +2695,123 @@ var StepTracker = class {
2667
2695
 
2668
2696
  // src/skills/generator.ts
2669
2697
  import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
2670
- import { join as join6, basename as basename3 } from "path";
2671
-
2672
- // src/skills/templates.ts
2673
- var checkInboxSkill = {
2674
- name: "check-inbox",
2675
- description: "Check your inbox for pending tasks and messages",
2676
- category: "core",
2677
- content: `---
2678
- description: Check your inbox for pending tasks and messages
2679
- ---
2680
-
2681
- # Check Inbox
2682
-
2683
- Check the inbox at \`KnowledgeLibrary/{{AGENT_NAME}}/inbox/\` for new messages.
2684
-
2685
- ## Instructions
2686
-
2687
- 1. Read all unprocessed messages in the inbox directory
2688
- 2. For each message:
2689
- - Parse the frontmatter (type, from, date, priority)
2690
- - Understand the request or task
2691
- - Take appropriate action based on message type
2692
- 3. After processing, move message to \`inbox/processed/\`
2693
- 4. Update your context file at \`KnowledgeLibrary/{{AGENT_NAME}}/context/current.txt\`
2694
-
2695
- ## Message Types
2696
-
2697
- - **task-assignment**: New work assigned to you
2698
- - **completion-report**: Another agent completed work
2699
- - **review-request**: Code review needed
2700
- - **feedback**: Response to your previous work
2701
-
2702
- ## Output Format
2703
-
2704
- Report what messages were processed and actions taken.
2705
- `
2706
- };
2707
- var delegateSkill = {
2708
- name: "delegate",
2709
- description: "Delegate a task to another agent via inbox messaging",
2710
- argumentHint: "<task-description> to <agent-name>",
2711
- category: "core",
2712
- content: `---
2713
- description: Delegate a task to another agent via inbox messaging
2714
- argument-hint: <task-description> to <agent-name>
2715
- ---
2716
-
2717
- # Delegate Task
2718
-
2719
- Delegate work to another agent using the inbox-based messaging system.
2720
-
2721
- ## CRITICAL: Do NOT use the Task tool
2722
-
2723
- Agent-to-agent delegation MUST use file-based messaging, not the Task tool.
2724
- The Task tool spawns subagents that lose MCP access.
2725
-
2726
- ## Instructions
2727
-
2728
- 1. Parse the delegation request to identify:
2729
- - The task to delegate
2730
- - The target agent
2731
-
2732
- 2. Create a message file in the target agent's inbox:
2733
- - Path: \`KnowledgeLibrary/<target-agent>/inbox/\`
2734
- - Filename: \`YYYYMMDD_HHMM-{{AGENT_NAME}}-<subject>.md\`
2735
-
2736
- 3. Use this message format:
2737
- \`\`\`markdown
2738
- ---
2739
- type: task-assignment
2740
- from: {{AGENT_NAME}}
2741
- to: <target-agent>
2742
- date: YYYY-MM-DD HH:MM
2743
- priority: P2
2744
- ---
2745
-
2746
- ## Task Assignment
2747
-
2748
- ### Description
2749
- <Clear description of what needs to be done>
2750
-
2751
- ### Context
2752
- <Any relevant context or background>
2753
-
2754
- ### Expected Deliverables
2755
- 1. <Deliverable 1>
2756
- 2. <Deliverable 2>
2757
-
2758
- ### Success Criteria
2759
- - <Criterion 1>
2760
- - <Criterion 2>
2761
- \`\`\`
2762
-
2763
- 4. Tell the user to invoke the target agent:
2764
- "Please invoke @<target-agent> to process this task."
2765
-
2766
- ## Output
2767
-
2768
- Confirm the delegation message was created and instruct user to invoke the agent.
2769
- `
2770
- };
2771
- var gitCommitSkill = {
2772
- name: "git-commit",
2773
- description: "Create a quality-gated git commit",
2774
- argumentHint: "<commit-message>",
2775
- category: "core",
2776
- dependencies: [{ type: "git", required: false, description: "For commit operations" }],
2777
- content: `---
2778
- description: Create a quality-gated git commit
2779
- argument-hint: <commit-message>
2780
- optional: [git]
2781
- ---
2782
-
2783
- # Git Commit
2784
-
2785
- Create a git commit after passing all quality gates.
2786
-
2787
- ## Quality Gates
2788
-
2789
- Run these checks before committing:
2790
-
2791
- 1. **Lint**: \`{{LINT_CMD}}\`
2792
- 2. **Tests**: \`{{TEST_CMD}}\`
2793
- 3. **Build**: \`{{BUILD_CMD}}\`
2794
-
2795
- ## Instructions
2796
-
2797
- 1. Stage the relevant files with \`git add\`
2798
- 2. Run all quality gate commands
2799
- 3. If any gate fails:
2800
- - Fix the issues
2801
- - Re-run the failed gate
2802
- - Continue only when all pass
2803
- 4. Create the commit with the provided message
2804
- 5. Format: Include ticket reference if applicable
2805
-
2806
- ## Commit Message Format
2807
-
2808
- \`\`\`
2809
- <type>(<scope>): <description>
2810
-
2811
- [optional body]
2812
-
2813
- [optional footer]
2814
- \`\`\`
2815
-
2816
- Types: feat, fix, docs, style, refactor, test, chore
2817
-
2818
- ## Fallbacks
2819
-
2820
- If quality gate commands are not configured:
2821
- - Ask the user what commands to run
2822
- - Or skip gates with user confirmation
2823
- `
2824
- };
2825
- var prCreateSkill = {
2826
- name: "pr-create",
2827
- description: "Create a pull request with proper format",
2828
- argumentHint: "[branch-name]",
2829
- category: "core",
2830
- dependencies: [{ type: "git", required: true, description: "For PR creation" }],
2831
- content: `---
2832
- description: Create a pull request with proper format
2833
- argument-hint: [branch-name]
2834
- requires: [git]
2835
- ---
2836
-
2837
- # Create Pull Request
2838
-
2839
- Create a well-formatted pull request for the current branch.
2840
-
2841
- ## Instructions
2842
-
2843
- 1. Ensure all changes are committed
2844
- 2. Push the branch to remote
2845
- 3. Create PR with proper format:
2846
-
2847
- \`\`\`markdown
2848
- ## Summary
2849
- <Brief description of changes>
2850
-
2851
- ## Changes
2852
- - <Change 1>
2853
- - <Change 2>
2854
-
2855
- ## Test Plan
2856
- - [ ] <Test case 1>
2857
- - [ ] <Test case 2>
2858
-
2859
- ## Related Issues
2860
- Closes {{JIRA_PROJECT}}-XXX
2861
- \`\`\`
2862
-
2863
- 4. Request reviewers if specified
2864
-
2865
- ## Using GitHub CLI
2866
-
2867
- \`\`\`bash
2868
- gh pr create --title "<title>" --body "<body>"
2869
- \`\`\`
2870
-
2871
- ## Output
2872
-
2873
- Provide the PR URL and summary of what was created.
2874
- `
2875
- };
2876
- var reviewSkill = {
2877
- name: "review",
2878
- description: "Request or perform a code review",
2879
- argumentHint: "<pr-number-or-url>",
2880
- category: "core",
2881
- dependencies: [{ type: "git", required: true, description: "For PR review" }],
2882
- content: `---
2883
- description: Request or perform a code review
2884
- argument-hint: <pr-number-or-url>
2885
- requires: [git]
2886
- ---
2887
-
2888
- # Code Review
2889
-
2890
- Review a pull request or delegate review to a specialist.
2891
-
2892
- ## Instructions
2893
-
2894
- ### If you are reviewing:
2895
-
2896
- 1. Fetch the PR details and diff
2897
- 2. Review for:
2898
- - Code quality and style
2899
- - Logic errors or bugs
2900
- - Security concerns
2901
- - Test coverage
2902
- - Documentation
2903
- 3. Provide feedback with specific line references
2904
- 4. Approve, request changes, or comment
2905
-
2906
- ### If delegating to a reviewer:
2907
-
2908
- 1. Identify the appropriate reviewer based on the changes
2909
- 2. Create a review request message in their inbox
2910
- 3. Include PR link and context
2911
-
2912
- ## Review Checklist
2913
-
2914
- - [ ] Code follows project conventions
2915
- - [ ] No obvious bugs or edge cases
2916
- - [ ] Tests cover the changes
2917
- - [ ] Documentation updated if needed
2918
- - [ ] No security vulnerabilities
2919
-
2920
- ## Output
2921
-
2922
- Provide review summary with actionable feedback.
2923
- `
2924
- };
2925
- var sprintStatusSkill = {
2926
- name: "sprint-status",
2927
- description: "Get current sprint status and progress",
2928
- category: "optional",
2929
- dependencies: [{ type: "issue_tracker", required: true, description: "For sprint data" }],
2930
- content: `---
2931
- description: Get current sprint status and progress
2932
- requires: [issue_tracker]
2933
- ---
2934
-
2935
- # Sprint Status
2936
-
2937
- Get the current sprint status and team progress.
2938
-
2939
- ## Instructions
2940
-
2941
- 1. Query the active sprint for project {{JIRA_PROJECT}}
2942
- 2. Gather metrics:
2943
- - Total story points committed
2944
- - Points completed
2945
- - Points in progress
2946
- - Points remaining
2947
- 3. List tickets by status
2948
- 4. Identify blockers or at-risk items
2949
-
2950
- ## Output Format
2951
-
2952
- \`\`\`
2953
- Sprint: <sprint-name>
2954
- Progress: XX/YY points (ZZ%)
2955
-
2956
- ## Completed
2957
- - [{{JIRA_PROJECT}}-123] Task name (3 pts)
2958
-
2959
- ## In Progress
2960
- - [{{JIRA_PROJECT}}-124] Task name (5 pts) - @assignee
2961
-
2962
- ## To Do
2963
- - [{{JIRA_PROJECT}}-125] Task name (2 pts)
2964
-
2965
- ## Blocked
2966
- - [{{JIRA_PROJECT}}-126] Task name - Reason
2967
- \`\`\`
2968
-
2969
- ## Fallbacks
2970
-
2971
- If issue tracker is unavailable:
2972
- - Report that sprint data cannot be fetched
2973
- - Suggest checking the issue tracker directly at {{JIRA_URL}}
2974
- `
2975
- };
2976
- var jiraCreateSkill = {
2977
- name: "jira-create",
2978
- description: "Create a new Jira ticket",
2979
- argumentHint: "<ticket-type> <summary>",
2980
- category: "optional",
2981
- dependencies: [{ type: "issue_tracker", required: true, description: "For ticket creation" }],
2982
- content: `---
2983
- description: Create a new Jira ticket
2984
- argument-hint: <ticket-type> <summary>
2985
- requires: [issue_tracker]
2986
- ---
2987
-
2988
- # Create Jira Ticket
2989
-
2990
- Create a new ticket in project {{JIRA_PROJECT}}.
2991
-
2992
- ## Instructions
2993
-
2994
- 1. Parse the ticket type and summary from arguments
2995
- 2. Gather additional details:
2996
- - Description
2997
- - Priority
2998
- - Labels
2999
- - Components (if applicable)
3000
- 3. Create the ticket via the issue tracker integration
3001
- 4. Return the ticket key and URL
3002
-
3003
- ## Ticket Types
3004
-
3005
- - **Story**: User-facing feature
3006
- - **Bug**: Defect to fix
3007
- - **Task**: Technical work
3008
- - **Spike**: Research/investigation
3009
-
3010
- ## Output
3011
-
3012
- \`\`\`
3013
- Created: {{JIRA_PROJECT}}-XXX
3014
- URL: {{JIRA_URL}}/browse/{{JIRA_PROJECT}}-XXX
3015
- Summary: <summary>
3016
- Type: <type>
3017
- \`\`\`
3018
-
3019
- ## Fallbacks
3020
-
3021
- If issue tracker is unavailable:
3022
- - Provide the user with manual creation instructions
3023
- - Include all details they should enter
3024
- `
3025
- };
3026
- var jiraTransitionSkill = {
3027
- name: "jira-transition",
3028
- description: "Transition a Jira ticket to a new status",
3029
- argumentHint: "<ticket-key> to <status>",
3030
- category: "optional",
3031
- dependencies: [{ type: "issue_tracker", required: true, description: "For ticket transitions" }],
3032
- content: `---
3033
- description: Transition a Jira ticket to a new status
3034
- argument-hint: <ticket-key> to <status>
3035
- requires: [issue_tracker]
3036
- ---
3037
-
3038
- # Transition Jira Ticket
3039
-
3040
- Update the status of a ticket in {{JIRA_PROJECT}}.
3041
-
3042
- ## Status Mapping
3043
-
3044
- | Workflow Status | Jira Status |
3045
- |-----------------|-------------|
3046
- | BACKLOG | Backlog |
3047
- | IN_PROGRESS | In Progress |
3048
- | PR_CREATED | In Review |
3049
- | IN_REVIEW | In Review |
3050
- | APPROVED | Ready to Merge |
3051
- | MERGED | Done |
3052
- | DONE | Done |
3053
-
3054
- ## Instructions
3055
-
3056
- 1. Parse ticket key and target status
3057
- 2. Validate the transition is allowed
3058
- 3. Add a comment explaining the transition
3059
- 4. Execute the transition
3060
-
3061
- ## Transition Comment Format
3062
-
3063
- \`\`\`
3064
- Status updated to <status>.
3065
- <optional context about why>
3066
- \`\`\`
3067
-
3068
- ## Fallbacks
3069
-
3070
- If issue tracker is unavailable:
3071
- - Instruct user to manually transition at {{JIRA_URL}}
3072
- - Provide the target status name
3073
- `
3074
- };
3075
- var docsUpdateSkill = {
3076
- name: "docs-update",
3077
- description: "Update project documentation",
3078
- argumentHint: "<doc-path-or-topic>",
3079
- category: "optional",
3080
- dependencies: [{ type: "documentation", required: false, description: "For remote docs" }],
3081
- content: `---
3082
- description: Update project documentation
3083
- argument-hint: <doc-path-or-topic>
3084
- optional: [documentation]
3085
- ---
3086
-
3087
- # Update Documentation
3088
-
3089
- Update project documentation for a specific topic or file.
3090
-
3091
- ## Instructions
3092
-
3093
- 1. Identify the documentation to update:
3094
- - Local: \`{{DOCS_PATH}}/\`
3095
- - Remote: {{CONFLUENCE_SPACE}} (if configured)
3096
-
3097
- 2. Make the necessary updates:
3098
- - Keep formatting consistent
3099
- - Update examples if code changed
3100
- - Add/update version information
3101
-
3102
- 3. For remote documentation:
3103
- - Use the documentation integration
3104
- - Or provide content for manual update
3105
-
3106
- ## Documentation Types
3107
-
3108
- - **README**: Project overview and setup
3109
- - **API Docs**: Endpoint documentation
3110
- - **Architecture**: Design decisions
3111
- - **Runbooks**: Operational procedures
3112
-
3113
- ## Fallbacks
3114
-
3115
- If documentation integration is unavailable:
3116
- - Create/update local markdown files
3117
- - Provide instructions for manual remote update
3118
- `
3119
- };
3120
- var builtInSkills = [
3121
- checkInboxSkill,
3122
- delegateSkill,
3123
- gitCommitSkill,
3124
- prCreateSkill,
3125
- reviewSkill,
3126
- sprintStatusSkill,
3127
- jiraCreateSkill,
3128
- jiraTransitionSkill,
3129
- docsUpdateSkill
3130
- ];
3131
-
3132
- // src/skills/generator.ts
2698
+ import { join as join6, dirname as dirname5 } from "path";
2699
+ function getCoreSkillsDir() {
2700
+ let currentDir = dirname5(import.meta.url.replace("file://", ""));
2701
+ for (let i = 0; i < 5; i++) {
2702
+ if (existsSync4(join6(currentDir, "package.json"))) {
2703
+ return join6(currentDir, "skills");
2704
+ }
2705
+ currentDir = dirname5(currentDir);
2706
+ }
2707
+ return join6(dirname5(dirname5(dirname5(import.meta.url.replace("file://", "")))), "skills");
2708
+ }
2709
+ function discoverSkills(skillsDir) {
2710
+ const templates = [];
2711
+ if (!existsSync4(skillsDir)) {
2712
+ return templates;
2713
+ }
2714
+ const categories = readdirSync2(skillsDir);
2715
+ for (const category of categories) {
2716
+ const categoryPath = join6(skillsDir, category);
2717
+ const stat = statSync(categoryPath);
2718
+ if (!stat.isDirectory()) continue;
2719
+ if (category.startsWith(".") || category.startsWith("_")) continue;
2720
+ const skillDirs = readdirSync2(categoryPath);
2721
+ for (const skillName of skillDirs) {
2722
+ const skillDir = join6(categoryPath, skillName);
2723
+ const skillStat = statSync(skillDir);
2724
+ if (!skillStat.isDirectory()) continue;
2725
+ const skillFile = join6(skillDir, "SKILL.md");
2726
+ if (!existsSync4(skillFile)) continue;
2727
+ try {
2728
+ const content = readFileSync4(skillFile, "utf-8");
2729
+ const template = parseSkillFile(skillName, category, content);
2730
+ templates.push(template);
2731
+ } catch {
2732
+ }
2733
+ }
2734
+ }
2735
+ return templates;
2736
+ }
2737
+ function parseSkillFile(name, category, content) {
2738
+ const template = {
2739
+ name,
2740
+ description: name,
2741
+ category,
2742
+ content
2743
+ };
2744
+ const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
2745
+ if (!frontmatterMatch) {
2746
+ return template;
2747
+ }
2748
+ const frontmatter = frontmatterMatch[1];
2749
+ const lines = frontmatter.split(/\r?\n/);
2750
+ const dependencies = [];
2751
+ for (const line of lines) {
2752
+ const colonIndex = line.indexOf(":");
2753
+ if (colonIndex === -1) continue;
2754
+ const key = line.slice(0, colonIndex).trim();
2755
+ let value = line.slice(colonIndex + 1).trim();
2756
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2757
+ value = value.slice(1, -1);
2758
+ }
2759
+ switch (key) {
2760
+ case "name":
2761
+ template.name = value;
2762
+ break;
2763
+ case "description":
2764
+ template.description = value;
2765
+ break;
2766
+ case "argument-hint":
2767
+ template.argumentHint = value;
2768
+ break;
2769
+ case "requires":
2770
+ if (value.startsWith("[") && value.endsWith("]")) {
2771
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
2772
+ for (const item of items) {
2773
+ if (item) {
2774
+ dependencies.push({
2775
+ type: mapIntegrationName(item),
2776
+ required: true
2777
+ });
2778
+ }
2779
+ }
2780
+ }
2781
+ break;
2782
+ case "optional":
2783
+ if (value.startsWith("[") && value.endsWith("]")) {
2784
+ const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
2785
+ for (const item of items) {
2786
+ if (item) {
2787
+ dependencies.push({
2788
+ type: mapIntegrationName(item),
2789
+ required: false
2790
+ });
2791
+ }
2792
+ }
2793
+ }
2794
+ break;
2795
+ }
2796
+ }
2797
+ if (dependencies.length > 0) {
2798
+ template.dependencies = dependencies;
2799
+ }
2800
+ return template;
2801
+ }
2802
+ function mapIntegrationName(name) {
2803
+ const lower = name.toLowerCase();
2804
+ if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
2805
+ return "issue_tracker";
2806
+ }
2807
+ if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
2808
+ return "git";
2809
+ }
2810
+ if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
2811
+ return "documentation";
2812
+ }
2813
+ return "state";
2814
+ }
3133
2815
  function extractVariables2(config) {
3134
2816
  const vars = {};
3135
2817
  if (!config) {
@@ -3239,112 +2921,12 @@ function checkDependencies(skill, config) {
3239
2921
  missing
3240
2922
  };
3241
2923
  }
3242
- function loadCustomTemplates(templatesDir) {
3243
- const templates = [];
3244
- if (!existsSync4(templatesDir)) {
3245
- return templates;
3246
- }
3247
- const files = readdirSync2(templatesDir);
3248
- for (const file of files) {
3249
- if (!file.endsWith(".md")) continue;
3250
- const filePath = join6(templatesDir, file);
3251
- const stat = statSync(filePath);
3252
- if (!stat.isFile()) continue;
3253
- try {
3254
- const content = readFileSync4(filePath, "utf-8");
3255
- const template = parseSkillTemplate(file, content);
3256
- templates.push(template);
3257
- } catch {
3258
- }
3259
- }
3260
- return templates;
3261
- }
3262
- function parseSkillTemplate(filename, content) {
3263
- const name = basename3(filename, ".md");
3264
- const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
3265
- let description = name;
3266
- let argumentHint;
3267
- const dependencies = [];
3268
- if (frontmatterMatch) {
3269
- const frontmatter = frontmatterMatch[1] ?? "";
3270
- const lines = frontmatter.split(/\r?\n/);
3271
- for (const line of lines) {
3272
- const colonIndex = line.indexOf(":");
3273
- if (colonIndex === -1) continue;
3274
- const key = line.slice(0, colonIndex).trim();
3275
- let value = line.slice(colonIndex + 1).trim();
3276
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3277
- value = value.slice(1, -1);
3278
- }
3279
- switch (key) {
3280
- case "description":
3281
- description = value;
3282
- break;
3283
- case "argument-hint":
3284
- argumentHint = value;
3285
- break;
3286
- case "requires":
3287
- if (value.startsWith("[") && value.endsWith("]")) {
3288
- const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3289
- for (const item of items) {
3290
- if (item) {
3291
- dependencies.push({
3292
- type: mapIntegrationName(item),
3293
- required: true
3294
- });
3295
- }
3296
- }
3297
- }
3298
- break;
3299
- case "optional":
3300
- if (value.startsWith("[") && value.endsWith("]")) {
3301
- const items = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
3302
- for (const item of items) {
3303
- if (item) {
3304
- dependencies.push({
3305
- type: mapIntegrationName(item),
3306
- required: false
3307
- });
3308
- }
3309
- }
3310
- }
3311
- break;
3312
- }
3313
- }
3314
- }
3315
- const template = {
3316
- name,
3317
- description,
3318
- category: "custom",
3319
- content
3320
- };
3321
- if (argumentHint) {
3322
- template.argumentHint = argumentHint;
3323
- }
3324
- if (dependencies.length > 0) {
3325
- template.dependencies = dependencies;
3326
- }
3327
- return template;
3328
- }
3329
- function mapIntegrationName(name) {
3330
- const lower = name.toLowerCase();
3331
- if (["jira", "linear", "issue_tracker", "issues", "github-issues"].includes(lower)) {
3332
- return "issue_tracker";
3333
- }
3334
- if (["git", "github", "gitlab", "bitbucket"].includes(lower)) {
3335
- return "git";
3336
- }
3337
- if (["docs", "documentation", "confluence", "notion", "wiki"].includes(lower)) {
3338
- return "documentation";
3339
- }
3340
- return "state";
3341
- }
3342
2924
  function generateSkills(config, options = {}) {
3343
2925
  const projectRoot = options.projectRoot ?? process.cwd();
3344
- const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "commands");
2926
+ const coreSkillsDir = options.coreSkillsDir ?? getCoreSkillsDir();
2927
+ const outputDir = options.outputDir ?? join6(projectRoot, ".claude", "skills");
3345
2928
  const includeCoreSkills = options.includeCoreSkills ?? true;
3346
- const includeOptionalSkills = options.includeOptionalSkills ?? true;
3347
- const overwrite = options.overwrite ?? false;
2929
+ const overwrite = options.overwrite ?? true;
3348
2930
  const result = {
3349
2931
  generated: [],
3350
2932
  errors: [],
@@ -3357,21 +2939,17 @@ function generateSkills(config, options = {}) {
3357
2939
  result.variables = variables;
3358
2940
  let templates = [];
3359
2941
  if (includeCoreSkills) {
3360
- templates.push(...builtInSkills.filter((s) => s.category === "core"));
3361
- }
3362
- if (includeOptionalSkills) {
3363
- templates.push(...builtInSkills.filter((s) => s.category === "optional"));
2942
+ const discovered = discoverSkills(coreSkillsDir);
2943
+ templates.push(...discovered);
3364
2944
  }
3365
2945
  if (options.customTemplatesDir && existsSync4(options.customTemplatesDir)) {
3366
- templates.push(...loadCustomTemplates(options.customTemplatesDir));
2946
+ const custom = discoverSkills(options.customTemplatesDir);
2947
+ templates.push(...custom);
3367
2948
  }
3368
2949
  if (options.skills && options.skills.length > 0) {
3369
2950
  const skillsToInclude = options.skills;
3370
2951
  templates = templates.filter((t) => skillsToInclude.includes(t.name));
3371
2952
  }
3372
- if (!existsSync4(outputDir)) {
3373
- mkdirSync2(outputDir, { recursive: true });
3374
- }
3375
2953
  for (const template of templates) {
3376
2954
  try {
3377
2955
  const generated = generateSkill(template, variables, config, outputDir, overwrite);
@@ -3386,7 +2964,8 @@ function generateSkills(config, options = {}) {
3386
2964
  return result;
3387
2965
  }
3388
2966
  function generateSkill(template, variables, config, outputDir, overwrite) {
3389
- const outputPath = join6(outputDir, `${template.name}.md`);
2967
+ const skillDir = join6(outputDir, template.name);
2968
+ const outputPath = join6(skillDir, "SKILL.md");
3390
2969
  if (existsSync4(outputPath) && !overwrite) {
3391
2970
  return {
3392
2971
  name: template.name,
@@ -3409,6 +2988,9 @@ function generateSkill(template, variables, config, outputDir, overwrite) {
3409
2988
  }
3410
2989
  const content = substituteVariables(template.content, variables);
3411
2990
  const isUpdate = existsSync4(outputPath);
2991
+ if (!existsSync4(skillDir)) {
2992
+ mkdirSync2(skillDir, { recursive: true });
2993
+ }
3412
2994
  writeFileSync2(outputPath, content, "utf-8");
3413
2995
  return {
3414
2996
  name: template.name,
@@ -3452,7 +3034,7 @@ function formatGenerateResult(result) {
3452
3034
  }
3453
3035
  const total = created.length + updated.length;
3454
3036
  if (total > 0) {
3455
- lines.push(`Generated ${total} skill(s) to .claude/commands/`);
3037
+ lines.push(`Generated ${total} skill(s) to .claude/skills/`);
3456
3038
  } else if (result.generated.length === 0 && result.errors.length === 0) {
3457
3039
  lines.push("No skills to generate.");
3458
3040
  }
@@ -3469,7 +3051,7 @@ import {
3469
3051
  renameSync,
3470
3052
  statSync as statSync2
3471
3053
  } from "fs";
3472
- import { join as join7, basename as basename4 } from "path";
3054
+ import { join as join7, basename as basename3 } from "path";
3473
3055
  var DEFAULT_KNOWLEDGE_LIBRARY_PATH = "KnowledgeLibrary";
3474
3056
  var STANDARD_FILES = {
3475
3057
  context: "context.txt",
@@ -3993,9 +3575,9 @@ function formatKnowledgeLibraryState(state) {
3993
3575
  lines.push(`KnowledgeLibrary: ${state.basePath}
3994
3576
  `);
3995
3577
  lines.push("Global files:");
3996
- lines.push(` - ${basename4(state.contextPath)}`);
3997
- lines.push(` - ${basename4(state.architecturePath)}`);
3998
- lines.push(` - ${basename4(state.prdPath)}`);
3578
+ lines.push(` - ${basename3(state.contextPath)}`);
3579
+ lines.push(` - ${basename3(state.architecturePath)}`);
3580
+ lines.push(` - ${basename3(state.prdPath)}`);
3999
3581
  lines.push("");
4000
3582
  if (state.agents.length > 0) {
4001
3583
  lines.push(`Agents (${state.agents.length}):`);
@@ -4040,8 +3622,8 @@ function formatAgentKnowledgeState(state) {
4040
3622
 
4041
3623
  // src/index.ts
4042
3624
  function findPackageJson() {
4043
- let dir = dirname5(fileURLToPath(import.meta.url));
4044
- while (dir !== dirname5(dir)) {
3625
+ let dir = dirname6(fileURLToPath(import.meta.url));
3626
+ while (dir !== dirname6(dir)) {
4045
3627
  const pkgPath = join8(dir, "package.json");
4046
3628
  try {
4047
3629
  const content = readFileSync6(pkgPath, "utf-8");
@@ -4051,7 +3633,7 @@ function findPackageJson() {
4051
3633
  }
4052
3634
  } catch {
4053
3635
  }
4054
- dir = dirname5(dir);
3636
+ dir = dirname6(dir);
4055
3637
  }
4056
3638
  return '{"version": "unknown"}';
4057
3639
  }
@@ -4077,7 +3659,6 @@ export {
4077
3659
  StepTracker,
4078
3660
  VERSION,
4079
3661
  agentKnowledgeLibraryExists,
4080
- builtInSkills,
4081
3662
  checkDependencies,
4082
3663
  cleanupContext,
4083
3664
  compileAgent,
@@ -4091,6 +3672,7 @@ export {
4091
3672
  createContextLoader,
4092
3673
  createDegradingHandler,
4093
3674
  createFileCacheProvider,
3675
+ discoverSkills,
4094
3676
  executeWithDegradation,
4095
3677
  extractVariables2 as extractSkillVariables,
4096
3678
  extractVariables,
@@ -4106,6 +3688,7 @@ export {
4106
3688
  getAgentKnowledgeState,
4107
3689
  getConfigPath,
4108
3690
  getCoreAgentsDir,
3691
+ getCoreSkillsDir,
4109
3692
  getGlobalRegistry,
4110
3693
  getKnowledgeLibraryState,
4111
3694
  getRoleFromFilename,
@@ -4121,9 +3704,9 @@ export {
4121
3704
  loadConfig,
4122
3705
  loadConfigFromFile,
4123
3706
  loadCoreAICommands,
4124
- loadCustomTemplates,
4125
3707
  markMessageProcessed,
4126
3708
  parseAgentYaml,
3709
+ parseSkillFile,
4127
3710
  readInboxMessages,
4128
3711
  resetGlobalRegistry,
4129
3712
  resolveAgentDefinition,