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.
Files changed (79) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +173 -32
  3. package/bin/cli.js +49 -192
  4. package/dist/cli/commands/doctor.d.ts +25 -0
  5. package/dist/cli/commands/doctor.d.ts.map +1 -0
  6. package/dist/cli/commands/doctor.js +238 -0
  7. package/dist/cli/commands/doctor.js.map +1 -0
  8. package/dist/cli/commands/doctor.test.d.ts +6 -0
  9. package/dist/cli/commands/doctor.test.d.ts.map +1 -0
  10. package/dist/cli/commands/doctor.test.js +137 -0
  11. package/dist/cli/commands/doctor.test.js.map +1 -0
  12. package/dist/cli/commands/index.d.ts +7 -0
  13. package/dist/cli/commands/index.d.ts.map +1 -0
  14. package/dist/cli/commands/index.js +10 -0
  15. package/dist/cli/commands/index.js.map +1 -0
  16. package/dist/cli/commands/quickstart.d.ts +18 -0
  17. package/dist/cli/commands/quickstart.d.ts.map +1 -0
  18. package/dist/cli/commands/quickstart.js +141 -0
  19. package/dist/cli/commands/quickstart.js.map +1 -0
  20. package/dist/core/agents/index.d.ts +6 -0
  21. package/dist/core/agents/index.d.ts.map +1 -0
  22. package/dist/core/agents/index.js +6 -0
  23. package/dist/core/agents/index.js.map +1 -0
  24. package/dist/core/agents/loader.d.ts +49 -0
  25. package/dist/core/agents/loader.d.ts.map +1 -0
  26. package/dist/core/agents/loader.js +217 -0
  27. package/dist/core/agents/loader.js.map +1 -0
  28. package/dist/core/agents/loader.test.d.ts +7 -0
  29. package/dist/core/agents/loader.test.d.ts.map +1 -0
  30. package/dist/core/agents/loader.test.js +144 -0
  31. package/dist/core/agents/loader.test.js.map +1 -0
  32. package/dist/core/agents/types.d.ts +77 -0
  33. package/dist/core/agents/types.d.ts.map +1 -0
  34. package/dist/core/agents/types.js +8 -0
  35. package/dist/core/agents/types.js.map +1 -0
  36. package/dist/core/agents/types.test.d.ts +6 -0
  37. package/dist/core/agents/types.test.d.ts.map +1 -0
  38. package/dist/core/agents/types.test.js +254 -0
  39. package/dist/core/agents/types.test.js.map +1 -0
  40. package/dist/core/skills/index.d.ts +6 -0
  41. package/dist/core/skills/index.d.ts.map +1 -0
  42. package/dist/core/skills/index.js +6 -0
  43. package/dist/core/skills/index.js.map +1 -0
  44. package/dist/core/skills/loader.d.ts +69 -0
  45. package/dist/core/skills/loader.d.ts.map +1 -0
  46. package/dist/core/skills/loader.js +243 -0
  47. package/dist/core/skills/loader.js.map +1 -0
  48. package/dist/core/skills/loader.test.d.ts +7 -0
  49. package/dist/core/skills/loader.test.d.ts.map +1 -0
  50. package/dist/core/skills/loader.test.js +184 -0
  51. package/dist/core/skills/loader.test.js.map +1 -0
  52. package/dist/core/skills/types.d.ts +58 -0
  53. package/dist/core/skills/types.d.ts.map +1 -0
  54. package/dist/core/skills/types.js +8 -0
  55. package/dist/core/skills/types.js.map +1 -0
  56. package/dist/index.d.ts +10 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +14 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/lib/index.d.ts +7 -0
  61. package/dist/lib/index.d.ts.map +1 -0
  62. package/dist/lib/index.js +7 -0
  63. package/dist/lib/index.js.map +1 -0
  64. package/dist/lib/pathValidation.d.ts +69 -0
  65. package/dist/lib/pathValidation.d.ts.map +1 -0
  66. package/dist/lib/pathValidation.js +185 -0
  67. package/dist/lib/pathValidation.js.map +1 -0
  68. package/dist/lib/pathValidation.test.d.ts +9 -0
  69. package/dist/lib/pathValidation.test.d.ts.map +1 -0
  70. package/dist/lib/pathValidation.test.js +195 -0
  71. package/dist/lib/pathValidation.test.js.map +1 -0
  72. package/package.json +15 -3
  73. package/templates/.github/agents/developer.agent.md +9 -0
  74. package/templates/.github/agents/product-manager.agent.md +9 -0
  75. package/templates/.github/agents/researcher.agent.md +9 -0
  76. package/templates/.github/agents/security-reviewer.agent.md +9 -2
  77. package/templates/.github/agents/tester.agent.md +9 -0
  78. package/templates/.github/agents/ux-designer.agent.md +9 -0
  79. 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,7 @@
1
+ /**
2
+ * Agent Loader Tests
3
+ *
4
+ * Tests for parsing .agent.md files into typed AgentDefinition objects.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=loader.test.d.ts.map
@@ -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,8 @@
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
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/agents/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Unit tests for agent schema types and parsing.
3
+ * Run with: node --test dist/core/agents/types.test.js
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.test.d.ts","sourceRoot":"","sources":["../../../src/core/agents/types.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}