guild-agents 0.2.7 → 0.2.9

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 CHANGED
@@ -3,62 +3,64 @@
3
3
  [![npm version](https://img.shields.io/npm/v/guild-agents)](https://www.npmjs.com/package/guild-agents)
4
4
  [![CI](https://github.com/guild-agents/guild/actions/workflows/ci.yml/badge.svg)](https://github.com/guild-agents/guild/actions/workflows/ci.yml)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
- [![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org)
6
+ [![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
7
7
 
8
- A multi-agent framework for Claude Code.
8
+ Claude Code is powerful but chaotic. Guild gives it structure.
9
9
 
10
- Sets up 8 specialized agents and 10 skill-based workflows as `.claude/` files in any project.
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
- ## Installation
12
+ ## Why Guild?
13
13
 
14
- ```bash
15
- npm install -g guild-agents
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
- Or run directly without installing:
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
- npx guild-agents init
43
+ npm install -g guild-agents
44
+ guild init
28
45
  ```
29
46
 
30
- Interactive onboarding asks for project name, type, stack, and repo details, then generates the full agent and skill structure.
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
- Open Claude Code in your project and run:
49
+ Next, let Guild learn your codebase:
33
50
 
34
51
  ```
35
52
  /guild-specialize
36
53
  ```
37
54
 
38
- This explores your actual codebase and enriches CLAUDE.md with real conventions, patterns, and stack details.
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 start building:
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: evaluation, spec, implementation, review, and QA.
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 >= 18
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/`) improve agent definitions or skill workflows.
143
- - **CLI code** (`src/`, `bin/`) bug fixes, new commands, onboarding improvements.
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 see [LICENSE](LICENSE).
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.7",
3
+ "version": "0.2.9",
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/utils/__tests__/"
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"
@@ -13,7 +13,7 @@ import * as p from '@clack/prompts';
13
13
  import chalk from 'chalk';
14
14
  import { existsSync } from 'fs';
15
15
  import { generateProjectMd, generateSessionMd, generateClaudeMd } from '../utils/generators.js';
16
- import { copyTemplates } from '../utils/files.js';
16
+ import { copyTemplates, getAgentNames } from '../utils/files.js';
17
17
 
18
18
  export async function runInit() {
19
19
  console.log('');
@@ -125,7 +125,7 @@ export async function runInit() {
125
125
  p.log.success('CLAUDE.md');
126
126
  p.log.success('PROJECT.md');
127
127
  p.log.success('SESSION.md');
128
- p.log.success('.claude/agents/ (8 base agents)');
128
+ p.log.success(`.claude/agents/ (${getAgentNames().length} base agents)`);
129
129
  p.log.success('.claude/skills/ (10 skills)');
130
130
 
131
131
  p.note(
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: platform-expert
3
3
  description: "Diagnoses and resolves Claude Code integration issues -- permissions, subagents, hooks, settings"
4
+ tools: Read, Write, Edit, Bash, Glob, Grep
5
+ permissionMode: bypassPermissions
4
6
  ---
5
7
 
6
8
  # Platform Expert
@@ -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
  ```
@@ -1,5 +1,5 @@
1
1
  /**
2
- * files.js — Utilidades de sistema de archivos para Guild v1
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
- * Lista los nombres de los 9 agentes v1.
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
- * Copia los templates de agentes y skills al proyecto del usuario.
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
- * Lee el contenido de PROJECT.md si existe.
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
- * Lee el contenido de SESSION.md si existe.
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
- * Resuelve la raiz del proyecto Guild caminando hacia arriba desde startDir.
87
- * Busca .claude/ o PROJECT.md como marcadores de un proyecto Guild.
88
- * Retorna la ruta absoluta del proyecto o null si no se encuentra.
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
- });