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.
- package/README.md +580 -81
- package/dist/cli/init.js +6 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/subcomandos.js +1 -1
- package/dist/doctor/verificadores.js +97 -1
- package/dist/doctor/verificadores.js.map +1 -1
- package/dist/harness/hooks.d.ts +27 -0
- package/dist/harness/hooks.js +36 -0
- package/dist/harness/hooks.js.map +1 -0
- package/dist/harness/settings.d.ts +2 -1
- package/dist/harness/settings.js +40 -2
- package/dist/harness/settings.js.map +1 -1
- package/dist/nucleo/caminhos.d.ts +1 -1
- package/dist/nucleo/catalogo.d.ts +1 -1
- package/dist/nucleo/catalogo.js +7 -1
- package/dist/nucleo/catalogo.js.map +1 -1
- package/dist/nucleo/layout.d.ts +3 -2
- package/dist/nucleo/layout.js +37 -1
- package/dist/nucleo/layout.js.map +1 -1
- package/dist/nucleo/versao.d.ts +1 -1
- package/dist/parser/conformidade/regras.d.ts +1 -0
- package/dist/parser/conformidade/regras.js +24 -0
- package/dist/parser/conformidade/regras.js.map +1 -1
- package/dist/parser/esquema/enums.d.ts +19 -0
- package/dist/parser/esquema/enums.js +18 -0
- package/dist/parser/esquema/enums.js.map +1 -1
- package/dist/parser/esquema/evento.d.ts +123 -0
- package/dist/parser/esquema/evento.js +141 -0
- package/dist/parser/esquema/evento.js.map +1 -0
- package/dist/parser/leitura/rejeicao.d.ts +9 -0
- package/dist/parser/leitura/rejeicao.js +56 -0
- package/dist/parser/leitura/rejeicao.js.map +1 -1
- package/dist/parser/memoria/ler.d.ts +38 -0
- package/dist/parser/memoria/ler.js +46 -0
- package/dist/parser/memoria/ler.js.map +1 -0
- package/dist/parser/memoria/projetar.d.ts +3 -0
- package/dist/parser/memoria/projetar.js +132 -0
- package/dist/parser/memoria/projetar.js.map +1 -0
- package/dist/parser/memoria/tipos.d.ts +155 -0
- package/dist/parser/memoria/tipos.js +97 -0
- package/dist/parser/memoria/tipos.js.map +1 -0
- package/dist/parser/projeto/montar.d.ts +17 -0
- package/dist/parser/projeto/montar.js +17 -0
- package/dist/parser/projeto/montar.js.map +1 -1
- package/dist/plugin/montagem.d.ts +7 -0
- package/dist/plugin/montagem.js +22 -2
- package/dist/plugin/montagem.js.map +1 -1
- package/dist/servidor/http.js +5 -0
- package/dist/servidor/http.js.map +1 -1
- package/dist/servidor/observador.js +5 -1
- package/dist/servidor/observador.js.map +1 -1
- package/dist/teste/repo-fixture.d.ts +7 -0
- package/dist/teste/repo-fixture.js +18 -0
- package/dist/teste/repo-fixture.js.map +1 -1
- package/nucleo/README.md +79 -0
- package/nucleo/hooks/expx-rastro.sh +261 -0
- package/package.json +6 -4
- package/ui/dist/assets/index-BNE_RJrV.js +15 -0
- package/ui/dist/index.html +1 -1
- 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":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"repo-fixture.js","sourceRoot":"","sources":["../../src/teste/repo-fixture.ts"],"names":[],"mappings":"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"}
|
package/nucleo/README.md
ADDED
|
@@ -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.
|
|
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/
|
|
67
|
+
"homepage": "https://github.com/bittencourtthulio/expxdev#readme",
|
|
66
68
|
"repository": {
|
|
67
69
|
"type": "git",
|
|
68
|
-
"url": "git+https://github.com/bittencourtthulio/
|
|
70
|
+
"url": "git+https://github.com/bittencourtthulio/expxdev.git"
|
|
69
71
|
},
|
|
70
72
|
"bugs": {
|
|
71
|
-
"url": "https://github.com/bittencourtthulio/
|
|
73
|
+
"url": "https://github.com/bittencourtthulio/expxdev/issues"
|
|
72
74
|
}
|
|
73
75
|
}
|