@pathbit/agentdevkit 0.0.0-stage → 0.0.5

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 (240) hide show
  1. package/.pbai4devs/COMPATIBILIDADE.md +109 -0
  2. package/.pbai4devs/INSTRUCTIONS.md +87 -0
  3. package/.pbai4devs/README.md +50 -0
  4. package/.pbai4devs/agents/README.md +18 -0
  5. package/.pbai4devs/agents/revisor/AGENT.md +16 -0
  6. package/.pbai4devs/agents/revisor/antigravity.yaml +8 -0
  7. package/.pbai4devs/agents/revisor/claude.yaml +5 -0
  8. package/.pbai4devs/agents/revisor/cursor.yaml +5 -0
  9. package/.pbai4devs/agents/revisor/gemini.yaml +6 -0
  10. package/.pbai4devs/agents/revisor/github.yaml +5 -0
  11. package/.pbai4devs/agents/revisor/kimi-code.yaml +5 -0
  12. package/.pbai4devs/agents/revisor/mimocode.yaml +10 -0
  13. package/.pbai4devs/agents/revisor/opencode.yaml +7 -0
  14. package/.pbai4devs/agents/revisor/zcode.yaml +5 -0
  15. package/.pbai4devs/commands/README.md +30 -0
  16. package/.pbai4devs/commands/atualizar-ferramentas/COMMAND.md +17 -0
  17. package/.pbai4devs/commands/diagnosticar/COMMAND.md +18 -0
  18. package/.pbai4devs/commands/instalar-ferramentas/COMMAND.md +21 -0
  19. package/.pbai4devs/commands/preparar-dev/COMMAND.md +14 -0
  20. package/.pbai4devs/commands/proximos-passos/COMMAND.md +9 -0
  21. package/.pbai4devs/commands/revisar-entrega/COMMAND.md +29 -0
  22. package/.pbai4devs/commands/sincronizar/COMMAND.md +20 -0
  23. package/.pbai4devs/commands/status-roadmap/COMMAND.md +12 -0
  24. package/.pbai4devs/commands/testar-navegador/COMMAND.md +16 -0
  25. package/.pbai4devs/commands/verificar-agentes/COMMAND.md +19 -0
  26. package/.pbai4devs/estado/README.md +12 -0
  27. package/.pbai4devs/external-skills/CATALOG.json +121 -0
  28. package/.pbai4devs/external-skills/README.md +48 -0
  29. package/.pbai4devs/rules/README.md +18 -0
  30. package/.pbai4devs/rules/ambiente-local/RULE.md +33 -0
  31. package/.pbai4devs/rules/ambiente-local/cursor.yaml +4 -0
  32. package/.pbai4devs/rules/documentacao/RULE.md +11 -0
  33. package/.pbai4devs/rules/documentacao/cursor.yaml +4 -0
  34. package/.pbai4devs/rules/estrutura/RULE.md +33 -0
  35. package/.pbai4devs/rules/estrutura/cursor.yaml +4 -0
  36. package/.pbai4devs/rules/git/RULE.md +18 -0
  37. package/.pbai4devs/rules/git/cursor.yaml +4 -0
  38. package/.pbai4devs/rules/proximos-passos/RULE.md +14 -0
  39. package/.pbai4devs/rules/qualidade/RULE.md +32 -0
  40. package/.pbai4devs/rules/qualidade/cursor.yaml +4 -0
  41. package/.pbai4devs/scripts/README.md +69 -0
  42. package/.pbai4devs/scripts/diagnosticar-ambiente/SCRIPT.mjs +41 -0
  43. package/.pbai4devs/scripts/diagnosticar-ambiente/tests/TEST.mjs +30 -0
  44. package/.pbai4devs/scripts/executar-script/README.md +28 -0
  45. package/.pbai4devs/scripts/executar-script/SCRIPT.mjs +78 -0
  46. package/.pbai4devs/scripts/executar-script/tests/TEST.mjs +122 -0
  47. package/.pbai4devs/scripts/gerenciar-skills-externas/README.md +31 -0
  48. package/.pbai4devs/scripts/gerenciar-skills-externas/SCRIPT.mjs +182 -0
  49. package/.pbai4devs/scripts/gerenciar-skills-externas/tests/TEST.mjs +134 -0
  50. package/.pbai4devs/scripts/inspecionar-projeto/SCRIPT.mjs +190 -0
  51. package/.pbai4devs/scripts/inspecionar-projeto/tests/TEST.mjs +161 -0
  52. package/.pbai4devs/scripts/lib/README.md +9 -0
  53. package/.pbai4devs/scripts/lib/adapters.mjs +135 -0
  54. package/.pbai4devs/scripts/lib/catalog.mjs +170 -0
  55. package/.pbai4devs/scripts/lib/gitignore.mjs +348 -0
  56. package/.pbai4devs/scripts/lib/npm.mjs +17 -0
  57. package/.pbai4devs/scripts/lib/resource-path.mjs +20 -0
  58. package/.pbai4devs/scripts/lib/runtime.mjs +28 -0
  59. package/.pbai4devs/scripts/lib/script-config.mjs +8 -0
  60. package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.md +34 -0
  61. package/.pbai4devs/scripts/preparar-ferramentas/BOOTSTRAP.mjs +189 -0
  62. package/.pbai4devs/scripts/preparar-ferramentas/README.md +71 -0
  63. package/.pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs +455 -0
  64. package/.pbai4devs/scripts/preparar-ferramentas/tests/FIXTURE.html +20 -0
  65. package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_BROWSER.mjs +55 -0
  66. package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_DESKTOP.mjs +61 -0
  67. package/.pbai4devs/scripts/preparar-ferramentas/tests/SMOKE_VERCEL.mjs +192 -0
  68. package/.pbai4devs/scripts/preparar-ferramentas/tests/TEST.mjs +552 -0
  69. package/.pbai4devs/scripts/preparar-ferramentas/tests/bootstrap.test.mjs +94 -0
  70. package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/just-bash/input.txt +2 -0
  71. package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/just-bash-overlay/input.txt +1 -0
  72. package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/skills/agentdevkit-smoke/SKILL.md +8 -0
  73. package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/webreel/index.html +6 -0
  74. package/.pbai4devs/scripts/preparar-ferramentas/tests/fixtures-vercel/webreel/webreel.config.json +10 -0
  75. package/.pbai4devs/scripts/revisar-entrega/README.md +36 -0
  76. package/.pbai4devs/scripts/revisar-entrega/SCRIPT.mjs +249 -0
  77. package/.pbai4devs/scripts/revisar-entrega/tests/TEST.mjs +249 -0
  78. package/.pbai4devs/scripts/sincronizar-agentes/README.md +41 -0
  79. package/.pbai4devs/scripts/sincronizar-agentes/SCRIPT.mjs +473 -0
  80. package/.pbai4devs/scripts/sincronizar-agentes/tests/LOCAL_IGNORE.mjs +290 -0
  81. package/.pbai4devs/scripts/sincronizar-agentes/tests/TEST.mjs +869 -0
  82. package/.pbai4devs/scripts/testar-infraestrutura/SCRIPT.mjs +39 -0
  83. package/.pbai4devs/scripts/testar-infraestrutura/tests/TEST.mjs +29 -0
  84. package/.pbai4devs/scripts/testar-maturidade/README.md +54 -0
  85. package/.pbai4devs/scripts/testar-maturidade/SCRIPT.mjs +477 -0
  86. package/.pbai4devs/scripts/testar-maturidade/assets/calculator.mjs +1 -0
  87. package/.pbai4devs/scripts/testar-maturidade/assets/calculator.test.mjs.template +8 -0
  88. package/.pbai4devs/scripts/testar-maturidade/assets/http-api.test.mjs.template +28 -0
  89. package/.pbai4devs/scripts/testar-maturidade/assets/server.mjs +34 -0
  90. package/.pbai4devs/scripts/testar-maturidade/tests/TEST.mjs +305 -0
  91. package/.pbai4devs/scripts/testar-navegador/REFERENCE.md +49 -0
  92. package/.pbai4devs/scripts/testar-navegador/SCRIPT.conf +1 -0
  93. package/.pbai4devs/scripts/testar-navegador/SCRIPT.js +64 -0
  94. package/.pbai4devs/scripts/testar-navegador/tests/FAIL.js +8 -0
  95. package/.pbai4devs/scripts/testar-navegador/tests/SUCCESS.js +13 -0
  96. package/.pbai4devs/scripts/verificar-recursos/README.md +25 -0
  97. package/.pbai4devs/scripts/verificar-recursos/SCRIPT.mjs +209 -0
  98. package/.pbai4devs/scripts/verificar-recursos/tests/TEST.mjs +310 -0
  99. package/.pbai4devs/scripts/verificar-recursos/tests/ambiente-local.mjs +80 -0
  100. package/.pbai4devs/skills/README.md +24 -0
  101. package/.pbai4devs/skills/git/git-branch/SKILL.md +11 -0
  102. package/.pbai4devs/skills/git/git-commit/SKILL.md +16 -0
  103. package/.pbai4devs/skills/git/git-diff/SKILL.md +9 -0
  104. package/.pbai4devs/skills/git/git-fetch/SKILL.md +10 -0
  105. package/.pbai4devs/skills/git/git-log/SKILL.md +9 -0
  106. package/.pbai4devs/skills/git/git-merge/SKILL.md +13 -0
  107. package/.pbai4devs/skills/git/git-pull/SKILL.md +12 -0
  108. package/.pbai4devs/skills/git/git-push/SKILL.md +12 -0
  109. package/.pbai4devs/skills/git/git-status/SKILL.md +9 -0
  110. package/.pbai4devs/skills/git/git-worktree/SKILL.md +10 -0
  111. package/.pbai4devs/skills/produto/criar-design-doc/SKILL.md +37 -0
  112. package/.pbai4devs/skills/produto/criar-prd/SKILL.md +35 -0
  113. package/.pbai4devs/skills/produto/criar-ux-ui/SKILL.md +34 -0
  114. package/.pbai4devs/skills/projeto/atualizar-documentacao/SKILL.md +26 -0
  115. package/.pbai4devs/skills/projeto/configurar-projeto/SKILL.md +62 -0
  116. package/.pbai4devs/skills/projeto/criar-agente/SKILL.md +20 -0
  117. package/.pbai4devs/skills/projeto/criar-comando/SKILL.md +25 -0
  118. package/.pbai4devs/skills/projeto/criar-recurso/SKILL.md +41 -0
  119. package/.pbai4devs/skills/projeto/criar-regra/SKILL.md +19 -0
  120. package/.pbai4devs/skills/projeto/criar-skill/SKILL.md +22 -0
  121. package/.pbai4devs/skills/projeto/executar-script/SKILL.md +29 -0
  122. package/.pbai4devs/skills/projeto/preparar-dev/SKILL.md +45 -0
  123. package/.pbai4devs/skills/projeto/preparar-ferramentas/SKILL.md +56 -0
  124. package/.pbai4devs/skills/projeto/proximos-passos/SKILL.md +23 -0
  125. package/.pbai4devs/skills/projeto/sincronizar-agentes/SKILL.md +42 -0
  126. package/.pbai4devs/skills/projeto/usar-skills-externas/SKILL.md +28 -0
  127. package/.pbai4devs/skills/projeto/verificar-trabalho/SKILL.md +45 -0
  128. package/.pbai4devs/skills/specs/criar-spec/SKILL.md +33 -0
  129. package/.pbai4devs/skills/specs/gerenciar-roadmap/SKILL.md +26 -0
  130. package/.pbai4devs/skills/specs/implementar-spec/SKILL.md +48 -0
  131. package/.pbai4devs/templates/README.md +65 -0
  132. package/.pbai4devs/templates/adr/TEMPLATE.md +21 -0
  133. package/.pbai4devs/templates/ambiente-local/Makefile.template +48 -0
  134. package/.pbai4devs/templates/ambiente-local/TEMPLATE.md +48 -0
  135. package/.pbai4devs/templates/ambiente-local/compose.local.yml.template +16 -0
  136. package/.pbai4devs/templates/ambiente-local/dockerignore.template +28 -0
  137. package/.pbai4devs/templates/changelog/TEMPLATE.md +17 -0
  138. package/.pbai4devs/templates/claude/TEMPLATE.md +8 -0
  139. package/.pbai4devs/templates/clients/ADAPTERS.json +306 -0
  140. package/.pbai4devs/templates/clients/TEMPLATE.md +12 -0
  141. package/.pbai4devs/templates/comando/TEMPLATE.md +15 -0
  142. package/.pbai4devs/templates/configuracao/TEMPLATE.md +46 -0
  143. package/.pbai4devs/templates/configuracao-raiz/TEMPLATE.md +22 -0
  144. package/.pbai4devs/templates/configuracao-raiz/editorconfig.template +21 -0
  145. package/.pbai4devs/templates/configuracao-raiz/env.example.template +3 -0
  146. package/.pbai4devs/templates/configuracao-raiz/gitattributes.template +6 -0
  147. package/.pbai4devs/templates/contribuicao/TEMPLATE.md +23 -0
  148. package/.pbai4devs/templates/design/TEMPLATE.md +30 -0
  149. package/.pbai4devs/templates/entrypoints/AGENTS.md +19 -0
  150. package/.pbai4devs/templates/entrypoints/CLAUDE.md +7 -0
  151. package/.pbai4devs/templates/entrypoints/GEMINI.md +7 -0
  152. package/.pbai4devs/templates/entrypoints/TEMPLATE.md +12 -0
  153. package/.pbai4devs/templates/gitignore/TEMPLATE.md +42 -0
  154. package/.pbai4devs/templates/gitignore/agents.ignore +45 -0
  155. package/.pbai4devs/templates/gitignore/clients.json +20 -0
  156. package/.pbai4devs/templates/gitignore/local.ignore +10 -0
  157. package/.pbai4devs/templates/gitignore/shared.ignore +60 -0
  158. package/.pbai4devs/templates/instrucoes-agentes/TEMPLATE.md +25 -0
  159. package/.pbai4devs/templates/plano-implementacao/TEMPLATE.md +27 -0
  160. package/.pbai4devs/templates/prd/TEMPLATE.md +30 -0
  161. package/.pbai4devs/templates/readme-pasta/TEMPLATE.md +16 -0
  162. package/.pbai4devs/templates/readme-projeto/TEMPLATE.md +34 -0
  163. package/.pbai4devs/templates/release/TEMPLATE.md +23 -0
  164. package/.pbai4devs/templates/revisao-entrega/TEMPLATE.md +41 -0
  165. package/.pbai4devs/templates/roadmap/TEMPLATE.md +18 -0
  166. package/.pbai4devs/templates/seguranca/TEMPLATE.md +22 -0
  167. package/.pbai4devs/templates/spec/TEMPLATE.md +61 -0
  168. package/.pbai4devs/templates/tasks/TEMPLATE.md +20 -0
  169. package/.pbai4devs/templates/ux-ui/TEMPLATE.md +26 -0
  170. package/.pbai4devs/tools/README.md +87 -0
  171. package/.pbai4devs/tools/agent-browser/README.md +26 -0
  172. package/.pbai4devs/tools/agent-browser/SCRIPT.mjs +5 -0
  173. package/.pbai4devs/tools/agent-browser/TOOL.json +33 -0
  174. package/.pbai4devs/tools/agent-desktop/README.md +26 -0
  175. package/.pbai4devs/tools/agent-desktop/SCRIPT.mjs +5 -0
  176. package/.pbai4devs/tools/agent-desktop/TOOL.json +30 -0
  177. package/.pbai4devs/tools/just-bash/README.md +23 -0
  178. package/.pbai4devs/tools/just-bash/SCRIPT.mjs +5 -0
  179. package/.pbai4devs/tools/just-bash/TOOL.json +27 -0
  180. package/.pbai4devs/tools/markdownlint-cli2/README.md +18 -0
  181. package/.pbai4devs/tools/markdownlint-cli2/SCRIPT.mjs +5 -0
  182. package/.pbai4devs/tools/markdownlint-cli2/TOOL.json +28 -0
  183. package/.pbai4devs/tools/opensrc/README.md +25 -0
  184. package/.pbai4devs/tools/opensrc/SCRIPT.mjs +5 -0
  185. package/.pbai4devs/tools/opensrc/TOOL.json +29 -0
  186. package/.pbai4devs/tools/portless/README.md +21 -0
  187. package/.pbai4devs/tools/portless/SCRIPT.mjs +5 -0
  188. package/.pbai4devs/tools/portless/TOOL.json +30 -0
  189. package/.pbai4devs/tools/skills/README.md +24 -0
  190. package/.pbai4devs/tools/skills/SCRIPT.mjs +5 -0
  191. package/.pbai4devs/tools/skills/TOOL.json +33 -0
  192. package/.pbai4devs/tools/webreel/README.md +23 -0
  193. package/.pbai4devs/tools/webreel/SCRIPT.mjs +5 -0
  194. package/.pbai4devs/tools/webreel/TOOL.json +25 -0
  195. package/CHANGELOG.md +58 -0
  196. package/CONTRIBUTING.md +73 -0
  197. package/LICENSE +21 -0
  198. package/README.en.md +78 -0
  199. package/README.es.md +80 -0
  200. package/README.md +88 -2
  201. package/bin/README.md +8 -0
  202. package/bin/agentdevkit.mjs +35 -0
  203. package/docs/README.md +81 -0
  204. package/docs/guides/README.md +14 -0
  205. package/docs/guides/cli.md +81 -0
  206. package/docs/guides/installation.md +78 -0
  207. package/docs/guides/resources.md +121 -0
  208. package/docs/guides/tools-and-testing.md +85 -0
  209. package/docs/guides/troubleshooting.md +151 -0
  210. package/docs/guides/workflow.md +130 -0
  211. package/docs/maintainers/README.md +12 -0
  212. package/docs/maintainers/community.md +49 -0
  213. package/docs/maintainers/development.md +54 -0
  214. package/docs/maintainers/maintenance.md +104 -0
  215. package/docs/maintainers/packages.md +76 -0
  216. package/docs/product/README.md +12 -0
  217. package/docs/product/design.md +94 -0
  218. package/docs/product/prd.md +64 -0
  219. package/docs/product/roadmap.md +36 -0
  220. package/docs/product/ux-ui.md +42 -0
  221. package/docs/specs/README.md +20 -0
  222. package/docs/specs/github-packages/SPEC.md +45 -0
  223. package/docs/specs/v0.0.1/README.md +10 -0
  224. package/docs/specs/v0.0.1/SPEC.md +57 -0
  225. package/docs/specs/v0.0.2/README.md +10 -0
  226. package/docs/specs/v0.0.2/SPEC.md +67 -0
  227. package/docs/specs/v0.0.3/README.md +10 -0
  228. package/docs/specs/v0.0.3/SPEC.md +64 -0
  229. package/docs/specs/v0.0.4/README.md +10 -0
  230. package/docs/specs/v0.0.4/SPEC.md +53 -0
  231. package/docs/specs/v0.0.5/README.md +9 -0
  232. package/docs/specs/v0.0.5/SPEC.md +42 -0
  233. package/package.json +52 -4
  234. package/src/README.md +16 -0
  235. package/src/adapters/index.mjs +1 -0
  236. package/src/cli.mjs +162 -0
  237. package/src/config.mjs +14 -0
  238. package/src/i18n.mjs +42 -0
  239. package/src/install.mjs +367 -0
  240. package/src/next.mjs +79 -0
@@ -0,0 +1,367 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { existsSync, lstatSync, readFileSync, writeFileSync, readdirSync, mkdirSync, mkdtempSync, realpathSync, renameSync, rmSync, rmdirSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
5
+ import { synchronize, isReference } from '../.pbai4devs/scripts/sincronizar-agentes/SCRIPT.mjs';
6
+ import { isGeneratedOutput, planLocalIgnore, checkLocalIgnore, assertLocalIgnoreUnchanged, applyLocalIgnore, planUntrack, applyUntrack, restoreUntrack } from '../.pbai4devs/scripts/lib/gitignore.mjs';
7
+ import { writeAdapterManifest, adapterRoots, normalizeClients, resolveAdapters } from './adapters/index.mjs';
8
+ import { packageRoot, packageInfo, statePath, entryNames, begin, end } from './config.mjs';
9
+ import { normalizeLanguage, text } from './i18n.mjs';
10
+
11
+ const hash = value => createHash('sha256').update(value).digest('hex');
12
+ const portable = value => value.split(sep).join('/');
13
+ const fail = (code, message) => { throw Object.assign(new Error(message), { code }); };
14
+ const stat = path => { try { return lstatSync(path); } catch (error) { if (error.code === 'ENOENT') return null; throw error; } };
15
+ const ignored = new Set(['.git', '.local', '.cache', 'node_modules', '.agent-tests', 'opencode-loop']);
16
+ const reservedTargets = new Set(['.git', 'node_modules', '.pbai4devs']);
17
+ const checkTarget = path => {
18
+ if (path.split(sep).some(part => reservedTargets.has(part.toLowerCase()))) fail('E_TARGET', 'Unsafe target directory.');
19
+ };
20
+
21
+ export function resolveTarget(input, cwd = process.cwd()) {
22
+ let target = resolve(cwd, input || '.');
23
+ checkTarget(target);
24
+ // The OS may expose its own temporary directory through a system alias.
25
+ const temporary = resolve(tmpdir()), insideTemporary = relative(temporary, target);
26
+ if (insideTemporary === '' || (!insideTemporary.startsWith(`..${sep}`) && insideTemporary !== '..' && !isAbsolute(insideTemporary))) target = join(realpathSync(temporary), insideTemporary);
27
+ let ancestor = target;
28
+ while (true) {
29
+ const info = stat(ancestor);
30
+ if (info && (info.isSymbolicLink() || !info.isDirectory())) fail('E_TARGET', 'Target must be a real directory, without a symbolic link.');
31
+ const parent = dirname(ancestor); if (parent === ancestor) break; ancestor = parent;
32
+ }
33
+ const missing = []; let parent = target;
34
+ while (!stat(parent)) { missing.unshift(parent.slice(dirname(parent).length + 1)); parent = dirname(parent); }
35
+ const info = stat(parent);
36
+ if (info.isSymbolicLink() || !info.isDirectory()) fail('E_TARGET', 'Target must be a real directory, without a symbolic link.');
37
+ const canonical = join(realpathSync(parent), ...missing);
38
+ checkTarget(canonical);
39
+ return canonical;
40
+ }
41
+
42
+ export function safePath(root, path) {
43
+ if (typeof path !== 'string' || !path || isAbsolute(path) || /[\\\x00-\x1f:]/.test(path) || path.split('/').some(part => !part || part === '.' || part === '..')) fail('E_PATH', `Invalid managed path: ${path}`);
44
+ let current = root;
45
+ for (const part of path.split('/')) {
46
+ current = join(current, part);
47
+ if (stat(current)?.isSymbolicLink()) fail('E_SYMLINK', `Symbolic link refused: ${path}`);
48
+ }
49
+ return current;
50
+ }
51
+
52
+ function resourceAllowed(path, directory = false) {
53
+ const parts = path.split('/');
54
+ const folders = new Set(['agents', 'commands', 'external-skills', 'rules', 'scripts', 'skills', 'templates', 'tools', 'estado']);
55
+ const files = new Set(['README.md', 'INSTRUCTIONS.md', 'COMPATIBILIDADE.md', '.gitignore']);
56
+ if (!folders.has(parts[0]) && !(parts.length === 1 && files.has(parts[0]))) return false;
57
+ if (parts[0] === 'estado') return directory && parts.length === 1 || path === 'estado/README.md';
58
+ if (isGeneratedOutput(path, directory) || parts.some(part => ignored.has(part)) || parts[0] === 'adapters' || path === 'estado/agentdevkit.json' || path === '.npmignore') return false;
59
+ if (parts[0] === 'tools') return parts.length === 1 || (directory && parts.length === 2 && !['bin', 'npm-cache'].includes(parts[1])) || (parts.length === 2 && parts[1] === 'README.md') || (parts.length === 3 && ['TOOL.json', 'SCRIPT.mjs', 'README.md'].includes(parts[2]));
60
+ if (parts[0] === 'external-skills') return parts.length === 1 || (parts.length === 2 && ['README.md', 'CATALOG.json'].includes(parts[1]));
61
+ return true;
62
+ }
63
+
64
+ function walk(root, path = '', filter = () => true) {
65
+ const directory = path ? join(root, path) : root;
66
+ if (!existsSync(directory)) return [];
67
+ const files = [];
68
+ for (const name of readdirSync(directory).sort()) {
69
+ const child = path ? `${path}/${name}` : name;
70
+ const info = lstatSync(join(root, child));
71
+ if (info.isSymbolicLink()) fail('E_SYMLINK', `Symbolic link refused: ${child}`);
72
+ if (!filter(child, info.isDirectory())) continue;
73
+ if (info.isDirectory()) files.push(...walk(root, child, filter));
74
+ else if (info.isFile()) files.push(child);
75
+ else fail('E_PATH', `Unsupported file: ${child}`);
76
+ }
77
+ return files;
78
+ }
79
+
80
+ function write(root, path, content) {
81
+ const target = safePath(root, path); mkdirSync(dirname(target), { recursive: true }); writeFileSync(target, content);
82
+ }
83
+
84
+ function read(root, path) {
85
+ const file = safePath(root, path), info = stat(file);
86
+ if (!info) return null;
87
+ if (!info.isFile()) fail('E_PATH', `Expected a file: ${path}`);
88
+ return readFileSync(file);
89
+ }
90
+
91
+ function allowedManaged(path) {
92
+ if (entryNames.includes(path) || path === '.gitignore') return true;
93
+ if (['catalog.json', 'skills.json', 'agents.json', 'rules.json', 'espelhos.conf'].some(name => path === `.pbai4devs/${name}`)) return true;
94
+ if (['.agents/skills.json', '.agents/agents.json', '.agents/rules.json'].includes(path)) return true;
95
+ if (path.startsWith('.pbai4devs/')) return resourceAllowed(path.slice('.pbai4devs/'.length));
96
+ return adapterRoots.some(root => path === `${root}/.gitignore` || ['skills', 'agents', 'commands', 'rules', 'instructions', 'prompts'].some(kind => path.startsWith(`${root}/${kind}/`)));
97
+ }
98
+
99
+ export function loadState(root) {
100
+ const content = read(root, statePath); if (content === null) return null;
101
+ let state; try { state = JSON.parse(content); } catch { fail('E_STATE', 'Invalid AgentDevKit state JSON.'); }
102
+ if (state?.schemaVersion !== 1 || !normalizeLanguage(state.language) || typeof state.version !== 'string' || !state.files || typeof state.files !== 'object' || Array.isArray(state.files) || !state.blocks || typeof state.blocks !== 'object' || Array.isArray(state.blocks)) fail('E_STATE', 'Invalid AgentDevKit state.');
103
+ if (state.clients !== undefined) {
104
+ if (!Array.isArray(state.clients)) fail('E_STATE', 'Invalid client selection in AgentDevKit state.');
105
+ try { state.clients = normalizeClients(state.clients); } catch { fail('E_STATE', 'Invalid client selection in AgentDevKit state.'); }
106
+ }
107
+ for (const [path, digest] of [...Object.entries(state.files), ...Object.entries(state.blocks)]) {
108
+ safePath(root, path);
109
+ if (!allowedManaged(path) || !/^[a-f0-9]{64}$/.test(digest)) fail('E_STATE', `Invalid managed state entry: ${path}`);
110
+ }
111
+ return state;
112
+ }
113
+
114
+ function extractBlock(content, first = begin, last = end) {
115
+ const start = content.indexOf(first), finish = content.indexOf(last);
116
+ if (start < 0 && finish < 0) return null;
117
+ if (start < 0 || finish < start || content.indexOf(first, start + first.length) >= 0 || content.indexOf(last, finish + last.length) >= 0) fail('E_BLOCK', 'Invalid or duplicate managed block markers.');
118
+ return content.slice(start, finish + last.length);
119
+ }
120
+
121
+ function blockDigest(path, content) {
122
+ const value = content.toString('utf8');
123
+ const block = path === '.gitignore' ? extractBlock(value, '# BEGIN AGENTDEVKIT', '# END AGENTDEVKIT') : entryNames.includes(path) ? extractBlock(value) : path.endsWith('/.gitignore') ? extractBlock(value, '# BEGIN AGENT IGNORE', '# END AGENT IGNORE') : null;
124
+ return block === null ? null : hash(block);
125
+ }
126
+
127
+ function replacedIgnoreBlocks(target, changes, previous) {
128
+ const blocks = [];
129
+ for (const change of changes) {
130
+ if (change.path !== '.gitignore' && !change.path.endsWith('/.gitignore')) continue;
131
+ const current = read(target, change.path); if (!current) continue;
132
+ const source = current.toString('utf8');
133
+ if (!previous?.blocks[change.path] || blockDigest(change.path, current) !== previous.blocks[change.path]) continue;
134
+ const block = change.path === '.gitignore' ? extractBlock(source, '# BEGIN AGENTDEVKIT', '# END AGENTDEVKIT') : extractBlock(source, '# BEGIN AGENT IGNORE', '# END AGENT IGNORE');
135
+ if (!block) continue;
136
+ const first = source.indexOf(block), last = first + block.length;
137
+ blocks.push({ path: safePath(target, change.path), firstLine: source.slice(0, first).split('\n').length, lastLine: source.slice(0, last).split('\n').length, sha256: hash(block) });
138
+ }
139
+ return blocks;
140
+ }
141
+
142
+ function entryContent(current, template, language, path) {
143
+ const lines = template.replaceAll('\r', '').split('\n');
144
+ const heading = lines.findIndex(line => line.startsWith('# '));
145
+ if (heading < 0) fail('E_TEMPLATE', `Missing title: ${path}`);
146
+ let body = lines.slice(heading + 1).join('\n').trim();
147
+ if (path === 'AGENTS.md') body = `${text(language, 'agentLanguage')}\n\n${body}`;
148
+ const managed = `${begin}\n${body}\n${end}`;
149
+ if (!current) return `${lines.slice(0, heading + 1).join('\n')}\n\n${managed}\n`;
150
+ const source = current.toString('utf8'), previous = extractBlock(source);
151
+ return previous ? source.replace(previous, managed) : `${source}${source.endsWith('\n\n') ? '' : source.endsWith('\n') ? '\n' : '\n\n'}${managed}\n`;
152
+ }
153
+
154
+ function copyResources(source, destination) {
155
+ const files = walk(source, '', resourceAllowed);
156
+ for (const path of files) write(destination, path, readFileSync(join(source, path)));
157
+ return files;
158
+ }
159
+
160
+ export function planInstallation({ target, language = 'pt', mode = 'init', force = false, clients }) {
161
+ const previous = loadState(target);
162
+ if (mode !== 'init' && !previous) fail('E_MISSING', text(language, 'missing'));
163
+ const selected = normalizeClients(clients ?? previous?.clients ?? ['all']);
164
+ const active = resolveAdapters(selected);
165
+ const changingClients = clients !== undefined || mode === 'agents';
166
+ const protectedEntries = new Set(), entryConflicts = [], ownedEntrypoints = new Set();
167
+ for (const name of entryNames) {
168
+ const current = read(target, name);
169
+ if (current && previous?.files[name] && previous.files[name] !== hash(current)) { protectedEntries.add(name); entryConflicts.push(name); }
170
+ }
171
+ let derivedEntries = {};
172
+ const derived = read(target, '.pbai4devs/estado/derived.json');
173
+ if (derived) {
174
+ try { const value = JSON.parse(derived); if (value.schemaVersion === 1 && value.entries && typeof value.entries === 'object') derivedEntries = value.entries; }
175
+ catch { fail('E_STATE', 'Invalid derived entrypoint state.'); }
176
+ }
177
+ const stage = realpathSync(mkdtempSync(join(tmpdir(), 'agentdevkit-')));
178
+ try {
179
+ const existing = copyResources(join(target, '.pbai4devs'), join(stage, '.pbai4devs'));
180
+ const bundled = mode === 'init' || mode === 'update' ? copyResources(join(packageRoot, '.pbai4devs'), join(stage, '.pbai4devs')) : [];
181
+ const supplied = new Set(bundled);
182
+ const internal = new Set(['catalog.json', 'skills.json', 'agents.json', 'rules.json', 'espelhos.conf', '.gitignore', 'estado/README.md']);
183
+ if (bundled.length) for (const path of Object.keys(previous?.files || {})) {
184
+ if (path.startsWith('.pbai4devs/') && !supplied.has(path.slice(11)) && !internal.has(path.slice(11))) rmSync(safePath(stage, path), { force: true });
185
+ }
186
+ for (const root of active.roots) {
187
+ const content = read(target, `${root}/.gitignore`);
188
+ if (content) write(stage, `${root}/.gitignore`, content);
189
+ }
190
+ const ownIgnore = read(target, '.pbai4devs/.gitignore');
191
+ if (ownIgnore) write(stage, '.pbai4devs/.gitignore', ownIgnore);
192
+ writeAdapterManifest(stage, { clients: selected });
193
+ const synchronized = synchronize({ root: stage, force: true, localIgnores: false, generateEntrypoints: false, output() {} });
194
+ for (const name of active.entrypoints) {
195
+ if (protectedEntries.has(name)) continue;
196
+ const current = read(target, name), template = readFileSync(join(packageRoot, '.pbai4devs/templates/entrypoints', name), 'utf8');
197
+ const legacy = entryContent(null, template, language, name);
198
+ const content = legacy.replace(`${begin}\n`, '').replace(`\n${end}`, '');
199
+ const knownFile = current && (previous?.files[name] === hash(current) || derivedEntries[name] === hash(current));
200
+ const knownLegacy = current && previous?.blocks[name] && current.toString('utf8') === entryContent(null, template, previous.language, name);
201
+ if (!current || knownFile || knownLegacy) { write(stage, name, content); ownedEntrypoints.add(name); }
202
+ }
203
+ if (!read(target, 'README.md')) write(stage, 'README.md', `---\ndescription: ${JSON.stringify(text(language, 'readme'))}\nlanguage: ${language}\n---\n\n# ${text(language, 'project')}\n\n${text(language, 'readme')}\n`);
204
+ if (!existsSync(join(stage, '.pbai4devs/estado/README.md'))) write(stage, '.pbai4devs/estado/README.md', `---\ndescription: AgentDevKit state.\n---\n\n# AgentDevKit\n\n${text(language, 'state')}\n`);
205
+ const unknown = new Set(existing.filter(path => !supplied.has(path) && !previous?.files[`.pbai4devs/${path}`] && !internal.has(path)));
206
+ const paths = walk(stage, '', path => !path.split('/').includes('.agent-tests')).filter(path => !path.startsWith('.pbai4devs/') || !unknown.has(path.slice(11)));
207
+ const desired = new Map(paths.map(path => [path, readFileSync(join(stage, path))]));
208
+ const manifest = { schemaVersion: 1, version: bundled.length ? packageInfo.version : previous.version, language, files: {}, blocks: {} };
209
+ if (mode !== 'sync' || clients !== undefined || previous?.clients !== undefined) manifest.clients = selected;
210
+ for (const [path, content] of desired) {
211
+ if (path === 'README.md') continue;
212
+ const block = blockDigest(path, content);
213
+ if (block) manifest.blocks[path] = block;
214
+ else manifest.files[path] = hash(content);
215
+ }
216
+ desired.set(statePath, Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`));
217
+ const changes = [], conflicts = [...entryConflicts];
218
+ for (const [path, content] of desired) {
219
+ const current = read(target, path);
220
+ if (current?.equals(content)) continue;
221
+ const managed = previous?.blocks[path] ? blockDigest(path, current || Buffer.alloc(0)) === previous.blocks[path] : previous?.files[path] ? hash(current || '') === previous.files[path] : false;
222
+ const appendBlock = entryNames.includes(path) || path === '.gitignore' || path.endsWith('/.gitignore');
223
+ const conflict = current && path !== statePath && !managed && !appendBlock;
224
+ const changedBlock = current && previous?.blocks[path] && !managed;
225
+ if (conflict || changedBlock) conflicts.push(path);
226
+ changes.push({ path, action: current ? 'update' : 'create', content, beforeHash: current ? hash(current) : null });
227
+ }
228
+ for (const path of protectedEntries) {
229
+ const current = read(target, path);
230
+ changes.push({ path, action: 'update', content: current, beforeHash: hash(current) });
231
+ }
232
+ for (const [path, digest] of Object.entries(previous?.files || {})) if (!desired.has(path) && !protectedEntries.has(path)) {
233
+ const current = read(target, path); if (!current) continue;
234
+ if (hash(current) !== digest) conflicts.push(path);
235
+ changes.push({ path, action: 'remove', content: null, beforeHash: hash(current) });
236
+ }
237
+ for (const [path, digest] of Object.entries(previous?.blocks || {})) if (!desired.has(path)) {
238
+ if (path === '.gitignore') continue;
239
+ const current = read(target, path); if (!current) continue;
240
+ const source = current.toString('utf8');
241
+ const block = path === '.gitignore' ? extractBlock(source, '# BEGIN AGENTDEVKIT', '# END AGENTDEVKIT') : path.endsWith('/.gitignore') ? extractBlock(source, '# BEGIN AGENT IGNORE', '# END AGENT IGNORE') : extractBlock(source);
242
+ if (!block || hash(block) !== digest) conflicts.push(path);
243
+ if (!block) continue;
244
+ let content = source.replace(block, '');
245
+ if (entryNames.includes(path)) {
246
+ const template = readFileSync(join(packageRoot, '.pbai4devs/templates/entrypoints', path), 'utf8');
247
+ if (source === entryContent(null, template, previous.language, path)) content = '';
248
+ }
249
+ changes.push({ path, action: content.trim() ? 'update' : 'remove', content: content.trim() ? Buffer.from(content) : null, beforeHash: hash(current) });
250
+ }
251
+ for (const root of changingClients ? [] : active.roots) for (const path of walk(join(target, root), '', path => !path.split('/').some(part => ignored.has(part)))) {
252
+ if (!['skills', 'agents', 'commands', 'rules', 'instructions', 'prompts'].includes(path.split('/')[0])) continue;
253
+ const full = `${root}/${path}`; if (desired.has(full) || changes.some(change => change.path === full)) continue;
254
+ const current = read(target, full), source = current.toString('utf8');
255
+ if (!(source.includes('<!-- gerado: sincronizar-agentes -->') || source.startsWith('# gerado: sincronizar-agentes\n'))) continue;
256
+ if (!isReference(source)) conflicts.push(full);
257
+ changes.push({ path: full, action: 'remove', content: null, beforeHash: hash(current) });
258
+ }
259
+ const legacy = '.pbai4devs/adapters/README.md', legacyContent = read(target, legacy);
260
+ if (legacyContent) {
261
+ const known = legacyContent.toString('utf8').includes('# Adaptadores') && /Antigravity|metadados/.test(legacyContent.toString('utf8'));
262
+ if (!known) conflicts.push(legacy);
263
+ changes.push({ path: legacy, action: 'remove', content: null, beforeHash: hash(legacyContent) });
264
+ }
265
+ const retiredRoots = adapterRoots.filter(root => !active.roots.includes(root) && changes.some(change => change.action === 'remove' && change.path.startsWith(`${root}/`) && (previous?.files[change.path] || previous?.blocks[change.path])));
266
+ const ownedOutputs = [...new Set([...synchronized.ownedOutputs, ...ownedEntrypoints, statePath])];
267
+ const hashes = {};
268
+ for (const [path, digest] of Object.entries(previous?.files || {})) if ((ownedOutputs.includes(path) || !path.startsWith('.pbai4devs/')) && !protectedEntries.has(path)) hashes[path] = digest;
269
+ for (const path of ownedEntrypoints) { const current = read(target, path); if (current && (previous?.blocks[path] || derivedEntries[path] === hash(current))) hashes[path] = hash(current); }
270
+ for (const path of Object.keys(previous?.blocks || {})) if (path.endsWith('/.gitignore') && adapterRoots.some(root => path === `${root}/.gitignore`)) {
271
+ const current = read(target, path);
272
+ if (current) { const source = current.toString('utf8'), block = extractBlock(source, '# BEGIN AGENT IGNORE', '# END AGENT IGNORE'); if (block && source.trim() === block.trim() && hash(block) === previous.blocks[path]) hashes[path] = hash(current); }
273
+ }
274
+ if (previous) hashes[statePath] = hash(read(target, statePath));
275
+ const untrack = existsSync(target) ? planUntrack(target, hashes) : null;
276
+ const localIgnore = planLocalIgnore(target, { outputs: ownedOutputs, templateRoot: stage });
277
+ const localIgnoreCheck = checkLocalIgnore(localIgnore, { replacedBlocks: replacedIgnoreBlocks(target, changes, previous) });
278
+ conflicts.push(...(untrack?.conflicts || []), ...localIgnoreCheck.missing);
279
+ return { target, language, mode, changes, conflicts: [...new Set(conflicts)].sort(), canApply: (!conflicts.length || force) && !untrack?.conflicts?.length && !localIgnoreCheck.missing.length, manifest, retiredRoots, ownedOutputs, untrack, localIgnore, localIgnoreCheck };
280
+ } finally { rmSync(stage, { recursive: true, force: true }); }
281
+ }
282
+
283
+ export function applyPlan(plan) {
284
+ if (!plan.canApply) fail('E_CONFLICT', text(plan.language, 'conflict'));
285
+ assertLocalIgnoreUnchanged(plan.localIgnore);
286
+ const { target } = plan;
287
+ const backup = `.agent-tests/agentdevkit/backups/${Date.now()}-${randomUUID()}`;
288
+ safePath(target, backup);
289
+ for (const change of plan.changes) safePath(target, change.path);
290
+ const before = new Map(plan.changes.map(change => [change.path, read(target, change.path)]));
291
+ for (const change of plan.changes) if ((before.get(change.path) ? hash(before.get(change.path)) : null) !== change.beforeHash) fail('E_CHANGED', `File changed after planning: ${change.path}`);
292
+ for (const [path, content] of before) if (content) write(target, `${backup}/${path}`, content);
293
+ const applied = [];
294
+ let untracked = false;
295
+ try {
296
+ if (plan.untrack?.paths.length) { applyUntrack(plan.untrack); untracked = true; }
297
+ for (const change of plan.changes) {
298
+ const file = safePath(target, change.path);
299
+ if (change.content === null) rmSync(file, { force: true });
300
+ else {
301
+ mkdirSync(dirname(file), { recursive: true });
302
+ const temporary = `${file}.agentdevkit-${randomUUID()}`;
303
+ try { writeFileSync(temporary, change.content, { flag: 'wx' }); renameSync(temporary, file); }
304
+ finally { rmSync(temporary, { force: true }); }
305
+ }
306
+ applied.push(change.path);
307
+ }
308
+ pruneRemovedDirectories(plan);
309
+ const changesFallback = plan.changes.some(change => change.path === '.gitignore');
310
+ // Metadata is committed last; its writer rolls back partial writes itself.
311
+ const ignored = applyLocalIgnore(changesFallback ? planLocalIgnore(target, { outputs: plan.ownedOutputs }) : plan.localIgnore);
312
+ return { changed: Boolean(plan.changes.length || ignored.changed || untracked), backup: [...before.values()].some(Boolean) ? backup : null };
313
+ } catch (error) {
314
+ const rollbackErrors = [];
315
+ for (const path of applied.reverse()) {
316
+ const content = before.get(path);
317
+ try { if (content) write(target, path, content); else rmSync(safePath(target, path), { force: true }); }
318
+ catch (failure) { rollbackErrors.push(failure); }
319
+ }
320
+ if (untracked) try { restoreUntrack(plan.untrack); } catch (failure) { rollbackErrors.push(failure); }
321
+ if (rollbackErrors.length) throw Object.assign(new AggregateError([error, ...rollbackErrors], `${error.message}; rollback incompleto: ${rollbackErrors.map(failure => failure.message).join('; ')}`, { cause: error }), { code: error.code || 'E_OPERATION' });
322
+ throw error;
323
+ }
324
+ }
325
+
326
+ function pruneRemovedDirectories(plan) {
327
+ const { target } = plan;
328
+ const legacy = '.pbai4devs/adapters/README.md';
329
+ const removed = plan.changes.filter(change => change.action === 'remove' && (allowedManaged(change.path) || change.path === legacy));
330
+ const parents = new Set(removed.map(change => portable(dirname(change.path))));
331
+ if (removed.some(change => change.path === legacy)) {
332
+ parents.add('.pbai4devs/adapters/antigravity');
333
+ parents.add('.pbai4devs/adapters/antigravity/agents');
334
+ }
335
+ for (let parent of [...parents].sort((left, right) => right.length - left.length)) {
336
+ const boundary = parent.startsWith('.pbai4devs/') ? '.pbai4devs' : adapterRoots.find(root => parent.startsWith(`${root}/`));
337
+ while (boundary && parent.startsWith(`${boundary}/`)) {
338
+ const directory = safePath(target, parent);
339
+ if (!stat(directory)?.isDirectory() || readdirSync(directory).length) break;
340
+ try { rmdirSync(directory); }
341
+ catch (error) { if (['ENOENT', 'ENOTEMPTY', 'EEXIST'].includes(error.code)) break; throw error; }
342
+ parent = portable(dirname(parent));
343
+ }
344
+ }
345
+ for (const root of plan.retiredRoots || []) {
346
+ if (!adapterRoots.includes(root)) continue;
347
+ const directory = safePath(target, root);
348
+ if (!stat(directory)?.isDirectory()) continue;
349
+ try { if (readdirSync(directory).length === 0) rmdirSync(directory); }
350
+ catch (error) { if (!['ENOENT', 'ENOTEMPTY', 'EEXIST'].includes(error.code)) throw error; }
351
+ }
352
+ }
353
+
354
+ export function inspect(target) {
355
+ const state = loadState(target);
356
+ if (!state) return { installed: false, issues: [{ code: 'missing', path: statePath }] };
357
+ const issues = [];
358
+ for (const [path, digest] of Object.entries(state.files)) {
359
+ const content = read(target, path);
360
+ if (!content || hash(content) !== digest) issues.push({ code: content ? 'modified' : 'missing', path });
361
+ }
362
+ for (const [path, digest] of Object.entries(state.blocks)) {
363
+ const content = read(target, path);
364
+ if (!content || blockDigest(path, content) !== digest) issues.push({ code: content ? 'modified' : 'missing', path });
365
+ }
366
+ return { installed: true, version: state.version, language: state.language, issues };
367
+ }
package/src/next.mjs ADDED
@@ -0,0 +1,79 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { releaseCommand } from './config.mjs';
4
+ import { inspectProject } from '../.pbai4devs/scripts/inspecionar-projeto/SCRIPT.mjs';
5
+
6
+ const messages = {
7
+ pt: {
8
+ install: 'Instale o AgentDevKit neste projeto.', verify: 'Confira a instalação.',
9
+ configure: 'Conclua a preparação inicial.', prepare: 'Prepare o ambiente existente.',
10
+ prd: 'Defina ou conclua o PRD.', ux: 'Defina UX/UI ou justifique sua não aplicação.',
11
+ design: 'Conclua o design técnico.', technical: 'Conclua a configuração técnica.',
12
+ spec: 'Defina a próxima spec.', roadmap: 'Revise o roadmap e escolha o próximo incremento.',
13
+ inspect: 'Confira o estado do projeto antes de avançar.',
14
+ ask: 'Use a skill indicada no agente; confirme as decisões ainda pendentes.',
15
+ existing: 'Preserve código e decisões existentes; não reinicie a definição do produto.',
16
+ },
17
+ en: {
18
+ install: 'Install AgentDevKit in this project.', verify: 'Check the installation.',
19
+ configure: 'Complete the initial preparation.', prepare: 'Prepare the existing environment.',
20
+ prd: 'Define or complete the PRD.', ux: 'Define UX/UI or document why it does not apply.',
21
+ design: 'Complete the technical design.', technical: 'Complete the technical configuration.',
22
+ spec: 'Define the next spec.', roadmap: 'Review the roadmap and select the next increment.',
23
+ inspect: 'Inspect the project before proceeding.',
24
+ ask: 'Use the indicated skill in your agent; confirm outstanding decisions.',
25
+ existing: 'Preserve existing code and decisions; do not restart product discovery.',
26
+ },
27
+ es: {
28
+ install: 'Instale AgentDevKit en este proyecto.', verify: 'Compruebe la instalación.',
29
+ configure: 'Complete la preparación inicial.', prepare: 'Prepare el entorno existente.',
30
+ prd: 'Defina o complete el PRD.', ux: 'Defina UX/UI o justifique que no se aplica.',
31
+ design: 'Complete el diseño técnico.', technical: 'Complete la configuración técnica.',
32
+ spec: 'Defina la próxima spec.', roadmap: 'Revise el roadmap y elija el próximo incremento.',
33
+ inspect: 'Inspeccione el proyecto antes de continuar.',
34
+ ask: 'Use la skill indicada en su agente y confirme las decisiones pendientes.',
35
+ existing: 'Preserve el código y las decisiones existentes; no reinicie el producto.',
36
+ },
37
+ };
38
+
39
+ function quote(value, platform) {
40
+ return platform === 'win32' ? `'${String(value).replaceAll("'", "''")}'`
41
+ : `'${String(value).replaceAll("'", "'\\''")}'`;
42
+ }
43
+
44
+ function commandLine(args, platform) {
45
+ return (platform === 'win32' ? '& ' : '') + args.map(value => quote(value, platform)).join(' ');
46
+ }
47
+
48
+ function workflow(report) {
49
+ const state = report.maturity;
50
+ const app = state.signals.application;
51
+ if (app && (!state.configuration.present || !state.planning.ready)) return ['prepare', 'preparar-dev'];
52
+ if (state.configuration.preparacao !== 'concluido') return app ? ['prepare', 'preparar-dev'] : ['configure', 'configurar-projeto'];
53
+ if (state.planning.prd.status !== 'aprovado') return ['prd', 'criar-prd'];
54
+ if (!['aprovado', 'nao-aplicavel'].includes(state.planning.ux_ui.status)) return ['ux', 'criar-ux-ui'];
55
+ if (state.planning.design.status !== 'aprovado') return ['design', 'criar-design-doc'];
56
+ if (state.configuration.configuracao_tecnica !== 'concluido') return ['technical', 'configurar-projeto'];
57
+ if (app && !report.contract.complete) return ['prepare', 'preparar-dev'];
58
+ return state.level === 'manutencao' ? ['roadmap', 'gerenciar-roadmap'] : ['spec', 'criar-spec'];
59
+ }
60
+
61
+ export function getNextSteps({ command, target, language = 'pt', installed, platform = process.platform }) {
62
+ target = resolve(target || '.');
63
+ const text = messages[language] || messages.pt;
64
+ const cli = action => `${platform === 'win32' ? '& ' : ''}${releaseCommand} ${action} --target ${quote(target, platform)} --lang ${quote(language, platform)}`;
65
+ if (!installed) return [{ label: text.install, command: cli('init'), stage: 'instalacao' }];
66
+ const verification = { label: text.verify, command: cli('doctor'), stage: 'verificacao' };
67
+ let report;
68
+ try { report = inspectProject(target); }
69
+ catch { return [verification]; }
70
+ const [key, skill] = workflow(report);
71
+ const inspector = join(target, '.pbai4devs/scripts/inspecionar-projeto/SCRIPT.mjs');
72
+ const step = {
73
+ label: text[key],
74
+ command: existsSync(inspector) ? commandLine([process.execPath, inspector], platform) : cli('doctor'),
75
+ skill, stage: report.maturity.level,
76
+ instruction: `${text.ask}${key === 'prepare' ? ` ${text.existing}` : ''}`,
77
+ };
78
+ return ['init', 'update', 'sync', 'lang', 'agents', 'tools'].includes(command) ? [verification, step] : [step];
79
+ }