@andespindola/crow-skills 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/catalog.json +24 -0
- package/crow_skills/__init__.py +1 -1
- package/crow_skills/autoupdate.py +71 -10
- package/crow_skills/cli.py +375 -61
- package/crow_skills/groups.py +76 -0
- package/crow_skills/guide.py +15 -2
- package/crow_skills/integrations.py +188 -13
- package/crow_skills/machine.py +720 -0
- package/crow_skills/trust.py +437 -0
- package/crow_skills/ui.py +198 -0
- package/docs/cli.md +72 -8
- package/package.json +1 -1
- package/release.json +31 -11
package/README.md
CHANGED
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Skills com escopo explícito, conhecimento especializado preservado e fluxos comuns reutilizáveis.
|
|
4
4
|
|
|
5
|
-
**Versão 0.
|
|
5
|
+
**Versão 0.11.0** ([mudanças](CHANGELOG.md)): `crow-skills setup --yes` configura de uma vez todos os CLIs de agente da máquina e `crow-skills upgrade --yes` atualiza tudo numa só passada; os hooks que o crow-skills grava já saem habilitados (no Codex, aprovados pelo próprio `codex app-server`, só os do crow-skills; `--no-trust` desliga) e `status`/`doctor` mostram se cada CLI vai rodá-los; a ajuda ficou curta e organizada por tarefa. A 0.10.1 passou a tratar swap e CPU como eixos de pressão no controle de recursos (swap quase cheio e carga alta reduzem agentes, jobs e workers; nenhuma recomendação cresce com a pressão), mostrou a CPU% dos CLIs de agente, trouxe `crow-skills resources --exec-prefix` para rodar jobs pesados em prioridade baixa e as regras da crow-behaviour sob pressão (reduzir já, um job pesado por vez, não repetir verificação, validação ampla no CI); os hooks do Codex vão para o `config.toml` quando o `hooks.json` é symlink. A 0.10.0 trouxe o crow-broadcast, que compartilha, de forma passiva, o que cada sessão e cada CLI (Claude Code, Codex, Gemini CLI, Antigravity, Devin, inclusive dentro do Uniflow) está fazendo nesta máquina: repositório, clone, branch, execução crow em andamento e arquivos em edição; o prompt recebe um resumo só quando outra sessão viva está no mesmo repositório, editar um arquivo que outra sessão tocou ou trocar de branch num clone em uso gera aviso (ou bloqueio, se configurado), e `crow-skills broadcast claim` reserva áreas; a crow-behaviour consulta isso antes de planejar e reserva as áreas que delega ([crow-broadcast](docs/broadcast.md)). A 0.9.0 trouxe o controle de memória da máquina: `crow-skills resources` mede memória, pressão e os CLIs de agente em execução e recomenda quantos agentes, jobs pesados e workers rodar em paralelo; a crow-behaviour consulta essa recomendação antes de cada fan-out (sob `warn` reduz, sob `critical` segue sequencial), limita workers de builds e testes, reutiliza um dev server por projeto e encerra o que abriu, e 15 especialistas que sobem processos pesados ganharam a regra correspondente; o hook de prompt e as status lines só avisam quando a máquina está sob pressão. A 0.8.0 trouxe `crow-skills mode on|off`, que liga e desliga a crow-behaviour em todas as sessões e CLIs (Claude Code, Codex, Gemini CLI, Antigravity, Devin) a partir do próximo prompt, com `/crow on|off` dentro da sessão e o indicador `▸▸ crow on` na status line; a crow-behaviour mostra o progresso como a lista de agentes do host (`● main`, `○ dono atividade`); `crow-skills events` publica um barramento de eventos dos hooks para terminais; `crow-skills autoupdate on` atualiza o CLI e as skills gerenciadas todo dia e no login. A 0.7.1 trouxe as correções da revalidação no Codex às skills especialistas; a 0.7.0 tornou o Uniflow agente de instalação (`--agents uniflow`); a 0.6.1 passou a mostrar o progresso da crow-behaviour na própria conversa; a 0.6.0 trouxe as regras de entrega das 32 skills especialistas, a partir da [validação no Codex](docs/evaluations/2026-10-26-codex.md).
|
|
6
6
|
|
|
7
7
|
**Reconstrução em andamento.** A primeira versão com 32 contratos genéricos não atende à preservação de capacidades solicitada. Não use esse número nem o mapeamento por categoria como prova de substituição das originais. A revisão passa a abranger cada definição e seus recursos, modos e dependências, sem número fixo de skills ou limite artificial de linhas. Veja [critérios e progresso](docs/reconstruction.md).
|
|
8
8
|
|
|
9
|
+
## Começar
|
|
10
|
+
|
|
11
|
+
Uma linha configura todos os CLIs de agente da máquina (Claude Code, Codex, Gemini CLI, Antigravity, Devin, Uniflow e o segmento do tmux):
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
brew install andersonflima/tap/crow-skills && crow-skills setup --yes
|
|
15
|
+
# ou, com npm:
|
|
16
|
+
npm install -g @andespindola/crow-skills && crow-skills setup --yes
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`setup` detecta cada CLI (binário no PATH ou diretório de configuração), instala todas as skills, o guia, as integrações e os hooks do modo crow já habilitados, liga o modo crow e o autoupdate, e termina com uma tabela por CLI e o doctor. `crow-skills setup --dry-run` mostra o plano sem gravar nada; rodar de novo só corrige o que mudou. Para atualizar tudo depois: `crow-skills upgrade --yes`. `crow-skills` sozinho mostra a ajuda curta e o estado atual; `crow-skills help <comando>` detalha cada comando. Detalhes em [setup, upgrade e ajuda](docs/cli.md#configurar-a-máquina-setup).
|
|
20
|
+
|
|
9
21
|
## Uso
|
|
10
22
|
|
|
11
23
|
1. Escolha pela intenção, estado do projeto, stack e risco. Leia a descrição antes do corpo.
|
|
@@ -30,10 +42,12 @@ Exemplos:
|
|
|
30
42
|
O pacote de cada skill é somente sua pasta em `skills/`. O [CLI crow-skills](docs/cli.md) instala cópias completas e versionadas em agentes/escopos explícitos, com preview, saída JSON, detecção de conflitos e recuperação. Requer Python 3.10+; Git para fontes em clone, Node 18+ para o launcher npm; mutações em macOS/Linux. A distribuição npm privada `@andespindola/crow-skills` inclui um snapshot completo das skills, sem clone ou hooks que as instalem automaticamente. No [Uniflow](docs/cli.md#uniflow), `--agents uniflow --global` grava as skills no store dele (`~/.config/uniflow/skills`), sem tocar no resto da configuração. Em `--global`, instalar a crow-behaviour também grava o guia aditivo do agente (claude, codex, gemini, devin) para usar as skills; `--no-guide` desliga. As integrações de interface (status lines do Claude Code, do Codex e do Antigravity, hooks do modo crow em cada CLI, comando `/crow`, segmento tmux) seguem o mesmo fluxo, preservando a configuração existente; `--no-integrations` desliga. O [barramento de eventos](docs/events.md) e a atualização automática (`crow-skills autoupdate on`) estão no [CLI](docs/cli.md).
|
|
31
43
|
|
|
32
44
|
```sh
|
|
33
|
-
npm install -g @andespindola/crow-skills@0.
|
|
45
|
+
npm install -g @andespindola/crow-skills@0.11.0
|
|
34
46
|
crow-skills mode
|
|
35
47
|
crow-skills progress
|
|
36
48
|
./bin/crow-skills list
|
|
49
|
+
./bin/crow-skills groups
|
|
50
|
+
./bin/crow-skills install --group essencial --agents claude,codex --global --dry-run
|
|
37
51
|
./bin/crow-skills install crow-behaviour --agents claude,codex --global --dry-run
|
|
38
52
|
./bin/crow-skills install crow-behaviour --agents claude,codex --global --yes --json
|
|
39
53
|
./bin/crow-skills related crow-backend --agents claude --global
|
package/catalog.json
CHANGED
|
@@ -8,6 +8,30 @@
|
|
|
8
8
|
}
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
|
+
"groups": [
|
|
12
|
+
{"name": "essencial", "title": "Essencial", "description": "Coordenação e o que serve a quase todo projeto: arquitetura, especificação, depuração, testes e revisão de segurança",
|
|
13
|
+
"skills": ["crow-behaviour", "crow-architecture", "crow-spec", "crow-debug", "crow-qa", "crow-security-review"]},
|
|
14
|
+
{"name": "web", "title": "Web", "description": "Interfaces web: direção visual, implementação, acessibilidade, navegador e SEO",
|
|
15
|
+
"skills": ["crow-frontend", "crow-interface", "crow-design", "crow-accessibility", "crow-browser", "crow-seo"]},
|
|
16
|
+
{"name": "backend", "title": "Backend", "description": "Serviços, APIs, dados e domínio",
|
|
17
|
+
"skills": ["crow-backend", "crow-api-test", "crow-postgres", "crow-domain", "crow-architecture"]},
|
|
18
|
+
{"name": "qualidade", "title": "Qualidade", "description": "Testes, defeitos, desempenho e observabilidade",
|
|
19
|
+
"skills": ["crow-qa", "crow-debug", "crow-performance", "crow-observe"]},
|
|
20
|
+
{"name": "seguranca", "title": "Segurança", "description": "Revisão, varredura, prova, modelagem de ameaças, credenciais e apps com LLM",
|
|
21
|
+
"skills": ["crow-security-review", "crow-security-scan", "crow-security-test", "crow-threat-model", "crow-secrets", "crow-agent-security"]},
|
|
22
|
+
{"name": "infra", "title": "Infra e entrega", "description": "Infraestrutura, release e coordenação de plataforma",
|
|
23
|
+
"skills": ["crow-infra", "crow-release", "crow-platform"]},
|
|
24
|
+
{"name": "mobile", "title": "Mobile", "description": "Apps nativos e mobile",
|
|
25
|
+
"skills": ["crow-native-mobile"]},
|
|
26
|
+
{"name": "produto", "title": "Produto", "description": "Descoberta, especificação, crescimento, liderança e coordenação de plataforma",
|
|
27
|
+
"skills": ["crow-discovery", "crow-spec", "crow-growth", "crow-product-leadership", "crow-platform"]},
|
|
28
|
+
{"name": "midia-docs", "title": "Mídia e documentos", "description": "Mídia, documentos, planilhas e apresentações",
|
|
29
|
+
"skills": ["crow-media", "crow-documents"]},
|
|
30
|
+
{"name": "reverse", "title": "Engenharia reversa", "description": "Análise de código, binário ou protocolo",
|
|
31
|
+
"skills": ["crow-reverse"]},
|
|
32
|
+
{"name": "autoria", "title": "Autoria de skills", "description": "Criar ou revisar skills",
|
|
33
|
+
"skills": ["crow-skill-author"]}
|
|
34
|
+
],
|
|
11
35
|
"skills": [
|
|
12
36
|
{
|
|
13
37
|
"name": "crow-behaviour",
|
package/crow_skills/__init__.py
CHANGED
|
@@ -13,6 +13,10 @@ Results go to ~/.local/state/crow-skills/autoupdate/state.json (last run and
|
|
|
13
13
|
a short history), shown by ``autoupdate status``, ``doctor`` and
|
|
14
14
|
``events snapshot``. Command output of brew/npm/git is never stored or
|
|
15
15
|
printed: only exit codes and versions.
|
|
16
|
+
|
|
17
|
+
``crow-skills upgrade`` is the same run started by hand (``trigger:
|
|
18
|
+
"upgrade"``); both go through :func:`run`, and ``--dry-run`` of either goes
|
|
19
|
+
through :func:`preview`, which runs nothing and writes nothing.
|
|
16
20
|
"""
|
|
17
21
|
from datetime import datetime, timezone
|
|
18
22
|
import json
|
|
@@ -289,8 +293,22 @@ def self_upgrade(install, git_pull):
|
|
|
289
293
|
return {"kind": "unknown", "result": "skipped", "reason": "instalação não reconhecida (brew, npm ou checkout git)"}
|
|
290
294
|
|
|
291
295
|
|
|
292
|
-
def
|
|
293
|
-
"""
|
|
296
|
+
def preview_self(install, git_pull):
|
|
297
|
+
"""What the self step would do, without running brew/npm/git."""
|
|
298
|
+
if install["kind"] in ("brew", "npm"):
|
|
299
|
+
return {"kind": install["kind"], "result": "would_run", "command": list(install["upgrade"]), "before": __version__}
|
|
300
|
+
if install["kind"] == "git":
|
|
301
|
+
if not git_pull:
|
|
302
|
+
return {"kind": "git", "result": "skipped", "reason": "checkout git: atualize com git pull, ou use --git-pull"}
|
|
303
|
+
return {"kind": "git", "result": "would_run", "command": ["git", "-C", install["root"], "pull", "--ff-only"],
|
|
304
|
+
"before": __version__, "note": "só se o checkout estiver limpo em main/master"}
|
|
305
|
+
return {"kind": "unknown", "result": "skipped", "reason": "instalação não reconhecida (brew, npm ou checkout git)"}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def skills_update(home, trust=True, dry_run=False):
|
|
309
|
+
"""update --global for every agent with managed installs; modified skills are kept and reported.
|
|
310
|
+
|
|
311
|
+
dry_run: the same per-agent plan with update --dry-run; "updated" lists what would change."""
|
|
294
312
|
from . import cli
|
|
295
313
|
from .cli import parser, run as cli_run
|
|
296
314
|
from .storage import Store
|
|
@@ -313,8 +331,27 @@ def skills_update(home):
|
|
|
313
331
|
except (CrowError, OSError) as exc:
|
|
314
332
|
results.append({"agent": agent, "error": {"code": getattr(exc, "code", "io_error"), "message": str(exc)}})
|
|
315
333
|
continue
|
|
334
|
+
from .guide import store_managed
|
|
335
|
+
store_ok = store_managed(home, store) if any(r["status"] == "uniflow_link" for r in rows) else set()
|
|
336
|
+
projected = sorted(r["name"] for r in rows if r["status"] == "uniflow_link" and r["name"] in store_ok)
|
|
316
337
|
rows = [r for r in rows if r["name"] and r["revision"]]
|
|
317
338
|
if not rows:
|
|
339
|
+
if projected:
|
|
340
|
+
# Every crow skill here comes from Uniflow's store (updated as agent uniflow): only the guide,
|
|
341
|
+
# integrations and hooks of this CLI are refreshed.
|
|
342
|
+
from . import machine
|
|
343
|
+
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": [], "error": None,
|
|
344
|
+
"via_uniflow": projected}
|
|
345
|
+
if dry_run:
|
|
346
|
+
entry["dry_run"] = True
|
|
347
|
+
try:
|
|
348
|
+
extras = machine.refresh_extras(agent, home, dry_run, trust)
|
|
349
|
+
entry["guides"] = (extras.get("guides") or {}).get("transaction")
|
|
350
|
+
except CrowError as exc:
|
|
351
|
+
entry["error"] = {"code": exc.code, "message": str(exc)}
|
|
352
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
353
|
+
entry["error"] = {"code": "io_error", "message": "Falha de leitura/gravação; nada concluído para este agente."}
|
|
354
|
+
results.append(entry)
|
|
318
355
|
continue
|
|
319
356
|
records = store.state(target["path"])["installed"]
|
|
320
357
|
names, kept = [], []
|
|
@@ -325,10 +362,17 @@ def skills_update(home):
|
|
|
325
362
|
kept.append({"name": r["name"], "status": "other_origin"}) # update --source or install switches it
|
|
326
363
|
else:
|
|
327
364
|
names.append(r["name"])
|
|
328
|
-
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept, "error": None
|
|
365
|
+
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept, "error": None,
|
|
366
|
+
"via_uniflow": projected}
|
|
367
|
+
if dry_run:
|
|
368
|
+
entry["dry_run"] = True
|
|
329
369
|
if names:
|
|
330
370
|
try:
|
|
331
|
-
|
|
371
|
+
argv = ["update", *names, "--agents", agent, "--global", "--dry-run" if dry_run else "--yes", "--json",
|
|
372
|
+
"--home", str(home)]
|
|
373
|
+
if not trust:
|
|
374
|
+
argv.append("--no-trust")
|
|
375
|
+
args = parser().parse_args(argv)
|
|
332
376
|
data = cli_run(args)
|
|
333
377
|
entry["updated"] = sorted({c["name"] for c in data["changes"] if c["action"] != "unchanged"})
|
|
334
378
|
entry["unchanged"] = sum(c["action"] == "unchanged" for c in data["changes"])
|
|
@@ -342,7 +386,21 @@ def skills_update(home):
|
|
|
342
386
|
return results
|
|
343
387
|
|
|
344
388
|
|
|
345
|
-
def
|
|
389
|
+
def preview(store, home, self_step=True, skills_step=True, trust=True, git_pull=None):
|
|
390
|
+
"""Dry run shared by autoupdate run --dry-run and upgrade --dry-run: nothing runs, nothing is written."""
|
|
391
|
+
state = load_state(store)
|
|
392
|
+
install = detect()
|
|
393
|
+
result = {"install": install, "applied": False, "dry_run": True,
|
|
394
|
+
"would": ["atualizar o crow-skills" if self_step else None, "update --global das skills gerenciadas, por agente"]}
|
|
395
|
+
if self_step:
|
|
396
|
+
result["self"] = preview_self(install, state.get("git_pull") if git_pull is None else git_pull)
|
|
397
|
+
if skills_step:
|
|
398
|
+
result["skills"] = skills_update(home, trust=trust, dry_run=True)
|
|
399
|
+
return result
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def run(store, home, self_step=True, skills_step=True, trust=True, git_pull=None, trigger="autoupdate"):
|
|
403
|
+
"""One run (scheduled autoupdate or crow-skills upgrade): self-upgrade, then every agent's update."""
|
|
346
404
|
try:
|
|
347
405
|
import fcntl
|
|
348
406
|
except ImportError as exc: # pragma: no cover
|
|
@@ -361,15 +419,18 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
361
419
|
log.write_text("")
|
|
362
420
|
state = load_state(store)
|
|
363
421
|
install = detect()
|
|
364
|
-
result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}}
|
|
422
|
+
result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}, "trigger": trigger}
|
|
365
423
|
handed_off = False
|
|
366
424
|
if self_step:
|
|
367
|
-
result["self"] = self_upgrade(install, state.get("git_pull"))
|
|
425
|
+
result["self"] = self_upgrade(install, state.get("git_pull") if git_pull is None else git_pull)
|
|
368
426
|
after = result["self"].get("after")
|
|
369
427
|
if skills_step and after and after != __version__ and install["launcher"]:
|
|
370
428
|
# The new version updates the skills (its own snapshot is the new source).
|
|
371
429
|
try:
|
|
372
|
-
|
|
430
|
+
child_args = [install["launcher"], "autoupdate", "run", "--skills-only", "--yes", "--json"]
|
|
431
|
+
if not trust:
|
|
432
|
+
child_args.append("--no-trust")
|
|
433
|
+
done = subprocess.run(child_args,
|
|
373
434
|
capture_output=True, text=True, timeout=1200, stdin=subprocess.DEVNULL,
|
|
374
435
|
env=dict(os.environ, CROW_SKILLS_AUTOUPDATE_CHILD="1"))
|
|
375
436
|
child = json.loads(done.stdout)
|
|
@@ -380,7 +441,7 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
380
441
|
result["handoff"] = {"version": after, "ok": False}
|
|
381
442
|
handed_off = True
|
|
382
443
|
if skills_step and not handed_off:
|
|
383
|
-
result["skills"] = skills_update(home)
|
|
444
|
+
result["skills"] = skills_update(home, trust=trust)
|
|
384
445
|
result["endedAt"] = now()
|
|
385
446
|
result["ok"] = (result.get("self", {}).get("result") != "failed"
|
|
386
447
|
and all(not s.get("error") for s in result.get("skills", []))
|
|
@@ -388,7 +449,7 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
388
449
|
state = load_state(store)
|
|
389
450
|
state["lastRun"] = result
|
|
390
451
|
history = state.get("history") or []
|
|
391
|
-
history.append({"startedAt": result["startedAt"], "ok": result["ok"],
|
|
452
|
+
history.append({"startedAt": result["startedAt"], "ok": result["ok"], "trigger": trigger,
|
|
392
453
|
"updated": sum(len(s.get("updated") or []) for s in result.get("skills", [])),
|
|
393
454
|
"self": (result.get("self") or {}).get("result")})
|
|
394
455
|
state["history"] = history[-HISTORY:]
|