@aksp/opencrew 1.6.3 → 1.7.1

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 (46) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +50 -5
  3. package/package.json +1 -1
  4. package/templates/AGENTS.md +20 -6
  5. package/templates/_opencrew/.opencrew-version +1 -1
  6. package/templates/_opencrew/core/architect.agent.yaml +1 -1
  7. package/templates/_opencrew/core/escritorio/animacao.js +64 -0
  8. package/templates/_opencrew/core/escritorio/app.js +137 -0
  9. package/templates/_opencrew/core/escritorio/cena.js +132 -0
  10. package/templates/_opencrew/core/escritorio/demo.js +79 -0
  11. package/templates/_opencrew/core/escritorio/escala.js +27 -0
  12. package/templates/_opencrew/core/escritorio/index.html +166 -0
  13. package/templates/_opencrew/core/escritorio/modelo-agentes.js +93 -0
  14. package/templates/_opencrew/core/escritorio/modelo-estado.js +71 -0
  15. package/templates/_opencrew/core/escritorio/modelo-mesas.js +81 -0
  16. package/templates/_opencrew/core/escritorio/modelo-pagina.js +95 -0
  17. package/templates/_opencrew/core/escritorio/modelo-textos.js +65 -0
  18. package/templates/_opencrew/core/escritorio/modelo-visao.js +91 -0
  19. package/templates/_opencrew/core/escritorio/modelo.js +29 -0
  20. package/templates/_opencrew/core/escritorio/painel.js +120 -0
  21. package/templates/_opencrew/core/escritorio/quadro.js +106 -0
  22. package/templates/_opencrew/core/escritorio/rota.js +62 -0
  23. package/templates/_opencrew/core/escritorio/rotulos.js +78 -0
  24. package/templates/_opencrew/core/escritorio/sprites-mesa.js +122 -0
  25. package/templates/_opencrew/core/escritorio/sprites-sala.js +92 -0
  26. package/templates/_opencrew/core/escritorio/sprites.js +187 -0
  27. package/templates/_opencrew/core/prompts/build.prompt.md +3 -3
  28. package/templates/_opencrew/core/prompts/discovery.prompt.md +1 -1
  29. package/templates/_opencrew/core/prompts/repair.prompt.md +7 -12
  30. package/templates/_opencrew/core/runner.pipeline.md +124 -223
  31. package/templates/_opencrew/core/scripts/caminho/argumentos.mjs +49 -0
  32. package/templates/_opencrew/core/scripts/caminho/disco.mjs +36 -0
  33. package/templates/_opencrew/core/scripts/caminho/nucleo.mjs +61 -0
  34. package/templates/_opencrew/core/scripts/caminho.mjs +124 -0
  35. package/templates/_opencrew/core/scripts/escritorio/leitura.mjs +31 -0
  36. package/templates/_opencrew/core/scripts/escritorio/porta.mjs +98 -0
  37. package/templates/_opencrew/core/scripts/escritorio/projeto.mjs +29 -0
  38. package/templates/_opencrew/core/scripts/escritorio/servidor.mjs +78 -0
  39. package/templates/_opencrew/core/scripts/escritorio.mjs +117 -0
  40. package/templates/_opencrew/core/scripts/estado/argumentos.mjs +61 -0
  41. package/templates/_opencrew/core/scripts/estado/arquivo.mjs +53 -0
  42. package/templates/_opencrew/core/scripts/estado/decisao.mjs +56 -0
  43. package/templates/_opencrew/core/scripts/estado/elenco.mjs +58 -0
  44. package/templates/_opencrew/core/scripts/estado/nucleo.mjs +113 -0
  45. package/templates/_opencrew/core/scripts/estado/preferencia.mjs +24 -0
  46. package/templates/_opencrew/core/scripts/estado.mjs +96 -0
@@ -0,0 +1,122 @@
1
+ // A mesa de cada agente e o que muda nela, em matrizes de pixels: o tampo com os pés, o monitor
2
+ // com as telas de cada status e os sinais que aparecem sobre a cabeça do boneco (✓, "!" e "?"
3
+ // são desenhos, não texto). Quem diz onde cada desenho vai é `cena.js`.
4
+ // Spec: fase-e1-escritorio-ao-vivo.md, regras 16, 18 e 19 (repositório do OpenCrew).
5
+ import { CORES, matriz } from './sprites.js';
6
+
7
+ /**
8
+ * A mesa vista de cima e de frente: o tampo (com teclado, papel e caneca), a borda, a saia com a
9
+ * gaveta e os pés. Tem a largura do retângulo da mesa no modelo e `MESA_ACIMA` linhas a mais.
10
+ */
11
+ export const MESA = matriz({
12
+ o: CORES.tinta, t: CORES.madeiraLuz, T: CORES.madeira, F: CORES.madeiraMedia, D: CORES.madeiraEscura, x: CORES.junta,
13
+ k: CORES.cinzaEscuro, K: CORES.cinzaClaro, w: CORES.branco, g: CORES.cinzaClaro, c: CORES.ceu, f: CORES.madeiraEscura,
14
+ }, [
15
+ '.oooooooooooooooooooooooooooooooooooooooooo.',
16
+ 'otttttttttttttttkkkkkkkkkkkkttttttttttttttto',
17
+ 'oTTTTTTTTTTTTTTTkKKKKKKKKKKkTTTTwwwwwwTcccTo',
18
+ 'oTTTTTTTTTTTTTTTkkkkkkkkkkkkTTTTwggggwTcfcTo',
19
+ 'oTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTwwwwwwTcccTo',
20
+ 'oTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTwgggwwTTTTTo',
21
+ 'oTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTwwwwwwTTTTTo',
22
+ 'oFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFo',
23
+ 'oooooooooooooooooooooooooooooooooooooooooooo',
24
+ '.oDDDDDDDDDDDDDDDDDDFFFFDDDDDDDDDDDDDDDDDDo.',
25
+ '.oDDooooooooooooooooooooooooooooooooooooDDo.',
26
+ '.oDDoxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoDDo.',
27
+ '.oDDoxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoDDo.',
28
+ '.oDDo..................................oDDo.',
29
+ '.oooo..................................oooo.',
30
+ ]);
31
+
32
+ /**
33
+ * Quantas linhas do desenho da mesa ficam acima do retângulo do tampo: é o fundo do tampo, que
34
+ * cobre as pernas de quem está sentado atrás dele.
35
+ */
36
+ export const MESA_ACIMA = 4;
37
+
38
+ /** O monitor, de frente para quem olha, com a tela apagada; a base pousa no fundo do tampo. */
39
+ export const MONITOR = matriz({ o: CORES.tinta, g: CORES.cinzaEscuro, k: CORES.telaApagada, G: CORES.cinzaClaro }, [
40
+ 'oooooooooooo',
41
+ 'oggggggggggo',
42
+ 'ogkkkkkkkkgo',
43
+ 'ogkkkkkkkkgo',
44
+ 'ogkkkkkkkkgo',
45
+ 'ogkkkkkkkkgo',
46
+ 'ogkkkkkkkkgo',
47
+ 'oggggggggggo',
48
+ 'oooooooooooo',
49
+ '....oGGo....',
50
+ '..oGGGGGGo..',
51
+ '..oooooooo..',
52
+ ]);
53
+
54
+ /** Onde o monitor fica, a partir do canto do retângulo da mesa; e a tela, a partir do canto do monitor. */
55
+ export const MONITOR_EM = Object.freeze({ x: 1, y: -13 });
56
+ export const TELA_EM = Object.freeze({ x: 2, y: 2 });
57
+
58
+ const CODIGO = ['vlllllvv', 'vvvvvvvv', 'vlllvllv', 'vvvvvvvv'];
59
+ const LINHAS_DA_TELA = [0, 1, 2, 3, 4];
60
+
61
+ /** O monitor aceso, uma tela por fase (0 a 3): as linhas de código sobem um pixel a cada fase. */
62
+ export const TELAS_ACESAS = Object.freeze([0, 1, 2, 3].map((fase) => matriz(
63
+ { v: CORES.telaAcesa, l: CORES.verde },
64
+ LINHAS_DA_TELA.map((linha) => CODIGO[(linha + fase) % CODIGO.length]),
65
+ )));
66
+
67
+ /** Âmbar, com o sinal de pausa: está esperando o usuário. */
68
+ export const TELA_AMBAR = matriz({ y: CORES.ambar, o: CORES.tinta }, [
69
+ 'yyyyyyyy',
70
+ 'yyoyyoyy',
71
+ 'yyoyyoyy',
72
+ 'yyoyyoyy',
73
+ 'yyyyyyyy',
74
+ ]);
75
+
76
+ /** Vermelha, com um xis: falhou. */
77
+ export const TELA_VERMELHA = matriz({ r: CORES.vermelho, o: CORES.tinta }, [
78
+ 'rrrrrrrr',
79
+ 'rrorrorr',
80
+ 'rrroorrr',
81
+ 'rrorrorr',
82
+ 'rrrrrrrr',
83
+ ]);
84
+
85
+ /** Sobre a cabeça de quem concluiu. */
86
+ export const SINAL_FEITO = matriz({ o: CORES.tinta, g: CORES.verde }, [
87
+ '......ooo',
88
+ '.....oogo',
89
+ 'ooo.ooggo',
90
+ 'ogoooggoo',
91
+ 'oggoggoo.',
92
+ 'oogggoo..',
93
+ '.oogoo...',
94
+ '..ooo....',
95
+ ]);
96
+
97
+ /** Sobre a cabeça de quem falhou. */
98
+ export const SINAL_FALHA = matriz({ o: CORES.tinta, r: CORES.vermelho }, [
99
+ 'oooo',
100
+ 'orro',
101
+ 'orro',
102
+ 'orro',
103
+ 'orro',
104
+ 'oooo',
105
+ 'orro',
106
+ 'oooo',
107
+ ]);
108
+
109
+ /** Sobre a cabeça de quem trabalhava e está sem sinal. */
110
+ export const SINAL_DUVIDA = matriz({ o: CORES.tinta, w: CORES.branco }, [
111
+ '.oooo.',
112
+ 'oowwoo',
113
+ 'owoowo',
114
+ 'ooowoo',
115
+ '.owoo.',
116
+ '.ooo..',
117
+ '.owo..',
118
+ '.ooo..',
119
+ ]);
120
+
121
+ /** A sombra no chão de quem está em pé, fora da mesa. */
122
+ export const SOMBRA = matriz({ x: CORES.junta }, ['.xxxxxxxx.']);
@@ -0,0 +1,92 @@
1
+ // A sala do escritório, em matrizes de pixels: a parede do fundo, o piso em ladrilho de dois tons
2
+ // e o que enfeita a parede (janela, relógio, planta). Quem diz onde cada desenho vai é `cena.js`.
3
+ // Spec: fase-e1-escritorio-ao-vivo.md, regra 16 (repositório do OpenCrew).
4
+ import { CORES, matriz } from './sprites.js';
5
+
6
+ /**
7
+ * A parede, numa faixa de 8 px que se repete de lado a lado: sanca de madeira, papel de parede
8
+ * listrado e lambri. A altura é a da parede no modelo (`TOPO`).
9
+ */
10
+ export const PAREDE = matriz({ m: CORES.madeiraMedia, d: CORES.madeiraEscura, p: CORES.parede, P: CORES.paredeSombra, h: CORES.madeiraLuz }, [
11
+ 'mmmmmmmm',
12
+ 'dddddddd',
13
+ 'PPPPPPPP',
14
+ 'pppppppP',
15
+ 'pppppppP',
16
+ 'pppppppP',
17
+ 'pppppppP',
18
+ 'pppppppP',
19
+ 'pppppppP',
20
+ 'pppppppP',
21
+ 'pppppppP',
22
+ 'pppppppP',
23
+ 'pppppppP',
24
+ 'pppppppP',
25
+ 'hhhhhhhh',
26
+ 'mmmmmmmm',
27
+ 'mmmmmmmm',
28
+ 'dddddddd',
29
+ ]);
30
+
31
+ const LADRILHO_LINHAS = Object.freeze([
32
+ 'jjjjjjjjjjjjjjjj',
33
+ 'jaaaaaaaaaaaaaaa',
34
+ 'jaaaaaaaaaaaaaaa',
35
+ 'jaaaaaaaaaaaaaaa',
36
+ 'jaaaaaaaaaaaaaaa',
37
+ 'jaaaaaaaaaaaaaaa',
38
+ 'jaaaaaaaaaaaaaaa',
39
+ 'jaaaaaaaaaaaaaaa',
40
+ 'jaaaaaaaaaaaaaaa',
41
+ ]);
42
+
43
+ /** O ladrilho do piso, com a junta em cima e à esquerda; o claro e o escuro se alternam em xadrez. */
44
+ export const LADRILHO = matriz({ j: CORES.junta, a: CORES.pisoClaro }, LADRILHO_LINHAS);
45
+ export const LADRILHO_ESCURO = matriz({ j: CORES.junta, a: CORES.pisoEscuro }, LADRILHO_LINHAS);
46
+
47
+ /** Janela de duas folhas: um reflexo no vidro da esquerda, uma nuvem no da direita. */
48
+ export const JANELA = matriz({ o: CORES.tinta, w: CORES.branco, b: CORES.ceu, B: CORES.ceuClaro }, [
49
+ 'oooooooooooooooooooooooo',
50
+ 'owwwwwwwwwwwwwwwwwwwwwwo',
51
+ 'owbbbbbBBbbwwbbbbbbbbbwo',
52
+ 'owbbbbBBbbbwwbbbbwwbbbwo',
53
+ 'owbbbBBbbbbwwbbwwwwwbbwo',
54
+ 'owbbBBbbbbbwwbbbbbbbbbwo',
55
+ 'owbBBbbbbbbwwbbbbbbbbbwo',
56
+ 'owbbbbbbbbbwwbbbbbbbbbwo',
57
+ 'owwwwwwwwwwwwwwwwwwwwwwo',
58
+ 'oooooooooooooooooooooooo',
59
+ ]);
60
+
61
+ /** Relógio de parede, parado nas três horas: nada na sala se mexe sem um agente trabalhando. */
62
+ export const RELOGIO = matriz({ o: CORES.tinta, w: CORES.branco }, [
63
+ '..ooooo..',
64
+ '.owwwwwo.',
65
+ 'owwwowwwo',
66
+ 'owwwowwwo',
67
+ 'owwwooowo',
68
+ 'owwwwwwwo',
69
+ 'owwwwwwwo',
70
+ '.owwwwwo.',
71
+ '..ooooo..',
72
+ ]);
73
+
74
+ /** Planta em vaso de barro, para o chão junto à parede. */
75
+ export const PLANTA = matriz({ o: CORES.tinta, g: CORES.folha, G: CORES.folhaEscura, t: CORES.madeiraEscura, v: CORES.madeiraMedia, V: CORES.madeiraEscura }, [
76
+ '...ooooo...',
77
+ '..oggggGo..',
78
+ '.oggGggggo.',
79
+ 'oggggggGggo',
80
+ 'ogGggggggGo',
81
+ 'oggggGggggo',
82
+ '.ogGgggGgo.',
83
+ '..oggggGo..',
84
+ '...oGGGo...',
85
+ '....oto....',
86
+ '..ooooooo..',
87
+ '..ovvvvvo..',
88
+ '..ovvvvVo..',
89
+ '...ovvVo...',
90
+ '...ovvVo...',
91
+ '...ooooo...',
92
+ ]);
@@ -0,0 +1,187 @@
1
+ // Os desenhos do escritório são matrizes de pixels escritas como texto: uma string por linha, uma
2
+ // letra por pixel e uma paleta (letra → cor). Nenhuma imagem entra no pacote.
3
+ // Este módulo traz as cores fixas de toda a cena, o molde do boneco de 16×16 com as trocas de
4
+ // linha de cada pose, e a conta que transforma uma matriz nos retângulos que a cena preenche.
5
+ // Os irmãos `sprites-sala.js` e `sprites-mesa.js` trazem a sala e os móveis.
6
+ // Spec: fase-e1-escritorio-ao-vivo.md, regra 16 (repositório do OpenCrew).
7
+
8
+ /** As cores fixas da cena. A camisa, o cabelo e a pele de cada boneco vêm do modelo. */
9
+ export const CORES = Object.freeze({
10
+ tinta: '#1a1c2c',
11
+ branco: '#f4f4ee',
12
+ cinzaClaro: '#c3c8d4',
13
+ cinzaEscuro: '#4a5266',
14
+ pisoClaro: '#9aa5b8',
15
+ pisoEscuro: '#8d98ad',
16
+ junta: '#808ba1',
17
+ parede: '#ead9b5',
18
+ paredeSombra: '#d6c196',
19
+ madeiraLuz: '#dba76a',
20
+ madeira: '#c58a52',
21
+ madeiraMedia: '#a0683f',
22
+ madeiraEscura: '#6f4630',
23
+ ceu: '#7ec4e0',
24
+ ceuClaro: '#bfe6f0',
25
+ folha: '#4c9a52',
26
+ folhaEscura: '#2f6b40',
27
+ telaApagada: '#232838',
28
+ telaAcesa: '#123f4a',
29
+ verde: '#5fd47a',
30
+ ambar: '#f4a73b',
31
+ vermelho: '#e0564c',
32
+ });
33
+
34
+ /**
35
+ * Uma matriz de pixels: `linhas` do mesmo tamanho e a `paleta` com a cor de cada letra. O ponto
36
+ * é sempre o pixel vazio.
37
+ */
38
+ export function matriz(paleta, linhas) {
39
+ return Object.freeze({ paleta: Object.freeze({ '.': null, ...paleta }), linhas: Object.freeze(linhas) });
40
+ }
41
+
42
+ /**
43
+ * O molde do boneco: 16×16, de frente, parado. Na paleta, `cabelo`, `pele`, `camisa` e as duas
44
+ * sombras são fendas que `coresDoBoneco` troca pelas cores de cada agente.
45
+ */
46
+ export const MOLDE = matriz({
47
+ o: CORES.tinta, h: 'cabelo', s: 'pele', S: 'pele-sombra', c: 'camisa', C: 'camisa-sombra',
48
+ p: CORES.cinzaEscuro, P: CORES.telaApagada, b: CORES.madeiraEscura, w: CORES.branco, g: CORES.cinzaClaro,
49
+ }, [
50
+ '....oooooooo....',
51
+ '...ohhhhhhhho...',
52
+ '..ohhhhhhhhhho..',
53
+ '..ohhhhhhhhhho..',
54
+ '..ohhsssssshho..',
55
+ '..ohsssssssSho..',
56
+ '..ossossssosSo..',
57
+ '..osssssssssSo..',
58
+ '...oSSSSSSSSo...',
59
+ '..oCccccccccCo..',
60
+ '..oCccccccccCo..',
61
+ '..osccccccccso..',
62
+ '...oCCCCCCCCo...',
63
+ '....oppppppo....',
64
+ '....oppoopPo....',
65
+ '...obbboobbbo...',
66
+ ]);
67
+
68
+ /**
69
+ * As poses são o molde com linhas trocadas: cada troca diz o número da linha e o texto novo.
70
+ * `digitar` e `andar` têm dois quadros; `mao` é o braço levantado de quem espera; `festa`, os
71
+ * dois braços para cima de quem comemora; `papel` é o braço com o papel, que se soma às pernas
72
+ * de quem anda.
73
+ */
74
+ export const TROCAS = Object.freeze({
75
+ 'digitar-a': { 11: '..oCccccccccso..', 12: '...ossCCCCCCo...' },
76
+ 'digitar-b': { 11: '..osccccccccCo..', 12: '...oCCCCCCsso...' },
77
+ 'andar-a': { 14: '....oppoobbo....', 15: '...obbbo.oo.....' },
78
+ 'andar-b': { 14: '....obboopPo....', 15: '.....oo.obbbo...' },
79
+ mao: {
80
+ 0: '....oooooooo.oo.',
81
+ 1: '...ohhhhhhhhosso',
82
+ 2: '..ohhhhhhhhhhoso',
83
+ 3: '..ohhhhhhhhhhoso',
84
+ 4: '..ohhsssssshhoCo',
85
+ 5: '..ohsssssssShoCo',
86
+ 6: '..ossossssosSoCo',
87
+ 7: '..osssssssssSoCo',
88
+ 8: '...oSSSSSSSSoCCo',
89
+ 9: '..oCcccccccccCo.',
90
+ 11: '..osccccccccCo..',
91
+ },
92
+ festa: {
93
+ 0: '.oo.oooooooo.oo.',
94
+ 1: 'ossohhhhhhhhosso',
95
+ 2: 'osohhhhhhhhhhoso',
96
+ 3: 'osohhhhhhhhhhoso',
97
+ 4: 'oCohhsssssshhoCo',
98
+ 5: 'oCohsssssssShoCo',
99
+ 6: 'oCossossssosSoCo',
100
+ 7: 'oCosssssssssSoCo',
101
+ 8: 'oCCoSSSSSSSSoCCo',
102
+ 9: '.oCccccccccccCo.',
103
+ 11: '..oCccccccccCo..',
104
+ },
105
+ papel: {
106
+ 8: '...oSSSSSSSSooo.',
107
+ 9: '..oCccccccccCwwo',
108
+ 10: '..oCccccccccCwgo',
109
+ 11: '..osccccccccswwo',
110
+ 12: '...oCCCCCCCCoooo',
111
+ },
112
+ });
113
+
114
+ const virar = (linha) => [...linha].reverse().join('');
115
+ const POSTAS = new Map();
116
+
117
+ /**
118
+ * As 16 linhas do boneco numa pose. A mesma pose devolve sempre a mesma lista.
119
+ * @param {string} pose uma das poses de `quadro` (`parado` é o molde)
120
+ * @param {{ papel?: boolean, festa?: boolean, espelhado?: boolean }} [o] `papel`: leva o papel ·
121
+ * `festa`: os dois braços para cima, no lugar da pose · `espelhado`: virado para a esquerda
122
+ */
123
+ export function linhasDoBoneco(pose, { papel = false, festa = false, espelhado = false } = {}) {
124
+ const chave = `${pose}|${papel}|${festa}|${espelhado}`;
125
+ if (!POSTAS.has(chave)) {
126
+ const trocas = { ...(festa ? TROCAS.festa : TROCAS[pose]), ...(papel ? TROCAS.papel : null) };
127
+ const linhas = MOLDE.linhas.map((linha, i) => trocas[i] ?? linha);
128
+ POSTAS.set(chave, espelhado ? linhas.map(virar) : linhas);
129
+ }
130
+ return POSTAS.get(chave);
131
+ }
132
+
133
+ /** A cor um quarto mais escura: a sombra que dá volume à pele e à camisa. */
134
+ export function sombra(cor) {
135
+ const canal = (inicio) => Math.round(parseInt(cor.slice(inicio, inicio + 2), 16) * 0.75).toString(16).padStart(2, '0');
136
+ return `#${canal(1)}${canal(3)}${canal(5)}`;
137
+ }
138
+
139
+ const PALETAS = new Map();
140
+
141
+ /** A paleta do molde com as cores de um agente (`{ camisa, cabelo, pele }`, em `#rrggbb`). */
142
+ export function coresDoBoneco({ camisa, cabelo, pele }) {
143
+ const chave = `${camisa}|${cabelo}|${pele}`;
144
+ if (!PALETAS.has(chave)) {
145
+ const fendas = { cabelo, pele, 'pele-sombra': sombra(pele), camisa, 'camisa-sombra': sombra(camisa) };
146
+ PALETAS.set(chave, Object.fromEntries(Object.entries(MOLDE.paleta).map(([letra, cor]) => [letra, fendas[cor] ?? cor])));
147
+ }
148
+ return PALETAS.get(chave);
149
+ }
150
+
151
+ /** Os trechos de uma linha: `[x, largura, letra]` de cada sequência da mesma letra, sem os vazios. */
152
+ function trechos(linha) {
153
+ return [...linha.matchAll(/([^.])\1*/g)].map((achado) => [achado.index, achado[0].length, achado[1]]);
154
+ }
155
+
156
+ const guardar = (lista, item) => {
157
+ lista.push(item);
158
+ return item;
159
+ };
160
+
161
+ /** Trechos iguais em linhas seguidas viram um retângulo só: a cena preenche menos vezes. */
162
+ function juntar(linhas) {
163
+ const todos = [];
164
+ let acima = new Map();
165
+ linhas.forEach((linha, y) => {
166
+ const nesta = new Map();
167
+ for (const [x, largura, letra] of trechos(linha)) {
168
+ const chave = `${x}:${largura}:${letra}`;
169
+ const retangulo = acima.get(chave) ?? guardar(todos, [x, y, largura, 0, letra]);
170
+ retangulo[3] += 1;
171
+ nesta.set(chave, retangulo);
172
+ }
173
+ acima = nesta;
174
+ });
175
+ return todos;
176
+ }
177
+
178
+ const RETANGULOS = new WeakMap();
179
+
180
+ /**
181
+ * Os retângulos que desenham uma matriz: `[x, y, largura, altura, letra]`, a partir do canto
182
+ * superior esquerdo dela. A conta é feita uma vez por lista de linhas.
183
+ */
184
+ export function retangulos(linhas) {
185
+ if (!RETANGULOS.has(linhas)) RETANGULOS.set(linhas, juntar(linhas));
186
+ return RETANGULOS.get(linhas);
187
+ }
@@ -131,9 +131,9 @@ Generate these files. Use the Write tool for all file creation — never use Bas
131
131
  - **`displayName` is REQUIRED and MUST be byte-for-byte identical to the agent's
132
132
  `name:` frontmatter field in its `.agent.md`** (the mandatory two-word "FirstName
133
133
  LastName" persona name). The Pipeline Runner reads `displayName` — NOT `title` — to
134
- render the agent's name in `state.json`, in "🤖 {name} is working…" announcements, and
135
- in the dashboard. If `displayName` is missing, empty, or set to the role/title instead
136
- of the persona name, the crew renders with functions but no names.
134
+ render the agent's name in "🤖 {name} is working…" announcements, and the Escritório
135
+ (the optional live view) shows the same column. If `displayName` is missing, empty, or set
136
+ to the role/title instead of the persona name, the crew renders with functions but no names.
137
137
  - `id` = the `path` basename with `./agents/` and `.agent.md` stripped
138
138
  (e.g. `./agents/researcher.agent.md` → `researcher`).
139
139
  - `title` = the agent's `title:` frontmatter (the role/function label). This is a
@@ -305,7 +305,7 @@ target_formats: # content crews only; empty list for others
305
305
 
306
306
  The `crew_code` must be a short, URL-safe slug derived from the crew's purpose (e.g., `content-calendar`, `competitor-tracker`, `lead-notify`).
307
307
 
308
- **CRITICAL — Name uniqueness:** The `crew_code` MUST NEVER match any existing folder name in `crews/`. Before finalizing, run `ls crews/ 2>/dev/null` (Bash) to list existing crew directories. If the slug you derive matches an existing folder, append a numeric suffix (`-2`, `-3`, etc.) until it is unique. Never reuse an existing crew folder name — doing so would overwrite another crew's files.
308
+ **CRITICAL — Name uniqueness:** The `crew_code` MUST NEVER match any existing folder name in `crews/`. Before finalizing, list the existing folders of `crews/` with the IDE's folder-listing tool (no shell command); if `crews/` does not exist yet, there are none. If the slug you derive matches an existing folder, append a numeric suffix (`-2`, `-3`, etc.) until it is unique. Never reuse an existing crew folder name — doing so would overwrite another crew's files.
309
309
 
310
310
  ---
311
311
 
@@ -1,8 +1,8 @@
1
1
  # Repair — Fix Crew Agent Names / Manifest
2
2
 
3
3
  You are the opencrew Repair agent. Your job is to fix an **already-created** crew whose
4
- agents show their function/role but not their persona names (e.g. the dashboard and the
5
- Pipeline Runner announce "Pesquisador" instead of "Pedro Pesquisa").
4
+ agents show their function/role but not their persona names (e.g. the Escritório and the
5
+ Pipeline Runner show "Pesquisador" instead of "Pedro Pesquisa").
6
6
 
7
7
  This is a known defect in crews built by older versions: the `crew-party.csv` manifest was
8
8
  generated without a `displayName` column (or with the role/title in it instead of the
@@ -13,10 +13,9 @@ re-run the Build phase.
13
13
 
14
14
  ## Scope
15
15
 
16
- You may ONLY touch files under `crews/{code}/`:
16
+ You may ONLY touch these files under `crews/{code}/`:
17
17
  - `crews/{code}/crew-party.csv`
18
18
  - `crews/{code}/agents/*.agent.md` (only in the fallback case — see Step 4)
19
- - `crews/{code}/state.json` (only if it exists)
20
19
 
21
20
  Never modify `_opencrew/`, `templates/`, or any other crew. Use the Write tool for all file
22
21
  writes (never Bash `mkdir`).
@@ -77,13 +76,7 @@ existed and must be generated now, following the **Agent Naming Convention** fro
77
76
  Only do this for agents that are actually broken. Agents that already have a valid two-word
78
77
  `name:` are left untouched (only the CSV is rewritten to carry it).
79
78
 
80
- ## Step 5: Refresh `state.json` (only if it exists)
81
-
82
- If `crews/{code}/state.json` exists, update each agent entry's `name` field to the repaired
83
- `displayName`. Do not change any other field. If the file does not exist, skip — the
84
- Pipeline Runner recreates it from the CSV on the next run.
85
-
86
- ## Step 6: Report
79
+ ## Step 5: Report
87
80
 
88
81
  Present a summary table of what changed:
89
82
 
@@ -96,11 +89,13 @@ Crew "{name}" repaired.
96
89
  | copywriter | Guilherme | ✍️ Guilherme Gancho | generated |
97
90
 
98
91
  crew-party.csv: rewritten with displayName column
99
- state.json: {updated | not present}
100
92
 
101
93
  Run it: /opencrew run {code}
102
94
  ```
103
95
 
96
+ The Escritório (the optional live view) takes the names from the CSV when the next run starts:
97
+ there is nothing else to refresh.
98
+
104
99
  If nothing was broken (CSV already had a valid `displayName` for every agent), say so
105
100
  plainly instead of inventing changes: "This crew's manifest is already correct — no repair
106
101
  needed."