beth-copilot 1.0.12 → 1.0.13
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/CHANGELOG.md +40 -0
- package/README.md +173 -32
- package/bin/cli.js +49 -192
- package/dist/cli/commands/doctor.d.ts +25 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +238 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/doctor.test.d.ts +6 -0
- package/dist/cli/commands/doctor.test.d.ts.map +1 -0
- package/dist/cli/commands/doctor.test.js +137 -0
- package/dist/cli/commands/doctor.test.js.map +1 -0
- package/dist/cli/commands/index.d.ts +7 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +10 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/quickstart.d.ts +18 -0
- package/dist/cli/commands/quickstart.d.ts.map +1 -0
- package/dist/cli/commands/quickstart.js +141 -0
- package/dist/cli/commands/quickstart.js.map +1 -0
- package/dist/core/agents/index.d.ts +6 -0
- package/dist/core/agents/index.d.ts.map +1 -0
- package/dist/core/agents/index.js +6 -0
- package/dist/core/agents/index.js.map +1 -0
- package/dist/core/agents/loader.d.ts +49 -0
- package/dist/core/agents/loader.d.ts.map +1 -0
- package/dist/core/agents/loader.js +217 -0
- package/dist/core/agents/loader.js.map +1 -0
- package/dist/core/agents/loader.test.d.ts +7 -0
- package/dist/core/agents/loader.test.d.ts.map +1 -0
- package/dist/core/agents/loader.test.js +144 -0
- package/dist/core/agents/loader.test.js.map +1 -0
- package/dist/core/agents/types.d.ts +77 -0
- package/dist/core/agents/types.d.ts.map +1 -0
- package/dist/core/agents/types.js +8 -0
- package/dist/core/agents/types.js.map +1 -0
- package/dist/core/agents/types.test.d.ts +6 -0
- package/dist/core/agents/types.test.d.ts.map +1 -0
- package/dist/core/agents/types.test.js +254 -0
- package/dist/core/agents/types.test.js.map +1 -0
- package/dist/core/skills/index.d.ts +6 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/skills/index.js +6 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/core/skills/loader.d.ts +69 -0
- package/dist/core/skills/loader.d.ts.map +1 -0
- package/dist/core/skills/loader.js +243 -0
- package/dist/core/skills/loader.js.map +1 -0
- package/dist/core/skills/loader.test.d.ts +7 -0
- package/dist/core/skills/loader.test.d.ts.map +1 -0
- package/dist/core/skills/loader.test.js +184 -0
- package/dist/core/skills/loader.test.js.map +1 -0
- package/dist/core/skills/types.d.ts +58 -0
- package/dist/core/skills/types.d.ts.map +1 -0
- package/dist/core/skills/types.js +8 -0
- package/dist/core/skills/types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/index.d.ts +7 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/pathValidation.d.ts +69 -0
- package/dist/lib/pathValidation.d.ts.map +1 -0
- package/dist/lib/pathValidation.js +185 -0
- package/dist/lib/pathValidation.js.map +1 -0
- package/dist/lib/pathValidation.test.d.ts +9 -0
- package/dist/lib/pathValidation.test.d.ts.map +1 -0
- package/dist/lib/pathValidation.test.js +195 -0
- package/dist/lib/pathValidation.test.js.map +1 -0
- package/package.json +15 -3
- package/templates/.github/agents/developer.agent.md +9 -0
- package/templates/.github/agents/product-manager.agent.md +9 -0
- package/templates/.github/agents/researcher.agent.md +9 -0
- package/templates/.github/agents/security-reviewer.agent.md +9 -2
- package/templates/.github/agents/tester.agent.md +9 -0
- package/templates/.github/agents/ux-designer.agent.md +9 -0
- package/templates/.github/copilot-instructions.md +3 -3
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Loader
|
|
3
|
+
*
|
|
4
|
+
* Parses .agent.md files from the agents directory into typed AgentDefinition objects.
|
|
5
|
+
* Uses gray-matter to extract YAML frontmatter and markdown body.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentDefinition, AgentLoadResult, AgentLoadError } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Default agents directory relative to workspace root.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_AGENTS_DIR = ".github/agents";
|
|
12
|
+
/**
|
|
13
|
+
* File extension for agent definition files.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AGENT_FILE_EXTENSION = ".agent.md";
|
|
16
|
+
/**
|
|
17
|
+
* Load all agents from a directory.
|
|
18
|
+
*
|
|
19
|
+
* @param agentsDir - Path to agents directory (default: .github/agents)
|
|
20
|
+
* @returns Object containing loaded agents and any errors
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadAgents(agentsDir?: string): AgentLoadResult;
|
|
23
|
+
/**
|
|
24
|
+
* Load a single agent from a file.
|
|
25
|
+
*
|
|
26
|
+
* @param filePath - Path to the .agent.md file
|
|
27
|
+
* @returns Either an agent definition or an error
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadAgent(filePath: string): {
|
|
30
|
+
agent: AgentDefinition;
|
|
31
|
+
} | {
|
|
32
|
+
error: AgentLoadError;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Get an agent by ID from a load result.
|
|
36
|
+
*
|
|
37
|
+
* @param result - The result from loadAgents()
|
|
38
|
+
* @param id - Agent ID to find (e.g., 'developer', 'beth')
|
|
39
|
+
* @returns The agent definition or undefined if not found
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAgentById(result: AgentLoadResult, id: string): AgentDefinition | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Get agents that can be used as subagents (infer: true).
|
|
44
|
+
*
|
|
45
|
+
* @param result - The result from loadAgents()
|
|
46
|
+
* @returns Array of agents with infer: true
|
|
47
|
+
*/
|
|
48
|
+
export declare function getInferableAgents(result: AgentLoadResult): AgentDefinition[];
|
|
49
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/agents/loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,eAAe,EAGf,eAAe,EACf,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,GAAE,MAA2B,GAAG,eAAe,CAoClF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,GACf;IAAE,KAAK,EAAE,eAAe,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,CAuCxD;AA6HD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,MAAM,GACT,eAAe,GAAG,SAAS,CAE7B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,EAAE,CAE7E"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Loader
|
|
3
|
+
*
|
|
4
|
+
* Parses .agent.md files from the agents directory into typed AgentDefinition objects.
|
|
5
|
+
* Uses gray-matter to extract YAML frontmatter and markdown body.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
8
|
+
import { join, basename } from 'node:path';
|
|
9
|
+
import matter from 'gray-matter';
|
|
10
|
+
/**
|
|
11
|
+
* Default agents directory relative to workspace root.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_AGENTS_DIR = '.github/agents';
|
|
14
|
+
/**
|
|
15
|
+
* File extension for agent definition files.
|
|
16
|
+
*/
|
|
17
|
+
export const AGENT_FILE_EXTENSION = '.agent.md';
|
|
18
|
+
/**
|
|
19
|
+
* Load all agents from a directory.
|
|
20
|
+
*
|
|
21
|
+
* @param agentsDir - Path to agents directory (default: .github/agents)
|
|
22
|
+
* @returns Object containing loaded agents and any errors
|
|
23
|
+
*/
|
|
24
|
+
export function loadAgents(agentsDir = DEFAULT_AGENTS_DIR) {
|
|
25
|
+
const agents = [];
|
|
26
|
+
const errors = [];
|
|
27
|
+
if (!existsSync(agentsDir)) {
|
|
28
|
+
errors.push({
|
|
29
|
+
filePath: agentsDir,
|
|
30
|
+
message: `Agents directory not found: ${agentsDir}`,
|
|
31
|
+
});
|
|
32
|
+
return { agents, errors };
|
|
33
|
+
}
|
|
34
|
+
const files = readdirSync(agentsDir).filter((f) => f.endsWith(AGENT_FILE_EXTENSION));
|
|
35
|
+
if (files.length === 0) {
|
|
36
|
+
errors.push({
|
|
37
|
+
filePath: agentsDir,
|
|
38
|
+
message: `No ${AGENT_FILE_EXTENSION} files found in ${agentsDir}`,
|
|
39
|
+
});
|
|
40
|
+
return { agents, errors };
|
|
41
|
+
}
|
|
42
|
+
for (const file of files) {
|
|
43
|
+
const filePath = join(agentsDir, file);
|
|
44
|
+
const result = loadAgent(filePath);
|
|
45
|
+
if ('error' in result) {
|
|
46
|
+
errors.push(result.error);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
agents.push(result.agent);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { agents, errors };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Load a single agent from a file.
|
|
56
|
+
*
|
|
57
|
+
* @param filePath - Path to the .agent.md file
|
|
58
|
+
* @returns Either an agent definition or an error
|
|
59
|
+
*/
|
|
60
|
+
export function loadAgent(filePath) {
|
|
61
|
+
try {
|
|
62
|
+
let content = readFileSync(filePath, 'utf-8');
|
|
63
|
+
// Handle GitHub Copilot agent file format: ```chatagent\n---\n...\n---\n...\n```
|
|
64
|
+
// Strip the code fence wrapper if present
|
|
65
|
+
content = stripCodeFence(content);
|
|
66
|
+
const { data, content: body } = matter(content);
|
|
67
|
+
// Validate required fields
|
|
68
|
+
const validation = validateFrontmatter(data, filePath);
|
|
69
|
+
if (validation.error) {
|
|
70
|
+
return { error: validation.error };
|
|
71
|
+
}
|
|
72
|
+
// Extract agent ID from filename (e.g., 'developer.agent.md' -> 'developer')
|
|
73
|
+
const id = basename(filePath, AGENT_FILE_EXTENSION);
|
|
74
|
+
// Normalize frontmatter
|
|
75
|
+
const frontmatter = normalizeFrontmatter(data);
|
|
76
|
+
return {
|
|
77
|
+
agent: {
|
|
78
|
+
id,
|
|
79
|
+
frontmatter,
|
|
80
|
+
body: body.trim(),
|
|
81
|
+
sourcePath: filePath,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return {
|
|
87
|
+
error: {
|
|
88
|
+
filePath,
|
|
89
|
+
message: `Failed to parse agent file: ${err instanceof Error ? err.message : String(err)}`,
|
|
90
|
+
cause: err instanceof Error ? err : undefined,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Strip GitHub Copilot code fence wrapper from agent/skill files.
|
|
97
|
+
*
|
|
98
|
+
* Files may be wrapped in ```chatagent or ```skill code fences.
|
|
99
|
+
* This extracts the content inside the fence.
|
|
100
|
+
*/
|
|
101
|
+
function stripCodeFence(content) {
|
|
102
|
+
// Match opening fence: ```chatagent, ```skill, ````chatagent, etc.
|
|
103
|
+
const fenceMatch = content.match(/^(`{3,})(chatagent|skill)\s*[\r\n]/);
|
|
104
|
+
if (!fenceMatch) {
|
|
105
|
+
return content;
|
|
106
|
+
}
|
|
107
|
+
const fenceLength = fenceMatch[1].length;
|
|
108
|
+
const closingFence = '`'.repeat(fenceLength);
|
|
109
|
+
// Find the closing fence
|
|
110
|
+
const closingIndex = content.lastIndexOf(closingFence);
|
|
111
|
+
if (closingIndex === -1 || closingIndex === 0) {
|
|
112
|
+
return content;
|
|
113
|
+
}
|
|
114
|
+
// Extract content between fences
|
|
115
|
+
const startIndex = fenceMatch[0].length;
|
|
116
|
+
return content.slice(startIndex, closingIndex).trim();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Validate that frontmatter has required fields.
|
|
120
|
+
*/
|
|
121
|
+
function validateFrontmatter(data, filePath) {
|
|
122
|
+
if (!data.name || typeof data.name !== 'string') {
|
|
123
|
+
return {
|
|
124
|
+
error: {
|
|
125
|
+
filePath,
|
|
126
|
+
message: `Missing or invalid 'name' in frontmatter`,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Validate handoffs if present
|
|
131
|
+
if (data.handoffs && !Array.isArray(data.handoffs)) {
|
|
132
|
+
return {
|
|
133
|
+
error: {
|
|
134
|
+
filePath,
|
|
135
|
+
message: `'handoffs' must be an array`,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(data.handoffs)) {
|
|
140
|
+
for (let i = 0; i < data.handoffs.length; i++) {
|
|
141
|
+
const handoff = data.handoffs[i];
|
|
142
|
+
if (!handoff.label || !handoff.agent || !handoff.prompt) {
|
|
143
|
+
return {
|
|
144
|
+
error: {
|
|
145
|
+
filePath,
|
|
146
|
+
message: `Handoff at index ${i} missing required fields (label, agent, prompt)`,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Validate tools if present
|
|
153
|
+
if (data.tools && !Array.isArray(data.tools)) {
|
|
154
|
+
return {
|
|
155
|
+
error: {
|
|
156
|
+
filePath,
|
|
157
|
+
message: `'tools' must be an array`,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Normalize frontmatter data to typed AgentFrontmatter.
|
|
165
|
+
*/
|
|
166
|
+
function normalizeFrontmatter(data) {
|
|
167
|
+
const frontmatter = {
|
|
168
|
+
name: data.name,
|
|
169
|
+
};
|
|
170
|
+
if (data.description) {
|
|
171
|
+
frontmatter.description = String(data.description);
|
|
172
|
+
}
|
|
173
|
+
if (data.model) {
|
|
174
|
+
frontmatter.model = String(data.model);
|
|
175
|
+
}
|
|
176
|
+
if (Array.isArray(data.tools)) {
|
|
177
|
+
frontmatter.tools = data.tools.map(String);
|
|
178
|
+
}
|
|
179
|
+
if (typeof data.infer === 'boolean') {
|
|
180
|
+
frontmatter.infer = data.infer;
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(data.handoffs)) {
|
|
183
|
+
frontmatter.handoffs = data.handoffs.map(normalizeHandoff);
|
|
184
|
+
}
|
|
185
|
+
return frontmatter;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Normalize a single handoff definition.
|
|
189
|
+
*/
|
|
190
|
+
function normalizeHandoff(data) {
|
|
191
|
+
return {
|
|
192
|
+
label: String(data.label),
|
|
193
|
+
agent: String(data.agent),
|
|
194
|
+
prompt: String(data.prompt),
|
|
195
|
+
send: typeof data.send === 'boolean' ? data.send : undefined,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get an agent by ID from a load result.
|
|
200
|
+
*
|
|
201
|
+
* @param result - The result from loadAgents()
|
|
202
|
+
* @param id - Agent ID to find (e.g., 'developer', 'beth')
|
|
203
|
+
* @returns The agent definition or undefined if not found
|
|
204
|
+
*/
|
|
205
|
+
export function getAgentById(result, id) {
|
|
206
|
+
return result.agents.find((agent) => agent.id.toLowerCase() === id.toLowerCase());
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get agents that can be used as subagents (infer: true).
|
|
210
|
+
*
|
|
211
|
+
* @param result - The result from loadAgents()
|
|
212
|
+
* @returns Array of agents with infer: true
|
|
213
|
+
*/
|
|
214
|
+
export function getInferableAgents(result) {
|
|
215
|
+
return result.agents.filter((agent) => agent.frontmatter.infer === true);
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/agents/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.d.ts","sourceRoot":"","sources":["../../../src/core/agents/loader.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Loader Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for parsing .agent.md files into typed AgentDefinition objects.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { loadAgents, loadAgent, getAgentById, getInferableAgents, DEFAULT_AGENTS_DIR, AGENT_FILE_EXTENSION, } from './loader.js';
|
|
10
|
+
// Test against templates directory
|
|
11
|
+
const TEMPLATES_AGENTS_DIR = join(process.cwd(), 'templates', '.github', 'agents');
|
|
12
|
+
describe('Agent Loader', () => {
|
|
13
|
+
describe('loadAgents', () => {
|
|
14
|
+
it('should load all agents from templates directory', () => {
|
|
15
|
+
const result = loadAgents(TEMPLATES_AGENTS_DIR);
|
|
16
|
+
assert.strictEqual(result.errors.length, 0, `Unexpected errors: ${JSON.stringify(result.errors)}`);
|
|
17
|
+
assert.ok(result.agents.length >= 6, `Expected at least 6 agents, got ${result.agents.length}`);
|
|
18
|
+
// Check expected agents exist
|
|
19
|
+
const agentIds = result.agents.map((a) => a.id);
|
|
20
|
+
assert.ok(agentIds.includes('beth'), 'Should include beth agent');
|
|
21
|
+
assert.ok(agentIds.includes('developer'), 'Should include developer agent');
|
|
22
|
+
assert.ok(agentIds.includes('product-manager'), 'Should include product-manager agent');
|
|
23
|
+
});
|
|
24
|
+
it('should return error for non-existent directory', () => {
|
|
25
|
+
const result = loadAgents('/non/existent/path');
|
|
26
|
+
assert.strictEqual(result.agents.length, 0);
|
|
27
|
+
assert.strictEqual(result.errors.length, 1);
|
|
28
|
+
assert.ok(result.errors[0].message.includes('not found'));
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('loadAgent', () => {
|
|
32
|
+
it('should parse Beth agent correctly', () => {
|
|
33
|
+
const filePath = join(TEMPLATES_AGENTS_DIR, 'beth.agent.md');
|
|
34
|
+
const result = loadAgent(filePath);
|
|
35
|
+
assert.ok(!('error' in result), `Unexpected error: ${JSON.stringify(result)}`);
|
|
36
|
+
const { agent } = result;
|
|
37
|
+
assert.strictEqual(agent.id, 'beth');
|
|
38
|
+
assert.strictEqual(agent.frontmatter.name, 'Beth');
|
|
39
|
+
assert.ok(agent.frontmatter.description?.includes('orchestrator'));
|
|
40
|
+
assert.strictEqual(agent.frontmatter.model, 'Claude Opus 4.5');
|
|
41
|
+
assert.strictEqual(agent.frontmatter.infer, true);
|
|
42
|
+
assert.ok(Array.isArray(agent.frontmatter.tools));
|
|
43
|
+
assert.ok(Array.isArray(agent.frontmatter.handoffs));
|
|
44
|
+
assert.ok(agent.body.length > 100, 'Should have substantial body content');
|
|
45
|
+
});
|
|
46
|
+
it('should parse handoffs correctly', () => {
|
|
47
|
+
const filePath = join(TEMPLATES_AGENTS_DIR, 'beth.agent.md');
|
|
48
|
+
const result = loadAgent(filePath);
|
|
49
|
+
assert.ok(!('error' in result));
|
|
50
|
+
const { agent } = result;
|
|
51
|
+
const handoffs = agent.frontmatter.handoffs;
|
|
52
|
+
assert.ok(Array.isArray(handoffs));
|
|
53
|
+
assert.ok(handoffs.length >= 5, 'Beth should have at least 5 handoffs');
|
|
54
|
+
// Check structure of first handoff
|
|
55
|
+
const devHandoff = handoffs.find((h) => h.agent === 'developer');
|
|
56
|
+
assert.ok(devHandoff, 'Should have developer handoff');
|
|
57
|
+
assert.ok(devHandoff.label, 'Handoff should have label');
|
|
58
|
+
assert.ok(devHandoff.prompt, 'Handoff should have prompt');
|
|
59
|
+
});
|
|
60
|
+
it('should parse developer agent with tools', () => {
|
|
61
|
+
const filePath = join(TEMPLATES_AGENTS_DIR, 'developer.agent.md');
|
|
62
|
+
const result = loadAgent(filePath);
|
|
63
|
+
assert.ok(!('error' in result));
|
|
64
|
+
const { agent } = result;
|
|
65
|
+
assert.strictEqual(agent.id, 'developer');
|
|
66
|
+
assert.ok(Array.isArray(agent.frontmatter.tools));
|
|
67
|
+
assert.ok(agent.frontmatter.tools.length > 0, 'Developer should have tools');
|
|
68
|
+
});
|
|
69
|
+
it('should extract sourcePath correctly', () => {
|
|
70
|
+
const filePath = join(TEMPLATES_AGENTS_DIR, 'developer.agent.md');
|
|
71
|
+
const result = loadAgent(filePath);
|
|
72
|
+
assert.ok(!('error' in result));
|
|
73
|
+
const { agent } = result;
|
|
74
|
+
assert.strictEqual(agent.sourcePath, filePath);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('getAgentById', () => {
|
|
78
|
+
it('should find agent by ID (case-insensitive)', () => {
|
|
79
|
+
const result = loadAgents(TEMPLATES_AGENTS_DIR);
|
|
80
|
+
const beth = getAgentById(result, 'Beth');
|
|
81
|
+
assert.ok(beth, 'Should find Beth agent');
|
|
82
|
+
assert.strictEqual(beth?.frontmatter.name, 'Beth');
|
|
83
|
+
const bethLower = getAgentById(result, 'beth');
|
|
84
|
+
assert.strictEqual(beth?.id, bethLower?.id, 'Case should not matter');
|
|
85
|
+
});
|
|
86
|
+
it('should return undefined for non-existent agent', () => {
|
|
87
|
+
const result = loadAgents(TEMPLATES_AGENTS_DIR);
|
|
88
|
+
const notFound = getAgentById(result, 'non-existent-agent');
|
|
89
|
+
assert.strictEqual(notFound, undefined);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('getInferableAgents', () => {
|
|
93
|
+
it('should return only agents with infer: true', () => {
|
|
94
|
+
const result = loadAgents(TEMPLATES_AGENTS_DIR);
|
|
95
|
+
const inferable = getInferableAgents(result);
|
|
96
|
+
assert.ok(inferable.length > 0, 'Should have at least one inferable agent');
|
|
97
|
+
for (const agent of inferable) {
|
|
98
|
+
assert.strictEqual(agent.frontmatter.infer, true, `${agent.id} should have infer: true`);
|
|
99
|
+
}
|
|
100
|
+
// Beth should be inferable
|
|
101
|
+
const bethInferable = inferable.find((a) => a.id === 'beth');
|
|
102
|
+
assert.ok(bethInferable, 'Beth should be inferable');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('validation', () => {
|
|
106
|
+
it('should reject files without name in frontmatter', () => {
|
|
107
|
+
// This tests the validation logic - we can't easily test with actual files
|
|
108
|
+
// without creating temp files, so we verify the loader handles the case
|
|
109
|
+
const result = loadAgent('/non/existent/file.agent.md');
|
|
110
|
+
assert.ok('error' in result);
|
|
111
|
+
assert.ok(result.error.message.includes('Failed to parse'));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('constants', () => {
|
|
115
|
+
it('should export correct constants', () => {
|
|
116
|
+
assert.strictEqual(DEFAULT_AGENTS_DIR, '.github/agents');
|
|
117
|
+
assert.strictEqual(AGENT_FILE_EXTENSION, '.agent.md');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe('Agent frontmatter structure compatibility', () => {
|
|
122
|
+
it('all loaded agents should have valid frontmatter structure', () => {
|
|
123
|
+
const result = loadAgents(TEMPLATES_AGENTS_DIR);
|
|
124
|
+
for (const agent of result.agents) {
|
|
125
|
+
// Required fields
|
|
126
|
+
assert.ok(agent.frontmatter.name, `${agent.id} should have name`);
|
|
127
|
+
// Optional fields should be correct type if present
|
|
128
|
+
if (agent.frontmatter.tools !== undefined) {
|
|
129
|
+
assert.ok(Array.isArray(agent.frontmatter.tools), `${agent.id} tools should be array`);
|
|
130
|
+
}
|
|
131
|
+
if (agent.frontmatter.handoffs !== undefined) {
|
|
132
|
+
assert.ok(Array.isArray(agent.frontmatter.handoffs), `${agent.id} handoffs should be array`);
|
|
133
|
+
for (const handoff of agent.frontmatter.handoffs) {
|
|
134
|
+
assert.ok(handoff.label, `${agent.id} handoff should have label`);
|
|
135
|
+
assert.ok(handoff.agent, `${agent.id} handoff should have agent`);
|
|
136
|
+
assert.ok(handoff.prompt, `${agent.id} handoff should have prompt`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Body should be non-empty
|
|
140
|
+
assert.ok(agent.body.length > 0, `${agent.id} should have body content`);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../../src/core/agents/loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Schema Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for Beth agent configurations parsed from .agent.md files.
|
|
5
|
+
* These types mirror the YAML frontmatter structure used by GitHub Copilot custom agents.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Tools available to agents.
|
|
9
|
+
* Maps to GitHub Copilot's tool capabilities.
|
|
10
|
+
*/
|
|
11
|
+
export type AgentTool = 'codebase' | 'readFile' | 'editFiles' | 'createFile' | 'listDirectory' | 'fileSearch' | 'textSearch' | 'runInTerminal' | 'getTerminalOutput' | 'problems' | 'usages' | 'runSubagent' | string;
|
|
12
|
+
/**
|
|
13
|
+
* Handoff definition for agent-to-agent transfers.
|
|
14
|
+
*/
|
|
15
|
+
export interface AgentHandoff {
|
|
16
|
+
/** UI label for the handoff action */
|
|
17
|
+
label: string;
|
|
18
|
+
/** Target agent name */
|
|
19
|
+
agent: string;
|
|
20
|
+
/** Default prompt to send with the handoff */
|
|
21
|
+
prompt: string;
|
|
22
|
+
/** Whether to automatically send or just prepare the handoff */
|
|
23
|
+
send?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Agent frontmatter parsed from YAML.
|
|
27
|
+
* This is the metadata block at the top of .agent.md files.
|
|
28
|
+
*/
|
|
29
|
+
export interface AgentFrontmatter {
|
|
30
|
+
/** Display name of the agent */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Brief description of the agent's purpose */
|
|
33
|
+
description?: string;
|
|
34
|
+
/** LLM model to use (e.g., 'Claude Opus 4.5') */
|
|
35
|
+
model?: string;
|
|
36
|
+
/** List of tools this agent can use */
|
|
37
|
+
tools?: AgentTool[];
|
|
38
|
+
/** Other agents this agent can hand off to */
|
|
39
|
+
handoffs?: AgentHandoff[];
|
|
40
|
+
/** Whether this agent can be invoked as a subagent */
|
|
41
|
+
infer?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Fully parsed agent definition.
|
|
45
|
+
* Combines frontmatter metadata with the markdown body (system prompt).
|
|
46
|
+
*/
|
|
47
|
+
export interface AgentDefinition {
|
|
48
|
+
/** Unique identifier derived from filename (e.g., 'developer' from 'developer.agent.md') */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Parsed YAML frontmatter */
|
|
51
|
+
frontmatter: AgentFrontmatter;
|
|
52
|
+
/** Raw markdown body (becomes the system prompt) */
|
|
53
|
+
body: string;
|
|
54
|
+
/** Source file path for debugging */
|
|
55
|
+
sourcePath: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Result of loading agents from a directory.
|
|
59
|
+
*/
|
|
60
|
+
export interface AgentLoadResult {
|
|
61
|
+
/** Successfully loaded agents */
|
|
62
|
+
agents: AgentDefinition[];
|
|
63
|
+
/** Errors encountered during loading */
|
|
64
|
+
errors: AgentLoadError[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error encountered while loading an agent file.
|
|
68
|
+
*/
|
|
69
|
+
export interface AgentLoadError {
|
|
70
|
+
/** Path to the problematic file */
|
|
71
|
+
filePath: string;
|
|
72
|
+
/** Human-readable error message */
|
|
73
|
+
message: string;
|
|
74
|
+
/** Original error for debugging */
|
|
75
|
+
cause?: Error;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/agents/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,UAAU,GACV,UAAU,GACV,WAAW,GACX,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,UAAU,GACV,QAAQ,GACR,aAAa,GACb,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IAEd,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IAEd,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IAEf,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IAEb,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,uCAAuC;IACvC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IAEpB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAE1B,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,4FAA4F;IAC5F,EAAE,EAAE,MAAM,CAAC;IAEX,8BAA8B;IAC9B,WAAW,EAAE,gBAAgB,CAAC;IAE9B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,MAAM,EAAE,eAAe,EAAE,CAAC;IAE1B,wCAAwC;IACxC,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IAEjB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAEhB,mCAAmC;IACnC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/agents/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../../src/core/agents/types.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|