expxdev 0.4.0 → 0.5.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 +27 -9
- package/dist/cli/expx.js +2 -0
- package/dist/cli/expx.js.map +1 -1
- package/dist/cli/init.js +9 -3
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/principal.js +30 -6
- package/dist/cli/principal.js.map +1 -1
- package/dist/cli/selecao.js +3 -0
- package/dist/cli/selecao.js.map +1 -1
- package/dist/cli/subcomandos.d.ts +1 -1
- package/dist/cli/subcomandos.js +3 -2
- package/dist/cli/subcomandos.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 +2 -2
- package/dist/nucleo/versao.d.ts +1 -1
- package/dist/parser/esquema/enums.d.ts +3 -2
- package/dist/parser/esquema/enums.js +3 -2
- package/dist/parser/esquema/enums.js.map +1 -1
- package/dist/parser/esquema/evento.d.ts +1 -0
- package/dist/servidor/http.d.ts +11 -0
- package/dist/servidor/http.js +31 -1
- package/dist/servidor/http.js.map +1 -1
- package/dist/watch/desenho/arvore.d.ts +3 -0
- package/dist/watch/desenho/arvore.js +62 -0
- package/dist/watch/desenho/arvore.js.map +1 -0
- package/dist/watch/desenho/bloqueios.d.ts +5 -0
- package/dist/watch/desenho/bloqueios.js +41 -0
- package/dist/watch/desenho/bloqueios.js.map +1 -0
- package/dist/watch/desenho/cabecalho.d.ts +11 -0
- package/dist/watch/desenho/cabecalho.js +49 -0
- package/dist/watch/desenho/cabecalho.js.map +1 -0
- package/dist/watch/desenho/cor.d.ts +44 -0
- package/dist/watch/desenho/cor.js +66 -0
- package/dist/watch/desenho/cor.js.map +1 -0
- package/dist/watch/desenho/desenhar.d.ts +16 -0
- package/dist/watch/desenho/desenhar.js +54 -0
- package/dist/watch/desenho/desenhar.js.map +1 -0
- package/dist/watch/desenho/eventos.d.ts +3 -0
- package/dist/watch/desenho/eventos.js +37 -0
- package/dist/watch/desenho/eventos.js.map +1 -0
- package/dist/watch/desenho/largura.d.ts +23 -0
- package/dist/watch/desenho/largura.js +42 -0
- package/dist/watch/desenho/largura.js.map +1 -0
- package/dist/watch/desenho/lista.d.ts +9 -0
- package/dist/watch/desenho/lista.js +28 -0
- package/dist/watch/desenho/lista.js.map +1 -0
- package/dist/watch/fontes/cauda.d.ts +14 -0
- package/dist/watch/fontes/cauda.js +49 -0
- package/dist/watch/fontes/cauda.js.map +1 -0
- package/dist/watch/fontes/estado-schema.d.ts +79 -0
- package/dist/watch/fontes/estado-schema.js +72 -0
- package/dist/watch/fontes/estado-schema.js.map +1 -0
- package/dist/watch/fontes/estado.d.ts +18 -0
- package/dist/watch/fontes/estado.js +38 -0
- package/dist/watch/fontes/estado.js.map +1 -0
- package/dist/watch/fontes/observar.d.ts +32 -0
- package/dist/watch/fontes/observar.js +101 -0
- package/dist/watch/fontes/observar.js.map +1 -0
- package/dist/watch/fontes/raiz.d.ts +12 -0
- package/dist/watch/fontes/raiz.js +25 -0
- package/dist/watch/fontes/raiz.js.map +1 -0
- package/dist/watch/fontes/rastro.d.ts +17 -0
- package/dist/watch/fontes/rastro.js +43 -0
- package/dist/watch/fontes/rastro.js.map +1 -0
- package/dist/watch/opcoes.d.ts +25 -0
- package/dist/watch/opcoes.js +73 -0
- package/dist/watch/opcoes.js.map +1 -0
- package/dist/watch/principal.d.ts +12 -0
- package/dist/watch/principal.js +49 -0
- package/dist/watch/principal.js.map +1 -0
- package/dist/watch/terminal/restaurar.d.ts +24 -0
- package/dist/watch/terminal/restaurar.js +58 -0
- package/dist/watch/terminal/restaurar.js.map +1 -0
- package/dist/watch/terminal/tela.d.ts +17 -0
- package/dist/watch/terminal/tela.js +64 -0
- package/dist/watch/terminal/tela.js.map +1 -0
- package/dist/watch/visao/escolher.d.ts +18 -0
- package/dist/watch/visao/escolher.js +57 -0
- package/dist/watch/visao/escolher.js.map +1 -0
- package/dist/watch/visao/projetar.d.ts +51 -0
- package/dist/watch/visao/projetar.js +38 -0
- package/dist/watch/visao/projetar.js.map +1 -0
- package/dist/watch/watch.d.ts +26 -0
- package/dist/watch/watch.js +89 -0
- package/dist/watch/watch.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Contrato `expx-estado` v1 — o arquivo que a barra de status lê.
|
|
4
|
+
*
|
|
5
|
+
* Primeiro leitor deste contrato no repositório: a busca por
|
|
6
|
+
* `estado.json|expx_estado` em `src/`, `ui/` e `nucleo/` não devolvia nada.
|
|
7
|
+
*
|
|
8
|
+
* Os enums vêm do `expx-schema` de propósito. A regra 7 do contrato manda que
|
|
9
|
+
* sejam os MESMOS ("minúsculo, sem acento; `e3`, não `E3`"), e redeclará-los
|
|
10
|
+
* aqui criaria duas listas que divergem com o tempo — foi exatamente assim que
|
|
11
|
+
* as listas de chaves do rastro divergiram entre duas skills
|
|
12
|
+
* (ver `src/parser/esquema/evento.ts`).
|
|
13
|
+
*/
|
|
14
|
+
/** A versão que este leitor entende. Diferente disso é degradado (D-12). */
|
|
15
|
+
export declare const VERSAO_ESTADO = 1;
|
|
16
|
+
/**
|
|
17
|
+
* As quinze chaves do contrato, na ordem do documento.
|
|
18
|
+
*
|
|
19
|
+
* Exportada porque o teste percorre a lista removendo uma por vez: sem ela, a
|
|
20
|
+
* verificação da R6 seria quinze blocos copiados.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CHAVES_ESTADO: readonly ["expx_estado", "atualizado_em", "trabalho", "ferramenta", "titulo_curto", "fase", "task", "tasks_concluidas", "tasks_total", "raio", "orcamento_arquivos", "orcamento_linhas", "branch", "pr_estado", "bloqueios"];
|
|
23
|
+
/** Faixa de raio do modo legado. `null` fora dele (regra 2 do contrato). */
|
|
24
|
+
export declare const Raio: z.ZodEnum<{
|
|
25
|
+
baixo: "baixo";
|
|
26
|
+
medio: "medio";
|
|
27
|
+
alto: "alto";
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Nenhum campo é `.optional()`: a regra 2 do contrato ("chave nunca omitida")
|
|
31
|
+
* é o que permite ao leitor distinguir "não se aplica" de "esqueceram de
|
|
32
|
+
* escrever". Ausente é `null`, e `null` é um valor presente.
|
|
33
|
+
*
|
|
34
|
+
* Sem `.passthrough()`: ao contrário do rastro, que declara chaves extras por
|
|
35
|
+
* skill, o `expx-estado` fixa quinze chaves e um limite de 1 KB. Chave a mais
|
|
36
|
+
* aqui é sinal de escritor fora do contrato, não de extensão legítima.
|
|
37
|
+
*/
|
|
38
|
+
export declare const EstadoExpx: z.ZodObject<{
|
|
39
|
+
expx_estado: z.ZodLiteral<1>;
|
|
40
|
+
atualizado_em: z.ZodString;
|
|
41
|
+
trabalho: z.ZodNullable<z.ZodString>;
|
|
42
|
+
ferramenta: z.ZodNullable<z.ZodEnum<{
|
|
43
|
+
sprintx: "sprintx";
|
|
44
|
+
runx: "runx";
|
|
45
|
+
mergex: "mergex";
|
|
46
|
+
legadox: "legadox";
|
|
47
|
+
stackx: "stackx";
|
|
48
|
+
memox: "memox";
|
|
49
|
+
prodx: "prodx";
|
|
50
|
+
}>>;
|
|
51
|
+
titulo_curto: z.ZodNullable<z.ZodString>;
|
|
52
|
+
fase: z.ZodNullable<z.ZodEnum<{
|
|
53
|
+
f1: "f1";
|
|
54
|
+
f2: "f2";
|
|
55
|
+
f3: "f3";
|
|
56
|
+
f4: "f4";
|
|
57
|
+
f5: "f5";
|
|
58
|
+
f6: "f6";
|
|
59
|
+
e1: "e1";
|
|
60
|
+
e2: "e2";
|
|
61
|
+
e3: "e3";
|
|
62
|
+
e4: "e4";
|
|
63
|
+
e5: "e5";
|
|
64
|
+
}>>;
|
|
65
|
+
task: z.ZodNullable<z.ZodString>;
|
|
66
|
+
tasks_concluidas: z.ZodNumber;
|
|
67
|
+
tasks_total: z.ZodNumber;
|
|
68
|
+
raio: z.ZodNullable<z.ZodEnum<{
|
|
69
|
+
baixo: "baixo";
|
|
70
|
+
medio: "medio";
|
|
71
|
+
alto: "alto";
|
|
72
|
+
}>>;
|
|
73
|
+
orcamento_arquivos: z.ZodNullable<z.ZodString>;
|
|
74
|
+
orcamento_linhas: z.ZodNullable<z.ZodString>;
|
|
75
|
+
branch: z.ZodNullable<z.ZodString>;
|
|
76
|
+
pr_estado: z.ZodNullable<z.ZodString>;
|
|
77
|
+
bloqueios: z.ZodNumber;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
export type EstadoExpx = z.infer<typeof EstadoExpx>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Estagio, Ferramenta } from "../../parser/esquema/enums.js";
|
|
3
|
+
/**
|
|
4
|
+
* Contrato `expx-estado` v1 — o arquivo que a barra de status lê.
|
|
5
|
+
*
|
|
6
|
+
* Primeiro leitor deste contrato no repositório: a busca por
|
|
7
|
+
* `estado.json|expx_estado` em `src/`, `ui/` e `nucleo/` não devolvia nada.
|
|
8
|
+
*
|
|
9
|
+
* Os enums vêm do `expx-schema` de propósito. A regra 7 do contrato manda que
|
|
10
|
+
* sejam os MESMOS ("minúsculo, sem acento; `e3`, não `E3`"), e redeclará-los
|
|
11
|
+
* aqui criaria duas listas que divergem com o tempo — foi exatamente assim que
|
|
12
|
+
* as listas de chaves do rastro divergiram entre duas skills
|
|
13
|
+
* (ver `src/parser/esquema/evento.ts`).
|
|
14
|
+
*/
|
|
15
|
+
/** A versão que este leitor entende. Diferente disso é degradado (D-12). */
|
|
16
|
+
export const VERSAO_ESTADO = 1;
|
|
17
|
+
/**
|
|
18
|
+
* As quinze chaves do contrato, na ordem do documento.
|
|
19
|
+
*
|
|
20
|
+
* Exportada porque o teste percorre a lista removendo uma por vez: sem ela, a
|
|
21
|
+
* verificação da R6 seria quinze blocos copiados.
|
|
22
|
+
*/
|
|
23
|
+
export const CHAVES_ESTADO = [
|
|
24
|
+
"expx_estado",
|
|
25
|
+
"atualizado_em",
|
|
26
|
+
"trabalho",
|
|
27
|
+
"ferramenta",
|
|
28
|
+
"titulo_curto",
|
|
29
|
+
"fase",
|
|
30
|
+
"task",
|
|
31
|
+
"tasks_concluidas",
|
|
32
|
+
"tasks_total",
|
|
33
|
+
"raio",
|
|
34
|
+
"orcamento_arquivos",
|
|
35
|
+
"orcamento_linhas",
|
|
36
|
+
"branch",
|
|
37
|
+
"pr_estado",
|
|
38
|
+
"bloqueios",
|
|
39
|
+
];
|
|
40
|
+
/** Faixa de raio do modo legado. `null` fora dele (regra 2 do contrato). */
|
|
41
|
+
export const Raio = z.enum(["baixo", "medio", "alto"]);
|
|
42
|
+
/** Timestamp do contrato: ISO-8601 em UTC, com `Z` (R4). */
|
|
43
|
+
const TimestampUtc = z
|
|
44
|
+
.string()
|
|
45
|
+
.regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/, "atualizado_em deve ser AAAA-MM-DDTHH:MM:SSZ");
|
|
46
|
+
/**
|
|
47
|
+
* Nenhum campo é `.optional()`: a regra 2 do contrato ("chave nunca omitida")
|
|
48
|
+
* é o que permite ao leitor distinguir "não se aplica" de "esqueceram de
|
|
49
|
+
* escrever". Ausente é `null`, e `null` é um valor presente.
|
|
50
|
+
*
|
|
51
|
+
* Sem `.passthrough()`: ao contrário do rastro, que declara chaves extras por
|
|
52
|
+
* skill, o `expx-estado` fixa quinze chaves e um limite de 1 KB. Chave a mais
|
|
53
|
+
* aqui é sinal de escritor fora do contrato, não de extensão legítima.
|
|
54
|
+
*/
|
|
55
|
+
export const EstadoExpx = z.object({
|
|
56
|
+
expx_estado: z.literal(VERSAO_ESTADO),
|
|
57
|
+
atualizado_em: TimestampUtc,
|
|
58
|
+
trabalho: z.string().min(1).nullable(),
|
|
59
|
+
ferramenta: Ferramenta.nullable(),
|
|
60
|
+
titulo_curto: z.string().nullable(),
|
|
61
|
+
fase: Estagio.nullable(),
|
|
62
|
+
task: z.string().nullable(),
|
|
63
|
+
tasks_concluidas: z.number().int().min(0),
|
|
64
|
+
tasks_total: z.number().int().min(0),
|
|
65
|
+
raio: Raio.nullable(),
|
|
66
|
+
orcamento_arquivos: z.string().nullable(),
|
|
67
|
+
orcamento_linhas: z.string().nullable(),
|
|
68
|
+
branch: z.string().nullable(),
|
|
69
|
+
pr_estado: z.string().nullable(),
|
|
70
|
+
bloqueios: z.number().int().min(0),
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=estado-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estado-schema.js","sourceRoot":"","sources":["../../../src/watch/fontes/estado-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEpE;;;;;;;;;;;GAWG;AAEH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,aAAa;IACb,eAAe;IACf,UAAU;IACV,YAAY;IACZ,cAAc;IACd,MAAM;IACN,MAAM;IACN,kBAAkB;IAClB,aAAa;IACb,MAAM;IACN,oBAAoB;IACpB,kBAAkB;IAClB,QAAQ;IACR,WAAW;IACX,WAAW;CACH,CAAC;AAEX,4EAA4E;AAC5E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAEvD,4DAA4D;AAC5D,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,EAAE;KACR,KAAK,CACJ,wCAAwC,EACxC,6CAA6C,CAC9C,CAAC;AAEJ;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IACrC,aAAa,EAAE,YAAY;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE;IACjC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE;IACxB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;IACrB,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACnC,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EstadoExpx } from "./estado-schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lê `.expx/estado.json` a partir da raiz do projeto.
|
|
4
|
+
*
|
|
5
|
+
* Falha SEMPRE para `null`, nunca lança. A regra 1 do contrato `expx-estado`
|
|
6
|
+
* declara o arquivo "derivado e descartável; apagá-lo não pode quebrar nada" —
|
|
7
|
+
* e o watch inteiro depende disso: a tolerância a falha "estado.json inválido
|
|
8
|
+
* cai para leitura direta do plano" é justamente este `null`.
|
|
9
|
+
*
|
|
10
|
+
* A leitura é de uma vez só porque o contrato exige escrita atômica (regra 3:
|
|
11
|
+
* temporário + rename). Não existe janela de leitura parcial: ou o arquivo
|
|
12
|
+
* antigo inteiro, ou o novo inteiro.
|
|
13
|
+
*
|
|
14
|
+
* Versão diferente de 1 é `null` de propósito (decisão D-12): o `EstadoExpx`
|
|
15
|
+
* declara `expx_estado: z.literal(1)`, então um arquivo de versão futura
|
|
16
|
+
* reprova no parse como qualquer outro defeito, e quem chama vai para o plano.
|
|
17
|
+
*/
|
|
18
|
+
export declare function lerEstadoExpx(raizProjeto: string): EstadoExpx | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { EstadoExpx } from "./estado-schema.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lê `.expx/estado.json` a partir da raiz do projeto.
|
|
6
|
+
*
|
|
7
|
+
* Falha SEMPRE para `null`, nunca lança. A regra 1 do contrato `expx-estado`
|
|
8
|
+
* declara o arquivo "derivado e descartável; apagá-lo não pode quebrar nada" —
|
|
9
|
+
* e o watch inteiro depende disso: a tolerância a falha "estado.json inválido
|
|
10
|
+
* cai para leitura direta do plano" é justamente este `null`.
|
|
11
|
+
*
|
|
12
|
+
* A leitura é de uma vez só porque o contrato exige escrita atômica (regra 3:
|
|
13
|
+
* temporário + rename). Não existe janela de leitura parcial: ou o arquivo
|
|
14
|
+
* antigo inteiro, ou o novo inteiro.
|
|
15
|
+
*
|
|
16
|
+
* Versão diferente de 1 é `null` de propósito (decisão D-12): o `EstadoExpx`
|
|
17
|
+
* declara `expx_estado: z.literal(1)`, então um arquivo de versão futura
|
|
18
|
+
* reprova no parse como qualquer outro defeito, e quem chama vai para o plano.
|
|
19
|
+
*/
|
|
20
|
+
export function lerEstadoExpx(raizProjeto) {
|
|
21
|
+
let bruto;
|
|
22
|
+
try {
|
|
23
|
+
bruto = readFileSync(join(raizProjeto, ".expx", "estado.json"), "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null; // ausente, sem permissão, é um diretório: tudo é "não há estado"
|
|
27
|
+
}
|
|
28
|
+
let dados;
|
|
29
|
+
try {
|
|
30
|
+
dados = JSON.parse(bruto);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const r = EstadoExpx.safeParse(dados);
|
|
36
|
+
return r.success ? r.data : null;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=estado.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estado.js","sourceRoot":"","sources":["../../../src/watch/fontes/estado.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,iEAAiE;IAChF,CAAC;IAED,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observa as DUAS fontes do watch, com gatilhos separados.
|
|
3
|
+
*
|
|
4
|
+
* Por que não reusar `observar()` do painel, já que ele existe e usa o mesmo
|
|
5
|
+
* chokidar: ele ignora `.expx/` (decisão D-06 dele, para o índice do memox não
|
|
6
|
+
* realimentar a recarga) e recebe uma raiz só, avisando com um callback cego
|
|
7
|
+
* que não diz o que mudou. O watch precisa do contrário nas três coisas.
|
|
8
|
+
* Mexer no observador do painel arriscaria a decisão dele — decisão D-06 desta
|
|
9
|
+
* feature manda ter o nosso (base/observador-de-arquivos.md, riscos 1 e 3).
|
|
10
|
+
*
|
|
11
|
+
* O gatilho separado não é preciosismo: a especificação exige que a árvore
|
|
12
|
+
* completa seja "relida apenas quando os arquivos do plano mudam — não a cada
|
|
13
|
+
* redesenho". Com um callback cego, uma linha nova no rastro releria o plano.
|
|
14
|
+
*/
|
|
15
|
+
export type ObservadorFontes = {
|
|
16
|
+
parar: () => Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export type Gatilhos = {
|
|
19
|
+
/** Um arquivo do plano mudou: relê a árvore (caro). */
|
|
20
|
+
aoMudarPlano: () => void;
|
|
21
|
+
/** `.expx/estado.json` mudou: relê só o estado (barato). */
|
|
22
|
+
aoMudarEstado: () => void;
|
|
23
|
+
/** O rastro mudou: relê só os eventos (barato). */
|
|
24
|
+
aoMudarRastro: () => void;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* O debounce é menor que o do painel (150 ms contra 300 ms, decisão D-08):
|
|
28
|
+
* uma tela sob observação humana contínua tolera menos latência que uma aba de
|
|
29
|
+
* navegador ao lado. Continua alto o bastante para não pegar `tasks.md` no
|
|
30
|
+
* meio da gravação, que é o motivo original do debounce do painel.
|
|
31
|
+
*/
|
|
32
|
+
export declare function observarFontes(raizProjeto: string, gatilhos: Gatilhos, debounceMs?: number): Promise<ObservadorFontes>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { watch } from "chokidar";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* O debounce é menor que o do painel (150 ms contra 300 ms, decisão D-08):
|
|
5
|
+
* uma tela sob observação humana contínua tolera menos latência que uma aba de
|
|
6
|
+
* navegador ao lado. Continua alto o bastante para não pegar `tasks.md` no
|
|
7
|
+
* meio da gravação, que é o motivo original do debounce do painel.
|
|
8
|
+
*/
|
|
9
|
+
export async function observarFontes(raizProjeto, gatilhos, debounceMs = 150) {
|
|
10
|
+
const timers = new Map();
|
|
11
|
+
const agendar = (chave, fn) => {
|
|
12
|
+
const anterior = timers.get(chave);
|
|
13
|
+
if (anterior !== undefined)
|
|
14
|
+
clearTimeout(anterior);
|
|
15
|
+
timers.set(chave, setTimeout(() => {
|
|
16
|
+
timers.delete(chave);
|
|
17
|
+
fn();
|
|
18
|
+
}, debounceMs));
|
|
19
|
+
};
|
|
20
|
+
const comum = {
|
|
21
|
+
ignoreInitial: true,
|
|
22
|
+
awaitWriteFinish: {
|
|
23
|
+
stabilityThreshold: Math.max(40, Math.floor(debounceMs / 3)),
|
|
24
|
+
pollInterval: 20,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
const wDocs = watch(join(raizProjeto, "docs"), {
|
|
28
|
+
...comum,
|
|
29
|
+
ignored: (caminho) => /(^|[/\\])(node_modules|\.git|dist)([/\\]|$)/.test(caminho),
|
|
30
|
+
});
|
|
31
|
+
// Observamos a PASTA `.expx`, não o arquivo: a escrita atômica que o
|
|
32
|
+
// contrato exige (temporário + rename) substitui o inode, e um watcher
|
|
33
|
+
// preso ao arquivo antigo pararia de ver mudança depois da primeira.
|
|
34
|
+
const wEstado = watch(join(raizProjeto, ".expx"), {
|
|
35
|
+
...comum,
|
|
36
|
+
depth: 0, // só o topo: o índice do memox vive em .expx/memoria/
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* `ignoreInitial` sozinho NÃO basta quando há `awaitWriteFinish`.
|
|
40
|
+
*
|
|
41
|
+
* Medido: com os dois ligados, a varredura inicial ainda entrega `add` de
|
|
42
|
+
* cada arquivo existente DEPOIS do evento `ready` — o `awaitWriteFinish`
|
|
43
|
+
* segura esses eventos além do ponto em que o `ignoreInitial` os
|
|
44
|
+
* descartaria. O resultado era o watch redesenhar, e reler o plano inteiro,
|
|
45
|
+
* assim que subia, sem ninguém ter tocado em nada.
|
|
46
|
+
*
|
|
47
|
+
* Só ligamos os gatilhos depois que a poeira da subida assenta.
|
|
48
|
+
*/
|
|
49
|
+
let armado = false;
|
|
50
|
+
/**
|
|
51
|
+
* O rastro mora DENTRO de `docs/` (`docs/eventos/<id>.jsonl`), então quem
|
|
52
|
+
* observa `docs/` recebe as duas coisas no mesmo watcher. Separar por
|
|
53
|
+
* caminho é o que faz valer a promessa da especificação: uma linha nova no
|
|
54
|
+
* rastro não pode custar a releitura do plano inteiro.
|
|
55
|
+
*/
|
|
56
|
+
const ehRastro = (caminho) => /[/\\]docs[/\\]eventos[/\\]/.test(caminho) && caminho.endsWith(".jsonl");
|
|
57
|
+
const eventos = ["add", "change", "unlink", "addDir", "unlinkDir"];
|
|
58
|
+
for (const e of eventos) {
|
|
59
|
+
wDocs.on(e, (caminho) => {
|
|
60
|
+
if (!armado)
|
|
61
|
+
return;
|
|
62
|
+
if (ehRastro(caminho))
|
|
63
|
+
agendar("rastro", gatilhos.aoMudarRastro);
|
|
64
|
+
else
|
|
65
|
+
agendar("plano", gatilhos.aoMudarPlano);
|
|
66
|
+
});
|
|
67
|
+
wEstado.on(e, (caminho) => {
|
|
68
|
+
// só o estado.json interessa aqui
|
|
69
|
+
if (armado && caminho.endsWith("estado.json")) {
|
|
70
|
+
agendar("estado", gatilhos.aoMudarEstado);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Erro de observação (permissão, limite de watchers do SO) não derruba o
|
|
75
|
+
// watch: ele continua mostrando o que já leu.
|
|
76
|
+
wDocs.on("error", () => undefined);
|
|
77
|
+
wEstado.on("error", () => undefined);
|
|
78
|
+
await Promise.all([
|
|
79
|
+
new Promise((ok) => wDocs.on("ready", () => ok())),
|
|
80
|
+
new Promise((ok) => wEstado.on("ready", () => ok())),
|
|
81
|
+
]);
|
|
82
|
+
// A janela de silêncio: um pouco mais que o `stabilityThreshold`, que é o
|
|
83
|
+
// que atrasa os eventos da varredura inicial.
|
|
84
|
+
const assentar = comum.awaitWriteFinish.stabilityThreshold + 60;
|
|
85
|
+
await new Promise((ok) => setTimeout(ok, assentar));
|
|
86
|
+
// O que tiver sido agendado durante a subida é descartado: não é mudança.
|
|
87
|
+
for (const t of timers.values())
|
|
88
|
+
clearTimeout(t);
|
|
89
|
+
timers.clear();
|
|
90
|
+
armado = true;
|
|
91
|
+
return {
|
|
92
|
+
parar: async () => {
|
|
93
|
+
armado = false;
|
|
94
|
+
for (const t of timers.values())
|
|
95
|
+
clearTimeout(t);
|
|
96
|
+
timers.clear();
|
|
97
|
+
await Promise.all([wDocs.close(), wEstado.close()]);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=observar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observar.js","sourceRoot":"","sources":["../../../src/watch/fontes/observar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A raiz do projeto: o diretório mais próximo que contém `.git`.
|
|
3
|
+
*
|
|
4
|
+
* O painel resolve isso com `--dir ./docs` e não precisa de mais nada. O watch
|
|
5
|
+
* precisa de `docs/` E `.expx/` ao mesmo tempo, e `.expx/` não é descendente
|
|
6
|
+
* de `docs/` — as duas só fazem sentido a partir da raiz do repositório
|
|
7
|
+
* (decisão D-17).
|
|
8
|
+
*
|
|
9
|
+
* Sem `.git` em nenhum ancestral, devolvemos o diretório recebido: um projeto
|
|
10
|
+
* ainda não versionado continua tendo `docs/` e `.expx/` no lugar certo.
|
|
11
|
+
*/
|
|
12
|
+
export declare function descobrirRaiz(partida?: string): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* A raiz do projeto: o diretório mais próximo que contém `.git`.
|
|
5
|
+
*
|
|
6
|
+
* O painel resolve isso com `--dir ./docs` e não precisa de mais nada. O watch
|
|
7
|
+
* precisa de `docs/` E `.expx/` ao mesmo tempo, e `.expx/` não é descendente
|
|
8
|
+
* de `docs/` — as duas só fazem sentido a partir da raiz do repositório
|
|
9
|
+
* (decisão D-17).
|
|
10
|
+
*
|
|
11
|
+
* Sem `.git` em nenhum ancestral, devolvemos o diretório recebido: um projeto
|
|
12
|
+
* ainda não versionado continua tendo `docs/` e `.expx/` no lugar certo.
|
|
13
|
+
*/
|
|
14
|
+
export function descobrirRaiz(partida = process.cwd()) {
|
|
15
|
+
let atual = resolve(partida);
|
|
16
|
+
for (;;) {
|
|
17
|
+
if (existsSync(join(atual, ".git")))
|
|
18
|
+
return atual;
|
|
19
|
+
const pai = dirname(atual);
|
|
20
|
+
if (pai === atual)
|
|
21
|
+
return resolve(partida); // chegou na raiz do sistema
|
|
22
|
+
atual = pai;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=raiz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raiz.js","sourceRoot":"","sources":["../../../src/watch/fontes/raiz.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB,OAAO,CAAC,GAAG,EAAE;IAC3D,IAAI,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7B,SAAS,CAAC;QACR,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,GAAG,KAAK,KAAK;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B;QACxE,KAAK,GAAG,GAAG,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LinhaEvento } from "../../parser/esquema/evento.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lê as últimas linhas do rastro de um trabalho, da mais recente para a mais
|
|
4
|
+
* antiga.
|
|
5
|
+
*
|
|
6
|
+
* O que o repositório já tinha era `validarRastro`, que conta defeitos e não
|
|
7
|
+
* devolve evento nenhum. O schema `LinhaEvento` e os enums, esses sim, são
|
|
8
|
+
* reaproveitados inteiros: são a fonte única do vocabulário do contrato.
|
|
9
|
+
*
|
|
10
|
+
* Rotação: acima de 5 MB o arquivo corrente vira `<id>.1.jsonl` e um novo
|
|
11
|
+
* começa (contrato `expx-eventos`), e "o painel lê os dois". O `.1` é o mais
|
|
12
|
+
* ANTIGO — inverter isso mostraria o rastro fora de ordem logo após uma
|
|
13
|
+
* rotação, que é justamente quando ninguém está olhando com atenção.
|
|
14
|
+
*/
|
|
15
|
+
/** Quantas linhas o watch exibe por padrão (decisão D-09). */
|
|
16
|
+
export declare const LINHAS_PADRAO = 10;
|
|
17
|
+
export declare function lerRastro(raizProjeto: string, trabalhoId: string, limite?: number): LinhaEvento[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { LinhaEvento } from "../../parser/esquema/evento.js";
|
|
3
|
+
import { lerCauda } from "./cauda.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lê as últimas linhas do rastro de um trabalho, da mais recente para a mais
|
|
6
|
+
* antiga.
|
|
7
|
+
*
|
|
8
|
+
* O que o repositório já tinha era `validarRastro`, que conta defeitos e não
|
|
9
|
+
* devolve evento nenhum. O schema `LinhaEvento` e os enums, esses sim, são
|
|
10
|
+
* reaproveitados inteiros: são a fonte única do vocabulário do contrato.
|
|
11
|
+
*
|
|
12
|
+
* Rotação: acima de 5 MB o arquivo corrente vira `<id>.1.jsonl` e um novo
|
|
13
|
+
* começa (contrato `expx-eventos`), e "o painel lê os dois". O `.1` é o mais
|
|
14
|
+
* ANTIGO — inverter isso mostraria o rastro fora de ordem logo após uma
|
|
15
|
+
* rotação, que é justamente quando ninguém está olhando com atenção.
|
|
16
|
+
*/
|
|
17
|
+
/** Quantas linhas o watch exibe por padrão (decisão D-09). */
|
|
18
|
+
export const LINHAS_PADRAO = 10;
|
|
19
|
+
export function lerRastro(raizProjeto, trabalhoId, limite = LINHAS_PADRAO) {
|
|
20
|
+
const dir = join(raizProjeto, "docs", "eventos");
|
|
21
|
+
// corrente primeiro, rotacionado depois: os dois já vêm em ordem
|
|
22
|
+
// cronológica crescente dentro de cada arquivo.
|
|
23
|
+
const cronologicas = [
|
|
24
|
+
...lerCauda(join(dir, `${trabalhoId}.1.jsonl`)),
|
|
25
|
+
...lerCauda(join(dir, `${trabalhoId}.jsonl`)),
|
|
26
|
+
];
|
|
27
|
+
const validas = [];
|
|
28
|
+
for (const bruta of cronologicas) {
|
|
29
|
+
let obj;
|
|
30
|
+
try {
|
|
31
|
+
obj = JSON.parse(bruta);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
continue; // linha malformada não derruba o resto do rastro
|
|
35
|
+
}
|
|
36
|
+
const r = LinhaEvento.safeParse(obj);
|
|
37
|
+
if (r.success)
|
|
38
|
+
validas.push(r.data);
|
|
39
|
+
}
|
|
40
|
+
// as N mais recentes, já invertidas para exibição
|
|
41
|
+
return validas.slice(-limite).reverse();
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=rastro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rastro.js","sourceRoot":"","sources":["../../../src/watch/fontes/rastro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;;GAYG;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC,MAAM,UAAU,SAAS,CACvB,WAAmB,EACnB,UAAkB,EAClB,SAAiB,aAAa;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAEjD,iEAAiE;IACjE,gDAAgD;IAChD,MAAM,YAAY,GAAG;QACnB,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,UAAU,CAAC,CAAC;QAC/C,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,QAAQ,CAAC,CAAC;KAC9C,CAAC;IAEF,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,IAAI,GAAY,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,iDAAiD;QAC7D,CAAC;QACD,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,kDAAkD;IAClD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrato de linha de comando do `expx watch`.
|
|
3
|
+
*
|
|
4
|
+
* Segue o padrão de `src/cli/argumentos.ts`: interpretar devolve `ok` ou um
|
|
5
|
+
* erro em texto, e nunca lança. A diferença é o argumento posicional, que o
|
|
6
|
+
* painel não tem.
|
|
7
|
+
*/
|
|
8
|
+
export type Opcoes = {
|
|
9
|
+
/** `expx watch <trabalho_id>` — segue um trabalho específico. */
|
|
10
|
+
trabalho: string | undefined;
|
|
11
|
+
/** `--todos` — lista os trabalhos abertos, um por linha, sem a árvore. */
|
|
12
|
+
todos: boolean;
|
|
13
|
+
ajuda: boolean;
|
|
14
|
+
/** Largura fixa, para teste e para quem quer saída estável. */
|
|
15
|
+
colunas: number | undefined;
|
|
16
|
+
};
|
|
17
|
+
export type Resultado = {
|
|
18
|
+
ok: true;
|
|
19
|
+
opcoes: Opcoes;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
erro: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function ajudaWatch(): string;
|
|
25
|
+
export declare function interpretarOpcoes(argv: readonly string[]): Resultado;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrato de linha de comando do `expx watch`.
|
|
3
|
+
*
|
|
4
|
+
* Segue o padrão de `src/cli/argumentos.ts`: interpretar devolve `ok` ou um
|
|
5
|
+
* erro em texto, e nunca lança. A diferença é o argumento posicional, que o
|
|
6
|
+
* painel não tem.
|
|
7
|
+
*/
|
|
8
|
+
const AJUDA = `
|
|
9
|
+
expx watch — acompanha um trabalho no terminal, ao vivo (somente leitura)
|
|
10
|
+
|
|
11
|
+
expx watch segue o trabalho atual, lido do .expx/estado.json
|
|
12
|
+
expx watch <trabalho_id> segue um trabalho especifico
|
|
13
|
+
expx watch --todos lista os trabalhos abertos, um por linha, sem arvore
|
|
14
|
+
|
|
15
|
+
--colunas <n> largura fixa, em vez da largura do terminal
|
|
16
|
+
--ajuda mostra esta ajuda
|
|
17
|
+
|
|
18
|
+
Sai com Ctrl+C, devolvendo o terminal ao estado anterior.
|
|
19
|
+
O watch nunca escreve nos arquivos do projeto.
|
|
20
|
+
`.trim();
|
|
21
|
+
export function ajudaWatch() {
|
|
22
|
+
return AJUDA;
|
|
23
|
+
}
|
|
24
|
+
export function interpretarOpcoes(argv) {
|
|
25
|
+
const opcoes = {
|
|
26
|
+
trabalho: undefined,
|
|
27
|
+
todos: false,
|
|
28
|
+
ajuda: false,
|
|
29
|
+
colunas: undefined,
|
|
30
|
+
};
|
|
31
|
+
const posicionais = [];
|
|
32
|
+
for (let i = 0; i < argv.length; i++) {
|
|
33
|
+
const bruto = argv[i] ?? "";
|
|
34
|
+
const [nome, embutido] = bruto.includes("=")
|
|
35
|
+
? [bruto.slice(0, bruto.indexOf("=")), bruto.slice(bruto.indexOf("=") + 1)]
|
|
36
|
+
: [bruto, undefined];
|
|
37
|
+
switch (nome) {
|
|
38
|
+
case "--todos":
|
|
39
|
+
opcoes.todos = true;
|
|
40
|
+
break;
|
|
41
|
+
case "--colunas": {
|
|
42
|
+
const v = embutido ?? argv[++i];
|
|
43
|
+
const n = Number(v);
|
|
44
|
+
if (v === undefined || !Number.isInteger(n) || n <= 0) {
|
|
45
|
+
return { ok: false, erro: `--colunas exige um numero inteiro positivo` };
|
|
46
|
+
}
|
|
47
|
+
opcoes.colunas = n;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "--ajuda":
|
|
51
|
+
case "--help":
|
|
52
|
+
case "-h":
|
|
53
|
+
opcoes.ajuda = true;
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
if (nome.startsWith("-")) {
|
|
57
|
+
return { ok: false, erro: `opcao desconhecida: ${nome}` };
|
|
58
|
+
}
|
|
59
|
+
posicionais.push(nome);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Dois trabalhos é engano, e o último vencendo em silêncio esconderia o
|
|
63
|
+
// engano até a pessoa reparar que está olhando o trabalho errado.
|
|
64
|
+
if (posicionais.length > 1) {
|
|
65
|
+
return { ok: false, erro: `informe um trabalho por vez: ${posicionais.join(", ")}` };
|
|
66
|
+
}
|
|
67
|
+
opcoes.trabalho = posicionais[0];
|
|
68
|
+
if (opcoes.trabalho !== undefined && opcoes.todos) {
|
|
69
|
+
return { ok: false, erro: "--todos lista todos os trabalhos: nao combine com um trabalho nomeado" };
|
|
70
|
+
}
|
|
71
|
+
return { ok: true, opcoes };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=opcoes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opcoes.js","sourceRoot":"","sources":["../../src/watch/opcoes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,MAAM,KAAK,GAAG;;;;;;;;;;;;CAYb,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,UAAU,UAAU;IACxB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAuB;IACvD,MAAM,MAAM,GAAW;QACrB,QAAQ,EAAE,SAAS;QACnB,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,SAAS;KACnB,CAAC;IAEF,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC1C,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3E,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAEvB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,SAAS;gBACZ,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,CAAC,GAAG,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACpB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,4CAA4C,EAAE,CAAC;gBAC3E,CAAC;gBACD,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;gBACnB,MAAM;YACR,CAAC;YACD,KAAK,SAAS,CAAC;YACf,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR;gBACE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAuB,IAAI,EAAE,EAAE,CAAC;gBAC5D,CAAC;gBACD,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,kEAAkE;IAClE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,gCAAgC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IACvF,CAAC;IACD,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,uEAAuE,EAAE,CAAC;IACtG,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O `expx watch` como comando: junta opções, terminal e loop.
|
|
3
|
+
*
|
|
4
|
+
* Segue o padrão de saída injetável de `src/cli/expx.ts` — capturar
|
|
5
|
+
* `process.stdout` global vaza entre testes paralelos e produz falha
|
|
6
|
+
* intermitente, e a alternativa adotada pelo projeto é receber a saída.
|
|
7
|
+
*/
|
|
8
|
+
export type SaidaWatch = {
|
|
9
|
+
escrever: (texto: string) => void;
|
|
10
|
+
escreverErro: (texto: string) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare function principalWatch(argv: readonly string[], saida: SaidaWatch, raizPedida?: string): Promise<number>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { descobrirRaiz } from "./fontes/raiz.js";
|
|
2
|
+
import { ajudaWatch, interpretarOpcoes } from "./opcoes.js";
|
|
3
|
+
import { criarRestaurador } from "./terminal/restaurar.js";
|
|
4
|
+
import { corAtiva, ambienteAtual } from "./desenho/cor.js";
|
|
5
|
+
import { executarWatch } from "./watch.js";
|
|
6
|
+
export async function principalWatch(argv, saida, raizPedida) {
|
|
7
|
+
const r = interpretarOpcoes(argv);
|
|
8
|
+
if (!r.ok) {
|
|
9
|
+
saida.escreverErro(`${r.erro}\n\n${ajudaWatch()}\n`);
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
if (r.opcoes.ajuda) {
|
|
13
|
+
saida.escrever(`${ajudaWatch()}\n`);
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
const raiz = raizPedida ?? descobrirRaiz();
|
|
17
|
+
// A cor sai por `stdout.isTTY` SOZINHO — em `expx watch | less` o stdin
|
|
18
|
+
// continua TTY, e usar o `ehInterativo()` do CLI sujaria o arquivo.
|
|
19
|
+
const amb = ambienteAtual();
|
|
20
|
+
const cor = corAtiva(amb);
|
|
21
|
+
// Controle de cursor é coisa de terminal, e é governado por `isTTY`, não
|
|
22
|
+
// por cor: com `NO_COLOR` num terminal de verdade o cursor ainda precisa
|
|
23
|
+
// ser escondido e restaurado. Com a saída redirecionada, nenhum escape pode
|
|
24
|
+
// sair — nem esse, que foi o único a vazar para o arquivo na primeira
|
|
25
|
+
// versão.
|
|
26
|
+
const restaurador = criarRestaurador({
|
|
27
|
+
escrever: amb.tty ? saida.escrever : () => undefined,
|
|
28
|
+
sair: (codigo) => {
|
|
29
|
+
process.exit(codigo);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const sessao = await executarWatch({
|
|
33
|
+
raiz,
|
|
34
|
+
opcoes: r.opcoes,
|
|
35
|
+
escrever: saida.escrever,
|
|
36
|
+
cor,
|
|
37
|
+
});
|
|
38
|
+
// Projeto sem `.expx/`: a mensagem já foi escrita e não há o que observar.
|
|
39
|
+
if (sessao.encerrou)
|
|
40
|
+
return sessao.codigo;
|
|
41
|
+
// Só escondemos o cursor depois de saber que o watch vai mesmo rodar, e a
|
|
42
|
+
// restauração cobre os quatro caminhos de saída (decisão D-21).
|
|
43
|
+
restaurador.registrar();
|
|
44
|
+
if (amb.tty)
|
|
45
|
+
restaurador.esconderCursor();
|
|
46
|
+
// O chokidar segura o event loop: o processo fica vivo até o sinal chegar.
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=principal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../../src/watch/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAe3C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAuB,EACvB,KAAiB,EACjB,UAAmB;IAEnB,MAAM,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACV,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,UAAU,EAAE,IAAI,CAAC,CAAC;QACrD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,IAAI,aAAa,EAAE,CAAC;IAE3C,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAE1B,yEAAyE;IACzE,yEAAyE;IACzE,4EAA4E;IAC5E,sEAAsE;IACtE,UAAU;IACV,MAAM,WAAW,GAAG,gBAAgB,CAAC;QACnC,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS;QACpD,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE;YACf,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;QACjC,IAAI;QACJ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG;KACJ,CAAC,CAAC;IAEH,2EAA2E;IAC3E,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAE1C,0EAA0E;IAC1E,gEAAgE;IAChE,WAAW,CAAC,SAAS,EAAE,CAAC;IACxB,IAAI,GAAG,CAAC,GAAG;QAAE,WAAW,CAAC,cAAc,EAAE,CAAC;IAE1C,2EAA2E;IAC3E,OAAO,CAAC,CAAC;AACX,CAAC"}
|