@fabioramos_02/create-esteira-gov 0.1.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/README.md +89 -0
- package/dist/bin/index.js +6 -0
- package/dist/src/cli.js +70 -0
- package/dist/src/copy.js +41 -0
- package/dist/src/presets.js +33 -0
- package/dist/src/wizard.js +24 -0
- package/package.json +41 -0
- package/presets/app/preset.json +12 -0
- package/presets/app/template/README.md +10 -0
- package/presets/app/template/package.json +13 -0
- package/presets/app/template/src/exemplo-ds.ts +9 -0
- package/presets/bi/preset.json +12 -0
- package/presets/bi/template/README.md +10 -0
- package/presets/bi/template/tema/build-tema.mjs +29 -0
- package/presets/blank/preset.json +12 -0
- package/presets/dados/preset.json +12 -0
- package/presets/dados/template/README.md +10 -0
- package/presets/dados/template/requirements.txt +2 -0
- package/presets/dados/template/src/analise_exemplo.py +18 -0
- package/presets/prototipo/preset.json +12 -0
- package/presets/prototipo/template/README.md +9 -0
- package/presets/prototipo/template/index.html +16 -0
- package/template/.claude/skills/especificar/SKILL.md +24 -0
- package/template/.claude/skills/esteira/SKILL.md +20 -0
- package/template/.claude/skills/implementar/SKILL.md +28 -0
- package/template/.claude/skills/planejar/SKILL.md +24 -0
- package/template/.claude/skills/validar/SKILL.md +24 -0
- package/template/CLAUDE.md +24 -0
- package/template/gitignore +4 -0
- package/template/specs/_templates/plano.md +22 -0
- package/template/specs/_templates/spec.md +17 -0
- package/template/specs/_templates/validacao.md +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# @fabioramos_02/create-esteira-gov
|
|
2
|
+
|
|
3
|
+
Scaffold de uma **esteira spec-driven multi-agente** para Claude Code, pensada para projetos
|
|
4
|
+
novos do governo de MS. Em vez de 14 skills, são **4 agentes + 1 orquestrador**, com o **core
|
|
5
|
+
agnóstico de linguagem e escopo** — a variabilidade vive em **presets** plugáveis (app, BI,
|
|
6
|
+
dados, protótipo, blank). Design System: [`@design-system-ms/ds-sis`](https://www.npmjs.com/package/@design-system-ms/ds-sis).
|
|
7
|
+
|
|
8
|
+
## Uso
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx @fabioramos_02/create-esteira-gov meu-projeto --preset app
|
|
12
|
+
# sem --preset abre um wizard para escolher
|
|
13
|
+
cd meu-projeto
|
|
14
|
+
# abra no Claude Code e rode: /esteira
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## A esteira
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart LR
|
|
21
|
+
D[Demanda] --> E[/especificar/]
|
|
22
|
+
E -->|spec.md| P[/planejar/]
|
|
23
|
+
P -->|plano.md| I[/implementar/]
|
|
24
|
+
I -->|código| V[/validar/]
|
|
25
|
+
V -->|validacao.md| OK([Pronto])
|
|
26
|
+
V -.REPROVADO.-> E
|
|
27
|
+
O{{/esteira}} -.orquestra.-> E
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Etapa | Skill | Lê | Produz |
|
|
31
|
+
|------:|-------|----|--------|
|
|
32
|
+
| 1 | `/especificar` | demanda | `spec.md` |
|
|
33
|
+
| 2 | `/planejar` | `spec.md` + preset | `plano.md` |
|
|
34
|
+
| 3 | `/implementar` | `plano.md` + preset | código |
|
|
35
|
+
| 4 | `/validar` | `spec.md` + código | `validacao.md` |
|
|
36
|
+
| — | `/esteira` | demanda | encadeia 1→4 |
|
|
37
|
+
|
|
38
|
+
Handoff é por **arquivos** em `specs/NNNN-<slug>/`. A **spec é a fonte da verdade**.
|
|
39
|
+
|
|
40
|
+
## Presets
|
|
41
|
+
|
|
42
|
+
| Preset | Escopo | Linguagem | DS |
|
|
43
|
+
|--------|--------|-----------|----|
|
|
44
|
+
| `app` | App web gov acessível | TypeScript | css + web components |
|
|
45
|
+
| `bi` | Dashboard / Power BI | JSON/DAX | tokens (tema) |
|
|
46
|
+
| `dados` | ETL + análise | Python | tokens (paleta) |
|
|
47
|
+
| `prototipo` | Protótipo rápido | HTML/CSS | css |
|
|
48
|
+
| `blank` | Só a esteira | a definir | none |
|
|
49
|
+
|
|
50
|
+
O Design System serve **qualquer escopo** porque exporta **tokens JSON** (Style Dictionary):
|
|
51
|
+
web usa `/css` + componentes; BI e dados leem `/tokens` para tema/paleta.
|
|
52
|
+
|
|
53
|
+
## Regras do template gerado
|
|
54
|
+
- SRP: 1 arquivo = 1 responsabilidade.
|
|
55
|
+
- Máximo **250 linhas por arquivo** (`npm run check` no projeto da esteira valida isso).
|
|
56
|
+
- Nunca hardcode de cor/espaçamento — sempre via DS.
|
|
57
|
+
- Conventional Commits, GitHub Flow, pt-BR.
|
|
58
|
+
|
|
59
|
+
## Criar um preset novo
|
|
60
|
+
Adicionar uma linguagem/escopo **não exige tocar nos agentes**:
|
|
61
|
+
|
|
62
|
+
1. Crie `presets/<nome>/preset.json`:
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"nome": "<nome>",
|
|
66
|
+
"descricao": "...",
|
|
67
|
+
"linguagem": "...",
|
|
68
|
+
"stack": ["..."],
|
|
69
|
+
"ds": "css+wc | css | tokens | none",
|
|
70
|
+
"comandos": { "check": "...", "lint": "...", "test": "..." }
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
2. (Opcional) Crie `presets/<nome>/template/` com o scaffold inicial daquele tipo.
|
|
74
|
+
3. Pronto — o preset aparece no CLI e no wizard.
|
|
75
|
+
|
|
76
|
+
Os agentes leem `.esteira/preset.json` do projeto gerado e se adaptam à stack/comandos.
|
|
77
|
+
|
|
78
|
+
## Desenvolvimento
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install
|
|
82
|
+
npm run build # tsc -> dist/
|
|
83
|
+
npm run check # falha se algum arquivo passar de 250 linhas
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Publicação: `npm publish --access public`.
|
|
87
|
+
|
|
88
|
+
## Créditos
|
|
89
|
+
Inspirado (e simplificado) a partir de [igoruehara/spec-driven](https://github.com/igoruehara/spec-driven).
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { listPresets, loadPreset, presetTemplateDir } from "./presets.js";
|
|
5
|
+
import { copyTree } from "./copy.js";
|
|
6
|
+
import { pickPreset } from "./wizard.js";
|
|
7
|
+
// dist/src/cli.js -> raiz do pacote (onde vivem template/ e presets/)
|
|
8
|
+
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9
|
+
function parseArgs(argv) {
|
|
10
|
+
const a = { help: false };
|
|
11
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12
|
+
const t = argv[i];
|
|
13
|
+
if (t === "--help" || t === "-h")
|
|
14
|
+
a.help = true;
|
|
15
|
+
else if (t === "--preset" || t === "-p")
|
|
16
|
+
a.preset = argv[++i];
|
|
17
|
+
else if (!t.startsWith("-") && !a.nome)
|
|
18
|
+
a.nome = t;
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
}
|
|
22
|
+
function usage() {
|
|
23
|
+
console.log(`
|
|
24
|
+
create-esteira-gov — scaffold de esteira spec-driven (gov MS)
|
|
25
|
+
|
|
26
|
+
Uso:
|
|
27
|
+
npx @fabioramos_02/create-esteira-gov <nome> [--preset <preset>]
|
|
28
|
+
|
|
29
|
+
Presets: ${listPresets(pkgRoot).join(", ") || "(nenhum)"}
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
export async function run(argv) {
|
|
33
|
+
const args = parseArgs(argv);
|
|
34
|
+
if (args.help || !args.nome) {
|
|
35
|
+
usage();
|
|
36
|
+
if (!args.nome)
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const dest = resolve(process.cwd(), args.nome);
|
|
41
|
+
if (existsSync(dest) && readdirSync(dest).length > 0) {
|
|
42
|
+
throw new Error(`Diretório "${args.nome}" já existe e não está vazio.`);
|
|
43
|
+
}
|
|
44
|
+
const preset = args.preset ?? (await pickPreset(listPresets(pkgRoot)));
|
|
45
|
+
const cfg = loadPreset(pkgRoot, preset);
|
|
46
|
+
const vars = { nome: args.nome, preset: cfg.nome };
|
|
47
|
+
mkdirSync(dest, { recursive: true });
|
|
48
|
+
copyTree(join(pkgRoot, "template"), dest, vars); // core agnóstico
|
|
49
|
+
const pt = presetTemplateDir(cfg);
|
|
50
|
+
if (pt)
|
|
51
|
+
copyTree(pt, dest, vars); // overlay do preset
|
|
52
|
+
writeManifest(dest, cfg);
|
|
53
|
+
printNext(args.nome, cfg);
|
|
54
|
+
}
|
|
55
|
+
/** Grava .esteira/preset.json no projeto p/ os agentes lerem stack/comandos. */
|
|
56
|
+
function writeManifest(dest, cfg) {
|
|
57
|
+
const { dir: _omit, ...manifest } = cfg;
|
|
58
|
+
mkdirSync(join(dest, ".esteira"), { recursive: true });
|
|
59
|
+
writeFileSync(join(dest, ".esteira", "preset.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
60
|
+
}
|
|
61
|
+
function printNext(nome, cfg) {
|
|
62
|
+
console.log(`
|
|
63
|
+
✔ Projeto "${nome}" criado (preset: ${cfg.nome} — ${cfg.descricao}).
|
|
64
|
+
|
|
65
|
+
Próximos passos:
|
|
66
|
+
cd ${nome}
|
|
67
|
+
# abra no Claude Code e rode a esteira completa: /esteira
|
|
68
|
+
# ou etapa a etapa: /especificar -> /planejar -> /implementar -> /validar
|
|
69
|
+
`);
|
|
70
|
+
}
|
package/dist/src/copy.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, writeFileSync, mkdirSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const TEXT_EXT = new Set([
|
|
4
|
+
".md", ".ts", ".tsx", ".js", ".mjs", ".cjs", ".json",
|
|
5
|
+
".css", ".html", ".txt", ".yml", ".yaml", ".py",
|
|
6
|
+
]);
|
|
7
|
+
// npm remove arquivos ".gitignore" de pacotes publicados; guardamos como
|
|
8
|
+
// "gitignore" no template e renomeamos na cópia.
|
|
9
|
+
const RENAME = { gitignore: ".gitignore" };
|
|
10
|
+
const TEXT_NAMES = new Set(["gitignore"]);
|
|
11
|
+
function isText(name) {
|
|
12
|
+
if (name.startsWith(".") || TEXT_NAMES.has(name))
|
|
13
|
+
return true;
|
|
14
|
+
const dot = name.lastIndexOf(".");
|
|
15
|
+
const ext = dot >= 0 ? name.slice(dot) : "";
|
|
16
|
+
return TEXT_EXT.has(ext);
|
|
17
|
+
}
|
|
18
|
+
/** Substitui ocorrências de {{chave}} pelos valores em vars. */
|
|
19
|
+
function applyVars(content, vars) {
|
|
20
|
+
return content.replace(/\{\{(\w+)\}\}/g, (m, k) => (k in vars ? vars[k] : m));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Copia srcDir -> destDir recursivamente.
|
|
24
|
+
* Arquivos de texto recebem substituição de placeholders; binários são copiados crus.
|
|
25
|
+
*/
|
|
26
|
+
export function copyTree(srcDir, destDir, vars) {
|
|
27
|
+
mkdirSync(destDir, { recursive: true });
|
|
28
|
+
for (const entry of readdirSync(srcDir)) {
|
|
29
|
+
const from = join(srcDir, entry);
|
|
30
|
+
const to = join(destDir, RENAME[entry] ?? entry);
|
|
31
|
+
if (statSync(from).isDirectory()) {
|
|
32
|
+
copyTree(from, to, vars);
|
|
33
|
+
}
|
|
34
|
+
else if (isText(entry)) {
|
|
35
|
+
writeFileSync(to, applyVars(readFileSync(from, "utf8"), vars));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
writeFileSync(to, readFileSync(from));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export function presetsDir(pkgRoot) {
|
|
4
|
+
return join(pkgRoot, "presets");
|
|
5
|
+
}
|
|
6
|
+
/** Lista nomes de presets válidos (pastas com preset.json). */
|
|
7
|
+
export function listPresets(pkgRoot) {
|
|
8
|
+
const dir = presetsDir(pkgRoot);
|
|
9
|
+
if (!existsSync(dir))
|
|
10
|
+
return [];
|
|
11
|
+
return readdirSync(dir)
|
|
12
|
+
.filter((n) => existsSync(join(dir, n, "preset.json")))
|
|
13
|
+
.sort();
|
|
14
|
+
}
|
|
15
|
+
/** Carrega e valida um preset pelo nome. */
|
|
16
|
+
export function loadPreset(pkgRoot, nome) {
|
|
17
|
+
const dir = join(presetsDir(pkgRoot), nome);
|
|
18
|
+
const file = join(dir, "preset.json");
|
|
19
|
+
if (!existsSync(file)) {
|
|
20
|
+
const disp = listPresets(pkgRoot).join(", ") || "(nenhum)";
|
|
21
|
+
throw new Error(`Preset "${nome}" não encontrado. Disponíveis: ${disp}`);
|
|
22
|
+
}
|
|
23
|
+
const data = JSON.parse(readFileSync(file, "utf8"));
|
|
24
|
+
if (!data.nome || !data.comandos) {
|
|
25
|
+
throw new Error(`preset.json inválido em ${file}: faltam campos obrigatórios.`);
|
|
26
|
+
}
|
|
27
|
+
return { ...data, dir };
|
|
28
|
+
}
|
|
29
|
+
/** Pasta template/ do preset, se existir. */
|
|
30
|
+
export function presetTemplateDir(preset) {
|
|
31
|
+
const t = join(preset.dir, "template");
|
|
32
|
+
return existsSync(t) && statSync(t).isDirectory() ? t : null;
|
|
33
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
/** Pergunta interativamente qual preset usar quando nenhum foi passado. */
|
|
4
|
+
export async function pickPreset(presets) {
|
|
5
|
+
if (presets.length === 0)
|
|
6
|
+
throw new Error("Nenhum preset disponível no pacote.");
|
|
7
|
+
if (presets.length === 1)
|
|
8
|
+
return presets[0];
|
|
9
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
10
|
+
try {
|
|
11
|
+
stdout.write("\nPresets disponíveis:\n");
|
|
12
|
+
presets.forEach((p, i) => stdout.write(` ${i + 1}) ${p}\n`));
|
|
13
|
+
const ans = (await rl.question("Escolha (número ou nome): ")).trim();
|
|
14
|
+
const byIndex = presets[Number(ans) - 1];
|
|
15
|
+
if (byIndex)
|
|
16
|
+
return byIndex;
|
|
17
|
+
if (presets.includes(ans))
|
|
18
|
+
return ans;
|
|
19
|
+
throw new Error(`Opção inválida: "${ans}".`);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
rl.close();
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fabioramos_02/create-esteira-gov",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold de esteira spec-driven multi-agente Claude para projetos gov MS (app, BI, dados, protótipo).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-esteira-gov": "dist/bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"template",
|
|
12
|
+
"presets"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"check": "node scripts/check-limits.mjs",
|
|
20
|
+
"prepublishOnly": "npm run build && npm run check"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"spec-driven",
|
|
27
|
+
"claude",
|
|
28
|
+
"claude-code",
|
|
29
|
+
"scaffold",
|
|
30
|
+
"create",
|
|
31
|
+
"governo",
|
|
32
|
+
"design-system",
|
|
33
|
+
"ms"
|
|
34
|
+
],
|
|
35
|
+
"author": "Fabio Ramos",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.11.0",
|
|
39
|
+
"typescript": "^5.4.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# {{nome}} (preset `app`)
|
|
2
|
+
|
|
3
|
+
App web gov acessível. Design System: `@design-system-ms/ds-sis` (CSS + Web Components). WCAG AA.
|
|
4
|
+
|
|
5
|
+
## Início
|
|
6
|
+
1. `npm install`
|
|
7
|
+
2. Configure seu bundler (Next.js ou Vite) — este scaffold é mínimo de propósito.
|
|
8
|
+
3. Veja `src/exemplo-ds.ts` para consumir o DS.
|
|
9
|
+
|
|
10
|
+
Esteira: rode `/esteira` no Claude Code (ou etapa a etapa).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{nome}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@design-system-ms/ds-sis": "^0.1.0"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "echo 'configure seu bundler (Next.js ou Vite)'",
|
|
10
|
+
"lint": "echo 'configure o eslint'",
|
|
11
|
+
"test": "echo 'configure os testes'"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Exemplo de consumo do Design System gov (preset app, ds = "css+wc").
|
|
2
|
+
// 1) CSS base do DS:
|
|
3
|
+
import "@design-system-ms/ds-sis/css";
|
|
4
|
+
// 2) Web components do DS (use as tags no HTML, ex.: <ds-button>):
|
|
5
|
+
import "@design-system-ms/ds-sis";
|
|
6
|
+
|
|
7
|
+
// Regra: nunca hardcode cor/espaçamento — use classes/tokens do DS.
|
|
8
|
+
export const dica =
|
|
9
|
+
"Veja o README de @design-system-ms/ds-sis para a lista de componentes disponíveis.";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nome": "bi",
|
|
3
|
+
"descricao": "Dashboard / Power BI com tema do DS",
|
|
4
|
+
"linguagem": "json",
|
|
5
|
+
"stack": ["power-bi"],
|
|
6
|
+
"ds": "tokens",
|
|
7
|
+
"comandos": {
|
|
8
|
+
"check": "node tema/build-tema.mjs",
|
|
9
|
+
"lint": "echo 'sem lint'",
|
|
10
|
+
"test": "echo 'sem teste'"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# {{nome}} (preset `bi`)
|
|
2
|
+
|
|
3
|
+
Projeto de BI / Power BI. Design System consumido via **tokens JSON**.
|
|
4
|
+
|
|
5
|
+
## Tema do DS
|
|
6
|
+
1. `npm i @design-system-ms/ds-sis`
|
|
7
|
+
2. `node tema/build-tema.mjs` → gera `tema/tema-powerbi.json`
|
|
8
|
+
3. No Power BI: **Exibir > Temas > Procurar temas** e selecione o JSON gerado.
|
|
9
|
+
|
|
10
|
+
Esteira: rode `/esteira` no Claude Code (foco em modelagem + indicadores).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Gera um tema do Power BI a partir dos tokens do DS gov (preset bi, ds = "tokens").
|
|
2
|
+
// Requer: npm i @design-system-ms/ds-sis
|
|
3
|
+
import { writeFileSync } from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
let tokens;
|
|
9
|
+
try {
|
|
10
|
+
tokens = require("@design-system-ms/ds-sis/tokens");
|
|
11
|
+
} catch {
|
|
12
|
+
console.log("Instale o DS primeiro: npm i @design-system-ms/ds-sis");
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function extrairCores(t) {
|
|
17
|
+
// tokens.json segue o formato Style Dictionary — ajuste conforme a estrutura real.
|
|
18
|
+
const cores = JSON.stringify(t).match(/#[0-9a-fA-F]{6}/g) || [];
|
|
19
|
+
return [...new Set(cores)].slice(0, 8);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const tema = {
|
|
23
|
+
name: "DS-MS",
|
|
24
|
+
dataColors: extrairCores(tokens),
|
|
25
|
+
background: "#FFFFFF",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
writeFileSync("tema/tema-powerbi.json", JSON.stringify(tema, null, 2) + "\n");
|
|
29
|
+
console.log("✔ tema/tema-powerbi.json gerado a partir dos tokens do DS.");
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nome": "blank",
|
|
3
|
+
"descricao": "Só a esteira; escolha a stack na etapa de planejar",
|
|
4
|
+
"linguagem": "indefinida",
|
|
5
|
+
"stack": [],
|
|
6
|
+
"ds": "none",
|
|
7
|
+
"comandos": {
|
|
8
|
+
"check": "echo 'defina o check ao planejar'",
|
|
9
|
+
"lint": "echo 'defina o lint ao planejar'",
|
|
10
|
+
"test": "echo 'defina o test ao planejar'"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nome": "dados",
|
|
3
|
+
"descricao": "ETL + análise de dados (Python) com paleta do DS",
|
|
4
|
+
"linguagem": "python",
|
|
5
|
+
"stack": ["python", "pandas"],
|
|
6
|
+
"ds": "tokens",
|
|
7
|
+
"comandos": {
|
|
8
|
+
"check": "python -m compileall src",
|
|
9
|
+
"lint": "ruff check .",
|
|
10
|
+
"test": "pytest -q"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# {{nome}} (preset `dados`)
|
|
2
|
+
|
|
3
|
+
ETL + análise em Python. As cores dos gráficos vêm dos **tokens JSON** do DS gov.
|
|
4
|
+
|
|
5
|
+
## Início
|
|
6
|
+
1. `pip install -r requirements.txt`
|
|
7
|
+
2. (opcional) `npm i @design-system-ms/ds-sis` para a paleta oficial.
|
|
8
|
+
3. `python src/analise_exemplo.py`
|
|
9
|
+
|
|
10
|
+
Esteira: rode `/esteira` no Claude Code.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Exemplo: usar a paleta do DS gov em gráficos (preset dados, ds = "tokens")."""
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def carregar_paleta() -> list[str]:
|
|
8
|
+
"""Lê as cores dos tokens do DS. Instale com: npm i @design-system-ms/ds-sis"""
|
|
9
|
+
p = Path("node_modules/@design-system-ms/ds-sis/dist/json/tokens.json")
|
|
10
|
+
if not p.exists():
|
|
11
|
+
return ["#244061"] # fallback até instalar o DS
|
|
12
|
+
dados = json.loads(p.read_text(encoding="utf-8"))
|
|
13
|
+
cores = re.findall(r"#[0-9a-fA-F]{6}", json.dumps(dados))
|
|
14
|
+
return list(dict.fromkeys(cores))[:8]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
print("Paleta DS:", carregar_paleta())
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nome": "prototipo",
|
|
3
|
+
"descricao": "Protótipo rápido (HTML + DS), sem rigor de teste",
|
|
4
|
+
"linguagem": "html",
|
|
5
|
+
"stack": ["html", "css"],
|
|
6
|
+
"ds": "css",
|
|
7
|
+
"comandos": {
|
|
8
|
+
"check": "echo 'ok'",
|
|
9
|
+
"lint": "echo 'sem lint'",
|
|
10
|
+
"test": "echo 'sem teste'"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# {{nome}} (preset `prototipo`)
|
|
2
|
+
|
|
3
|
+
Protótipo rápido HTML + DS gov. Sem rigor de teste — foco em validar ideia.
|
|
4
|
+
|
|
5
|
+
## Início
|
|
6
|
+
1. `npm i @design-system-ms/ds-sis`
|
|
7
|
+
2. Abra `index.html` no navegador (ou use uma extensão Live Server).
|
|
8
|
+
|
|
9
|
+
Esteira: rode `/esteira` (foco em `/especificar` + prototipar).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="pt-BR">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{nome}} — protótipo</title>
|
|
7
|
+
<!-- DS gov: instale com `npm i @design-system-ms/ds-sis` -->
|
|
8
|
+
<link rel="stylesheet" href="node_modules/@design-system-ms/ds-sis/dist/css/ds-sis.css" />
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<main class="container">
|
|
12
|
+
<h1>{{nome}}</h1>
|
|
13
|
+
<p>Protótipo rápido com o Design System gov. Use classes/tokens do DS, sem hardcode.</p>
|
|
14
|
+
</main>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: especificar
|
|
3
|
+
description: Etapa 1 da esteira spec-driven. Transforma uma demanda solta em spec.md (a fonte da verdade) com objetivo, escopo e critérios de aceite testáveis. Use ao iniciar uma feature nova.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /especificar — Etapa 1 da esteira
|
|
7
|
+
|
|
8
|
+
Transforma demanda solta em **spec** rastreável.
|
|
9
|
+
|
|
10
|
+
**Lê:** demanda do usuário (texto).
|
|
11
|
+
**Produz:** `specs/NNNN-<slug>/spec.md` (base: `specs/_templates/spec.md`).
|
|
12
|
+
|
|
13
|
+
## Passos
|
|
14
|
+
1. Pergunte só o crítico (máx. 3): objetivo, escopo, restrições.
|
|
15
|
+
2. Crie `specs/NNNN-<slug>/` (NNNN = próximo número sequencial).
|
|
16
|
+
3. Preencha o template: objetivo único, escopo (inclui/não inclui), AC testáveis.
|
|
17
|
+
4. Não invente requisito. Faltou info → registre como suposição explícita.
|
|
18
|
+
|
|
19
|
+
## Pronto quando
|
|
20
|
+
- [ ] objetivo mensurável
|
|
21
|
+
- [ ] escopo delimitado
|
|
22
|
+
- [ ] ≥ 1 AC por comportamento, todos verificáveis
|
|
23
|
+
|
|
24
|
+
Próxima etapa: `/planejar`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: esteira
|
|
3
|
+
description: Orquestrador da esteira spec-driven. Encadeia as 4 etapas (especificar → planejar → implementar → validar) com handoff via arquivos. Use para tocar uma feature de ponta a ponta.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /esteira — Orquestrador
|
|
7
|
+
|
|
8
|
+
Roda a esteira inteira, com handoff explícito via arquivos em `specs/NNNN-<slug>/`.
|
|
9
|
+
|
|
10
|
+
## Fluxo
|
|
11
|
+
1. `/especificar` → `spec.md`
|
|
12
|
+
2. `/planejar` → `plano.md` (só começa com a spec pronta)
|
|
13
|
+
3. `/implementar` → código (só começa com o plano pronto)
|
|
14
|
+
4. `/validar` → `validacao.md` (confronta com a spec)
|
|
15
|
+
|
|
16
|
+
## Regras
|
|
17
|
+
- Não pule etapa: cada uma só inicia quando a anterior entregou seu artefato.
|
|
18
|
+
- Se `/validar` reprovar, volte à etapa apontada no veredito e reexecute dali.
|
|
19
|
+
- Não duplique conteúdo entre etapas — cada artefato é a fonte da etapa seguinte.
|
|
20
|
+
- Pare e peça confirmação ao usuário antes de decisões irreversíveis.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implementar
|
|
3
|
+
description: Etapa 3 da esteira spec-driven. Escreve o código seguindo plano.md, o Design System do governo e os comandos do preset, mantendo SRP e 250 linhas por arquivo. Use depois de /planejar.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /implementar — Etapa 3 da esteira
|
|
7
|
+
|
|
8
|
+
Escreve código fiel ao plano.
|
|
9
|
+
|
|
10
|
+
**Lê:** `specs/NNNN-<slug>/plano.md` + `.esteira/preset.json`.
|
|
11
|
+
**Produz:** código no projeto.
|
|
12
|
+
|
|
13
|
+
## Regras
|
|
14
|
+
- Siga a árvore e os contratos do plano. Precisou desviar → atualize o plano antes.
|
|
15
|
+
- 1 responsabilidade por arquivo, ≤ 250 linhas.
|
|
16
|
+
- Design System (`@design-system-ms/ds-sis`) conforme `preset.ds`:
|
|
17
|
+
- `css+wc` → importe `/css` + web components (`.`)
|
|
18
|
+
- `css` → importe `/css`
|
|
19
|
+
- `tokens` → carregue `/tokens` (JSON) p/ tema/paleta (BI, gráficos, Python)
|
|
20
|
+
- **nunca** hardcode cor/espaçamento.
|
|
21
|
+
- Ao final, rode `preset.comandos.check`.
|
|
22
|
+
|
|
23
|
+
## Pronto quando
|
|
24
|
+
- [ ] todos os arquivos do plano implementados
|
|
25
|
+
- [ ] `check` passa
|
|
26
|
+
- [ ] sem hardcode de DS
|
|
27
|
+
|
|
28
|
+
Anterior: `/planejar` · Próxima: `/validar`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planejar
|
|
3
|
+
description: Etapa 2 da esteira spec-driven. Converte spec.md em plano.md — arquitetura, árvore de arquivos e contratos — respeitando o preset, o princípio de responsabilidade única e o limite de 250 linhas por arquivo. Use depois de /especificar.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /planejar — Etapa 2 da esteira
|
|
7
|
+
|
|
8
|
+
Desenha COMO construir, antes de escrever código.
|
|
9
|
+
|
|
10
|
+
**Lê:** `specs/NNNN-<slug>/spec.md` + `.esteira/preset.json` (linguagem/stack).
|
|
11
|
+
**Produz:** `specs/NNNN-<slug>/plano.md` (base: `specs/_templates/plano.md`).
|
|
12
|
+
|
|
13
|
+
## Passos
|
|
14
|
+
1. Leia a spec e o preset.
|
|
15
|
+
2. Defina camadas e a árvore de arquivos — cada arquivo com 1 responsabilidade e ≤ 250 linhas.
|
|
16
|
+
3. Para cada arquivo: responsabilidade + entrada → saída.
|
|
17
|
+
4. Defina ordem de execução e riscos.
|
|
18
|
+
|
|
19
|
+
## Pronto quando
|
|
20
|
+
- [ ] todo AC da spec coberto por algum arquivo
|
|
21
|
+
- [ ] nenhum arquivo planejado tende a passar de 250 linhas
|
|
22
|
+
- [ ] contratos sem ambiguidade para implementar
|
|
23
|
+
|
|
24
|
+
Anterior: `/especificar` · Próxima: `/implementar`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: validar
|
|
3
|
+
description: Etapa 4 da esteira spec-driven. Confronta o código com a spec e os gates de qualidade (AC, lint, test, limite de 250 linhas, uso correto do Design System) e gera validacao.md. Use por último.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /validar — Etapa 4 da esteira
|
|
7
|
+
|
|
8
|
+
Confere se o código cumpre a spec.
|
|
9
|
+
|
|
10
|
+
**Lê:** `specs/NNNN-<slug>/spec.md` + código + `.esteira/preset.json`.
|
|
11
|
+
**Produz:** `specs/NNNN-<slug>/validacao.md` (base: `specs/_templates/validacao.md`).
|
|
12
|
+
|
|
13
|
+
## Passos
|
|
14
|
+
1. Marque cada AC da spec como OK/NOK com evidência.
|
|
15
|
+
2. Rode os gates: `preset.comandos.lint`, `preset.comandos.test`, limite de 250 linhas.
|
|
16
|
+
3. Cheque DS: sem cor/espaçamento hardcoded.
|
|
17
|
+
4. Veredito: APROVADO só se todos os AC e gates passam.
|
|
18
|
+
|
|
19
|
+
## Pronto quando
|
|
20
|
+
- [ ] todos os AC OK
|
|
21
|
+
- [ ] lint + test + limite de 250 OK
|
|
22
|
+
- [ ] veredito escrito
|
|
23
|
+
|
|
24
|
+
Anterior: `/implementar`. Se REPROVADO → volte à etapa indicada no veredito.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# {{nome}} — convenções do projeto
|
|
2
|
+
|
|
3
|
+
Projeto gov MS estruturado com a **esteira spec-driven** (preset: `{{preset}}`).
|
|
4
|
+
|
|
5
|
+
## Fluxo de trabalho
|
|
6
|
+
Toda feature passa pela esteira (skills em `.claude/skills/`):
|
|
7
|
+
|
|
8
|
+
`/especificar` → `/planejar` → `/implementar` → `/validar`
|
|
9
|
+
|
|
10
|
+
Ou rode `/esteira` para tocar tudo de ponta a ponta. Os artefatos ficam em
|
|
11
|
+
`specs/NNNN-<slug>/` (`spec.md`, `plano.md`, `validacao.md`). **A spec é a fonte da verdade** —
|
|
12
|
+
o código deriva dela, não o contrário.
|
|
13
|
+
|
|
14
|
+
## Regras
|
|
15
|
+
- **SRP:** 1 arquivo = 1 responsabilidade.
|
|
16
|
+
- **Máx 250 linhas por arquivo.**
|
|
17
|
+
- **Design System gov:** `@design-system-ms/ds-sis` — nunca hardcode de cor/espaçamento.
|
|
18
|
+
Modo de consumo conforme `.esteira/preset.json` (campo `ds`).
|
|
19
|
+
- Conventional Commits, GitHub Flow.
|
|
20
|
+
- Código e comunicação em pt-BR.
|
|
21
|
+
|
|
22
|
+
## Preset
|
|
23
|
+
Stack, linguagem e comandos (`check`/`lint`/`test`) ficam em `.esteira/preset.json`.
|
|
24
|
+
Os agentes leem esse arquivo para se adaptar à linguagem/escopo do projeto.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Plano — <feature>
|
|
2
|
+
|
|
3
|
+
> Deriva de `spec.md`. Cada arquivo ≤ 250 linhas, 1 responsabilidade.
|
|
4
|
+
|
|
5
|
+
## Arquitetura
|
|
6
|
+
<camadas / abordagem em 2-3 linhas>
|
|
7
|
+
|
|
8
|
+
## Árvore de arquivos
|
|
9
|
+
```
|
|
10
|
+
src/...
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Contratos
|
|
14
|
+
| Arquivo | Responsabilidade | Entrada → Saída |
|
|
15
|
+
|---------|------------------|-----------------|
|
|
16
|
+
| | | |
|
|
17
|
+
|
|
18
|
+
## Ordem de execução
|
|
19
|
+
1. ...
|
|
20
|
+
|
|
21
|
+
## Riscos / decisões
|
|
22
|
+
- ...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Spec — <feature>
|
|
2
|
+
|
|
3
|
+
> Fonte da verdade. O código deriva daqui.
|
|
4
|
+
|
|
5
|
+
## Objetivo
|
|
6
|
+
<frase única e mensurável>
|
|
7
|
+
|
|
8
|
+
## Escopo
|
|
9
|
+
- **Inclui:** ...
|
|
10
|
+
- **Não inclui:** ...
|
|
11
|
+
|
|
12
|
+
## Critérios de aceite (AC)
|
|
13
|
+
- [ ] AC1 — <comportamento verificável>
|
|
14
|
+
- [ ] AC2 — ...
|
|
15
|
+
|
|
16
|
+
## Restrições / notas
|
|
17
|
+
- ...
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Validação — <feature>
|
|
2
|
+
|
|
3
|
+
> Confronta o código com `spec.md`.
|
|
4
|
+
|
|
5
|
+
## Critérios de aceite
|
|
6
|
+
- [ ] AC1 — OK/NOK + evidência
|
|
7
|
+
- [ ] AC2 — ...
|
|
8
|
+
|
|
9
|
+
## Gates de qualidade
|
|
10
|
+
- [ ] lint (`preset.comandos.lint`) ok
|
|
11
|
+
- [ ] test (`preset.comandos.test`) ok
|
|
12
|
+
- [ ] limite de 250 linhas ok
|
|
13
|
+
- [ ] DS: sem cor/espaçamento hardcoded
|
|
14
|
+
|
|
15
|
+
## Veredito
|
|
16
|
+
APROVADO / REPROVADO — <motivo; se reprovado, indicar a etapa para retorno>
|