expxdev 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/cli/argumentos.d.ts +22 -0
  4. package/dist/cli/argumentos.js +85 -0
  5. package/dist/cli/argumentos.js.map +1 -0
  6. package/dist/cli/expx-bin.d.ts +2 -0
  7. package/dist/cli/expx-bin.js +40 -0
  8. package/dist/cli/expx-bin.js.map +1 -0
  9. package/dist/cli/expx.d.ts +13 -0
  10. package/dist/cli/expx.js +123 -0
  11. package/dist/cli/expx.js.map +1 -0
  12. package/dist/cli/init-flags.d.ts +34 -0
  13. package/dist/cli/init-flags.js +83 -0
  14. package/dist/cli/init-flags.js.map +1 -0
  15. package/dist/cli/init.d.ts +34 -0
  16. package/dist/cli/init.js +103 -0
  17. package/dist/cli/init.js.map +1 -0
  18. package/dist/cli/principal.d.ts +2 -0
  19. package/dist/cli/principal.js +107 -0
  20. package/dist/cli/principal.js.map +1 -0
  21. package/dist/cli/projeto.d.ts +19 -0
  22. package/dist/cli/projeto.js +28 -0
  23. package/dist/cli/projeto.js.map +1 -0
  24. package/dist/cli/selecao.d.ts +19 -0
  25. package/dist/cli/selecao.js +28 -0
  26. package/dist/cli/selecao.js.map +1 -0
  27. package/dist/cli/selecionar.d.ts +23 -0
  28. package/dist/cli/selecionar.js +45 -0
  29. package/dist/cli/selecionar.js.map +1 -0
  30. package/dist/cli/subcomandos.d.ts +25 -0
  31. package/dist/cli/subcomandos.js +43 -0
  32. package/dist/cli/subcomandos.js.map +1 -0
  33. package/dist/doctor/efeito.d.ts +17 -0
  34. package/dist/doctor/efeito.js +18 -0
  35. package/dist/doctor/efeito.js.map +1 -0
  36. package/dist/doctor/verificadores.d.ts +21 -0
  37. package/dist/doctor/verificadores.js +158 -0
  38. package/dist/doctor/verificadores.js.map +1 -0
  39. package/dist/harness/backup.d.ts +15 -0
  40. package/dist/harness/backup.js +29 -0
  41. package/dist/harness/backup.js.map +1 -0
  42. package/dist/harness/instalar.d.ts +31 -0
  43. package/dist/harness/instalar.js +43 -0
  44. package/dist/harness/instalar.js.map +1 -0
  45. package/dist/harness/opencode.d.ts +18 -0
  46. package/dist/harness/opencode.js +32 -0
  47. package/dist/harness/opencode.js.map +1 -0
  48. package/dist/harness/settings.d.ts +36 -0
  49. package/dist/harness/settings.js +66 -0
  50. package/dist/harness/settings.js.map +1 -0
  51. package/dist/index.d.ts +8 -0
  52. package/dist/index.js +9 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/nucleo/busca.d.ts +28 -0
  55. package/dist/nucleo/busca.js +29 -0
  56. package/dist/nucleo/busca.js.map +1 -0
  57. package/dist/nucleo/caminhos.d.ts +21 -0
  58. package/dist/nucleo/caminhos.js +64 -0
  59. package/dist/nucleo/caminhos.js.map +1 -0
  60. package/dist/nucleo/catalogo.d.ts +20 -0
  61. package/dist/nucleo/catalogo.js +50 -0
  62. package/dist/nucleo/catalogo.js.map +1 -0
  63. package/dist/nucleo/integridade.d.ts +20 -0
  64. package/dist/nucleo/integridade.js +75 -0
  65. package/dist/nucleo/integridade.js.map +1 -0
  66. package/dist/nucleo/layout.d.ts +23 -0
  67. package/dist/nucleo/layout.js +73 -0
  68. package/dist/nucleo/layout.js.map +1 -0
  69. package/dist/nucleo/lock.d.ts +61 -0
  70. package/dist/nucleo/lock.js +96 -0
  71. package/dist/nucleo/lock.js.map +1 -0
  72. package/dist/nucleo/versao.d.ts +35 -0
  73. package/dist/nucleo/versao.js +63 -0
  74. package/dist/nucleo/versao.js.map +1 -0
  75. package/dist/parser/conformidade/regras.d.ts +41 -0
  76. package/dist/parser/conformidade/regras.js +209 -0
  77. package/dist/parser/conformidade/regras.js.map +1 -0
  78. package/dist/parser/descoberta/trabalhos.d.ts +35 -0
  79. package/dist/parser/descoberta/trabalhos.js +28 -0
  80. package/dist/parser/descoberta/trabalhos.js.map +1 -0
  81. package/dist/parser/descoberta/varredura.d.ts +4 -0
  82. package/dist/parser/descoberta/varredura.js +79 -0
  83. package/dist/parser/descoberta/varredura.js.map +1 -0
  84. package/dist/parser/esquema/cabecalho.d.ts +60 -0
  85. package/dist/parser/esquema/cabecalho.js +57 -0
  86. package/dist/parser/esquema/cabecalho.js.map +1 -0
  87. package/dist/parser/esquema/enums.d.ts +114 -0
  88. package/dist/parser/esquema/enums.js +64 -0
  89. package/dist/parser/esquema/enums.js.map +1 -0
  90. package/dist/parser/esquema/kinds.d.ts +768 -0
  91. package/dist/parser/esquema/kinds.js +231 -0
  92. package/dist/parser/esquema/kinds.js.map +1 -0
  93. package/dist/parser/leitura/arquivo.d.ts +9 -0
  94. package/dist/parser/leitura/arquivo.js +25 -0
  95. package/dist/parser/leitura/arquivo.js.map +1 -0
  96. package/dist/parser/leitura/frontmatter.d.ts +31 -0
  97. package/dist/parser/leitura/frontmatter.js +77 -0
  98. package/dist/parser/leitura/frontmatter.js.map +1 -0
  99. package/dist/parser/leitura/rejeicao.d.ts +43 -0
  100. package/dist/parser/leitura/rejeicao.js +73 -0
  101. package/dist/parser/leitura/rejeicao.js.map +1 -0
  102. package/dist/parser/projeto/montar.d.ts +62 -0
  103. package/dist/parser/projeto/montar.js +149 -0
  104. package/dist/parser/projeto/montar.js.map +1 -0
  105. package/dist/plugin/atomico.d.ts +13 -0
  106. package/dist/plugin/atomico.js +42 -0
  107. package/dist/plugin/atomico.js.map +1 -0
  108. package/dist/plugin/manifestos.d.ts +38 -0
  109. package/dist/plugin/manifestos.js +57 -0
  110. package/dist/plugin/manifestos.js.map +1 -0
  111. package/dist/plugin/montagem.d.ts +22 -0
  112. package/dist/plugin/montagem.js +30 -0
  113. package/dist/plugin/montagem.js.map +1 -0
  114. package/dist/relatorio/markdown.d.ts +22 -0
  115. package/dist/relatorio/markdown.js +0 -0
  116. package/dist/relatorio/markdown.js.map +1 -0
  117. package/dist/relatorio/pagina.d.ts +22 -0
  118. package/dist/relatorio/pagina.js +338 -0
  119. package/dist/relatorio/pagina.js.map +1 -0
  120. package/dist/servidor/estado.d.ts +16 -0
  121. package/dist/servidor/estado.js +16 -0
  122. package/dist/servidor/estado.js.map +1 -0
  123. package/dist/servidor/http.d.ts +22 -0
  124. package/dist/servidor/http.js +164 -0
  125. package/dist/servidor/http.js.map +1 -0
  126. package/dist/servidor/observador.d.ts +12 -0
  127. package/dist/servidor/observador.js +37 -0
  128. package/dist/servidor/observador.js.map +1 -0
  129. package/dist/servidor/painel.d.ts +24 -0
  130. package/dist/servidor/painel.js +49 -0
  131. package/dist/servidor/painel.js.map +1 -0
  132. package/dist/teste/layouts-fixture.d.ts +16 -0
  133. package/dist/teste/layouts-fixture.js +9 -0
  134. package/dist/teste/layouts-fixture.js.map +1 -0
  135. package/dist/teste/projeto-temporario.d.ts +14 -0
  136. package/dist/teste/projeto-temporario.js +16 -0
  137. package/dist/teste/projeto-temporario.js.map +1 -0
  138. package/dist/teste/repo-fixture.d.ts +27 -0
  139. package/dist/teste/repo-fixture.js +49 -0
  140. package/dist/teste/repo-fixture.js.map +1 -0
  141. package/dist/update/comparar.d.ts +33 -0
  142. package/dist/update/comparar.js +67 -0
  143. package/dist/update/comparar.js.map +1 -0
  144. package/dist/update/compatibilidade.d.ts +19 -0
  145. package/dist/update/compatibilidade.js +36 -0
  146. package/dist/update/compatibilidade.js.map +1 -0
  147. package/dist/update/flags.d.ts +47 -0
  148. package/dist/update/flags.js +123 -0
  149. package/dist/update/flags.js.map +1 -0
  150. package/dist/update/modificacao.d.ts +23 -0
  151. package/dist/update/modificacao.js +36 -0
  152. package/dist/update/modificacao.js.map +1 -0
  153. package/package.json +73 -0
  154. package/ui/dist/assets/index-BmDTogQZ.js +14 -0
  155. package/ui/dist/assets/index-DUzbt2M7.css +1 -0
  156. package/ui/dist/index.html +13 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * As cinco skills do ecossistema Expx.
3
+ *
4
+ * Fonte única do que o CLI sabe instalar. `papel` é o texto mostrado na seleção
5
+ * do `init`; `camada` marca as skills que, sozinhas, não fazem nada — elas
6
+ * modificam o comportamento da sprintx/runx em vez de agir por conta própria
7
+ * (ver `docs/expx-cli/base/08-repositorios-reais.md`).
8
+ */
9
+ export type Skill = {
10
+ nome: string;
11
+ repositorio: string;
12
+ papel: string;
13
+ camada: boolean;
14
+ };
15
+ export declare const CATALOGO: readonly Skill[];
16
+ /** Os nomes na ordem em que a seleção do `init` os apresenta. */
17
+ export declare const NOMES: readonly string[];
18
+ export declare function buscarNoCatalogo(nome: string): Skill | undefined;
19
+ /** Camada é skill que sozinha não faz nada: precisa de sprintx ou runx junto. */
20
+ export declare function ehCamada(nome: string): boolean;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * As cinco skills do ecossistema Expx.
3
+ *
4
+ * Fonte única do que o CLI sabe instalar. `papel` é o texto mostrado na seleção
5
+ * do `init`; `camada` marca as skills que, sozinhas, não fazem nada — elas
6
+ * modificam o comportamento da sprintx/runx em vez de agir por conta própria
7
+ * (ver `docs/expx-cli/base/08-repositorios-reais.md`).
8
+ */
9
+ export const CATALOGO = [
10
+ {
11
+ nome: "sprintx",
12
+ repositorio: "https://github.com/bittencourtthulio/sprintx",
13
+ papel: "planeja e executa features novas",
14
+ camada: false,
15
+ },
16
+ {
17
+ nome: "runx",
18
+ repositorio: "https://github.com/bittencourtthulio/runx",
19
+ papel: "ocorrencias de manutencao do dia a dia",
20
+ camada: false,
21
+ },
22
+ {
23
+ nome: "legadox",
24
+ repositorio: "https://github.com/bittencourtthulio/legadox",
25
+ papel: "camada para projetos legados",
26
+ camada: true,
27
+ },
28
+ {
29
+ nome: "stackx",
30
+ repositorio: "https://github.com/bittencourtthulio/stackx",
31
+ papel: "descobre o dialeto tecnico do repositorio",
32
+ camada: true,
33
+ },
34
+ {
35
+ nome: "mergex",
36
+ repositorio: "https://github.com/bittencourtthulio/mergex",
37
+ papel: "versionamento, entrega e revisao de pull requests",
38
+ camada: false,
39
+ },
40
+ ];
41
+ /** Os nomes na ordem em que a seleção do `init` os apresenta. */
42
+ export const NOMES = CATALOGO.map((s) => s.nome);
43
+ export function buscarNoCatalogo(nome) {
44
+ return CATALOGO.find((s) => s.nome === nome);
45
+ }
46
+ /** Camada é skill que sozinha não faz nada: precisa de sprintx ou runx junto. */
47
+ export function ehCamada(nome) {
48
+ return buscarNoCatalogo(nome)?.camada ?? false;
49
+ }
50
+ //# sourceMappingURL=catalogo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogo.js","sourceRoot":"","sources":["../../src/nucleo/catalogo.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,MAAM,CAAC,MAAM,QAAQ,GAAqB;IACxC;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,8CAA8C;QAC3D,KAAK,EAAE,kCAAkC;QACzC,MAAM,EAAE,KAAK;KACd;IACD;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,2CAA2C;QACxD,KAAK,EAAE,wCAAwC;QAC/C,MAAM,EAAE,KAAK;KACd;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,8CAA8C;QAC3D,KAAK,EAAE,8BAA8B;QACrC,MAAM,EAAE,IAAI;KACb;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,6CAA6C;QAC1D,KAAK,EAAE,2CAA2C;QAClD,MAAM,EAAE,IAAI;KACb;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,6CAA6C;QAC1D,KAAK,EAAE,mDAAmD;QAC1D,MAAM,EAAE,KAAK;KACd;CACO,CAAC;AAEX,iEAAiE;AACjE,MAAM,CAAC,MAAM,KAAK,GAAsB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAEpE,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,KAAK,CAAC;AACjD,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Detecção de modificação local.
3
+ *
4
+ * Quem ajustou uma skill à mão não pode perder o trabalho por rodar um comando
5
+ * de rotina. Por isso o lock guarda o hash de CADA arquivo, e não um hash único
6
+ * da árvore: só assim o `update` consegue LISTAR quais arquivos mudaram, que é
7
+ * o que a decisão exige para oferecer manter, substituir ou salvar ao lado.
8
+ */
9
+ export type Hashes = Record<string, string>;
10
+ export type Divergencia = {
11
+ limpo: boolean;
12
+ alterados: string[];
13
+ removidos: string[];
14
+ novos: string[];
15
+ };
16
+ export declare function hashDoArquivo(caminho: string): string;
17
+ /** O hash de cada arquivo da pasta, indexado pelo caminho relativo. */
18
+ export declare function hashearPasta(raiz: string): Hashes;
19
+ /** Compara o disco com os hashes do lock. `limpo: true` = nada mudou. */
20
+ export declare function compararComHashes(raiz: string, esperados: Hashes): Divergencia;
@@ -0,0 +1,75 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { join, relative, sep } from "node:path";
4
+ const IGNORADAS = new Set([".git", "node_modules"]);
5
+ function arquivosDe(raiz) {
6
+ const saida = [];
7
+ const fila = [raiz];
8
+ while (fila.length > 0) {
9
+ const dir = fila.shift();
10
+ if (dir === undefined)
11
+ break;
12
+ let entradas;
13
+ try {
14
+ entradas = readdirSync(dir);
15
+ }
16
+ catch {
17
+ continue;
18
+ }
19
+ for (const e of entradas) {
20
+ if (IGNORADAS.has(e))
21
+ continue;
22
+ const p = join(dir, e);
23
+ try {
24
+ if (statSync(p).isDirectory())
25
+ fila.push(p);
26
+ else
27
+ saida.push(p);
28
+ }
29
+ catch {
30
+ // entrada sumiu entre o readdir e o stat: ignora
31
+ }
32
+ }
33
+ }
34
+ return saida.sort();
35
+ }
36
+ /** Caminho relativo com separador normalizado, para o lock não depender do SO. */
37
+ function chave(raiz, arquivo) {
38
+ return relative(raiz, arquivo).split(sep).join("/");
39
+ }
40
+ export function hashDoArquivo(caminho) {
41
+ return createHash("sha256").update(readFileSync(caminho)).digest("hex");
42
+ }
43
+ /** O hash de cada arquivo da pasta, indexado pelo caminho relativo. */
44
+ export function hashearPasta(raiz) {
45
+ const saida = {};
46
+ for (const a of arquivosDe(raiz))
47
+ saida[chave(raiz, a)] = hashDoArquivo(a);
48
+ return saida;
49
+ }
50
+ /** Compara o disco com os hashes do lock. `limpo: true` = nada mudou. */
51
+ export function compararComHashes(raiz, esperados) {
52
+ const atuais = hashearPasta(raiz);
53
+ const alterados = [];
54
+ const removidos = [];
55
+ const novos = [];
56
+ for (const [rel, hash] of Object.entries(esperados)) {
57
+ const atual = atuais[rel];
58
+ if (atual === undefined)
59
+ removidos.push(rel);
60
+ else if (atual !== hash)
61
+ alterados.push(rel);
62
+ }
63
+ for (const rel of Object.keys(atuais)) {
64
+ if (esperados[rel] === undefined)
65
+ novos.push(rel);
66
+ }
67
+ const norm = (l) => l.map((x) => x.split("/").join(sep)).sort();
68
+ return {
69
+ limpo: alterados.length === 0 && removidos.length === 0 && novos.length === 0,
70
+ alterados: norm(alterados),
71
+ removidos: norm(removidos),
72
+ novos: norm(novos),
73
+ };
74
+ }
75
+ //# sourceMappingURL=integridade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integridade.js","sourceRoot":"","sources":["../../src/nucleo/integridade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Normaliza os layouts de repositório de skill.
3
+ *
4
+ * Os cinco repositórios reais têm DOIS layouts distintos
5
+ * (`base/08-repositorios-reais.md`):
6
+ *
7
+ * embutido — `.claude/skills/<nome>/` + `.claude/commands/` (sprintx, stackx, mergex)
8
+ * plano — `skill/` + `commands/` (runx, legadox)
9
+ *
10
+ * Por isso a detecção NÃO assume caminho fixo: procura o `SKILL.md` e toma o
11
+ * diretório que o contém como raiz da skill. Um layout novo passa a funcionar
12
+ * sem alterar esta camada, desde que o `SKILL.md` exista em algum lugar.
13
+ */
14
+ export type Layout = {
15
+ ok: true;
16
+ nome: string;
17
+ raizSkill: string;
18
+ comandos: string[];
19
+ } | {
20
+ ok: false;
21
+ erro: string;
22
+ };
23
+ export declare function detectarLayout(raizRepo: string, nomeEsperado: string): Layout;
@@ -0,0 +1,73 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
+ const IGNORADAS = new Set([".git", "node_modules", ".github", "dist"]);
4
+ const CANDIDATAS_COMANDOS = [join(".claude", "commands"), "commands", join(".opencode", "commands"), join(".opencode", "command")];
5
+ /** Procura o SKILL.md mais raso, ignorando pastas de infraestrutura. */
6
+ function acharSkillMd(raiz, profundidadeMax = 5) {
7
+ const fila = [{ dir: raiz, nivel: 0 }];
8
+ while (fila.length > 0) {
9
+ const atual = fila.shift();
10
+ if (atual === undefined)
11
+ break;
12
+ if (atual.nivel > profundidadeMax)
13
+ continue;
14
+ let entradas;
15
+ try {
16
+ entradas = readdirSync(atual.dir);
17
+ }
18
+ catch {
19
+ continue;
20
+ }
21
+ if (entradas.includes("SKILL.md"))
22
+ return join(atual.dir, "SKILL.md");
23
+ for (const e of entradas) {
24
+ if (IGNORADAS.has(e))
25
+ continue;
26
+ const p = join(atual.dir, e);
27
+ try {
28
+ if (statSync(p).isDirectory())
29
+ fila.push({ dir: p, nivel: atual.nivel + 1 });
30
+ }
31
+ catch {
32
+ // entrada sumiu entre o readdir e o stat: ignora
33
+ }
34
+ }
35
+ }
36
+ return undefined;
37
+ }
38
+ /** O `name:` do frontmatter, que no OpenCode precisa bater com o nome da pasta. */
39
+ function nomeDoFrontmatter(skillMd) {
40
+ const bruto = readFileSync(skillMd, "utf8");
41
+ const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(bruto);
42
+ if (m === null)
43
+ return undefined;
44
+ const linha = /^name:\s*(.+)$/m.exec(m[1] ?? "");
45
+ return linha?.[1]?.trim().replace(/^["']|["']$/g, "");
46
+ }
47
+ /** Os arquivos de comando da skill, no primeiro diretório candidato que existir. */
48
+ function acharComandos(raiz, nome) {
49
+ for (const c of CANDIDATAS_COMANDOS) {
50
+ const dir = join(raiz, c);
51
+ if (!existsSync(dir))
52
+ continue;
53
+ const arquivos = readdirSync(dir)
54
+ .filter((a) => a.endsWith(".md"))
55
+ .filter((a) => a === `${nome}.md` || a.startsWith(`${nome}-`))
56
+ .map((a) => join(dir, a));
57
+ if (arquivos.length > 0)
58
+ return arquivos;
59
+ }
60
+ return [];
61
+ }
62
+ export function detectarLayout(raizRepo, nomeEsperado) {
63
+ const skillMd = acharSkillMd(raizRepo);
64
+ if (skillMd === undefined)
65
+ return { ok: false, erro: `SKILL.md nao encontrado em ${raizRepo}` };
66
+ const raizSkill = join(skillMd, "..");
67
+ const nome = nomeDoFrontmatter(skillMd) ?? basename(raizSkill);
68
+ if (nome !== nomeEsperado) {
69
+ return { ok: false, erro: `nome da skill e "${nome}", esperado "${nomeEsperado}"` };
70
+ }
71
+ return { ok: true, nome, raizSkill, comandos: acharComandos(raizRepo, nome) };
72
+ }
73
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/nucleo/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * O lock: o que está instalado, e em que versão exata.
4
+ *
5
+ * É commitado junto com `.expx/`. Quem clona o projeto recebe as skills já em
6
+ * disco e não precisa de rede nem de rodar o `init` para trabalhar — a
7
+ * instalação é travada por este arquivo, e só o `update` o reescreve.
8
+ *
9
+ * `arquivos` guarda o hash de cada arquivo instalado: é o que permite detectar
10
+ * modificação local e recusar sobrescrever trabalho manual (ver `integridade.ts`).
11
+ */
12
+ export declare const VERSAO_LOCK = 1;
13
+ export declare const SkillTravada: z.ZodObject<{
14
+ repositorio: z.ZodString;
15
+ referencia: z.ZodString;
16
+ travado: z.ZodBoolean;
17
+ commit: z.ZodString;
18
+ resolvido_em: z.ZodString;
19
+ arquivos: z.ZodRecord<z.ZodString, z.ZodString>;
20
+ }, z.core.$strip>;
21
+ export type SkillTravada = z.infer<typeof SkillTravada>;
22
+ export declare const Lock: z.ZodObject<{
23
+ lock_version: z.ZodNumber;
24
+ cli_version: z.ZodString;
25
+ harness: z.ZodArray<z.ZodString>;
26
+ skills: z.ZodRecord<z.ZodString, z.ZodObject<{
27
+ repositorio: z.ZodString;
28
+ referencia: z.ZodString;
29
+ travado: z.ZodBoolean;
30
+ commit: z.ZodString;
31
+ resolvido_em: z.ZodString;
32
+ arquivos: z.ZodRecord<z.ZodString, z.ZodString>;
33
+ }, z.core.$strip>>;
34
+ }, z.core.$strip>;
35
+ export type Lock = z.infer<typeof Lock>;
36
+ export type LeituraLock = {
37
+ ok: true;
38
+ lock: Lock;
39
+ incompativel: boolean;
40
+ } | {
41
+ ok: false;
42
+ erro: string;
43
+ };
44
+ export declare function caminhoDoLock(raizProjeto: string): string;
45
+ export declare function escreverLock(raizProjeto: string, lock: Lock): void;
46
+ /**
47
+ * Compara duas versões `x.y.z`. Devolve >0 se `a` é maior.
48
+ *
49
+ * Usado para detectar estrutura criada por CLI MAIS NOVO que o em execução —
50
+ * caso em que o método manda parar com mensagem clara, nunca adivinhar.
51
+ */
52
+ export declare function compararVersoes(a: string, b: string): number;
53
+ /**
54
+ * A versão deste CLI, lida do package.json do próprio pacote.
55
+ *
56
+ * Fixar a versão em literal faria o lock "do futuro" ser detectado errado a
57
+ * cada publicação — o valor tem que vir da mesma fonte que o npm publica.
58
+ */
59
+ export declare function versaoDoCli(): string;
60
+ /** Lê o lock. Ausente ou inválido devolve `ok: false` — nunca lança. */
61
+ export declare function lerLock(raizProjeto: string, versaoCliAtual?: string): LeituraLock;
@@ -0,0 +1,96 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { z } from "zod";
5
+ /**
6
+ * O lock: o que está instalado, e em que versão exata.
7
+ *
8
+ * É commitado junto com `.expx/`. Quem clona o projeto recebe as skills já em
9
+ * disco e não precisa de rede nem de rodar o `init` para trabalhar — a
10
+ * instalação é travada por este arquivo, e só o `update` o reescreve.
11
+ *
12
+ * `arquivos` guarda o hash de cada arquivo instalado: é o que permite detectar
13
+ * modificação local e recusar sobrescrever trabalho manual (ver `integridade.ts`).
14
+ */
15
+ export const VERSAO_LOCK = 1;
16
+ export const SkillTravada = z.object({
17
+ repositorio: z.string().min(1),
18
+ referencia: z.string().min(1),
19
+ /** `false` quando a referência é branch: a skill não está em versão publicada. */
20
+ travado: z.boolean(),
21
+ commit: z.string().min(1),
22
+ resolvido_em: z.string().min(1),
23
+ arquivos: z.record(z.string(), z.string()),
24
+ });
25
+ export const Lock = z.object({
26
+ lock_version: z.number().int(),
27
+ cli_version: z.string().min(1),
28
+ harness: z.array(z.string()),
29
+ skills: z.record(z.string(), SkillTravada),
30
+ });
31
+ export function caminhoDoLock(raizProjeto) {
32
+ return join(raizProjeto, ".expx", "expx-lock.json");
33
+ }
34
+ export function escreverLock(raizProjeto, lock) {
35
+ const destino = caminhoDoLock(raizProjeto);
36
+ mkdirSync(join(destino, ".."), { recursive: true });
37
+ writeFileSync(destino, `${JSON.stringify(lock, null, 2)}\n`);
38
+ }
39
+ /**
40
+ * Compara duas versões `x.y.z`. Devolve >0 se `a` é maior.
41
+ *
42
+ * Usado para detectar estrutura criada por CLI MAIS NOVO que o em execução —
43
+ * caso em que o método manda parar com mensagem clara, nunca adivinhar.
44
+ */
45
+ export function compararVersoes(a, b) {
46
+ const pa = a.split(".").map((n) => Number(n) || 0);
47
+ const pb = b.split(".").map((n) => Number(n) || 0);
48
+ for (let i = 0; i < 3; i++) {
49
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
50
+ if (d !== 0)
51
+ return d;
52
+ }
53
+ return 0;
54
+ }
55
+ /**
56
+ * A versão deste CLI, lida do package.json do próprio pacote.
57
+ *
58
+ * Fixar a versão em literal faria o lock "do futuro" ser detectado errado a
59
+ * cada publicação — o valor tem que vir da mesma fonte que o npm publica.
60
+ */
61
+ export function versaoDoCli() {
62
+ for (const rel of ["../../package.json", "../package.json"]) {
63
+ try {
64
+ const p = join(dirname(fileURLToPath(import.meta.url)), rel);
65
+ const d = JSON.parse(readFileSync(p, "utf8"));
66
+ if (typeof d.version === "string")
67
+ return d.version;
68
+ }
69
+ catch {
70
+ // tenta o próximo candidato
71
+ }
72
+ }
73
+ return "0.0.0";
74
+ }
75
+ /** Lê o lock. Ausente ou inválido devolve `ok: false` — nunca lança. */
76
+ export function lerLock(raizProjeto, versaoCliAtual = versaoDoCli()) {
77
+ const caminho = caminhoDoLock(raizProjeto);
78
+ if (!existsSync(caminho))
79
+ return { ok: false, erro: `lock nao encontrado em ${caminho}` };
80
+ let bruto;
81
+ try {
82
+ bruto = JSON.parse(readFileSync(caminho, "utf8"));
83
+ }
84
+ catch (e) {
85
+ return { ok: false, erro: `lock ilegivel: ${String(e)}` };
86
+ }
87
+ const r = Lock.safeParse(bruto);
88
+ if (!r.success)
89
+ return { ok: false, erro: `lock fora do formato: ${r.error.message}` };
90
+ return {
91
+ ok: true,
92
+ lock: r.data,
93
+ incompativel: compararVersoes(r.data.cli_version, versaoCliAtual) > 0,
94
+ };
95
+ }
96
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/nucleo/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Resolução de versão alvo de uma skill.
3
+ *
4
+ * A regra do método: por padrão, a MAIOR tag de versão semântica do
5
+ * repositório. Sem nenhuma tag, cai para a branch padrão e avisa
6
+ * explicitamente que a skill não está travada em versão publicada — nunca
7
+ * segue a branch em silêncio quando existe tag.
8
+ *
9
+ * Hoje NENHUMA das cinco skills tem tag (`base/08-repositorios-reais.md`), então
10
+ * o caminho de fallback é o corrente na prática, não a exceção.
11
+ */
12
+ export type Alvo = {
13
+ ok: boolean;
14
+ /** Tag escolhida, ou a branch padrão quando não há tag. */
15
+ referencia: string;
16
+ /** `false` quando a referência é branch: a skill não está travada em versão publicada. */
17
+ travado: boolean;
18
+ erro?: string;
19
+ };
20
+ /**
21
+ * A maior tag semver da lista, ou `undefined` se nenhuma for semver.
22
+ *
23
+ * Compara número a número — ordenação de string colocaria `v1.10.0` antes de
24
+ * `v1.2.0`, que é o erro clássico e justamente o que o teste cobre.
25
+ */
26
+ export declare function maiorTagSemver(tags: readonly string[]): string | undefined;
27
+ /** As tags publicadas de um repositório, sem as referências desreferenciadas (`^{}`). */
28
+ export declare function listarTags(repositorio: string): Promise<string[]>;
29
+ /**
30
+ * A referência que deve ser instalada.
31
+ *
32
+ * Repositório inacessível NÃO lança: devolve `ok: false` com o motivo, porque o
33
+ * método exige que uma skill inacessível não aborte a instalação das demais.
34
+ */
35
+ export declare function resolverAlvo(repositorio: string, forcar?: string): Promise<Alvo>;
@@ -0,0 +1,63 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const exec = promisify(execFile);
4
+ const BRANCH_PADRAO = "main";
5
+ /** `v1.2.3` → [1,2,3]. Pré-lançamento (`-rc.1`) é ignorado: não é versão publicada. */
6
+ function partes(tag) {
7
+ const m = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(tag.trim());
8
+ if (m === null)
9
+ return undefined;
10
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
11
+ }
12
+ /**
13
+ * A maior tag semver da lista, ou `undefined` se nenhuma for semver.
14
+ *
15
+ * Compara número a número — ordenação de string colocaria `v1.10.0` antes de
16
+ * `v1.2.0`, que é o erro clássico e justamente o que o teste cobre.
17
+ */
18
+ export function maiorTagSemver(tags) {
19
+ let melhor;
20
+ for (const tag of tags) {
21
+ const p = partes(tag);
22
+ if (p === undefined)
23
+ continue;
24
+ if (melhor === undefined ||
25
+ p[0] > melhor.p[0] ||
26
+ (p[0] === melhor.p[0] && p[1] > melhor.p[1]) ||
27
+ (p[0] === melhor.p[0] && p[1] === melhor.p[1] && p[2] > melhor.p[2])) {
28
+ melhor = { tag, p };
29
+ }
30
+ }
31
+ return melhor?.tag;
32
+ }
33
+ /** As tags publicadas de um repositório, sem as referências desreferenciadas (`^{}`). */
34
+ export async function listarTags(repositorio) {
35
+ const { stdout } = await exec("git", ["ls-remote", "--tags", repositorio]);
36
+ return stdout
37
+ .split("\n")
38
+ .filter((l) => l.includes("refs/tags/") && !l.endsWith("^{}"))
39
+ .map((l) => l.slice(l.indexOf("refs/tags/") + "refs/tags/".length).trim())
40
+ .filter((t) => t !== "");
41
+ }
42
+ /**
43
+ * A referência que deve ser instalada.
44
+ *
45
+ * Repositório inacessível NÃO lança: devolve `ok: false` com o motivo, porque o
46
+ * método exige que uma skill inacessível não aborte a instalação das demais.
47
+ */
48
+ export async function resolverAlvo(repositorio, forcar) {
49
+ if (forcar !== undefined && forcar !== "") {
50
+ return { ok: true, referencia: forcar, travado: !forcar.includes(BRANCH_PADRAO) };
51
+ }
52
+ try {
53
+ const tags = await listarTags(repositorio);
54
+ const maior = maiorTagSemver(tags);
55
+ if (maior !== undefined)
56
+ return { ok: true, referencia: maior, travado: true };
57
+ return { ok: true, referencia: BRANCH_PADRAO, travado: false };
58
+ }
59
+ catch (e) {
60
+ return { ok: false, referencia: "", travado: false, erro: String(e) };
61
+ }
62
+ }
63
+ //# sourceMappingURL=versao.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versao.js","sourceRoot":"","sources":["../../src/nucleo/versao.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { Projeto } from "../projeto/montar.js";
2
+ /**
3
+ * Violações do método — arquivos que o painel LEU e cujo conteúdo desobedece
4
+ * uma regra. Distinto de rejeição, que é falha de leitura (decisão D-03).
5
+ *
6
+ * Cada regra aqui tem um escopo estreito de propósito. A definição de pronto
7
+ * proíbe violação falsa, e todos os caminhos conhecidos para produzir uma
8
+ * nascem de aplicar uma regra a quem ela não se destina:
9
+ *
10
+ * - regressão cobrada de trabalho sprintx, ou de runx que não é bug;
11
+ * - critério de saída exigido de fase que não o declara por não existir;
12
+ * - dependência inexistente acusada sem olhar o escopo do trabalho.
13
+ */
14
+ export declare const TipoViolacao: {
15
+ readonly TesteAusente: "teste_ausente";
16
+ readonly RegressaoAusente: "regressao_ausente";
17
+ readonly ConcluidaSemVerde: "concluida_sem_verde";
18
+ readonly ParalelaComDependencia: "paralela_com_dependencia";
19
+ readonly SemCriterioSaida: "sem_criterio_saida";
20
+ readonly BloqueioAntigo: "bloqueio_antigo";
21
+ readonly DependenciaInexistente: "dependencia_inexistente";
22
+ readonly CicloDependencia: "ciclo_dependencia";
23
+ readonly EstagioIncoerente: "estagio_incoerente";
24
+ };
25
+ export type TipoViolacao = (typeof TipoViolacao)[keyof typeof TipoViolacao];
26
+ export type Violacao = {
27
+ tipo: TipoViolacao;
28
+ trabalho_id: string;
29
+ /** id da task/fase/bloqueio a que a violação se refere. */
30
+ alvo: string;
31
+ arquivo: string;
32
+ linha: number | null;
33
+ detalhe: string;
34
+ };
35
+ export type OpcoesConformidade = {
36
+ /** "Hoje" entra como parâmetro: regra que lê o relógio não é testável (decisão D-16). */
37
+ hoje: Date;
38
+ /** Limite de dias para bloqueio antigo (decisão D-15). */
39
+ diasBloqueio: number;
40
+ };
41
+ export declare function verificarConformidade(projeto: Projeto, op: OpcoesConformidade): Violacao[];