@andespindola/crow-skills 0.10.1 → 0.11.1
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 +144 -10
- package/crow_skills/cli.py +439 -62
- package/crow_skills/groups.py +76 -0
- package/crow_skills/guide.py +37 -2
- package/crow_skills/integrations.py +188 -13
- package/crow_skills/machine.py +795 -0
- package/crow_skills/projection.py +128 -0
- package/crow_skills/trust.py +437 -0
- package/crow_skills/ui.py +198 -0
- package/docs/cli.md +84 -8
- package/package.json +1 -1
- package/release.json +36 -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.1** ([mudanças](CHANGELOG.md)): o Codex deixa de mostrar em dobro as skills que o Uniflow já projeta em `~/.codex/skills`. A 0.11.0 trouxe `crow-skills setup --yes`, que configura de uma vez todos os CLIs de agente da máquina, e `crow-skills upgrade --yes`, que 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.1
|
|
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,76 @@ 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 broken_projections(agent, home, store, rows):
|
|
309
|
+
"""Uniflow links of this CLI whose store entry was edited or lost files: the CLI may not load them, so
|
|
310
|
+
upgrade reports them as needing the user (same as setup), with the command that restores the store."""
|
|
311
|
+
from .guide import broken_fix, store_broken
|
|
312
|
+
names = set()
|
|
313
|
+
if any(r["status"] == "uniflow_link" for r in rows):
|
|
314
|
+
bad = store_broken(home, store)
|
|
315
|
+
names |= {r["name"] for r in rows if r["status"] == "uniflow_link" and r["name"] in bad}
|
|
316
|
+
if agent == "codex":
|
|
317
|
+
from . import projection
|
|
318
|
+
names |= {n for n, kind in projection.links(home, store).items() if kind == "modified"}
|
|
319
|
+
return [{"name": n, "status": "uniflow_link_modified", "fix": broken_fix(n)} for n in sorted(names)]
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def reinstall_behaviour(home, entry, dry_run, trust):
|
|
323
|
+
"""Codex without a working crow-behaviour (its projection is broken, no native copy): install it natively,
|
|
324
|
+
as setup does, so the guide and hooks keep a coordinator to point to."""
|
|
325
|
+
from .cli import parser, run as cli_run
|
|
326
|
+
argv = ["install", "crow-behaviour", "--agents", "codex", "--global", "--json", "--home", str(home),
|
|
327
|
+
"--dry-run" if dry_run else "--yes"]
|
|
328
|
+
if not trust:
|
|
329
|
+
argv.append("--no-trust")
|
|
330
|
+
data = cli_run(parser().parse_args(argv))
|
|
331
|
+
if any(c["name"] == "crow-behaviour" and c["action"] != "unchanged" for c in data["changes"]):
|
|
332
|
+
entry["updated"].append("crow-behaviour")
|
|
333
|
+
entry["transaction"] = data.get("transaction")
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def codex_duplicates(home, store, entry, names, dry_run):
|
|
337
|
+
"""Codex sees Uniflow's links in ~/.codex/skills: those names are not updated natively, and intact managed
|
|
338
|
+
native copies of them are removed through uninstall (backup, transaction). Returns the names to update."""
|
|
339
|
+
from . import projection
|
|
340
|
+
from .cli import parser, run as cli_run
|
|
341
|
+
seen = projection.projected("codex", home, store)
|
|
342
|
+
if not seen:
|
|
343
|
+
return names
|
|
344
|
+
dupes = projection.duplicates(home, store)
|
|
345
|
+
entry["via_uniflow"] = sorted(set(entry["via_uniflow"]) | seen)
|
|
346
|
+
entry["kept"] = [k for k in entry["kept"] if k["name"] not in seen]
|
|
347
|
+
entry["kept"] += [{"name": n, "status": "duplicate_modified"} for n in dupes["modified"]]
|
|
348
|
+
entry["kept"] += [{"name": n, "status": "duplicate_shared"} for n in dupes["shared"]]
|
|
349
|
+
if dupes["remove"]:
|
|
350
|
+
argv = ["uninstall", *dupes["remove"], "--agents", "codex", "--global", "--json", "--home", str(home),
|
|
351
|
+
"--dry-run" if dry_run else "--yes", "--no-integrations"]
|
|
352
|
+
try:
|
|
353
|
+
data = cli_run(parser().parse_args(argv))
|
|
354
|
+
entry["removed"] = [{"name": c["name"], "reason": "removida: duplicava a projeção do Uniflow"}
|
|
355
|
+
for c in data["changes"] if c["action"] != "unchanged"]
|
|
356
|
+
entry["removal_transaction"] = data.get("transaction")
|
|
357
|
+
except CrowError as exc:
|
|
358
|
+
entry["error"] = {"code": exc.code, "message": str(exc)}
|
|
359
|
+
return [n for n in names if n not in seen]
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def skills_update(home, trust=True, dry_run=False):
|
|
363
|
+
"""update --global for every agent with managed installs; modified skills are kept and reported.
|
|
364
|
+
|
|
365
|
+
dry_run: the same per-agent plan with update --dry-run; "updated" lists what would change."""
|
|
294
366
|
from . import cli
|
|
295
367
|
from .cli import parser, run as cli_run
|
|
296
368
|
from .storage import Store
|
|
@@ -313,8 +385,33 @@ def skills_update(home):
|
|
|
313
385
|
except (CrowError, OSError) as exc:
|
|
314
386
|
results.append({"agent": agent, "error": {"code": getattr(exc, "code", "io_error"), "message": str(exc)}})
|
|
315
387
|
continue
|
|
388
|
+
from .guide import store_managed
|
|
389
|
+
store_ok = store_managed(home, store) if any(r["status"] == "uniflow_link" for r in rows) else set()
|
|
390
|
+
projected = sorted(r["name"] for r in rows if r["status"] == "uniflow_link" and r["name"] in store_ok)
|
|
391
|
+
if agent == "codex":
|
|
392
|
+
from . import projection
|
|
393
|
+
projected = sorted(set(projected) | projection.projected("codex", home, store)) # ~/.codex/skills links
|
|
394
|
+
broken = broken_projections(agent, home, store, rows)
|
|
316
395
|
rows = [r for r in rows if r["name"] and r["revision"]]
|
|
317
396
|
if not rows:
|
|
397
|
+
if projected or broken:
|
|
398
|
+
# Every crow skill here comes from Uniflow's store (updated as agent uniflow): only the guide,
|
|
399
|
+
# integrations and hooks of this CLI are refreshed.
|
|
400
|
+
from . import machine
|
|
401
|
+
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": list(broken), "error": None,
|
|
402
|
+
"via_uniflow": projected}
|
|
403
|
+
if dry_run:
|
|
404
|
+
entry["dry_run"] = True
|
|
405
|
+
try:
|
|
406
|
+
if agent == "codex" and "crow-behaviour" in [k["name"] for k in broken]:
|
|
407
|
+
reinstall_behaviour(home, entry, dry_run, trust)
|
|
408
|
+
extras = machine.refresh_extras(agent, home, dry_run, trust)
|
|
409
|
+
entry["guides"] = (extras.get("guides") or {}).get("transaction")
|
|
410
|
+
except CrowError as exc:
|
|
411
|
+
entry["error"] = {"code": exc.code, "message": str(exc)}
|
|
412
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
413
|
+
entry["error"] = {"code": "io_error", "message": "Falha de leitura/gravação; nada concluído para este agente."}
|
|
414
|
+
results.append(entry)
|
|
318
415
|
continue
|
|
319
416
|
records = store.state(target["path"])["installed"]
|
|
320
417
|
names, kept = [], []
|
|
@@ -325,10 +422,30 @@ def skills_update(home):
|
|
|
325
422
|
kept.append({"name": r["name"], "status": "other_origin"}) # update --source or install switches it
|
|
326
423
|
else:
|
|
327
424
|
names.append(r["name"])
|
|
328
|
-
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept
|
|
425
|
+
entry = {"agent": agent, "target": target["path"], "updated": [], "unchanged": 0, "kept": kept + list(broken),
|
|
426
|
+
"error": None, "via_uniflow": projected}
|
|
427
|
+
if dry_run:
|
|
428
|
+
entry["dry_run"] = True
|
|
429
|
+
if agent == "codex":
|
|
430
|
+
names = codex_duplicates(home, store, entry, names, dry_run)
|
|
431
|
+
if "crow-behaviour" in [k["name"] for k in broken] and "crow-behaviour" not in [r["name"] for r in rows]:
|
|
432
|
+
try:
|
|
433
|
+
reinstall_behaviour(home, entry, dry_run, trust)
|
|
434
|
+
except CrowError as exc:
|
|
435
|
+
entry["error"] = {"code": exc.code, "message": str(exc)}
|
|
436
|
+
if not names and not entry.get("error"):
|
|
437
|
+
from . import machine
|
|
438
|
+
try:
|
|
439
|
+
machine.refresh_extras(agent, home, dry_run, trust)
|
|
440
|
+
except CrowError as exc:
|
|
441
|
+
entry["error"] = {"code": exc.code, "message": str(exc)}
|
|
329
442
|
if names:
|
|
330
443
|
try:
|
|
331
|
-
|
|
444
|
+
argv = ["update", *names, "--agents", agent, "--global", "--dry-run" if dry_run else "--yes", "--json",
|
|
445
|
+
"--home", str(home)]
|
|
446
|
+
if not trust:
|
|
447
|
+
argv.append("--no-trust")
|
|
448
|
+
args = parser().parse_args(argv)
|
|
332
449
|
data = cli_run(args)
|
|
333
450
|
entry["updated"] = sorted({c["name"] for c in data["changes"] if c["action"] != "unchanged"})
|
|
334
451
|
entry["unchanged"] = sum(c["action"] == "unchanged" for c in data["changes"])
|
|
@@ -342,7 +459,21 @@ def skills_update(home):
|
|
|
342
459
|
return results
|
|
343
460
|
|
|
344
461
|
|
|
345
|
-
def
|
|
462
|
+
def preview(store, home, self_step=True, skills_step=True, trust=True, git_pull=None):
|
|
463
|
+
"""Dry run shared by autoupdate run --dry-run and upgrade --dry-run: nothing runs, nothing is written."""
|
|
464
|
+
state = load_state(store)
|
|
465
|
+
install = detect()
|
|
466
|
+
result = {"install": install, "applied": False, "dry_run": True,
|
|
467
|
+
"would": ["atualizar o crow-skills" if self_step else None, "update --global das skills gerenciadas, por agente"]}
|
|
468
|
+
if self_step:
|
|
469
|
+
result["self"] = preview_self(install, state.get("git_pull") if git_pull is None else git_pull)
|
|
470
|
+
if skills_step:
|
|
471
|
+
result["skills"] = skills_update(home, trust=trust, dry_run=True)
|
|
472
|
+
return result
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def run(store, home, self_step=True, skills_step=True, trust=True, git_pull=None, trigger="autoupdate"):
|
|
476
|
+
"""One run (scheduled autoupdate or crow-skills upgrade): self-upgrade, then every agent's update."""
|
|
346
477
|
try:
|
|
347
478
|
import fcntl
|
|
348
479
|
except ImportError as exc: # pragma: no cover
|
|
@@ -361,15 +492,18 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
361
492
|
log.write_text("")
|
|
362
493
|
state = load_state(store)
|
|
363
494
|
install = detect()
|
|
364
|
-
result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}}
|
|
495
|
+
result = {"startedAt": now(), "version": __version__, "install": {"kind": install["kind"]}, "trigger": trigger}
|
|
365
496
|
handed_off = False
|
|
366
497
|
if self_step:
|
|
367
|
-
result["self"] = self_upgrade(install, state.get("git_pull"))
|
|
498
|
+
result["self"] = self_upgrade(install, state.get("git_pull") if git_pull is None else git_pull)
|
|
368
499
|
after = result["self"].get("after")
|
|
369
500
|
if skills_step and after and after != __version__ and install["launcher"]:
|
|
370
501
|
# The new version updates the skills (its own snapshot is the new source).
|
|
371
502
|
try:
|
|
372
|
-
|
|
503
|
+
child_args = [install["launcher"], "autoupdate", "run", "--skills-only", "--yes", "--json"]
|
|
504
|
+
if not trust:
|
|
505
|
+
child_args.append("--no-trust")
|
|
506
|
+
done = subprocess.run(child_args,
|
|
373
507
|
capture_output=True, text=True, timeout=1200, stdin=subprocess.DEVNULL,
|
|
374
508
|
env=dict(os.environ, CROW_SKILLS_AUTOUPDATE_CHILD="1"))
|
|
375
509
|
child = json.loads(done.stdout)
|
|
@@ -380,7 +514,7 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
380
514
|
result["handoff"] = {"version": after, "ok": False}
|
|
381
515
|
handed_off = True
|
|
382
516
|
if skills_step and not handed_off:
|
|
383
|
-
result["skills"] = skills_update(home)
|
|
517
|
+
result["skills"] = skills_update(home, trust=trust)
|
|
384
518
|
result["endedAt"] = now()
|
|
385
519
|
result["ok"] = (result.get("self", {}).get("result") != "failed"
|
|
386
520
|
and all(not s.get("error") for s in result.get("skills", []))
|
|
@@ -388,7 +522,7 @@ def run(store, home, self_step=True, skills_step=True):
|
|
|
388
522
|
state = load_state(store)
|
|
389
523
|
state["lastRun"] = result
|
|
390
524
|
history = state.get("history") or []
|
|
391
|
-
history.append({"startedAt": result["startedAt"], "ok": result["ok"],
|
|
525
|
+
history.append({"startedAt": result["startedAt"], "ok": result["ok"], "trigger": trigger,
|
|
392
526
|
"updated": sum(len(s.get("updated") or []) for s in result.get("skills", [])),
|
|
393
527
|
"self": (result.get("self") or {}).get("result")})
|
|
394
528
|
state["history"] = history[-HISTORY:]
|