expxdev 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +580 -81
  2. package/dist/cli/init.js +6 -2
  3. package/dist/cli/init.js.map +1 -1
  4. package/dist/cli/subcomandos.js +1 -1
  5. package/dist/doctor/verificadores.js +97 -1
  6. package/dist/doctor/verificadores.js.map +1 -1
  7. package/dist/harness/hooks.d.ts +27 -0
  8. package/dist/harness/hooks.js +36 -0
  9. package/dist/harness/hooks.js.map +1 -0
  10. package/dist/harness/settings.d.ts +2 -1
  11. package/dist/harness/settings.js +40 -2
  12. package/dist/harness/settings.js.map +1 -1
  13. package/dist/nucleo/caminhos.d.ts +1 -1
  14. package/dist/nucleo/catalogo.d.ts +1 -1
  15. package/dist/nucleo/catalogo.js +7 -1
  16. package/dist/nucleo/catalogo.js.map +1 -1
  17. package/dist/nucleo/layout.d.ts +3 -2
  18. package/dist/nucleo/layout.js +37 -1
  19. package/dist/nucleo/layout.js.map +1 -1
  20. package/dist/nucleo/versao.d.ts +1 -1
  21. package/dist/parser/conformidade/regras.d.ts +1 -0
  22. package/dist/parser/conformidade/regras.js +24 -0
  23. package/dist/parser/conformidade/regras.js.map +1 -1
  24. package/dist/parser/esquema/enums.d.ts +19 -0
  25. package/dist/parser/esquema/enums.js +18 -0
  26. package/dist/parser/esquema/enums.js.map +1 -1
  27. package/dist/parser/esquema/evento.d.ts +123 -0
  28. package/dist/parser/esquema/evento.js +141 -0
  29. package/dist/parser/esquema/evento.js.map +1 -0
  30. package/dist/parser/leitura/rejeicao.d.ts +9 -0
  31. package/dist/parser/leitura/rejeicao.js +56 -0
  32. package/dist/parser/leitura/rejeicao.js.map +1 -1
  33. package/dist/parser/memoria/ler.d.ts +38 -0
  34. package/dist/parser/memoria/ler.js +46 -0
  35. package/dist/parser/memoria/ler.js.map +1 -0
  36. package/dist/parser/memoria/projetar.d.ts +3 -0
  37. package/dist/parser/memoria/projetar.js +132 -0
  38. package/dist/parser/memoria/projetar.js.map +1 -0
  39. package/dist/parser/memoria/tipos.d.ts +155 -0
  40. package/dist/parser/memoria/tipos.js +97 -0
  41. package/dist/parser/memoria/tipos.js.map +1 -0
  42. package/dist/parser/projeto/montar.d.ts +17 -0
  43. package/dist/parser/projeto/montar.js +17 -0
  44. package/dist/parser/projeto/montar.js.map +1 -1
  45. package/dist/plugin/montagem.d.ts +7 -0
  46. package/dist/plugin/montagem.js +22 -2
  47. package/dist/plugin/montagem.js.map +1 -1
  48. package/dist/servidor/http.js +5 -0
  49. package/dist/servidor/http.js.map +1 -1
  50. package/dist/servidor/observador.js +5 -1
  51. package/dist/servidor/observador.js.map +1 -1
  52. package/dist/teste/repo-fixture.d.ts +7 -0
  53. package/dist/teste/repo-fixture.js +18 -0
  54. package/dist/teste/repo-fixture.js.map +1 -1
  55. package/nucleo/README.md +79 -0
  56. package/nucleo/hooks/expx-rastro.sh +261 -0
  57. package/package.json +6 -4
  58. package/ui/dist/assets/index-BNE_RJrV.js +15 -0
  59. package/ui/dist/index.html +1 -1
  60. package/ui/dist/assets/index-BmDTogQZ.js +0 -14
@@ -14,6 +14,13 @@ export type OpcoesRepo = {
14
14
  layout?: Layout;
15
15
  /** Conteúdo extra do SKILL.md, para fixtures que precisam de um corpo específico. */
16
16
  corpo?: string;
17
+ /**
18
+ * Hooks da skill, gravados em `.claude/hooks/` com bit de execução. O memox é
19
+ * a primeira skill do catálogo que traz hooks; antes dele nenhuma trazia.
20
+ */
21
+ hooks?: readonly string[];
22
+ /** Arquivos de `assets/` da skill, por nome. É onde mora o motor do memox. */
23
+ assets?: Readonly<Record<string, string>>;
17
24
  };
18
25
  /**
19
26
  * Onde o SKILL.md e os comandos ficam em cada layout. `embutido` é o do
@@ -35,6 +35,24 @@ export function criarRepoSkill(op) {
35
35
  `---\nname: ${op.nome}\ndescription: Skill de fixture ${op.nome} para a suite do expx-cli\n---\n\n# ${op.nome}\n\nDetalhe em \`references/01.md\`.\n`);
36
36
  writeFileSync(join(raiz, skill, "references", "01.md"), `# referencia de ${op.nome}\n`);
37
37
  writeFileSync(join(raiz, comandos, `${op.nome}.md`), `---\ndescription: comando ${op.nome}\n---\n\nInvoque a skill \`${op.nome}\`.\n`);
38
+ // Os hooks nascem executáveis: o README do memox manda `chmod +x`, e um hook
39
+ // sem o bit sai `0` em silêncio — indistinguível de "nada a injetar".
40
+ if (op.hooks !== undefined && op.hooks.length > 0) {
41
+ const dirHooks = join(raiz, ".claude", "hooks");
42
+ mkdirSync(dirHooks, { recursive: true });
43
+ for (const h of op.hooks) {
44
+ writeFileSync(join(dirHooks, h), `#!/usr/bin/env bash\n# hook de fixture ${h}\nexit 0\n`, {
45
+ mode: 0o755,
46
+ });
47
+ }
48
+ }
49
+ if (op.assets !== undefined) {
50
+ const dirAssets = join(raiz, skill, "assets");
51
+ mkdirSync(dirAssets, { recursive: true });
52
+ for (const [nome, conteudo] of Object.entries(op.assets)) {
53
+ writeFileSync(join(dirAssets, nome), conteudo);
54
+ }
55
+ }
38
56
  git(raiz, "init", "-q", "-b", "main");
39
57
  git(raiz, "add", "-A");
40
58
  git(raiz, "commit", "-q", "-m", `${op.nome}: commit inicial`);
@@ -1 +1 @@
1
- {"version":3,"file":"repo-fixture.js","sourceRoot":"","sources":["../../src/teste/repo-fixture.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repo-fixture.js","sourceRoot":"","sources":["../../src/teste/repo-fixture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ # Núcleo compartilhado
2
+
3
+ O que as skills do método precisam ter **igual**, escrito uma vez só.
4
+
5
+ ## O que tem aqui
6
+
7
+ | Arquivo | O que é |
8
+ |---|---|
9
+ | `hooks/expx-rastro.sh` | O rastro de eventos, os modos de hook e o `trabalho_id` |
10
+
11
+ ## Como chega até um projeto
12
+
13
+ Por **cópia**, nunca por dependência.
14
+
15
+ Nenhum dos repositórios de skill tem `package.json` — eles são plugins
16
+ instalados sozinhos, e cada projeto precisa rodar de forma independente. Uma
17
+ biblioteca importada em tempo de execução quebraria exatamente isso.
18
+
19
+ Então: a fonte é este diretório, o `expx init` copia (`montarPlugin` leva
20
+ `nucleo/` junto com o plugin), e o que chega ao projeto é um arquivo em disco.
21
+ Sem `npm install`, sem runtime compartilhado, sem rede.
22
+
23
+ ## Como usar num hook
24
+
25
+ A ferramenta é **parâmetro**, definido antes do `source`:
26
+
27
+ ```sh
28
+ EXPX_FERRAMENTA=mergex
29
+ . "$(dirname "$0")/../nucleo/hooks/expx-rastro.sh"
30
+
31
+ MODO="$(expx_modo "$RAIZ" git-perigoso seguranca)"
32
+ [ "$MODO" = "desligado" ] && exit 0
33
+
34
+ expx_rastro_grava "$RAIZ" acao_bloqueada hook bloqueado "commit na main" '[]' \
35
+ '"hook":"git-perigoso"'
36
+ ```
37
+
38
+ Variáveis que o rastro lê, todas opcionais:
39
+
40
+ | Variável | Efeito |
41
+ |---|---|
42
+ | `EXPX_FERRAMENTA` | o campo `ferramenta` da linha (**defina sempre**) |
43
+ | `EXPX_TRABALHO_ID` | vence a detecção automática |
44
+ | `EXPX_FASE` / `EXPX_TASK` | preenchem `fase` e `task` (JSON: com aspas) |
45
+ | `EXPX_AGENTE` | o subagente; sem ela, `principal` |
46
+
47
+ ## Por que existe
48
+
49
+ Cada skill tinha a sua implementação do rastro — quatro no total, em duas
50
+ linguagens. Não eram cópias que divergiram: eram **reescritas**, porque o
51
+ `comum/rastro.sh` de cada repositório trazia o nome da ferramenta cravado no
52
+ código (`"ferramenta":"sprintx"`), e um arquivo que se identifica não pode ser
53
+ compartilhado.
54
+
55
+ E já divergiam em produção, antes mesmo de o painel ler o rastro:
56
+
57
+ - chave extra no meio do objeto, quebrando a verificação de uma skill irmã
58
+ - `agente` ora `null`, ora `"principal"`, para o mesmo caso
59
+ - três estratégias diferentes para descobrir o `trabalho_id`
60
+ - dois conjuntos de modos: uma skill não conhecia `desligado` e continuava
61
+ rodando depois de alguém pedir para desligá-la
62
+ - um leitor de lock com o nome do arquivo errado, falhando em silêncio
63
+
64
+ ## Adoção
65
+
66
+ Incremental, uma skill por vez. Uma skill migra quando trocar o `source` do seu
67
+ `comum/rastro.sh` por este arquivo e renomear as chamadas (`rastro_*` →
68
+ `expx_*`). Enquanto não migra, continua com a cópia própria — que é o ponto de
69
+ distribuir por cópia: nada quebra enquanto a migração não acontece.
70
+
71
+ O que garante que as duas não divirjam no meio do caminho é o validador:
72
+ `expx doctor` lê `docs/eventos/*.jsonl` e aponta toda linha fora do contrato,
73
+ seja qual for a implementação que a escreveu.
74
+
75
+ ## Contratos
76
+
77
+ - [`CONVENCOES.md`](../docs/contrato/CONVENCOES.md) — R1 a R14, o documento raiz
78
+ - [`CONTRATO-expx-eventos.md`](../docs/contrato/CONTRATO-expx-eventos.md) — a linha do rastro, hooks e agentes
79
+ - [`CONTRATO-expx-schema-v1.md`](../docs/contrato/CONTRATO-expx-schema-v1.md) — o frontmatter de estado
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env bash
2
+ # expx-rastro.sh — o rastro de eventos do metodo Expx, uma vez so.
3
+ #
4
+ # Implementa o contrato `expx-eventos` v1 e as convencoes R1-R14
5
+ # (docs/contrato/CONVENCOES.md e CONTRATO-expx-eventos.md).
6
+ #
7
+ # NAO E EXECUTAVEL: os hooks fazem `source` deste arquivo.
8
+ #
9
+ # ---------------------------------------------------------------------------
10
+ # Por que este arquivo existe
11
+ #
12
+ # Cada skill tinha a sua propria implementacao do rastro — quatro no total, em
13
+ # duas linguagens. Nao eram copias que divergiram: eram reescritas, porque o
14
+ # `comum/rastro.sh` de cada repo trazia o nome da ferramenta CRAVADO no codigo
15
+ # (`"ferramenta":"sprintx"`) e por isso nao dava para compartilhar. Elas ja
16
+ # divergiam em producao: chave extra no meio do objeto, `agente` ora null ora
17
+ # "principal", tres estrategias de trabalho_id, dois conjuntos de modos.
18
+ #
19
+ # Aqui a ferramenta e PARAMETRO. Defina `EXPX_FERRAMENTA` antes do source:
20
+ #
21
+ # EXPX_FERRAMENTA=mergex
22
+ # . "$(dirname "$0")/expx-rastro.sh"
23
+ #
24
+ # ---------------------------------------------------------------------------
25
+ # Como este arquivo chega ate um projeto
26
+ #
27
+ # Por COPIA, nunca por dependencia. O `expx init` copia; cada repositorio
28
+ # continua rodando sozinho, com o que tem em disco, sem `npm install` e sem
29
+ # runtime compartilhado. A fonte e o plugin; a copia e versionada com a skill.
30
+ #
31
+ # ---------------------------------------------------------------------------
32
+ # Regras do contrato que este arquivo materializa
33
+ # 1. Rapido — sem rede, sem parser externo pesado.
34
+ # 3. Falha aberta — toda funcao retorna 0 mesmo sem conseguir gravar.
35
+ # 6. Sem estado — tudo sai de arquivo que ja existe.
36
+ # 7. Sempre grava — inclusive quando permite.
37
+
38
+ # A ferramenta e obrigatoria, mas a ausencia NAO derruba o hook (regra 3):
39
+ # cai para "desconhecida", que o validador aponta em vez de sumir em silencio.
40
+ : "${EXPX_FERRAMENTA:=desconhecida}"
41
+
42
+ # ---------------------------------------------------------------- util basica
43
+
44
+ # Raiz do repositorio: sobe ate achar .git; sem .git, o cwd.
45
+ expx_raiz() {
46
+ local d="${1:-$PWD}"
47
+ while [ "$d" != "/" ]; do
48
+ [ -d "$d/.git" ] && { printf '%s' "$d"; return 0; }
49
+ d="$(dirname "$d")"
50
+ done
51
+ printf '%s' "${1:-$PWD}"
52
+ }
53
+
54
+ # Escapa uma string para caber num JSON string literal.
55
+ # A barra invertida vem primeiro, senao escapamos o que ja foi escapado.
56
+ expx_json_escape() {
57
+ local s="$1"
58
+ s="${s//\\/\\\\}"
59
+ s="${s//\"/\\\"}"
60
+ s="${s// /\\t}"
61
+ s="${s//$'\r'/\\r}"
62
+ s="${s//$'\n'/\\n}"
63
+ printf '%s' "$s"
64
+ }
65
+
66
+ # Le uma chave de topo do JSON que o harness manda no stdin do hook.
67
+ # Com jq quando existe; sem jq, um grep tolerante. Nunca falha.
68
+ expx_json_get() {
69
+ local json="$1" chave="$2"
70
+ if command -v jq >/dev/null 2>&1; then
71
+ printf '%s' "$json" | jq -r --arg k "$chave" '.[$k] // empty' 2>/dev/null
72
+ return 0
73
+ fi
74
+ printf '%s' "$json" \
75
+ | grep -o "\"$chave\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" \
76
+ | head -1 | sed 's/.*:[[:space:]]*"//; s/"$//'
77
+ }
78
+
79
+ # Le uma chave aninhada em tool_input (ex.: file_path).
80
+ expx_tool_input_get() {
81
+ local json="$1" chave="$2"
82
+ if command -v jq >/dev/null 2>&1; then
83
+ printf '%s' "$json" | jq -r --arg k "$chave" '.tool_input[$k] // empty' 2>/dev/null
84
+ return 0
85
+ fi
86
+ printf '%s' "$json" \
87
+ | grep -o "\"$chave\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" \
88
+ | head -1 | sed 's/.*:[[:space:]]*"//; s/"$//'
89
+ }
90
+
91
+ # ------------------------------------------------------------- trabalho_id
92
+
93
+ # O trabalho corrente.
94
+ #
95
+ # UMA estrategia, em ordem de autoridade — antes eram tres, uma por skill, que
96
+ # davam respostas diferentes no mesmo repositorio na mesma execucao:
97
+ #
98
+ # 1. EXPX_TRABALHO_ID, quando a skill ja sabe qual e
99
+ # 2. .expx/expx-lock.json, que o CLI mantem
100
+ # 3. o ORQUESTRADOR.md mais recente, nos dois layouts de pasta
101
+ # 4. "sem-trabalho"
102
+ #
103
+ # O nome do lock e `expx-lock.json` (src/nucleo/lock.ts). Ler `lock.json` sem
104
+ # o prefixo devolve "sem-trabalho" para sempre, em silencio — a falha aqui e
105
+ # aberta por desenho, entao o erro nunca se anuncia.
106
+ expx_trabalho_id() {
107
+ local raiz="$1" v=""
108
+
109
+ if [ -n "${EXPX_TRABALHO_ID:-}" ]; then
110
+ printf '%s' "$EXPX_TRABALHO_ID" | tr -c 'A-Za-z0-9._-' '-' | cut -c1-64
111
+ return 0
112
+ fi
113
+
114
+ local lock="$raiz/.expx/expx-lock.json"
115
+ if [ -f "$lock" ]; then
116
+ if command -v jq >/dev/null 2>&1; then
117
+ v="$(jq -r '.trabalho_id // empty' "$lock" 2>/dev/null)"
118
+ else
119
+ v="$(grep -o '"trabalho_id"[[:space:]]*:[[:space:]]*"[^"]*"' "$lock" 2>/dev/null \
120
+ | head -1 | sed 's/.*:[[:space:]]*"//; s/"$//')"
121
+ fi
122
+ if [ -n "$v" ]; then
123
+ printf '%s' "$v" | tr -c 'A-Za-z0-9._-' '-' | cut -c1-64
124
+ return 0
125
+ fi
126
+ fi
127
+
128
+ # Os dois layouts: o novo (docs/<skill>/features|ocorrencias/<slug>/) e o
129
+ # antigo (docs/<slug>/), que as skills declaram continuar suportando.
130
+ #
131
+ # `find` em vez de glob: no zsh um padrao sem match ABORTA a funcao (nomatch),
132
+ # e o hook perderia o trabalho_id no shell de metade dos usuarios. O -maxdepth
133
+ # 4 cobre os dois layouts sem varrer o repositorio inteiro.
134
+ local f mais_novo=""
135
+ while IFS= read -r f; do
136
+ [ -f "$f" ] || continue
137
+ if [ -z "$mais_novo" ] || [ "$f" -nt "$mais_novo" ]; then mais_novo="$f"; fi
138
+ done <<EOF
139
+ $(find "$raiz/docs" -maxdepth 4 -name ORQUESTRADOR.md -type f 2>/dev/null)
140
+ EOF
141
+ if [ -n "$mais_novo" ]; then
142
+ basename "$(dirname "$mais_novo")"
143
+ return 0
144
+ fi
145
+
146
+ printf 'sem-trabalho'
147
+ }
148
+
149
+ # ------------------------------------------------------------------ modo
150
+
151
+ # Modo de um hook: aviso | bloqueio | desligado.
152
+ #
153
+ # Uso: expx_modo <raiz> <hook> [tipo] tipo: metodo (padrao) | seguranca
154
+ #
155
+ # Os TRES modos sao obrigatorios. Reconhecer so dois e cair no padrao diante do
156
+ # terceiro faz o hook continuar rodando depois de alguem pedir para desliga-lo.
157
+ #
158
+ # O padrao sai do `tipo`: hook de seguranca nasce em bloqueio e NUNCA e
159
+ # rebaixado por ausencia de configuracao; hook de metodo nasce em aviso. So um
160
+ # "desligado" explicito desliga um hook de seguranca.
161
+ expx_modo() {
162
+ local raiz="$1" hook="$2" tipo="${3:-metodo}" m=""
163
+ local cfg="$raiz/.expx/hooks.json"
164
+ local padrao='aviso'
165
+ [ "$tipo" = "seguranca" ] && padrao='bloqueio'
166
+
167
+ [ -f "$cfg" ] || { printf '%s' "$padrao"; return 0; }
168
+
169
+ if command -v jq >/dev/null 2>&1; then
170
+ # `.modos[...]` e a forma antiga, aceita para nao quebrar quem escreveu o
171
+ # arquivo a mao antes do formato atual.
172
+ m="$(jq -r --arg h "$hook" '.hooks[$h].modo // .modos[$h] // empty' "$cfg" 2>/dev/null)"
173
+ else
174
+ m="$(grep -o "\"$hook\"[[:space:]]*:[[:space:]]*{[^}]*}" "$cfg" 2>/dev/null \
175
+ | grep -o '"modo"[[:space:]]*:[[:space:]]*"[^"]*"' \
176
+ | head -1 | sed 's/.*:[[:space:]]*"//; s/"$//')"
177
+ fi
178
+
179
+ case "$m" in
180
+ aviso|bloqueio|desligado) printf '%s' "$m" ;;
181
+ *) printf '%s' "$padrao" ;;
182
+ esac
183
+ }
184
+
185
+ # ---------------------------------------------------------------- gravacao
186
+
187
+ # expx_rastro_grava <raiz> <evento> <origem> <resultado> <detalhe> [arquivos_json] [extras_json]
188
+ #
189
+ # Grava UMA linha em docs/eventos/<trabalho_id>.jsonl.
190
+ #
191
+ # As DOZE chaves obrigatorias saem sempre todas, na ordem do contrato, e chave
192
+ # sem valor vai como null — nunca omitida (R6). As extras declaradas (`hook`,
193
+ # `faixa`) vao DEPOIS das doze, em `extras_json`, nunca no meio: quem valida
194
+ # procura as doze por contencao, e uma chave no meio do objeto ja quebrou a
195
+ # verificacao de uma skill irma.
196
+ #
197
+ # Falha aberta: erro aqui e engolido. Um hook nunca trava o trabalho por nao
198
+ # conseguir escrever o proprio rastro.
199
+ expx_rastro_grava() {
200
+ local raiz="$1" evento="$2" origem="$3" resultado="$4" detalhe="$5"
201
+ local arquivos="${6:-[]}" extras="${7:-}"
202
+
203
+ {
204
+ local dir="$raiz/docs/eventos"
205
+ mkdir -p "$dir" 2>/dev/null || return 0
206
+
207
+ local tid; tid="$(expx_trabalho_id "$raiz")"
208
+ local arq="$dir/$tid.jsonl"
209
+
210
+ # Rotacao: acima de 5 MB o arquivo vira <trabalho_id>.1.jsonl (contrato).
211
+ if [ -f "$arq" ]; then
212
+ local tam
213
+ tam=$(wc -c < "$arq" 2>/dev/null | tr -d ' ')
214
+ if [ -n "$tam" ] && [ "$tam" -gt 5242880 ] 2>/dev/null; then
215
+ mv -f "$arq" "$dir/$tid.1.jsonl" 2>/dev/null || true
216
+ fi
217
+ fi
218
+
219
+ local ts; ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
220
+ local linha
221
+ linha="{\"ts\":\"$ts\""
222
+ linha="$linha,\"expx_eventos\":1"
223
+ linha="$linha,\"trabalho_id\":\"$(expx_json_escape "$tid")\""
224
+ linha="$linha,\"ferramenta\":\"$EXPX_FERRAMENTA\""
225
+ linha="$linha,\"origem\":\"$origem\""
226
+ linha="$linha,\"evento\":\"$evento\""
227
+ linha="$linha,\"fase\":${EXPX_FASE:-null}"
228
+ linha="$linha,\"task\":${EXPX_TASK:-null}"
229
+ # Sem subagente o valor e "principal", nunca null: "foi o principal" e
230
+ # informacao, nao ausencia.
231
+ linha="$linha,\"agente\":\"${EXPX_AGENTE:-principal}\""
232
+ linha="$linha,\"resultado\":\"$resultado\""
233
+ linha="$linha,\"detalhe\":\"$(expx_json_escape "$detalhe")\""
234
+ linha="$linha,\"arquivos\":$arquivos"
235
+ [ -n "$extras" ] && linha="$linha,$extras"
236
+ linha="$linha}"
237
+
238
+ printf '%s\n' "$linha" >> "$arq" 2>/dev/null || true
239
+ } 2>/dev/null || true
240
+ return 0
241
+ }
242
+
243
+ # ------------------------------------------------------------------- saida
244
+
245
+ # Aviso que CHEGA ao modelo em PostToolUse.
246
+ #
247
+ # Ali o exit 2 nao bloqueia e o stderr NAO volta ao modelo — verificado na
248
+ # documentacao oficial. O unico canal e JSON no stdout. Escrever em stderr num
249
+ # PostToolUse e falha silenciosa.
250
+ expx_aviso_ao_modelo() {
251
+ printf '{"hookSpecificOutput":{"hookEventName":"%s","additionalContext":"%s"}}\n' \
252
+ "$1" "$(expx_json_escape "$2")"
253
+ }
254
+
255
+ # Bloqueio em PreToolUse: exit 2 com o motivo no stderr, que vira a mensagem
256
+ # que o modelo le. Mensagem acionavel: diga o que fazer, nao so o que esta
257
+ # errado.
258
+ expx_bloqueia() {
259
+ printf '%s\n' "$1" >&2
260
+ exit 2
261
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "expxdev",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI do metodo Expx: instala, atualiza e opera o ecossistema de skills, e sobe o painel de operacao",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "expx": "dist/cli/expx-bin.js",
8
+ "expxdev": "dist/cli/expx-bin.js",
8
9
  "expx-painel": "dist/cli/principal.js"
9
10
  },
10
11
  "engines": {
@@ -22,6 +23,7 @@
22
23
  "files": [
23
24
  "dist",
24
25
  "ui/dist",
26
+ "nucleo",
25
27
  "README.md",
26
28
  "LICENSE"
27
29
  ],
@@ -62,12 +64,12 @@
62
64
  "painel"
63
65
  ],
64
66
  "author": "Expx",
65
- "homepage": "https://github.com/bittencourtthulio/expx-painel#readme",
67
+ "homepage": "https://github.com/bittencourtthulio/expxdev#readme",
66
68
  "repository": {
67
69
  "type": "git",
68
- "url": "git+https://github.com/bittencourtthulio/expx-painel.git"
70
+ "url": "git+https://github.com/bittencourtthulio/expxdev.git"
69
71
  },
70
72
  "bugs": {
71
- "url": "https://github.com/bittencourtthulio/expx-painel/issues"
73
+ "url": "https://github.com/bittencourtthulio/expxdev/issues"
72
74
  }
73
75
  }