@cristiancorreau/forge 2.1.0
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 +228 -0
- package/LICENSE +191 -0
- package/README.md +156 -0
- package/assets/adapters/claude-code/commands/deploy-check.md +12 -0
- package/assets/adapters/claude-code/commands/new-feature.md +11 -0
- package/assets/adapters/claude-code/commands/plan.md +116 -0
- package/assets/adapters/claude-code/commands/review.md +219 -0
- package/assets/adapters/claude-code/commands/session-close.md +109 -0
- package/assets/adapters/claude-code/commands/session-start.md +59 -0
- package/assets/adapters/claude-code/commands/ship.md +133 -0
- package/assets/adapters/claude-code/commands/wiki-ingest.md +7 -0
- package/assets/adapters/claude-code/commands/wiki-lint.md +5 -0
- package/assets/adapters/claude-code/commands/wiki-query.md +7 -0
- package/assets/adapters/claude-code/commands/work.md +101 -0
- package/assets/adapters/claude-code/generate-claude-md.py +304 -0
- package/assets/adapters/codex/commands/plan.md +63 -0
- package/assets/adapters/codex/commands/review.md +53 -0
- package/assets/adapters/codex/commands/session-close.md +53 -0
- package/assets/adapters/codex/commands/session-start.md +49 -0
- package/assets/adapters/codex/commands/ship.md +53 -0
- package/assets/adapters/codex/commands/work.md +53 -0
- package/assets/adapters/codex/generate-codex-config.py +269 -0
- package/assets/adapters/codex/hooks/codex.yaml.tpl +43 -0
- package/assets/adapters/codex/hooks/forge-codex-finish.sh +158 -0
- package/assets/adapters/codex/hooks/forge-codex-start.sh +186 -0
- package/assets/adapters/kiro/generate-steering.py +367 -0
- package/assets/adapters/opencode/HOOKS.md +123 -0
- package/assets/adapters/opencode/commands/plan.md +119 -0
- package/assets/adapters/opencode/commands/review.md +164 -0
- package/assets/adapters/opencode/commands/session-close.md +111 -0
- package/assets/adapters/opencode/commands/session-start.md +62 -0
- package/assets/adapters/opencode/commands/ship.md +135 -0
- package/assets/adapters/opencode/commands/work.md +82 -0
- package/assets/adapters/opencode/generate-agents-md.py +262 -0
- package/assets/core/agents/backend-engineer.md +61 -0
- package/assets/core/agents/compliance-reviewer.md +83 -0
- package/assets/core/agents/docs-writer.md +77 -0
- package/assets/core/agents/frontend-engineer.md +70 -0
- package/assets/core/agents/orchestrator.md +104 -0
- package/assets/core/agents/security-auditor.md +54 -0
- package/assets/core/agents/test-engineer.md +57 -0
- package/assets/core/hooks/hooks-registry.yaml +48 -0
- package/assets/core/hooks/post-turn-check.sh +139 -0
- package/assets/core/hooks/pre-bash-check.py +202 -0
- package/assets/core/hooks/pre-edit-check.py +317 -0
- package/assets/core/hooks/session-start.sh +184 -0
- package/assets/core/schemas/project.schema.json +503 -0
- package/assets/core/skills/README.md +88 -0
- package/assets/core/skills/aitmpl-search/SKILL.md +74 -0
- package/assets/core/skills/browser-test/SKILL.md +177 -0
- package/assets/core/skills/db-migrate/SKILL.md +163 -0
- package/assets/core/skills/local2prod/SKILL.md +147 -0
- package/assets/core/skills/new-feature/SKILL.md +155 -0
- package/assets/core/skills/obsidian-sync/SKILL.md +152 -0
- package/assets/core/skills/phase-kickoff/SKILL.md +69 -0
- package/assets/core/skills/security-audit/SKILL.md +125 -0
- package/assets/core/skills/spec/SKILL.md +72 -0
- package/assets/core/skills/wiki-ingest/SKILL.md +183 -0
- package/assets/core/skills/wiki-lint/SKILL.md +109 -0
- package/assets/core/skills/wiki-query/SKILL.md +100 -0
- package/assets/core/templates/claude-md/architecture.rules +20 -0
- package/assets/core/templates/claude-md/global.md +30 -0
- package/assets/core/templates/claude-md/project.md +36 -0
- package/assets/core/templates/daily-note.md +38 -0
- package/assets/core/templates/spec-template.md +43 -0
- package/assets/core/workflows/sdd.md +69 -0
- package/assets/core/workflows/sprint.md +59 -0
- package/assets/forge.py +1265 -0
- package/assets/hooks/pre-commit +43 -0
- package/assets/manifest.json +274 -0
- package/assets/profiles/astro/README.md +24 -0
- package/assets/profiles/astro/agents/frontend-engineer.md +74 -0
- package/assets/profiles/django/agents/api-engineer.md +83 -0
- package/assets/profiles/expo/README.md +24 -0
- package/assets/profiles/expo/agents/mobile-engineer.md +69 -0
- package/assets/profiles/express/agents/api-engineer.md +60 -0
- package/assets/profiles/fastapi/README.md +32 -0
- package/assets/profiles/fastapi/agents/api-engineer.md +87 -0
- package/assets/profiles/go-gin/agents/api-engineer.md +98 -0
- package/assets/profiles/hono-drizzle/README.md +31 -0
- package/assets/profiles/hono-drizzle/agents/api-engineer.md +82 -0
- package/assets/profiles/laravel/README.md +32 -0
- package/assets/profiles/laravel/agents/api-engineer.md +114 -0
- package/assets/profiles/laravel/agents/fullstack-engineer.md +67 -0
- package/assets/profiles/laravel/agents/migration-specialist.md +420 -0
- package/assets/profiles/nestjs/agents/api-engineer.md +79 -0
- package/assets/profiles/nextjs-admin/README.md +32 -0
- package/assets/profiles/nextjs-admin/agents/admin-engineer.md +78 -0
- package/assets/profiles/playwright-crawler/agents/scanner-engineer.md +51 -0
- package/assets/profiles/rails/agents/fullstack-engineer.md +61 -0
- package/assets/profiles/sveltekit/agents/frontend-engineer.md +96 -0
- package/assets/profiles/vuenuxt/agents/frontend-engineer.md +82 -0
- package/assets/profiles/wordpress/README.md +30 -0
- package/assets/profiles/wordpress/agents/divi-engineer.md +273 -0
- package/assets/profiles/wordpress/agents/elementor-engineer.md +310 -0
- package/assets/profiles/wordpress/agents/wp-engineer.md +216 -0
- package/assets/requirements.txt +2 -0
- package/assets/scripts/aitmpl-search.py +808 -0
- package/assets/scripts/forge-add-opportunities.py +92 -0
- package/assets/scripts/forge-audit.py +1061 -0
- package/assets/scripts/forge-generate-all.py +283 -0
- package/assets/scripts/forge-init.py +900 -0
- package/assets/scripts/forge-migrate-project-yaml.py +397 -0
- package/assets/scripts/forge-scaffold-profile.py +181 -0
- package/assets/scripts/forge-teardown.py +193 -0
- package/assets/scripts/forge-validate-project-yaml.py +457 -0
- package/assets/scripts/forge-wizard.py +1003 -0
- package/assets/scripts/setup-codex.sh +229 -0
- package/assets/scripts/team-install.sh +147 -0
- package/assets/scripts/token-stats.py +201 -0
- package/assets/templates/modes/enterprise.yaml.tpl +114 -0
- package/assets/templates/modes/multi-runtime.yaml.tpl +89 -0
- package/assets/templates/modes/new-stack.yaml.tpl +101 -0
- package/assets/templates/modes/startup.yaml.tpl +74 -0
- package/assets/templates/project.yaml.tpl +185 -0
- package/assets/templates/wiki/concepts/_template.md +22 -0
- package/assets/templates/wiki/entities/_template.md +19 -0
- package/assets/templates/wiki/index.md +32 -0
- package/assets/templates/wiki/log.md +6 -0
- package/assets/templates/wiki/sources/_template.md +25 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +64 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/audit.d.ts +2 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +21 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +58 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +27 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +22 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +20 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/lib/paths.d.ts +10 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +49 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/python.d.ts +4 -0
- package/dist/lib/python.d.ts.map +1 -0
- package/dist/lib/python.js +46 -0
- package/dist/lib/python.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Skill: obsidian-sync
|
|
2
|
+
|
|
3
|
+
Mantiene un vault de Obsidian sincronizado con el código del proyecto.
|
|
4
|
+
Skill de integración — requiere Obsidian corriendo localmente con el plugin Local REST API.
|
|
5
|
+
|
|
6
|
+
Triggers: /obsidian-sync, "actualizar obsidian", "sync vault", "documentar cambios",
|
|
7
|
+
"nota diaria", "actualizar docs", "actualizar vault".
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Prerequisitos
|
|
12
|
+
|
|
13
|
+
1. **Obsidian corriendo** con el plugin "Local REST API" activo.
|
|
14
|
+
2. **Token configurado** — en `.env.local` o en `settings.local.json`:
|
|
15
|
+
```
|
|
16
|
+
OBSIDIAN_TOKEN=<tu-token>
|
|
17
|
+
OBSIDIAN_API=http://127.0.0.1:27123
|
|
18
|
+
```
|
|
19
|
+
3. **Vault path configurado** en `project.yaml`:
|
|
20
|
+
```yaml
|
|
21
|
+
integrations:
|
|
22
|
+
obsidian:
|
|
23
|
+
vault_path: "docs/mi-vault" # relativo a la raíz del proyecto
|
|
24
|
+
map: # área modificada → nota del vault a actualizar
|
|
25
|
+
api: "03-api/endpoints.md"
|
|
26
|
+
database: "02-base-de-datos/migraciones.md"
|
|
27
|
+
frontend: "01-arquitectura/componentes.md"
|
|
28
|
+
deploy: "06-deploy/ci-cd.md"
|
|
29
|
+
decisions: "08-decisiones/log-decisiones.md"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Comandos MCP del plugin Local REST API
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
TOKEN=$OBSIDIAN_TOKEN
|
|
38
|
+
API=http://127.0.0.1:27123
|
|
39
|
+
|
|
40
|
+
# Leer una nota
|
|
41
|
+
curl -s -H "Authorization: Bearer $TOKEN" "$API/vault/<ruta-nota>.md"
|
|
42
|
+
|
|
43
|
+
# Reemplazar una nota completa (PUT)
|
|
44
|
+
curl -X PUT \
|
|
45
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
46
|
+
-H "Content-Type: text/markdown" \
|
|
47
|
+
--data-binary "contenido" \
|
|
48
|
+
"$API/vault/<ruta-nota>.md"
|
|
49
|
+
|
|
50
|
+
# Agregar al final de una nota (PATCH)
|
|
51
|
+
curl -X PATCH \
|
|
52
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
53
|
+
-H "Content-Type: text/markdown" \
|
|
54
|
+
--data-binary "\n## Nuevo contenido" \
|
|
55
|
+
"$API/vault/<ruta-nota>.md"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Flujo de sync
|
|
61
|
+
|
|
62
|
+
### 1. Identificar qué cambió
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git log --oneline --since="today" 2>/dev/null || git log --oneline -5
|
|
66
|
+
git diff --name-only HEAD~1 HEAD
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. Mapear cambios → notas del vault
|
|
70
|
+
|
|
71
|
+
Usar el mapa configurado en `project.yaml` (`integrations.obsidian.map`).
|
|
72
|
+
Si no hay mapa configurado, usar criterio propio:
|
|
73
|
+
|
|
74
|
+
| Tipo de cambio | Nota típica a actualizar |
|
|
75
|
+
|---------------|--------------------------|
|
|
76
|
+
| Nuevos endpoints de API | sección de API del vault |
|
|
77
|
+
| Cambios en schema de BD | sección de base de datos / migraciones |
|
|
78
|
+
| Nuevas páginas o componentes | sección de arquitectura / UI |
|
|
79
|
+
| Deploy / infra | sección de deploy / CI-CD |
|
|
80
|
+
| Decisión de arquitectura | log de decisiones / ADRs |
|
|
81
|
+
|
|
82
|
+
### 3. Leer nota actual → actualizar → verificar
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# 1. Leer estado actual
|
|
86
|
+
curl -s -H "Authorization: Bearer $TOKEN" "$API/vault/<ruta>.md"
|
|
87
|
+
|
|
88
|
+
# 2. Preparar contenido actualizado (mantener lo que ya había, agregar lo nuevo)
|
|
89
|
+
|
|
90
|
+
# 3. Escribir con PUT o PATCH según si reemplaza o agrega
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 4. Crear o actualizar nota diaria
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
DATE=$(date +%Y-%m-%d)
|
|
97
|
+
curl -X PUT \
|
|
98
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
99
|
+
-H "Content-Type: text/markdown" \
|
|
100
|
+
--data-binary "# $DATE
|
|
101
|
+
|
|
102
|
+
## Implementado
|
|
103
|
+
- [listar cambios del día]
|
|
104
|
+
|
|
105
|
+
## Archivos modificados
|
|
106
|
+
$(git diff --name-only HEAD~1 HEAD | sed 's/^/- /')
|
|
107
|
+
|
|
108
|
+
## Commits
|
|
109
|
+
$(git log --oneline --since="today")
|
|
110
|
+
|
|
111
|
+
## Decisiones
|
|
112
|
+
- [si se tomó alguna decisión de arquitectura]
|
|
113
|
+
|
|
114
|
+
## Pendiente
|
|
115
|
+
- [si quedó algo sin terminar]
|
|
116
|
+
" \
|
|
117
|
+
"$API/vault/daily-notes/$DATE.md"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Template de ADR (para sección de decisiones)
|
|
123
|
+
|
|
124
|
+
Si la implementación implicó una decisión de arquitectura no documentada:
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
## ADR-NNN — Título de la decisión (YYYY-MM-DD)
|
|
128
|
+
|
|
129
|
+
**Contexto**: Por qué se necesitó tomar esta decisión.
|
|
130
|
+
|
|
131
|
+
**Decisión**: Qué se decidió hacer exactamente.
|
|
132
|
+
|
|
133
|
+
**Alternativas descartadas**: Qué otras opciones se evaluaron.
|
|
134
|
+
|
|
135
|
+
**Consecuencias**: Qué implica esta decisión hacia adelante.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Cuándo NO usar este skill
|
|
141
|
+
|
|
142
|
+
- Si Obsidian no está corriendo localmente → skip, no falla el flujo
|
|
143
|
+
- Si el proyecto no tiene `integrations.obsidian` en `project.yaml` → skip
|
|
144
|
+
- Si el cambio es trivial (fix de typo, cambio de style) → skip
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Relación con otros skills
|
|
149
|
+
|
|
150
|
+
- Es invocado opcionalmente por `new-feature` (Fase 6) y `local2prod` (Paso 5).
|
|
151
|
+
- Es una integración opcional — si no está configurada, los skills que la invocan la saltean.
|
|
152
|
+
- No invoca otros skills.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Skill: phase-kickoff
|
|
2
|
+
|
|
3
|
+
Protocolo para iniciar una nueva fase de desarrollo en un proyecto forge.
|
|
4
|
+
Activar al comienzo de cada sprint o fase nueva.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Cuándo usar este skill
|
|
9
|
+
|
|
10
|
+
Al iniciar trabajo en una nueva fase o sprint del proyecto.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Pasos del kickoff
|
|
15
|
+
|
|
16
|
+
### 1. Revisar el estado actual
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Ver qué está en curso y qué falta
|
|
20
|
+
cat CLAUDE.md | grep -A 10 "Phases activas"
|
|
21
|
+
ls docs/specs/
|
|
22
|
+
git log --oneline -10
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Leer specs de la fase
|
|
26
|
+
|
|
27
|
+
Para cada spec de la fase que empieza:
|
|
28
|
+
- Leer el archivo en `docs/specs/[ID]-[nombre].md`
|
|
29
|
+
- Verificar que el estado sea `APPROVED` (no `DRAFT`)
|
|
30
|
+
- Verificar que las dependencias estén implementadas
|
|
31
|
+
|
|
32
|
+
### 3. Identificar dependencias entre specs
|
|
33
|
+
|
|
34
|
+
Antes de asignar trabajo, mapear cuáles specs deben ir en qué orden:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Ejemplo:
|
|
38
|
+
A1 (schema) → A2 (consent store) → B1 (banner)
|
|
39
|
+
A1 (schema) → A3 (vendor catalog) [paralelo con A2]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 4. Spawnear el team
|
|
43
|
+
|
|
44
|
+
Con el mapa de dependencias claro:
|
|
45
|
+
- Specs sin dependencias → pueden ir en paralelo (background agents)
|
|
46
|
+
- Specs con dependencias → secuenciales o con SendMessage de coordinación
|
|
47
|
+
|
|
48
|
+
### 5. Actualizar CLAUDE.md
|
|
49
|
+
|
|
50
|
+
Al terminar la fase, actualizar la sección de "Phases activas":
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
## Phases activas y estado
|
|
54
|
+
|
|
55
|
+
- **Sprint actual:** Sprint N
|
|
56
|
+
- **Completadas:** [IDs completados]
|
|
57
|
+
- **En curso:** [IDs en progreso]
|
|
58
|
+
- **Pendientes:** [IDs pendientes]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Checklist de kickoff
|
|
64
|
+
|
|
65
|
+
- [ ] Specs de la fase leídas y en estado APPROVED
|
|
66
|
+
- [ ] Dependencias entre specs mapeadas
|
|
67
|
+
- [ ] Team spawneado con agentes apropiados
|
|
68
|
+
- [ ] CLAUDE.md actualizado con fase activa
|
|
69
|
+
- [ ] No hay specs en DRAFT sin aprobación del humano
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Skill: security-audit
|
|
2
|
+
|
|
3
|
+
Checklist de seguridad para endpoints de API y módulos que manejan autenticación,
|
|
4
|
+
autorización o datos sensibles. Agnóstico al stack.
|
|
5
|
+
|
|
6
|
+
Triggers: /security-audit, "auditar seguridad", "revisar endpoints", "security check",
|
|
7
|
+
"vulnerabilidades", "es seguro", "revisar auth".
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Cuándo usar este skill
|
|
12
|
+
|
|
13
|
+
- Al implementar nuevos endpoints de API
|
|
14
|
+
- Al modificar lógica de autenticación o autorización
|
|
15
|
+
- Antes de mergear cualquier PR que toque rutas protegidas
|
|
16
|
+
- Cuando el security-auditor lo solicita como parte de un review
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Checklist por endpoint
|
|
21
|
+
|
|
22
|
+
### 1. Autenticación — ¿quién sos?
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
✓ El token/sesión se verifica ANTES de procesar el request
|
|
26
|
+
✓ Si no hay token válido → 401 inmediato, sin procesar nada
|
|
27
|
+
✓ La verificación está en CADA método del handler (GET, POST, PUT, DELETE)
|
|
28
|
+
— no solo en el primero que se implementó
|
|
29
|
+
|
|
30
|
+
✗ NUNCA saltear auth porque "es solo GET" o "es público por diseño" sin confirmarlo
|
|
31
|
+
✗ NUNCA confiar en headers que el cliente puede modificar (X-User-Id, X-Role)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Patrón genérico:
|
|
35
|
+
```typescript
|
|
36
|
+
// Verificar antes de cualquier lógica
|
|
37
|
+
const session = await getSession(request);
|
|
38
|
+
if (!session) return Response.json({ error: 'No autenticado' }, { status: 401 });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Autorización — ¿podés hacer esto?
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
✓ Verificar que el usuario tiene el ROL requerido para la operación
|
|
45
|
+
✓ Verificar que el usuario tiene ACCESO al recurso específico (no solo al tipo)
|
|
46
|
+
✓ Las operaciones de escritura requieren más verificación que las de lectura
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Patrón genérico:
|
|
50
|
+
```typescript
|
|
51
|
+
// Rol
|
|
52
|
+
if (session.role !== 'admin') return Response.json({ error: 'Sin permiso' }, { status: 403 });
|
|
53
|
+
|
|
54
|
+
// Acceso al recurso (IDOR check — ver punto 3)
|
|
55
|
+
const resource = await db.find(id);
|
|
56
|
+
if (resource.ownerId !== session.userId && session.role !== 'admin') return 403;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. IDOR — Insecure Direct Object Reference
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
✓ Al acceder por ID, verificar que el recurso pertenece al usuario (o que tiene permiso)
|
|
63
|
+
✓ No asumir que si el ID es "difícil de adivinar" está protegido
|
|
64
|
+
✓ Siempre cargar el recurso de la BD y verificar ownership antes de operar
|
|
65
|
+
|
|
66
|
+
Patrón de riesgo:
|
|
67
|
+
GET /api/documents/:id → devuelve el doc sin verificar si es del usuario
|
|
68
|
+
DELETE /api/comments/:id → borra sin verificar ownership
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 4. Validación de input
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
✓ Validar tipos, longitudes y formatos antes de pasar a la BD o cualquier servicio
|
|
75
|
+
✓ Usar un schema de validación explícito (Zod, Yup, Joi, Pydantic, etc.)
|
|
76
|
+
✓ No castear el body con 'as Type' — validar explícitamente
|
|
77
|
+
✓ Parámetros preparados siempre — NUNCA interpolar input del usuario en queries SQL
|
|
78
|
+
|
|
79
|
+
✗ NUNCA: `db.query("SELECT * FROM users WHERE id = " + userId)`
|
|
80
|
+
✓ SIEMPRE: `db.query("SELECT * FROM users WHERE id = $1", [userId])`
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 5. Exposición de información
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
✓ Los errores de producción no exponen stacktraces ni mensajes internos al cliente
|
|
87
|
+
✓ No loguear PII (email, teléfono, contraseña) en stdout/logs
|
|
88
|
+
✓ Los IDs de BD no son el único control de acceso (ver IDOR)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Comandos de escaneo rápido
|
|
94
|
+
|
|
95
|
+
Adaptar el path a la estructura del proyecto:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Endpoints/handlers sin verificación de sesión:
|
|
99
|
+
grep -r "export.*function\|app\.\(get\|post\|put\|delete\)" src/routes --include="*.ts" -l | \
|
|
100
|
+
xargs grep -L "session\|auth\|token\|verify" 2>/dev/null
|
|
101
|
+
|
|
102
|
+
# Queries SQL con interpolación (peligro de inyección):
|
|
103
|
+
grep -rn "queryRaw\|query\`\|execute\`" src/ --include="*.ts" | grep -v "queryRawTyped\|drizzle"
|
|
104
|
+
|
|
105
|
+
# Input del body sin validación de schema:
|
|
106
|
+
grep -rn "req\.body\|request\.json()\|await req\.json()" src/ --include="*.ts" | \
|
|
107
|
+
grep -v "parse\|validate\|schema\|zod\|yup"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Severidades
|
|
113
|
+
|
|
114
|
+
- **CRÍTICO**: Sin auth en endpoint admin, SQL injection directa, IDOR sin verificación de ownership, RCE.
|
|
115
|
+
- **ALTO**: Bypass de autorización por rol, mass assignment, información sensible en respuestas de error.
|
|
116
|
+
- **MEDIO**: Sin rate limiting en endpoints de auth/IA, verbose errors en producción, CSRF en rutas sensibles.
|
|
117
|
+
- **BAJO**: Headers de seguridad faltantes, dependencias desactualizadas sin CVE activo, slugs permisivos.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Relación con otros skills
|
|
122
|
+
|
|
123
|
+
- Este skill es invocado por `new-feature` como parte del checklist de implementación.
|
|
124
|
+
- El agente `security-auditor` puede invocarlo en sus reviews.
|
|
125
|
+
- No depende de otros skills (es standalone).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Skill: spec
|
|
2
|
+
|
|
3
|
+
Redactar specs de features siguiendo la plantilla del framework forge.
|
|
4
|
+
Activar antes de escribir cualquier spec nueva.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Cuándo usar este skill
|
|
9
|
+
|
|
10
|
+
- Al crear una spec nueva en `docs/specs/`
|
|
11
|
+
- Al actualizar una spec existente después de cambios de implementación
|
|
12
|
+
- Al convertir un ticket/issue en una spec formal
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Plantilla obligatoria
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
# [ID] Título de la Feature
|
|
20
|
+
|
|
21
|
+
> Estado: DRAFT | REVIEW | APPROVED | IMPLEMENTED
|
|
22
|
+
> Responsable: [nombre o rol]
|
|
23
|
+
> Creada: YYYY-MM-DD | Actualizada: YYYY-MM-DD
|
|
24
|
+
|
|
25
|
+
## Contexto
|
|
26
|
+
|
|
27
|
+
Por qué existe esta feature. Qué problema resuelve. Qué pasa si no la hacemos.
|
|
28
|
+
|
|
29
|
+
## Decisión
|
|
30
|
+
|
|
31
|
+
Qué vamos a implementar exactamente. Ser específico: endpoints, tablas, componentes.
|
|
32
|
+
|
|
33
|
+
## Alternativas consideradas
|
|
34
|
+
|
|
35
|
+
| Opción | Pros | Contras | Descartada por |
|
|
36
|
+
|--------|------|---------|----------------|
|
|
37
|
+
| Opción A | ... | ... | ... |
|
|
38
|
+
| Opción B | ... | ... | ... |
|
|
39
|
+
|
|
40
|
+
## Criterios de aceptación
|
|
41
|
+
|
|
42
|
+
- [ ] Criterio verificable 1
|
|
43
|
+
- [ ] Criterio verificable 2
|
|
44
|
+
- [ ] Criterio verificable N
|
|
45
|
+
|
|
46
|
+
## Impacto de compliance
|
|
47
|
+
|
|
48
|
+
Si el proyecto tiene `compliance.frameworks` configurado, completar:
|
|
49
|
+
|
|
50
|
+
- **Ley 21.719**: art. X → [descripción del impacto]
|
|
51
|
+
- **GDPR**: Art. Y → [descripción del impacto]
|
|
52
|
+
- No aplica (si no hay impacto de compliance)
|
|
53
|
+
|
|
54
|
+
## Dependencias
|
|
55
|
+
|
|
56
|
+
- Requiere que [otra spec ID] esté implementada
|
|
57
|
+
- Bloqueada por [issue/ticket]
|
|
58
|
+
|
|
59
|
+
## Notas de implementación
|
|
60
|
+
|
|
61
|
+
Cualquier decisión tomada durante la implementación que no estaba en la spec original.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Reglas al redactar specs
|
|
67
|
+
|
|
68
|
+
1. **ID único y secuencial**: `A1`, `A2`, `B1`, `C3`... La letra indica la fase/módulo.
|
|
69
|
+
2. **Una spec por feature atómica**: si no podés implementarla en un sprint, dividila.
|
|
70
|
+
3. **Criterios de aceptación verificables**: cada uno debe poder marcarse DONE sin ambigüedad.
|
|
71
|
+
4. **Sin código de implementación en la spec**: la spec describe QUÉ, no CÓMO.
|
|
72
|
+
5. **Actualizar la spec durante la implementación**: si tomás una decisión no contemplada, agregala en "Notas de implementación".
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Skill: wiki-ingest
|
|
2
|
+
|
|
3
|
+
Ingesta una fuente nueva en el wiki del proyecto. Almacena el original en `raw/`,
|
|
4
|
+
compila conocimiento en páginas wiki, actualiza el índice y registra la operación.
|
|
5
|
+
|
|
6
|
+
Triggers: /wiki-ingest, "ingestar", "agregar al wiki", "aprender de", "leer e
|
|
7
|
+
incorporar", "ingest this", "add to wiki", "incorporar este documento",
|
|
8
|
+
"guardar conocimiento de".
|
|
9
|
+
|
|
10
|
+
Argumento: URL, path a archivo, o texto pegado directamente.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Cuándo usar este skill
|
|
15
|
+
|
|
16
|
+
- Al incorporar documentación técnica, papers, specs regulatorias o decisiones de diseño
|
|
17
|
+
- Al leer código fuente de dependencias relevantes para el proyecto
|
|
18
|
+
- Al registrar una decisión de arquitectura que no está en un ADR formal
|
|
19
|
+
- Cuando el usuario dice "recordá esto" o "guardá esto en el wiki"
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Protocolo de ingest
|
|
24
|
+
|
|
25
|
+
### Paso 1 — Obtener la fuente
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Si es URL → agent-browser open <url> && agent-browser get text "article,main"
|
|
29
|
+
Si es archivo → Read(path)
|
|
30
|
+
Si es texto → usar el texto tal como está
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Paso 2 — Almacenar en raw/ (inmutable)
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Path: docs/wiki/raw/<tema>/<YYYY-MM-DD>-<slug-del-titulo>.md
|
|
37
|
+
|
|
38
|
+
Formato del archivo raw:
|
|
39
|
+
---
|
|
40
|
+
source: <url o path original>
|
|
41
|
+
date: <YYYY-MM-DD>
|
|
42
|
+
title: <título inferido>
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
<contenido tal cual, sin editar>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`raw/` es append-only — NUNCA editar ni borrar archivos existentes.
|
|
49
|
+
|
|
50
|
+
### Paso 3 — Extraer conocimiento
|
|
51
|
+
|
|
52
|
+
Leer el contenido y identificar:
|
|
53
|
+
|
|
54
|
+
1. **Entidades** — personas, proyectos, empresas, sistemas, frameworks mencionados
|
|
55
|
+
2. **Conceptos** — ideas, patrones, métodos, protocolos
|
|
56
|
+
3. **Hechos clave** — afirmaciones concretas, cifras, fechas, decisiones
|
|
57
|
+
4. **Contradicciones** — si algo contradice páginas wiki existentes
|
|
58
|
+
|
|
59
|
+
### Paso 4 — Actualizar páginas wiki
|
|
60
|
+
|
|
61
|
+
Para cada concepto identificado:
|
|
62
|
+
- Si `docs/wiki/concepts/<nombre>.md` existe → agregar sección con nueva info + citar fuente
|
|
63
|
+
- Si no existe → crear la página desde la plantilla
|
|
64
|
+
|
|
65
|
+
Para cada entidad identificada:
|
|
66
|
+
- Si `docs/wiki/entities/<nombre>.md` existe → actualizar con nueva info
|
|
67
|
+
- Si no existe → crear la página desde la plantilla
|
|
68
|
+
|
|
69
|
+
Crear siempre `docs/wiki/sources/<slug>.md` con resumen de la fuente:
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
---
|
|
73
|
+
title: <título>
|
|
74
|
+
source: <url o path>
|
|
75
|
+
ingested: <YYYY-MM-DD>
|
|
76
|
+
tags: [tag1, tag2]
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
# <título>
|
|
80
|
+
|
|
81
|
+
## Resumen
|
|
82
|
+
<2-3 párrafos con los puntos más importantes>
|
|
83
|
+
|
|
84
|
+
## Hechos clave
|
|
85
|
+
- <hecho 1>
|
|
86
|
+
- <hecho 2>
|
|
87
|
+
|
|
88
|
+
## Conceptos mencionados
|
|
89
|
+
- [[concepts/nombre]] — breve contexto
|
|
90
|
+
- [[concepts/nombre2]] — breve contexto
|
|
91
|
+
|
|
92
|
+
## Entidades mencionadas
|
|
93
|
+
- [[entities/nombre]] — rol en la fuente
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Paso 5 — Actualizar index.md y log.md
|
|
97
|
+
|
|
98
|
+
En `docs/wiki/index.md`:
|
|
99
|
+
- Agregar filas nuevas en las tablas correspondientes (concepts, entities, sources)
|
|
100
|
+
- Si la categoría no existe, crearla
|
|
101
|
+
|
|
102
|
+
En `docs/wiki/log.md` (append-only — NUNCA editar entradas anteriores):
|
|
103
|
+
|
|
104
|
+
```markdown
|
|
105
|
+
## [<YYYY-MM-DD>] ingest | <título de la fuente>
|
|
106
|
+
|
|
107
|
+
- **Fuente**: <url o path>
|
|
108
|
+
- **Páginas creadas**: [[concepts/X]], [[entities/Y]], [[sources/Z]]
|
|
109
|
+
- **Páginas actualizadas**: [[concepts/W]]
|
|
110
|
+
- **Contradicciones detectadas**: <si hay alguna, describirla>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Formato de páginas wiki
|
|
116
|
+
|
|
117
|
+
### concepts/<nombre>.md
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
---
|
|
121
|
+
title: Nombre del Concepto
|
|
122
|
+
tags: [tag1, tag2]
|
|
123
|
+
sources: [[[sources/fuente1]], [[sources/fuente2]]]
|
|
124
|
+
updated: YYYY-MM-DD
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
# Nombre del Concepto
|
|
128
|
+
|
|
129
|
+
Definición en 1-2 oraciones.
|
|
130
|
+
|
|
131
|
+
## Detalles
|
|
132
|
+
|
|
133
|
+
Desarrollo del concepto. Cross-referencias con [[concepts/otro]] o [[entities/entidad]].
|
|
134
|
+
|
|
135
|
+
## En este proyecto
|
|
136
|
+
|
|
137
|
+
Cómo aplica específicamente al proyecto actual.
|
|
138
|
+
|
|
139
|
+
## Fuentes
|
|
140
|
+
- [[sources/fuente1]] — contexto
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### entities/<nombre>.md
|
|
144
|
+
|
|
145
|
+
```markdown
|
|
146
|
+
---
|
|
147
|
+
title: Nombre de la Entidad
|
|
148
|
+
type: project | person | company | framework | api
|
|
149
|
+
tags: [tag1, tag2]
|
|
150
|
+
sources: [[[sources/fuente1]]]
|
|
151
|
+
updated: YYYY-MM-DD
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
# Nombre de la Entidad
|
|
155
|
+
|
|
156
|
+
Descripción en 1-2 oraciones.
|
|
157
|
+
|
|
158
|
+
## Relevancia para el proyecto
|
|
159
|
+
|
|
160
|
+
Por qué importa.
|
|
161
|
+
|
|
162
|
+
## Fuentes
|
|
163
|
+
- [[sources/fuente1]] — contexto
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Contradicciones
|
|
169
|
+
|
|
170
|
+
Si la nueva fuente contradice algo en el wiki:
|
|
171
|
+
|
|
172
|
+
1. Agregar en la página afectada una sección `## Contradicciones`
|
|
173
|
+
2. Describir qué fuente dice qué
|
|
174
|
+
3. Marcar cuál es la versión actual adoptada por el proyecto
|
|
175
|
+
4. Registrar en log.md
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Relación con otros skills
|
|
180
|
+
|
|
181
|
+
- `wiki-query` consume las páginas que este skill crea
|
|
182
|
+
- `wiki-lint` verifica la integridad después de un ingest
|
|
183
|
+
- `docs-writer` puede invocar wiki-ingest al documentar una decisión nueva
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Skill: wiki-lint
|
|
2
|
+
|
|
3
|
+
Verifica la integridad estructural del wiki: índice, links, huérfanos y salud
|
|
4
|
+
general. Auto-repara lo que puede; reporta lo que necesita decisión humana.
|
|
5
|
+
|
|
6
|
+
Triggers: /wiki-lint, "lint wiki", "verificar wiki", "revisar wiki", "chequear
|
|
7
|
+
wiki", "wiki health", "wiki check".
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Cuándo usar este skill
|
|
12
|
+
|
|
13
|
+
- Después de un `wiki-ingest` para verificar consistencia
|
|
14
|
+
- Periódicamente (por ejemplo, al inicio de cada sprint)
|
|
15
|
+
- Cuando se sospecha que hay links rotos o páginas huérfanas
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Checklist de linting
|
|
20
|
+
|
|
21
|
+
### 1. Integridad del índice
|
|
22
|
+
|
|
23
|
+
Leer `docs/wiki/index.md` y verificar:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
✓ Cada [[link]] del índice apunta a un archivo que existe
|
|
27
|
+
✗ Archivos en concepts/, entities/, sources/, synthesis/ que NO están en el índice
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Auto-reparar: agregar al índice los archivos que faltan (con descripción vacía marcada `TODO`).
|
|
31
|
+
|
|
32
|
+
### 2. Wikilinks rotos
|
|
33
|
+
|
|
34
|
+
Buscar en todas las páginas wiki referencias `[[ruta/nombre]]` y verificar que
|
|
35
|
+
el archivo `docs/wiki/ruta/nombre.md` existe.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
grep -rn "\[\[" docs/wiki/ --include="*.md" | grep -v "raw/"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Reportar: lista de links rotos con el archivo donde aparecen.
|
|
42
|
+
|
|
43
|
+
### 3. Páginas huérfanas
|
|
44
|
+
|
|
45
|
+
Páginas que no son referenciadas por ninguna otra página ni por el índice.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Para cada archivo en wiki/ (excluyendo index, log, raw/)
|
|
49
|
+
# verificar si su nombre aparece en algún [[link]] de otra página
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Reportar: lista de huérfanas. No auto-borrar — requiere decisión humana.
|
|
53
|
+
|
|
54
|
+
### 4. Integridad del log
|
|
55
|
+
|
|
56
|
+
Verificar que `docs/wiki/log.md` existe y tiene al menos una entrada.
|
|
57
|
+
El log es append-only — nunca modificar entradas pasadas.
|
|
58
|
+
|
|
59
|
+
Reportar si el log no ha sido actualizado en los últimos 30 días (wiki posiblemente abandonado).
|
|
60
|
+
|
|
61
|
+
### 5. Consistencia de frontmatter
|
|
62
|
+
|
|
63
|
+
Para cada página wiki (excluyendo raw/):
|
|
64
|
+
- Tiene bloque `---` con `title`, `tags`, `updated`
|
|
65
|
+
- El campo `updated` tiene formato válido `YYYY-MM-DD`
|
|
66
|
+
- El campo `sources` lista solo archivos que existen en `sources/`
|
|
67
|
+
|
|
68
|
+
Auto-reparar: agregar campos faltantes con valor `TODO`.
|
|
69
|
+
|
|
70
|
+
### 6. Raw/ inmutable
|
|
71
|
+
|
|
72
|
+
Verificar que ningún archivo en `raw/` ha sido modificado desde su ingest.
|
|
73
|
+
Comparar fecha de modificación vs fecha en frontmatter.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Formato de reporte
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
Wiki Lint — <project>
|
|
81
|
+
══════════════════════════
|
|
82
|
+
|
|
83
|
+
RESUMEN
|
|
84
|
+
<N> páginas en el wiki
|
|
85
|
+
<N> en el índice
|
|
86
|
+
<N> issues encontrados
|
|
87
|
+
|
|
88
|
+
ISSUES
|
|
89
|
+
✗ [CRÍTICO] Link roto: [[concepts/X]] en entities/Y.md — archivo no existe
|
|
90
|
+
⚠ [WARN] Huérfana: sources/fuente-vieja.md — sin referencias
|
|
91
|
+
⚠ [WARN] Falta en índice: concepts/nuevo-concepto.md
|
|
92
|
+
→ [INFO] Log sin actualizaciones en 15 días
|
|
93
|
+
|
|
94
|
+
AUTO-REPARADO
|
|
95
|
+
✓ Agregado concepts/nuevo-concepto.md al índice
|
|
96
|
+
✓ Agregado campo 'updated: TODO' a 2 páginas con frontmatter incompleto
|
|
97
|
+
|
|
98
|
+
REQUIERE ATENCIÓN MANUAL
|
|
99
|
+
• sources/fuente-vieja.md — ¿borrar o referenciar?
|
|
100
|
+
• [[concepts/X]] roto en entities/Y.md — ¿crear X o actualizar la referencia?
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Relación con otros skills
|
|
106
|
+
|
|
107
|
+
- `wiki-ingest` puede crear inconsistencias que este skill detecta
|
|
108
|
+
- `wiki-query` depende de los links que este skill verifica
|
|
109
|
+
- Sin dependencias de otros skills (es standalone)
|