@promovaweb/specsfy 0.7.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 (61) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +248 -0
  4. package/bin/specsfy.cjs +3 -0
  5. package/dist/backlog.d.ts +17 -0
  6. package/dist/backlog.d.ts.map +1 -0
  7. package/dist/backlog.js +73 -0
  8. package/dist/backlog.js.map +1 -0
  9. package/dist/catalog.d.ts +33 -0
  10. package/dist/catalog.d.ts.map +1 -0
  11. package/dist/catalog.js +135 -0
  12. package/dist/catalog.js.map +1 -0
  13. package/dist/cli.d.ts +12 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +258 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/config.d.ts +14 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +44 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/filesystem.d.ts +19 -0
  22. package/dist/filesystem.d.ts.map +1 -0
  23. package/dist/filesystem.js +67 -0
  24. package/dist/filesystem.js.map +1 -0
  25. package/dist/github.d.ts +8 -0
  26. package/dist/github.d.ts.map +1 -0
  27. package/dist/github.js +36 -0
  28. package/dist/github.js.map +1 -0
  29. package/dist/installer.d.ts +48 -0
  30. package/dist/installer.d.ts.map +1 -0
  31. package/dist/installer.js +613 -0
  32. package/dist/installer.js.map +1 -0
  33. package/dist/main.d.ts +5 -0
  34. package/dist/main.d.ts.map +1 -0
  35. package/dist/main.js +13 -0
  36. package/dist/main.js.map +1 -0
  37. package/dist/progress.d.ts +46 -0
  38. package/dist/progress.d.ts.map +1 -0
  39. package/dist/progress.js +148 -0
  40. package/dist/progress.js.map +1 -0
  41. package/dist/project-testing.d.ts +27 -0
  42. package/dist/project-testing.d.ts.map +1 -0
  43. package/dist/project-testing.js +150 -0
  44. package/dist/project-testing.js.map +1 -0
  45. package/dist/skill-lock.d.ts +23 -0
  46. package/dist/skill-lock.d.ts.map +1 -0
  47. package/dist/skill-lock.js +80 -0
  48. package/dist/skill-lock.js.map +1 -0
  49. package/dist/tui.d.ts +141 -0
  50. package/dist/tui.d.ts.map +1 -0
  51. package/dist/tui.js +1219 -0
  52. package/dist/tui.js.map +1 -0
  53. package/dist/updater.d.ts +41 -0
  54. package/dist/updater.d.ts.map +1 -0
  55. package/dist/updater.js +221 -0
  56. package/dist/updater.js.map +1 -0
  57. package/dist/version.d.ts +7 -0
  58. package/dist/version.d.ts.map +1 -0
  59. package/dist/version.js +7 -0
  60. package/dist/version.js.map +1 -0
  61. package/package.json +58 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ Todas as mudanças relevantes do Specsfy CLI são registradas neste arquivo.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.7.0] - 2026-07-30
8
+
9
+ - Migra o CLI e a TUI de Python para Node.js 22, com instalação global por
10
+ `@promovaweb/specsfy`.
11
+ - Mantém as seis abas da TUI e adiciona execução do Pest com resumo e saída
12
+ rolável.
13
+ - Corrige os atalhos de controle interpretados pelo `neo-blessed` e evita o
14
+ encerramento da TUI durante a atualização da saída dos testes.
15
+ - Adiciona o fluxo de release com changelog, commit, tag anotada, GitHub
16
+ Actions, publicação npm e GitHub Release vinculados à mesma versão.
17
+ - Atualiza o instalador, o catálogo de especialistas e a documentação do
18
+ usuário para os comandos do CLI em Node.js.
19
+
20
+ - Autentica catálogo e verificação de tags em repositórios privados com
21
+ `GH_TOKEN`, `GITHUB_TOKEN` ou a sessão do GitHub CLI.
22
+ - Torna o fingerprint do executável estável entre permissões equivalentes do
23
+ Git e ambientes locais/CI.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Specsfy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # Specsfy CLI
2
+
3
+ <!-- markdownlint-disable MD033 -->
4
+ <p align="center">
5
+ <picture>
6
+ <source srcset="../brand/logo/icon.svg" type="image/svg+xml">
7
+ <img src="../brand/logo/icon.png" alt="Logo do Specsfy" width="128">
8
+ </picture>
9
+ </p>
10
+ <!-- markdownlint-enable MD033 -->
11
+
12
+ CLI e TUI para instalar e atualizar skills do Specsfy com segurança, detectar
13
+ tecnologias e acompanhar em tempo real o progresso das specs de um projeto.
14
+
15
+ ## Pré-requisitos
16
+
17
+ - Node.js 22.12 ou superior, com o npm disponível.
18
+ - `skills`, do projeto
19
+ [`vercel-labs/skills`](https://github.com/vercel-labs/skills), ou `npx`
20
+ disponível para executá-lo sob demanda.
21
+ - acesso autenticado ao repositório privado: execute `gh auth login` no uso
22
+ interativo ou defina `GH_TOKEN`/`GITHUB_TOKEN` na automação.
23
+
24
+ ## Download oficial
25
+
26
+ O executável versionado é publicado em `get.specsfy.dev`. Ele reúne o código e
27
+ as dependências JavaScript em um arquivo, mas continua usando o Node.js
28
+ instalado na máquina. Coloque o arquivo em um diretório do seu `PATH` e preserve
29
+ a permissão de execução.
30
+
31
+ ## Instalar com npm
32
+
33
+ ```bash
34
+ npm install --global @promovaweb/specsfy
35
+ specsfy --version
36
+ ```
37
+
38
+ O npm instala o pacote publicado e disponibiliza o comando `specsfy`. Para
39
+ atualizar a instalação global:
40
+
41
+ ```bash
42
+ npm update --global @promovaweb/specsfy
43
+ ```
44
+
45
+ O catálogo e a verificação de versões usam a API do GitHub. O CLI procura,
46
+ nesta ordem, `GH_TOKEN`, `GITHUB_TOKEN` e a sessão retornada por
47
+ `gh auth token`. As credenciais não são gravadas pelo Specsfy.
48
+
49
+ Para instalar uma versão específica, informe a versão no próprio pacote:
50
+
51
+ ```bash
52
+ npm install --global @promovaweb/specsfy@0.6.0
53
+ ```
54
+
55
+ ## Comandos
56
+
57
+ ```bash
58
+ specsfy
59
+ specsfy install --project .
60
+ specsfy install --project . --detected
61
+ specsfy install --project . \
62
+ --specialist specsfy-specialist-laravel \
63
+ --specialist specsfy-specialist-postgres
64
+ specsfy skills list
65
+ specsfy skills detect --project .
66
+ specsfy skills add specsfy-specialist-laravel --project .
67
+ specsfy skills remove specsfy-specialist-laravel --project .
68
+ specsfy skills update --project .
69
+ specsfy progress --project .
70
+ specsfy progress --project . --json
71
+ specsfy progress --project . --watch
72
+ specsfy test --project .
73
+ specsfy config show --project .
74
+ specsfy config set --project . --watch-interval 0.5
75
+ ```
76
+
77
+ Dependências declaradas pelo catálogo são resolvidas automaticamente. Por
78
+ exemplo, instalar `specsfy-specialist-react-ui-components` também instala
79
+ `specsfy-specialist-ui-design`, tanto pelo comando quanto pela TUI:
80
+
81
+ ```bash
82
+ specsfy skills add specsfy-specialist-react-ui-components --project .
83
+ ```
84
+
85
+ Sem subcomando, `specsfy` abre o dashboard TUI no diretório atual. A interface
86
+ possui seis abas:
87
+
88
+ - **Home**: totais de specs, tarefas, checklists e progresso global.
89
+ - **Backlogs**: lista navegável à esquerda e preview Markdown formatado à
90
+ direita.
91
+ - **Specs**: tabela detalhada com gates e progresso de cada especificação.
92
+ destaque uma linha e pressione `Espaço` para abrir a spec completa em um
93
+ modal Markdown rolável, retornando à listagem com `Esc`.
94
+ - **Testes**: executa o Pest do projeto e separa o resultado entre as subabas
95
+ **Resumo** e **Testes**, mantendo a saída detalhada rolável.
96
+ - **Skills**: catálogo tabular com plano, nome, categoria e estado, acompanhado
97
+ por um painel de detalhes e resumo das alterações pendentes.
98
+ - **Sobre**: versão e finalidade do CLI.
99
+
100
+ ## Capturas de tela
101
+
102
+ ![Dashboard Home](../docs/user/assets/cli/cli-dash.png)
103
+
104
+ ![Backlogs](../docs/user/assets/cli/cli-backlogs.png)
105
+
106
+ ![Specs](../docs/user/assets/cli/cli-specs.png)
107
+
108
+ ![Skills](../docs/user/assets/cli/cli-skills.png)
109
+
110
+ Alterações em `specs/inbox/*.md`, `specs/backlog/*.md`,
111
+ `specs/specs/*/spec.md` e no `skills-lock.json` são detectadas
112
+ automaticamente.
113
+
114
+ Em projetos Laravel com Pest, `specsfy test --project .` detecta `artisan` e
115
+ `pestphp/pest`, executa `php artisan test` a partir da raiz selecionada,
116
+ transmite a saída e devolve o mesmo exit code. Na TUI, `Executar testes ^X`
117
+ mostra status, runner, comando, duração e resumo em uma subaba. A outra exibe
118
+ cada teste e falha. Relatórios Pest estruturados são convertidos em linhas
119
+ legíveis com arquivo, linha e mensagem.
120
+
121
+ O bootstrap instala as nove skills base, incluindo `specsfy-01-inbox` e
122
+ `specsfy-update-spec` para pedidos surgidos depois da definição,
123
+ `specsfy-setup`,
124
+ `specsfy-documentator` e as três skills `specsfy-aux-*`, publica as regras em
125
+ `.specsfy/Spec.md`, os templates `Inbox.md`, `Backlog.md`, `Spec.md`, `Tasks.md`,
126
+ `Project.md`, `Stack.md`, `Rules.md` e `Database.md` em
127
+ `.specsfy/templates/`, cria o diretório não gerenciado
128
+ `.specsfy/templates/custom/`, publica um exemplo em
129
+ `.specsfy/examples/Spec.md` e mescla blocos gerenciados em `AGENTS.md` e
130
+ `CLAUDE.md`, preservando as instruções do usuário. Instalações repetidas são
131
+ idempotentes. O lock registra fingerprints: versões intactas podem ser
132
+ atualizadas, mas conteúdo gerenciado customizado localmente só é substituído ou
133
+ removido com `--force`. Arquivos em `.specsfy/templates/custom/` sempre têm
134
+ precedência sobre os homônimos gerenciados e nunca são alterados, nem com
135
+ `--force`.
136
+
137
+ A materialização das skills é delegada ao comando oficial:
138
+
139
+ ```bash
140
+ npx skills add <repositorio> \
141
+ --skill <nome> \
142
+ --agent universal \
143
+ --copy \
144
+ -y \
145
+ --full-depth
146
+ ```
147
+
148
+ O `skills-lock.json` gerado por essa ferramenta registra a proveniência e é a
149
+ fonte usada pela aba Skills para marcar os checkboxes instalados. Quando ainda
150
+ não existe em um projeto consumidor, o CLI cria o lock vazio compatível:
151
+
152
+ ```json
153
+ {
154
+ "version": 1,
155
+ "skills": {}
156
+ }
157
+ ```
158
+
159
+ O gerenciador lista exclusivamente `specsfy-setup`, `specsfy-documentator` e
160
+ skills do catálogo base, `specsfy-aux-*` e `specsfy-specialist-*`. Skills externas
161
+ presentes no mesmo lock não aparecem na interface e nunca são removidas ou
162
+ alteradas. O `.specsfy/skills-lock.json`
163
+ mantém os fingerprints usados pelo Specsfy para impedir que uma atualização
164
+ descarte alterações locais.
165
+
166
+ Na aba Skills, o botão `Atualizar ^R` baixa as origens atuais e atualiza de uma
167
+ vez todas as skills Specsfy instaladas. O comando equivalente é
168
+ `specsfy skills update --project .`. Customizações locais continuam protegidas e
169
+ só podem ser substituídas explicitamente com `--force` no comando.
170
+
171
+ ## Atualização do CLI gerenciada pelo npm
172
+
173
+ Ao abrir `specsfy` ou `specsfy tui` em um terminal interativo, o CLI consulta
174
+ as tags semânticas estáveis do monorepo. A consulta é limitada pelo cache
175
+ global `~/.specsfy/cli.json`, cujo intervalo padrão é de 24 horas. Falha de rede
176
+ ou do GitHub nunca impede a abertura do dashboard.
177
+
178
+ Quando existe versão mais recente, o CLI mostra as versões atual e disponível e
179
+ pergunta antes de atualizar. Uma resposta negativa abre a aplicação normalmente.
180
+ Uma resposta positiva delega a atualização ao npm, que instala a versão mais
181
+ recente de `@promovaweb/specsfy` no escopo global. O processo então fecha. Abra
182
+ `specsfy` novamente para iniciar a versão instalada.
183
+
184
+ O arquivo global usa permissão `0600`, preserva chaves desconhecidas e separa:
185
+
186
+ - `settings.check_updates_on_startup`.
187
+ - `settings.check_interval_seconds`.
188
+ - `cache.last_checked_at`, tag, versão, commit, ETag e eventual erro recente.
189
+
190
+ Para publicar uma versão atualizável a partir do workspace de desenvolvimento,
191
+ use a skill local `$specsfy-release-cli`. Ela promove as notas confirmadas para
192
+ o [`CHANGELOG.md`](CHANGELOG.md), atualiza as versões do pacote e o lock,
193
+ reconstrói os artefatos versionados, cria a tag anotada `v<versão>` no mesmo
194
+ commit e usa exatamente a seção promovida como corpo do GitHub Release. O CI
195
+ valida o build e a correspondência da tag.
196
+
197
+ Novas specs usam `specs/specs/<NNNN>-<slug>/spec.md`. Capturas imediatas ficam
198
+ em `specs/inbox/<data-hora>-<slug>.md` e itens refináveis em
199
+ `specs/backlog/<NNNN>-<slug>.md`. O dashboard mantém leitura do layout
200
+ legado. A skill de especificação renderiza cada arquivo novo a partir do
201
+ template instalado. O CLI recusa instalação na raiz do monorepo oficial.
202
+
203
+ ## Executável versionado
204
+
205
+ O executável empacotado fica em `bin/specsfy`, contém as dependências do CLI e
206
+ requer apenas o Node.js compatível. Reconstrua-o depois de qualquer alteração
207
+ neste módulo:
208
+
209
+ ```bash
210
+ npm run build:executable
211
+ ```
212
+
213
+ `bin/specsfy.build.json` registra o fingerprint dos inputs. A suíte de testes
214
+ falha quando o artefato não corresponde ao estado atual.
215
+
216
+ O pacote publicado no npm usa `@promovaweb/specsfy`. A tag estável dispara o
217
+ job de publicação depois que tipos, testes, build, instalação local e
218
+ executável versionado passam no CI. O job inclui proveniência quando o
219
+ repositório estiver público; enquanto ele permanecer privado, publica com o
220
+ token do registro e sem essa atestação.
221
+
222
+ ## Atalhos da TUI
223
+
224
+ - `Ctrl+Q`: sair.
225
+ - `Ctrl+U`: atualizar.
226
+ - `Ctrl+D`: detectar recomendações.
227
+ - `Ctrl+B`: selecionar todas as skills do framework.
228
+ - `Ctrl+E`: alternar o plano da skill destacada.
229
+ - `Ctrl+V` / `Ctrl+L`: marcar ou limpar os itens visíveis.
230
+ - `Ctrl+A`: aplicar.
231
+ - `Ctrl+R`: atualizar todas as skills Specsfy instaladas.
232
+ - `Ctrl+T`, `Ctrl+N`, `Ctrl+C`: filtros Todas, Instaladas e Recomendadas.
233
+ - `Ctrl+H`, `Ctrl+G`, `Ctrl+S`, `Ctrl+K`, `Ctrl+O`: Home, Backlogs, Specs,
234
+ Skills e Sobre.
235
+ - `Ctrl+J`: abre Testes.
236
+ - `Ctrl+X`: executa os testes do projeto.
237
+ - `Espaço`: abre a spec destacada ou alterna a skill destacada, conforme a aba.
238
+ - `Esc`: fecha o modal da spec, limpa a busca de Skills ou volta para Home.
239
+
240
+ Cada botão mostra seu atalho no próprio rótulo. `Tab` e `Shift+Tab` percorrem
241
+ os controles e as setas navegam as tabelas. Na aba Skills, `Enter` ou `Espaço`
242
+ alternam o plano entre instalar, manter, remover e ignorar. Na aba Specs, abrem
243
+ o modal da linha destacada. O campo de projeto entra em edição com `Enter` ou
244
+ com um clique e atualiza o dashboard depois da confirmação. `Esc` retorna, e o
245
+ mouse opera abas, linhas e botões. Nada é instalado ou removido antes de
246
+ `Aplicar`.
247
+
248
+ A documentação completa está em [`docs/`](../docs/).
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ void import("../dist/main.js");
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Leitura dos itens de backlog de um projeto consumidor.
3
+ */
4
+ /** Projeção de um arquivo em `specs/backlog/`. */
5
+ export interface BacklogItem {
6
+ slug: string;
7
+ title: string;
8
+ identifier: string;
9
+ status: string;
10
+ path: string;
11
+ content: string;
12
+ }
13
+ /** Lê todos os backlogs do projeto em ordem estável. */
14
+ export declare function scanBacklogs(project: string): Promise<BacklogItem[]>;
15
+ /** Calcula o fingerprint dos caminhos e conteúdos de backlog. */
16
+ export declare function backlogsFingerprint(project: string): Promise<string>;
17
+ //# sourceMappingURL=backlog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backlog.d.ts","sourceRoot":"","sources":["../src/backlog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wDAAwD;AACxD,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAG1E;AAED,iEAAiE;AACjE,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc1E"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Leitura dos itens de backlog de um projeto consumidor.
3
+ */
4
+ import { createHash } from "node:crypto";
5
+ import { readFile, readdir } from "node:fs/promises";
6
+ import { basename, join, relative } from "node:path";
7
+ import { isFile, resolvePath } from "./filesystem.js";
8
+ const FIELD = /^\*\*([^*]+)\*\*:\s*(.+?)\s*$/;
9
+ const TABLE_FIELD = /^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*$/;
10
+ /** Lê todos os backlogs do projeto em ordem estável. */
11
+ export async function scanBacklogs(project) {
12
+ const root = resolvePath(project);
13
+ return Promise.all((await backlogPaths(root)).map(parseBacklog));
14
+ }
15
+ /** Calcula o fingerprint dos caminhos e conteúdos de backlog. */
16
+ export async function backlogsFingerprint(project) {
17
+ const root = resolvePath(project);
18
+ const digest = createHash("sha256");
19
+ for (const path of await backlogPaths(root)) {
20
+ digest.update(relative(root, path));
21
+ digest.update("\0");
22
+ try {
23
+ digest.update(await readFile(path));
24
+ }
25
+ catch {
26
+ continue;
27
+ }
28
+ digest.update("\0");
29
+ }
30
+ return digest.digest("hex");
31
+ }
32
+ async function backlogPaths(root) {
33
+ const directory = join(root, "specs", "backlog");
34
+ let names;
35
+ try {
36
+ names = await readdir(directory);
37
+ }
38
+ catch {
39
+ return [];
40
+ }
41
+ const paths = names
42
+ .filter((name) => name.endsWith(".md"))
43
+ .map((name) => join(directory, name));
44
+ const checks = await Promise.all(paths.map(isFile));
45
+ return paths.filter((_, index) => checks[index]).sort();
46
+ }
47
+ async function parseBacklog(path) {
48
+ const content = await readFile(path, "utf8");
49
+ const slug = basename(path, ".md");
50
+ let title = slug;
51
+ const fields = new Map();
52
+ for (const line of content.split(/\r?\n/u)) {
53
+ if (line.startsWith("# ") && title === slug) {
54
+ title = line.slice(2).trim();
55
+ if (title.toLowerCase().startsWith("backlog:")) {
56
+ title = title.split(":", 2)[1]?.trim() ?? title;
57
+ }
58
+ }
59
+ const match = FIELD.exec(line) ?? TABLE_FIELD.exec(line);
60
+ if (match?.[1] && match[2]) {
61
+ fields.set(match[1].trim().toLowerCase(), match[2].trim());
62
+ }
63
+ }
64
+ return {
65
+ slug,
66
+ title,
67
+ identifier: fields.get("id") ?? slug,
68
+ status: fields.get("status") ?? "Unknown",
69
+ path,
70
+ content,
71
+ };
72
+ }
73
+ //# sourceMappingURL=backlog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backlog.js","sourceRoot":"","sources":["../src/backlog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Catálogo de especialistas e detecção de tecnologias do projeto.
3
+ */
4
+ export declare const DEFAULT_CATALOG_URL = "https://api.github.com/repos/promovaweb/specsfy/contents/specialists/catalog.json?ref=main";
5
+ /** Entrada normalizada do catálogo de especialistas. */
6
+ export interface CatalogEntryValue {
7
+ name: string;
8
+ description: string;
9
+ category: string;
10
+ tags: string[];
11
+ files: string[];
12
+ dependencies: string[];
13
+ requires: string[];
14
+ }
15
+ /** Catálogo validado com resolução de dependências entre especialistas. */
16
+ export declare class Catalog {
17
+ #private;
18
+ readonly entries: CatalogEntryValue[];
19
+ constructor(entries: CatalogEntryValue[]);
20
+ /** Constrói o catálogo a partir do schema JSON público. */
21
+ static fromPayload(payload: unknown): Catalog;
22
+ /** Lê o catálogo de um arquivo local. */
23
+ static fromPath(path: string): Promise<Catalog>;
24
+ /** Obtém o catálogo remoto ou usa o override de ambiente. */
25
+ static fetch(url?: string): Promise<Catalog>;
26
+ /** Exige uma skill existente com o namespace de especialistas. */
27
+ require(name: string): CatalogEntryValue;
28
+ /** Resolve requisitos em ordem topológica e rejeita ciclos. */
29
+ resolve(names: string[]): CatalogEntryValue[];
30
+ /** Detecta entradas por arquivos marcadores e dependências declaradas. */
31
+ detect(project: string): Promise<CatalogEntryValue[]>;
32
+ }
33
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,eAAO,MAAM,mBAAmB,+FAC8D,CAAC;AAE/F,wDAAwD;AACxD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAcD,2EAA2E;AAC3E,qBAAa,OAAO;;IAClB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAGtC,YAAY,OAAO,EAAE,iBAAiB,EAAE,EAKvC;IAED,2DAA2D;IAC3D,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAqB5C;IAED,yCAAyC;IACzC,OAAa,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEpD;IAED,6DAA6D;IAC7D,OAAa,KAAK,CAAC,GAAG,SAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB9D;IAED,kEAAkE;IAClE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CASvC;IAED,+DAA+D;IAC/D,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAkB5C;IAED,0EAA0E;IACpE,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAgB1D;CACF"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Catálogo de especialistas e detecção de tecnologias do projeto.
3
+ */
4
+ import { readFile } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { apiHeaders } from "./github.js";
7
+ import { isFile, pathExists, resolvePath } from "./filesystem.js";
8
+ export const DEFAULT_CATALOG_URL = "https://api.github.com/repos/promovaweb/specsfy/contents/specialists/catalog.json?ref=main";
9
+ /** Catálogo validado com resolução de dependências entre especialistas. */
10
+ export class Catalog {
11
+ entries;
12
+ #byName;
13
+ constructor(entries) {
14
+ this.entries = [...entries].sort((left, right) => left.name.localeCompare(right.name));
15
+ this.#byName = new Map(entries.map((entry) => [entry.name, entry]));
16
+ }
17
+ /** Constrói o catálogo a partir do schema JSON público. */
18
+ static fromPayload(payload) {
19
+ if (!payload ||
20
+ typeof payload !== "object" ||
21
+ payload.schema_version !== 1 ||
22
+ !Array.isArray(payload.skills)) {
23
+ throw new Error("versão de catálogo não suportada");
24
+ }
25
+ const source = payload;
26
+ return new Catalog(source.skills.map((value) => ({
27
+ name: value.name,
28
+ description: value.description,
29
+ category: value.category,
30
+ tags: value.tags ?? [],
31
+ files: value.detect?.files ?? [],
32
+ dependencies: value.detect?.dependencies ?? [],
33
+ requires: value.requires ?? [],
34
+ })));
35
+ }
36
+ /** Lê o catálogo de um arquivo local. */
37
+ static async fromPath(path) {
38
+ return Catalog.fromPayload(JSON.parse(await readFile(resolvePath(path), "utf8")));
39
+ }
40
+ /** Obtém o catálogo remoto ou usa o override de ambiente. */
41
+ static async fetch(url = DEFAULT_CATALOG_URL) {
42
+ const override = process.env.SPECSFY_SPECIALISTS_CATALOG;
43
+ if (override)
44
+ return Catalog.fromPath(override);
45
+ const response = await fetch(url, {
46
+ headers: await apiHeaders("specsfy-cli", "application/vnd.github.raw+json"),
47
+ signal: AbortSignal.timeout(20_000),
48
+ });
49
+ if (!response.ok) {
50
+ if ([401, 403, 404].includes(response.status)) {
51
+ throw new Error("catálogo de especialistas indisponível; autentique o GitHub " +
52
+ "com `gh auth login` ou defina GH_TOKEN");
53
+ }
54
+ throw new Error(`falha ao consultar catálogo: HTTP ${response.status}`);
55
+ }
56
+ return Catalog.fromPayload((await response.json()));
57
+ }
58
+ /** Exige uma skill existente com o namespace de especialistas. */
59
+ require(name) {
60
+ if (!name.startsWith("specsfy-specialist-")) {
61
+ throw new Error("a skill especialista deve usar o prefixo specsfy-specialist-");
62
+ }
63
+ const entry = this.#byName.get(name);
64
+ if (!entry)
65
+ throw new Error(`skill não encontrada no catálogo: ${name}`);
66
+ return entry;
67
+ }
68
+ /** Resolve requisitos em ordem topológica e rejeita ciclos. */
69
+ resolve(names) {
70
+ const resolved = [];
71
+ const completed = new Set();
72
+ const active = new Set();
73
+ const visit = (name) => {
74
+ if (completed.has(name))
75
+ return;
76
+ if (active.has(name)) {
77
+ throw new Error(`dependência circular entre especialistas: ${name}`);
78
+ }
79
+ const entry = this.require(name);
80
+ active.add(name);
81
+ for (const required of entry.requires)
82
+ visit(required);
83
+ active.delete(name);
84
+ completed.add(name);
85
+ resolved.push(entry);
86
+ };
87
+ for (const name of names)
88
+ visit(name);
89
+ return resolved;
90
+ }
91
+ /** Detecta entradas por arquivos marcadores e dependências declaradas. */
92
+ async detect(project) {
93
+ const root = resolvePath(project);
94
+ const dependencies = await readDependencies(root);
95
+ const detected = [];
96
+ for (const entry of this.entries) {
97
+ const matches = await Promise.all(entry.files.map((marker) => pathExists(join(root, marker))));
98
+ if (matches.some(Boolean) ||
99
+ entry.dependencies.some((dependency) => dependencies.has(dependency))) {
100
+ detected.push(entry);
101
+ }
102
+ }
103
+ return detected;
104
+ }
105
+ }
106
+ async function readDependencies(project) {
107
+ const dependencies = new Set();
108
+ for (const filename of ["package.json", "composer.json"]) {
109
+ const path = join(project, filename);
110
+ if (!(await isFile(path)))
111
+ continue;
112
+ let payload;
113
+ try {
114
+ payload = JSON.parse(await readFile(path, "utf8"));
115
+ }
116
+ catch {
117
+ continue;
118
+ }
119
+ for (const key of [
120
+ "dependencies",
121
+ "devDependencies",
122
+ "require",
123
+ "require-dev",
124
+ "peerDependencies",
125
+ ]) {
126
+ const value = payload[key];
127
+ if (value && typeof value === "object" && !Array.isArray(value)) {
128
+ for (const dependency of Object.keys(value))
129
+ dependencies.add(dependency);
130
+ }
131
+ }
132
+ }
133
+ return dependencies;
134
+ }
135
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAElE,MAAM,CAAC,MAAM,mBAAmB,GAC9B,4FAA4F,CAAC;AAyB/F,2EAA2E;AAC3E,MAAM,OAAO,OAAO;IACT,OAAO,CAAsB;IAC7B,OAAO,CAAiC;IAEjD,YAAY,OAA4B;QACtC,IAAI,CAAC,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAC/C,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CACpC,CAAC;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,2DAA2D;IAC3D,MAAM,CAAC,WAAW,CAAC,OAAgB;QACjC,IACE,CAAC,OAAO;YACR,OAAO,OAAO,KAAK,QAAQ;YAC1B,OAAmC,CAAC,cAAc,KAAK,CAAC;YACzD,CAAC,KAAK,CAAC,OAAO,CAAE,OAAmC,CAAC,MAAM,CAAC,EAC3D,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,MAAM,GAAG,OAAyB,CAAC;QACzC,OAAO,IAAI,OAAO,CAChB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;YAChC,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE;YAC9C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;SAC/B,CAAC,CAAC,CACJ,CAAC;IACJ,CAAC;IAED,yCAAyC;IACzC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAY;QAChC,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,6DAA6D;IAC7D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,mBAAmB;QAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;QACzD,IAAI,QAAQ;YAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,MAAM,UAAU,CACvB,aAAa,EACb,iCAAiC,CAClC;YACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CACb,8DAA8D;oBAC5D,wCAAwC,CAC3C,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC,CAAC;IACjE,CAAC;IAED,kEAAkE;IAClE,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+DAA+D;IAC/D,OAAO,CAAC,KAAe;QACrB,MAAM,QAAQ,GAAwB,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QACjC,MAAM,KAAK,GAAG,CAAC,IAAY,EAAQ,EAAE;YACnC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO;YAChC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjB,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,QAAQ;gBAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,MAAM,CAAC,OAAe;QAC1B,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAwB,EAAE,CAAC;QACzC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAC5D,CAAC;YACF,IACE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;gBACrB,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EACrE,CAAC;gBACD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,KAAK,UAAU,gBAAgB,CAAC,OAAe;IAC7C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,KAAK,MAAM,QAAQ,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACpC,IAAI,OAAgC,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,GAAG,IAAI;YAChB,cAAc;YACd,iBAAiB;YACjB,SAAS;YACT,aAAa;YACb,kBAAkB;SACnB,EAAE,CAAC;YACF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChE,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Entrada pública do Specsfy CLI.
3
+ *
4
+ * Define a gramática de comandos e coordena módulos de domínio sem incorporar
5
+ * regras de instalação, catálogo ou progresso.
6
+ */
7
+ import { Command } from "commander";
8
+ /** Constrói o parser público sem executar efeitos. */
9
+ export declare function buildProgram(): Command;
10
+ /** Executa o CLI e converte falhas conhecidas em exit code previsível. */
11
+ export declare function runCli(argv?: string[]): Promise<number>;
12
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAA0B,MAAM,WAAW,CAAC;AAoB5D,sDAAsD;AACtD,wBAAgB,YAAY,IAAI,OAAO,CAkKtC;AAED,0EAA0E;AAC1E,wBAAsB,MAAM,CAAC,IAAI,WAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBjE"}