guild-agents 0.2.7 → 0.2.8
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/README.md +45 -35
- package/bin/guild.js +2 -0
- package/package.json +4 -5
- package/src/templates/agents/platform-expert.md +2 -0
- package/src/templates/skills/guild-specialize/SKILL.md +1 -0
- package/src/templates/skills/status/SKILL.md +1 -1
- package/src/utils/files.js +8 -8
- package/src/commands/__tests__/doctor.test.js +0 -85
- package/src/commands/__tests__/list.test.js +0 -82
- package/src/commands/__tests__/new-agent.test.js +0 -40
- package/src/commands/__tests__/status.test.js +0 -35
package/README.md
CHANGED
|
@@ -3,62 +3,64 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/guild-agents)
|
|
4
4
|
[](https://github.com/guild-agents/guild/actions/workflows/ci.yml)
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[](https://nodejs.org)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Claude Code is powerful but chaotic. Guild gives it structure.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Guild is an npm CLI that sets up 9 specialized agents and 10 skill-based workflows as `.claude/` files in any project. Agents define **who** does the work. Skills define **how** it gets done. Everything is markdown, tracked by git, works offline.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Why Guild?
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
- **Structure over chaos.** Claude Code without guidance produces inconsistent results. Guild gives every task a clear owner and a repeatable process.
|
|
15
|
+
- **Agents = WHO, Skills = HOW.** Agents are flat `.md` files with identity and expertise. Skills are workflow definitions invoked as slash commands. Clean separation, no magic.
|
|
16
|
+
- **State that persists.** Context lives in `CLAUDE.md`, `PROJECT.md`, and `SESSION.md` -- tracked by git, readable by humans, never lost between sessions.
|
|
17
|
+
- **Zero infrastructure.** No servers, no APIs, no config files. Just markdown files that Claude Code reads natively.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
## How It Works
|
|
19
20
|
|
|
20
|
-
```bash
|
|
21
|
-
npx guild-agents init
|
|
22
21
|
```
|
|
22
|
+
You ──> /build-feature "Add JWT auth"
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
┌─────────┐ ┌───────────────┐ ┌───────────────┐
|
|
26
|
+
│ Advisor │────>│ Tech Lead │────>│ Developer │
|
|
27
|
+
│ evaluate │ │ plan │ │ implement │
|
|
28
|
+
└─────────┘ └───────────────┘ └───────┬───────┘
|
|
29
|
+
│
|
|
30
|
+
┌─────────────┼─────────────┐
|
|
31
|
+
▼ ▼ ▼
|
|
32
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
33
|
+
│ Reviewer │ │ QA │ │ Bugfix │
|
|
34
|
+
│ review │ │ test │ │ fix │
|
|
35
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Skills orchestrate agents through structured pipelines. You invoke a skill as a slash command, and it coordinates the right agents in the right order.
|
|
23
39
|
|
|
24
40
|
## Quick Start
|
|
25
41
|
|
|
26
42
|
```bash
|
|
27
|
-
|
|
43
|
+
npm install -g guild-agents
|
|
44
|
+
guild init
|
|
28
45
|
```
|
|
29
46
|
|
|
30
|
-
|
|
47
|
+
The interactive onboarding asks for project name, type, stack, and repo details, then generates the full structure: 9 agents, 10 skills, and 3 state files.
|
|
31
48
|
|
|
32
|
-
|
|
49
|
+
Next, let Guild learn your codebase:
|
|
33
50
|
|
|
34
51
|
```
|
|
35
52
|
/guild-specialize
|
|
36
53
|
```
|
|
37
54
|
|
|
38
|
-
This explores your actual
|
|
55
|
+
This explores your actual code and enriches `CLAUDE.md` with real conventions, patterns, and stack details. Every agent now understands your project.
|
|
39
56
|
|
|
40
|
-
Then
|
|
57
|
+
Then build something:
|
|
41
58
|
|
|
42
59
|
```
|
|
43
60
|
/build-feature Add user authentication with JWT
|
|
44
61
|
```
|
|
45
62
|
|
|
46
|
-
This runs the full pipeline
|
|
47
|
-
|
|
48
|
-
`guild init` generates: CLAUDE.md, PROJECT.md, SESSION.md, `.claude/agents/` (8 agents), `.claude/skills/` (10 skills).
|
|
49
|
-
|
|
50
|
-
## How It Works
|
|
51
|
-
|
|
52
|
-
**Agents** are the WHO. Each agent is a flat `.md` file in `.claude/agents/` that defines identity, responsibilities, and process. Skills invoke agents via the Task tool when their expertise is needed.
|
|
53
|
-
|
|
54
|
-
**Skills** are the HOW. Each skill is a workflow defined in `.claude/skills/*/SKILL.md` and invoked as a slash command. Skills orchestrate one or more agents through a structured process.
|
|
55
|
-
|
|
56
|
-
**State** is maintained across sessions through three files:
|
|
57
|
-
- `CLAUDE.md` — central enriched context (stack, conventions, rules)
|
|
58
|
-
- `PROJECT.md` — project metadata (name, type, architecture)
|
|
59
|
-
- `SESSION.md` — session continuity (current task, progress, next steps)
|
|
60
|
-
|
|
61
|
-
After init, agents are generic. Running `/guild-specialize` reads the real codebase and tailors each agent to the project's specific stack and patterns.
|
|
63
|
+
This runs the full pipeline -- advisor evaluation, tech lead planning, developer implementation, code review, and QA -- all coordinated automatically.
|
|
62
64
|
|
|
63
65
|
## Agents
|
|
64
66
|
|
|
@@ -72,6 +74,7 @@ After init, agents are generic. Running `/guild-specialize` reads the real codeb
|
|
|
72
74
|
| qa | Testing, edge cases, regression validation |
|
|
73
75
|
| bugfix | Bug diagnosis and resolution |
|
|
74
76
|
| db-migration | Schema changes and safe migrations |
|
|
77
|
+
| platform-expert | Diagnoses and resolves Claude Code integration issues |
|
|
75
78
|
|
|
76
79
|
## Skills
|
|
77
80
|
|
|
@@ -94,6 +97,8 @@ After init, agents are generic. Running `/guild-specialize` reads the real codeb
|
|
|
94
97
|
guild init # Interactive project onboarding
|
|
95
98
|
guild new-agent <name> # Create a custom agent
|
|
96
99
|
guild status # Show project status
|
|
100
|
+
guild doctor # Diagnose installation state
|
|
101
|
+
guild list # List installed agents and skills
|
|
97
102
|
```
|
|
98
103
|
|
|
99
104
|
## Generated Structure
|
|
@@ -114,6 +119,7 @@ SESSION.md
|
|
|
114
119
|
qa.md
|
|
115
120
|
bugfix.md
|
|
116
121
|
db-migration.md
|
|
122
|
+
platform-expert.md
|
|
117
123
|
skills/
|
|
118
124
|
guild-specialize/SKILL.md
|
|
119
125
|
build-feature/SKILL.md
|
|
@@ -129,9 +135,13 @@ SESSION.md
|
|
|
129
135
|
|
|
130
136
|
All files are markdown, tracked by git, and work fully offline.
|
|
131
137
|
|
|
138
|
+
## Guild Builds Itself
|
|
139
|
+
|
|
140
|
+
This project uses its own agents and skills to develop itself. Every feature, review, and bugfix goes through the same pipelines that Guild installs in your project.
|
|
141
|
+
|
|
132
142
|
## Requirements
|
|
133
143
|
|
|
134
|
-
- Node.js >=
|
|
144
|
+
- Node.js >= 20
|
|
135
145
|
- Claude Code
|
|
136
146
|
- `gh` CLI (optional, for GitHub integration)
|
|
137
147
|
|
|
@@ -139,11 +149,11 @@ All files are markdown, tracked by git, and work fully offline.
|
|
|
139
149
|
|
|
140
150
|
Two types of contributions:
|
|
141
151
|
|
|
142
|
-
- **Agent and skill templates** (`src/templates/`)
|
|
143
|
-
- **CLI code** (`src/`, `bin/`)
|
|
152
|
+
- **Agent and skill templates** (`src/templates/`) -- improve agent definitions or skill workflows.
|
|
153
|
+
- **CLI code** (`src/`, `bin/`) -- bug fixes, new commands, onboarding improvements.
|
|
144
154
|
|
|
145
155
|
See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for details.
|
|
146
156
|
|
|
147
157
|
## License
|
|
148
158
|
|
|
149
|
-
MIT
|
|
159
|
+
MIT -- see [LICENSE](LICENSE).
|
package/bin/guild.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* guild init — interactive onboarding v1
|
|
7
7
|
* guild new-agent — create a new agent
|
|
8
8
|
* guild status — view project status
|
|
9
|
+
* guild doctor — verify setup and report issues
|
|
10
|
+
* guild list — list installed agents and skills
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import { program } from 'commander';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guild-agents",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "A multi-agent framework for Claude Code — specialized AI teams for every project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"src/commands/",
|
|
9
9
|
"src/templates/",
|
|
10
10
|
"src/utils/",
|
|
11
|
-
"!src
|
|
11
|
+
"!src/**/__tests__/"
|
|
12
12
|
],
|
|
13
13
|
"bin": {
|
|
14
14
|
"guild": "bin/guild.js"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"code-review",
|
|
40
40
|
"nodejs"
|
|
41
41
|
],
|
|
42
|
-
"author": "",
|
|
42
|
+
"author": "Guild Agents <guild-agents@users.noreply.github.com>",
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|
|
@@ -52,8 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@clack/prompts": "^1.0.1",
|
|
54
54
|
"chalk": "^5.3.0",
|
|
55
|
-
"commander": "^14.0.3"
|
|
56
|
-
"picocolors": "^1.0.0"
|
|
55
|
+
"commander": "^14.0.3"
|
|
57
56
|
},
|
|
58
57
|
"engines": {
|
|
59
58
|
"node": ">=20.0.0"
|
|
@@ -87,6 +87,7 @@ For each agent in `.claude/agents/*.md`, add project-specific context:
|
|
|
87
87
|
- **qa.md**: testing framework, commands to run tests, current coverage
|
|
88
88
|
- **bugfix.md**: debugging stack, logs, available tools
|
|
89
89
|
- **db-migration.md**: ORM, migration tool, current schema (if applicable)
|
|
90
|
+
- **platform-expert.md**: Claude Code version, known permission bugs, hook configuration
|
|
90
91
|
|
|
91
92
|
Use the `Task` tool to invoke each agent by reading their `.claude/agents/[name].md` if you need a specialized perspective to enrich their configuration.
|
|
92
93
|
|
|
@@ -75,7 +75,7 @@ Session: 2026-02-23
|
|
|
75
75
|
Task: Implementing user preferences
|
|
76
76
|
State: Phase 4 — Developer implementing
|
|
77
77
|
|
|
78
|
-
Agents: advisor, product-owner, tech-lead, developer, code-reviewer, qa, bugfix, db-migration
|
|
78
|
+
Agents: advisor, product-owner, tech-lead, developer, code-reviewer, qa, bugfix, db-migration, platform-expert
|
|
79
79
|
Skills: guild-specialize, build-feature, new-feature, council, qa-cycle, review, dev-flow,
|
|
80
80
|
status, session-start, session-end
|
|
81
81
|
```
|
package/src/utils/files.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* files.js —
|
|
2
|
+
* files.js — File system utilities for Guild v1
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { mkdirSync, copyFileSync, existsSync, readdirSync, readFileSync } from 'fs';
|
|
@@ -12,7 +12,7 @@ const AGENTS_DIR = join('.claude', 'agents');
|
|
|
12
12
|
const SKILLS_DIR = join('.claude', 'skills');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Returns the names of the 9 v1 agents.
|
|
16
16
|
*/
|
|
17
17
|
export function getAgentNames() {
|
|
18
18
|
return [
|
|
@@ -29,7 +29,7 @@ export function getAgentNames() {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* Copies agent and skill templates to the user's project.
|
|
33
33
|
*/
|
|
34
34
|
export async function copyTemplates() {
|
|
35
35
|
mkdirSync(AGENTS_DIR, { recursive: true });
|
|
@@ -65,7 +65,7 @@ export async function copyTemplates() {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
68
|
+
* Reads the contents of PROJECT.md if it exists.
|
|
69
69
|
*/
|
|
70
70
|
export function readProjectMd() {
|
|
71
71
|
const path = 'PROJECT.md';
|
|
@@ -74,7 +74,7 @@ export function readProjectMd() {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
77
|
+
* Reads the contents of SESSION.md if it exists.
|
|
78
78
|
*/
|
|
79
79
|
export function readSessionMd() {
|
|
80
80
|
const path = 'SESSION.md';
|
|
@@ -83,9 +83,9 @@ export function readSessionMd() {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* Resolves the Guild project root by walking up from startDir.
|
|
87
|
+
* Looks for .claude/ or PROJECT.md as markers of a Guild project.
|
|
88
|
+
* Returns the absolute path to the project or null if not found.
|
|
89
89
|
*/
|
|
90
90
|
export function resolveProjectRoot(startDir = process.cwd()) {
|
|
91
91
|
let dir = resolve(startDir);
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { mkdirSync, rmSync, mkdtempSync, writeFileSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
|
|
6
|
-
describe('runDoctor', () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
let originalCwd;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
tempDir = mkdtempSync(join(tmpdir(), 'guild-doctor-'));
|
|
12
|
-
originalCwd = process.cwd();
|
|
13
|
-
vi.resetModules();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
process.chdir(originalCwd);
|
|
18
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should pass all checks for a healthy project', async () => {
|
|
22
|
-
// Setup a complete Guild project
|
|
23
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
24
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'build-feature'), { recursive: true });
|
|
25
|
-
writeFileSync(join(tempDir, '.claude', 'agents', 'advisor.md'), '---\nname: advisor\n---');
|
|
26
|
-
writeFileSync(join(tempDir, '.claude', 'skills', 'build-feature', 'SKILL.md'), '---\nname: build-feature\n---');
|
|
27
|
-
writeFileSync(join(tempDir, 'CLAUDE.md'), '# CLAUDE');
|
|
28
|
-
writeFileSync(join(tempDir, 'PROJECT.md'), '# PROJECT');
|
|
29
|
-
writeFileSync(join(tempDir, 'SESSION.md'), '# SESSION');
|
|
30
|
-
|
|
31
|
-
process.chdir(tempDir);
|
|
32
|
-
const { runDoctor } = await import('../doctor.js');
|
|
33
|
-
// Should not throw for healthy project
|
|
34
|
-
await expect(runDoctor()).resolves.toBeUndefined();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should throw when .claude directory is missing', async () => {
|
|
38
|
-
writeFileSync(join(tempDir, 'CLAUDE.md'), '# CLAUDE');
|
|
39
|
-
writeFileSync(join(tempDir, 'PROJECT.md'), '# PROJECT');
|
|
40
|
-
writeFileSync(join(tempDir, 'SESSION.md'), '# SESSION');
|
|
41
|
-
|
|
42
|
-
process.chdir(tempDir);
|
|
43
|
-
const { runDoctor } = await import('../doctor.js');
|
|
44
|
-
await expect(runDoctor()).rejects.toThrow('Guild setup has issues');
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should throw when agents directory is empty', async () => {
|
|
48
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
49
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'test-skill'), { recursive: true });
|
|
50
|
-
writeFileSync(join(tempDir, '.claude', 'skills', 'test-skill', 'SKILL.md'), '---\nname: test\n---');
|
|
51
|
-
writeFileSync(join(tempDir, 'CLAUDE.md'), '# CLAUDE');
|
|
52
|
-
writeFileSync(join(tempDir, 'PROJECT.md'), '# PROJECT');
|
|
53
|
-
writeFileSync(join(tempDir, 'SESSION.md'), '# SESSION');
|
|
54
|
-
|
|
55
|
-
process.chdir(tempDir);
|
|
56
|
-
const { runDoctor } = await import('../doctor.js');
|
|
57
|
-
await expect(runDoctor()).rejects.toThrow('Guild setup has issues');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should throw when CLAUDE.md is missing', async () => {
|
|
61
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
62
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'test-skill'), { recursive: true });
|
|
63
|
-
writeFileSync(join(tempDir, '.claude', 'agents', 'advisor.md'), '---\nname: advisor\n---');
|
|
64
|
-
writeFileSync(join(tempDir, '.claude', 'skills', 'test-skill', 'SKILL.md'), '---\nname: test\n---');
|
|
65
|
-
writeFileSync(join(tempDir, 'PROJECT.md'), '# PROJECT');
|
|
66
|
-
writeFileSync(join(tempDir, 'SESSION.md'), '# SESSION');
|
|
67
|
-
|
|
68
|
-
process.chdir(tempDir);
|
|
69
|
-
const { runDoctor } = await import('../doctor.js');
|
|
70
|
-
await expect(runDoctor()).rejects.toThrow('Guild setup has issues');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should throw when PROJECT.md is missing', async () => {
|
|
74
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
75
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'test-skill'), { recursive: true });
|
|
76
|
-
writeFileSync(join(tempDir, '.claude', 'agents', 'advisor.md'), '---\nname: advisor\n---');
|
|
77
|
-
writeFileSync(join(tempDir, '.claude', 'skills', 'test-skill', 'SKILL.md'), '---\nname: test\n---');
|
|
78
|
-
writeFileSync(join(tempDir, 'CLAUDE.md'), '# CLAUDE');
|
|
79
|
-
writeFileSync(join(tempDir, 'SESSION.md'), '# SESSION');
|
|
80
|
-
|
|
81
|
-
process.chdir(tempDir);
|
|
82
|
-
const { runDoctor } = await import('../doctor.js');
|
|
83
|
-
await expect(runDoctor()).rejects.toThrow('Guild setup has issues');
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { mkdirSync, rmSync, mkdtempSync, writeFileSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
|
|
6
|
-
describe('runList', () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
let originalCwd;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
tempDir = mkdtempSync(join(tmpdir(), 'guild-list-'));
|
|
12
|
-
originalCwd = process.cwd();
|
|
13
|
-
vi.resetModules();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
process.chdir(originalCwd);
|
|
18
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should list agents and skills with descriptions', async () => {
|
|
22
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
23
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'build-feature'), { recursive: true });
|
|
24
|
-
writeFileSync(
|
|
25
|
-
join(tempDir, '.claude', 'agents', 'advisor.md'),
|
|
26
|
-
'---\nname: advisor\ndescription: "Strategic advisor"\n---\n# Advisor'
|
|
27
|
-
);
|
|
28
|
-
writeFileSync(
|
|
29
|
-
join(tempDir, '.claude', 'skills', 'build-feature', 'SKILL.md'),
|
|
30
|
-
'---\nname: build-feature\ndescription: "Full pipeline"\n---\n# Build Feature'
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
process.chdir(tempDir);
|
|
34
|
-
const { runList } = await import('../list.js');
|
|
35
|
-
await expect(runList()).resolves.toBeUndefined();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should handle missing agents directory', async () => {
|
|
39
|
-
mkdirSync(join(tempDir, '.claude', 'skills', 'test'), { recursive: true });
|
|
40
|
-
writeFileSync(
|
|
41
|
-
join(tempDir, '.claude', 'skills', 'test', 'SKILL.md'),
|
|
42
|
-
'---\nname: test\n---'
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
process.chdir(tempDir);
|
|
46
|
-
const { runList } = await import('../list.js');
|
|
47
|
-
await expect(runList()).resolves.toBeUndefined();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should handle missing skills directory', async () => {
|
|
51
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
52
|
-
writeFileSync(
|
|
53
|
-
join(tempDir, '.claude', 'agents', 'advisor.md'),
|
|
54
|
-
'---\nname: advisor\n---'
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
process.chdir(tempDir);
|
|
58
|
-
const { runList } = await import('../list.js');
|
|
59
|
-
await expect(runList()).resolves.toBeUndefined();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should handle empty directories', async () => {
|
|
63
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
64
|
-
mkdirSync(join(tempDir, '.claude', 'skills'), { recursive: true });
|
|
65
|
-
|
|
66
|
-
process.chdir(tempDir);
|
|
67
|
-
const { runList } = await import('../list.js');
|
|
68
|
-
await expect(runList()).resolves.toBeUndefined();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should handle agents without frontmatter', async () => {
|
|
72
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
73
|
-
writeFileSync(
|
|
74
|
-
join(tempDir, '.claude', 'agents', 'custom.md'),
|
|
75
|
-
'# Custom Agent\nNo frontmatter here'
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
process.chdir(tempDir);
|
|
79
|
-
const { runList } = await import('../list.js');
|
|
80
|
-
await expect(runList()).resolves.toBeUndefined();
|
|
81
|
-
});
|
|
82
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { mkdirSync, rmSync, mkdtempSync, writeFileSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
|
|
6
|
-
describe('runNewAgent', () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
let originalCwd;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
tempDir = mkdtempSync(join(tmpdir(), 'guild-test-'));
|
|
12
|
-
originalCwd = process.cwd();
|
|
13
|
-
vi.resetModules();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
process.chdir(originalCwd);
|
|
18
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should throw with invalid agent name', async () => {
|
|
22
|
-
process.chdir(tempDir);
|
|
23
|
-
const { runNewAgent } = await import('../new-agent.js');
|
|
24
|
-
await expect(runNewAgent('Invalid Name!')).rejects.toThrow('Invalid name');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should throw when .claude/agents/ does not exist', async () => {
|
|
28
|
-
process.chdir(tempDir);
|
|
29
|
-
const { runNewAgent } = await import('../new-agent.js');
|
|
30
|
-
await expect(runNewAgent('valid-name')).rejects.toThrow('Guild is not installed');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should throw when agent already exists', async () => {
|
|
34
|
-
process.chdir(tempDir);
|
|
35
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
36
|
-
writeFileSync(join(tempDir, '.claude', 'agents', 'existing.md'), '# existing');
|
|
37
|
-
const { runNewAgent } = await import('../new-agent.js');
|
|
38
|
-
await expect(runNewAgent('existing')).rejects.toThrow('already exists');
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { mkdirSync, writeFileSync, rmSync, mkdtempSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { tmpdir } from 'os';
|
|
5
|
-
|
|
6
|
-
describe('runStatus', () => {
|
|
7
|
-
let tempDir;
|
|
8
|
-
let originalCwd;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
tempDir = mkdtempSync(join(tmpdir(), 'guild-test-'));
|
|
12
|
-
originalCwd = process.cwd();
|
|
13
|
-
vi.resetModules();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
process.chdir(originalCwd);
|
|
18
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should throw when PROJECT.md does not exist', async () => {
|
|
22
|
-
process.chdir(tempDir);
|
|
23
|
-
const { runStatus } = await import('../status.js');
|
|
24
|
-
await expect(runStatus()).rejects.toThrow('Guild is not installed');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should not throw when PROJECT.md exists', async () => {
|
|
28
|
-
process.chdir(tempDir);
|
|
29
|
-
writeFileSync(join(tempDir, 'PROJECT.md'), '**Name:** TestProject\n**Stack:** Node.js');
|
|
30
|
-
mkdirSync(join(tempDir, '.claude', 'agents'), { recursive: true });
|
|
31
|
-
mkdirSync(join(tempDir, '.claude', 'skills'), { recursive: true });
|
|
32
|
-
const { runStatus } = await import('../status.js');
|
|
33
|
-
await expect(runStatus()).resolves.not.toThrow();
|
|
34
|
-
});
|
|
35
|
-
});
|