@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.
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/README.md +248 -0
- package/bin/specsfy.cjs +3 -0
- package/dist/backlog.d.ts +17 -0
- package/dist/backlog.d.ts.map +1 -0
- package/dist/backlog.js +73 -0
- package/dist/backlog.js.map +1 -0
- package/dist/catalog.d.ts +33 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +135 -0
- package/dist/catalog.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +258 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/filesystem.d.ts +19 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +67 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/github.d.ts +8 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +36 -0
- package/dist/github.js.map +1 -0
- package/dist/installer.d.ts +48 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +613 -0
- package/dist/installer.js.map +1 -0
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +13 -0
- package/dist/main.js.map +1 -0
- package/dist/progress.d.ts +46 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +148 -0
- package/dist/progress.js.map +1 -0
- package/dist/project-testing.d.ts +27 -0
- package/dist/project-testing.d.ts.map +1 -0
- package/dist/project-testing.js +150 -0
- package/dist/project-testing.js.map +1 -0
- package/dist/skill-lock.d.ts +23 -0
- package/dist/skill-lock.d.ts.map +1 -0
- package/dist/skill-lock.js +80 -0
- package/dist/skill-lock.js.map +1 -0
- package/dist/tui.d.ts +141 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +1219 -0
- package/dist/tui.js.map +1 -0
- package/dist/updater.d.ts +41 -0
- package/dist/updater.d.ts.map +1 -0
- package/dist/updater.js +221 -0
- package/dist/updater.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- 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
|
+

|
|
103
|
+
|
|
104
|
+

|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+

|
|
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/).
|
package/bin/specsfy.cjs
ADDED
|
@@ -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"}
|
package/dist/backlog.js
ADDED
|
@@ -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"}
|
package/dist/catalog.js
ADDED
|
@@ -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"}
|