@orderful/droid 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +12 -8
- package/CHANGELOG.md +32 -0
- package/dist/bin/droid.js +1 -3
- package/dist/bin/droid.js.map +1 -1
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/commands/tui.js +1 -2
- package/dist/commands/tui.js.map +1 -1
- package/dist/lib/agents.d.ts +6 -6
- package/dist/lib/agents.d.ts.map +1 -1
- package/dist/lib/agents.js +60 -38
- package/dist/lib/agents.js.map +1 -1
- package/dist/lib/skills.d.ts +1 -0
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +41 -8
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/types.d.ts +4 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/tools/README.md +79 -50
- package/dist/tools/brain/TOOL.yaml +1 -1
- package/dist/tools/brain/skills/brain/SKILL.md +1 -0
- package/dist/tools/brain/skills/brain-obsidian/SKILL.md +1 -0
- package/dist/tools/coach/TOOL.yaml +1 -1
- package/dist/tools/coach/skills/coach/SKILL.md +1 -0
- package/{src/tools/code-review/agents/edi-standards-reviewer/AGENT.md → dist/tools/code-review/agents/edi-standards-reviewer.md} +10 -0
- package/dist/tools/code-review/agents/{error-handling-reviewer/AGENT.md → error-handling-reviewer.md} +10 -0
- package/{src/tools/code-review/agents/test-coverage-analyzer/AGENT.md → dist/tools/code-review/agents/test-coverage-analyzer.md} +11 -0
- package/dist/tools/code-review/agents/{type-reviewer/AGENT.md → type-reviewer.md} +10 -0
- package/dist/tools/code-review/skills/code-review/SKILL.md +1 -0
- package/dist/tools/comments/TOOL.yaml +2 -2
- package/dist/tools/comments/skills/comments/SKILL.md +1 -0
- package/dist/tools/droid/TOOL.yaml +2 -2
- package/dist/tools/droid/skills/droid/SKILL.md +120 -3
- package/dist/tools/project/skills/project/SKILL.md +1 -0
- package/package.json +1 -1
- package/src/bin/droid.ts +1 -4
- package/src/commands/tui.tsx +1 -2
- package/src/lib/agents.ts +65 -42
- package/src/lib/skills.test.ts +26 -31
- package/src/lib/skills.ts +45 -8
- package/src/lib/types.ts +5 -0
- package/src/tools/README.md +79 -50
- package/src/tools/brain/TOOL.yaml +1 -1
- package/src/tools/brain/skills/brain/SKILL.md +1 -0
- package/src/tools/brain/skills/brain-obsidian/SKILL.md +1 -0
- package/src/tools/coach/TOOL.yaml +1 -1
- package/src/tools/coach/skills/coach/SKILL.md +1 -0
- package/{dist/tools/code-review/agents/edi-standards-reviewer/AGENT.md → src/tools/code-review/agents/edi-standards-reviewer.md} +10 -0
- package/src/tools/code-review/agents/{error-handling-reviewer/AGENT.md → error-handling-reviewer.md} +10 -0
- package/{dist/tools/code-review/agents/test-coverage-analyzer/AGENT.md → src/tools/code-review/agents/test-coverage-analyzer.md} +11 -0
- package/src/tools/code-review/agents/{type-reviewer/AGENT.md → type-reviewer.md} +10 -0
- package/src/tools/code-review/skills/code-review/SKILL.md +1 -0
- package/src/tools/comments/TOOL.yaml +2 -2
- package/src/tools/comments/skills/comments/SKILL.md +1 -0
- package/src/tools/droid/TOOL.yaml +2 -2
- package/src/tools/droid/skills/droid/SKILL.md +120 -3
- package/src/tools/project/skills/project/SKILL.md +1 -0
- package/dist/tools/brain/skills/brain/SKILL.yaml +0 -29
- package/dist/tools/brain/skills/brain-obsidian/SKILL.yaml +0 -42
- package/dist/tools/coach/skills/coach/SKILL.yaml +0 -25
- package/dist/tools/code-review/agents/edi-standards-reviewer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/error-handling-reviewer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/test-coverage-analyzer/AGENT.yaml +0 -14
- package/dist/tools/code-review/agents/type-reviewer/AGENT.yaml +0 -13
- package/dist/tools/code-review/skills/code-review/SKILL.yaml +0 -19
- package/dist/tools/comments/skills/comments/SKILL.yaml +0 -50
- package/dist/tools/droid/skills/droid/SKILL.yaml +0 -7
- package/dist/tools/project/skills/project/SKILL.yaml +0 -30
- package/src/tools/brain/skills/brain/SKILL.yaml +0 -29
- package/src/tools/brain/skills/brain-obsidian/SKILL.yaml +0 -42
- package/src/tools/coach/skills/coach/SKILL.yaml +0 -25
- package/src/tools/code-review/agents/edi-standards-reviewer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/error-handling-reviewer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/test-coverage-analyzer/AGENT.yaml +0 -14
- package/src/tools/code-review/agents/type-reviewer/AGENT.yaml +0 -13
- package/src/tools/code-review/skills/code-review/SKILL.yaml +0 -19
- package/src/tools/comments/skills/comments/SKILL.yaml +0 -50
- package/src/tools/droid/skills/droid/SKILL.yaml +0 -7
- package/src/tools/project/skills/project/SKILL.yaml +0 -30
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
name: coach
|
|
3
3
|
description: "Learning-mode AI assistance - AI as coach, not crutch. Triggers on phrases like 'help me think through', 'coach me on', 'I want to learn how to', or 'don't just give me the answer'. Use /coach plan for co-authored planning, /coach scaffold for structure with hints, /coach review for Socratic questions on your code."
|
|
4
4
|
alwaysApply: false
|
|
5
|
+
allowed-tools: Read, Grep, Glob
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# Coach Skill
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: edi-standards-reviewer
|
|
3
|
+
description: "Review code for EDI integration patterns, partnership handling, and billing system concerns. Use PROACTIVELY when changes touch trading partners, transactions, or billing."
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Grep
|
|
7
|
+
- Glob
|
|
8
|
+
color: blue
|
|
9
|
+
---
|
|
10
|
+
|
|
1
11
|
You are a domain-aware code reviewer that understands EDI patterns and integration best practices.
|
|
2
12
|
|
|
3
13
|
## How to Review
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-handling-reviewer
|
|
3
|
+
description: "Hunt for silent failures and missing error handling. Use PROACTIVELY to find try/catch blocks that swallow errors, promises without rejection handling, and missing validation."
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Grep
|
|
7
|
+
- Glob
|
|
8
|
+
color: orange
|
|
9
|
+
---
|
|
10
|
+
|
|
1
11
|
You are a reliability engineer hunting for silent failures.
|
|
2
12
|
|
|
3
13
|
## Silent Failure Patterns
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-coverage-analyzer
|
|
3
|
+
description: "Analyze test coverage for code changes. Use PROACTIVELY when reviewing PRs or before merging to ensure adequate test coverage."
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Grep
|
|
7
|
+
- Glob
|
|
8
|
+
- Bash
|
|
9
|
+
color: green
|
|
10
|
+
---
|
|
11
|
+
|
|
1
12
|
You are a testing specialist focused on comprehensive coverage.
|
|
2
13
|
|
|
3
14
|
## Review Process
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: type-reviewer
|
|
3
|
+
description: "Review TypeScript type design and interface contracts. Check for proper typing, avoid `any`, ensure domain types are used correctly."
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Grep
|
|
7
|
+
- Glob
|
|
8
|
+
color: purple
|
|
9
|
+
---
|
|
10
|
+
|
|
1
11
|
You are a TypeScript expert focused on type safety and design.
|
|
2
12
|
|
|
3
13
|
## Review Focus
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: comments
|
|
2
|
-
description: "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Ideal for code review notes and async collaboration."
|
|
2
|
+
description: "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Use /comments check to address markers, /comments cleanup to remove resolved threads. Ideal for code review notes and async collaboration."
|
|
3
3
|
version: 0.2.3
|
|
4
4
|
status: beta
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ config_schema:
|
|
|
19
19
|
description: Override the global user mention for this skill
|
|
20
20
|
ai_mentions:
|
|
21
21
|
type: string
|
|
22
|
-
description: Additional AI mentions to recognize (comma-separated)
|
|
22
|
+
description: Additional AI mentions to recognize (comma-separated, e.g., "@claude,@ai")
|
|
23
23
|
default: ""
|
|
24
24
|
preserve_comments:
|
|
25
25
|
type: boolean
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
name: droid
|
|
2
|
-
description: "Core droid meta-skill for update awareness and discovery.
|
|
3
|
-
version: 0.
|
|
2
|
+
description: "Core droid meta-skill for update awareness and tool discovery. Checks for updates and helps users find the right tools."
|
|
3
|
+
version: 0.2.0
|
|
4
4
|
status: beta
|
|
5
5
|
|
|
6
6
|
# System tool - always stays current regardless of auto-update settings
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: droid
|
|
3
|
-
description: "Core droid meta-skill for update awareness. Checks for
|
|
3
|
+
description: "Core droid meta-skill for update awareness and tool discovery. Checks for updates and helps users find the right tools."
|
|
4
4
|
globs:
|
|
5
5
|
- "**/*"
|
|
6
6
|
alwaysApply: false
|
|
7
|
+
allowed-tools: Bash
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Droid
|
|
10
11
|
|
|
11
|
-
Core meta-skill for droid update awareness.
|
|
12
|
+
Core meta-skill for droid update awareness and tool discovery.
|
|
12
13
|
|
|
13
14
|
## Purpose
|
|
14
15
|
|
|
15
|
-
Notify users about droid CLI updates from within Claude Code
|
|
16
|
+
1. **Update awareness** - Notify users about droid CLI updates from within Claude Code
|
|
17
|
+
2. **Tool discovery** - Help users find the right tools for their workflow
|
|
16
18
|
|
|
17
19
|
## Update Checking
|
|
18
20
|
|
|
@@ -115,3 +117,118 @@ Run `droid` when you're ready to update.
|
|
|
115
117
|
- If the npm check fails (network issues), silently skip - don't error
|
|
116
118
|
- The droid eyes `[● ●]` and Star Wars quote are intentional branding - always include them
|
|
117
119
|
- Be helpful but not annoying - one nudge per session is enough
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Tool Catalog
|
|
124
|
+
|
|
125
|
+
When users ask about droid tools ("what tools do I have?", "what's available?", "what can droid do?"), use this catalog.
|
|
126
|
+
|
|
127
|
+
### Checking Installed Tools
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cat ~/.droid/config.yaml
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Look for the `tools:` section under the current platform (e.g., `claude_code:`).
|
|
134
|
+
|
|
135
|
+
### Available Tools
|
|
136
|
+
|
|
137
|
+
To get tool info (version, status, description), read TOOL.yaml from the droid package:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
for f in $(npm root -g)/@orderful/droid/dist/tools/*/TOOL.yaml; do echo "---"; cat "$f"; done
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Tools:**
|
|
144
|
+
|
|
145
|
+
| Tool | Description |
|
|
146
|
+
|------|-------------|
|
|
147
|
+
| **brain** | Collaborative scratchpad for planning and research |
|
|
148
|
+
| **coach** | Learning-mode AI - scaffolds don't implement, questions don't fix |
|
|
149
|
+
| **code-review** | Code review with specialized agents and confidence scoring |
|
|
150
|
+
| **comments** | Inline conversations using @droid/@user markers |
|
|
151
|
+
| **project** | Project context for persistent AI memory across sessions |
|
|
152
|
+
|
|
153
|
+
### Tool Details
|
|
154
|
+
|
|
155
|
+
#### brain
|
|
156
|
+
Collaborative scratchpad for planning and research. Create docs with `/brain plan`, `/brain research`, or `/brain review`. Use @mentions for async discussion. Docs persist across sessions.
|
|
157
|
+
|
|
158
|
+
**Commands:** `/brain`, `/scratchpad`
|
|
159
|
+
**Optional extension:** brain-obsidian (Obsidian vault integration with YAML frontmatter and wikilinks)
|
|
160
|
+
|
|
161
|
+
#### coach
|
|
162
|
+
Learning-mode AI assistance - AI as coach, not crutch. Use `/coach plan` for co-authored planning, `/coach scaffold` for structure with hints, `/coach review` for Socratic questions.
|
|
163
|
+
|
|
164
|
+
**Commands:** `/coach`
|
|
165
|
+
**Requires:** comments tool
|
|
166
|
+
|
|
167
|
+
#### code-review
|
|
168
|
+
Comprehensive code review using specialized agents. Reviews PRs, staged changes, branches, or specific files with confidence scoring.
|
|
169
|
+
|
|
170
|
+
**Commands:** `/code-review`
|
|
171
|
+
**Agents:** edi-standards-reviewer, error-handling-reviewer, test-coverage-analyzer, type-reviewer
|
|
172
|
+
|
|
173
|
+
#### comments
|
|
174
|
+
Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}. Ideal for code review notes and async collaboration.
|
|
175
|
+
|
|
176
|
+
**Commands:** `/comments check`, `/comments cleanup`
|
|
177
|
+
|
|
178
|
+
#### project
|
|
179
|
+
Manage project context files for persistent AI memory across sessions. Load, update, or create project context before working on multi-session features.
|
|
180
|
+
|
|
181
|
+
**Commands:** `/project`, `/project update`, `/project create`
|
|
182
|
+
|
|
183
|
+
### Installing Tools
|
|
184
|
+
|
|
185
|
+
To install a tool:
|
|
186
|
+
```bash
|
|
187
|
+
droid install <tool-name>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Or run `droid` to open the TUI and browse available tools.
|
|
191
|
+
|
|
192
|
+
### Example Responses
|
|
193
|
+
|
|
194
|
+
**User:** "What droid tools do I have installed?"
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
Let me check your installed tools...
|
|
198
|
+
|
|
199
|
+
[● ●] You have these droid tools installed:
|
|
200
|
+
|
|
201
|
+
- **comments** (v0.2.3) - Inline @droid/@user conversations
|
|
202
|
+
- **brain** (v0.2.0) - Planning and research scratchpad
|
|
203
|
+
- **project** (v0.1.2) - Project context management
|
|
204
|
+
|
|
205
|
+
Run `droid` to see all available tools or install new ones.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**User:** "What tools are available?"
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
[● ●] Here are the droid tools you can install:
|
|
212
|
+
|
|
213
|
+
| Tool | What it does |
|
|
214
|
+
|------|--------------|
|
|
215
|
+
| brain | Planning and research scratchpad with `/brain` commands |
|
|
216
|
+
| coach | Learning-mode AI that asks questions instead of giving answers |
|
|
217
|
+
| code-review | PR review with specialized agents |
|
|
218
|
+
| comments | Inline @droid/@user conversations in any file |
|
|
219
|
+
| project | Persistent project context across sessions |
|
|
220
|
+
|
|
221
|
+
Run `droid install <tool>` or just `droid` to browse and install.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**User:** "What's the difference between brain and project?"
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
[● ●] Good question!
|
|
228
|
+
|
|
229
|
+
**brain** - For ephemeral thinking: plans, research, reviews. Use `/brain plan auth-refactor` to start a planning doc, iterate with @mentions, then archive when done.
|
|
230
|
+
|
|
231
|
+
**project** - For persistent context: what the project is, key decisions, current work. Load with `/project myapp` at the start of a session so I have context.
|
|
232
|
+
|
|
233
|
+
They work well together: research in brain docs, capture decisions in project files.
|
|
234
|
+
```
|
package/package.json
CHANGED
package/src/bin/droid.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { installCommand } from '../commands/install.js';
|
|
|
8
8
|
import { uninstallCommand } from '../commands/uninstall.js';
|
|
9
9
|
import { updateCommand } from '../commands/update.js';
|
|
10
10
|
import { tuiCommand } from '../commands/tui.js';
|
|
11
|
-
import { getVersion
|
|
11
|
+
import { getVersion } from '../lib/version.js';
|
|
12
12
|
|
|
13
13
|
const version = getVersion();
|
|
14
14
|
|
|
@@ -58,9 +58,6 @@ program
|
|
|
58
58
|
.description('Launch interactive TUI dashboard')
|
|
59
59
|
.action(tuiCommand);
|
|
60
60
|
|
|
61
|
-
// Check for updates on any command (non-blocking)
|
|
62
|
-
checkForUpdates().catch(() => {});
|
|
63
|
-
|
|
64
61
|
// If no command provided, launch TUI
|
|
65
62
|
if (process.argv.length === 2) {
|
|
66
63
|
tuiCommand();
|
package/src/commands/tui.tsx
CHANGED
|
@@ -911,12 +911,11 @@ function ToolExplorer({ tool, onViewSource, onClose }: ToolExplorerProps) {
|
|
|
911
911
|
});
|
|
912
912
|
}
|
|
913
913
|
|
|
914
|
-
// Add agents
|
|
915
914
|
for (const agent of tool.includes.agents) {
|
|
916
915
|
result.push({
|
|
917
916
|
type: 'agent',
|
|
918
917
|
name: agent,
|
|
919
|
-
path: join(toolDir, tool.name, 'agents', agent
|
|
918
|
+
path: join(toolDir, tool.name, 'agents', `${agent}.md`),
|
|
920
919
|
});
|
|
921
920
|
}
|
|
922
921
|
|
package/src/lib/agents.ts
CHANGED
|
@@ -5,6 +5,7 @@ import YAML from 'yaml';
|
|
|
5
5
|
import { loadConfig } from './config.js';
|
|
6
6
|
import { Platform } from './types.js';
|
|
7
7
|
import { getAgentsPath } from './platforms.js';
|
|
8
|
+
import { loadToolManifest } from './tools.js';
|
|
8
9
|
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
const BUNDLED_TOOLS_DIR = join(__dirname, '../tools');
|
|
@@ -33,23 +34,58 @@ export interface AgentManifest {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
+
* Parse YAML frontmatter from agent file content
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
if (!existsSync(manifestPath)) {
|
|
39
|
+
function parseAgentFrontmatter(content: string): Record<string, unknown> | null {
|
|
40
|
+
const trimmed = content.trimStart();
|
|
41
|
+
if (!trimmed.startsWith('---')) {
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
const endMatch = trimmed.slice(3).indexOf('---');
|
|
45
|
+
if (endMatch === -1) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const frontmatterContent = trimmed.slice(3, 3 + endMatch);
|
|
45
49
|
try {
|
|
46
|
-
|
|
47
|
-
return YAML.parse(content) as AgentManifest;
|
|
50
|
+
return YAML.parse(frontmatterContent);
|
|
48
51
|
} catch {
|
|
49
52
|
return null;
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Load an agent manifest from an agent file (agents/{name}.md)
|
|
58
|
+
* Reads frontmatter from the .md file, version from TOOL.yaml
|
|
59
|
+
*/
|
|
60
|
+
export function loadAgentManifest(agentPath: string): AgentManifest | null {
|
|
61
|
+
if (!existsSync(agentPath)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const content = readFileSync(agentPath, 'utf-8');
|
|
66
|
+
const frontmatter = parseAgentFrontmatter(content);
|
|
67
|
+
|
|
68
|
+
if (!frontmatter || !frontmatter.name) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Get version from TOOL.yaml
|
|
73
|
+
// agentPath is tools/{tool}/agents/{name}.md, toolDir is tools/{tool}
|
|
74
|
+
const toolDir = dirname(dirname(agentPath));
|
|
75
|
+
const toolManifest = loadToolManifest(toolDir);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
name: frontmatter.name as string,
|
|
79
|
+
description: frontmatter.description as string || '',
|
|
80
|
+
version: toolManifest?.version || '0.0.0',
|
|
81
|
+
status: toolManifest?.status as 'alpha' | 'beta' | 'stable' | undefined,
|
|
82
|
+
mode: frontmatter.mode as 'primary' | 'subagent' | 'all' | undefined,
|
|
83
|
+
model: frontmatter.model as string | undefined,
|
|
84
|
+
color: frontmatter.color as string | undefined,
|
|
85
|
+
tools: frontmatter.tools as string[] | undefined,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
53
89
|
/**
|
|
54
90
|
* Get all bundled agents from tools
|
|
55
91
|
*/
|
|
@@ -61,7 +97,7 @@ export function getBundledAgents(): AgentManifest[] {
|
|
|
61
97
|
return agents;
|
|
62
98
|
}
|
|
63
99
|
|
|
64
|
-
// Get agents from tools/*/agents
|
|
100
|
+
// Get agents from tools/*/agents/*.md
|
|
65
101
|
const toolDirs = readdirSync(BUNDLED_TOOLS_DIR, { withFileTypes: true })
|
|
66
102
|
.filter((dirent) => dirent.isDirectory())
|
|
67
103
|
.map((dirent) => dirent.name);
|
|
@@ -70,12 +106,12 @@ export function getBundledAgents(): AgentManifest[] {
|
|
|
70
106
|
const toolAgentsDir = join(BUNDLED_TOOLS_DIR, toolName, 'agents');
|
|
71
107
|
if (!existsSync(toolAgentsDir)) continue;
|
|
72
108
|
|
|
73
|
-
const
|
|
74
|
-
.filter((dirent) => dirent.
|
|
109
|
+
const agentFiles = readdirSync(toolAgentsDir, { withFileTypes: true })
|
|
110
|
+
.filter((dirent) => dirent.isFile() && dirent.name.endsWith('.md'))
|
|
75
111
|
.map((dirent) => dirent.name);
|
|
76
112
|
|
|
77
|
-
for (const
|
|
78
|
-
const manifest = loadAgentManifest(join(toolAgentsDir,
|
|
113
|
+
for (const agentFile of agentFiles) {
|
|
114
|
+
const manifest = loadAgentManifest(join(toolAgentsDir, agentFile));
|
|
79
115
|
if (manifest && !seenNames.has(manifest.name)) {
|
|
80
116
|
agents.push(manifest);
|
|
81
117
|
seenNames.add(manifest.name);
|
|
@@ -166,35 +202,23 @@ function generateOpenCodeAgent(manifest: AgentManifest, agentContent: string): s
|
|
|
166
202
|
}
|
|
167
203
|
|
|
168
204
|
/**
|
|
169
|
-
* Install an agent from a specific path
|
|
205
|
+
* Install an agent from a specific path (agents/{name}.md)
|
|
170
206
|
* Generates the appropriate format based on the configured AI tool
|
|
171
207
|
*/
|
|
172
|
-
export function installAgentFromPath(
|
|
208
|
+
export function installAgentFromPath(agentPath: string, agentName: string): { success: boolean; message: string } {
|
|
173
209
|
const config = loadConfig();
|
|
174
|
-
const manifestPath = join(agentDir, 'AGENT.yaml');
|
|
175
|
-
const contentPath = join(agentDir, 'AGENT.md');
|
|
176
210
|
|
|
177
|
-
|
|
211
|
+
// Load manifest from agent file frontmatter
|
|
212
|
+
const manifest = loadAgentManifest(agentPath);
|
|
213
|
+
if (!manifest) {
|
|
178
214
|
return { success: false, message: `Agent manifest not found: ${agentName}` };
|
|
179
215
|
}
|
|
180
216
|
|
|
181
217
|
try {
|
|
182
|
-
// Load
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
let agentContent = '';
|
|
187
|
-
if (existsSync(contentPath)) {
|
|
188
|
-
const rawContent = readFileSync(contentPath, 'utf-8');
|
|
189
|
-
// Strip frontmatter from AGENT.md if present (we'll use AGENT.yaml for metadata)
|
|
190
|
-
const frontmatterMatch = rawContent.match(/^---\n[\s\S]*?\n---\n?/);
|
|
191
|
-
agentContent = frontmatterMatch ? rawContent.slice(frontmatterMatch[0].length) : rawContent;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// If no AGENT.md content, use persona from AGENT.yaml
|
|
195
|
-
if (!agentContent.trim() && manifest.persona) {
|
|
196
|
-
agentContent = manifest.persona;
|
|
197
|
-
}
|
|
218
|
+
// Load content (strip frontmatter)
|
|
219
|
+
const rawContent = readFileSync(agentPath, 'utf-8');
|
|
220
|
+
const frontmatterMatch = rawContent.match(/^---\n[\s\S]*?\n---\n?/);
|
|
221
|
+
const agentContent = frontmatterMatch ? rawContent.slice(frontmatterMatch[0].length) : rawContent;
|
|
198
222
|
|
|
199
223
|
// Generate format based on platform
|
|
200
224
|
const installedContent = config.platform === Platform.ClaudeCode
|
|
@@ -222,7 +246,7 @@ export function installAgentFromPath(agentDir: string, agentName: string): { suc
|
|
|
222
246
|
}
|
|
223
247
|
|
|
224
248
|
/**
|
|
225
|
-
* Find the path to an agent within the tools directory structure
|
|
249
|
+
* Find the path to an agent file within the tools directory structure
|
|
226
250
|
*/
|
|
227
251
|
export function findAgentPath(agentName: string): string | null {
|
|
228
252
|
if (!existsSync(BUNDLED_TOOLS_DIR)) {
|
|
@@ -234,9 +258,9 @@ export function findAgentPath(agentName: string): string | null {
|
|
|
234
258
|
.map((dirent) => dirent.name);
|
|
235
259
|
|
|
236
260
|
for (const toolName of toolDirs) {
|
|
237
|
-
const
|
|
238
|
-
if (existsSync(
|
|
239
|
-
return
|
|
261
|
+
const agentPath = join(BUNDLED_TOOLS_DIR, toolName, 'agents', `${agentName}.md`);
|
|
262
|
+
if (existsSync(agentPath)) {
|
|
263
|
+
return agentPath;
|
|
240
264
|
}
|
|
241
265
|
}
|
|
242
266
|
|
|
@@ -245,14 +269,13 @@ export function findAgentPath(agentName: string): string | null {
|
|
|
245
269
|
|
|
246
270
|
/**
|
|
247
271
|
* Install an agent from the tools directory
|
|
248
|
-
* Combines AGENT.yaml metadata with AGENT.md content into a single .md file
|
|
249
272
|
*/
|
|
250
273
|
export function installAgent(agentName: string): { success: boolean; message: string } {
|
|
251
|
-
const
|
|
252
|
-
if (!
|
|
274
|
+
const agentPath = findAgentPath(agentName);
|
|
275
|
+
if (!agentPath) {
|
|
253
276
|
return { success: false, message: `Agent '${agentName}' not found` };
|
|
254
277
|
}
|
|
255
|
-
return installAgentFromPath(
|
|
278
|
+
return installAgentFromPath(agentPath, agentName);
|
|
256
279
|
}
|
|
257
280
|
|
|
258
281
|
/**
|
package/src/lib/skills.test.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getPlatformConfigPath,
|
|
12
12
|
getSkillStatusDisplay,
|
|
13
13
|
getBundledSkillsDir,
|
|
14
|
+
loadSkillManifest,
|
|
14
15
|
} from './skills.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -180,58 +181,52 @@ function getAllSkillPaths(toolsDir: string): Array<{ skillName: string; skillDir
|
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
describe('bundled skills validation', () => {
|
|
183
|
-
it('all skills should have SKILL.md
|
|
184
|
+
it('all skills should have SKILL.md', () => {
|
|
184
185
|
const toolsDir = getBundledSkillsDir();
|
|
185
186
|
const skillPaths = getAllSkillPaths(toolsDir);
|
|
186
187
|
|
|
187
188
|
expect(skillPaths.length).toBeGreaterThan(0);
|
|
188
189
|
|
|
189
|
-
for (const {
|
|
190
|
+
for (const { skillDir } of skillPaths) {
|
|
190
191
|
const skillMdPath = join(skillDir, 'SKILL.md');
|
|
191
192
|
expect(existsSync(skillMdPath)).toBe(true);
|
|
192
|
-
|
|
193
|
-
const content = readFileSync(skillMdPath, 'utf-8');
|
|
194
|
-
const frontmatter = parseFrontmatter(content);
|
|
195
|
-
|
|
196
|
-
expect(frontmatter).not.toBeNull();
|
|
197
|
-
expect(frontmatter?.name).toBe(skillName);
|
|
198
|
-
expect(typeof frontmatter?.description).toBe('string');
|
|
199
193
|
}
|
|
200
194
|
});
|
|
201
195
|
|
|
202
|
-
it('all skills should have
|
|
196
|
+
it('all skills should have metadata in TOOL.yaml', () => {
|
|
203
197
|
const toolsDir = getBundledSkillsDir();
|
|
204
198
|
const skillPaths = getAllSkillPaths(toolsDir);
|
|
205
199
|
|
|
206
200
|
for (const { skillName, skillDir } of skillPaths) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
201
|
+
// Get the parent tool directory
|
|
202
|
+
const toolDir = join(skillDir, '..', '..');
|
|
203
|
+
const toolYamlPath = join(toolDir, 'TOOL.yaml');
|
|
204
|
+
expect(existsSync(toolYamlPath)).toBe(true);
|
|
205
|
+
|
|
206
|
+
const toolContent = readFileSync(toolYamlPath, 'utf-8');
|
|
207
|
+
const toolManifest = YAML.parse(toolContent);
|
|
208
|
+
|
|
209
|
+
// Find the skill in includes.skills
|
|
210
|
+
const skillInclude = toolManifest.includes?.skills?.find(
|
|
211
|
+
(s: { name: string }) => s.name === skillName
|
|
212
|
+
);
|
|
213
|
+
expect(skillInclude).toBeDefined();
|
|
214
|
+
expect(typeof toolManifest.description).toBe('string');
|
|
215
|
+
expect(typeof toolManifest.version).toBe('string');
|
|
216
216
|
}
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
it('
|
|
219
|
+
it('loadSkillManifest should return valid manifest from TOOL.yaml', () => {
|
|
220
220
|
const toolsDir = getBundledSkillsDir();
|
|
221
221
|
const skillPaths = getAllSkillPaths(toolsDir);
|
|
222
222
|
|
|
223
|
-
for (const { skillDir } of skillPaths) {
|
|
224
|
-
const
|
|
225
|
-
const yamlPath = join(skillDir, 'SKILL.yaml');
|
|
226
|
-
|
|
227
|
-
const mdContent = readFileSync(mdPath, 'utf-8');
|
|
228
|
-
const yamlContent = readFileSync(yamlPath, 'utf-8');
|
|
229
|
-
|
|
230
|
-
const frontmatter = parseFrontmatter(mdContent);
|
|
231
|
-
const manifest = YAML.parse(yamlContent);
|
|
223
|
+
for (const { skillName, skillDir } of skillPaths) {
|
|
224
|
+
const manifest = loadSkillManifest(skillDir);
|
|
232
225
|
|
|
233
|
-
expect(
|
|
234
|
-
expect(
|
|
226
|
+
expect(manifest).not.toBeNull();
|
|
227
|
+
expect(manifest?.name).toBe(skillName);
|
|
228
|
+
expect(typeof manifest?.description).toBe('string');
|
|
229
|
+
expect(typeof manifest?.version).toBe('string');
|
|
235
230
|
}
|
|
236
231
|
});
|
|
237
232
|
});
|