guild-agents 0.1.0 → 0.2.1

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 (33) hide show
  1. package/bin/guild.js +49 -6
  2. package/package.json +2 -3
  3. package/src/commands/__tests__/doctor.test.js +85 -0
  4. package/src/commands/__tests__/list.test.js +82 -0
  5. package/src/commands/__tests__/new-agent.test.js +40 -0
  6. package/src/commands/__tests__/status.test.js +35 -0
  7. package/src/commands/doctor.js +99 -0
  8. package/src/commands/init.js +5 -6
  9. package/src/commands/list.js +82 -0
  10. package/src/commands/new-agent.js +5 -10
  11. package/src/commands/status.js +1 -2
  12. package/src/templates/agents/advisor.md +2 -0
  13. package/src/templates/agents/bugfix.md +2 -0
  14. package/src/templates/agents/code-reviewer.md +2 -0
  15. package/src/templates/agents/db-migration.md +2 -0
  16. package/src/templates/agents/developer.md +2 -0
  17. package/src/templates/agents/platform-expert.md +89 -0
  18. package/src/templates/agents/product-owner.md +2 -0
  19. package/src/templates/agents/qa.md +2 -0
  20. package/src/templates/agents/tech-lead.md +2 -0
  21. package/src/templates/skills/build-feature/SKILL.md +114 -14
  22. package/src/templates/skills/council/SKILL.md +33 -1
  23. package/src/templates/skills/dev-flow/SKILL.md +15 -1
  24. package/src/templates/skills/guild-specialize/SKILL.md +44 -1
  25. package/src/templates/skills/new-feature/SKILL.md +29 -2
  26. package/src/templates/skills/qa-cycle/SKILL.md +40 -11
  27. package/src/templates/skills/review/SKILL.md +31 -3
  28. package/src/templates/skills/session-end/SKILL.md +31 -1
  29. package/src/templates/skills/session-start/SKILL.md +33 -3
  30. package/src/templates/skills/status/SKILL.md +20 -1
  31. package/src/utils/files.js +23 -2
  32. package/src/utils/generators.js +7 -0
  33. package/src/utils/github.js +32 -14
@@ -20,20 +20,32 @@ Ejecuta un code review independiente sobre los cambios actuales del proyecto. In
20
20
 
21
21
  ## Proceso
22
22
 
23
- ### Paso 1 — Obtener diff
23
+ ### Paso 1 — Obtener diff y estado de verificacion
24
24
 
25
25
  Obtiene los cambios actuales:
26
+
26
27
  1. Primero intenta `git diff --staged` (cambios en staging)
27
28
  2. Si no hay cambios en staging, usa `git diff` (cambios sin stage)
28
29
  3. Si no hay ningun cambio, informa que no hay nada que revisar
29
30
 
31
+ Ejecuta verificacion automatizada para dar contexto al reviewer:
32
+
33
+ 4. Ejecuta tests del proyecto (ej: `npm test`) — captura resultado
34
+ 5. Ejecuta lint del proyecto (ej: `npm run lint`) — captura resultado
35
+ 6. Incluye ambos resultados como contexto para el Code Reviewer
36
+
37
+ Nota: El Code Reviewer no tiene acceso a Bash (solo Read, Glob, Grep), por eso los tests y lint se ejecutan aqui antes de invocar al reviewer.
38
+
30
39
  ### Paso 2 — Invocar Code Reviewer
31
40
 
32
41
  Invoca al agente Code Reviewer usando Task tool:
42
+
33
43
  1. Lee `.claude/agents/code-reviewer.md` para asumir el rol
34
44
  2. Lee CLAUDE.md para entender las convenciones del proyecto
35
- 3. Revisa el diff completo
36
- 4. Clasifica cada hallazgo por severidad:
45
+ 3. Recibe el diff completo + resultados de tests y lint del Paso 1
46
+ 4. Si tests o lint fallaron, esto es automaticamente un hallazgo Blocker
47
+ 5. Revisa el diff completo
48
+ 6. Clasifica cada hallazgo por severidad:
37
49
  - **Blocker**: Debe corregirse antes de merge
38
50
  - **Warning**: Deberia corregirse, introduce deuda tecnica
39
51
  - **Suggestion**: Mejora opcional
@@ -41,8 +53,24 @@ Invoca al agente Code Reviewer usando Task tool:
41
53
  ### Paso 3 — Presentar hallazgos
42
54
 
43
55
  Presenta el reporte organizado por severidad:
56
+
44
57
  - Cantidad total de hallazgos por tipo
45
58
  - Detalle de cada hallazgo: archivo, descripcion, sugerencia de correccion
46
59
  - Veredicto final: Aprobado / Aprobado con warnings / Bloqueado
47
60
 
48
61
  Si hay blockers, sugiere corregirlos y ejecutar `/review` de nuevo.
62
+
63
+ ## Example Session
64
+
65
+ ```text
66
+ User: /review
67
+
68
+ Reviewing diff: 4 files changed, +127 -34
69
+
70
+ Findings:
71
+ - [Warning] src/api/users.js:45 — No input validation on email parameter
72
+ - [Suggestion] src/utils/format.js:12 — Consider using Intl.DateTimeFormat
73
+ - [Blocker] src/db/queries.js:78 — SQL injection vulnerability in raw query
74
+
75
+ 1 blocker, 1 warning, 1 suggestion.
76
+ ```
@@ -22,6 +22,7 @@ Guarda el estado actual del trabajo en SESSION.md para poder retomarlo en la sig
22
22
  ### Paso 1 — Recopilar estado actual
23
23
 
24
24
  Analiza el estado actual del trabajo:
25
+
25
26
  - Que tarea estaba en curso
26
27
  - En que fase del pipeline se encuentra (si aplica)
27
28
  - Que archivos se modificaron (via `git status`)
@@ -38,17 +39,46 @@ Actualiza SESSION.md con la siguiente informacion:
38
39
  - **Estado:** descripcion concreta de donde quedo el trabajo
39
40
 
40
41
  **Contexto relevante:**
42
+
41
43
  - Decisiones tomadas en esta sesion
42
44
  - Problemas encontrados y como se resolvieron
43
45
  - Informacion importante para retomar
44
46
 
45
47
  **Proximos pasos:**
48
+
46
49
  - Las 2-3 acciones concretas mas importantes al retomar
47
50
  - Skill sugerido para continuar (ej: "ejecutar /build-feature para continuar desde Fase 4")
48
51
 
49
- ### Paso 3 — Confirmar
52
+ ### Paso 3 — Commit WIP if uncommitted work exists
53
+
54
+ If there are uncommitted changes, create a checkpoint commit:
55
+
56
+ ```bash
57
+ git add -A
58
+ git commit -m "wip: session paused — [brief description of current state]"
59
+ ```
60
+
61
+ This ensures no work is lost between sessions. Never leave uncommitted changes across session boundaries.
62
+
63
+ ## Example Session
64
+
65
+ ```text
66
+ User: /session-end
67
+
68
+ Saving session state...
69
+ Task: user-preferences
70
+ Phase: 4 — Implementation (in progress)
71
+ Files modified: 3 files
72
+ WIP committed: wip: session paused — user-preferences phase 4
73
+
74
+ SESSION.md updated. Safe to close.
75
+ ```
76
+
77
+ ### Paso 4 — Confirmar
50
78
 
51
79
  Confirma al usuario:
80
+
52
81
  - SESSION.md actualizado con el estado actual
82
+ - WIP committed (if applicable)
53
83
  - Proximos pasos registrados
54
84
  - Puedes cerrar la sesion con seguridad
@@ -22,32 +22,62 @@ Carga el contexto del proyecto y retoma el trabajo desde donde se dejo en la ses
22
22
  ### Paso 1 — Cargar contexto
23
23
 
24
24
  Lee los archivos de estado de Guild:
25
+
25
26
  - `CLAUDE.md` — instrucciones, convenciones y reglas del proyecto
26
27
  - `SESSION.md` — estado de la ultima sesion, tarea en curso, proximos pasos
27
28
  - `PROJECT.md` — identidad del proyecto, stack, agentes configurados
28
29
 
29
- ### Paso 2 — Presentar estado
30
+ ### Paso 2 — Detect resumable work
31
+
32
+ Check for `wip:` checkpoint commits on active branches:
33
+
34
+ ```bash
35
+ git branch --list "feature/*" --list "fix/*" | while read branch; do
36
+ git log --oneline "$branch" -1 | grep "^wip:" && echo "Resumable: $branch"
37
+ done
38
+ ```
39
+
40
+ If `wip:` commits are found, present them to the user with the phase they were in when interrupted.
41
+
42
+ ### Paso 3 — Presentar estado
30
43
 
31
44
  Muestra un resumen de la sesion anterior:
45
+
32
46
  - Fecha de la ultima sesion
33
47
  - Tarea en curso (si existe)
34
48
  - Estado en que quedo el trabajo
35
49
  - Decisiones tomadas previamente
36
50
  - Proximos pasos registrados
51
+ - **Resumable pipelines** (if wip: commits detected)
37
52
 
38
- ### Paso 3 — Sugerir como continuar
53
+ ### Paso 4 — Sugerir como continuar
39
54
 
40
55
  Si hay tarea en curso:
56
+
41
57
  - Muestra el estado de la tarea
42
58
  - Sugiere continuar con el skill apropiado (ej: `/build-feature` si esta en implementacion)
43
59
  - Muestra los proximos pasos registrados en SESSION.md
44
60
 
45
61
  Si no hay tarea en curso, sugiere opciones:
62
+
46
63
  - `/build-feature [descripcion]` — para implementar una feature nueva
47
64
  - `/new-feature [nombre]` — para preparar el entorno de una feature
48
65
  - `/status` — para ver el estado general del proyecto
49
66
  - `/council [pregunta]` — para debatir una decision importante
50
67
 
51
- ### Paso 4 — Actualizar sesion
68
+ ### Paso 5 — Actualizar sesion
52
69
 
53
70
  Actualiza SESSION.md con la fecha actual para registrar que la sesion inicio.
71
+
72
+ ## Example Session
73
+
74
+ ```text
75
+ User: /session-start
76
+
77
+ Loading context...
78
+ Last session: 2026-02-22
79
+ Task in progress: user-preferences (Phase 4 — Implementation)
80
+ Resumable: feature/user-preferences (wip: phase 3 complete)
81
+
82
+ Suggested: Continue with /build-feature to resume implementation.
83
+ ```
@@ -23,6 +23,7 @@ Muestra un resumen completo del estado actual del proyecto, la sesion activa y l
23
23
  ### Paso 1 — Leer archivos de estado
24
24
 
25
25
  Lee los archivos de configuracion de Guild:
26
+
26
27
  - `CLAUDE.md` — instrucciones y convenciones del proyecto
27
28
  - `PROJECT.md` — identidad, stack y agentes configurados
28
29
  - `SESSION.md` — estado de la sesion actual
@@ -31,7 +32,7 @@ Lee los archivos de configuracion de Guild:
31
32
 
32
33
  Muestra el resumen con el siguiente formato:
33
34
 
34
- ```
35
+ ```text
35
36
  Guild v1 — [nombre del proyecto]
36
37
 
37
38
  Sesion actual:
@@ -55,8 +56,26 @@ Proximos pasos:
55
56
  ### Paso 3 — Sugerir acciones
56
57
 
57
58
  Si no hay tarea en curso, sugiere:
59
+
58
60
  - `/build-feature` para implementar algo nuevo
59
61
  - `/new-feature` para preparar el entorno de una feature
60
62
  - `/council` para debatir una decision
61
63
 
62
64
  Si hay tarea en curso, sugiere continuar con el skill apropiado segun el estado.
65
+
66
+ ## Example Session
67
+
68
+ ```text
69
+ User: /status
70
+
71
+ Guild — MyProject
72
+ Stack: Node.js 20, React 18, PostgreSQL
73
+
74
+ Session: 2026-02-23
75
+ Task: Implementing user preferences
76
+ State: Phase 4 — Developer implementing
77
+
78
+ Agents: advisor, product-owner, tech-lead, developer, code-reviewer, qa, bugfix, db-migration
79
+ Skills: guild-specialize, build-feature, new-feature, council, qa-cycle, review, dev-flow,
80
+ status, session-start, session-end
81
+ ```
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { mkdirSync, copyFileSync, existsSync, readdirSync, readFileSync } from 'fs';
6
- import { join, dirname } from 'path';
6
+ import { join, dirname, resolve } from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
 
9
9
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -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 8 agentes v1.
15
+ * Lista los nombres de los 9 agentes v1.
16
16
  */
17
17
  export function getAgentNames() {
18
18
  return [
@@ -24,6 +24,7 @@ export function getAgentNames() {
24
24
  'qa',
25
25
  'bugfix',
26
26
  'db-migration',
27
+ 'platform-expert',
27
28
  ];
28
29
  }
29
30
 
@@ -80,3 +81,23 @@ export function readSessionMd() {
80
81
  if (!existsSync(path)) return null;
81
82
  return readFileSync(path, 'utf8');
82
83
  }
84
+
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.
89
+ */
90
+ export function resolveProjectRoot(startDir = process.cwd()) {
91
+ let dir = resolve(startDir);
92
+ while (true) {
93
+ if (existsSync(join(dir, '.claude')) || existsSync(join(dir, 'PROJECT.md'))) {
94
+ return dir;
95
+ }
96
+ const parent = dirname(dir);
97
+ if (parent === dir) {
98
+ // Reached filesystem root without finding a project
99
+ return null;
100
+ }
101
+ dir = parent;
102
+ }
103
+ }
@@ -61,6 +61,13 @@ ${data.stack}
61
61
  - ESModules en todo el codigo
62
62
  - path.join() siempre para construir paths
63
63
 
64
+ ## Subagent rules
65
+ - Guild agent roles (advisor, developer, tech-lead, etc.) are NOT Claude Code subagent_types
66
+ - Always use \`subagent_type: "general-purpose"\` when spawning agents via Task tool
67
+ - CLAUDE.md and SESSION.md changes must be committed separately from feature code
68
+ - No \`git stash\` in automated pipelines — use \`wip:\` commits instead
69
+ - Parallel agents must use git worktrees for isolation
70
+
64
71
  ## Skills disponibles
65
72
  - /guild-specialize — enriquecer CLAUDE.md explorando el proyecto real
66
73
  - /build-feature — pipeline completo de desarrollo
@@ -4,9 +4,12 @@
4
4
  * Requiere que el usuario tenga gh instalado y autenticado.
5
5
  * Todas las operaciones son no-bloqueantes — si gh no está disponible,
6
6
  * Guild funciona normalmente sin integración GitHub.
7
+ *
8
+ * Uses execFileSync with array-based arguments to prevent shell injection
9
+ * through user-controlled strings (issue titles, bodies, labels).
7
10
  */
8
11
 
9
- import { execSync } from 'child_process';
12
+ import { execFileSync } from 'node:child_process';
10
13
 
11
14
  const LABELS = [
12
15
  { name: 'backlog', color: '8E8E8E', description: 'Tarea documentada, pendiente de iniciar' },
@@ -22,7 +25,7 @@ const LABELS = [
22
25
  */
23
26
  export function isGhAvailable() {
24
27
  try {
25
- execSync('gh auth status', { stdio: 'ignore' });
28
+ execFileSync('gh', ['auth', 'status'], { stdio: 'ignore' });
26
29
  return true;
27
30
  } catch {
28
31
  return false;
@@ -43,10 +46,13 @@ export async function setupGithubLabels(repoUrl) {
43
46
 
44
47
  for (const label of LABELS) {
45
48
  try {
46
- execSync(
47
- `gh label create "${label.name}" --color "${label.color}" --description "${label.description}" --repo ${repo} --force`,
48
- { stdio: 'ignore' }
49
- );
49
+ execFileSync('gh', [
50
+ 'label', 'create', label.name,
51
+ '--color', label.color,
52
+ '--description', label.description,
53
+ '--repo', repo,
54
+ '--force',
55
+ ], { stdio: 'ignore' });
50
56
  } catch {
51
57
  // Label ya existe o error no crítico
52
58
  }
@@ -60,8 +66,14 @@ export function assignIssue(issueNumber, fromLabel, toLabel) {
60
66
  if (!isGhAvailable()) return;
61
67
 
62
68
  try {
63
- execSync(`gh issue assign ${issueNumber} --assignee @me`, { stdio: 'ignore' });
64
- execSync(`gh issue edit ${issueNumber} --add-label "${toLabel}" --remove-label "${fromLabel}"`, { stdio: 'ignore' });
69
+ execFileSync('gh', [
70
+ 'issue', 'assign', String(issueNumber), '--assignee', '@me',
71
+ ], { stdio: 'ignore' });
72
+ execFileSync('gh', [
73
+ 'issue', 'edit', String(issueNumber),
74
+ '--add-label', toLabel,
75
+ '--remove-label', fromLabel,
76
+ ], { stdio: 'ignore' });
65
77
  } catch {
66
78
  // Non-critical
67
79
  }
@@ -74,7 +86,9 @@ export function commentIssue(issueNumber, body) {
74
86
  if (!isGhAvailable()) return;
75
87
 
76
88
  try {
77
- execSync(`gh issue comment ${issueNumber} --body "${body}"`, { stdio: 'ignore' });
89
+ execFileSync('gh', [
90
+ 'issue', 'comment', String(issueNumber), '--body', body,
91
+ ], { stdio: 'ignore' });
78
92
  } catch {
79
93
  // Non-critical
80
94
  }
@@ -87,7 +101,9 @@ export function closeIssue(issueNumber, comment) {
87
101
  if (!isGhAvailable()) return;
88
102
 
89
103
  try {
90
- execSync(`gh issue close ${issueNumber} --comment "${comment}"`, { stdio: 'ignore' });
104
+ execFileSync('gh', [
105
+ 'issue', 'close', String(issueNumber), '--comment', comment,
106
+ ], { stdio: 'ignore' });
91
107
  } catch {
92
108
  // Non-critical
93
109
  }
@@ -100,10 +116,12 @@ export function createBugIssue(title, body, parentIssueNumber) {
100
116
  if (!isGhAvailable()) return null;
101
117
 
102
118
  try {
103
- const result = execSync(
104
- `gh issue create --title "${title}" --body "${body}" --label "bug"`,
105
- { encoding: 'utf8' }
106
- );
119
+ const result = execFileSync('gh', [
120
+ 'issue', 'create',
121
+ '--title', title,
122
+ '--body', body,
123
+ '--label', 'bug',
124
+ ], { encoding: 'utf8' });
107
125
  const issueUrl = result.trim();
108
126
  const issueNumber = issueUrl.split('/').pop();
109
127