jarvis-ai-framework 2.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/AGENTS.md +14 -115
  2. package/agents/AGENTS.md +11 -23
  3. package/agents/README.md +27 -129
  4. package/agents/engineering/data/eng.data-engineer.agent.md +11 -34
  5. package/agents/engineering/eng.advisor.agent.md +56 -0
  6. package/agents/engineering/eng.agent.md +14 -24
  7. package/agents/engineering/eng.bug-hunter.md +7 -15
  8. package/agents/engineering/eng.dev-code-reviewer.md +1 -1
  9. package/agents/engineering/eng.frontend.agent.md +3 -7
  10. package/agents/engineering/eng.rpa.agent.md +2 -8
  11. package/agents/engineering/qa/eng.qa.quality-strategist.md +6 -11
  12. package/agents/engineering/qa/eng.qa.test-architect.md +8 -18
  13. package/agents/engineering/qa/eng.qa.test-planner.md +10 -14
  14. package/agents/engineering/qa/eng.qa.testing-engineer.md +91 -24
  15. package/agents/product/prod.discovery-interviewer.md +3 -3
  16. package/bin/README.md +142 -0
  17. package/bin/commands/docs-publish.js +105 -141
  18. package/bin/commands/docs-sync.js +66 -104
  19. package/bin/commands/info.js +7 -27
  20. package/bin/commands/init.js +23 -51
  21. package/bin/commands/install-rtk.js +9 -3
  22. package/bin/commands/list.js +5 -18
  23. package/bin/commands/map.js +20 -5
  24. package/bin/commands/qa-signoff.js +58 -55
  25. package/bin/commands/tokens.js +14 -17
  26. package/bin/commands/whoami.js +30 -26
  27. package/bin/jarvis.js +9 -163
  28. package/bin/lib/auth/session.js +20 -20
  29. package/bin/lib/cli/program.js +219 -0
  30. package/bin/lib/cli/shared-options.js +29 -0
  31. package/bin/lib/config/constants.js +59 -2
  32. package/bin/lib/config/ide-config.js +4 -8
  33. package/bin/lib/core/profile-filter.js +4 -1
  34. package/bin/lib/core/scanner.js +3 -29
  35. package/bin/lib/core/sync-engine.js +21 -14
  36. package/bin/lib/core/token-report.js +12 -2
  37. package/bin/lib/docs/fetch-file.js +39 -0
  38. package/bin/lib/docs/publish-file.js +194 -0
  39. package/bin/lib/docs/redis-cache.js +49 -0
  40. package/bin/lib/docs/validate-frontmatter.js +9 -39
  41. package/bin/lib/env-loader.js +11 -34
  42. package/bin/lib/flow-map/parse.js +11 -5
  43. package/bin/lib/flow-map/render.js +5 -2
  44. package/bin/lib/flow-map/tree.js +59 -10
  45. package/bin/lib/tasks/comment.js +40 -35
  46. package/bin/lib/utils/frontmatter.js +57 -0
  47. package/bin/lib/utils/git-parser.js +4 -6
  48. package/bin/lib/utils/npmrc-parser.js +6 -13
  49. package/bin/lib/utils/paths.js +2 -4
  50. package/bin/lib/utils/ui.js +3 -9
  51. package/bin/lib/vcs/api.js +25 -41
  52. package/bin/lib/vcs/create-issue.js +49 -33
  53. package/bin/lib/vcs/create-merge.js +47 -31
  54. package/bin/lib/vcs/fetch-raw.js +35 -23
  55. package/package.json +14 -5
  56. package/rules/engineering/eng-rules.md +1 -1
  57. package/rules/engineering/eng-security-rules.md +18 -16
  58. package/rules/engineering/eng.bump-rules.md +3 -2
  59. package/rules/engineering/eng.docs-scraping-rules.md +4 -4
  60. package/rules/engineering/eng.integrations-rules.md +6 -4
  61. package/rules/engineering/eng.skills-rules.md +1 -1
  62. package/rules/engineering/eng.specializations-rules.md +18 -4
  63. package/rules/engineering/frontend/eng.frontend-rules.md +1 -4
  64. package/rules/engineering/qa/eng.qa.cypress-standards-rules.md +1 -1
  65. package/rules/engineering/rpa/eng.rpa-rules.md +4 -9
  66. package/rules-on-demand/engineering/eng.pre-pr-rules.md +1 -1
  67. package/rules-on-demand/engineering/eng.start-rules.md +2 -0
  68. package/skills/AGENTS.md +52 -87
  69. package/skills/SKILLS-ROADMAP.md +47 -128
  70. package/skills/eng-ai/SKILL.md +270 -0
  71. package/skills/eng-ai/references/1-fundamentos-ml.md +24 -0
  72. package/skills/eng-ai/references/10-arquitetura-solucoes-ia.md +24 -0
  73. package/skills/eng-ai/references/11-governanca-ia.md +24 -0
  74. package/skills/eng-ai/references/12-seguranca-ia-responsavel.md +25 -0
  75. package/skills/eng-ai/references/2-matematica-estatistica.md +24 -0
  76. package/skills/eng-ai/references/3-dados-para-ia.md +24 -0
  77. package/skills/eng-ai/references/4-deep-learning-fundacionais.md +24 -0
  78. package/skills/eng-ai/references/5-llms-chatbots-agentes-rag.md +25 -0
  79. package/skills/eng-ai/references/6-avaliacao-experimentacao.md +24 -0
  80. package/skills/eng-ai/references/7-engenharia-sistemas-ia.md +24 -0
  81. package/skills/eng-ai/references/8-mlops-plataforma.md +24 -0
  82. package/skills/eng-ai/references/9-produto-ia.md +24 -0
  83. package/skills/eng-ai/references/especializacoes.md +17 -0
  84. package/skills/eng-automation/SKILL.md +290 -0
  85. package/skills/eng-automation/references/1-fundamentos-automacao.md +25 -0
  86. package/skills/eng-automation/references/10-ingestao-dados.md +25 -0
  87. package/skills/eng-automation/references/11-captcha-antibot.md +25 -0
  88. package/skills/eng-automation/references/12-limites-taxa-sessoes.md +25 -0
  89. package/skills/eng-automation/references/13-agendamento-orquestracao.md +24 -0
  90. package/skills/eng-automation/references/14-retentativa-erros.md +25 -0
  91. package/skills/eng-automation/references/15-autenticacao-credenciais.md +24 -0
  92. package/skills/eng-automation/references/16-observabilidade-confiabilidade.md +24 -0
  93. package/skills/eng-automation/references/2-aquisicao-dados.md +25 -0
  94. package/skills/eng-automation/references/3-automacao-navegador.md +24 -0
  95. package/skills/eng-automation/references/4-scraping-crawling.md +25 -0
  96. package/skills/eng-automation/references/5-apis-rest-graphql-soap.md +26 -0
  97. package/skills/eng-automation/references/6-webhooks-integracao.md +25 -0
  98. package/skills/eng-automation/references/7-rpa.md +25 -0
  99. package/skills/eng-automation/references/8-extracao-estruturada.md +25 -0
  100. package/skills/eng-automation/references/9-extracao-documentos.md +25 -0
  101. package/skills/eng-automation/references/especializacoes.md +18 -0
  102. package/skills/eng-backend-nestjs/SKILL.md +1 -1
  103. package/skills/eng-data/SKILL.md +271 -0
  104. package/skills/eng-data/references/1-fundamentos-dados.md +24 -0
  105. package/skills/eng-data/references/10-ciencia-dados.md +24 -0
  106. package/skills/eng-data/references/11-dataops-plataforma.md +24 -0
  107. package/skills/eng-data/references/12-seguranca-privacidade.md +24 -0
  108. package/skills/eng-data/references/2-modelagem-dados.md +24 -0
  109. package/skills/eng-data/references/3-bancos-dados.md +24 -0
  110. package/skills/eng-data/references/4-arquitetura-dados.md +24 -0
  111. package/skills/eng-data/references/5-pipelines-integracao.md +24 -0
  112. package/skills/eng-data/references/6-qualidade-dados.md +24 -0
  113. package/skills/eng-data/references/7-governanca-metadados.md +24 -0
  114. package/skills/eng-data/references/8-estatistica-analise.md +24 -0
  115. package/skills/eng-data/references/9-analytics-bi.md +24 -0
  116. package/skills/eng-data/references/especializacoes.md +20 -0
  117. package/skills/eng-frontend/SKILL.md +12 -5
  118. package/skills/eng-frontend/references/13-design-system.md +48 -0
  119. package/skills/eng-frontend/references/14-microfrontend.md +46 -0
  120. package/skills/eng-global-task-comment/SKILL.md +3 -3
  121. package/skills/eng-platform/SKILL.md +331 -0
  122. package/skills/eng-platform/references/1-fundamentos-sistemas.md +23 -0
  123. package/skills/eng-platform/references/10-resiliencia-arquitetura.md +24 -0
  124. package/skills/eng-platform/references/11-plataforma-devex.md +24 -0
  125. package/skills/eng-platform/references/12-finops-custos.md +24 -0
  126. package/skills/eng-platform/references/13-seguranca-fundamentos.md +26 -0
  127. package/skills/eng-platform/references/14-profiling-performance.md +23 -0
  128. package/skills/eng-platform/references/15-testes-carga-chaos.md +23 -0
  129. package/skills/eng-platform/references/16-cache-multicamada.md +22 -0
  130. package/skills/eng-platform/references/2-redes.md +23 -0
  131. package/skills/eng-platform/references/3-cloud.md +24 -0
  132. package/skills/eng-platform/references/4-iac-automacao.md +24 -0
  133. package/skills/eng-platform/references/5-containers-orquestracao.md +25 -0
  134. package/skills/eng-platform/references/6-cicd-entrega.md +24 -0
  135. package/skills/eng-platform/references/7-observabilidade.md +24 -0
  136. package/skills/eng-platform/references/8-confiabilidade-sre.md +24 -0
  137. package/skills/eng-platform/references/9-seguranca-infra.md +26 -0
  138. package/skills/eng-platform/references/especializacoes.md +34 -0
  139. package/skills/eng-qa/SKILL.md +283 -0
  140. package/skills/eng-qa/references/1-fundamentos-qualidade.md +25 -0
  141. package/skills/eng-qa/references/10-confiabilidade.md +25 -0
  142. package/skills/eng-qa/references/11-seguranca.md +24 -0
  143. package/skills/eng-qa/references/12-acessibilidade.md +24 -0
  144. package/skills/eng-qa/references/13-dados-testes.md +24 -0
  145. package/skills/eng-qa/references/14-gestao-testes-defeitos.md +25 -0
  146. package/skills/eng-qa/references/15-arquitetura-qa.md +25 -0
  147. package/skills/eng-qa/references/2-estrategia-planejamento.md +25 -0
  148. package/skills/eng-qa/references/3-design-testes.md +25 -0
  149. package/skills/eng-qa/references/4-manual-exploratorio.md +24 -0
  150. package/skills/eng-qa/references/5-automacao-testes.md +25 -0
  151. package/skills/eng-qa/references/6-api-integracao.md +25 -0
  152. package/skills/eng-qa/references/7-contrato.md +24 -0
  153. package/skills/eng-qa/references/8-interface-compat-mobile.md +24 -0
  154. package/skills/eng-qa/references/9-performance.md +24 -0
  155. package/skills/eng-qa/references/especializacoes.md +29 -0
  156. package/skills/eng-qa-planner/SKILL.md +264 -0
  157. package/skills/jarvis-context-detect/SKILL.md +1 -1
  158. package/skills/jarvis-context-detect/assets/context-profile-template.md +1 -1
  159. package/skills/jarvis-create-specialization/SKILL.md +8 -0
  160. package/skills/jarvis-docs-central/README.md +31 -28
  161. package/skills/jarvis-docs-central/SKILL.md +5 -5
  162. package/skills/jarvis-init/SKILL.md +9 -8
  163. package/skills/jarvis-init/assets/passo-adicionar-stacks.md +47 -18
  164. package/skills/jarvis-list-specializations/SKILL.md +30 -17
  165. package/skills/jarvis-report-issue/SKILL.md +1 -1
  166. package/taxonomy.md +4 -16
  167. package/templates/AGENTS.md +2 -0
  168. package/templates/ENV-template.md +20 -2
  169. package/templates/engineering/advisor-template.md +65 -0
  170. package/templates/engineering/architecture-template.md +52 -4
  171. package/templates/engineering/qa/qa.sprint-plan-template.md +1 -1
  172. package/workflows/AGENTS.md +3 -1
  173. package/workflows/README.md +0 -10
  174. package/workflows/engineering/data/data.new-pipeline.md +6 -5
  175. package/workflows/engineering/eng.bug-audit.md +4 -14
  176. package/workflows/engineering/eng.debug.md +4 -20
  177. package/workflows/engineering/eng.plan.md +4 -26
  178. package/workflows/engineering/eng.pr.md +13 -63
  179. package/workflows/engineering/eng.pre-pr.md +14 -51
  180. package/workflows/engineering/eng.review.md +7 -13
  181. package/workflows/engineering/eng.rpa.robot.md +3 -9
  182. package/workflows/engineering/eng.start.md +37 -32
  183. package/workflows/engineering/eng.work.md +17 -40
  184. package/workflows/engineering/qa/eng.qa-sprint-planning.md +1 -1
  185. package/workflows/product/prod.spec.discovery.md +2 -2
  186. package/workflows/warm-up.md +35 -63
  187. package/agents/engineering/eng.cybersecurity.agent.md +0 -486
  188. package/agents/engineering/qa/eng.qa.cypress-specialist.md +0 -112
  189. package/bin/lib/docs/fetch-file.sh +0 -41
  190. package/bin/lib/docs/publish-file.sh +0 -284
  191. package/rules/engineering/qa/eng.qa.exploratory-session-rules.md +0 -137
  192. package/rules/engineering/qa/eng.qa.quality-gate-scoring-rules.md +0 -181
  193. package/rules/engineering/qa/eng.qa.tech-spec-validation-criteria-rules.md +0 -120
  194. package/skills/eng-ai-engineer/SKILL.md +0 -303
  195. package/skills/eng-data-bi/SKILL.md +0 -206
  196. package/skills/eng-data-debug/SKILL.md +0 -314
  197. package/skills/eng-data-engineer/SKILL.md +0 -266
  198. package/skills/eng-data-onboard/SKILL.md +0 -317
  199. package/skills/eng-data-orchestrator/SKILL.md +0 -433
  200. package/skills/eng-devops-performance-engineer/SKILL.md +0 -319
  201. package/skills/eng-frontend-design-system/SKILL.md +0 -155
  202. package/skills/eng-frontend-design-system/references/1-estrutura-pacote.md +0 -57
  203. package/skills/eng-frontend-design-system/references/2-tokens.md +0 -116
  204. package/skills/eng-frontend-design-system/references/3-componentes.md +0 -165
  205. package/skills/eng-frontend-design-system/references/4-storybook.md +0 -85
  206. package/skills/eng-frontend-design-system/references/5-auditoria-versionamento.md +0 -76
  207. package/skills/eng-frontend-microfrontend/SKILL.md +0 -164
  208. package/skills/eng-frontend-microfrontend/references/1-criando-remote.md +0 -109
  209. package/skills/eng-frontend-microfrontend/references/2-configurando-shell.md +0 -70
  210. package/skills/eng-frontend-microfrontend/references/3-contratos-interface.md +0 -73
  211. package/skills/eng-frontend-microfrontend/references/4-shared-dependencies.md +0 -48
  212. package/skills/eng-frontend-microfrontend/references/5-event-bus.md +0 -59
  213. package/skills/eng-frontend-microfrontend/references/6-monorepo-deploy.md +0 -77
  214. package/skills/eng-frontend-microfrontend/references/7-troubleshooting.md +0 -45
  215. package/skills/eng-global-browser-extension-builder/SKILL.md +0 -392
  216. package/skills/eng-global-jira-comment/SKILL.md +0 -27
  217. package/skills/eng-qa-a11y-audit/SKILL.md +0 -276
  218. package/skills/eng-qa-bug-report/SKILL.md +0 -877
  219. package/skills/eng-qa-bug-report/TASK_MANAGERS.md +0 -138
  220. package/skills/eng-qa-bug-report/references/1-integracao-task-managers.md +0 -148
  221. package/skills/eng-qa-bug-report/references/2-exemplos-de-uso.md +0 -46
  222. package/skills/eng-qa-bug-report/references/3-bug-to-test.md +0 -45
  223. package/skills/eng-qa-cypress-e2e/SKILL.md +0 -184
  224. package/skills/eng-qa-dev-guide/SKILL.md +0 -173
  225. package/skills/eng-qa-e2e/SKILL.md +0 -407
  226. package/skills/eng-qa-e2e-spec-writer/SKILL.md +0 -329
  227. package/skills/eng-qa-exploratory/SKILL.md +0 -196
  228. package/skills/eng-qa-gate/SKILL.md +0 -377
  229. package/skills/eng-qa-gate/assets/checklist-validacao.md +0 -291
  230. package/skills/eng-qa-graphql-contract/SKILL.md +0 -263
  231. package/skills/eng-qa-quality-report/SKILL.md +0 -419
  232. package/skills/eng-qa-test-plan/SKILL.md +0 -473
  233. package/skills/eng-qa-testsprite/SKILL.md +0 -332
  234. package/skills/eng-qa-testsprite/references/testsprite-mcp.md +0 -224
  235. package/skills/eng-qa-unit-test/SKILL.md +0 -478
  236. package/skills/eng-scraper/SKILL.md +0 -260
  237. package/skills/eng-scraper/references/1-puppeteer.md +0 -140
  238. package/skills/eng-scraper/references/2-playwright-cheerio-pdf.md +0 -82
  239. package/skills/eng-scraper/references/3-anti-bot.md +0 -94
  240. package/skills/eng-scraper/references/4-resiliencia-etl-monitoramento.md +0 -137
  241. package/skills/eng-scraper-robot-builder/SKILL.md +0 -377
  242. package/skills/eng-security-cybersecurity/SKILL.md +0 -250
  243. package/skills/eng-security-cybersecurity/references/1-owasp-top-10.md +0 -331
  244. package/skills/eng-security-cybersecurity/references/2-secrets-management.md +0 -31
  245. package/skills/eng-security-cybersecurity/references/3-input-validation.md +0 -43
  246. package/skills/eng-security-cybersecurity/references/4-compliance.md +0 -20
  247. package/skills/eng-security-patch/SKILL.md +0 -388
  248. package/skills/eng-security-threat-model/SKILL.md +0 -171
  249. package/skills/eng-security-triage/SKILL.md +0 -276
  250. package/templates/engineering/qa/eng.qa.quality-gate-examples-template.md +0 -311
  251. package/templates/engineering/qa/eng.qa.quality-gate-report-template.md +0 -249
  252. package/templates/engineering/qa/qa.cypress-test-template.md +0 -172
  253. package/templates/engineering/qa/qa.exploratory-session-template.md +0 -148
  254. package/templates/engineering/qa/qa.quality-report-template.md +0 -130
  255. package/workflows/engineering/eng.security-audit.md +0 -319
  256. package/workflows/engineering/eng.security-incident.md +0 -281
  257. package/workflows/engineering/eng.security-pipeline.md +0 -219
  258. package/workflows/engineering/eng.security-review.md +0 -241
  259. package/workflows/engineering/qa/eng.qa-dev-quality-guide.md +0 -57
  260. package/workflows/engineering/qa/eng.qa-e2e-test-generation.md +0 -57
  261. package/workflows/engineering/qa/eng.qa-exploratory-session.md +0 -68
  262. package/workflows/engineering/qa/eng.qa-quality-gate-validation.md +0 -209
  263. package/workflows/engineering/qa/eng.qa-quality-report.md +0 -85
  264. /package/skills/{eng-qa-test-plan → eng-qa-planner}/assets/test-coverage-template.md +0 -0
  265. /package/skills/{eng-qa-test-plan → eng-qa-planner}/assets/test-patterns.md +0 -0
  266. /package/templates/{CDD aplicado a Prompts.md → cdd-aplicado-a-prompts.md} +0 -0
@@ -48,7 +48,8 @@ function describe(node) {
48
48
  export function renderTree(root) {
49
49
  const lines = [describe(root)];
50
50
  if (root.status === "selfContained") lines.push("└── (autocontido: não chama nenhum outro item)");
51
- else if (root.status === "undeclared") lines.push("└── (sem declaração de chamadas: o item não segue a tabela padronizada)");
51
+ else if (root.status === "undeclared")
52
+ lines.push("└── (sem declaração de chamadas: o item não segue a tabela padronizada)");
52
53
 
53
54
  function walk(node, prefix) {
54
55
  node.children.forEach((child, i) => {
@@ -80,7 +81,9 @@ export function renderReverse(name, type, edges) {
80
81
  const condition = summarizeCondition(e.condicao);
81
82
  if (condition) notes.push(condition);
82
83
  if (e.via) notes.push(`via ${e.via}`);
83
- lines.push(`${i === edges.length - 1 ? "└── " : "├── "}${e.from} [${TYPE_LABEL[e.type]}]${notes.length ? ` (${notes.join("; ")})` : ""}`);
84
+ lines.push(
85
+ `${i === edges.length - 1 ? "└── " : "├── "}${e.from} [${TYPE_LABEL[e.type]}]${notes.length ? ` (${notes.join("; ")})` : ""}`
86
+ );
84
87
  });
85
88
  return lines;
86
89
  }
@@ -53,7 +53,16 @@ export function forwardTree(graph, name, opts = {}) {
53
53
  const expanded = new Set([name]);
54
54
 
55
55
  function base(partial) {
56
- return { passo: null, condicao: "", via: null, marker: null, available: false, status: null, children: [], ...partial };
56
+ return {
57
+ passo: null,
58
+ condicao: "",
59
+ via: null,
60
+ marker: null,
61
+ available: false,
62
+ status: null,
63
+ children: [],
64
+ ...partial,
65
+ };
57
66
  }
58
67
 
59
68
  function childrenOf(itemName, level, ancestors) {
@@ -61,12 +70,22 @@ export function forwardTree(graph, name, opts = {}) {
61
70
  const children = [];
62
71
  for (const row of d.rows) {
63
72
  if (row.targets.length === 0) continue;
64
- const grouped = row.targets.filter((t) => t.kind === "internal" || t.kind === "agent").length > 1;
73
+ const grouped =
74
+ row.targets.filter((t) => t.kind === "internal" || t.kind === "agent").length > 1;
65
75
  // Em menu, a condição fica no nó do menu e não se repete em cada alvo.
66
- const nodes = row.targets.map((t) => targetNode(t, grouped ? { ...row, condicao: "", via: null } : row, level + 1, ancestors));
76
+ const nodes = row.targets.map((t) =>
77
+ targetNode(t, grouped ? { ...row, condicao: "", via: null } : row, level + 1, ancestors)
78
+ );
67
79
  if (grouped) {
68
80
  children.push(
69
- base({ name: `menu (${nodes.length} opções)`, kind: "menu", passo: row.passo, condicao: row.condicao, via: row.via, children: nodes }),
81
+ base({
82
+ name: `menu (${nodes.length} opções)`,
83
+ kind: "menu",
84
+ passo: row.passo,
85
+ condicao: row.condicao,
86
+ via: row.via,
87
+ children: nodes,
88
+ })
70
89
  );
71
90
  } else {
72
91
  children.push(...nodes);
@@ -76,13 +95,25 @@ export function forwardTree(graph, name, opts = {}) {
76
95
  }
77
96
 
78
97
  function targetNode(target, row, level, ancestors) {
79
- const common = { passo: row.passo, condicao: row.condicao, via: row.via, marker: row.marker, available: row.available };
98
+ const common = {
99
+ passo: row.passo,
100
+ condicao: row.condicao,
101
+ via: row.via,
102
+ marker: row.marker,
103
+ available: row.available,
104
+ };
80
105
 
81
106
  if (["cli", "mcp", "external", "unresolved"].includes(target.kind)) {
82
107
  return base({ name: target.name, kind: target.kind, ...common });
83
108
  }
84
109
  const item = graph.items.get(target.name);
85
- if (!item) return base({ name: target.name, kind: "broken", ...common, marker: row.marker ?? "quebrada" });
110
+ if (!item)
111
+ return base({
112
+ name: target.name,
113
+ kind: "broken",
114
+ ...common,
115
+ marker: row.marker ?? "quebrada",
116
+ });
86
117
 
87
118
  const node = base({ name: item.name, kind: item.type, ...common });
88
119
  if (ancestors.has(item.name)) node.status = "cycle";
@@ -132,7 +163,14 @@ export function suggest(items, name) {
132
163
  return [...items.keys()]
133
164
  .map((candidate) => {
134
165
  const c = candidate.toLowerCase();
135
- const score = c.startsWith(lower) || lower.startsWith(c) ? 0 : c.includes(lower) || lower.includes(c) ? 1 : levenshtein(lower, c) <= Math.max(1, Math.floor(Math.min(lower.length, c.length) / 4)) ? 2 : null;
166
+ const score =
167
+ c.startsWith(lower) || lower.startsWith(c)
168
+ ? 0
169
+ : c.includes(lower) || lower.includes(c)
170
+ ? 1
171
+ : levenshtein(lower, c) <= Math.max(1, Math.floor(Math.min(lower.length, c.length) / 4))
172
+ ? 2
173
+ : null;
136
174
  return { candidate, score };
137
175
  })
138
176
  .filter((s) => s.score !== null)
@@ -152,7 +190,9 @@ export function reverseEdges(graph, name) {
152
190
  for (const [from, d] of graph.decl) {
153
191
  if (from === name) continue;
154
192
  for (const row of d.rows) {
155
- if (row.targets.some((t) => (t.kind === "internal" || t.kind === "agent") && t.name === name)) {
193
+ if (
194
+ row.targets.some((t) => (t.kind === "internal" || t.kind === "agent") && t.name === name)
195
+ ) {
156
196
  edges.push({
157
197
  from,
158
198
  type: graph.items.get(from).type,
@@ -186,7 +226,12 @@ export function findBrokenReferences(graph) {
186
226
  warnings.push({ file, name: t.name, reason: `referência ${row.marker}` });
187
227
  } else if ((t.kind === "internal" || t.kind === "agent") && !graph.items.has(t.name)) {
188
228
  if (row.marker) warnings.push({ file, name: t.name, reason: `referência ${row.marker}` });
189
- else errors.push({ file, name: t.name, reason: "não existe como workflow, skill ou agente" });
229
+ else
230
+ errors.push({
231
+ file,
232
+ name: t.name,
233
+ reason: "não existe como workflow, skill ou agente",
234
+ });
190
235
  }
191
236
  }
192
237
  }
@@ -195,5 +240,9 @@ export function findBrokenReferences(graph) {
195
240
  }
196
241
 
197
242
  function duplicatesOf(graph) {
198
- return graph.duplicates.map((name) => ({ file: name, name, reason: "nome repetido entre os artefatos" }));
243
+ return graph.duplicates.map((name) => ({
244
+ file: name,
245
+ name,
246
+ reason: "nome repetido entre os artefatos",
247
+ }));
199
248
  }
@@ -1,3 +1,4 @@
1
+ import { fileURLToPath } from "node:url";
1
2
  import { cardUrl } from "../vcs/api.js";
2
3
 
3
4
  function env(name) {
@@ -13,9 +14,7 @@ async function commentJira(cardKey, message) {
13
14
  const token = env("TOKEN_TASK_MANAGER");
14
15
  const email = env("USER");
15
16
  if (!base || !token) {
16
- throw new Error(
17
- "Jira: preencha TASK_MANAGER_URL_BASE e TOKEN_TASK_MANAGER no ENV.md",
18
- );
17
+ throw new Error("Jira: preencha TASK_MANAGER_URL_BASE e TOKEN_TASK_MANAGER no ENV.md");
19
18
  }
20
19
  const auth = email
21
20
  ? `Basic ${Buffer.from(`${email}:${token}`).toString("base64")}`
@@ -68,28 +67,24 @@ async function commentLinear(cardKey, message) {
68
67
  }
69
68
 
70
69
  async function commentGithub(cardKey, message) {
71
- const token =
72
- env("TOKEN_TASK_MANAGER") || env("GITHUB_TOKEN") || env("GH_TOKEN");
70
+ const token = env("TOKEN_TASK_MANAGER") || env("GITHUB_TOKEN") || env("GH_TOKEN");
73
71
  const base = env("TASK_MANAGER_URL_BASE").replace(/\/$/, "");
74
72
  if (!token || !base) {
75
73
  throw new Error(
76
- "GitHub Issues: TASK_MANAGER_URL_BASE (https://github.com/org/repo) e TOKEN_TASK_MANAGER/GITHUB_TOKEN",
74
+ "GitHub Issues: TASK_MANAGER_URL_BASE (https://github.com/org/repo) e TOKEN_TASK_MANAGER/GITHUB_TOKEN"
77
75
  );
78
76
  }
79
77
  const path = new URL(base).pathname.replace(/^\/+|\/+$/g, "");
80
78
  const number = String(cardKey).replace(/^#/, "");
81
- const res = await fetch(
82
- `https://api.github.com/repos/${path}/issues/${number}/comments`,
83
- {
84
- method: "POST",
85
- headers: {
86
- Authorization: `Bearer ${token}`,
87
- Accept: "application/vnd.github+json",
88
- "Content-Type": "application/json",
89
- },
90
- body: JSON.stringify({ body: message }),
79
+ const res = await fetch(`https://api.github.com/repos/${path}/issues/${number}/comments`, {
80
+ method: "POST",
81
+ headers: {
82
+ Authorization: `Bearer ${token}`,
83
+ Accept: "application/vnd.github+json",
84
+ "Content-Type": "application/json",
91
85
  },
92
- );
86
+ body: JSON.stringify({ body: message }),
87
+ });
93
88
  if (!res.ok) throw new Error(`GitHub ${res.status}: ${await res.text()}`);
94
89
  }
95
90
 
@@ -107,25 +102,35 @@ async function commentAsana(cardKey, message) {
107
102
  if (!res.ok) throw new Error(`Asana ${res.status}: ${await res.text()}`);
108
103
  }
109
104
 
110
- const cardKey = process.argv[2];
111
- const message = process.argv.slice(3).join(" ");
105
+ /**
106
+ * Comenta num card do task manager configurado em TASK_MANAGER (jira/linear/github/asana).
107
+ * Usada por `jarvis tasks comment` e pelo skill `eng-global-task-comment`.
108
+ * @param {string} cardKey - Chave/ID do card (ex: `TASK-123`, ou número de issue no GitHub)
109
+ * @param {string} message - Texto do comentário
110
+ */
111
+ export async function runComment(cardKey, message) {
112
+ if (!cardKey || !message) {
113
+ console.error("Uso: jarvis tasks comment <TASK_MANAGER_KEY> <mensagem>");
114
+ process.exit(1);
115
+ }
116
+
117
+ const tm = taskManager();
118
+ try {
119
+ if (tm === "linear") await commentLinear(cardKey, message);
120
+ else if (tm === "github") await commentGithub(cardKey, message);
121
+ else if (tm === "asana") await commentAsana(cardKey, message);
122
+ else await commentJira(cardKey, message);
112
123
 
113
- if (!cardKey || !message) {
114
- console.error("Uso: comment.js <TASK_MANAGER_KEY> <mensagem>");
115
- process.exit(1);
124
+ const url = cardUrl(tm, env("TASK_MANAGER_URL_BASE"), cardKey);
125
+ console.log(`💬 Comentário adicionado em ${cardKey} (${tm})`);
126
+ if (url !== cardKey) console.log(` ${url}`);
127
+ } catch (err) {
128
+ console.error(`⚠️ Não foi possível comentar no card ${cardKey}: ${err.message}`);
129
+ process.exit(2);
130
+ }
116
131
  }
117
132
 
118
- const tm = taskManager();
119
- try {
120
- if (tm === "linear") await commentLinear(cardKey, message);
121
- else if (tm === "github") await commentGithub(cardKey, message);
122
- else if (tm === "asana") await commentAsana(cardKey, message);
123
- else await commentJira(cardKey, message);
124
-
125
- const url = cardUrl(tm, env("TASK_MANAGER_URL_BASE"), cardKey);
126
- console.log(`💬 Comentário adicionado em ${cardKey} (${tm})`);
127
- if (url !== cardKey) console.log(` ${url}`);
128
- } catch (err) {
129
- console.error(`⚠️ Não foi possível comentar no card ${cardKey}: ${err.message}`);
130
- process.exit(2);
133
+ // Compatibilidade: continua funcionando como `node bin/lib/tasks/comment.js <key> <mensagem>`
134
+ if (fileURLToPath(import.meta.url) === process.argv[1]) {
135
+ await runComment(process.argv[2], process.argv.slice(3).join(" "));
131
136
  }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Leitura de frontmatter YAML (`---\n...\n---`) compartilhada
3
+ * entre scanner.js, validate-frontmatter.js, qa-signoff.js e sync-engine.js —
4
+ * cada um tinha sua própria cópia da mesma regex de bloco.
5
+ * @module utils/frontmatter
6
+ */
7
+
8
+ const BLOCK_PATTERN = /^---\s*\n([\s\S]*?)\n---/;
9
+
10
+ // Exige a chave começando na coluna 0 (sem indentação) — por design, não
11
+ // desce em blocos aninhados (ex: `metadata:\n area: x`). As 4 implementações
12
+ // que este módulo substitui já assumiam isso (`^\w`, sem flag multiline por
13
+ // linha); manter a mesma regra evita "vazar" uma chave aninhada como se fosse
14
+ // de nível raiz.
15
+ // Unicode-aware (`u` flag) para aceitar chaves acentuadas, como "Versão" e
16
+ // "Autor" usadas no frontmatter de ARD/RFC.
17
+ const KEY_VALUE_PATTERN = /^([\p{L}\p{N}_][\p{L}\p{N}_-]*):\s*(.+)$/u;
18
+
19
+ /**
20
+ * Extrai o conteúdo bruto entre as cercas `---` do frontmatter.
21
+ * @param {string} content - Conteúdo completo do arquivo
22
+ * @returns {string | null} O bloco (sem as cercas), ou null se não houver frontmatter
23
+ */
24
+ export function extractFrontmatterBlock(content) {
25
+ const match = content.match(BLOCK_PATTERN);
26
+ return match ? match[1] : null;
27
+ }
28
+
29
+ /**
30
+ * Parseia um bloco de frontmatter YAML simples (`chave: valor`, uma por linha,
31
+ * sem indentação). Não suporta estruturas aninhadas, listas ou blocos
32
+ * multilinha (`>`/`|`) — para isso, veja `sync-engine.js#parseSkillFrontmatter`,
33
+ * que extrai campos específicos com necessidades diferentes.
34
+ * @param {string} content - Conteúdo completo do arquivo (com ou sem frontmatter)
35
+ * @returns {Record<string, string>} Metadados; `{}` se não houver frontmatter
36
+ */
37
+ export function parseFrontmatter(content) {
38
+ const block = extractFrontmatterBlock(content);
39
+ if (block === null) return {};
40
+
41
+ const metadata = {};
42
+ for (const line of block.split("\n")) {
43
+ const kv = line.match(KEY_VALUE_PATTERN);
44
+ if (!kv) continue;
45
+
46
+ let value = kv[2].trim();
47
+ if (
48
+ (value.startsWith('"') && value.endsWith('"')) ||
49
+ (value.startsWith("'") && value.endsWith("'"))
50
+ ) {
51
+ value = value.slice(1, -1);
52
+ }
53
+
54
+ metadata[kv[1]] = value;
55
+ }
56
+ return metadata;
57
+ }
@@ -67,7 +67,7 @@ export function parseRepoUrl(url) {
67
67
  } catch {
68
68
  throw new Error(
69
69
  `URL inválida: ${url}\n` +
70
- "Formatos: https://github.com/org/repo.git | https://gitlab.com/grupo/repo.git | https://bitbucket.org/ws/repo.git",
70
+ "Formatos: https://github.com/org/repo.git | https://gitlab.com/grupo/repo.git | https://bitbucket.org/ws/repo.git"
71
71
  );
72
72
  }
73
73
 
@@ -82,7 +82,7 @@ export function parseRepoUrl(url) {
82
82
  if (!vendor) {
83
83
  throw new Error(
84
84
  `Não foi possível detectar o vendor de ${host}.\n` +
85
- "Defina VERSION_CONTROL=gitlab|github|bitbucket no ENV.md.",
85
+ "Defina VERSION_CONTROL=gitlab|github|bitbucket no ENV.md."
86
86
  );
87
87
  }
88
88
 
@@ -108,16 +108,14 @@ export function parseGitLabUrl(url) {
108
108
  const parsed = parseRepoUrl(url);
109
109
  if (parsed.vendor !== "gitlab") {
110
110
  throw new Error(
111
- `URL não é GitLab (${parsed.vendor}): ${url}\n` +
112
- "Use parseRepoUrl() para GitHub/Bitbucket.",
111
+ `URL não é GitLab (${parsed.vendor}): ${url}\n` + "Use parseRepoUrl() para GitHub/Bitbucket."
113
112
  );
114
113
  }
115
114
  return parsed;
116
115
  }
117
116
 
118
117
  export function buildApiUrl(repoUrl, endpoint) {
119
- const { vendor, apiBase, projectPathEncoded, owner, repo } =
120
- parseRepoUrl(repoUrl);
118
+ const { vendor, apiBase, projectPathEncoded, owner, repo } = parseRepoUrl(repoUrl);
121
119
  if (vendor === "gitlab") {
122
120
  return `${apiBase}/projects/${projectPathEncoded}/${endpoint}`;
123
121
  }
@@ -5,9 +5,7 @@ import { execSync } from "node:child_process";
5
5
 
6
6
  function readNpmrcToken(hostFragment, cwd = process.cwd()) {
7
7
  const paths = [join(cwd, ".npmrc"), join(homedir(), ".npmrc")];
8
- const re = new RegExp(
9
- `//[^\\s]*${hostFragment.replace(".", "\\.")}[^\\s]*:_authToken=([^\\s]+)`,
10
- );
8
+ const re = new RegExp(`//[^\\s]*${hostFragment.replace(".", "\\.")}[^\\s]*:_authToken=([^\\s]+)`);
11
9
 
12
10
  for (const path of paths) {
13
11
  if (!existsSync(path)) continue;
@@ -54,31 +52,26 @@ export function getVcsToken(vendor, cwd = process.cwd()) {
54
52
  if (token) return token;
55
53
  throw new Error(
56
54
  "Token GitHub não encontrado.\n" +
57
- "Use `gh auth login`, ou defina GITHUB_TOKEN, ou //npm.pkg.github.com/:_authToken= no .npmrc.",
55
+ "Use `gh auth login`, ou defina GITHUB_TOKEN, ou //npm.pkg.github.com/:_authToken= no .npmrc."
58
56
  );
59
57
  }
60
58
 
61
59
  if (v === "bitbucket") {
62
- const token =
63
- process.env.BITBUCKET_TOKEN ||
64
- readNpmrcToken("bitbucket.org", cwd);
60
+ const token = process.env.BITBUCKET_TOKEN || readNpmrcToken("bitbucket.org", cwd);
65
61
  if (token) return token;
66
62
  throw new Error(
67
- "Token Bitbucket não encontrado.\n" +
68
- "Defina BITBUCKET_TOKEN (App Password) no ambiente.",
63
+ "Token Bitbucket não encontrado.\n" + "Defina BITBUCKET_TOKEN (App Password) no ambiente."
69
64
  );
70
65
  }
71
66
 
72
67
  const token =
73
- process.env.GITLAB_TOKEN ||
74
- readNpmrcToken("gitlab.com", cwd) ||
75
- readNpmrcToken("gitlab", cwd);
68
+ process.env.GITLAB_TOKEN || readNpmrcToken("gitlab.com", cwd) || readNpmrcToken("gitlab", cwd);
76
69
  if (token) return token;
77
70
  throw new Error(
78
71
  "Token GitLab não encontrado no .npmrc\n" +
79
72
  "Configure:\n" +
80
73
  " //gitlab.com/api/v4/packages/npm/:_authToken=seu-token\n" +
81
- "Ou GITLAB_TOKEN no ambiente.",
74
+ "Ou GITLAB_TOKEN no ambiente."
82
75
  );
83
76
  }
84
77
 
@@ -18,8 +18,7 @@ export function getFrameworkRoot() {
18
18
  }
19
19
 
20
20
  throw new Error(
21
- "Could not locate framework assets.\n" +
22
- "Run: npm install jarvis-framework --save-dev",
21
+ "Could not locate framework assets.\n" + "Run: npm install jarvis-framework --save-dev"
23
22
  );
24
23
  }
25
24
 
@@ -48,8 +47,7 @@ export function detectIDE(cwd) {
48
47
  }
49
48
 
50
49
  export function detectAllIDEs(cwd) {
51
- return IDES
52
- .filter((ide) => ide.supported)
50
+ return IDES.filter((ide) => ide.supported)
53
51
  .filter((ide) => existsSync(join(cwd, `.${ide.folderName || ide.value}`)))
54
52
  .map((ide) => ide.value);
55
53
  }
@@ -35,21 +35,15 @@ export function showBanner() {
35
35
  console.log("");
36
36
  console.log(" ──────── J . A . R . V . I . S ────────");
37
37
  console.log(NC);
38
- console.log(
39
- `${DIM}Framework Jarvis para desenvolvimento assistido por IA${NC}`,
40
- );
38
+ console.log(`${DIM}Framework Jarvis para desenvolvimento assistido por IA${NC}`);
41
39
 
42
40
  try {
43
41
  const pkg = getPackageInfo();
44
42
  console.log("");
45
- console.log(
46
- `${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`,
47
- );
43
+ console.log(`${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`);
48
44
  console.log(`${BOLD}${CYAN} ${pkg.name} v${pkg.version}${NC}`);
49
45
  console.log(`${DIM} origem: ${pkg.root}${NC}`);
50
- console.log(
51
- `${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`,
52
- );
46
+ console.log(`${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}`);
53
47
  } catch {
54
48
  // banner sem versão se assets não forem encontrados
55
49
  }
@@ -89,12 +89,10 @@ export async function createMergeRequest(repoUrl, opts) {
89
89
  description,
90
90
  remove_source_branch: true,
91
91
  },
92
- },
92
+ }
93
93
  );
94
94
  if (!ok || !json?.web_url) {
95
- throw new Error(
96
- `Falha ao criar MR GitLab (${status}): ${JSON.stringify(json)}`,
97
- );
95
+ throw new Error(`Falha ao criar MR GitLab (${status}): ${JSON.stringify(json)}`);
98
96
  }
99
97
  return { vendor: "gitlab", iid: json.iid, url: json.web_url };
100
98
  }
@@ -111,12 +109,10 @@ export async function createMergeRequest(repoUrl, opts) {
111
109
  base: target,
112
110
  body: description,
113
111
  },
114
- },
112
+ }
115
113
  );
116
114
  if (!ok || !json?.html_url) {
117
- throw new Error(
118
- `Falha ao criar PR GitHub (${status}): ${JSON.stringify(json)}`,
119
- );
115
+ throw new Error(`Falha ao criar PR GitHub (${status}): ${JSON.stringify(json)}`);
120
116
  }
121
117
  return { vendor: "github", iid: json.number, url: json.html_url };
122
118
  }
@@ -133,12 +129,10 @@ export async function createMergeRequest(repoUrl, opts) {
133
129
  destination: { branch: { name: target } },
134
130
  close_source_branch: true,
135
131
  },
136
- },
132
+ }
137
133
  );
138
134
  if (!ok || !json?.links?.html?.href) {
139
- throw new Error(
140
- `Falha ao criar PR Bitbucket (${status}): ${JSON.stringify(json)}`,
141
- );
135
+ throw new Error(`Falha ao criar PR Bitbucket (${status}): ${JSON.stringify(json)}`);
142
136
  }
143
137
  return {
144
138
  vendor: "bitbucket",
@@ -174,12 +168,10 @@ export async function commitFiles(repoUrl, opts) {
174
168
  encoding: "base64",
175
169
  })),
176
170
  },
177
- },
171
+ }
178
172
  );
179
173
  if (!ok || !json?.id) {
180
- throw new Error(
181
- `Falha no commit GitLab (${status}): ${JSON.stringify(json)}`,
182
- );
174
+ throw new Error(`Falha no commit GitLab (${status}): ${JSON.stringify(json)}`);
183
175
  }
184
176
  return { sha: json.id };
185
177
  }
@@ -187,22 +179,17 @@ export async function commitFiles(repoUrl, opts) {
187
179
  if (repo.vendor === "github") {
188
180
  const refRes = await request(
189
181
  `${repo.apiBase}/repos/${repo.owner}/${repo.repo}/git/ref/heads/${startBranch}`,
190
- { headers },
182
+ { headers }
191
183
  );
192
184
  if (!refRes.ok) {
193
- throw new Error(
194
- `Branch ${startBranch} não encontrada no GitHub (${refRes.status})`,
195
- );
185
+ throw new Error(`Branch ${startBranch} não encontrada no GitHub (${refRes.status})`);
196
186
  }
197
187
  const sha = refRes.json.object.sha;
198
- await request(
199
- `${repo.apiBase}/repos/${repo.owner}/${repo.repo}/git/refs`,
200
- {
201
- method: "POST",
202
- headers,
203
- body: { ref: `refs/heads/${branch}`, sha },
204
- },
205
- );
188
+ await request(`${repo.apiBase}/repos/${repo.owner}/${repo.repo}/git/refs`, {
189
+ method: "POST",
190
+ headers,
191
+ body: { ref: `refs/heads/${branch}`, sha },
192
+ });
206
193
  let lastSha = sha;
207
194
  for (const file of files) {
208
195
  const put = await request(
@@ -215,11 +202,11 @@ export async function commitFiles(repoUrl, opts) {
215
202
  content: file.contentBase64,
216
203
  branch,
217
204
  },
218
- },
205
+ }
219
206
  );
220
207
  if (!put.ok) {
221
208
  throw new Error(
222
- `Falha ao escrever ${file.path} no GitHub (${put.status}): ${JSON.stringify(put.json)}`,
209
+ `Falha ao escrever ${file.path} no GitHub (${put.status}): ${JSON.stringify(put.json)}`
223
210
  );
224
211
  }
225
212
  lastSha = put.json.commit?.sha || lastSha;
@@ -235,14 +222,11 @@ export async function commitFiles(repoUrl, opts) {
235
222
  const buf = Buffer.from(file.contentBase64, "base64");
236
223
  form.set(file.path, new Blob([buf]));
237
224
  }
238
- const res = await fetch(
239
- `${repo.apiBase}/repositories/${repo.owner}/${repo.repo}/src`,
240
- {
241
- method: "POST",
242
- headers: { Authorization: `Bearer ${token}` },
243
- body: form,
244
- },
245
- );
225
+ const res = await fetch(`${repo.apiBase}/repositories/${repo.owner}/${repo.repo}/src`, {
226
+ method: "POST",
227
+ headers: { Authorization: `Bearer ${token}` },
228
+ body: form,
229
+ });
246
230
  if (!res.ok) {
247
231
  throw new Error(`Falha no commit Bitbucket (${res.status}): ${await res.text()}`);
248
232
  }
@@ -262,7 +246,7 @@ export async function createIssue(repoUrl, opts) {
262
246
  method: "POST",
263
247
  headers,
264
248
  body: { title, description: body, labels: labels.join(",") },
265
- },
249
+ }
266
250
  );
267
251
  if (!ok || !json?.web_url) {
268
252
  throw new Error(`Issue GitLab (${status}): ${JSON.stringify(json)}`);
@@ -277,7 +261,7 @@ export async function createIssue(repoUrl, opts) {
277
261
  method: "POST",
278
262
  headers,
279
263
  body: { title, body, labels },
280
- },
264
+ }
281
265
  );
282
266
  if (!ok || !json?.html_url) {
283
267
  throw new Error(`Issue GitHub (${status}): ${JSON.stringify(json)}`);
@@ -291,7 +275,7 @@ export async function createIssue(repoUrl, opts) {
291
275
  method: "POST",
292
276
  headers,
293
277
  body: { title, content: { raw: body } },
294
- },
278
+ }
295
279
  );
296
280
  if (!ok || !json?.links?.html?.href) {
297
281
  throw new Error(`Issue Bitbucket (${status}): ${JSON.stringify(json)}`);