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.
- package/AGENTS.md +1 -0
- package/README.md +14 -1
- package/agents/product/prod.discovery-interviewer.md +18 -83
- package/bin/commands/init.js +149 -2
- package/bin/commands/tokens.js +9 -3
- package/bin/lib/cli/program.js +14 -2
- package/bin/lib/core/docs-migrate.js +259 -0
- package/bin/lib/core/env-upgrade.js +84 -0
- package/bin/lib/core/profile-filter.js +15 -3
- package/bin/lib/core/sync-engine.js +5 -3
- package/bin/lib/core/token-report.js +1 -0
- package/bin/lib/docs/storage/build-index.js +2 -1
- package/bin/lib/vcs/api.js +13 -1
- package/bin/lib/vcs/create-issue.js +17 -3
- package/package.json +2 -2
- package/rules/AGENTS.md +7 -3
- package/rules/artifact-style-rules.md +53 -0
- package/rules/product/prod-rules.md +4 -2
- package/rules/product/prod.spec-rules.md +4 -4
- package/rules-on-demand/engineering/eng.plan-rules.md +1 -1
- package/rules-on-demand/engineering/eng.pr-rules.md +4 -3
- package/rules-on-demand/engineering/eng.start-rules.md +2 -2
- package/rules-on-demand/engineering/eng.transitions-rules.md +58 -0
- package/rules-on-demand/engineering/eng.work-rules.md +9 -3
- package/rules-on-demand/warm-up-consume-rules.md +30 -0
- package/skills/AGENTS.md +1 -1
- package/skills/eng-global-pr/SKILL.md +3 -1
- package/skills/eng-global-task-comment/SKILL.md +2 -0
- package/skills/jarvis-docs-central/SKILL.md +1 -1
- package/skills/jarvis-init/SKILL.md +60 -17
- package/skills/jarvis-report-issue/SKILL.md +64 -9
- package/templates/AGENTS.md +2 -0
- package/templates/ENV-template.md +11 -1
- package/templates/cdd-mind-map-template.md +26 -0
- package/templates/engineering/architecture-template.md +2 -1
- package/templates/engineering/plan-template.md +2 -0
- package/templates/product/prod-discovery-template.md +39 -71
- package/templates/product/prod-epic-template.md +1 -1
- package/templates/product/prod-frd-template.md +1 -1
- package/templates/product/prod-issue-template.md +1 -1
- package/templates/product/prod-prd-template.md +1 -1
- package/templates/warm-up-template.md +45 -0
- package/workflows/engineering/eng.plan.md +2 -1
- package/workflows/engineering/eng.pr.md +39 -6
- package/workflows/engineering/eng.pre-pr.md +2 -1
- package/workflows/engineering/eng.spec-consolidate.md +3 -1
- package/workflows/engineering/eng.start.md +12 -2
- package/workflows/engineering/eng.work.md +22 -5
- package/workflows/product/prod.spec.ard.md +2 -0
- package/workflows/product/prod.spec.breakdown.md +2 -0
- package/workflows/product/prod.spec.clarify.md +2 -0
- package/workflows/product/prod.spec.discovery.md +56 -116
- package/workflows/product/prod.spec.epic.md +2 -0
- package/workflows/product/prod.spec.frd.md +2 -0
- package/workflows/product/prod.spec.issue.md +2 -0
- package/workflows/product/prod.spec.md +2 -0
- package/workflows/product/prod.spec.prd.md +2 -0
- 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} #
|
|
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:
|
|
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
|
|
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
|
-
|
|
12
|
+
## Postura
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Você é um product manager experiente: **testa a ideia, não a julga**, e economiza o tempo de quem responde.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
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
|
package/bin/commands/init.js
CHANGED
|
@@ -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
|
+
}
|
package/bin/commands/tokens.js
CHANGED
|
@@ -6,16 +6,20 @@ import { logger } from "../lib/utils/logger.js";
|
|
|
6
6
|
|
|
7
7
|
const AXES = ["HUB", "POSITION", "AREA", "SQUAD"];
|
|
8
8
|
|
|
9
|
-
/**
|
|
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
|
|
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}`);
|
package/bin/lib/cli/program.js
CHANGED
|
@@ -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({
|
|
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");
|