beth-copilot 1.0.11 → 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 +170 -0
- package/README.md +181 -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 +17 -4
- package/sbom.json +7 -7
- 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,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for doctor command.
|
|
3
|
+
* Run with: node --test dist/cli/commands/doctor.test.js
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import { existsSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { tmpdir } from 'os';
|
|
11
|
+
// Test utilities - we can't import the private functions from doctor.ts
|
|
12
|
+
// but we can test the overall behavior
|
|
13
|
+
describe('doctor command integration', () => {
|
|
14
|
+
let testDir;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
// Create a temp directory for testing
|
|
17
|
+
testDir = join(tmpdir(), `beth-test-${Date.now()}`);
|
|
18
|
+
mkdirSync(testDir, { recursive: true });
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
// Clean up temp directory
|
|
22
|
+
if (existsSync(testDir)) {
|
|
23
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
describe('Node.js version check', () => {
|
|
27
|
+
it('should pass with current Node.js version', () => {
|
|
28
|
+
const version = process.version;
|
|
29
|
+
const major = parseInt(version.slice(1).split('.')[0], 10);
|
|
30
|
+
assert.ok(major >= 18, `Node.js ${version} should be >= 18`);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('agents directory validation', () => {
|
|
34
|
+
it('should detect missing .github/agents directory', () => {
|
|
35
|
+
const agentsDir = join(testDir, '.github', 'agents');
|
|
36
|
+
assert.strictEqual(existsSync(agentsDir), false);
|
|
37
|
+
});
|
|
38
|
+
it('should detect existing .github/agents directory', () => {
|
|
39
|
+
const agentsDir = join(testDir, '.github', 'agents');
|
|
40
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
41
|
+
assert.strictEqual(existsSync(agentsDir), true);
|
|
42
|
+
});
|
|
43
|
+
it('should detect valid agent files', () => {
|
|
44
|
+
const agentsDir = join(testDir, '.github', 'agents');
|
|
45
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
46
|
+
const agentContent = `---
|
|
47
|
+
name: test-agent
|
|
48
|
+
description: A test agent
|
|
49
|
+
model: Claude Opus 4.5
|
|
50
|
+
tools:
|
|
51
|
+
- readFile
|
|
52
|
+
- editFiles
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# Test Agent
|
|
56
|
+
|
|
57
|
+
This is a test agent.
|
|
58
|
+
`;
|
|
59
|
+
writeFileSync(join(agentsDir, 'test.agent.md'), agentContent);
|
|
60
|
+
const files = existsSync(agentsDir);
|
|
61
|
+
assert.strictEqual(files, true);
|
|
62
|
+
});
|
|
63
|
+
it('should detect agent files missing name in frontmatter', () => {
|
|
64
|
+
const agentsDir = join(testDir, '.github', 'agents');
|
|
65
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
66
|
+
// Agent file without name field
|
|
67
|
+
const agentContent = `---
|
|
68
|
+
description: A test agent without name
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
# Test Agent
|
|
72
|
+
`;
|
|
73
|
+
writeFileSync(join(agentsDir, 'invalid.agent.md'), agentContent);
|
|
74
|
+
// We'd need to import gray-matter to actually parse this
|
|
75
|
+
// For now, just verify file was created
|
|
76
|
+
assert.strictEqual(existsSync(join(agentsDir, 'invalid.agent.md')), true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('skills directory validation', () => {
|
|
80
|
+
it('should detect missing .github/skills directory', () => {
|
|
81
|
+
const skillsDir = join(testDir, '.github', 'skills');
|
|
82
|
+
assert.strictEqual(existsSync(skillsDir), false);
|
|
83
|
+
});
|
|
84
|
+
it('should detect skill directories with SKILL.md', () => {
|
|
85
|
+
const skillDir = join(testDir, '.github', 'skills', 'test-skill');
|
|
86
|
+
mkdirSync(skillDir, { recursive: true });
|
|
87
|
+
writeFileSync(join(skillDir, 'SKILL.md'), '# Test Skill\n\nThis is a test skill.');
|
|
88
|
+
assert.strictEqual(existsSync(join(skillDir, 'SKILL.md')), true);
|
|
89
|
+
});
|
|
90
|
+
it('should detect skill directories missing SKILL.md', () => {
|
|
91
|
+
const skillDir = join(testDir, '.github', 'skills', 'incomplete-skill');
|
|
92
|
+
mkdirSync(skillDir, { recursive: true });
|
|
93
|
+
// Create directory but no SKILL.md
|
|
94
|
+
assert.strictEqual(existsSync(skillDir), true);
|
|
95
|
+
assert.strictEqual(existsSync(join(skillDir, 'SKILL.md')), false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('beads initialization check', () => {
|
|
99
|
+
it('should detect missing .beads directory', () => {
|
|
100
|
+
const beadsDir = join(testDir, '.beads');
|
|
101
|
+
assert.strictEqual(existsSync(beadsDir), false);
|
|
102
|
+
});
|
|
103
|
+
it('should detect existing .beads directory', () => {
|
|
104
|
+
const beadsDir = join(testDir, '.beads');
|
|
105
|
+
mkdirSync(beadsDir, { recursive: true });
|
|
106
|
+
assert.strictEqual(existsSync(beadsDir), true);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('CLI availability checks', () => {
|
|
111
|
+
it('should detect beads CLI if installed', () => {
|
|
112
|
+
try {
|
|
113
|
+
const output = execSync('bd --version', {
|
|
114
|
+
encoding: 'utf-8',
|
|
115
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
116
|
+
});
|
|
117
|
+
assert.ok(output.includes('version'), 'bd --version should return version info');
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// bd not installed - this is not a failure, just skip
|
|
121
|
+
assert.ok(true, 'bd CLI not installed, skipping');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
it('should handle missing CLI gracefully', () => {
|
|
125
|
+
try {
|
|
126
|
+
execSync('nonexistent-cli-tool-12345 --version', {
|
|
127
|
+
encoding: 'utf-8',
|
|
128
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
129
|
+
});
|
|
130
|
+
assert.fail('Should have thrown for non-existent CLI');
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
assert.ok(true, 'Correctly threw for missing CLI');
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=doctor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.test.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Command implementations for the Beth CLI.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
// Commands will be exported here as they're implemented
|
|
8
|
+
// export { doctor } from './doctor.js';
|
|
9
|
+
// export { quickstart } from './quickstart.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;AAEH,wDAAwD;AACxD,wCAAwC;AACxC,gDAAgD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quickstart Command
|
|
3
|
+
*
|
|
4
|
+
* Streamlined setup for Beth:
|
|
5
|
+
* - Checks if Beth is already initialized
|
|
6
|
+
* - Runs doctor to validate setup
|
|
7
|
+
* - Initializes beads if needed
|
|
8
|
+
* - Prints "what's next" guidance
|
|
9
|
+
*/
|
|
10
|
+
interface QuickstartOptions {
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Main quickstart command
|
|
15
|
+
*/
|
|
16
|
+
export declare function quickstart(options?: QuickstartOptions): Promise<void>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=quickstart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quickstart.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/quickstart.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiED;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE/E"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quickstart Command
|
|
3
|
+
*
|
|
4
|
+
* Streamlined setup for Beth:
|
|
5
|
+
* - Checks if Beth is already initialized
|
|
6
|
+
* - Runs doctor to validate setup
|
|
7
|
+
* - Initializes beads if needed
|
|
8
|
+
* - Prints "what's next" guidance
|
|
9
|
+
*/
|
|
10
|
+
import { execSync, spawnSync } from 'child_process';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { doctor } from './doctor.js';
|
|
14
|
+
// Colors for terminal output
|
|
15
|
+
const COLORS = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
bright: '\x1b[1m',
|
|
18
|
+
dim: '\x1b[2m',
|
|
19
|
+
red: '\x1b[31m',
|
|
20
|
+
green: '\x1b[32m',
|
|
21
|
+
yellow: '\x1b[33m',
|
|
22
|
+
cyan: '\x1b[36m',
|
|
23
|
+
};
|
|
24
|
+
function log(message, color = '') {
|
|
25
|
+
console.log(`${color}${message}${COLORS.reset}`);
|
|
26
|
+
}
|
|
27
|
+
function logSuccess(message) {
|
|
28
|
+
log(`✓ ${message}`, COLORS.green);
|
|
29
|
+
}
|
|
30
|
+
function logWarning(message) {
|
|
31
|
+
log(`⚠ ${message}`, COLORS.yellow);
|
|
32
|
+
}
|
|
33
|
+
function logError(message) {
|
|
34
|
+
log(`✗ ${message}`, COLORS.red);
|
|
35
|
+
}
|
|
36
|
+
function logInfo(message) {
|
|
37
|
+
log(` ${message}`, COLORS.cyan);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Check if Beth is initialized in the project
|
|
41
|
+
*/
|
|
42
|
+
function isBethInitialized(cwd) {
|
|
43
|
+
const agentsDir = join(cwd, '.github', 'agents');
|
|
44
|
+
return existsSync(agentsDir);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if beads is initialized in the project
|
|
48
|
+
*/
|
|
49
|
+
function isBeadsInitialized(cwd) {
|
|
50
|
+
const beadsDir = join(cwd, '.beads');
|
|
51
|
+
return existsSync(beadsDir);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if beads CLI is available
|
|
55
|
+
*/
|
|
56
|
+
function isBeadsAvailable() {
|
|
57
|
+
try {
|
|
58
|
+
execSync('bd --version', { stdio: 'ignore' });
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Initialize beads in the project
|
|
67
|
+
*/
|
|
68
|
+
function initializeBeads(cwd) {
|
|
69
|
+
log('\nInitializing beads...', COLORS.cyan);
|
|
70
|
+
const result = spawnSync('bd', ['init'], {
|
|
71
|
+
cwd,
|
|
72
|
+
stdio: 'inherit',
|
|
73
|
+
shell: true,
|
|
74
|
+
});
|
|
75
|
+
return result.status === 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Main quickstart command
|
|
79
|
+
*/
|
|
80
|
+
export async function quickstart(options = {}) {
|
|
81
|
+
const { verbose = false } = options;
|
|
82
|
+
const cwd = process.cwd();
|
|
83
|
+
console.log('');
|
|
84
|
+
log('Beth Quickstart', COLORS.bright);
|
|
85
|
+
log('─'.repeat(40), COLORS.dim);
|
|
86
|
+
// Step 1: Check if Beth is initialized
|
|
87
|
+
if (!isBethInitialized(cwd)) {
|
|
88
|
+
console.log('');
|
|
89
|
+
logWarning('Beth not initialized in this project.');
|
|
90
|
+
logInfo('Run: npx beth-copilot init');
|
|
91
|
+
console.log('');
|
|
92
|
+
logInfo('Then run: npx beth-copilot quickstart');
|
|
93
|
+
console.log('');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
logSuccess('Beth is initialized');
|
|
97
|
+
// Step 2: Check if beads CLI is available
|
|
98
|
+
if (!isBeadsAvailable()) {
|
|
99
|
+
console.log('');
|
|
100
|
+
logError('beads CLI not found.');
|
|
101
|
+
logInfo('Install: npm install -g @beads/bd');
|
|
102
|
+
logInfo('Or: curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash');
|
|
103
|
+
console.log('');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
// Step 3: Initialize beads if needed
|
|
107
|
+
if (!isBeadsInitialized(cwd)) {
|
|
108
|
+
const initialized = initializeBeads(cwd);
|
|
109
|
+
if (!initialized) {
|
|
110
|
+
logError('Failed to initialize beads.');
|
|
111
|
+
logInfo('Run manually: bd init');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
logSuccess('beads initialized');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
logSuccess('beads already initialized');
|
|
118
|
+
}
|
|
119
|
+
// Step 4: Run doctor (don't exit on failure, we still want to show next steps)
|
|
120
|
+
console.log('');
|
|
121
|
+
log('Running health check...', COLORS.cyan);
|
|
122
|
+
await doctor({ verbose }, false);
|
|
123
|
+
// Step 5: Print next steps
|
|
124
|
+
console.log('');
|
|
125
|
+
log('─'.repeat(40), COLORS.dim);
|
|
126
|
+
log('\nQuick Start Guide:', COLORS.bright);
|
|
127
|
+
console.log('');
|
|
128
|
+
log('1. Open this project in VS Code', COLORS.cyan);
|
|
129
|
+
log('2. Open Copilot Chat (Ctrl+Alt+I / Cmd+Alt+I)', COLORS.cyan);
|
|
130
|
+
log('3. Type @Beth to start working', COLORS.cyan);
|
|
131
|
+
console.log('');
|
|
132
|
+
log('Pro tip:', COLORS.bright);
|
|
133
|
+
logInfo('Start every session with @Beth and let her route work to specialists.');
|
|
134
|
+
console.log('');
|
|
135
|
+
log('Documentation:', COLORS.bright);
|
|
136
|
+
logInfo('https://github.com/stephschofield/beth');
|
|
137
|
+
console.log('');
|
|
138
|
+
log('"They broke my wings and forgot I had claws."', COLORS.cyan);
|
|
139
|
+
console.log('');
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=quickstart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quickstart.js","sourceRoot":"","sources":["../../../src/cli/commands/quickstart.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
|
@@ -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"}
|