@seedgrid/ai-toolkit 0.0.0-stage → 0.3.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 (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -2
  3. package/dist/adapters/claude.js +114 -0
  4. package/dist/adapters/codex.js +108 -0
  5. package/dist/adapters/index.js +17 -0
  6. package/dist/adapters/shared.js +142 -0
  7. package/dist/adapters/types.js +1 -0
  8. package/dist/cli.js +209 -0
  9. package/dist/commands/common.js +98 -0
  10. package/dist/commands/doctor.js +290 -0
  11. package/dist/commands/init.js +9 -0
  12. package/dist/commands/install.js +107 -0
  13. package/dist/commands/remove.js +54 -0
  14. package/dist/commands/review.js +127 -0
  15. package/dist/commands/selfinstall.js +63 -0
  16. package/dist/commands/status.js +73 -0
  17. package/dist/commands/update.js +8 -0
  18. package/dist/commands/validate.js +27 -0
  19. package/dist/core/apply.js +181 -0
  20. package/dist/core/blocks.js +64 -0
  21. package/dist/core/content.js +528 -0
  22. package/dist/core/env.js +40 -0
  23. package/dist/core/frontmatter.js +29 -0
  24. package/dist/core/hash.js +14 -0
  25. package/dist/core/inspect.js +51 -0
  26. package/dist/core/lock.js +124 -0
  27. package/dist/core/paths.js +65 -0
  28. package/dist/core/plan.js +242 -0
  29. package/dist/core/tools.js +62 -0
  30. package/dist/core/types.js +11 -0
  31. package/dist/core/updates.js +121 -0
  32. package/docs/arquitetura.md +80 -0
  33. package/docs/compatibilidade.md +50 -0
  34. package/docs/formato.md +155 -0
  35. package/docs/instalacao.md +105 -0
  36. package/docs/manutencao.md +115 -0
  37. package/package.json +43 -4
  38. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
  39. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
  40. package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
  41. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
  42. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
  43. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
  44. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
  45. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
  46. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
  47. package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
  48. package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
  49. package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
  50. package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
  51. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
  52. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
  53. package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
  54. package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
  55. package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
  56. package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
  57. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
  58. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
  59. package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
  60. package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
  61. package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
  62. package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
  63. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
  64. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
  65. package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
  66. package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
  67. package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
  68. package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
  69. package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
  70. package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
  71. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
  72. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
  73. package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
  74. package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
  75. package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
  76. package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
  77. package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
  78. package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
  79. package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
  80. package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
  81. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
  82. package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
  83. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
  84. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
  85. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
  86. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
  87. package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
  88. package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
  89. package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
  90. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
  91. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
  92. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
  93. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
  94. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
  95. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
  96. package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
  97. package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
  98. package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
  99. package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
  100. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
  101. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
  102. package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
  103. package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
  104. package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
  105. package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
  106. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
  107. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
  108. package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
  109. package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
  110. package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
  111. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
  112. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
  113. package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
  114. package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
  115. package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
  116. package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
  117. package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
  118. package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
  119. package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
  120. package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
  121. package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
  122. package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
  123. package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
  124. package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
  125. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
  126. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
  127. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
  128. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
  129. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
  130. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
  131. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
  132. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
  133. package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
  134. package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
  135. package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
  136. package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
  137. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
  138. package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
  139. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
  140. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
  141. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
  142. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
  143. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
  144. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
  145. package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
  146. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
  147. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
  148. package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
  149. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
  150. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
  151. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
  152. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
  153. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
  154. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
  155. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
  156. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
  157. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
  158. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
  159. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
  160. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
  161. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
  162. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
  163. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
  164. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
  165. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
  166. package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
  167. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
  168. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
  169. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
  170. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
  171. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
  172. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
  173. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
  174. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
  175. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
  176. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
  177. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
  178. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
  179. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
  180. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
  181. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
  182. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
  183. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
  184. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
  185. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
  186. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
  187. package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
  188. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
  189. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
  190. package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
  191. package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
  192. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
  193. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
  194. package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
  195. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
  196. package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
  197. package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
  198. package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
  199. package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
  200. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
  201. package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
  202. package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
  203. package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
  204. package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
  205. package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
  206. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
  207. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
  208. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
  209. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
  210. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
  211. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
  212. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
  213. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
  214. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
  215. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
  216. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
  217. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
  218. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
  219. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
  220. package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
  221. package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
  222. package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
  223. package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
  224. package/seedgridKB/SeedGrid/Versoes.md +64 -0
  225. package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
  226. package/seedgridKB/manifest.json +142 -0
package/dist/cli.js ADDED
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { parseArgs } from 'node:util';
5
+ import { EXIT_ERROR } from './commands/common.js';
6
+ import { doctorCommand } from './commands/doctor.js';
7
+ import { initCommand } from './commands/init.js';
8
+ import { removeCommand } from './commands/remove.js';
9
+ import { reviewCommand } from './commands/review.js';
10
+ import { selfInstallCommand } from './commands/selfinstall.js';
11
+ import { statusCommand } from './commands/status.js';
12
+ import { updateCommand } from './commands/update.js';
13
+ import { validateCommand } from './commands/validate.js';
14
+ import { cliVersion } from './core/env.js';
15
+ import { TOOL_NAME } from './core/lock.js';
16
+ import { ToolkitError } from './core/types.js';
17
+ import { checkLatest, confirm, isInteractive, npxCommandLine, runPublishedVersion, } from './core/updates.js';
18
+ const HELP = `seedgrid-ai — instala o SeedGrid AI Toolkit em projetos locais (Claude Code e Codex)
19
+
20
+ Comandos:
21
+ install Instala o comando seedgrid-ai nesta máquina (npm install -g), para usar sem npx; não altera nenhum projeto
22
+ init Instala o toolkit (regras, papéis, skills, base de conhecimento) no projeto; idempotente
23
+ update Leva o projeto ao conteúdo da versão do CLI em execução (use npx @seedgrid/ai-toolkit@latest para a mais nova)
24
+ status Mostra versões, opções e divergências da instalação
25
+ doctor Diagnostica sintaxe, consistência e limitações; --probe confirma a descoberta real no Codex
26
+ remove Remove só o que o toolkit instalou e continua intacto
27
+ validate Valida uma fonte de conteúdo (manifesto, papéis, skills, KB) sem tocar em projetos
28
+ review Confere o código contra os padrões SeedGrid, chamando a skill seedgrid-review no Claude Code ou no Codex
29
+ help Mostra esta ajuda
30
+
31
+ Uso:
32
+ seedgrid-ai install [--dry-run]
33
+ seedgrid-ai init [--target claude|codex|both] [--mode shared|native] [--source <pasta>] [--dry-run]
34
+ seedgrid-ai update [--target ...] [--mode ...] [--source <pasta>] [--dry-run]
35
+ seedgrid-ai status
36
+ seedgrid-ai doctor [--probe]
37
+ seedgrid-ai remove [--dry-run]
38
+ seedgrid-ai validate [--source <pasta>]
39
+ seedgrid-ai review [front|back] [--tool claude|codex] [--full]
40
+
41
+ Opções comuns:
42
+ --project <caminho> Projeto alvo (padrão: pasta atual)
43
+ --json Saída JSON para scripts
44
+ --dry-run Mostra o plano sem escrever nenhum arquivo
45
+ --probe (doctor) Confirma a descoberta real onde a ferramenta oferece sonda local
46
+ (Codex: codex debug prompt-input; não chama o modelo, mas inicia a CLI com sua configuração)
47
+ --tool, --full (review) Ferramenta que executa a revisão (padrão: Claude Code, depois Codex) e revisão do projeto inteiro
48
+ (padrão: só os arquivos alterados). Chama o modelo da ferramenta com o seu login e consome tokens;
49
+ roda em modo somente leitura. Código de saída 3 quando há violações.
50
+ --no-update-check Não consulta o npm por versões mais novas (também: SEEDGRID_AI_NO_UPDATE_CHECK=1)
51
+ --version, --help
52
+
53
+ Primeira vez: npx @seedgrid/ai-toolkit@latest install (depois use seedgrid-ai init, update, ... sem npx)
54
+ Padrões do init: --target both --mode shared (ou as opções do lock existente).
55
+ Em terminal interativo, init/update/status perguntam se devem usar uma versão mais nova publicada no npm.
56
+ Conflitos abortam a operação inteira (código de saída 2); nada é sobrescrito.`;
57
+ const COMMANDS = {
58
+ install: { handler: selfInstallCommand, allowed: ['dry-run'] },
59
+ init: { handler: initCommand, allowed: ['target', 'mode', 'source', 'dry-run'] },
60
+ update: { handler: updateCommand, allowed: ['target', 'mode', 'source', 'dry-run'] },
61
+ status: { handler: statusCommand, allowed: [] },
62
+ doctor: { handler: doctorCommand, allowed: ['probe'] },
63
+ remove: { handler: removeCommand, allowed: ['dry-run'] },
64
+ validate: { handler: validateCommand, allowed: ['source'] },
65
+ review: { handler: reviewCommand, allowed: ['tool', 'full'] },
66
+ };
67
+ export async function main(argv) {
68
+ let parsed;
69
+ try {
70
+ parsed = parseArgs({
71
+ args: argv,
72
+ allowPositionals: true,
73
+ strict: true,
74
+ options: {
75
+ target: { type: 'string' },
76
+ mode: { type: 'string' },
77
+ source: { type: 'string' },
78
+ project: { type: 'string' },
79
+ 'dry-run': { type: 'boolean' },
80
+ json: { type: 'boolean' },
81
+ probe: { type: 'boolean' },
82
+ tool: { type: 'string' },
83
+ full: { type: 'boolean' },
84
+ 'no-update-check': { type: 'boolean' },
85
+ help: { type: 'boolean', short: 'h' },
86
+ version: { type: 'boolean', short: 'v' },
87
+ },
88
+ });
89
+ }
90
+ catch (err) {
91
+ console.error(`${err.message}\n\n${HELP}`);
92
+ return EXIT_ERROR;
93
+ }
94
+ const { values, positionals } = parsed;
95
+ if (values.version) {
96
+ console.log(cliVersion());
97
+ return 0;
98
+ }
99
+ const name = positionals[0];
100
+ if (values.help || !name || name === 'help') {
101
+ console.log(HELP);
102
+ return 0;
103
+ }
104
+ const command = COMMANDS[name];
105
+ const maxPositionals = name === 'review' ? 2 : 1;
106
+ if (!command || positionals.length > maxPositionals) {
107
+ console.error(`Comando desconhecido: ${positionals.join(' ')}\n\n${HELP}`);
108
+ return EXIT_ERROR;
109
+ }
110
+ for (const opt of ['target', 'mode', 'source', 'dry-run', 'probe', 'tool', 'full']) {
111
+ if (values[opt] !== undefined && !command.allowed.includes(opt)) {
112
+ console.error(`A opção --${opt} não se aplica ao comando ${name}.`);
113
+ return EXIT_ERROR;
114
+ }
115
+ }
116
+ const opts = {
117
+ project: values.project,
118
+ source: values.source,
119
+ target: values.target,
120
+ mode: values.mode,
121
+ dryRun: values['dry-run'] ?? false,
122
+ json: values.json ?? false,
123
+ probe: values.probe ?? false,
124
+ scope: name === 'review' ? positionals[1] : undefined,
125
+ tool: values.tool,
126
+ full: values.full ?? false,
127
+ };
128
+ // Consulta somente leitura ao npm; nunca com --source (conteúdo local em teste).
129
+ const checkUpdates = ['init', 'update', 'status', 'doctor'].includes(name) && !values['no-update-check'] && !opts.source;
130
+ const update = checkUpdates ? await checkLatest(cliVersion()) : null;
131
+ const newer = update?.newer ? update : null;
132
+ const canAsk = newer !== null && isInteractive() && !opts.json;
133
+ try {
134
+ if (newer && (name === 'init' || name === 'update')) {
135
+ if (canAsk) {
136
+ console.log(`Versão ${newer.latest} do SeedGrid AI Toolkit disponível (este CLI: ${newer.current}).`);
137
+ if (await confirm(`Usar a ${newer.latest} neste ${name}?`))
138
+ return delegate(newer, argv);
139
+ }
140
+ else if (!opts.json) {
141
+ console.error(updateNotice(newer, argv));
142
+ }
143
+ }
144
+ const result = await command.handler(opts);
145
+ if (newer)
146
+ result.report.npm = { latest: newer.latest, newer: true };
147
+ if (opts.json)
148
+ console.log(JSON.stringify(result.report, null, 2));
149
+ else
150
+ console.log(result.lines.join('\n'));
151
+ if (newer && (name === 'status' || name === 'doctor') && !opts.json) {
152
+ const installed = result.report.installed === true;
153
+ const followUp = [installed ? 'update' : 'init', '--project', String(result.report.project)];
154
+ console.log('');
155
+ if (canAsk && name === 'status' && installed) {
156
+ console.log(`Versão ${newer.latest} do SeedGrid AI Toolkit disponível (este CLI: ${newer.current}).`);
157
+ if (await confirm('Atualizar este projeto agora?'))
158
+ return delegate(newer, followUp);
159
+ }
160
+ else {
161
+ console.log(updateNotice(newer, followUp));
162
+ }
163
+ }
164
+ return result.exitCode;
165
+ }
166
+ catch (err) {
167
+ const isKnown = err instanceof ToolkitError;
168
+ const details = isKnown ? err.details : [];
169
+ if (opts.json) {
170
+ console.log(JSON.stringify({ command: name, error: err.message, details }, null, 2));
171
+ }
172
+ else {
173
+ console.error(`ERRO: ${err.message}`);
174
+ for (const d of details)
175
+ console.error(` - ${d}`);
176
+ if (!isKnown)
177
+ console.error(err.stack);
178
+ }
179
+ return EXIT_ERROR;
180
+ }
181
+ }
182
+ function updateNotice(info, args) {
183
+ return `Aviso: versão ${info.latest} disponível no npm (este CLI: ${info.current}). Para usá-la: ${npxCommandLine(info.latest, args)}. Para atualizar o comando seedgrid-ai instalado na máquina: npx ${TOOL_NAME}@latest install`;
184
+ }
185
+ /** Repassa o comando para a versão publicada mais nova. */
186
+ async function delegate(info, args) {
187
+ console.log(`> ${npxCommandLine(info.latest, args)}`);
188
+ const code = await runPublishedVersion(info.latest, args);
189
+ if (code === null) {
190
+ console.error('Os argumentos contêm caracteres que não podem ser repassados com segurança. Rode o comando acima manualmente.');
191
+ return EXIT_ERROR;
192
+ }
193
+ return code;
194
+ }
195
+ function invokedDirectly() {
196
+ if (!process.argv[1])
197
+ return false;
198
+ try {
199
+ return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
200
+ }
201
+ catch {
202
+ return false;
203
+ }
204
+ }
205
+ if (invokedDirectly()) {
206
+ main(process.argv.slice(2)).then((code) => {
207
+ process.exitCode = code;
208
+ });
209
+ }
@@ -0,0 +1,98 @@
1
+ import path from 'node:path';
2
+ import { isInside, toPosix } from '../core/paths.js';
3
+ import { ALL_MODES, ToolkitError } from '../core/types.js';
4
+ export const EXIT_OK = 0;
5
+ export const EXIT_ERROR = 1;
6
+ export const EXIT_CONFLICT = 2;
7
+ /** review: a revisão terminou e encontrou violações. */
8
+ export const EXIT_VIOLATIONS = 3;
9
+ export function parseTargets(value) {
10
+ if (value === undefined)
11
+ return undefined;
12
+ if (value === 'both')
13
+ return ['claude', 'codex'];
14
+ if (value === 'claude' || value === 'codex')
15
+ return [value];
16
+ throw new ToolkitError(`--target inválido: ${value} (use claude, codex ou both)`);
17
+ }
18
+ export function parseMode(value) {
19
+ if (value === undefined)
20
+ return undefined;
21
+ if (ALL_MODES.includes(value))
22
+ return value;
23
+ throw new ToolkitError(`--mode inválido: ${value} (use shared ou native)`);
24
+ }
25
+ /** Caminho relativo portável da fonte local, apenas se estiver dentro do projeto. */
26
+ export function sourceRelPath(projectRoot, sourceDir) {
27
+ if (!isInside(projectRoot, sourceDir) || sourceDir === projectRoot)
28
+ return undefined;
29
+ return toPosix(path.relative(projectRoot, sourceDir));
30
+ }
31
+ const FILE_LABELS = {
32
+ create: 'criar',
33
+ update: 'atualizar',
34
+ unchanged: 'sem mudança',
35
+ adopt: 'adotar',
36
+ delete: 'remover',
37
+ forget: 'esquecer',
38
+ 'create-file': 'criar arquivo',
39
+ insert: 'inserir bloco',
40
+ remove: 'remover bloco',
41
+ 'delete-file': 'remover arquivo',
42
+ };
43
+ export function planOperations(plan) {
44
+ return [
45
+ ...plan.fileOps.map((o) => ({ path: o.path, type: 'file', action: o.action, reason: o.reason })),
46
+ ...plan.blockOps.map((o) => ({ path: o.file, type: 'block', action: o.action, reason: o.reason })),
47
+ {
48
+ path: '.ai/toolkit-lock.json',
49
+ type: 'lock',
50
+ action: plan.lockOp.action === 'write'
51
+ ? plan.lockOp.expectedHash === null
52
+ ? 'create'
53
+ : 'update'
54
+ : plan.lockOp.action === 'delete'
55
+ ? 'delete'
56
+ : 'unchanged',
57
+ reason: 'registro da instalação',
58
+ },
59
+ ];
60
+ }
61
+ export function planSummary(plan) {
62
+ const summary = {};
63
+ for (const op of planOperations(plan))
64
+ summary[op.action] = (summary[op.action] ?? 0) + 1;
65
+ return summary;
66
+ }
67
+ export function renderPlan(plan) {
68
+ const lines = [];
69
+ const ops = planOperations(plan);
70
+ const changing = ops.filter((o) => o.action !== 'unchanged');
71
+ for (const o of changing) {
72
+ const label = o.type === 'block' && o.action === 'update' ? 'atualizar bloco' : FILE_LABELS[o.action] ?? o.action;
73
+ lines.push(` ${label.padEnd(16)} ${o.path}`);
74
+ }
75
+ const unchanged = ops.length - changing.length;
76
+ if (unchanged > 0)
77
+ lines.push(` ${'sem mudança'.padEnd(16)} ${unchanged} item(ns)`);
78
+ if (plan.warnings.length > 0) {
79
+ lines.push('', 'Avisos:');
80
+ for (const w of plan.warnings)
81
+ lines.push(` - ${w}`);
82
+ }
83
+ if (plan.conflicts.length > 0) {
84
+ lines.push('', `Conflitos (${plan.conflicts.length}):`);
85
+ for (const c of plan.conflicts)
86
+ lines.push(` ! ${c.path}: ${c.reason}`);
87
+ }
88
+ return lines;
89
+ }
90
+ export function conflictHelp() {
91
+ return [
92
+ '',
93
+ 'Operação abortada: nada foi alterado.',
94
+ 'Para resolver: mova suas personalizações para .ai/local/, restaure o arquivo original',
95
+ '(o backup da última operação fica em .ai/backups/<operação>/) ou renomeie o arquivo conflitante.',
96
+ 'O toolkit não sobrescreve customizações, nem com --yes.',
97
+ ];
98
+ }
@@ -0,0 +1,290 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { parse as parseToml } from 'smol-toml';
4
+ import { ADAPTERS } from '../adapters/index.js';
5
+ import { loadContent } from '../core/content.js';
6
+ import { bundledContentDir, cliVersion, resolveProject } from '../core/env.js';
7
+ import { parseFrontmatter } from '../core/frontmatter.js';
8
+ import { inspectInstallation, readIfFile } from '../core/inspect.js';
9
+ import { readLock } from '../core/lock.js';
10
+ import { resolveInProject } from '../core/paths.js';
11
+ import { BLOCK_BEGIN } from '../core/blocks.js';
12
+ import { detectTool, runProbe } from '../core/tools.js';
13
+ import { EXIT_ERROR, EXIT_OK } from './common.js';
14
+ const HOW_TO_VERIFY = {
15
+ claude: {
16
+ instruções: 'Abra uma nova sessão (claude) na pasta do projeto e pergunte quais regras do SeedGrid AI Toolkit estão carregadas; /memory lista os arquivos de memória.',
17
+ skills: 'Em nova sessão, digite / e confira as skills do toolkit no menu, ou peça a lista de skills disponíveis.',
18
+ agentes: 'Em nova sessão, use /agents e confira os papéis do catálogo.',
19
+ },
20
+ codex: {
21
+ instruções: 'Rode seedgrid-ai doctor --probe, ou abra nova sessão (codex) e pergunte quais instruções de AGENTS.md foram carregadas.',
22
+ skills: 'Rode seedgrid-ai doctor --probe, ou em nova sessão digite $ e confira as skills do toolkit.',
23
+ agentes: 'Marque o projeto como confiável (trust) e, em nova sessão, peça os tipos de agente aceitos por spawn_agent; sem confiança, .codex/agents/ é ignorado.',
24
+ },
25
+ };
26
+ async function skillNamesIn(projectRoot, dir) {
27
+ const byName = new Map();
28
+ let entries;
29
+ try {
30
+ entries = await readdir(resolveInProject(projectRoot, dir), { withFileTypes: true });
31
+ }
32
+ catch {
33
+ return byName;
34
+ }
35
+ for (const e of entries) {
36
+ if (!e.isDirectory())
37
+ continue;
38
+ const text = await readIfFile(resolveInProject(projectRoot, `${dir}/${e.name}/SKILL.md`));
39
+ if (text === null)
40
+ continue;
41
+ const fm = parseFrontmatter(text);
42
+ const name = 'error' in fm || typeof fm.data.name !== 'string' ? e.name : fm.data.name;
43
+ byName.set(name, [...(byName.get(name) ?? []), `${dir}/${e.name}`]);
44
+ }
45
+ return byName;
46
+ }
47
+ async function agentNamesIn(projectRoot, adapter) {
48
+ const byName = new Map();
49
+ const dir = adapter.nativeAgentsDir;
50
+ let files = [];
51
+ try {
52
+ files = (await readdir(resolveInProject(projectRoot, dir), { recursive: true })).map(String);
53
+ }
54
+ catch {
55
+ return byName;
56
+ }
57
+ for (const f of files.filter((x) => x.endsWith(adapter.nativeAgentExtension))) {
58
+ const rel = `${dir}/${f.split(path.sep).join('/')}`;
59
+ const text = await readIfFile(resolveInProject(projectRoot, rel));
60
+ if (text === null)
61
+ continue;
62
+ let name;
63
+ if (adapter.nativeAgentExtension === '.toml') {
64
+ try {
65
+ name = parseToml(text).name;
66
+ }
67
+ catch {
68
+ continue;
69
+ }
70
+ }
71
+ else {
72
+ const fm = parseFrontmatter(text);
73
+ name = 'error' in fm ? undefined : fm.data.name;
74
+ }
75
+ if (typeof name === 'string')
76
+ byName.set(name, [...(byName.get(name) ?? []), rel]);
77
+ }
78
+ return byName;
79
+ }
80
+ function probeResult(probe, found) {
81
+ if (typeof probe !== 'string')
82
+ return 'não verificada';
83
+ return found ? 'confirmada' : 'não encontrada';
84
+ }
85
+ async function checkTarget(projectRoot, lock, adapter, checks, discovery, probe) {
86
+ const area = adapter.displayName;
87
+ const how = HOW_TO_VERIFY[adapter.target];
88
+ const managed = new Set(lock.files.map((f) => f.path));
89
+ // Instruções
90
+ const instrFile = adapter.target === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
91
+ const instrOk = lock.blocks.some((b) => b.file === instrFile);
92
+ discovery.push({
93
+ target: adapter.target,
94
+ kind: 'instruções',
95
+ location: instrFile,
96
+ syntax: instrOk ? 'válida' : 'inválida',
97
+ realDiscovery: probeResult(probe, typeof probe === 'string' && probe.includes(BLOCK_BEGIN)),
98
+ howToVerify: how.instruções,
99
+ });
100
+ for (const issue of await adapter.projectChecks(projectRoot, lock.mode)) {
101
+ checks.push({ level: issue.level, area, message: issue.message });
102
+ }
103
+ // Skills
104
+ const skillNames = [...new Set(lock.files.filter((f) => f.component.startsWith('skill:')).map((f) => f.component.slice(6)))];
105
+ const found = await skillNamesIn(projectRoot, adapter.skillsDir);
106
+ let skillsValid = true;
107
+ for (const name of skillNames) {
108
+ const rel = `${adapter.skillsDir}/${name}/SKILL.md`;
109
+ if (!managed.has(rel))
110
+ continue;
111
+ const text = await readIfFile(resolveInProject(projectRoot, rel));
112
+ if (text === null) {
113
+ checks.push({ level: 'erro', area, message: `${rel} ausente` });
114
+ skillsValid = false;
115
+ continue;
116
+ }
117
+ const fm = parseFrontmatter(text);
118
+ if ('error' in fm) {
119
+ checks.push({ level: 'erro', area, message: `${rel}: ${fm.error}` });
120
+ skillsValid = false;
121
+ }
122
+ else if (fm.data.name !== name || typeof fm.data.description !== 'string' || fm.data.description.trim() === '') {
123
+ checks.push({ level: 'erro', area, message: `${rel}: name deve ser "${name}" e description é obrigatória` });
124
+ skillsValid = false;
125
+ }
126
+ const dirs = found.get(name) ?? [];
127
+ if (dirs.length > 1) {
128
+ checks.push({ level: 'aviso', area, message: `skill "${name}" declarada em mais de uma pasta: ${dirs.join(', ')}` });
129
+ }
130
+ }
131
+ discovery.push({
132
+ target: adapter.target,
133
+ kind: 'skills',
134
+ location: `${adapter.skillsDir}/ (${skillNames.length})`,
135
+ syntax: skillsValid ? 'válida' : 'inválida',
136
+ realDiscovery: probeResult(probe, typeof probe === 'string' && skillNames.every((n) => probe.includes(n))),
137
+ howToVerify: how.skills,
138
+ });
139
+ // Agentes nativos
140
+ if (lock.mode === 'native') {
141
+ const agentFiles = lock.files.filter((f) => f.path.startsWith(`${adapter.nativeAgentsDir}/`));
142
+ let valid = agentFiles.length > 0;
143
+ for (const f of agentFiles) {
144
+ const text = await readIfFile(resolveInProject(projectRoot, f.path));
145
+ if (text === null) {
146
+ checks.push({ level: 'erro', area, message: `${f.path} ausente` });
147
+ valid = false;
148
+ continue;
149
+ }
150
+ const issues = adapter.checkNativeAgent(f.path, text);
151
+ for (const i of issues)
152
+ checks.push({ level: i.level, area, message: i.message });
153
+ if (issues.some((i) => i.level === 'erro'))
154
+ valid = false;
155
+ }
156
+ for (const [name, files] of await agentNamesIn(projectRoot, adapter)) {
157
+ if (files.length > 1)
158
+ checks.push({ level: 'aviso', area, message: `agente "${name}" definido mais de uma vez: ${files.join(', ')}` });
159
+ }
160
+ discovery.push({
161
+ target: adapter.target,
162
+ kind: 'agentes',
163
+ location: `${adapter.nativeAgentsDir}/ (${agentFiles.length})`,
164
+ syntax: valid ? 'válida' : 'inválida',
165
+ realDiscovery: 'não verificada',
166
+ howToVerify: how.agentes,
167
+ });
168
+ }
169
+ }
170
+ function toolCheck(info, mode) {
171
+ if (!info.installed) {
172
+ return {
173
+ level: 'aviso',
174
+ area: info.displayName,
175
+ message: `${info.displayName} não encontrado no PATH: o teste real de descoberta não foi executado.`,
176
+ };
177
+ }
178
+ if (info.validated) {
179
+ return { level: 'ok', area: info.displayName, message: `${info.displayName} ${info.version} (versão validada).` };
180
+ }
181
+ return {
182
+ level: mode === 'native' ? 'aviso' : 'info',
183
+ area: info.displayName,
184
+ message: `${info.displayName} ${info.version ?? '(versão desconhecida)'} não consta das versões validadas (${info.validatedVersions.join(', ')}).`,
185
+ };
186
+ }
187
+ /**
188
+ * Diagnóstico: valida sintaxe e consistência dos destinos de descoberta e
189
+ * relata o que não pode ser verificado sem abrir a ferramenta.
190
+ */
191
+ export async function doctorCommand(opts) {
192
+ const projectRoot = resolveProject(opts.project);
193
+ const checks = [];
194
+ const discovery = [];
195
+ const limitations = [];
196
+ const tools = [];
197
+ try {
198
+ const bundle = await loadContent(bundledContentDir());
199
+ checks.push({ level: 'ok', area: 'conteúdo', message: `Conteúdo empacotado ${bundle.contentVersion} válido.` });
200
+ }
201
+ catch (err) {
202
+ checks.push({ level: 'erro', area: 'conteúdo', message: `Conteúdo empacotado inválido: ${err.message}` });
203
+ }
204
+ const lockState = await readLock(projectRoot);
205
+ let lock = null;
206
+ if (lockState.status === 'absent') {
207
+ checks.push({ level: 'info', area: 'instalação', message: 'Toolkit não instalado neste projeto.' });
208
+ }
209
+ else if (lockState.status === 'invalid') {
210
+ checks.push({ level: 'erro', area: 'instalação', message: `Lock inválido: ${lockState.errors.join('; ')}` });
211
+ }
212
+ else {
213
+ lock = lockState.lock;
214
+ checks.push({ level: 'ok', area: 'instalação', message: `Lock válido: conteúdo ${lock.contentVersion}, ${lock.targets.join('+')}, ${lock.mode}.` });
215
+ const insp = await inspectInstallation(projectRoot, lock);
216
+ for (const f of insp.files.filter((x) => x.state !== 'ok')) {
217
+ checks.push({ level: 'erro', area: 'arquivos', message: `${f.path}: ${f.state}${f.detail ? ` (${f.detail})` : ''}` });
218
+ }
219
+ for (const b of insp.blocks.filter((x) => x.state !== 'ok')) {
220
+ checks.push({ level: 'erro', area: 'blocos', message: `${b.file}: bloco ${b.state}${b.detail ? ` (${b.detail})` : ''}` });
221
+ }
222
+ if (insp.files.every((f) => f.state === 'ok') && insp.blocks.every((b) => b.state === 'ok')) {
223
+ checks.push({ level: 'ok', area: 'arquivos', message: `${insp.files.length} arquivos e ${insp.blocks.length} blocos conferem com os hashes do lock.` });
224
+ }
225
+ // Cópias de skills entre targets devem ser idênticas (mesma fonte).
226
+ const bySkillFile = new Map();
227
+ for (const f of lock.files.filter((x) => x.component.startsWith('skill:'))) {
228
+ const rel = f.path.replace(/^\.(claude|agents)\/skills\//, '');
229
+ if (!bySkillFile.has(rel))
230
+ bySkillFile.set(rel, new Set());
231
+ bySkillFile.get(rel).add(f.sha256);
232
+ }
233
+ for (const [rel, hashes] of bySkillFile) {
234
+ if (hashes.size > 1)
235
+ checks.push({ level: 'erro', area: 'skills', message: `cópias divergentes de ${rel} entre targets` });
236
+ }
237
+ const hasLocal = (await readdir(resolveInProject(projectRoot, '.ai/local')).catch(() => null)) !== null;
238
+ checks.push({
239
+ level: 'info',
240
+ area: 'personalização',
241
+ message: hasLocal ? '.ai/local/ presente: personalizações locais serão consideradas.' : '.ai/local/ não existe (opcional).',
242
+ });
243
+ }
244
+ const targets = lock?.targets ?? ['claude', 'codex'];
245
+ for (const t of targets) {
246
+ const adapter = ADAPTERS[t];
247
+ const info = await detectTool(adapter);
248
+ tools.push(info);
249
+ checks.push(toolCheck(info, lock?.mode ?? 'shared'));
250
+ let probe;
251
+ if (lock && opts.probe && adapter.probeCommand && info.installed) {
252
+ probe = await runProbe(adapter.probeCommand, projectRoot);
253
+ checks.push(probe === null
254
+ ? { level: 'aviso', area: adapter.displayName, message: `sonda falhou: ${adapter.probeCommand}` }
255
+ : { level: 'info', area: adapter.displayName, message: `sonda executada: ${adapter.probeCommand}` });
256
+ }
257
+ else if (lock && opts.probe && !adapter.probeCommand) {
258
+ checks.push({ level: 'info', area: adapter.displayName, message: 'sem sonda automática; use o smoke test manual.' });
259
+ }
260
+ if (lock) {
261
+ await checkTarget(projectRoot, lock, adapter, checks, discovery, probe);
262
+ limitations.push(...adapter.limitations(lock.mode).map((l) => `${adapter.displayName}: ${l}`));
263
+ }
264
+ }
265
+ limitations.push('O doctor valida sintaxe e consistência. A descoberta real só é confirmada com --probe (Codex: instruções e skills) ou abrindo uma nova sessão de cada ferramenta.', 'Seleção de papéis e delegação seguem instruções; não são garantias determinísticas do instalador.');
266
+ for (const d of discovery.filter((x) => x.realDiscovery === 'não encontrada')) {
267
+ checks.push({ level: 'erro', area: d.target, message: `${d.kind}: a sonda não encontrou o conteúdo instalado em ${d.location}` });
268
+ }
269
+ const hasError = checks.some((c) => c.level === 'erro');
270
+ const icon = { ok: '[ok]', info: '[i]', aviso: '[!]', erro: '[x]' };
271
+ const lines = [`seedgrid-ai doctor (CLI ${cliVersion()}) em ${projectRoot}`, ''];
272
+ for (const c of checks)
273
+ lines.push(`${icon[c.level].padEnd(5)}${c.area}: ${c.message}`);
274
+ if (discovery.length > 0) {
275
+ lines.push('', 'Destinos de descoberta (sintaxe x descoberta real):');
276
+ for (const d of discovery) {
277
+ lines.push(` ${d.target.padEnd(7)} ${d.kind.padEnd(11)} ${d.location.padEnd(28)} sintaxe ${d.syntax}; descoberta real ${d.realDiscovery}`);
278
+ lines.push(` como verificar: ${d.howToVerify}`);
279
+ }
280
+ }
281
+ lines.push('', 'Limitações:');
282
+ for (const l of limitations)
283
+ lines.push(` - ${l}`);
284
+ lines.push('', 'Após instalar ou atualizar, abra uma nova sessão: não há recarga garantida em todas as ferramentas.');
285
+ return {
286
+ exitCode: hasError ? EXIT_ERROR : EXIT_OK,
287
+ report: { command: 'doctor', project: projectRoot, cliVersion: cliVersion(), installed: lock !== null, tools, checks, discovery, limitations },
288
+ lines,
289
+ };
290
+ }
@@ -0,0 +1,9 @@
1
+ import { runInstall } from './install.js';
2
+ /**
3
+ * Instala o toolkit no projeto. Idempotente: repetir não altera arquivos nem
4
+ * duplica blocos. Sem --target/--mode, reaproveita as opções do lock existente
5
+ * (ou usa both/shared numa instalação nova).
6
+ */
7
+ export function initCommand(opts) {
8
+ return runInstall('init', opts);
9
+ }