Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"name": "fluig",
"source": "./fluig",
"description": "Plugin para desenvolvimento TOTVS Fluig — ciclo completo: design (brainstorm), scaffolding (widget/dataset/form/workflow), revisão estática + testes (review) e deploy (verify).",
"version": "2.2.0",
"version": "2.3.0",
"author": {
"name": "DataAgile"
},
Expand Down
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,61 @@ Histórico das versões públicas do `dataagile-agent-kit`.

---

## [2.9.0] — 2026-08-08

### Dataset e evento agora têm teste unitário de verdade (fluig 2.3.0)

O server-side do Fluig rodava sem rede: dataset e evento só eram exercidos depois do
deploy, no servidor. Agora a `/fluig:test` traz um **harness Node** (`fluig-mock.cjs`) que
carrega o fonte `ds_*`/`wf_*` **sem alterar nada** num contexto com os globais Fluig
mockados — o motor do Fluig é Rhino/ES5, subconjunto do que o Node executa. Gate mecânico
por `node --test` com JUnit e cobertura, mais a checagem que a cobertura não faz: **fonte
que nenhum teste carrega é invisível no relatório**, então todo artefato tocado pela task
precisa ter arquivo de teste, independente do percentual. O limite fica dito em voz alta:
o Node valida a lógica, não o Rhino — interop Java só o QA pega.

O `fluig-lint.sh` passou a **rotear por mundo**: `ds_*`, `wf_*`, `events/` e `Util/` são
lintados como ES5 (`let`/`const`/arrow/`class` viram erro de parse, porque quebram no
servidor) e isso roda mesmo em repositório sem `@po-ui`; `.ts` de widget continua no
ESLint do projeto, com fallback para o config do plugin. Sem ESLint disponível, greps
mínimos seguram o gate em vez de deixá-lo passar em silêncio.

### E2E saiu da /fluig:test e virou skill própria

Nova **`/fluig:test-web`**: roteiro aprovado antes de executar, screenshot por passo em
`evidencias/`, critério verificável **literal** (não "a tela parece certa"), tratamento de
erro com o log do servidor, e — o pulo — a sessão exploratória validada vira **spec de
regressão versionada** rodada com `--reporter=junit`. Dois modos, uma fonte: a sessão dá a
evidência, o spec dá o gate determinístico que o `/fluig:qa` consome.

O `/fluig:qa` deixou de aceitar "a suíte está verde": confere artefato por artefato da
task qual spec o cobre, e artefato sem spec **para o QA** e aciona a `/fluig:test-web`.
Ganhou também uma **lista fechada de risco ALTO** — seis itens que não se julgam nem se
rebaixam por impressão visual.

### Memória do ambiente do cliente

Nova **`/fluig:arqueologia`**, a variante de ambiente: sem código-fonte no repositório, o
mapa da fatia sai do que está **publicado** (REST autenticada do Fluig ou exportações do
Studio), e o teto de confiança muda junto — LACUNA frequente aqui é informação, não falha.
Divergência entre repositório e servidor é achado próprio. O `/fluig:plan` ganhou o Passo
3.5 (o que não pode quebrar, com forma de verificar) e o `/fluig:verify` o writeback do
Passo 5.5, que só roda **com o deploy concluído** — entrega fantasma no mapa seria uma
regra CONFIRMADO falsa.

### gates.json unificado e brainstorm por rodadas

O `gates.json` do Fluig passou a viver em `docs/fluig/plans/<slug>.gates.json` com esquema
único, `tests_unit` dividido em `widget` e `server` (metade sem artefato grava `n/a`
**explícito**, nunca chave ausente) e um **lint gate global** antes dos reviews — máquina
antes do LLM. `deploy`, `qa` e `verify` leem o arquivo em vez da conversa.

O `/fluig:brainstorm` ganhou o Passo 0 (levantar os fatos do projeto antes de perguntar
qualquer coisa), rodadas de fronteira e recomendação rotulada com fonte — com o teto
correto: a base fluig vem de documentação, então MCP sozinho não passa de INFERIDO. A
`/fluig:api-ref` foi reescrita sobre as tools que o seu tier realmente expõe, com o
vocabulário real dos dados.

## [2.8.0] — 2026-08-08

### O ciclo Protheus passou a lembrar do legado do cliente (protheus 2.16.0)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# DA DataAgile Agent Kit

[![Versão](https://img.shields.io/badge/versão-2.8.0-1a4d5c?style=flat-square&logoColor=white)](https://github.com/tbc-servicos/dataagile-agent-kit/releases)
[![Versão](https://img.shields.io/badge/versão-2.9.0-1a4d5c?style=flat-square&logoColor=white)](https://github.com/tbc-servicos/dataagile-agent-kit/releases)
[![Claude Code](https://img.shields.io/badge/Claude_Code-plugin-CC785C?style=flat-square&logoColor=white)](https://claude.ai/code)
[![Protheus](https://img.shields.io/badge/Protheus-ADVPL%2FTLPP-1a4d5c?style=flat-square&logoColor=white)](https://dataagile-agent-kit.dataagile.com.br)
[![PO--UI MCP](https://img.shields.io/badge/PO--UI-MCP-22C55E?style=flat-square&logoColor=white)](https://po-ui.io)
Expand Down Expand Up @@ -146,7 +146,7 @@ mkdir -p ~/.config/dataagile && echo '{"api_key":"SUA_CHAVE"}' > ~/.config/dataa

| Server | Função |
|--------|--------|
| `tbc-knowledge` | Base ADVPL remota — `searchFunction`, `findEndpoint`, `findSmartView`, `findExecAuto`, `findMvcPattern` e mais 4 tools |
| `tbc-knowledge` | Base ADVPL remota — `searchFunction`, `findEndpoint`, `findSmartView`, `searchKnowledge`, `submitFeedback` + busca vetorial `ragSearchKnowledge`/`ragSearchDocs` |
| `local-knowledge-external` | Base offline de conhecimento técnico ADVPL/TLPP curado e docs Protheus |
| `po-ui` | MCP oficial PO-UI — componentes Angular para fronts Protheus, inputs, outputs e exemplos |

Expand Down
2 changes: 1 addition & 1 deletion fluig/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "fluig",
"description": "Plugin Claude Code para desenvolvimento TOTVS Fluig — ciclo completo: brainstorm, planejamento, implementação com teammates (TDD), deploy, QA (E2E Playwright), verificação. Scaffolding de formulários, datasets, widgets Angular 19 + PO-UI, workflows BPM.",
"version": "2.2.0",
"version": "2.3.0",
"author": {
"name": "TBC - Time de Desenvolvimento"
},
Expand Down
6 changes: 5 additions & 1 deletion fluig/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
- Custo: ~2K tokens fixos

### Camada 2 — Sob demanda (0 tokens até chamada)
- MCP queries (`searchFluigPatterns`, `searchFluigApi`, etc.)
- MCP queries (`searchKnowledge`, `ragSearchKnowledge`, `ragSearchDocs`)
- Consultas ao RAG de documentação

### Camada 3 — Compactável (contexto de trabalho)
Expand All @@ -87,6 +87,10 @@ export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=50
## Ciclo de Desenvolvimento

```
/fluig:base → sandbox descartável na máquina do dev (inner loop E2E)
↓ (opcional)
/fluig:arqueologia → mapa do ambiente da fatia (quando não houver)
↓
/fluig:brainstorm → design aprovado
↓
/fluig:plan → plano de implementação
Expand Down
7 changes: 6 additions & 1 deletion fluig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ source ~/.zshrc
## Ciclo de Desenvolvimento

```
/fluig:arqueologia → mapa do ambiente da fatia (quando não houver)
↓
/fluig:brainstorm → entrevista + design aprovado + spec em disco
↓
/fluig:plan → plano de implementação com tasks TDD
Expand All @@ -102,6 +104,7 @@ Cada skill termina com **"Próximo passo:"** guiando o dev para a etapa seguinte
| Comando | Descrição |
|---------|-----------|
| `/fluig:init-project` | Inicializa projeto — entrevista o dev e gera CLAUDE.md com contexto do cliente (URL servidor, prefixos, integração Protheus) |
| `/fluig:arqueologia` | Mapeia a fatia do ambiente Fluig do cliente (artefatos publicados e regras) antes do design |
| `/fluig:brainstorm` | Gate de design — entrevista, mapeia integrações, gera spec aprovada antes de qualquer scaffolding |
| `/fluig:plan` | Plano de implementação com tasks TDD e file mapping, salvo em `docs/fluig/plans/` |
| `/fluig:implement` | Agent Team executando o plano (fluig-implementer em worktree + fluig-spec-reviewer + fluig-reviewer, comunicação bidirecional) |
Expand All @@ -123,7 +126,9 @@ Cada skill termina com **"Próximo passo:"** guiando o dev para a etapa seguinte
| Comando | Descrição |
|---------|-----------|
| `/fluig:review` | Atalho: pipeline completo (revisão estática → testes → deploy → qa) — alternativa rápida ao fluxo guiado |
| `/fluig:test` | Gera e executa testes unitários (Jasmine/Karma) + E2E (Playwright) |
| `/fluig:test` | Testes unitários — widget (runner do projeto) e server-side (harness Node para `ds_*`/`wf_*`/eventos) |
| `/fluig:test-web` | Ciclo E2E no servidor real: roteiro aprovado, evidências por passo e spec de regressão com JUnit |
| `/fluig:base` | Sandbox Fluig descartável em Docker NA MÁQUINA DO DEV — inner loop E2E, reset em segundos |
| `/fluig:debug` | Debugging sistemático em 4 fases (reproduzir → investigar → hipótese → corrigir) com logs Docker, Playwright traces, Karma |
| `/fluig:api-ref` | Referência rápida das APIs Fluig: `DatasetFactory`, `DatasetBuilder`, `CardAPI`, `WCMAPI`, `fluigc`, `WFMovementDTO`, `getValue/setValue` |
| `/fluig:feedback` | Registra aprendizado quando Claude erra e o dev corrige — alimenta a base de conhecimento Fluig |
Expand Down
103 changes: 83 additions & 20 deletions fluig/hooks/fluig-lint.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#!/usr/bin/env bash
# fluig-lint.sh — Lint JS/TS/HTML em projetos Angular/PO-UI Fluig
# fluig-lint.sh — Lint JS/TS/HTML para desenvolvimento Fluig
# Ativado por PostToolUse (Write|Edit)
# Padrão: espelha quality-check.sh global, adaptado para projetos com @po-ui
#
# Dois mundos, convenções OPOSTAS:
# - SERVER-SIDE (ds_*.js, wf_*.js, events/, Util/): Rhino/ECMA 5 — let/const/arrow/class
# quebram NO SERVIDOR; o config eslint.server.config.mjs do plugin torna isso erro de
# parse aqui. Roda SEMPRE, mesmo sem @po-ui no package.json (repo de datasets puro).
# - WIDGET (.ts/.html em projeto @po-ui): ES moderno; usa o eslint do projeto, com
# fallback para o config do plugin.

set -euo pipefail

Expand Down Expand Up @@ -34,11 +40,28 @@ if [[ "$FILE_PATH" == *.min.js ]] || \
exit 0
fi

# Detectar se é projeto Fluig: procura @po-ui/ng-components no package.json
# Sobe até 4 níveis a partir do diretório do arquivo
CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
[[ -z "$CWD" ]] && CWD="$(dirname "$FILE_PATH")"

# Assets do plugin (configs ESLint) — CLAUDE_PLUGIN_ROOT quando disponível,
# senão relativo a este script (hooks/ → skills/test/assets/)
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
SERVER_CONFIG="$PLUGIN_ROOT/skills/test/assets/eslint.server.config.mjs"
WIDGET_CONFIG="$PLUGIN_ROOT/skills/test/assets/eslint.widget.config.mjs"

BASENAME=$(basename "$FILE_PATH")

# Roteamento: server-side Fluig se bater no padrão de nome/caminho
is_server_side() {
[[ "$EXT" != "js" ]] && return 1
[[ "$BASENAME" == *.spec.js || "$BASENAME" == *.test.js ]] && return 1
[[ "$BASENAME" == ds_* ]] && return 0
[[ "$BASENAME" == wf_* ]] && return 0
[[ "$FILE_PATH" == */events/* ]] && return 0
[[ "$FILE_PATH" == */Util/* ]] && return 0
return 1
}

is_fluig_project() {
local dir="$1"
for i in 1 2 3 4; do
Expand All @@ -51,29 +74,78 @@ is_fluig_project() {
return 1
}

if ! is_fluig_project "$CWD"; then
ERRORS=""

# ============ ROTA SERVER-SIDE — roda SEMPRE, independe de @po-ui ============
if is_server_side; then
LINTED=0
if command -v npx &>/dev/null && [[ -f "$SERVER_CONFIG" ]]; then
ESLINT_EXIT=0
# cd para o diretório do arquivo: ESLint flat config ignora ("outside of base
# path", exit 0) arquivo fora do cwd — rodar de outro diretório silencia o gate
ESLINT_OUT=$(cd "$(dirname "$FILE_PATH")" && npx --no-install eslint --config "$SERVER_CONFIG" "$(basename "$FILE_PATH")" 2>&1) || ESLINT_EXIT=$?
# exit 1 = achado de lint (bloqueia com a saída); exit >= 2 ou eslint ausente =
# falha da FERRAMENTA (config inválido, versão sem flat config, não instalado) —
# não é culpa do código do dev: cai no fallback de greps
if [[ $ESLINT_EXIT -le 1 ]] && ! echo "$ESLINT_OUT" | grep -qiE "not found|command failed|could not determine"; then
LINTED=1
if [[ $ESLINT_EXIT -eq 1 ]]; then
ERRORS+="ESLint (server-side Rhino/ES5):\n${ESLINT_OUT}\n"
fi
fi
fi

# Fallback sem eslint: greps mínimos (melhor que zero gate)
if [[ $LINTED -eq 0 ]]; then
if grep -qE '(^|[^A-Za-z_])(const |let |=>|class )' "$FILE_PATH" 2>/dev/null; then
ERRORS+="Fluig server-side: const/let/arrow/class detectado — o motor do Fluig é Rhino ECMA 5; use var e function\n"
fi
if grep -q 'alert(' "$FILE_PATH" 2>/dev/null; then
ERRORS+="Fluig: uso de alert() proibido\n"
fi
fi

# Regras estruturais (sempre)
if [[ "$BASENAME" == ds_* ]] || [[ "$BASENAME" == wf_* ]]; then
if ! grep -qE '^[[:space:]]*try[[:space:]]*\{' "$FILE_PATH" 2>/dev/null; then
ERRORS+="Fluig: '${BASENAME}' não tem try/catch — obrigatório em datasets e workflows\n"
fi
fi

if [[ -n "$ERRORS" ]]; then
jq -n --arg reason "Qualidade Fluig — corrija antes de continuar:\n\n${ERRORS}\nRegra errada para este caso? Registre: /fluig:feedback" \
'{"decision":"block","reason":$reason}'
fi
exit 0
fi

ERRORS=""
# ============ ROTA WIDGET — exige projeto @po-ui ============
if ! is_fluig_project "$CWD"; then
exit 0
fi

# 1. Prettier — auto-fix silencioso (não bloqueia)
if command -v npx &>/dev/null; then
npx --no-install prettier --write "$FILE_PATH" &>/dev/null || true
fi

# 2. ESLint — bloqueia se erros (só se config existir no projeto)
# 2. ESLint — config do projeto; sem config, fallback para o do plugin
if command -v npx &>/dev/null; then
ESLINT_CONFIG=$(find "$CWD" -maxdepth 4 -name node_modules -prune -o \( \
-name "eslint.config.js" -o -name "eslint.config.mjs" -o \
-name ".eslintrc.js" -o -name ".eslintrc.cjs" -o \
-name ".eslintrc.json" -o -name ".eslintrc.yml" -o \
-name ".eslintrc" \
\) -print 2>/dev/null | head -1)
ESLINT_ARGS=()
if [[ -z "$ESLINT_CONFIG" && "$EXT" == "ts" && -f "$WIDGET_CONFIG" ]]; then
ESLINT_ARGS=(--config "$WIDGET_CONFIG")
ESLINT_CONFIG="$WIDGET_CONFIG"
fi
if [[ -n "$ESLINT_CONFIG" ]]; then
ESLINT_EXIT=0
ESLINT_OUT=$(npx --no-install eslint "$FILE_PATH" 2>&1) || ESLINT_EXIT=$?
if [[ $ESLINT_EXIT -ne 0 ]]; then
ESLINT_OUT=$(npx --no-install eslint "${ESLINT_ARGS[@]}" "$FILE_PATH" 2>&1) || ESLINT_EXIT=$?
if [[ $ESLINT_EXIT -ne 0 ]] && ! echo "$ESLINT_OUT" | grep -qiE "not found|command failed|could not determine"; then
ERRORS+="ESLint:\n${ESLINT_OUT}\n"
fi
fi
Expand All @@ -93,26 +165,17 @@ if [[ "$EXT" == "ts" ]] && [[ "$FILE_PATH" != *.spec.ts ]]; then
fi
fi

# 4. Regras Fluig-específicas para JS (não aplica a spec/test)
# 4. Regras Fluig para JS de widget (não aplica a spec/test)
if [[ "$EXT" == "js" ]] && \
[[ "$FILE_PATH" != *.spec.js ]] && \
[[ "$FILE_PATH" != *.test.js ]]; then

if grep -q 'alert(' "$FILE_PATH" 2>/dev/null; then
ERRORS+="Fluig: uso de alert() proibido — use Swal.fire() (SweetAlert2)\n"
fi

# Datasets e workflows devem ter try/catch
BASENAME=$(basename "$FILE_PATH")
if [[ "$BASENAME" == ds_* ]] || [[ "$BASENAME" == wf_* ]]; then
if ! grep -qE '^\s*try\s*\{' "$FILE_PATH" 2>/dev/null; then
ERRORS+="Fluig: '${BASENAME}' não tem try/catch — obrigatório em datasets e workflows\n"
fi
fi
fi

if [[ -n "$ERRORS" ]]; then
jq -n --arg reason "Qualidade Fluig — corrija antes de continuar:\n\n${ERRORS}" \
jq -n --arg reason "Qualidade Fluig — corrija antes de continuar:\n\n${ERRORS}\nRegra errada para este caso? Registre: /fluig:feedback" \
'{"decision":"block","reason":$reason}'
exit 0
fi
Expand Down
6 changes: 3 additions & 3 deletions fluig/hooks/session-context.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ emitSessionContext({
profile: 'internal',
cleanupTbcDbs: false,
groups: [
{ title: 'Ciclo de desenvolvimento (nesta ordem)', names: ['init-project', 'brainstorm', 'plan', 'implement', 'deploy', 'qa', 'verify'] },
{ title: 'Ciclo de desenvolvimento (nesta ordem)', names: ['init-project', 'arqueologia', 'brainstorm', 'plan', 'implement', 'deploy', 'qa', 'verify'] },
{ title: 'Scaffolding', names: ['widget', 'dataset', 'form', 'workflow'] },
{ title: 'Qualidade e apoio', names: ['review', 'test', 'debug', 'api-ref', 'feedback'] },
{ title: 'Qualidade e apoio', names: ['review', 'test', 'test-web', 'debug', 'api-ref', 'feedback', 'base'] },
],
notes: [
'MCP tools disponiveis: searchFluigPatterns, searchFluigApi, searchKnowledge (plugin fluig tbc-knowledge)',
'MCP tools disponiveis: searchKnowledge (padroes/convencoes, use platform: "fluig") + ragSearchKnowledge, ragSearchDocs (busca semantica) — plugin fluig tbc-knowledge',
'Regra de modelos: opus para brainstorm/design, sonnet para implementacao e review/QA, haiku somente para deploy/compilacao.',
],
});
Loading
Loading