jarvis-ai-framework 5.1.0 → 5.5.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 (58) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +14 -1
  3. package/agents/product/prod.discovery-interviewer.md +18 -83
  4. package/bin/commands/init.js +149 -2
  5. package/bin/commands/tokens.js +9 -3
  6. package/bin/lib/cli/program.js +14 -2
  7. package/bin/lib/core/docs-migrate.js +259 -0
  8. package/bin/lib/core/env-upgrade.js +84 -0
  9. package/bin/lib/core/profile-filter.js +15 -3
  10. package/bin/lib/core/sync-engine.js +5 -3
  11. package/bin/lib/core/token-report.js +1 -0
  12. package/bin/lib/docs/storage/build-index.js +2 -1
  13. package/bin/lib/vcs/api.js +13 -1
  14. package/bin/lib/vcs/create-issue.js +17 -3
  15. package/package.json +2 -2
  16. package/rules/AGENTS.md +7 -3
  17. package/rules/artifact-style-rules.md +53 -0
  18. package/rules/product/prod-rules.md +4 -2
  19. package/rules/product/prod.spec-rules.md +4 -4
  20. package/rules-on-demand/engineering/eng.plan-rules.md +1 -1
  21. package/rules-on-demand/engineering/eng.pr-rules.md +4 -3
  22. package/rules-on-demand/engineering/eng.start-rules.md +2 -2
  23. package/rules-on-demand/engineering/eng.transitions-rules.md +58 -0
  24. package/rules-on-demand/engineering/eng.work-rules.md +9 -3
  25. package/rules-on-demand/warm-up-consume-rules.md +30 -0
  26. package/skills/AGENTS.md +1 -1
  27. package/skills/eng-global-pr/SKILL.md +3 -1
  28. package/skills/eng-global-task-comment/SKILL.md +2 -0
  29. package/skills/jarvis-docs-central/SKILL.md +1 -1
  30. package/skills/jarvis-init/SKILL.md +60 -17
  31. package/skills/jarvis-report-issue/SKILL.md +64 -9
  32. package/templates/AGENTS.md +2 -0
  33. package/templates/ENV-template.md +11 -1
  34. package/templates/cdd-mind-map-template.md +26 -0
  35. package/templates/engineering/architecture-template.md +2 -1
  36. package/templates/engineering/plan-template.md +2 -0
  37. package/templates/product/prod-discovery-template.md +39 -71
  38. package/templates/product/prod-epic-template.md +1 -1
  39. package/templates/product/prod-frd-template.md +1 -1
  40. package/templates/product/prod-issue-template.md +1 -1
  41. package/templates/product/prod-prd-template.md +1 -1
  42. package/templates/warm-up-template.md +45 -0
  43. package/workflows/engineering/eng.plan.md +2 -1
  44. package/workflows/engineering/eng.pr.md +39 -6
  45. package/workflows/engineering/eng.pre-pr.md +2 -1
  46. package/workflows/engineering/eng.spec-consolidate.md +3 -1
  47. package/workflows/engineering/eng.start.md +12 -2
  48. package/workflows/engineering/eng.work.md +22 -5
  49. package/workflows/product/prod.spec.ard.md +2 -0
  50. package/workflows/product/prod.spec.breakdown.md +2 -0
  51. package/workflows/product/prod.spec.clarify.md +2 -0
  52. package/workflows/product/prod.spec.discovery.md +56 -116
  53. package/workflows/product/prod.spec.epic.md +2 -0
  54. package/workflows/product/prod.spec.frd.md +2 -0
  55. package/workflows/product/prod.spec.issue.md +2 -0
  56. package/workflows/product/prod.spec.md +2 -0
  57. package/workflows/product/prod.spec.prd.md +2 -0
  58. package/workflows/warm-up.md +68 -483
package/AGENTS.md CHANGED
@@ -194,6 +194,7 @@ Comandos disponíveis:
194
194
  jarvis whoami [--logout] # Exibir identidade (ENV.md / git / SO)
195
195
  jarvis logout # Remover auth.json legado (opcional)
196
196
  jarvis init # Bootstrap do framework no projeto
197
+ jarvis init --upgrade [--ide X] [--yes] # Atualizar projeto existente: assets + variáveis novas do ENV + documentos nas pastas novas
197
198
  jarvis list # Listar agents, skills e workflows
198
199
  jarvis install-rtk # Instalar RTK (token killer — economia 60-90% em tokens de shell)
199
200
  jarvis tokens [--hub X --position Y --area Z --squad W] [--rtk] [--json] # Estimar o que carrega no início da sessão (perfil do ENV.md se sem flags)
package/README.md CHANGED
@@ -116,9 +116,11 @@ Mesmos passos 2 e 3 do [Get Started](#get-started) acima — `jarvis init --ide
116
116
 
117
117
  ```bash
118
118
  npm install -g jarvis-ai-framework@latest
119
- jarvis init --ide {ide} # re-sincroniza os assets (agents/skills/workflows/rules)
119
+ jarvis init --upgrade --ide {ide} # assets + variáveis novas do ENV.md + documentos para as pastas novas
120
120
  ```
121
121
 
122
+ Depois, na IDE, rode `/jarvis-init upgrade`: ele vai direto ao Upgrade (C) e cuida do que precisa de conversa (Central docs antigo e o passo das stacks). O `--upgrade` só **acrescenta** chaves ao `ENV.md`: nenhuma chave existente muda. Ele mostra os documentos que estão em caminhos antigos e pergunta antes de movê-los (`--yes` move sem perguntar; sem terminal interativo, não move).
123
+
122
124
  **Instalou via clone local** (fluxo de [Desenvolvendo o Jarvis localmente](#desenvolvendo-o-jarvis-localmente)) — quando o repo no GitHub ganhar commits novos, sincronize assim:
123
125
 
124
126
  ### 1. Atualizar o clone
@@ -203,6 +205,17 @@ Escolha **Upgrade (C)** — adiciona chaves novas do template sem apagar os valo
203
205
 
204
206
  ---
205
207
 
208
+ ## Estilo dos artefatos
209
+
210
+ O `/jarvis-init` pergunta o `ARTIFACT_STYLE` (variável do `ENV.md`):
211
+
212
+ | Valor | O que acontece |
213
+ |---|---|
214
+ | `ai-generated` (padrão) | Como sempre: metadados, links de rastreabilidade e padrões da ferramenta |
215
+ | `human-generated` | Nada do que o Jarvis publica (commit, PR/MR, comentário no card, issue) leva marca de IA ou da IDE: o `/eng.pr` confere e limpa antes do push. Todo documento gerado pergunta, no fim, se você quer a versão humanizada, gravada ao lado como `{nome}.public.md` para repassar a clientes ou stakeholders |
216
+
217
+ Com `human-generated`, o `/jarvis-init` copia a rule `rules/artifact-style-rules.md` (eixo `ARTIFACT_STYLE` do `Applies to`); com `ai-generated`, ela nem existe na sessão. Trocou o valor à mão? Rode `/jarvis-init upgrade`.
218
+
206
219
  ## Funciona com qualquer stack
207
220
 
208
221
  O Jarvis não presume Go, PHP, NestJS ou React. Cada área (backend e frontend) tem uma **skill base neutra**, e cada projeto registra no `ENV.md` as **especializações** da sua stack (`BACKEND_SPECIALIZATIONS` e `FRONTEND_SPECIALIZATIONS`). Os comandos `eng.*` carregam a base mais o que o projeto registrou.
@@ -1,105 +1,40 @@
1
1
  ---
2
2
  name: prod.discovery-interviewer
3
- description: Entrevistador de produto que conduz o discovery de uma ideia: entende o problema, os requisitos iniciais e a viabilidade sem chutar, e registra tudo em um rascunho estruturado.
3
+ description: Entrevistador de produto que conduz o discovery de uma ideia: mostra primeiro o que entendeu, faz poucas perguntas de alto impacto com recomendação e registra um rascunho com scorecard e veredito, sem chutar.
4
4
  tools: Read, Write, Edit, Glob, Grep, LS, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
8
  # @prod.discovery-interviewer
9
9
 
10
- Entrevistador de produto do Jarvis. Conduz o `/prod.spec.discovery`: transforma uma ideia ainda crua em um rascunho estruturado, com o que se sabe, o que é hipótese e o que ainda é lacuna, e indica o próximo passo.
10
+ Entrevistador de produto do Jarvis no `/prod.spec.discovery`. **O fluxo, o orçamento de perguntas e a regra "não chute" estão no workflow `workflows/product/prod.spec.discovery.md`: siga-o.** Este arquivo define só a postura.
11
11
 
12
- As regras de escrita de especificação ficam em `rules/product/` (`prod.spec-rules.md`). O fluxo do comando (criação e retomada do arquivo, veredito, limites) está no workflow `workflows/product/prod.spec.discovery.md`; este arquivo define a **postura**.
12
+ ## Postura
13
13
 
14
- ## Persona
14
+ Você é um product manager experiente: **testa a ideia, não a julga**, e economiza o tempo de quem responde.
15
15
 
16
- Você é um product manager experiente e curioso, e faz o papel de entrevistador: a qualidade do discovery depende das perguntas certas, não de preencher um formulário.
17
-
18
- - **Faz perguntas abertas** e escuta a resposta antes de formular a próxima
19
- - **Aprofunda respostas rasas**: "por quê?", "para quem?", "com que frequência?", "me dá um exemplo real", "o que acontece hoje?"
20
- - **Pede evidência** quando ouve uma afirmação sem base ("todo mundo quer") e registra se ela é dado, observação ou suposição
21
- - **Aponta contradições**, entre respostas ou entre o que o usuário disse e o que está no projeto, e pede que o usuário resolva
22
- - **Levanta o que o usuário provavelmente não considerou**: quem mais é impactado, custo de manutenção, o que acontece se der errado, a alternativa mais simples
23
- - **Adapta o roteiro às respostas**: não segue uma lista fixa e não repete temas já esgotados
24
- - Tom direto e respeitoso; não julga a ideia, testa a ideia
25
-
26
- ## Objetivo
27
-
28
- Ajudar o usuário a fazer o melhor discovery possível de uma ideia, cobrindo quatro eixos:
29
-
30
- 1. **Ideia**: o que é e para quem
31
- 2. **Problema**: qual dor, que evidência existe, quem sofre, como se resolve hoje
32
- 3. **Requisitos iniciais**: o que precisaria ser verdade, em alto nível, como hipóteses
33
- 4. **Viabilidade**: sinal indicativo de valor, usabilidade, técnica e negócio, com riscos e dependências
34
-
35
- O resultado é um arquivo no formato do template `$PROD_TEMPLATES/prod-discovery-template.md` (`templates/product/prod-discovery-template.md`), terminando com um veredito (`proceed`, `investigate_more` ou `do_not_proceed`) e um próximo passo sugerido.
36
-
37
- ## Quando Usar
38
-
39
- - O usuário tem uma ideia e ainda não sabe se o problema é real, quais são os requisitos ou se é viável
40
- - O usuário roda `/prod.spec.discovery`, com uma ideia ou apontando um discovery existente para retomar
41
- - O `/prod.spec` identifica que só existe uma ideia inicial
42
-
43
- Não use quando já existe uma spec (use `/prod.spec.clarify`) ou quando o escopo já está claro e o usuário quer documentá-lo (use `/prod.spec.prd`, `/prod.spec.frd` ou `/prod.spec.issue`).
44
-
45
- ## Entrada
46
-
47
- - A ideia em texto livre (`$ARGUMENTS`), ou o caminho ou nome de um discovery existente para retomar
48
- - O contexto do projeto: `ENV.md`, documentos em `$PROD_DOCS` e o código, lidos antes de perguntar
49
-
50
- ## Saída
51
-
52
- - O arquivo `$PROD_DOCS/discoveries/discovery-{id}-{nome}.md`, preenchido pelo template e atualizado a cada tema
53
- - Uma seção de **Próximo passo sugerido**, sempre presente e sempre só uma sugestão
54
-
55
- ## Como conduzir a entrevista
56
-
57
- 1. **Comece explicando** em poucas linhas que vai entrevistar, quais temas cobrirá (ideia, problema, requisitos, viabilidade) e que o usuário pode responder "não sei" a qualquer momento
58
- 2. **Consulte o projeto antes de perguntar**: documentos existentes (para não duplicar um PRD) e o código (para embasar a viabilidade)
59
- 3. **Uma pergunta por vez.** Use o `AskUserQuestion` quando estiver disponível; caso contrário, o formato de tabela do `prod-rules.md`. Espere a resposta antes de seguir
60
- 4. **Se o usuário não responde ou diz "não sei"**, não repita a pergunta: registre "não informado" e siga
61
- 5. **Ao cobrir um tema**, resuma em poucas linhas o que entendeu e peça confirmação antes de passar ao próximo
62
- 6. **Priorize as perguntas de maior impacto** na decisão de seguir ou não, em vez de esgotar todas as possíveis
63
- 7. **Quando achar que já tem informação suficiente**, proponha encerrar e pergunte se o usuário quer acrescentar algo antes de fechar o documento
64
-
65
- ## Não chute (regra inviolável)
66
-
67
- - Quando você não tem uma informação (público, volume, custo, prazo, restrição técnica, comportamento de usuários, estado atual do código), **não presuma nem complete com "o que costuma ser"**: pergunte, busque no projeto ou registre como lacuna
68
- - Todo fato citado indica a origem: resposta do usuário, arquivo do projeto ou documentação consultada. O que não tem origem entra no documento como **suposição a validar**
69
- - Se o usuário pedir "preencha o que faltar" ou "assuma o padrão", registre o item como **suposição explícita**, nunca como fato, e não a use para sustentar o veredito
70
- - Uma **lacuna crítica nunca** resulta em `proceed`: o veredito é `investigate_more`
71
- - Quando a viabilidade técnica depende de bibliotecas, APIs ou serviços, consulte a documentação atual (por exemplo via Context7) em vez de responder de memória
16
+ - **Entende antes de perguntar:** lê o que já existe e devolve o que entendeu, separando o que foi dito, o que é suposição e o que falta
17
+ - **Pergunta pouco e certo:** só o que muda o veredito, da pergunta mais impactante para a menos, sempre com o porquê e uma recomendação
18
+ - **Não pergunta o óbvio:** um padrão razoável vira suposição registrada, não pergunta
19
+ - **Pede evidência e aponta contradição** só quando isso muda a decisão
20
+ - **Lembra do que o usuário não considerou:** quem mais é impactado, custo de manutenção, o que acontece se der errado, a alternativa mais simples
21
+ - **Fecha com clareza:** abordagens com recomendação, scorecard honesto (`desconhecido` é uma resposta válida) e um próximo passo pronto para usar
22
+ - Tom direto e respeitoso
72
23
 
73
24
  ## Skills Disponíveis
74
25
 
75
- As skills são apoio, nunca a fonte da decisão. A busca em `$PROD_DOCS` não é uma skill: é feita sempre, antes de perguntar.
76
-
77
26
  ### jarvis-docs-central
78
- Para conhecer o que já foi implementado no produto (funcionalidades do Central docs), quando `CENTRAL_DOCS_STORAGE` estiver configurado:
79
- - Arquivo: `$IDE/skills/jarvis-docs-central/SKILL.md`
80
- - Confiança: sempre
81
-
82
- ### jarvis-context-detect
83
- Para calibrar a profundidade da entrevista:
84
- - Arquivo: `$IDE/skills/jarvis-context-detect/SKILL.md`
85
- - Confiança: sempre
27
+ O que já foi implementado, quando `CENTRAL_DOCS_STORAGE` estiver configurado. Confiança: sempre.
86
28
 
87
29
  ### eng-backend-arch-c4
88
- Para consultar a arquitetura atual:
89
- - Arquivo: `$IDE/skills/eng-backend-arch-c4/SKILL.md`
90
- - Confiança: só com a confirmação do usuário (skill de engenharia: pergunte antes de consultá-la; o que ela retornar entra no discovery como **suposição a validar**, não como fato)
30
+ Arquitetura atual. Confiança: só com a confirmação do usuário; o retorno é **suposição a validar**.
91
31
 
92
32
  ### eng-platform
93
- Para quando a ideia envolve infraestrutura, dados pessoais ou fluxo financeiro com risco de segurança/privacidade:
94
- - Arquivo: `$IDE/skills/eng-platform/SKILL.md` (temas 9 e 13)
95
- - Confiança: só com a confirmação do usuário (skill de engenharia: pergunte antes de consultá-la; o que ela retornar entra no discovery como **suposição a validar**, não como fato)
33
+ Infraestrutura, dados pessoais ou risco de segurança (temas 9 e 13). Confiança: só com a confirmação do usuário; o retorno é **suposição a validar**.
96
34
 
97
35
  ## Restrições
98
36
 
99
- - **O discovery é um rascunho.** Você **não** gera PRD, FRD, épico, issue, tarefas, histórias, critérios de aceitação nem estimativas (horas ou pontos). Se o usuário pedir, explique que é outra etapa e indique o comando certo
100
- - **Não escreve código** e não implementa nada
101
- - **Não grava credenciais, tokens nem dados pessoais de clientes** no arquivo: o discovery é versionado
102
- - **Não entrevista terceiros**: a entrevista é sempre com o usuário que executou o comando
103
- - **Não executa o próximo passo**: só sugere. O usuário pode escolher outro caminho ou parar ali
104
- - Um rascunho de abordagem técnica pode aparecer na viabilidade, sempre como hipótese a validar; a decisão de arquitetura pertence ao fluxo de engenharia
105
- - Siga as regras de `$PROD_RULES` (`prod-rules.md`): validação do `ENV.md`, idioma (pt-BR por padrão, ou o idioma da interação do usuário) e confirmação antes de salvar arquivos
37
+ - Não gera PRD, FRD, épico, issue, histórias, critérios de aceitação nem estimativas; indique o comando certo
38
+ - Não escreve código nem decide arquitetura (um rascunho técnico é sempre suposição)
39
+ - Não entrevista terceiros e não executa o próximo passo: só sugere
40
+ - Não grava credenciais, tokens nem dados pessoais de clientes
@@ -1,5 +1,5 @@
1
1
  import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { join, dirname, basename } from "node:path";
3
3
  import { createInterface } from "node:readline";
4
4
  import { syncAssets } from "../lib/core/sync-engine.js";
5
5
  import { discoverAll } from "../lib/core/scanner.js";
@@ -7,12 +7,23 @@ import {
7
7
  IDES,
8
8
  getIDEConfig,
9
9
  getIDEFolder,
10
+ getIDEValues,
10
11
  getWorkflowsFolder,
11
12
  isIDESupported,
12
13
  } from "../lib/config/ide-config.js";
13
14
  import { showBanner, RED, GREEN, BLUE, YELLOW, CYAN, DIM, BOLD, NC } from "../lib/utils/ui.js";
14
- import { getPackageInfo } from "../lib/utils/paths.js";
15
+ import { getPackageInfo, getFrameworkRoot } from "../lib/utils/paths.js";
15
16
  import { logger, configureFromFlags } from "../lib/utils/logger.js";
17
+ import { resolveEnvPath } from "../lib/env-loader.js";
18
+ import { LOCK_FILE } from "../lib/config/constants.js";
19
+ import { parseEnvEntries, planEnvUpgrade, applyEnvUpgrade } from "../lib/core/env-upgrade.js";
20
+ import {
21
+ expandEnv,
22
+ planDocsMigration,
23
+ applyDocsMigration,
24
+ rewriteRelatedDiscovery,
25
+ declineEnvValues,
26
+ } from "../lib/core/docs-migrate.js";
16
27
 
17
28
  function ask(rl, question) {
18
29
  return new Promise((resolve) => rl.question(question, resolve));
@@ -25,6 +36,11 @@ export async function init(flags) {
25
36
 
26
37
  showBanner();
27
38
 
39
+ if (flags.upgrade) {
40
+ process.exitCode = await runUpgrade(cwd, flags);
41
+ return;
42
+ }
43
+
28
44
  let ide;
29
45
  if (flags.ide) {
30
46
  if (!isIDESupported(flags.ide)) {
@@ -207,3 +223,134 @@ export async function init(flags) {
207
223
  logger.info(` ${YELLOW}jarvis list${NC}`);
208
224
  logger.info("");
209
225
  }
226
+
227
+ /** IDE de um ENV.md encontrado (`.claude/ENV.md` → `claude`). */
228
+ function ideFromEnvPath(envPath) {
229
+ const folder = basename(dirname(envPath));
230
+ return getIDEValues().find((v) => `.${getIDEFolder(v)}` === folder);
231
+ }
232
+
233
+ function readLockVersion(workspaceDir) {
234
+ try {
235
+ return (
236
+ JSON.parse(readFileSync(join(workspaceDir, LOCK_FILE), "utf-8")).version || "desconhecida"
237
+ );
238
+ } catch {
239
+ return "desconhecida";
240
+ }
241
+ }
242
+
243
+ /**
244
+ * `jarvis init --upgrade`: atualiza um projeto já configurado em uma passada.
245
+ * 1. arquivos do framework (como o --force, sem perguntar); 2. só as chaves novas do ENV;
246
+ * 3. documentos dos caminhos antigos → docs/jarvis/… (com confirmação ou --yes).
247
+ * Nunca imprime valores do ENV, só nomes de chave e caminhos.
248
+ * @returns {Promise<number>} código de saída
249
+ */
250
+ async function runUpgrade(cwd, flags) {
251
+ let resolved;
252
+ try {
253
+ resolved = resolveEnvPath(cwd, flags.ide ? { ide: flags.ide } : {});
254
+ } catch (err) {
255
+ resolved = { error: err.message.split("\n")[0] };
256
+ }
257
+ const ide = flags.ide || (resolved.path && ideFromEnvPath(resolved.path));
258
+ if (resolved.error || !ide || !existsSync(resolved.path)) {
259
+ logger.error(
260
+ `${RED}🚫 Nenhuma instalação do Jarvis encontrada (ENV.md ausente)${resolved.error ? `: ${resolved.error}` : ""}.${NC}`
261
+ );
262
+ logger.error(
263
+ `${YELLOW}Rode ${BOLD}jarvis init --ide ${flags.ide || "{ide}"}${NC}${YELLOW} e depois ${BOLD}/jarvis-init${NC}${YELLOW} na IDE.${NC}\n`
264
+ );
265
+ return 1;
266
+ }
267
+ const workspaceDir = resolved.root;
268
+ const envPath = resolved.path;
269
+ const previousVersion = readLockVersion(workspaceDir);
270
+
271
+ // 1. Arquivos do framework (o ENV.md não está entre os sincronizados)
272
+ logger.info(`${BLUE}⬆️ Upgrade do Jarvis em .${getIDEFolder(ide)}/${NC}\n`);
273
+ const sync = syncAssets(workspaceDir, ide, {
274
+ force: true,
275
+ workflowsFolder: getWorkflowsFolder(ide),
276
+ keepEnvValues: true,
277
+ });
278
+ for (const item of sync.errors) logger.error(`${RED} ✗ ${item}${NC}`);
279
+
280
+ // 2. Variáveis novas (só acrescenta)
281
+ const envText = readFileSync(envPath, "utf-8");
282
+ const templateText = readFileSync(
283
+ join(getFrameworkRoot(), "templates", "ENV-template.md"),
284
+ "utf-8"
285
+ );
286
+ const envPlan = planEnvUpgrade(envText, templateText);
287
+ const addedKeys = envPlan.added.map((a) => a.key);
288
+
289
+ // 3. Documentos: o plano usa o ENV como ficará depois do upgrade (com as chaves novas)
290
+ const futureEntries = parseEnvEntries(
291
+ `${envText}\n${envPlan.added.map(({ key, value }) => `${key}=${value}`).join("\n")}\n`
292
+ );
293
+ const env = expandEnv(futureEntries);
294
+ const docsPlan = planDocsMigration(workspaceDir, env);
295
+
296
+ let accepted = false;
297
+ if (docsPlan.moves.length > 0) {
298
+ logger.info(`${YELLOW}📁 Documentos em caminhos antigos:${NC}`);
299
+ for (const m of docsPlan.moves) logger.info(` ${m.from} → ${m.to}`);
300
+ if (flags.yes) accepted = true;
301
+ else if (process.stdin.isTTY) {
302
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
303
+ const answer = await ask(rl, `Mover para docs/jarvis/…? (s/N): `);
304
+ rl.close();
305
+ accepted = answer.trim().toLowerCase() === "s";
306
+ } else {
307
+ logger.info(`${DIM} Sem terminal interativo e sem --yes: nada será movido.${NC}`);
308
+ }
309
+ }
310
+
311
+ const overrides =
312
+ docsPlan.moves.length > 0 && !accepted ? declineEnvValues(docsPlan, addedKeys, env) : {};
313
+ const today = new Date().toISOString().slice(0, 10);
314
+ applyEnvUpgrade(envPath, envPlan, today, overrides);
315
+
316
+ let moved = [];
317
+ let rewritten = [];
318
+ let moveErrors = [];
319
+ if (accepted) {
320
+ const result = applyDocsMigration(workspaceDir, docsPlan, env);
321
+ moved = result.moved;
322
+ moveErrors = result.errors;
323
+ rewritten = rewriteRelatedDiscovery(workspaceDir, env, moved);
324
+ }
325
+
326
+ // 4. Resumo (só nomes de chave e caminhos)
327
+ const pkg = getPackageInfo();
328
+ logger.info("");
329
+ logger.info(`${GREEN}✅ Upgrade concluído: ${previousVersion} → ${pkg.version}${NC}`);
330
+ logger.info(` • Arquivos do framework: ${sync.copied.length} item(ns) sincronizado(s)`);
331
+ logger.info(
332
+ ` • ENV.md: ${addedKeys.length ? `+ ${addedKeys.join(", ")}` : "nenhuma variável nova"}`
333
+ );
334
+ if (Object.keys(overrides).length) {
335
+ logger.info(` • Mantidos no caminho antigo: ${Object.keys(overrides).join(", ")}`);
336
+ }
337
+ if (docsPlan.moves.length && !accepted) {
338
+ logger.info(` • Documentos: nada movido (${docsPlan.moves.length} no caminho antigo)`);
339
+ }
340
+ if (moved.length) logger.info(` • Documentos movidos: ${moved.length}`);
341
+ if (rewritten.length) logger.info(` • related_discovery atualizado: ${rewritten.join(", ")}`);
342
+ for (const s of docsPlan.skipped)
343
+ logger.info(`${YELLOW} ⚠️ Pulado (${s.reason}): ${s.from}${NC}`);
344
+ for (const e of moveErrors) logger.error(`${RED} ✗ ${e}${NC}`);
345
+ for (const k of envPlan.pending) {
346
+ logger.info(`${YELLOW} ⚠️ ${k} está vazio: responda no /jarvis-init upgrade${NC}`);
347
+ }
348
+ if (envPlan.warnings.includes("CENTRAL_DOCS_REPO")) {
349
+ logger.info(
350
+ `${YELLOW} ⚠️ Central docs no formato antigo (CENTRAL_DOCS_REPO): a migração é feita pelo /jarvis-init upgrade${NC}`
351
+ );
352
+ }
353
+ logger.info("");
354
+ logger.info(`${CYAN}➡️ Agora rode ${BOLD}/jarvis-init upgrade${NC}${CYAN} na IDE.${NC}\n`);
355
+ return sync.errors.length || moveErrors.length ? 1 : 0;
356
+ }
@@ -6,16 +6,20 @@ import { logger } from "../lib/utils/logger.js";
6
6
 
7
7
  const AXES = ["HUB", "POSITION", "AREA", "SQUAD"];
8
8
 
9
- /** Perfil: as flags (`--hub` etc.) mandam; o que faltar vem do ENV.md. */
9
+ /**
10
+ * Perfil: as flags (`--hub` etc.) mandam; o que faltar vem do ENV.md.
11
+ * ARTIFACT_STYLE é opcional (vazio = ai-generated) e não entra em `missing`.
12
+ */
10
13
  function resolveProfile(flags) {
11
14
  const profile = {};
12
15
  for (const axis of AXES) {
13
16
  const value = flags[axis.toLowerCase()];
14
17
  if (typeof value === "string") profile[axis] = value;
15
18
  }
19
+ if (typeof flags.artifactStyle === "string") profile.ARTIFACT_STYLE = flags.artifactStyle;
16
20
 
17
21
  let rtkEnabled = flags.rtk === true || flags.rtk === "true";
18
- // O ENV.md só entra quando falta algum eixo; com os 4 eixos nas flags, o RTK vem só da flag.
22
+ // O ENV.md só entra quando falta algum eixo; com os 4 eixos nas flags, o RTK e o estilo vêm só das flags.
19
23
  if (AXES.some((axis) => !profile[axis])) {
20
24
  try {
21
25
  const { path } = resolveEnvPath(process.cwd(), flags);
@@ -23,6 +27,8 @@ function resolveProfile(flags) {
23
27
  for (const axis of AXES) {
24
28
  if (!profile[axis] && env[axis]) profile[axis] = env[axis];
25
29
  }
30
+ if (!profile.ARTIFACT_STYLE && env.ARTIFACT_STYLE)
31
+ profile.ARTIFACT_STYLE = env.ARTIFACT_STYLE;
26
32
  if (flags.rtk === undefined) rtkEnabled = env.RTK_ENABLED === "true";
27
33
  } catch {
28
34
  // sem ENV.md: valem só as flags
@@ -59,7 +65,7 @@ export async function tokens(flags) {
59
65
  showBanner();
60
66
  logger.info(`${CYAN}📏 Custo estimado no início da sessão${NC}`);
61
67
  logger.info(
62
- `${DIM}Perfil: HUB=${profile.HUB} | POSITION=${profile.POSITION} | AREA=${profile.AREA} | SQUAD=${profile.SQUAD}` +
68
+ `${DIM}Perfil: HUB=${profile.HUB} | POSITION=${profile.POSITION} | AREA=${profile.AREA} | SQUAD=${profile.SQUAD} | ARTIFACT_STYLE=${profile.ARTIFACT_STYLE || "ai-generated"}` +
63
69
  ` | RTK=${rtkEnabled ? "ligado" : "desligado"}${NC}`
64
70
  );
65
71
  logger.info(`${DIM}${report.estimate}${NC}`);
@@ -87,7 +87,12 @@ export function buildProgram() {
87
87
  const initCmd = cmd(program, "init")
88
88
  .description("Bootstrap do framework no workspace")
89
89
  .option("--ide <ide>", "IDE a configurar (pula o menu interativo)")
90
- .option("--force", "Sobrescreve a instalação existente sem perguntar");
90
+ .option("--force", "Sobrescreve a instalação existente sem perguntar")
91
+ .option(
92
+ "--upgrade",
93
+ "Atualiza um projeto já configurado: arquivos do framework, variáveis novas do ENV e pastas de documentos"
94
+ )
95
+ .option("--yes", "Com --upgrade, move os documentos para as pastas novas sem perguntar");
91
96
  withLogOptions(initCmd).action((options) => init(toLegacyFlags(options)));
92
97
 
93
98
  cmd(program, "list")
@@ -164,6 +169,7 @@ export function buildProgram() {
164
169
  .option("--position <position>")
165
170
  .option("--area <area>")
166
171
  .option("--squad <squad>")
172
+ .option("--artifact-style <estilo>", "ai-generated ou human-generated (padrão: lido do ENV.md)")
167
173
  .option("--rtk", "Força RTK ligado (padrão: lido do ENV.md)")
168
174
  .option("--json", "Saída em JSON")
169
175
  .option("--ide <ide>")
@@ -201,8 +207,14 @@ export function buildProgram() {
201
207
  .option("--repo <url-ou-path>")
202
208
  .option("--title <titulo>")
203
209
  .option("--body-file <path>")
210
+ .option("--label <labels>", "Labels separadas por vírgula (padrão: bug)")
204
211
  .action((options) =>
205
- runCreateIssue({ repo: options.repo, title: options.title, bodyFile: options.bodyFile })
212
+ runCreateIssue({
213
+ repo: options.repo,
214
+ title: options.title,
215
+ bodyFile: options.bodyFile,
216
+ labels: options.label,
217
+ })
206
218
  );
207
219
 
208
220
  const tasks = cmd(program, "tasks").description("Adapters de task manager");