ganbatte-os 0.2.41 → 0.2.42
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/.gos/README.md +2 -6
- package/.gos/agents/profiles/ganbatte-os-master.md +91 -58
- package/.gos/agents/profiles/index.json +3 -1
- package/.gos/agents/profiles/perf-optimizer.md +10 -0
- package/.gos/agents/profiles/po.md +1 -1
- package/.gos/agents/profiles/security-auditor.md +11 -0
- package/.gos/agents/profiles/sm.md +4 -4
- package/.gos/agents/profiles/squad-creator.md +2 -2
- package/.gos/config.json +23 -2
- package/.gos/docs/curation.md +8 -6
- package/.gos/docs/gos_installation_guide.md +1 -1
- package/.gos/docs/plan-distribuicao-publica.md +2 -3
- package/.gos/docs/toolchain-map.md +2 -2
- package/.gos/libraries/doc-sync-policy.md +31 -0
- package/.gos/libraries/lazy-dev-policy.md +38 -0
- package/.gos/libraries/lucide-icons-policy.md +1 -1
- package/.gos/libraries/performance-audit-playbook.md +54 -0
- package/.gos/libraries/security-audit-playbook.md +63 -0
- package/.gos/manifests/g-os-runtime-manifest.json +29 -8
- package/.gos/playbooks/plan-creation-playbook.md +3 -5
- package/.gos/prompts/01-search.md +2 -2
- package/.gos/prompts/03-tasks.md +4 -4
- package/.gos/prompts/05-reviews.md +1 -1
- package/.gos/scripts/cli/gos-cli.js +16 -0
- package/.gos/scripts/hooks/claude-stop-summary.js +0 -16
- package/.gos/scripts/integrations/check-plan.js +15 -5
- package/.gos/scripts/integrations/setup-ide-adapters.js +72 -75
- package/.gos/scripts/tools/model-router.js +122 -0
- package/.gos/skills/execute-plan/SKILL.md +37 -23
- package/.gos/skills/perf-review/SKILL.md +58 -0
- package/.gos/skills/plan-blueprint/SKILL.md +26 -26
- package/.gos/skills/plan-to-tasks/SKILL.md +4 -1
- package/.gos/skills/progress-tracker/SKILL.md +3 -3
- package/.gos/skills/registry.json +3 -4
- package/.gos/skills/security-review/SKILL.md +59 -0
- package/.gos/skills/simplify-review/SKILL.md +59 -0
- package/.gos/skills/validate-plan/SKILL.md +29 -30
- package/.gos/squads/code-quality/README.md +20 -0
- package/.gos/squads/code-quality/squad.yaml +32 -0
- package/.gos/squads/code-quality/workflows/wf-code-quality.yaml +19 -0
- package/.gos/squads/design-delivery/README.md +1 -1
- package/.gos/squads/design-delivery/squad.yaml +4 -3
- package/.gos/squads/design-delivery/workflows/wf-design-delivery.yaml +6 -6
- package/.gos/templates/planTemplate.md +14 -5
- package/.gos/templates/specTemplate.md +68 -0
- package/.gos/templates/taskTemplate.md +8 -5
- package/AGENTS.md +0 -2
- package/CLAUDE.md +25 -9
- package/GEMINI.md +3 -3
- package/LICENSE +1 -1
- package/README.md +6 -8
- package/package.json +2 -3
- package/.gos/docs/slack-notifications.md +0 -219
- package/.gos/playbooks/sprint-planner-playbook.md +0 -127
- package/.gos/scripts/hooks/post-commit-notify.js +0 -175
- package/.gos/scripts/tools/clickup-preprocess.js +0 -218
- package/.gos/scripts/tools/clickup.js +0 -1058
- package/.gos/scripts/tools/slack-notify.js +0 -271
- package/.gos/skills/clickup/SKILL.md +0 -151
- package/.gos/skills/slack-review/SKILL.md +0 -91
- package/.gos/skills/sprint-planner/SKILL.md +0 -434
- package/.gos/skills/weekly-update/CHANGELOG.md +0 -165
- package/.gos/skills/weekly-update/SKILL.md +0 -361
- package/.gos/squads/sprint-planning/agents/sprint-chief.md +0 -47
- package/.gos/squads/sprint-planning/agents/sprint-planner-agent.md +0 -43
- package/.gos/squads/sprint-planning/agents/sprint-tracker.md +0 -43
- package/.gos/squads/sprint-planning/agents/task-importer.md +0 -44
- package/.gos/squads/sprint-planning/checklists/sprint-readiness.md +0 -27
- package/.gos/squads/sprint-planning/config/config.yaml +0 -65
- package/.gos/squads/sprint-planning/data/clickup-field-mapping.yaml +0 -94
- package/.gos/squads/sprint-planning/squad.yaml +0 -52
- package/.gos/squads/sprint-planning/tasks/close-sprint.md +0 -43
- package/.gos/squads/sprint-planning/tasks/create-sprint.md +0 -42
- package/.gos/squads/sprint-planning/tasks/import-tasks.md +0 -39
- package/.gos/squads/sprint-planning/tasks/sync-status.md +0 -31
- package/.gos/squads/sprint-planning/workflows/wf-sprint-creation.yaml +0 -59
- package/.gos/squads/sprint-planning/workflows/wf-sprint-sync.yaml +0 -35
- package/.gos/templates/sprint-clickup.template.md +0 -80
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Performance Audit Playbook (G-OS)
|
|
2
|
+
|
|
3
|
+
Catálogo de otimizações para código de desenvolvimento (React/Next.js frontend + backend Supabase / Cloudflare D1/Workers). Usado por `perf-review` e pelo fechamento de `validate-plan`. Foco em ganhos algorítmicos e arquiteturais, não micro-otimização.
|
|
4
|
+
|
|
5
|
+
## Regras de manejo
|
|
6
|
+
|
|
7
|
+
- Finding só com evidência (`file:line`) + impacto concreto ("cada render da lista dispara 1+N queries") + correção. "Provavelmente lento" não é finding.
|
|
8
|
+
- Índice/materialização "por suspeita" precisa de evidência de schema/query antes de afirmar.
|
|
9
|
+
- Findings viram tasks de correção e entram no loop do pipeline.
|
|
10
|
+
|
|
11
|
+
## Categorias
|
|
12
|
+
|
|
13
|
+
### 1. N+1 e complexidade
|
|
14
|
+
- Query/fetch por item dentro de loop ou por linha de lista renderizada → batch / `in (...)` / dataloader.
|
|
15
|
+
- Varreduras aninhadas na mesma coleção; `find`/`filter` repetido em hot loop onde cabe `Map`.
|
|
16
|
+
|
|
17
|
+
### 2. Cache estratégico
|
|
18
|
+
- Computações/fetches caros idênticos repetidos por request/render → memoização no boundary certo.
|
|
19
|
+
- Sem cache HTTP / data-layer em dado estável. **Cloudflare**: Cache API / KV para dado quente; `cache-control` correto. **Supabase**: cache no edge / revalidação.
|
|
20
|
+
- **Next.js**: `revalidate`, `cache: 'force-cache'`, React Query/SWR staleTime para dado estável; evitar refetch desnecessário.
|
|
21
|
+
|
|
22
|
+
### 3. Trabalho fora do caminho crítico (item 4)
|
|
23
|
+
- Serviço/função que NÃO precisa ser realtime rodando síncrono no request → mover para **fila** (Cloudflare Queues / Supabase pg-boss/pgmq) e processar em background.
|
|
24
|
+
- Tarefas periódicas → **cron** (Cloudflare Cron Triggers / Supabase `pg_cron`).
|
|
25
|
+
- Envio de email, geração de relatório, webhooks, agregações pesadas: background, não no caminho do usuário.
|
|
26
|
+
|
|
27
|
+
### 4. Banco de dados (Supabase Postgres / Cloudflare D1)
|
|
28
|
+
- **Índices**: padrões de query (filtro por coluna, join, order by) sem índice de suporte → flag com evidência do schema.
|
|
29
|
+
- **Views / materialized views**: agregação cara repetida → materialized view + refresh agendado (cron). View para encapsular join complexo recorrente.
|
|
30
|
+
- **Paginação obrigatória**: lista sem limite → `limit`/`offset` ou keyset pagination. Consumo **mediante filtro/search** (não trazer tudo e filtrar no client).
|
|
31
|
+
- **Over-fetch**: `select *` / objeto inteiro onde IDs bastam; colunas não usadas; JSON grande enviado ao client.
|
|
32
|
+
- Query pesada em request quente → materializar / cachear / paginar.
|
|
33
|
+
- **D1**: batch de statements; evitar round-trips múltiplos; usar prepared statements reusados.
|
|
34
|
+
|
|
35
|
+
### 5. Frontend (React/Next.js)
|
|
36
|
+
- Bundle: dependência pesada para uso trivial; falta de code-splitting em rota rara; imagens/fontes não otimizadas.
|
|
37
|
+
- Render waterfalls; fetch no client para dado disponível no render (mover para server component / server-side).
|
|
38
|
+
- Memoização ausente em boundary claro; re-render em cascata.
|
|
39
|
+
- Deferir para as guidelines do projeto (react-best-practices) quando houver.
|
|
40
|
+
|
|
41
|
+
### 6. Build/CI
|
|
42
|
+
- CI lento por falta de cache; passos redundantes; suíte que poderia paralelizar.
|
|
43
|
+
|
|
44
|
+
## Formato do finding
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
### [PERF-NN] Título imperativo curto
|
|
48
|
+
- **Evidência**: `path/file.ts:142` — o padrão concreto.
|
|
49
|
+
- **Impacto**: custo pago ("cada listagem: 1+N queries", "500KB de JSON por request").
|
|
50
|
+
- **Esforço**: S | M | L (para a correção).
|
|
51
|
+
- **Correção**: técnica específica (batch, cache, fila, índice, view, paginação).
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Ordenar por leverage (impacto ÷ esforço). Findings de alto impacto viram task antes de fechar o plano.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Security Audit Playbook (G-OS)
|
|
2
|
+
|
|
3
|
+
Catálogo de vulnerabilidades conhecidas para auditar código de desenvolvimento (React, Next.js, TypeScript, Node, Deno, Supabase, Cloudflare D1/Workers). Usado por `security-review` e pelo fechamento de `validate-plan`.
|
|
4
|
+
|
|
5
|
+
## Regras de manejo
|
|
6
|
+
|
|
7
|
+
- Uma vulnerabilidade só é finding **com evidência**: `file:line` + descrição do padrão + impacto em produção + remediação. "Provavelmente tem XSS em algum lugar" não é finding.
|
|
8
|
+
- **NUNCA reproduzir valor de secret.** Referenciar só `file:line` + tipo da credencial; a correção sempre inclui rotação (secret commitado está queimado mesmo após remoção).
|
|
9
|
+
- Comportamento by-design (convenção de plataforma, decisão registrada em ADR) não é finding — salvo se a implementação adiciona risco além da convenção. ADR desatualizada vs código É finding (drift).
|
|
10
|
+
- Findings viram tasks de correção e entram no loop do `execute-plan` / correção do `validate-plan`.
|
|
11
|
+
|
|
12
|
+
## Categorias
|
|
13
|
+
|
|
14
|
+
### 1. Credenciais e secrets
|
|
15
|
+
- Chaves/tokens/senhas hardcoded no código ou em `.env` commitado.
|
|
16
|
+
- **Supabase**: `service_role` key usada no client (deve ser só server/edge). `anon` key com RLS desligado = acesso total.
|
|
17
|
+
- Secrets logados ou persistidos em stores de evento/histórico.
|
|
18
|
+
- **Cloudflare**: secrets via `wrangler secret` (não em `wrangler.toml` versionado nem `vars`).
|
|
19
|
+
- Remediação: remover, **rotacionar**, mover para secret manager / env server-side.
|
|
20
|
+
|
|
21
|
+
### 2. Dados cruzando para interpretadores
|
|
22
|
+
- **SQL injection**: query montada com string de request (Postgres/D1). Usar parâmetros/prepared statements.
|
|
23
|
+
- **Command injection**: shell montado com input.
|
|
24
|
+
- **XSS**: `dangerouslySetInnerHTML`, `eval`, `innerHTML` com conteúdo controlado pelo usuário. Sanitizar / usar APIs seguras.
|
|
25
|
+
- **Path traversal**: path de arquivo derivado de request.
|
|
26
|
+
- **SSRF**: fetch para URL controlada pelo usuário sem allowlist.
|
|
27
|
+
|
|
28
|
+
### 3. Controle de acesso (o eixo mais crítico em Supabase)
|
|
29
|
+
- **RLS**: tabela com dado sensível e RLS **desligado** ou sem policy → qualquer `anon`/`authenticated` lê tudo. Toda tabela exposta via PostgREST precisa de RLS ligado + policy explícita por operação (select/insert/update/delete).
|
|
30
|
+
- **Policies frouxas**: `using (true)` em tabela sensível; policy que não checa `auth.uid()` / tenant / ownership (IDOR).
|
|
31
|
+
- **Edge Functions (Supabase)**: função sem verificação de JWT/authz server-side; confiar em header do client; `verify_jwt` desligado sem motivo.
|
|
32
|
+
- **Next.js**: route handler / server action sem checagem de identidade server-side; autorização só no client; middleware que não cobre a rota.
|
|
33
|
+
- **Cloudflare Workers**: endpoint mutável sem auth; falta de checagem de origem.
|
|
34
|
+
- **CSRF**: rota que muda estado sem checagem de autenticidade.
|
|
35
|
+
|
|
36
|
+
### 4. Contratos de entrada
|
|
37
|
+
- Boundary de API que confia no body sem validação de schema (usar **Zod** front + back — validação no client não substitui a do server).
|
|
38
|
+
- Upload de arquivo sem restrição de tipo/tamanho/armazenamento.
|
|
39
|
+
- Mass assignment: atribuição ampla de objeto do request para modelo de persistência.
|
|
40
|
+
|
|
41
|
+
### 5. Configuração de produção
|
|
42
|
+
- CORS amplo (`*`) com credenciais permitidas.
|
|
43
|
+
- Headers de segurança ausentes (CSP) em superfícies sensíveis; cookies sem `HttpOnly`/`Secure`/`SameSite`.
|
|
44
|
+
- Debug/verbose habilitado em produção; stack trace vazando para o client.
|
|
45
|
+
- **Supabase**: bucket de Storage público quando deveria ser privado; policy de Storage ausente.
|
|
46
|
+
|
|
47
|
+
### 6. Dependências
|
|
48
|
+
- Rodar o audit do ecossistema em modo read-only: `npm audit` / `pnpm audit` / `deno info`. Reportar só advisories critical/high que afetam código runtime alcançável.
|
|
49
|
+
|
|
50
|
+
### 7. Minimização de dados
|
|
51
|
+
- PII / dado operacional sensível em logs, em respostas de erro, ou exposto via API.
|
|
52
|
+
|
|
53
|
+
## Formato do finding
|
|
54
|
+
|
|
55
|
+
```markdown
|
|
56
|
+
### [SEC-NN] Título imperativo curto
|
|
57
|
+
- **Evidência**: `path/file.ts:123` — o que está lá (sem reproduzir secret).
|
|
58
|
+
- **Impacto**: o que um atacante consegue / o que vaza.
|
|
59
|
+
- **Severidade**: CRITICAL | HIGH | MEDIUM | LOW.
|
|
60
|
+
- **Remediação**: mudança de código/config + rotação quando aplicável.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Ordenar por severidade; CRITICAL/HIGH viram task de correção obrigatória antes de fechar o plano.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"runtime": "ganbatte-os-
|
|
2
|
+
"runtime": "ganbatte-os-development",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"description": "Runtime curado do ganbatte-os para design-to-code,
|
|
4
|
+
"description": "Runtime curado do ganbatte-os para desenvolvimento: prototipacao, design-to-code, implementacao, otimizacao e seguranca.",
|
|
5
5
|
"modules": {
|
|
6
6
|
"agents": [
|
|
7
7
|
"ganbatte-os-master",
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
"dev",
|
|
11
11
|
"sm",
|
|
12
12
|
"po",
|
|
13
|
+
"qa",
|
|
13
14
|
"devops",
|
|
14
|
-
"squad-creator"
|
|
15
|
+
"squad-creator",
|
|
16
|
+
"security-auditor",
|
|
17
|
+
"perf-optimizer"
|
|
15
18
|
],
|
|
16
19
|
"skills": [
|
|
17
20
|
"design-to-code",
|
|
@@ -21,21 +24,39 @@
|
|
|
21
24
|
"make-version-diff",
|
|
22
25
|
"component-dedup",
|
|
23
26
|
"frontend-dev",
|
|
27
|
+
"interface-design",
|
|
24
28
|
"react-best-practices",
|
|
25
29
|
"react-doctor",
|
|
26
|
-
"sprint-planner",
|
|
27
|
-
"clickup",
|
|
28
30
|
"plan-to-tasks",
|
|
29
31
|
"agent-teams",
|
|
30
32
|
"git-ssh-setup",
|
|
31
33
|
"humanizer",
|
|
32
|
-
"
|
|
34
|
+
"stack-profiler",
|
|
35
|
+
"plan-blueprint",
|
|
36
|
+
"progress-tracker",
|
|
37
|
+
"execute-plan",
|
|
38
|
+
"validate-plan",
|
|
39
|
+
"audit-screenshots",
|
|
40
|
+
"idea-intake",
|
|
41
|
+
"prd-from-intake",
|
|
42
|
+
"adr-tech-decisions",
|
|
43
|
+
"prototype-orchestrator",
|
|
44
|
+
"gos-caveman",
|
|
45
|
+
"gos-compress",
|
|
46
|
+
"figma-print-diff",
|
|
47
|
+
"ui-guardrails",
|
|
48
|
+
"cloudflare-pages-setup",
|
|
49
|
+
"typeform-form-pattern",
|
|
50
|
+
"timer-component-pattern",
|
|
51
|
+
"security-review",
|
|
52
|
+
"perf-review",
|
|
53
|
+
"simplify-review"
|
|
33
54
|
],
|
|
34
55
|
"squads": [
|
|
35
56
|
"design-delivery",
|
|
36
57
|
"design-squad",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
58
|
+
"git-operations",
|
|
59
|
+
"code-quality"
|
|
39
60
|
]
|
|
40
61
|
}
|
|
41
62
|
}
|
|
@@ -46,7 +46,6 @@ FIGMA = <url-frame>
|
|
|
46
46
|
FIGMA+ = [<url-comp>, ...] # opcional
|
|
47
47
|
INTERACOES = """<lista estruturada — obrigatório quando tela tem table-clicável/drawer/modal/popup>"""
|
|
48
48
|
NOTAS = """<prosa livre>""" # opcional
|
|
49
|
-
ASSIGNEE = <user-id> # opcional, default 112010775 (Douglas)
|
|
50
49
|
```
|
|
51
50
|
|
|
52
51
|
`gos-master` resolve no comprehension gate (não pedir ao usuário):
|
|
@@ -59,7 +58,7 @@ ASSIGNEE = <user-id> # opcional, default 112010775 (
|
|
|
59
58
|
1. Fase 1 — Mapeamento Visual & Componentização
|
|
60
59
|
1.4 Comportamentos & Overrides — `## Interações & Estados` + `## Page-level overrides` no plano
|
|
61
60
|
2. Fase 2 — Aderência à Stack (sem redefinir arquitetura)
|
|
62
|
-
2.5 Fase 2.5 — Backend gaps →
|
|
61
|
+
2.5 Fase 2.5 — Backend gaps → registro local em `## Backend pendings` + plano-irmão `PLAN-NNN-backend-<slug>` quando grande (`--skip-backend-tracking` desliga)
|
|
63
62
|
3. Fase 3 — Plano de Execução (gera tasks com `interaction_target` e `override_target` para cobrir comportamentos e overrides)
|
|
64
63
|
|
|
65
64
|
Saídas:
|
|
@@ -117,7 +116,7 @@ NOTAS = """<opcional — desvios conhecidos, contexto de QA>"""
|
|
|
117
116
|
|
|
118
117
|
Skill `validate-plan` (Opus, revisor):
|
|
119
118
|
- Para cada task em `validacao`: re-roda visual gate curto (anatomia + tokens + comportamentos), confronta `git diff --staged` vs Componentes mapeados, confere checklist da task e `interaction_target`/`override_target`. Tudo bate → auto-marca `concluido`. Falha → mantém `validacao` com nota.
|
|
120
|
-
- Para o plano: cobertura de comportamento (`## Interações & Estados`) + cobertura de overrides (`## Page-level overrides`) + checklist do plano + backend pendings
|
|
119
|
+
- Para o plano: cobertura de comportamento (`## Interações & Estados`) + cobertura de overrides (`## Page-level overrides`) + checklist do plano + backend pendings locais todos `concluido` → marca `validated_at:` no plan.md + `*progress status PLAN-NNN-<slug> concluido`. Senão → mantém em `validacao`.
|
|
121
120
|
- Tasks `bloqueada-backend` ficam intocadas — backend tem que fechar primeiro.
|
|
122
121
|
|
|
123
122
|
### 5. Push manual e fechamento
|
|
@@ -128,7 +127,7 @@ Skill `validate-plan` (Opus, revisor):
|
|
|
128
127
|
git push
|
|
129
128
|
```
|
|
130
129
|
|
|
131
|
-
Push é ato consciente do humano. Tasks `bloqueada-backend` aguardam
|
|
130
|
+
Push é ato consciente do humano. Tasks `bloqueada-backend` aguardam o pending local de backend fechar — quando isso acontece, rodar `*progress status T-NNN-NN em-andamento` (state machine valida o status local) e voltar pra etapa 4.
|
|
132
131
|
|
|
133
132
|
### 6. Commit & resumo
|
|
134
133
|
|
|
@@ -159,4 +158,3 @@ Push é ato consciente do humano. Tasks `bloqueada-backend` aguardam ClickUp fec
|
|
|
159
158
|
- `execute-plan` — executa plano com visual gate, non-blocking em backend gaps (Codex IDE, execução)
|
|
160
159
|
- `validate-plan` — valida plano pós-execute, auto-marca concluido (Opus, revisor)
|
|
161
160
|
- `progress-tracker` — gerencia `progress.txt` + state machine (incluindo `bloqueada-backend`)
|
|
162
|
-
- `clickup` — sync opcional para tracking externo (não obrigatório)
|
|
@@ -14,5 +14,5 @@ Use este prompt quando a tarefa for descobrir contexto antes de construir.
|
|
|
14
14
|
- Screenshot ou referencia visual: `design-to-code`
|
|
15
15
|
- Figma Make bruto: `figma-make-analyzer`
|
|
16
16
|
- Codigo do Stitch ou outro gerador: `make-code-triage`
|
|
17
|
-
- Planejamento
|
|
18
|
-
-
|
|
17
|
+
- Planejamento por tela: `plan-blueprint`
|
|
18
|
+
- Auditoria de seguranca/performance: `security-review`, `perf-review`
|
package/.gos/prompts/03-tasks.md
CHANGED
|
@@ -5,11 +5,11 @@ Quebre a especificacao em tarefas pequenas e ordenadas.
|
|
|
5
5
|
## Regras
|
|
6
6
|
|
|
7
7
|
- cada task deve caber em menos de um dia
|
|
8
|
-
- separar
|
|
9
|
-
- incluir criterios de aceite objetivos
|
|
8
|
+
- separar backend, frontend, UX e QA quando fizer sentido (backend-first quando houver dependencia)
|
|
9
|
+
- incluir criterios de aceite objetivos e verificaveis
|
|
10
10
|
- explicitar dependencias
|
|
11
11
|
|
|
12
12
|
## Saida esperada
|
|
13
13
|
|
|
14
|
-
- backlog pronto para `
|
|
15
|
-
-
|
|
14
|
+
- backlog pronto para `plan-to-tasks`
|
|
15
|
+
- tasks em markdown com frontmatter e criterios de aceite
|
|
@@ -8,4 +8,4 @@ Revise a entrega com foco em regressao, fidelidade ao design e prontidao para sp
|
|
|
8
8
|
- aderencia ao design/tokens
|
|
9
9
|
- acessibilidade
|
|
10
10
|
- riscos de dados mockados ou codigo Make misturado com UI final
|
|
11
|
-
-
|
|
11
|
+
- seguranca (RLS, authz, secrets) e performance (N+1, cache, paginacao) quando fizer parte do fluxo
|
|
@@ -315,6 +315,22 @@ function cmdInit(root, args) {
|
|
|
315
315
|
const gitignoreUpdated = mergeGitignore(root, manifest.gitignoreEntries || []);
|
|
316
316
|
if (gitignoreUpdated) ok('.gitignore atualizado com entradas do manifest.');
|
|
317
317
|
|
|
318
|
+
// 8b. Config de modelo por etapa (Junior executa, Senior audita)
|
|
319
|
+
try {
|
|
320
|
+
const { writeLocalDefaults, resolveAll } = require(path.join(root, '.gos', 'scripts', 'tools', 'model-router.js'));
|
|
321
|
+
const res = writeLocalDefaults(root);
|
|
322
|
+
const map = resolveAll(root);
|
|
323
|
+
if (res.created) {
|
|
324
|
+
ok('Config de modelos por etapa criada em .gos-local/models.json');
|
|
325
|
+
} else {
|
|
326
|
+
info('Config de modelos por etapa ja existe (.gos-local/models.json).');
|
|
327
|
+
}
|
|
328
|
+
info(` plan=${map.plan.model} | execute=${map.execute.model} | validate=${map.validate.model}`);
|
|
329
|
+
info(' Edite .gos-local/models.json para trocar modelo/provider por etapa.');
|
|
330
|
+
} catch (err) {
|
|
331
|
+
warn(`Nao foi possivel configurar models por etapa: ${err.message}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
318
334
|
// 9. Salvar install log
|
|
319
335
|
writeJson(installLog, {
|
|
320
336
|
version: VERSION,
|
|
@@ -122,22 +122,6 @@ function main() {
|
|
|
122
122
|
const summary = [];
|
|
123
123
|
const syncMatcher = /^(\.gos|\.claude|data|README\.md|CLAUDE\.md|AGENTS\.md|GEMINI\.md)/;
|
|
124
124
|
|
|
125
|
-
// Trigger post-commit notification if git commit was made
|
|
126
|
-
if (state.gitCommit) {
|
|
127
|
-
try {
|
|
128
|
-
execFileSync('node', [path.join(ROOT, '.gos', 'scripts', 'hooks', 'post-commit-notify.js')], {
|
|
129
|
-
cwd: ROOT,
|
|
130
|
-
encoding: 'utf8',
|
|
131
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
132
|
-
timeout: 30000,
|
|
133
|
-
})
|
|
134
|
-
summary.push('post-commit-notify OK')
|
|
135
|
-
} catch (error) {
|
|
136
|
-
const message = error.stderr || error.stdout || error.message || 'falha no post-commit'
|
|
137
|
-
summary.push(`post-commit-notify falhou (${String(message).split(/\r?\n/)[0]})`)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
125
|
if (anyPathMatches(touchedFiles, syncMatcher)) {
|
|
142
126
|
try {
|
|
143
127
|
runNpm(["run", "sync:ides"], { timeout: 180000 });
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
* Verificacoes:
|
|
14
14
|
* 1. plan.md existe e tem frontmatter YAML.
|
|
15
15
|
* 2. context.md existe.
|
|
16
|
-
* 3.
|
|
17
|
-
* 4.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* 3. spec.md existe (spec completa de desenvolvimento).
|
|
17
|
+
* 4. tasks/ existe e contem >= 1 T-NN*.md.
|
|
18
|
+
* 5. Cada T-NN*.md: head -1 == "---" E frontmatter contem `status: pendente`
|
|
19
|
+
* E `id:`, `plan_id:`, `seq:`, `title:`, E body tem `## Critérios de aceite`.
|
|
20
|
+
* 6. Nenhum T-NN*.md tem secao `## Status` no body (formato bugado legado).
|
|
20
21
|
*
|
|
21
22
|
* Exit code:
|
|
22
23
|
* 0 = plano valido, usavel pelo pipeline
|
|
@@ -43,6 +44,7 @@ const warnings = [];
|
|
|
43
44
|
|
|
44
45
|
const planFile = path.join(planDir, 'plan.md');
|
|
45
46
|
const contextFile = path.join(planDir, 'context.md');
|
|
47
|
+
const specFile = path.join(planDir, 'spec.md');
|
|
46
48
|
const tasksDir = path.join(planDir, 'tasks');
|
|
47
49
|
|
|
48
50
|
if (!fs.existsSync(planFile)) {
|
|
@@ -58,6 +60,10 @@ if (!fs.existsSync(contextFile)) {
|
|
|
58
60
|
warnings.push(`context.md ausente — recomendado, nao bloqueia`);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
if (!fs.existsSync(specFile)) {
|
|
64
|
+
errors.push(`spec.md ausente em ${planDir} — *plan deve emitir spec.md (templates/specTemplate.md)`);
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
if (!fs.existsSync(tasksDir)) {
|
|
62
68
|
errors.push(`tasks/ ausente em ${planDir} — *plan deve invocar plan-to-tasks`);
|
|
63
69
|
} else {
|
|
@@ -100,6 +106,10 @@ if (!fs.existsSync(tasksDir)) {
|
|
|
100
106
|
if (/^## Status\s*$/m.test(body)) {
|
|
101
107
|
errors.push(`${rel}: contem secao "## Status" no body (formato legado bugado) — rodar migrate-task-status.js`);
|
|
102
108
|
}
|
|
109
|
+
|
|
110
|
+
if (!/^## Crit[eé]rios de aceite/m.test(body)) {
|
|
111
|
+
errors.push(`${rel}: sem secao "## Critérios de aceite" no body — task precisa de criterios verificaveis`);
|
|
112
|
+
}
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
115
|
|
|
@@ -116,5 +126,5 @@ if (errors.length) {
|
|
|
116
126
|
|
|
117
127
|
const taskCount = fs.readdirSync(tasksDir)
|
|
118
128
|
.filter((f) => /^T-\d+.*\.md$/.test(f)).length;
|
|
119
|
-
console.log(`[check-plan] OK — ${planDir}: plan.md + context.md + ${taskCount} tasks (
|
|
129
|
+
console.log(`[check-plan] OK — ${planDir}: plan.md + context.md + spec.md + ${taskCount} tasks (frontmatter status: pendente + criterios de aceite).`);
|
|
120
130
|
process.exit(0);
|
|
@@ -26,37 +26,36 @@ function agentSlug(id) {
|
|
|
26
26
|
return id.startsWith('gos-') ? id : `gos-${id}`;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
const agentsDir = path.join(root, ide, 'agents');
|
|
45
|
-
if (fs.existsSync(agentsDir)) {
|
|
46
|
-
for (const entry of fs.readdirSync(agentsDir)) {
|
|
47
|
-
if (/^gos-gos-/.test(entry)) {
|
|
48
|
-
fs.unlinkSync(path.join(agentsDir, entry));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
29
|
+
// IDEs alvo do G-OS (adapters gerados para estas).
|
|
30
|
+
// Claude Code, Codex, Qwen, Opencode, Gemini CLI, Antigravity (.agent).
|
|
31
|
+
const TARGET_IDES = ['.claude', '.codex', '.qwen', '.opencode', '.gemini', '.agent'];
|
|
32
|
+
// Entrypoints user-facing (slash/workflow). O master roteia o resto internamente (item 10).
|
|
33
|
+
const CMD_WHITELIST = new Set(['gos-master', 'ux-design-expert']);
|
|
34
|
+
|
|
35
|
+
function removeGosPrefixed(dir) {
|
|
36
|
+
// Remove apenas entradas G-OS (prefixo gos-), preservando skills/agents/workflows
|
|
37
|
+
// proprios do usuario que coexistem no mesmo diretorio (contrato do prefixo gos-).
|
|
38
|
+
if (!fs.existsSync(dir)) return;
|
|
39
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
40
|
+
if (/^gos-/.test(entry)) {
|
|
41
|
+
fs.rmSync(path.join(dir, entry), { recursive: true, force: true });
|
|
51
42
|
}
|
|
52
43
|
}
|
|
44
|
+
}
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
function cleanupStaleAdapters() {
|
|
47
|
+
for (const ide of TARGET_IDES) {
|
|
48
|
+
removeGosPrefixed(path.join(root, ide, 'skills')); // gos-<slug>/
|
|
49
|
+
removeGosPrefixed(path.join(root, ide, 'agents')); // gos-<id>.md
|
|
50
|
+
// Commands sao namespaced sob gos/ — seguro remover o namespace inteiro.
|
|
51
|
+
const cmdGos = path.join(root, ide, 'commands', 'gos');
|
|
52
|
+
if (fs.existsSync(cmdGos)) fs.rmSync(cmdGos, { recursive: true, force: true });
|
|
59
53
|
}
|
|
54
|
+
// Antigravity: workflows dos entrypoints (gos-*) — limpar apenas os do G-OS.
|
|
55
|
+
removeGosPrefixed(path.join(root, '.agent', 'workflows'));
|
|
56
|
+
// .antigravity/ e o diretorio errado (Antigravity usa .agent/) — remover legado.
|
|
57
|
+
const legacyAntigravity = path.join(root, '.antigravity');
|
|
58
|
+
if (fs.existsSync(legacyAntigravity)) fs.rmSync(legacyAntigravity, { recursive: true, force: true });
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
function agentWrapper(agentId, target) {
|
|
@@ -131,71 +130,57 @@ function main() {
|
|
|
131
130
|
const agentProfilePath = path.join(root, '.gos', 'agents', 'profiles', agent.path);
|
|
132
131
|
const agentDesc = extractAgentDescription(agentProfilePath) || `${agent.id} agent`;
|
|
133
132
|
const aSlug = agentSlug(agent.id);
|
|
133
|
+
const safeDesc = agentDesc.replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
134
|
+
const isEntrypoint = CMD_WHITELIST.has(agent.id);
|
|
135
|
+
|
|
136
|
+
// Subagents (delegacao interna do master) — para TODOS os agents.
|
|
137
|
+
const qwenAgent = path.join(root, '.qwen', 'agents', `${aSlug}.md`);
|
|
138
|
+
const qwenAgentTarget = relativeTarget(qwenAgent, agentProfilePath);
|
|
139
|
+
writeFile(qwenAgent, `---\nname: "${aSlug}"\ndescription: "${safeDesc}"\nmodel: inherit\ntools:\n - Read\n - Glob\n - Grep\n - Bash\n - Edit\n - Write\n---\n\nFonte canonica: \`${qwenAgentTarget}\`\nLeia e siga o perfil em \`${qwenAgentTarget}\`.`);
|
|
140
|
+
|
|
141
|
+
const codexAgent = path.join(root, '.codex', 'agents', `${aSlug}.md`);
|
|
142
|
+
const codexAgentTarget = relativeTarget(codexAgent, agentProfilePath);
|
|
143
|
+
writeFile(codexAgent, `---\nname: "${aSlug}"\ndescription: "${safeDesc}"\nmodel: inherit\ntools:\n - Read\n - Glob\n - Grep\n - Bash\n - Edit\n - Write\n---\n\nFonte canonica: \`${codexAgentTarget}\`\nLeia e siga o perfil em \`${codexAgentTarget}\`.`);
|
|
144
|
+
|
|
145
|
+
// Slash commands / picker (user-facing) — APENAS entrypoints (item 10).
|
|
146
|
+
if (!isEntrypoint) continue;
|
|
134
147
|
|
|
135
|
-
// Claude commands (requires YAML frontmatter with description)
|
|
136
148
|
const claudeFile = path.join(root, '.claude', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
137
149
|
writeFile(claudeFile, claudeCommandWrapper(aSlug, agentDesc, relativeTarget(claudeFile, agentProfilePath), '', 'Claude'));
|
|
138
150
|
|
|
139
|
-
// Qwen commands (requires YAML frontmatter with description)
|
|
140
151
|
const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
141
152
|
writeFile(qwenCmd, qwenCommandWrapper(aSlug, agentDesc, relativeTarget(qwenCmd, agentProfilePath)));
|
|
142
153
|
|
|
143
|
-
// Qwen sub-agents
|
|
144
|
-
const qwenAgent = path.join(root, '.qwen', 'agents', `${aSlug}.md`);
|
|
145
|
-
const agentTarget = relativeTarget(qwenAgent, agentProfilePath);
|
|
146
|
-
const safeDesc = agentDesc.replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
147
|
-
writeFile(qwenAgent, `---\nname: "${aSlug}"\ndescription: "${safeDesc}"\nmodel: inherit\ntools:\n - Read\n - Glob\n - Grep\n - Bash\n - Edit\n - Write\n---\n\nFonte canonica: \`${agentTarget}\`\nLeia e siga o perfil em \`${agentTarget}\`.`);
|
|
148
|
-
|
|
149
|
-
// Codex commands (slash commands no Codex IDE Extension)
|
|
150
154
|
const codexCmd = path.join(root, '.codex', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
151
155
|
writeFile(codexCmd, claudeCommandWrapper(aSlug, agentDesc, relativeTarget(codexCmd, agentProfilePath), '', 'Codex'));
|
|
152
156
|
|
|
153
|
-
// Codex
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
writeFile(codexAgent, `---\nname: "${aSlug}"\ndescription: "${safeDesc}"\nmodel: inherit\ntools:\n - Read\n - Glob\n - Grep\n - Bash\n - Edit\n - Write\n---\n\nFonte canonica: \`${codexAgentTarget}\`\nLeia e siga o perfil em \`${codexAgentTarget}\`.`);
|
|
157
|
-
|
|
158
|
-
// Codex / Antigravity (.agent/) / Gemini / Opencode usam namespace plano gos-<slug> em skills/.
|
|
159
|
-
// Agents aparecem no mesmo picker se emitidos como wrapper SKILL.md em skills/.
|
|
160
|
-
for (const ide of ['.codex', '.agent', '.gemini', '.opencode']) {
|
|
157
|
+
// Codex/Opencode/Gemini/Antigravity populam o picker a partir de <ide>/skills/<slug>/SKILL.md.
|
|
158
|
+
// Emitir o entrypoint tambem como skill garante que aparece no picker de cada uma.
|
|
159
|
+
for (const ide of ['.codex', '.opencode', '.gemini', '.agent']) {
|
|
161
160
|
const ideAgentSkill = path.join(root, ide, 'skills', aSlug, 'SKILL.md');
|
|
162
161
|
writeFile(ideAgentSkill, skillWrapper(agent.id, relativeTarget(ideAgentSkill, agentProfilePath), agentDesc));
|
|
163
162
|
}
|
|
164
163
|
|
|
165
|
-
// Antigravity
|
|
166
|
-
const antigravityWorkflow = path.join(root, '.agent', 'workflows', `${
|
|
164
|
+
// Antigravity: workflow (slash command no picker) — nome prefixado gos- p/ coexistencia.
|
|
165
|
+
const antigravityWorkflow = path.join(root, '.agent', 'workflows', `${aSlug}.md`);
|
|
167
166
|
const workflowTarget = relativeTarget(antigravityWorkflow, agentProfilePath);
|
|
168
|
-
const safeAgentDesc = agentDesc.replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
169
167
|
writeFile(
|
|
170
168
|
antigravityWorkflow,
|
|
171
|
-
`---\ndescription: "${
|
|
169
|
+
`---\ndescription: "${safeDesc}"\n---\n\n# /${aSlug} (Antigravity Workflow)\n\nFonte canonica: \`${workflowTarget}\`\n\nLeia o arquivo canonico apontado em CANONICAL-SOURCE e execute as instrucoes como fonte primaria.\n\nCANONICAL-SOURCE: ${workflowTarget}\n\nArgumentos do usuario seguem o prompt do agente.`
|
|
172
170
|
);
|
|
173
171
|
}
|
|
174
172
|
|
|
173
|
+
// Skills: auto-discoveraveis (o master as invoca internamente), NAO slash commands.
|
|
175
174
|
for (const skill of skills) {
|
|
176
175
|
const skillTargetPath = skill.skillFile || skill.path;
|
|
177
176
|
const canonicalPath = path.join(root, '.gos', skillTargetPath);
|
|
178
|
-
const claudeSkill = path.join(root, '.claude', 'commands', 'gos', 'skills', `${skill.slug}.md`);
|
|
179
|
-
const codexSkill = path.join(root, '.codex', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
180
|
-
const antigravitySkill = path.join(root, '.agent', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
181
|
-
const geminiSkill = path.join(root, '.gemini', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
182
|
-
const opencodeSkill = path.join(root, '.opencode', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
183
|
-
const qwenSkill = path.join(root, '.qwen', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
184
|
-
|
|
185
|
-
const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'skills', `${skill.slug}.md`);
|
|
186
|
-
|
|
187
177
|
const skillFm = parseFrontmatter(canonicalPath);
|
|
188
178
|
const skillDesc = skillFm.description || skill.description || skill.name || skill.slug;
|
|
189
|
-
const skillArgHint = skillFm['argument-hint'] || '';
|
|
190
|
-
|
|
191
|
-
writeFile(codexSkill, skillWrapper(skill.slug, relativeTarget(codexSkill, canonicalPath), skillDesc));
|
|
192
|
-
writeFile(antigravitySkill, skillWrapper(skill.slug, relativeTarget(antigravitySkill, canonicalPath), skillDesc));
|
|
193
|
-
writeFile(geminiSkill, skillWrapper(skill.slug, relativeTarget(geminiSkill, canonicalPath), skillDesc));
|
|
194
|
-
writeFile(opencodeSkill, skillWrapper(skill.slug, relativeTarget(opencodeSkill, canonicalPath), skillDesc));
|
|
195
|
-
writeFile(qwenSkill, skillWrapper(skill.slug, relativeTarget(qwenSkill, canonicalPath), skillDesc));
|
|
196
179
|
|
|
197
|
-
|
|
198
|
-
|
|
180
|
+
for (const ide of TARGET_IDES) {
|
|
181
|
+
const t = path.join(root, ide, 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
182
|
+
writeFile(t, skillWrapper(skill.slug, relativeTarget(t, canonicalPath), skillDesc));
|
|
183
|
+
}
|
|
199
184
|
}
|
|
200
185
|
|
|
201
186
|
// Antigravity le AGENTS.md no root do workspace (ja existe no projeto).
|
|
@@ -228,11 +213,17 @@ function main() {
|
|
|
228
213
|
'Ciclo: pre-flight visual -> loop por task com state machine -> visual gate -> validacao -> humano marca concluido.',
|
|
229
214
|
'Detalhes: `../.gos/skills/execute-plan/SKILL.md`.',
|
|
230
215
|
'',
|
|
231
|
-
'##
|
|
216
|
+
'## Entrypoints (slash commands user-facing)',
|
|
217
|
+
'',
|
|
218
|
+
'Apenas 2 comandos: o master roteia o resto internamente (skills, subagents, squads).',
|
|
219
|
+
'',
|
|
220
|
+
...agents.filter((a) => CMD_WHITELIST.has(a.id)).map((agent) => `- \`/gos:agents:${agent.id}\` -> \`../.gos/agents/profiles/${agent.path}\``),
|
|
221
|
+
'',
|
|
222
|
+
'## Subagents (delegacao interna do master)',
|
|
232
223
|
'',
|
|
233
224
|
...agents.map((agent) => `- \`gos-${agent.id}\` -> \`../.gos/agents/profiles/${agent.path}\``),
|
|
234
225
|
'',
|
|
235
|
-
'## Skills curadas',
|
|
226
|
+
'## Skills curadas (auto-discoveraveis, invocadas pelo master)',
|
|
236
227
|
'',
|
|
237
228
|
'| Slug | Arquivo canonico |',
|
|
238
229
|
'|------|------------------|',
|
|
@@ -240,9 +231,10 @@ function main() {
|
|
|
240
231
|
'',
|
|
241
232
|
'## Como o Codex consome',
|
|
242
233
|
'',
|
|
243
|
-
'- Slash commands
|
|
244
|
-
'- Subagents em `.codex/agents/gos-<id>.md` ->
|
|
245
|
-
'-
|
|
234
|
+
'- Slash commands (`.codex/commands/gos/agents/`) apenas para os 2 entrypoints. O `gos-master` analisa o input e decide quais skills, agents, subagents e squads acionar.',
|
|
235
|
+
'- Subagents em `.codex/agents/gos-<id>.md` -> delegacao interna (Task tool).',
|
|
236
|
+
'- Skills em `.codex/skills/gos-<slug>/SKILL.md` -> auto-discoveraveis; o master as invoca, o usuario nao digita.',
|
|
237
|
+
'- Para comecar, digite `/gos:agents:gos-master` no picker.',
|
|
246
238
|
''
|
|
247
239
|
].join('\n');
|
|
248
240
|
writeFile(path.join(root, '.codex', 'AGENTS.md'), codexAgentsMd);
|
|
@@ -267,10 +259,14 @@ function main() {
|
|
|
267
259
|
// Evita regressoes silenciosas que ja quebraram a IDE no passado.
|
|
268
260
|
const codexFailures = [];
|
|
269
261
|
for (const agent of agents) {
|
|
262
|
+
// Subagent (delegacao) para TODOS os agents.
|
|
270
263
|
const expectedAgent = path.join(root, '.codex', 'agents', `${agentSlug(agent.id)}.md`);
|
|
271
|
-
const expectedCmd = path.join(root, '.codex', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
272
264
|
if (!fs.existsSync(expectedAgent)) codexFailures.push(expectedAgent);
|
|
273
|
-
|
|
265
|
+
// Slash command apenas para entrypoints.
|
|
266
|
+
if (CMD_WHITELIST.has(agent.id)) {
|
|
267
|
+
const expectedCmd = path.join(root, '.codex', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
268
|
+
if (!fs.existsSync(expectedCmd)) codexFailures.push(expectedCmd);
|
|
269
|
+
}
|
|
274
270
|
}
|
|
275
271
|
for (const skill of skills) {
|
|
276
272
|
const expectedSkill = path.join(root, '.codex', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
@@ -284,8 +280,9 @@ function main() {
|
|
|
284
280
|
process.exit(1);
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
|
|
288
|
-
console.log(`
|
|
283
|
+
const entrypoints = agents.filter((a) => CMD_WHITELIST.has(a.id)).length;
|
|
284
|
+
console.log(`Adapters gerados: ${entrypoints} entrypoints (slash), ${agents.length} subagents, ${skills.length} skills.`);
|
|
285
|
+
console.log(`IDEs alvo: ${TARGET_IDES.join(', ')}.`);
|
|
289
286
|
}
|
|
290
287
|
|
|
291
288
|
main();
|