jarvis-ai-framework 1.0.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 (240) hide show
  1. package/AGENTS.md +416 -0
  2. package/LICENSE +21 -0
  3. package/README.md +190 -0
  4. package/agents/AGENTS.md +234 -0
  5. package/agents/README.md +309 -0
  6. package/agents/engineering/data/eng.data-engineer.agent.md +309 -0
  7. package/agents/engineering/eng.agent.md +303 -0
  8. package/agents/engineering/eng.bug-hunter.md +386 -0
  9. package/agents/engineering/eng.cybersecurity.agent.md +503 -0
  10. package/agents/engineering/eng.dev-code-reviewer.md +148 -0
  11. package/agents/engineering/eng.docs-writer.md +152 -0
  12. package/agents/engineering/eng.frontend.agent.md +117 -0
  13. package/agents/engineering/eng.rpa.agent.md +215 -0
  14. package/agents/engineering/eng.tech-analyst.agent.md +102 -0
  15. package/agents/engineering/eng.ux-designer.agent.md +193 -0
  16. package/agents/engineering/qa/eng.qa.cypress-specialist.md +109 -0
  17. package/agents/engineering/qa/eng.qa.quality-champion-task-agent.md +85 -0
  18. package/agents/engineering/qa/eng.qa.quality-strategist.md +111 -0
  19. package/agents/engineering/qa/eng.qa.test-architect.md +400 -0
  20. package/agents/engineering/qa/eng.qa.test-planner.md +477 -0
  21. package/agents/engineering/qa/eng.qa.testing-engineer.md +339 -0
  22. package/agents/product/prod.pm-checker.md +52 -0
  23. package/bin/commands/docs-publish.js +184 -0
  24. package/bin/commands/docs-sync.js +139 -0
  25. package/bin/commands/info.js +87 -0
  26. package/bin/commands/init.js +237 -0
  27. package/bin/commands/install-rtk.js +90 -0
  28. package/bin/commands/list.js +48 -0
  29. package/bin/commands/qa-signoff.js +112 -0
  30. package/bin/commands/whoami.js +43 -0
  31. package/bin/jarvis.js +159 -0
  32. package/bin/lib/auth/session.js +56 -0
  33. package/bin/lib/config/constants.js +123 -0
  34. package/bin/lib/config/ide-config.js +233 -0
  35. package/bin/lib/core/scanner.js +124 -0
  36. package/bin/lib/core/sync-engine.js +551 -0
  37. package/bin/lib/docs/fetch-file.sh +41 -0
  38. package/bin/lib/docs/publish-file.sh +284 -0
  39. package/bin/lib/docs/validate-frontmatter.js +157 -0
  40. package/bin/lib/env-loader.js +198 -0
  41. package/bin/lib/tasks/comment.js +131 -0
  42. package/bin/lib/utils/git-parser.js +145 -0
  43. package/bin/lib/utils/logger.js +104 -0
  44. package/bin/lib/utils/npmrc-parser.js +106 -0
  45. package/bin/lib/utils/paths.js +55 -0
  46. package/bin/lib/utils/ui.js +59 -0
  47. package/bin/lib/vcs/api.js +312 -0
  48. package/bin/lib/vcs/create-issue.js +43 -0
  49. package/bin/lib/vcs/create-merge.js +43 -0
  50. package/bin/lib/vcs/fetch-raw.js +30 -0
  51. package/bin/postinstall.js +41 -0
  52. package/members.md +25 -0
  53. package/package.json +55 -0
  54. package/rules/AGENTS.md +205 -0
  55. package/rules/engineering/data/data-rules.md +200 -0
  56. package/rules/engineering/eng-rules.md +243 -0
  57. package/rules/engineering/eng-security-rules.md +186 -0
  58. package/rules/engineering/eng.breakdown-subtasks-rules.md +585 -0
  59. package/rules/engineering/eng.bump-rules.md +27 -0
  60. package/rules/engineering/eng.docs-scraping-rules.md +64 -0
  61. package/rules/engineering/eng.downstream-flow-rules.md +297 -0
  62. package/rules/engineering/eng.integrations-rules.md +73 -0
  63. package/rules/engineering/eng.plan-rules.md +333 -0
  64. package/rules/engineering/eng.pr-rules.md +359 -0
  65. package/rules/engineering/eng.pre-pr-rules.md +103 -0
  66. package/rules/engineering/eng.start-rules.md +246 -0
  67. package/rules/engineering/eng.tech-spec-rules.md +968 -0
  68. package/rules/engineering/eng.work-rules.md +312 -0
  69. package/rules/engineering/frontend/eng.frontend-rules.md +147 -0
  70. package/rules/engineering/qa/eng.qa.cypress-standards-rules.md +259 -0
  71. package/rules/engineering/qa/eng.qa.exploratory-session-rules.md +137 -0
  72. package/rules/engineering/qa/eng.qa.quality-gate-scoring-rules.md +181 -0
  73. package/rules/engineering/qa/eng.qa.tech-spec-validation-criteria-rules.md +120 -0
  74. package/rules/engineering/rpa/eng.rpa-rules.md +230 -0
  75. package/rules/product/README.md +24 -0
  76. package/rules/product/prod-rules.md +151 -0
  77. package/rules/rtk-rules.md +68 -0
  78. package/skills/AGENTS.md +290 -0
  79. package/skills/SKILLS-ROADMAP.md +333 -0
  80. package/skills/churn-audit/SKILL.md +385 -0
  81. package/skills/context-detect/SKILL.md +399 -0
  82. package/skills/context-detect/assets/context-profile-template.md +127 -0
  83. package/skills/docs-central/README.md +310 -0
  84. package/skills/docs-central/SKILL.md +423 -0
  85. package/skills/docs-index/SKILL.md +377 -0
  86. package/skills/eng-ai-engineer/SKILL.md +296 -0
  87. package/skills/eng-arch-c4/SKILL.md +358 -0
  88. package/skills/eng-arch-c4/assets/example-code.md +189 -0
  89. package/skills/eng-arch-c4/assets/example-component.md +105 -0
  90. package/skills/eng-arch-c4/assets/example-container.md +104 -0
  91. package/skills/eng-arch-c4/assets/example-context.md +81 -0
  92. package/skills/eng-backend/SKILL.md +776 -0
  93. package/skills/eng-browser-extension-builder/SKILL.md +385 -0
  94. package/skills/eng-cybersecurity/SKILL.md +645 -0
  95. package/skills/eng-data-bi/SKILL.md +199 -0
  96. package/skills/eng-data-debug/SKILL.md +307 -0
  97. package/skills/eng-data-engineer/SKILL.md +256 -0
  98. package/skills/eng-data-onboard/SKILL.md +310 -0
  99. package/skills/eng-data-orchestrator/SKILL.md +426 -0
  100. package/skills/eng-design-system/SKILL.md +619 -0
  101. package/skills/eng-docs-write/SKILL.md +312 -0
  102. package/skills/eng-frontend/SKILL.md +913 -0
  103. package/skills/eng-jira-comment/SKILL.md +17 -0
  104. package/skills/eng-microfrontend/SKILL.md +602 -0
  105. package/skills/eng-ms-trace/SKILL.md +469 -0
  106. package/skills/eng-nestjs/SKILL.md +791 -0
  107. package/skills/eng-performance-engineer/SKILL.md +312 -0
  108. package/skills/eng-pr/SKILL.md +339 -0
  109. package/skills/eng-qa-a11y-audit/SKILL.md +269 -0
  110. package/skills/eng-qa-bug-report/SKILL.md +1088 -0
  111. package/skills/eng-qa-bug-report/TASK_MANAGERS.md +138 -0
  112. package/skills/eng-qa-cypress-e2e/SKILL.md +177 -0
  113. package/skills/eng-qa-dev-guide/SKILL.md +164 -0
  114. package/skills/eng-qa-e2e/SKILL.md +400 -0
  115. package/skills/eng-qa-e2e-spec-writer/SKILL.md +322 -0
  116. package/skills/eng-qa-exploratory/SKILL.md +188 -0
  117. package/skills/eng-qa-gate/SKILL.md +370 -0
  118. package/skills/eng-qa-gate/assets/checklist-validacao.md +291 -0
  119. package/skills/eng-qa-graphql-contract/SKILL.md +256 -0
  120. package/skills/eng-qa-quality-report/SKILL.md +412 -0
  121. package/skills/eng-qa-test-plan/SKILL.md +466 -0
  122. package/skills/eng-qa-test-plan/assets/test-coverage-template.md +92 -0
  123. package/skills/eng-qa-test-plan/assets/test-patterns.md +178 -0
  124. package/skills/eng-qa-testsprite/SKILL.md +325 -0
  125. package/skills/eng-qa-testsprite/references/testsprite-mcp.md +224 -0
  126. package/skills/eng-qa-unit-test/SKILL.md +471 -0
  127. package/skills/eng-rabbitmq/SKILL.md +661 -0
  128. package/skills/eng-scraper/SKILL.md +683 -0
  129. package/skills/eng-scraper-robot-builder/SKILL.md +370 -0
  130. package/skills/eng-security-patch/SKILL.md +378 -0
  131. package/skills/eng-security-triage/SKILL.md +266 -0
  132. package/skills/eng-task-comment/SKILL.md +60 -0
  133. package/skills/eng-tech-analyst/SKILL.md +529 -0
  134. package/skills/eng-threat-model/SKILL.md +161 -0
  135. package/skills/init-jarvis/SKILL.md +1304 -0
  136. package/skills/init-jarvis/assets/mcp-configs.md +389 -0
  137. package/skills/init-jarvis/assets/onboarding-checklist.md +104 -0
  138. package/skills/init-jarvis/assets/setup-guide.md +360 -0
  139. package/skills/lovable-prompt-generator/SKILL.md +304 -0
  140. package/skills/prod-roadmap-report/README.md +303 -0
  141. package/skills/prod-roadmap-report/SKILL.md +198 -0
  142. package/skills/prod-roadmap-report/commands/status.compiled.single.team.md +23 -0
  143. package/skills/prod-roadmap-report/commands/status.list.projects.md +17 -0
  144. package/skills/prod-roadmap-report/commands/status.memory.md +192 -0
  145. package/skills/prod-roadmap-report/commands/status.roadmap.preview.md +94 -0
  146. package/skills/prod-roadmap-report/references/detailed-guide.md +236 -0
  147. package/skills/prod-roadmap-report/rules/detailed-guide.md +237 -0
  148. package/skills/prod-roadmap-report/rules/status-report-rules.md +44 -0
  149. package/skills/prod-roadmap-report/templates/template-multiple-teams-compiled-status.md +53 -0
  150. package/skills/prod-roadmap-report/templates/template-projects-list.md +23 -0
  151. package/skills/prod-roadmap-report/templates/template-single-team-compiled-status.md +60 -0
  152. package/skills/prod-roadmap-report/templates/template-single-team-status.md +49 -0
  153. package/skills/prod-specs/SKILL.md +108 -0
  154. package/skills/prod-specs/references/prod.spec.clarify.md +176 -0
  155. package/skills/prod-specs/references/prod.spec.epic.md +107 -0
  156. package/skills/prod-specs/references/prod.spec.frd.md +135 -0
  157. package/skills/prod-specs/references/prod.spec.issue.md +145 -0
  158. package/skills/prod-specs/references/prod.spec.prd.md +118 -0
  159. package/skills/prod-specs/rules/prod-spec-rules.md +186 -0
  160. package/skills/prod-specs/templates/prod-breakdown-template.md +136 -0
  161. package/skills/prod-specs/templates/prod-epic-template.md +76 -0
  162. package/skills/prod-specs/templates/prod-frd-template.md +172 -0
  163. package/skills/prod-specs/templates/prod-issue-template.md +68 -0
  164. package/skills/prod-specs/templates/prod-prd-full-template.md +159 -0
  165. package/skills/prod-specs/templates/prod-prd-template.md +173 -0
  166. package/skills/prod-specs-update/SKILL.md +272 -0
  167. package/skills/report-issue/SKILL.md +156 -0
  168. package/taxonomy.md +270 -0
  169. package/templates/AGENTS.md +189 -0
  170. package/templates/CDD aplicado a Prompts.md +182 -0
  171. package/templates/ENV-template.md +187 -0
  172. package/templates/engineering/AGENTS-template.md +71 -0
  173. package/templates/engineering/ARD-template.md +193 -0
  174. package/templates/engineering/CONTACTS-template.md +135 -0
  175. package/templates/engineering/PR-template.md +40 -0
  176. package/templates/engineering/RFC-Playbook.md +325 -0
  177. package/templates/engineering/RFC-template.md +199 -0
  178. package/templates/engineering/architecture-template.md +277 -0
  179. package/templates/engineering/breakdown-subtasks-template.md +582 -0
  180. package/templates/engineering/c4-model-template.md +516 -0
  181. package/templates/engineering/data-contract-template.md +135 -0
  182. package/templates/engineering/data-pipeline-template.md +163 -0
  183. package/templates/engineering/plan-template.md +255 -0
  184. package/templates/engineering/qa/eng.qa.quality-gate-examples-template.md +311 -0
  185. package/templates/engineering/qa/eng.qa.quality-gate-report-template.md +249 -0
  186. package/templates/engineering/qa/qa.cypress-test-template.md +172 -0
  187. package/templates/engineering/qa/qa.exploratory-session-template.md +148 -0
  188. package/templates/engineering/qa/qa.quality-report-template.md +130 -0
  189. package/templates/engineering/qa/qa.release-signoff-template.md +54 -0
  190. package/templates/engineering/qa/qa.sprint-plan-template.md +49 -0
  191. package/templates/engineering/swagger-template.md +145 -0
  192. package/templates/engineering/tech-spec-template.md +497 -0
  193. package/templates/engineering/work-progress-template.md +155 -0
  194. package/workflows/AGENTS.md +240 -0
  195. package/workflows/README.md +160 -0
  196. package/workflows/all-tools.md +11 -0
  197. package/workflows/engineering/data/data.contract.md +202 -0
  198. package/workflows/engineering/data/data.new-pipeline.md +234 -0
  199. package/workflows/engineering/eng.breakdown-subtasks.md +420 -0
  200. package/workflows/engineering/eng.bug-audit.md +591 -0
  201. package/workflows/engineering/eng.build-tech-spec.md +1116 -0
  202. package/workflows/engineering/eng.create-ard-from-code.md +259 -0
  203. package/workflows/engineering/eng.create-ard.md +382 -0
  204. package/workflows/engineering/eng.create-rfc.md +245 -0
  205. package/workflows/engineering/eng.debug.md +479 -0
  206. package/workflows/engineering/eng.docs.md +40 -0
  207. package/workflows/engineering/eng.light-arch.md +84 -0
  208. package/workflows/engineering/eng.plan.md +213 -0
  209. package/workflows/engineering/eng.pr.md +466 -0
  210. package/workflows/engineering/eng.pre-pr.md +167 -0
  211. package/workflows/engineering/eng.review.md +185 -0
  212. package/workflows/engineering/eng.rpa.robot.md +342 -0
  213. package/workflows/engineering/eng.security-audit.md +312 -0
  214. package/workflows/engineering/eng.security-incident.md +275 -0
  215. package/workflows/engineering/eng.security-pipeline.md +210 -0
  216. package/workflows/engineering/eng.security-review.md +235 -0
  217. package/workflows/engineering/eng.start.md +494 -0
  218. package/workflows/engineering/eng.work.md +558 -0
  219. package/workflows/engineering/frontend/eng.frontend-component.md +190 -0
  220. package/workflows/engineering/frontend/eng.frontend-perf-audit.md +375 -0
  221. package/workflows/engineering/frontend/eng.frontend-review.md +185 -0
  222. package/workflows/engineering/qa/eng.qa-dev-quality-guide.md +51 -0
  223. package/workflows/engineering/qa/eng.qa-e2e-test-generation.md +51 -0
  224. package/workflows/engineering/qa/eng.qa-exploratory-session.md +60 -0
  225. package/workflows/engineering/qa/eng.qa-quality-gate-validation.md +202 -0
  226. package/workflows/engineering/qa/eng.qa-quality-report.md +83 -0
  227. package/workflows/engineering/qa/eng.qa-refinement-entry.md +83 -0
  228. package/workflows/engineering/qa/eng.qa-release-signoff.md +170 -0
  229. package/workflows/engineering/qa/eng.qa-sprint-planning.md +100 -0
  230. package/workflows/engineering/ta/eng.ta.atendimento.md +93 -0
  231. package/workflows/product/prod.roadmap.preview.md +110 -0
  232. package/workflows/product/prod.spec.breakdown.md +163 -0
  233. package/workflows/product/prod.spec.clarify.md +178 -0
  234. package/workflows/product/prod.spec.epic.md +154 -0
  235. package/workflows/product/prod.spec.frd.md +96 -0
  236. package/workflows/product/prod.spec.issue.md +145 -0
  237. package/workflows/product/prod.spec.md +60 -0
  238. package/workflows/product/prod.spec.prd.md +100 -0
  239. package/workflows/taxonomy.md +92 -0
  240. package/workflows/warm-up.md +574 -0
@@ -0,0 +1,284 @@
1
+ #!/bin/bash
2
+ # Publica documento no central-docs (GitLab / GitHub / Bitbucket) via branch + MR/PR
3
+
4
+ set -e
5
+
6
+ LOCAL_FILE="$1" # Ex: ./docs/engineering/ard-api-wallet.md
7
+ TIPO="$2" # prd|frd|ard|rfc
8
+ FEATURE="$3" # Ex: api-wallet-auth-jwt
9
+
10
+ # Resolver path absoluto do script (independente de cwd)
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+
13
+ if [ -z "$LOCAL_FILE" ] || [ -z "$TIPO" ] || [ -z "$FEATURE" ]; then
14
+ echo "Uso: publish-file.sh <local-file> <tipo> <feature>" >&2
15
+ echo "Tipos válidos: prd, frd, ard, rfc, swagger, qa-report" >&2
16
+ exit 1
17
+ fi
18
+
19
+ if [ ! -f "$LOCAL_FILE" ]; then
20
+ echo "Erro: Arquivo não encontrado: $LOCAL_FILE" >&2
21
+ exit 1
22
+ fi
23
+
24
+ # Detectar IDE directory
25
+ if [ -d ".windsurf" ]; then
26
+ IDE=".windsurf"
27
+ elif [ -d ".claude" ]; then
28
+ IDE=".claude"
29
+ elif [ -d ".cursor" ]; then
30
+ IDE=".cursor"
31
+ elif [ -d ".vscode" ]; then
32
+ IDE=".vscode"
33
+ else
34
+ echo "Erro: IDE directory não encontrado (.windsurf, .claude, .cursor, .vscode)" >&2
35
+ exit 1
36
+ fi
37
+
38
+ # 1. Ler ENV.md (se não houver override)
39
+ if [ -n "$SQUAD_OVERRIDE" ] && [ -n "$WORKSPACE_OVERRIDE" ]; then
40
+ # Usar override das variáveis de ambiente
41
+ SQUAD="$SQUAD_OVERRIDE"
42
+ WORKSPACE="$WORKSPACE_OVERRIDE"
43
+ else
44
+ # Ler do ENV.md
45
+ if [ ! -f "$IDE/ENV.md" ]; then
46
+ echo "Erro: ENV.md não encontrado em $IDE/" >&2
47
+ echo "Ou passe --squad e --workspace via CLI" >&2
48
+ exit 1
49
+ fi
50
+
51
+ SQUAD=$(grep '^SQUAD=' "$IDE/ENV.md" | cut -d'=' -f2 | tr -d ' ')
52
+ WORKSPACE=$(grep '^WORKSPACE=' "$IDE/ENV.md" | cut -d'=' -f2 | tr -d ' ')
53
+
54
+ if [ -z "$SQUAD" ] || [ -z "$WORKSPACE" ]; then
55
+ echo "Erro: SQUAD ou WORKSPACE não definidos no ENV.md" >&2
56
+ echo "Ou passe --squad e --workspace via CLI" >&2
57
+ exit 1
58
+ fi
59
+ fi
60
+
61
+ TARGET_BRANCH="${CENTRAL_DOCS_TARGET_BRANCH:-dev}"
62
+
63
+ if [ -z "$CENTRAL_DOCS_REPO" ]; then
64
+ echo "Erro: CENTRAL_DOCS_REPO não definido no ENV.md" >&2
65
+ exit 1
66
+ fi
67
+
68
+ # 2. Validar frontmatter
69
+ echo "Validando frontmatter..."
70
+ node --input-type=module -e "
71
+ import { validateFrontmatter } from 'file://${SCRIPT_DIR}/validate-frontmatter.js';
72
+ try {
73
+ validateFrontmatter('$LOCAL_FILE', '$TIPO');
74
+ console.log('✅ Frontmatter válido');
75
+ } catch (error) {
76
+ console.error(error.message);
77
+ process.exit(1);
78
+ }
79
+ "
80
+
81
+ if [ $? -ne 0 ]; then
82
+ exit 1
83
+ fi
84
+
85
+ # 3. Extrair metadados
86
+ METADATA=$(node --input-type=module -e "
87
+ import { extractMetadata } from 'file://${SCRIPT_DIR}/validate-frontmatter.js';
88
+ const metadata = extractMetadata('$LOCAL_FILE');
89
+ console.log(JSON.stringify(metadata));
90
+ ")
91
+
92
+ VERSION=$(echo "$METADATA" | jq -r '.version // "1.0.0"')
93
+ STATUS=$(echo "$METADATA" | jq -r '.status // "draft"')
94
+ JIRA=$(echo "$METADATA" | jq -r '.jira // ""')
95
+ DOC_NAME=$(echo "$METADATA" | jq -r '.name // ""')
96
+
97
+ # 4. Definir paths
98
+ if [ "$TIPO" = "prd" ] || [ "$TIPO" = "frd" ]; then
99
+ DEST_PATH="${SQUAD}/${WORKSPACE}/product/${TIPO}-${FEATURE}.md"
100
+ AREA="product"
101
+ elif [ "$TIPO" = "ard" ]; then
102
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/ARD/${TIPO}-${FEATURE}.md"
103
+ AREA="engineering"
104
+ elif [ "$TIPO" = "rfc" ]; then
105
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/RFC/${TIPO}-${FEATURE}.md"
106
+ AREA="engineering"
107
+ elif [ "$TIPO" = "swagger" ]; then
108
+ # Detectar extensão do arquivo (yaml, json ou md)
109
+ FILE_EXT="${LOCAL_FILE##*.}"
110
+ if [ "$FILE_EXT" = "yaml" ] || [ "$FILE_EXT" = "yml" ]; then
111
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/swagger/api-${FEATURE}.yaml"
112
+ elif [ "$FILE_EXT" = "json" ]; then
113
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/swagger/api-${FEATURE}.json"
114
+ else
115
+ # Default para .md (wrapper com metadados)
116
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/swagger/swagger-${FEATURE}.md"
117
+ fi
118
+ AREA="engineering"
119
+ elif [ "$TIPO" = "qa-report" ]; then
120
+ DEST_PATH="${SQUAD}/${WORKSPACE}/engineering/qa/qa-report-${FEATURE}.md"
121
+ AREA="engineering"
122
+ else
123
+ echo "Erro: Tipo inválido: $TIPO" >&2
124
+ echo "Tipos válidos: prd, frd, ard, rfc, swagger, qa-report" >&2
125
+ exit 1
126
+ fi
127
+
128
+ INDEX_PATH="${SQUAD}/${WORKSPACE}/index.md"
129
+ BRANCH_NAME="docs/${SQUAD}/${WORKSPACE}/${TIPO}-${FEATURE}"
130
+
131
+ echo ""
132
+ echo "📋 Resumo da Publicação:"
133
+ echo " Squad: $SQUAD"
134
+ echo " Workspace: $WORKSPACE"
135
+ echo " Tipo: $TIPO"
136
+ echo " Feature: $FEATURE"
137
+ echo " Destino: $DEST_PATH"
138
+ echo " Branch: $BRANCH_NAME → $TARGET_BRANCH"
139
+ echo ""
140
+
141
+ # 5–6. Token e parse do repo ficam no adapter VCS (api.js)
142
+
143
+ # 7. Ler conteúdo do arquivo local e encodar em base64
144
+ FILE_CONTENT=$(cat "$LOCAL_FILE" | base64)
145
+
146
+ # 8. Buscar index.md atual
147
+ echo "Buscando index.md do workspace..."
148
+ INDEX_CONTENT=$(bash "${SCRIPT_DIR}/fetch-file.sh" "$INDEX_PATH" "$TARGET_BRANCH" 2>/dev/null || echo "")
149
+
150
+ if [ -z "$INDEX_CONTENT" ]; then
151
+ echo "⚠️ index.md não encontrado, será criado"
152
+ INDEX_ACTION="create"
153
+ INDEX_CONTENT="# $WORKSPACE
154
+
155
+ **Squad:** $SQUAD
156
+
157
+ ## $AREA
158
+
159
+ "
160
+ else
161
+ INDEX_ACTION="update"
162
+ fi
163
+
164
+ # 9. Adicionar nova linha ao index.md
165
+ NEW_LINE="- [${TIPO}-${FEATURE}.md](${AREA}/${TIPO}-${FEATURE}.md) | v${VERSION} | ${STATUS}"
166
+ [ -n "$JIRA" ] && NEW_LINE="${NEW_LINE} | jira: ${JIRA}"
167
+ [ -n "$DOC_NAME" ] && NEW_LINE="${NEW_LINE} | ${DOC_NAME}"
168
+
169
+ # Adicionar linha na seção correta
170
+ UPDATED_INDEX=$(echo "$INDEX_CONTENT" | awk -v line="$NEW_LINE" -v area="$AREA" '
171
+ /^## (product|engineering)/ {
172
+ print
173
+ if ($2 == area) {
174
+ found = 1
175
+ getline
176
+ print line
177
+ }
178
+ next
179
+ }
180
+ { print }
181
+ END {
182
+ if (!found) {
183
+ print ""
184
+ print "## " area
185
+ print line
186
+ }
187
+ }
188
+ ')
189
+
190
+ UPDATED_INDEX_B64=$(echo "$UPDATED_INDEX" | base64)
191
+
192
+ # 10. Criar commit via adapter VCS
193
+ echo "Criando branch e commit..."
194
+
195
+ COMMIT_JSON=$(mktemp)
196
+ cat > "$COMMIT_JSON" <<EOF
197
+ {
198
+ "branch": $(printf '%s' "$BRANCH_NAME" | jq -Rs .),
199
+ "startBranch": $(printf '%s' "$TARGET_BRANCH" | jq -Rs .),
200
+ "message": $(printf '%s' "docs(${SQUAD}): add ${TIPO} ${FEATURE}" | jq -Rs .),
201
+ "files": [
202
+ {
203
+ "path": $(printf '%s' "$DEST_PATH" | jq -Rs .),
204
+ "contentBase64": $(printf '%s' "$FILE_CONTENT" | jq -Rs .),
205
+ "action": "create"
206
+ },
207
+ {
208
+ "path": $(printf '%s' "$INDEX_PATH" | jq -Rs .),
209
+ "contentBase64": $(printf '%s' "$UPDATED_INDEX_B64" | jq -Rs .),
210
+ "action": $(printf '%s' "$INDEX_ACTION" | jq -Rs .)
211
+ }
212
+ ]
213
+ }
214
+ EOF
215
+
216
+ COMMIT_RESULT=$(node --input-type=module -e "
217
+ import { readFileSync } from 'node:fs';
218
+ import { commitFiles } from 'file://${SCRIPT_DIR}/../vcs/api.js';
219
+ const opts = JSON.parse(readFileSync('$COMMIT_JSON', 'utf-8'));
220
+ const result = await commitFiles(process.env.CENTRAL_DOCS_REPO, opts);
221
+ console.log(JSON.stringify(result));
222
+ " 2>&1)
223
+ COMMIT_EXIT=$?
224
+ rm -f "$COMMIT_JSON"
225
+
226
+ if [ $COMMIT_EXIT -ne 0 ]; then
227
+ echo "❌ Erro ao criar commit:" >&2
228
+ echo "$COMMIT_RESULT" >&2
229
+ exit 1
230
+ fi
231
+
232
+ COMMIT_SHA=$(echo "$COMMIT_RESULT" | jq -r '.sha')
233
+ echo "✅ Commit criado: $COMMIT_SHA"
234
+
235
+ # 11. Criar MR/PR
236
+ echo "Criando Merge/Pull Request..."
237
+
238
+ MR_DESCRIPTION="## Documento
239
+
240
+ - **Tipo**: ${TIPO}
241
+ - **Workspace**: ${WORKSPACE}
242
+ - **Feature**: ${FEATURE}"
243
+
244
+ [ -n "$JIRA" ] && MR_DESCRIPTION="${MR_DESCRIPTION}
245
+ - **Card**: ${JIRA}"
246
+
247
+ [ -n "$DOC_NAME" ] && MR_DESCRIPTION="${MR_DESCRIPTION}
248
+ - **Nome**: ${DOC_NAME}"
249
+
250
+ BODY_FILE=$(mktemp)
251
+ printf '%s' "$MR_DESCRIPTION" > "$BODY_FILE"
252
+
253
+ MR_RESULT=$(node "${SCRIPT_DIR}/../vcs/create-merge.js" \
254
+ --repo "$CENTRAL_DOCS_REPO" \
255
+ --source "$BRANCH_NAME" \
256
+ --target "$TARGET_BRANCH" \
257
+ --title "docs(${SQUAD}): ${TIPO} ${FEATURE}" \
258
+ --body-file "$BODY_FILE" 2>&1)
259
+ MR_EXIT=$?
260
+ rm -f "$BODY_FILE"
261
+
262
+ if [ $MR_EXIT -ne 0 ]; then
263
+ echo "❌ Erro ao criar MR/PR:" >&2
264
+ echo "$MR_RESULT" >&2
265
+ exit 1
266
+ fi
267
+
268
+ MR_URL=$(echo "$MR_RESULT" | tail -1 | jq -r '.url // empty')
269
+ MR_IID=$(echo "$MR_RESULT" | tail -1 | jq -r '.iid // empty')
270
+
271
+ echo ""
272
+ echo "✅ Merge/Pull Request criado com sucesso!"
273
+ echo ""
274
+ echo " #${MR_IID}: ${BRANCH_NAME} → ${TARGET_BRANCH}"
275
+ echo " URL: ${MR_URL}"
276
+ echo ""
277
+
278
+ # 12. Invalidar cache Redis
279
+ redis-cli DEL "docs:${INDEX_PATH}:${TARGET_BRANCH}" >/dev/null 2>&1 || true
280
+ redis-cli DEL "docs:${INDEX_PATH}:main" >/dev/null 2>&1 || true
281
+
282
+ echo "🔄 Cache Redis invalidado"
283
+ echo ""
284
+ echo "✅ Publicação concluída!"
@@ -0,0 +1,157 @@
1
+ import { readFileSync } from 'node:fs'
2
+
3
+ /**
4
+ * Valida frontmatter YAML de documentos (PRD, FRD, ARD, RFC)
5
+ *
6
+ * @param {string} filePath - Caminho do arquivo
7
+ * @param {string} tipo - Tipo do documento (prd|frd|ard|rfc)
8
+ * @returns {Object} Metadados extraídos
9
+ * @throws {Error} Se frontmatter for inválido
10
+ */
11
+ export function validateFrontmatter(filePath, tipo) {
12
+ const content = readFileSync(filePath, 'utf-8')
13
+
14
+ // Extrair frontmatter YAML (entre --- e ---)
15
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
16
+
17
+ if (!frontmatterMatch) {
18
+ throw new Error(
19
+ `Frontmatter YAML não encontrado em ${filePath}\n` +
20
+ 'Formato esperado:\n' +
21
+ '---\n' +
22
+ 'id: DOC-001\n' +
23
+ 'version: 1.0.0\n' +
24
+ '---'
25
+ )
26
+ }
27
+
28
+ const frontmatter = frontmatterMatch[1]
29
+ const metadata = parseFrontmatter(frontmatter)
30
+
31
+ // Validar campos obrigatórios por tipo
32
+ const requiredFields = getRequiredFields(tipo)
33
+ const missingFields = []
34
+
35
+ for (const field of requiredFields) {
36
+ if (!metadata[field]) {
37
+ missingFields.push(field)
38
+ }
39
+ }
40
+
41
+ if (missingFields.length > 0) {
42
+ throw new Error(
43
+ `Campos obrigatórios ausentes no frontmatter de ${tipo.toUpperCase()}:\n` +
44
+ missingFields.map(f => ` - ${f}`).join('\n') +
45
+ '\n\nFrontmatter atual:\n' + frontmatter
46
+ )
47
+ }
48
+
49
+ // Validar formato de version (X.Y.Z)
50
+ if (metadata.version && !metadata.version.match(/^\d+\.\d+(\.\d+)?$/)) {
51
+ throw new Error(
52
+ `Formato de version inválido: "${metadata.version}"\n` +
53
+ 'Formato esperado: X.Y.Z (ex: 1.0.0 ou 1.2)'
54
+ )
55
+ }
56
+
57
+ // Validar status
58
+ const validStatuses = ['icebox', 'in_review', 'in_progress', 'in_production', 'deprecated', 'Proposta', 'Em desenvolvimento', 'Em validação', 'Finalizada', 'Draft', 'In Review', 'Ready for Decision', 'Accepted', 'Rejected', 'Superseded']
59
+
60
+ if (metadata.status && !validStatuses.includes(metadata.status)) {
61
+ console.warn(
62
+ `⚠️ Status "${metadata.status}" não está na lista padrão.\n` +
63
+ `Status válidos: ${validStatuses.join(', ')}`
64
+ )
65
+ }
66
+
67
+ return metadata
68
+ }
69
+
70
+ /**
71
+ * Parseia frontmatter YAML simples (key: value)
72
+ *
73
+ * @param {string} frontmatter - Conteúdo do frontmatter
74
+ * @returns {Object} Metadados parseados
75
+ */
76
+ function parseFrontmatter(frontmatter) {
77
+ const metadata = {}
78
+ const lines = frontmatter.split('\n')
79
+
80
+ for (const line of lines) {
81
+ const trimmed = line.trim()
82
+ if (!trimmed || trimmed.startsWith('#')) continue
83
+
84
+ const colonIndex = trimmed.indexOf(':')
85
+ if (colonIndex === -1) continue
86
+
87
+ const key = trimmed.slice(0, colonIndex).trim()
88
+ const value = trimmed.slice(colonIndex + 1).trim()
89
+
90
+ if (key && value) {
91
+ metadata[key] = value
92
+ }
93
+ }
94
+
95
+ return metadata
96
+ }
97
+
98
+ /**
99
+ * Retorna campos obrigatórios por tipo de documento
100
+ *
101
+ * @param {string} tipo - Tipo do documento
102
+ * @returns {string[]} Lista de campos obrigatórios
103
+ */
104
+ function getRequiredFields(tipo) {
105
+ const fields = {
106
+ prd: ['id', 'name', 'version', 'status'],
107
+ frd: ['id', 'name', 'version', 'status', 'related_prd'],
108
+ ard: ['Status', 'Data', 'Autor', 'Versão'],
109
+ rfc: ['Status', 'Criado em', 'Proponente'],
110
+ 'qa-report': ['period', 'squad', 'version']
111
+ }
112
+
113
+ return fields[tipo] || []
114
+ }
115
+
116
+ /**
117
+ * Extrai metadados específicos do frontmatter
118
+ *
119
+ * @param {string} filePath - Caminho do arquivo
120
+ * @returns {Object} Metadados extraídos (id, version, status, jira, etc)
121
+ */
122
+ export function extractMetadata(filePath) {
123
+ const content = readFileSync(filePath, 'utf-8')
124
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/)
125
+
126
+ if (!frontmatterMatch) {
127
+ return {}
128
+ }
129
+
130
+ const metadata = parseFrontmatter(frontmatterMatch[1])
131
+
132
+ // Normalizar campos (suportar variações de nomenclatura)
133
+ const taskLink = metadata.task_link || metadata.jira
134
+ const jiraId = taskLink ? extractJiraFromContent(taskLink) : extractJiraFromContent(content)
135
+
136
+ return {
137
+ id: metadata.id || metadata.ID,
138
+ name: metadata.name || metadata.Name,
139
+ version: metadata.version || metadata.Version || metadata.Versão,
140
+ status: metadata.status || metadata.Status,
141
+ jira: jiraId,
142
+ related_prd: metadata.related_prd,
143
+ author: metadata.author || metadata.Autor || metadata.created_by,
144
+ date: metadata.date || metadata.Data || metadata.created_at
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Extrai Jira ID do conteúdo (fallback se não estiver no frontmatter)
150
+ *
151
+ * @param {string} content - Conteúdo do arquivo
152
+ * @returns {string|null} Jira ID ou null
153
+ */
154
+ function extractJiraFromContent(content) {
155
+ const match = content.match(/\b([A-Z]+-\d+)\b/)
156
+ return match ? match[1] : null
157
+ }
@@ -0,0 +1,198 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+
3
+ import { join, isAbsolute, dirname, basename } from "node:path";
4
+
5
+ const IDE_DIRS = {
6
+ windsurf: ".windsurf",
7
+ claude: ".claude",
8
+ cursor: ".cursor",
9
+ vscode: ".vscode",
10
+ codex: ".codex",
11
+ opencode: ".opencode",
12
+ gemini: ".gemini",
13
+ };
14
+
15
+ const AUTO_DETECT_ORDER = [
16
+ "windsurf",
17
+ "claude",
18
+ "cursor",
19
+ "vscode",
20
+ "codex",
21
+ "opencode",
22
+ "gemini",
23
+ ];
24
+
25
+ function* walkAncestors(start) {
26
+ let dir = start;
27
+ while (true) {
28
+ yield dir;
29
+ const parent = dirname(dir);
30
+ if (parent === dir) break;
31
+ dir = parent;
32
+ }
33
+ }
34
+
35
+ function envsAt(dir, ideFilter = null) {
36
+ const ides = ideFilter ? [ideFilter] : AUTO_DETECT_ORDER;
37
+ const found = [];
38
+ for (const ide of ides) {
39
+ const folder = IDE_DIRS[ide];
40
+ if (!folder) continue;
41
+ const p = join(dir, folder, "ENV.md");
42
+ if (existsSync(p)) found.push({ ide, path: p, root: dir });
43
+ }
44
+ return found;
45
+ }
46
+
47
+ /** Nome do workspace: pasta que contém $IDE/ (não o repo aberto). */
48
+ export function deriveWorkspaceName(envPath) {
49
+ const parent = dirname(envPath);
50
+ const name = basename(parent);
51
+ if (name.startsWith(".")) return basename(dirname(parent));
52
+ return name;
53
+ }
54
+
55
+ /**
56
+ * Resolve o path do ENV.md com a seguinte precedência:
57
+ * 1. --env-file (path explícito)
58
+ * 2. --ide (ex: windsurf → .windsurf/ENV.md) — sobe pastas se estiver num repo filho
59
+ * 3. JARVIS_ENV_FILE (variável de ambiente)
60
+ * 4. IDE (variável de ambiente → .{ide}/ENV.md)
61
+ * 5. Auto-detect (sobe até achar $IDE/ENV.md no workspace)
62
+ *
63
+ * Retorna { path, source, warnings, root }
64
+ */
65
+ export function resolveEnvPath(cwd, flags = {}) {
66
+ // 1. --env-file
67
+ if (flags["env-file"]) {
68
+ const p = isAbsolute(flags["env-file"])
69
+ ? flags["env-file"]
70
+ : join(cwd, flags["env-file"]);
71
+ if (!existsSync(p)) {
72
+ throw new Error(
73
+ `ENV.md não encontrado: ${p}\n` +
74
+ `Dica: verifique o path passado em --env-file`,
75
+ );
76
+ }
77
+ return { path: p, source: "--env-file", warnings: [], root: dirname(dirname(p)) };
78
+ }
79
+
80
+ // 2. --ide (cwd e ancestrais — abre um repo filho e ainda acha o workspace)
81
+ if (flags.ide) {
82
+ if (!IDE_DIRS[flags.ide]) {
83
+ throw new Error(
84
+ `IDE não suportada: "${flags.ide}"\n` +
85
+ `IDEs válidas: ${Object.keys(IDE_DIRS).join(", ")}`,
86
+ );
87
+ }
88
+ for (const dir of walkAncestors(cwd)) {
89
+ const found = envsAt(dir, flags.ide);
90
+ if (found.length === 1) {
91
+ return {
92
+ path: found[0].path,
93
+ source: `--ide ${flags.ide}`,
94
+ warnings: [],
95
+ root: found[0].root,
96
+ };
97
+ }
98
+ }
99
+ throw new Error(
100
+ `ENV.md não encontrado para --ide ${flags.ide} a partir de ${cwd}\n` +
101
+ `Dica: rode jarvis init --ide ${flags.ide} na pasta do workspace`,
102
+ );
103
+ }
104
+
105
+ // 3. JARVIS_ENV_FILE
106
+ if (process.env.JARVIS_ENV_FILE) {
107
+ const p = isAbsolute(process.env.JARVIS_ENV_FILE)
108
+ ? process.env.JARVIS_ENV_FILE
109
+ : join(cwd, process.env.JARVIS_ENV_FILE);
110
+ if (!existsSync(p)) {
111
+ throw new Error(`ENV.md não encontrado (JARVIS_ENV_FILE): ${p}`);
112
+ }
113
+ return { path: p, source: "JARVIS_ENV_FILE", warnings: [], root: dirname(dirname(p)) };
114
+ }
115
+
116
+ // 4. IDE env var
117
+ if (process.env.IDE && IDE_DIRS[process.env.IDE]) {
118
+ for (const dir of walkAncestors(cwd)) {
119
+ const found = envsAt(dir, process.env.IDE);
120
+ if (found.length === 1) {
121
+ return {
122
+ path: found[0].path,
123
+ source: `IDE=${process.env.IDE}`,
124
+ warnings: [],
125
+ root: found[0].root,
126
+ };
127
+ }
128
+ }
129
+ }
130
+
131
+ // 5. Auto-detect (ancestral mais próximo com exatamente um ENV.md)
132
+ for (const dir of walkAncestors(cwd)) {
133
+ const found = envsAt(dir);
134
+ if (found.length > 1) {
135
+ const ides = found.map((f) => f.ide).join(" | ");
136
+ throw new Error(
137
+ `Múltiplos ENV.md encontrados em ${dir} (${ides}).\n` +
138
+ `Especifique a IDE ativa. Exemplo: --ide claude`,
139
+ );
140
+ }
141
+ if (found.length === 1) {
142
+ return {
143
+ path: found[0].path,
144
+ source: `auto-detect (${found[0].ide})`,
145
+ warnings: [],
146
+ root: found[0].root,
147
+ };
148
+ }
149
+ }
150
+
151
+ // Fallback: ENV.md na raiz (comportamento legado)
152
+ return {
153
+ path: join(cwd, "ENV.md"),
154
+ source: "auto-detect (root)",
155
+ warnings: [],
156
+ root: cwd,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Lê e parseia o ENV.md do projeto.
162
+ * @param {string} cwd - Diretório raiz do projeto
163
+ * @param {string|null} envPath - Path explícito do ENV.md (opcional)
164
+ * Retorna um objeto com todas as variáveis key=value encontradas.
165
+ */
166
+ export function loadEnv(cwd, envPath = null) {
167
+ const p = envPath ?? join(cwd, "ENV.md");
168
+ if (!existsSync(p)) return {};
169
+
170
+ const lines = readFileSync(p, "utf-8").split("\n");
171
+ const env = {};
172
+
173
+ for (const line of lines) {
174
+ const trimmed = line.trim();
175
+ if (!trimmed || trimmed.startsWith("#")) continue;
176
+ const idx = trimmed.indexOf("=");
177
+ if (idx === -1) continue;
178
+ const key = trimmed.slice(0, idx).trim();
179
+ const value = trimmed.slice(idx + 1).trim();
180
+ if (key && value) env[key] = value;
181
+ }
182
+
183
+ if (!env.WORKSPACE) {
184
+ env.WORKSPACE = deriveWorkspaceName(p);
185
+ }
186
+
187
+ return env;
188
+ }
189
+
190
+ /** `{workspace}/.jarvis` — sobe ancestrais até achar `$IDE/ENV.md`. */
191
+ export function getJarvisDir(cwd = process.cwd(), flags = {}) {
192
+ try {
193
+ const { root } = resolveEnvPath(cwd, flags);
194
+ return join(root || cwd, ".jarvis");
195
+ } catch {
196
+ return join(cwd, ".jarvis");
197
+ }
198
+ }