@andespindola/crow-skills 0.7.1 → 0.8.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.
@@ -31,6 +31,20 @@ MAX_LEDGER = 2 * 1024 * 1024
31
31
  MAX_LOG_LINE = 8 * 1024 * 1024
32
32
  RECENT_DONE = 300 # seconds a finished run stays visible in compact views
33
33
  STALE = 2 * 3600 # a "running" ledger untouched for this long is treated as abandoned
34
+ MAX_AGENT_ROWS = 6 # process rows shown in a status line before "+N"
35
+
36
+
37
+ def hook_module():
38
+ """The mode/event helpers: the package module, or crow_hook.py copied beside this script."""
39
+ try:
40
+ from . import hook # type: ignore[attr-defined]
41
+ return hook
42
+ except ImportError:
43
+ try:
44
+ import crow_hook as hook # sibling copy in the integrations directory
45
+ return hook
46
+ except ImportError:
47
+ return None
34
48
 
35
49
 
36
50
  # --- ledger -------------------------------------------------------------------------
@@ -501,6 +515,7 @@ def render(run, usage=None, now=None, color=False, unicode=True, width=20):
501
515
  bar(info["progress"], width, unicode) + " " + str(int(info["progress"] * 100)).rjust(3) + "% " +
502
516
  str(info["done"]) + "/" + str(info["total"]) + " unidades" +
503
517
  (" - " + str(info["failed"]) + " falha(s)" if info["failed"] else "") + " " + token_text(usage, unicode)]
518
+ lines += ["", *agent_rows(run, unicode, counts=False), ""]
504
519
  phase_ids = [p["id"] for p in run["phases"]]
505
520
  groups = [(p, [u for u in run["units"] if u["phase"] == p["id"]]) for p in run["phases"]]
506
521
  loose = [u for u in run["units"] if u["phase"] not in phase_ids]
@@ -527,6 +542,50 @@ def render(run, usage=None, now=None, color=False, unicode=True, width=20):
527
542
  return "\n".join(lines)
528
543
 
529
544
 
545
+ def owner_label(owner):
546
+ """subagent:leitor -> leitor; workflow:x and sequential stay as written."""
547
+ owner = owner or "main"
548
+ return owner.split(":", 1)[1] if owner.startswith("subagent:") and owner[9:] else owner
549
+
550
+
551
+ def agent_rows(run, unicode=True, limit=None, counts=True):
552
+ """Live process list, like the host's own agent list:
553
+
554
+ ● main <what the coordinator is doing>
555
+ ○ <owner> <running unit>
556
+ ✓ 3 concluídas · ✗ 1 falhou · 2 pendentes
557
+
558
+ Rows come only from the ledger (units the coordinator recorded); nothing is invented.
559
+ """
560
+ dot, ring = ("●", "○") if unicode else ("*", "o")
561
+ sep = " · " if unicode else " - "
562
+ running = [u for u in run["units"] if u["status"] == "running"]
563
+ mine = [u for u in running if owner_label(u["owner"]) in ("main", "sequential")]
564
+ others = [u for u in running if u not in mine]
565
+ head = dot + " main"
566
+ if mine:
567
+ head += " " + safe(mine[0]["title"], 60) + (" (+" + str(len(mine) - 1) + ")" if len(mine) > 1 else "")
568
+ elif run["status"] == "running":
569
+ head += " " + safe(run["title"], 60)
570
+ lines = [head]
571
+ shown = others if limit is None else others[:limit]
572
+ for unit in shown:
573
+ lines.append(ring + " " + safe(owner_label(unit["owner"]), 32) + " " + safe(unit["title"], 60))
574
+ if limit is not None and len(others) > limit:
575
+ lines.append(ring + " +" + str(len(others) - limit))
576
+ if counts:
577
+ done = sum(u["status"] == "done" for u in run["units"])
578
+ failed = sum(u["status"] == "failed" for u in run["units"])
579
+ pending = sum(u["status"] == "pending" for u in run["units"])
580
+ parts = [("✓ " if unicode else "ok ") + str(done) + " concluída(s)"]
581
+ if failed:
582
+ parts.append(("✗ " if unicode else "x ") + str(failed) + " falha(s)")
583
+ if pending:
584
+ parts.append(str(pending) + " pendente(s)")
585
+ lines.append(sep.join(parts))
586
+ return lines
587
+
588
+
530
589
  def compact(run, usage=None, unicode=True, width=10):
531
590
  info = summary(run)
532
591
  mark = "✓" if run["status"] == "done" else ("✗" if run["status"] in ("failed", "cancelled") else "▸")
@@ -580,19 +639,41 @@ def watch(cwd, home, run_id=None, interval=1.0, stream=None, linger=5.0, max_fra
580
639
  return 0
581
640
 
582
641
 
583
- def statusline(home, stdin_text, chain=None):
584
- """Claude Code statusLine: one line; the previous status line (if chained) comes first."""
642
+ def mode_text(home, unicode=True):
643
+ hook = hook_module()
644
+ if hook is None:
645
+ return ""
646
+ try:
647
+ return hook.indicator(hook.read_mode(home)["mode"], unicode)
648
+ except (OSError, ValueError, KeyError):
649
+ return ""
650
+
651
+
652
+ def statusline(home, stdin_text, chain=None, host="claude"):
653
+ """Status line for Claude Code and Antigravity (agy).
654
+
655
+ First line: the previous (chained) status line, the mode indicator and the compact
656
+ run; then one row per running unit of the ledger, like the host's agent list. agy
657
+ stacks it under its default line (stack_with_default), so no chain is needed there.
658
+ """
585
659
  try:
586
660
  payload = json.loads(stdin_text) if stdin_text.strip() else {}
587
661
  except ValueError:
588
662
  payload = {}
589
663
  if not isinstance(payload, dict):
590
664
  payload = {}
591
- cwd = (payload.get("workspace") or {}).get("current_dir") or payload.get("cwd") or os.getcwd()
665
+ workspace = payload.get("workspace") if isinstance(payload.get("workspace"), dict) else {}
666
+ cwd = workspace.get("current_dir") or payload.get("cwd") or os.getcwd()
592
667
  transcript = payload.get("transcript_path")
593
- session = payload.get("session_id")
668
+ session = payload.get("session_id") or payload.get("conversation_id")
594
669
  if not (isinstance(session, str) and session):
595
670
  session = Path(transcript).stem if isinstance(transcript, str) and transcript.endswith(".jsonl") else None
671
+ hook = hook_module()
672
+ if hook is not None:
673
+ try:
674
+ hook.update_metrics(home, host, payload)
675
+ except Exception: # noqa: BLE001 - metrics never break the status line
676
+ pass
596
677
  previous = ""
597
678
  if chain:
598
679
  try:
@@ -603,9 +684,10 @@ def statusline(home, stdin_text, chain=None):
603
684
  except (OSError, subprocess.SubprocessError):
604
685
  previous = ""
605
686
  run = select(discover(cwd, home), cwd, strict=True, session=session)
606
- ours = ""
687
+ parts = [p for p in (mode_text(home),) if p]
688
+ rows = []
607
689
  if active(run):
608
- if run["host"] == "claude" and not run["session"].get("id") and session:
690
+ if run["host"] == "claude" and host == "claude" and not run["session"].get("id") and session:
609
691
  # The status line knows its own session: exact usage instead of every session in the directory.
610
692
  try:
611
693
  usage = claude_tokens(dict(run, session={"id": session}), Path(home), *window(run))
@@ -613,19 +695,28 @@ def statusline(home, stdin_text, chain=None):
613
695
  usage = None
614
696
  else:
615
697
  usage = tokens(run, home)
616
- ours = compact(run, usage)
698
+ parts.append(compact(run, usage))
699
+ if run["status"] == "running":
700
+ rows = agent_rows(run, limit=MAX_AGENT_ROWS, counts=False)
701
+ if len(rows) == 1:
702
+ rows = [] # only "● main": the compact segment already says it
703
+ ours = " │ ".join(parts)
617
704
  if not previous.strip():
618
- return ours
619
- if not ours:
620
- return previous
621
- return previous + " │ " + ours
705
+ first_line = ours
706
+ elif not ours:
707
+ first_line = previous
708
+ else:
709
+ first_line = previous + " │ " + ours
710
+ return "\n".join([first_line, *rows]) if rows else first_line
622
711
 
623
712
 
624
713
  def tmux_segment(home, cwd):
714
+ mode = mode_text(home)
625
715
  run = select(discover(cwd, home), cwd, strict=True)
626
716
  if not active(run):
627
- return ""
628
- return compact(run, tokens(run, home), unicode=True, width=8).replace("#", "##")
717
+ return mode
718
+ text = compact(run, tokens(run, home), unicode=True, width=8)
719
+ return ((mode + " · " if mode else "") + text).replace("#", "##")
629
720
 
630
721
 
631
722
  def main(argv=None):
@@ -636,6 +727,7 @@ def main(argv=None):
636
727
  p.add_argument("--cwd", default=None)
637
728
  p.add_argument("--home", default=None)
638
729
  p.add_argument("--chain-file", default=None, help="JSON com o comando de status line anterior, encadeado antes do crow")
730
+ p.add_argument("--host", default="claude", choices=("claude", "agy"), help="CLI que chama a status line")
639
731
  args = p.parse_args(argv)
640
732
  home = Path(args.home).expanduser() if args.home else Path.home()
641
733
  cwd = args.cwd or os.getcwd()
@@ -646,7 +738,7 @@ def main(argv=None):
646
738
  chain = json.loads(Path(args.chain_file).read_text(encoding="utf-8")).get("command")
647
739
  except (OSError, ValueError, AttributeError):
648
740
  chain = None
649
- print(statusline(home, sys.stdin.read() if not sys.stdin.isatty() else "", chain))
741
+ print(statusline(home, sys.stdin.read() if not sys.stdin.isatty() else "", chain, args.host))
650
742
  return 0
651
743
  if args.mode == "tmux":
652
744
  print(tmux_segment(home, cwd))
@@ -8,6 +8,11 @@ import stat
8
8
  import subprocess
9
9
 
10
10
  NAME = re.compile(r"crow-[a-z0-9]+(?:-[a-z0-9]+)*\Z")
11
+ PACKAGE = "@andespindola/crow-skills"
12
+ # Where a packaged release (npm tarball, also used by the Homebrew formula) lives. The
13
+ # version is part of the Homebrew path and npx caches, so it changes on every upgrade.
14
+ PACKAGED = (re.compile(r"/Cellar/crow-skills/[^/]+/libexec\Z"), re.compile(r"/node_modules/@andespindola/crow-skills\Z"),
15
+ re.compile(r"/_npx/[^/]+/node_modules/@andespindola/crow-skills\Z"))
11
16
  SHA = re.compile(r"[a-f0-9]{40,64}\Z")
12
17
  MAX_FILE = 8 * 1024 * 1024
13
18
  MAX_PACKAGE = 32 * 1024 * 1024
@@ -80,7 +85,9 @@ class Source:
80
85
  if ref not in ("HEAD", self.revision):
81
86
  raise CrowError("immutable_release", "A referência não está neste snapshot npm; selecione um clone Git para outras refs.")
82
87
  raw = self.bundle_file("catalog.json")
88
+ self.identity = self._bundle_identity()
83
89
  else:
90
+ self.identity = "git:" + str(self.path)
84
91
  if fetch:
85
92
  self.git("fetch", "--no-recurse-submodules", "origin", timeout=120)
86
93
  self.revision = self.git("rev-parse", "--verify", "--end-of-options", ref + "^{commit}").decode().strip()
@@ -138,6 +145,18 @@ class Source:
138
145
  except (OSError, ValueError, TypeError, KeyError) as exc:
139
146
  raise CrowError("invalid_release", "Manifesto do snapshot npm inválido.") from exc
140
147
 
148
+ def _bundle_identity(self):
149
+ """A verified snapshot of the published package: same identity on every version/path."""
150
+ try:
151
+ name = json.loads(self.bundle_file("package.json")).get("name")
152
+ except (CrowError, ValueError, AttributeError):
153
+ name = None
154
+ # Only where a release really lives (Homebrew Cellar, npm global, npx cache): a folder
155
+ # elsewhere that merely claims the name is another origin.
156
+ if name == PACKAGE and any(p.search(str(self.path)) for p in PACKAGED):
157
+ return "package:" + name
158
+ return "bundle:" + str(self.path)
159
+
141
160
  def bundle_file(self, name):
142
161
  safe_relative(name)
143
162
  try:
@@ -254,3 +273,24 @@ class Source:
254
273
  except (ValueError, KeyError, UnicodeError) as exc:
255
274
  raise CrowError("invalid_package", "Frontmatter/referências do pacote não correspondem ao catálogo.") from exc
256
275
  return Package(name, files, entries_for(files))
276
+
277
+
278
+ def identity_of(record_source, record_identity=None):
279
+ """Identity recorded for an installation. Records made before 0.8.0 only kept the path:
280
+ a packaged-release path (Homebrew Cellar, npm global or npx cache) means the package."""
281
+ if record_identity:
282
+ return record_identity
283
+ if isinstance(record_source, str) and any(p.search(record_source) for p in PACKAGED):
284
+ return "package:" + PACKAGE
285
+ return "git:" + str(record_source)
286
+
287
+
288
+ def source_identity(source):
289
+ return getattr(source, "identity", None) or "git:" + str(source.path)
290
+
291
+
292
+ def same_source(record, source):
293
+ """An update keeps the recorded origin: the same path, or the same package at another version."""
294
+ if record.get("source") == str(source.path):
295
+ return True
296
+ return identity_of(record.get("source"), record.get("source_id")) == source_identity(source)
@@ -16,7 +16,7 @@ import stat
16
16
  import uuid
17
17
 
18
18
  from .agents import uniflow_store
19
- from .source import CrowError, MAX_FILE, MAX_PACKAGE, MAX_FILES, SHA, digest, file_entry, safe_relative, valid_name
19
+ from .source import CrowError, MAX_FILE, MAX_PACKAGE, MAX_FILES, SHA, digest, file_entry, safe_relative, same_source, source_identity, valid_name
20
20
 
21
21
 
22
22
  def checked(path):
@@ -314,8 +314,9 @@ class Store:
314
314
  raise CrowError("unmanaged_conflict", "Destino já existe e não é gerenciado: " + name + ". Use --replace após revisar.")
315
315
  new = None
316
316
  if command != "uninstall":
317
- if record and command == "update" and record.get("source") != str(source.path):
318
- raise CrowError("source_mismatch", "Update requer a mesma origem; selecione --source explicitamente.")
317
+ if record and command == "update" and not same_source(record, source):
318
+ raise CrowError("source_mismatch", "Update requer a mesma origem (o mesmo clone, ou o mesmo pacote "
319
+ "publicado em outra versão); para trocar de origem, use install com --source.")
319
320
  if name not in packages:
320
321
  packages[name] = source.package(name)
321
322
  new = packages[name].entries
@@ -337,7 +338,7 @@ class Store:
337
338
  after[key]["installed"].pop(name)
338
339
  else:
339
340
  after[key]["installed"][name] = {
340
- "revision": source.revision, "source": str(source.path), "entries": new,
341
+ "revision": source.revision, "source": str(source.path), "source_id": source_identity(source), "entries": new,
341
342
  "package_sha256": digest(new), "agents": target_info["agents"],
342
343
  "installed_at": datetime.now(timezone.utc).isoformat(),
343
344
  }
package/docs/cli.md CHANGED
@@ -1,6 +1,6 @@
1
- # crow-skills CLI 0.7.1
1
+ # crow-skills CLI 0.8.0
2
2
 
3
- CLI local-first para humanos e agentes. Python 3.10+, sem bibliotecas Python externas; Git é necessário para fontes em clone, não para o snapshot npm. O launcher npm requer Node 18+. Mutações suportadas em macOS/Linux (locks POSIX). Não instala o agente, não executa scripts das skills e não muda modelos, prompts base ou permissões. Instruções de uso das skills (o guia do agente, abaixo) são gravadas pelo comando `guide` e, por padrão, por `install`/`update`/`uninstall` em `--global` quando a crow-behaviour fica instalada para um agente com mecanismo verificado; `--no-guide` desliga isso. Os mesmos comandos também aplicam as [integrações de interface](#integrações-de-interface-integrations) (status line do Claude Code e do Codex, segmento tmux); `--no-integrations` desliga. `crow-skills progress` mostra o [painel de progresso](#progresso-progress) da execução crow-behaviour ativa.
3
+ CLI local-first para humanos e agentes. Python 3.10+, sem bibliotecas Python externas; Git é necessário para fontes em clone, não para o snapshot npm. O launcher npm requer Node 18+. Mutações suportadas em macOS/Linux (locks POSIX). Não instala o agente, não executa scripts das skills e não muda modelos, prompts base ou permissões. Instruções de uso das skills (o guia do agente, abaixo) são gravadas pelo comando `guide` e, por padrão, por `install`/`update`/`uninstall` em `--global` quando a crow-behaviour fica instalada para um agente com mecanismo verificado; `--no-guide` desliga isso. Os mesmos comandos também aplicam as [integrações de interface](#integrações-de-interface-integrations) (status lines do Claude Code, do Codex e do Antigravity, hooks do modo crow em cada CLI, comando `/crow`, segmento tmux); `--no-integrations` desliga. `crow-skills mode on|off` liga e desliga a crow-behaviour em [todas as sessões e CLIs](#modo-crow-mode); `crow-skills progress` mostra o [painel de progresso](#progresso-progress) da execução ativa; `crow-skills events` expõe o [barramento de eventos](#eventos-events) dos hooks; `crow-skills autoupdate on` liga a [atualização automática](#atualização-automática-autoupdate).
4
4
 
5
5
  ## Executar
6
6
 
@@ -31,7 +31,7 @@ Para testar/distribuir o arquivo local sem registry:
31
31
 
32
32
  ```sh
33
33
  npm pack
34
- npm install -g ./andespindola-crow-skills-0.7.1.tgz --ignore-scripts
34
+ npm install -g ./andespindola-crow-skills-0.8.0.tgz --ignore-scripts
35
35
  ```
36
36
 
37
37
  O pacote contém o CLI Python e todas as skills do commit, com `release.json` de hashes. Não requer acesso ao GitHub ou clone para list/install. O launcher Node encaminha argumentos sem shell para Python em modo isolado, evitando imports pelo diretório do chamador/PYTHONPATH. `CROW_SKILLS_PYTHON` pode apontar para outro executável Python 3.10+. Não há dependências npm nem hooks de instalação que instalem skills automaticamente.
@@ -80,9 +80,9 @@ A fonte em checkout deve ser um clone Git já existente. O padrão é o checkout
80
80
 
81
81
  `--fetch` busca `origin` somente quando solicitado, usando credenciais Git externas; não atualiza o checkout. É incompatível com `--dry-run`. Sem fetch, uma ref remota pode estar desatualizada. Git replace-objects e hooks não são usados para interpretar a fonte; erros de Git não imprimem stderr que possa conter credenciais. URL arbitrária/credencial não é argumento suportado de `--source`.
82
82
 
83
- Atualização é explícita. `update` sem nomes atualiza apenas instalações gerenciadas nos destinos selecionados; não instala o catálogo inteiro. A origem deve corresponder à registrada. Mudança intencional de origem requer install/revisão explícita, não troca silenciosa durante update.
83
+ Atualização é explícita (ou agendada com [autoupdate](#atualização-automática-autoupdate)). `update` sem nomes atualiza apenas instalações gerenciadas nos destinos selecionados; não instala o catálogo inteiro. A origem deve corresponder à registrada. Mudança intencional de origem requer install/revisão explícita, não troca silenciosa durante update.
84
84
 
85
- No npm, primeiro atualize o pacote npm e então execute o update das skills, ou escolha uma fonte Git explicitamente. Com npx, o caminho de cache pode mudar entre versões; nesse caso, use install explícito para revisar/registrar a nova origem em vez de contornar source_mismatch.
85
+ Desde a 0.8.0, a origem registrada é também uma identidade (`source_id`): `git:<caminho do clone>` para um clone, ou `package:@andespindola/crow-skills` para o snapshot publicado, só quando ele está onde um release é instalado (Cellar do Homebrew, `lib/node_modules` do npm global, cache do npx); uma pasta em outro lugar que só declare esse nome é `bundle:<caminho>`, outra origem. O caminho do pacote muda a cada versão (`.../Cellar/crow-skills/<versão>/libexec`, cache do npx), mas a identidade não: `update` aceita o mesmo pacote em outro caminho e registra o novo. Registros anteriores à 0.8.0, que só guardavam o caminho, são reconhecidos pelo formato do caminho de um pacote publicado (Cellar do Homebrew, `node_modules/@andespindola/crow-skills`). Um snapshot com outro nome de pacote, ou um clone Git, continua sendo outra origem: `source_mismatch`, e a troca exige install. No npm, primeiro atualize o pacote e então execute o update das skills (o autoupdate faz os dois).
86
86
 
87
87
  ## Estado, conflitos e recuperação
88
88
 
@@ -139,7 +139,7 @@ Erros retornam `ok:false` e `error.code/message`. Saídas reais incluem alteraç
139
139
 
140
140
  Codex/shared são deduplicados quando apontam para o mesmo diretório. O diretório compartilhado também pode ser lido por outros hosts; não é isolamento entre agentes. `.codex/skills` é uma localização legada encontrada em ambientes existentes; o adaptador usa a localização moderna documentada. Para um destino legado específico, use `--dest` explicitamente.
141
141
 
142
- `agents` só verifica PATH e caminhos, sem iniciar agente/LLM. `status`/`doctor` conferem arquivos e estado de instalação, não provam carregamento, ativação, independência dos workers ou execução correta da skill. Gemini oferece `/skills reload`; para outros hosts, confira sua lista/reload ou reinicie a sessão conforme a versão. Nenhum hook ou system prompt base é alterado para forçar uso; o guia abaixo, aplicado por padrão em `--global` e desligável com `--no-guide`, é aditivo.
142
+ `agents` só verifica PATH e caminhos, sem iniciar agente/LLM. `status`/`doctor` conferem arquivos e estado de instalação, não provam carregamento, ativação, independência dos workers ou execução correta da skill. Gemini oferece `/skills reload`; para outros hosts, confira sua lista/reload ou reinicie a sessão conforme a versão. Nenhum system prompt base é alterado; o guia abaixo e os hooks do modo crow, aplicados por padrão em `--global` e desligáveis com `--no-guide` e `--no-integrations`, são aditivos: só informam ao agente o modo escolhido pelo usuário.
143
143
 
144
144
  ### Uniflow
145
145
 
@@ -177,7 +177,7 @@ crow-skills guide status
177
177
  crow-skills guide uninstall --agents codex --global --yes
178
178
  ```
179
179
 
180
- `guide` grava, no mecanismo nativo e sempre carregado de cada CLI, instruções curtas em pt-BR para o agente usar as skills instaladas: carregar a crow-behaviour por iniciativa própria antes de tarefas substantivas (várias etapas ou partes, decisões, vários arquivos, verificação), responder direto em conversa ou ajuste trivial, consultar a lista de skills disponíveis no agente (crow ou não) e carregar a especialista pertinente pelo nome. O conteúdo é gerado do catálogo e das skills gerenciadas pelo CLI naquele agente, com a forma de invocação dele. Exige a crow-behaviour instalada para o agente.
180
+ `guide` grava, no mecanismo nativo e sempre carregado de cada CLI, instruções curtas em pt-BR para o agente usar as skills instaladas: obedecer ao [modo crow](#modo-crow-mode) vigente (anunciado pelo hook a cada prompt ou, sem hook, lido de `~/.config/crow-skills/mode.json`), carregar a crow-behaviour por iniciativa própria antes de tarefas substantivas (várias etapas ou partes, decisões, vários arquivos, verificação), responder direto em conversa ou ajuste trivial, consultar a lista de skills disponíveis no agente (crow ou não) e carregar a especialista pertinente pelo nome. O conteúdo é gerado do catálogo e das skills gerenciadas pelo CLI naquele agente, com a forma de invocação dele. Exige a crow-behaviour instalada para o agente.
181
181
 
182
182
  Aplicação automática (padrão em `install`, `update` e `uninstall` com `--global`, desligada por `--no-guide`):
183
183
 
@@ -211,6 +211,8 @@ crow-skills progress --watch # redesenha a cada segundo; sai sozinho ap
211
211
  crow-skills progress --run ID --json # leitura por agente/automação
212
212
  ```
213
213
 
214
+ O painel começa pela lista de processos no formato da lista de agentes do host: `● main <atividade do coordenador>` e uma linha `○ <dono> <atividade>` por unidade em andamento de outro dono (o prefixo `subagent:` sai do nome). É o mesmo bloco que a crow-behaviour mostra na conversa (`crow_ledger.py show`) e que a status line do Claude Code e do Antigravity exibem abaixo da linha principal.
215
+
214
216
  Lê o ledger `crow-run/1` que a crow-behaviour mantém em tarefas substantivas (formato em `skills/crow-behaviour/references/progress-ledger.md`): `$CROW_LEDGER`, `.crow/runs/*.json` no diretório atual e nos pais, e `~/.crow/runs/`. Sem `--run`, prefere execuções do diretório (ou de pais e filhos dele), depois as em andamento, depois a mais recente; um ledger `running` sem atualização há mais de 2 h conta como abandonado. Status line e tmux só mostram execuções do próprio diretório. Somente leitura; não inicia agentes.
215
217
 
216
218
  Tokens vêm dos logs locais do próprio host, filtrados pela janela da execução (`startedAt` até `endedAt` ou agora) e pela sessão (`session.id` no ledger) ou, sem ela, pelo diretório de trabalho (marcado como aproximado, pois outras sessões no mesmo diretório e janela entram na soma). Só campos numéricos de uso são lidos e impressos; conteúdo de mensagens, prompts e credenciais nunca é exibido.
@@ -237,13 +239,21 @@ crow-skills integrations uninstall --global --yes
237
239
  crow-skills install crow-behaviour --agents claude --global --no-integrations --yes # sem integrações
238
240
  ```
239
241
 
240
- Aplicadas por padrão junto com `install`/`update` em `--global` para os agentes selecionados que ficam com a crow-behaviour, e removidas quando ela sai (`uninstall`, `rollback`, `recover`). `--no-integrations` desliga o passo; `--project`/`--dest` não têm integração. São um passo posterior às transações de skills e guia: uma recusa aparece em `integrations.skipped` e não desfaz as skills.
242
+ Aplicadas por padrão junto com `install`/`update` em `--global` para os agentes selecionados que ficam com a crow-behaviour, e removidas quando ela sai (`uninstall`, `rollback`, `recover`). `--no-integrations` desliga o passo; `--project`/`--dest` não têm integração. São um passo posterior às transações de skills e guia: uma recusa aparece em `integrations.skipped` e não desfaz as skills. Integrações de um CLI que não está configurado no perfil (sem `~/.codex`, `~/.gemini/settings.json`, `~/.gemini/antigravity-cli` ou `~/.config/devin/config.json`) são puladas com o motivo, sem criar arquivos.
241
243
 
242
- | Integração | Agentes | Mecanismo | O que mostra |
244
+ | Integração | Agentes | Mecanismo | O que faz |
243
245
  |---|---|---|---|
244
- | claude-statusline | claude | chave `statusLine` (`type: command`) em `~/.claude/settings.json` | `crow ▸ título x/y ████░░ 46% · 1.2M tok` enquanto houver execução ativa no diretório da sessão (nunca de outro projeto, nunca uma execução gravada para outra sessão, nunca um ledger `running` parado há mais de 2 h); tokens da transcrição da sessão, com `~` quando forem aproximados |
246
+ | claude-statusline | claude | chave `statusLine` (`type: command`) em `~/.claude/settings.json` | 1ª linha: `▸▸ crow on │ crow ▸ título x/y ████░░ 46% · 1.2M tok` (o indicador sempre; o resto enquanto houver execução ativa no diretório da sessão, nunca de outro projeto, de outra sessão ou de um ledger parado há mais de 2 h); linhas seguintes: a lista de processos (`● main …`, `○ dono atividade`, até 6) |
247
+ | claude-hooks | claude | entradas em `hooks` de `~/.claude/settings.json` | modo por prompt (`UserPromptSubmit`, síncrono) e eventos (demais, `async: true`) |
248
+ | claude-command | claude | `~/.claude/commands/crow.md` (arquivo próprio) | `/crow on\|off\|status`: roda o toggle por `!` com `allowed-tools` restrito ao script; `disable-model-invocation` impede o modelo de chamá-lo |
245
249
  | codex-statusline | codex | `[tui].status_line` em `~/.codex/config.toml`, em bloco marcado | itens nativos `model-with-reasoning`, `context-remaining`, `current-dir`, `task-progress`, `used-tokens`; `task-progress` reflete o plano nativo que a skill espelha |
246
- | tmux-status | claude, codex, gemini (agy), devin | `~/.config/crow-skills/tmux.conf` (arquivo próprio) e um bloco `source-file -q` no fim do seu `tmux.conf` | segmento acrescentado ao `status-right` (`set -ag`, sem substituir o seu), com o diretório do painel ativo |
250
+ | codex-hooks | codex | entradas em `~/.codex/hooks.json` | modo por prompt, `/crow on\|off\|status` interceptado e bloqueado com o resultado, `systemMessage` com o modo no início da sessão e quando muda, eventos (`async: true`) |
251
+ | gemini-hooks | gemini (Gemini CLI) | `hooks` em `~/.gemini/settings.json` | modo por prompt (`BeforeAgent`), `systemMessage` quando muda, eventos |
252
+ | gemini-command | gemini (Gemini CLI) | `~/.gemini/commands/crow.toml` (arquivo próprio) | `/crow on\|off\|status` por `!{…}` (o Gemini pede confirmação do shell, salvo política que o permita) |
253
+ | agy-hooks | gemini (Antigravity) | chave `crow-skills` em `~/.gemini/config/hooks.json` | modo por prompt (`PreInvocation` → `injectSteps`), `/crow …` interceptado quando o agy envia o texto (`lastUserInput`, 1.4.7+), eventos |
254
+ | agy-statusline | gemini (Antigravity) | `statusLine` em `~/.gemini/antigravity-cli/settings.json` com `stack_with_default: true` | indicador e lista de processos empilhados sob a linha padrão do agy |
255
+ | devin-hooks | devin | `hooks` em `~/.config/devin/config.json` | modo por prompt, `/crow …` interceptado, `systemMessage` quando muda, eventos |
256
+ | tmux-status | claude, codex, gemini (agy), devin | `~/.config/crow-skills/tmux.conf` (arquivo próprio) e um bloco `source-file -q` no fim do seu `tmux.conf` | `▸▸ crow on · crow ▸ …` acrescentado ao `status-right` (`set -ag`, sem substituir o seu), com o diretório do painel ativo |
247
257
 
248
258
  Regras de preservação:
249
259
 
@@ -251,12 +261,81 @@ Regras de preservação:
251
261
  - Claude: um `statusLine` existente do tipo `command` é encadeado: o comando anterior roda primeiro, com o mesmo stdin, sua saída é mantida inteira (todas as linhas, espaços internos) e o segmento crow entra no fim da última linha; as demais chaves dele (`padding` etc.) são preservadas. Outro tipo é mantido e a integração é pulada. Se você mudar o `statusLine` depois, ele não é sobrescrito nem removido. No uninstall, se `settings.json` ainda tiver exatamente o que o crow-skills gravou, os bytes originais do backup voltam; se você editou outra parte do arquivo, a restauração é só da chave `statusLine` (JSON reescrito com indentação 2).
252
262
  - Codex: só aplicado se você ainda não definiu `tui.status_line`; um `[tui]` existente recebe o bloco logo após o cabeçalho, senão o bloco cria a tabela no fim do arquivo. A edição é verificada por parse TOML (Python 3.11+). O uninstall só remove o bloco se ele estiver como foi gravado e se o resultado tiver as mesmas chaves que o arquivo atual menos `tui.status_line`; sem outras edições, o arquivo volta byte a byte. Chaves acrescentadas a um `[tui]` criado pelo crow-skills mantêm o cabeçalho `[tui]`; bloco editado ou remoção que mudaria outra chave é recusado e reportado em `skipped`. O Codex não aceita comando externo na status line, então ela não lê o ledger.
253
263
  - tmux: só quando o `tmux` está no PATH e já existe `~/.tmux.conf` ou `~/.config/tmux/tmux.conf`. Se o `tmux.conf` for symlink, o snippet é instalado mas o arquivo não é editado: o resultado traz a linha `source-file -q ...` para você adicionar. O snippet acrescenta o segmento só quando `status-right` ainda não o contém, então ele volta depois de cada `tmux source-file` do seu `tmux.conf` sem duplicar. O diretório do painel chega ao script escapado por `#{q:pane_current_path}` (tmux 3.0 ou mais novo): nome de diretório com `$(...)` ou crase não é executado. Depois de remover, o segmento sai da sessão atual quando o `status-right` é redefinido (recarregar um `tmux.conf` que o define) ou quando o servidor tmux reinicia.
254
- - O script usado pela status line e pelo tmux é uma cópia de `crow_skills/progress.py` em `~/.local/state/crow-skills/integrations/`, executada com o `python3` do PATH no momento da instalação; não depende do caminho do cache npm.
264
+ - Hooks: as entradas do crow-skills são acrescentadas depois das suas, em todos os eventos (no Codex, a aprovação de `/hooks` é por índice, então o hook que você já aprovou continua aprovado), e reconhecidas pelo caminho do script. No Antigravity, ficam numa chave própria (`crow-skills`) de `hooks.json`, ao lado das suas. Uninstall tira só essas entradas; se ninguém mais editou o arquivo, os bytes originais voltam.
265
+ - Arquivos JSON compartilhados por duas integrações (o `settings.json` do Claude Code recebe a status line e os hooks) têm um único ponto de restauração por arquivo: o conteúdo antes da primeira gravação do crow-skills. Removidas as duas, ele volta byte a byte; se o arquivo foi editado por você no meio do caminho, só as chaves/entradas do crow-skills saem.
266
+ - O Devin também lê os hooks do `~/.claude/settings.json`. Para não duplicar nem rotular errado, o hook instalado para o Claude Code só age quando quem o executa é o Claude Code: a transcrição informada fica em `~/.claude/projects` (ou em `$CLAUDE_CONFIG_DIR/projects`), ou, sem transcrição, o ambiente traz `CLAUDECODE=1` (exportado pelo Claude Code para os processos filhos); um campo exclusivo do Devin (`tool_provenance`) também o silencia. O Devin usa a entrada própria, rotulada `devin`. Do mesmo modo, a entrada do Gemini CLI fica em silêncio quando o Antigravity a executa (`ANTIGRAVITY_AGENT=1`).
267
+ - Codex: hooks novos ou alterados só rodam depois de aprovados em `/hooks` dentro do Codex, e só com `[features] hooks = true` no `config.toml`; o crow-skills não altera esse flag e avisa na nota da instalação quando ele falta.
268
+ - Os scripts usados pela status line, pelo tmux, pelos hooks e pelos comandos `/crow` são cópias de `crow_skills/progress.py` (`crow_progress.py`) e `crow_skills/hook.py` (`crow_hook.py`) em `~/.local/state/crow-skills/integrations/`, executadas com o `python3` do PATH no momento da instalação (os hooks com `-I -S`); não dependem do caminho do cache npm ou do Homebrew.
269
+
270
+ Sem superfície que mostre um valor externo persistente (conferido em 2026-10-28, Codex CLI 0.165.0, Gemini CLI 0.66.0, Devin CLI 3000.11.228):
271
+
272
+ - Codex: `[tui].status_line` e `terminal_title` só aceitam itens nativos; o rodapé não mostra o modo crow. O hook mostra `▸▸ crow on|off` como `systemMessage` no início da sessão e quando o modo muda.
273
+ - Gemini CLI: `ui.footer.items` aceita só itens nativos; idem, `systemMessage` quando muda.
274
+ - Devin CLI: sem status line ou rodapé configurável; idem, `systemMessage` quando muda.
275
+ - Nenhum CLI aceita alimentar a lista nativa de subagentes de fora; a lista de processos vem do ledger (status line do Claude Code e do agy, `crow-skills progress`, bloco no chat).
276
+
277
+ O Antigravity (`agy`, agente `gemini` do instalador) ganhou `statusLine` por comando: a integração agy-statusline usa `stack_with_default` (o agy desliga a status line após falhas seguidas; o script sempre sai com código 0). O formato da chave foi lido do binário 1.4.4 e das notas de versão, sem sessão de verificação: se a linha não aparecer, rode `/statusline` no agy. No ledger, o host dele é `agy`; `gemini` no ledger significa Gemini CLI. Para os demais, use o segmento tmux ou `crow-skills progress --watch` num painel ao lado.
278
+
279
+ ## Modo crow (mode)
280
+
281
+ ```sh
282
+ crow-skills mode # status: ▸▸ crow on
283
+ crow-skills mode off # desliga em todas as sessões e CLIs, a partir do próximo prompt
284
+ crow-skills mode on
285
+ crow-skills mode toggle --json
286
+ ```
287
+
288
+ O modo é um interruptor único para a crow-behaviour em todos os CLIs. `on` (padrão, também quando o arquivo não existe) é o modo de orquestração permanente: o agente carrega e segue a crow-behaviour em toda tarefa substantiva, sem o usuário pedir. `off`: o agente não a carrega nem aplica, salvo se o usuário a invocar no pedido; as especialistas continuam disponíveis. O estado fica em `~/.config/crow-skills/mode.json` (`crow-mode/1`, gravação atômica com `updatedAt` e quem mudou).
289
+
290
+ Como cada CLI fica sabendo, sem reiniciar a sessão:
291
+
292
+ | CLI | A cada prompt | Alternar dentro da sessão | Indicador visível |
293
+ |---|---|---|---|
294
+ | Claude Code | hook `UserPromptSubmit` injeta `[crow-skills] modo crow: ON\|OFF` | `/crow on\|off\|status` (`~/.claude/commands/crow.md`) | status line `▸▸ crow on` |
295
+ | Codex | hook `UserPromptSubmit` (após aprovar em `/hooks`) | prompt exatamente `/crow on\|off\|status`: o hook alterna e bloqueia o prompt com o resultado | `systemMessage` no início e quando muda; o rodapé não aceita item externo |
296
+ | Gemini CLI | hook `BeforeAgent` | `/crow on\|off\|status` (`~/.gemini/commands/crow.toml`) | `systemMessage` quando muda |
297
+ | Antigravity (agy) | hook `PreInvocation` (`injectSteps`) | `/crow …` interceptado só quando o agy envia o texto do prompt (1.4.7+); senão peça ao agente para rodar `crow-skills mode on\|off` | status line `▸▸ crow on` (empilhada) |
298
+ | Devin | hook `UserPromptSubmit` | prompt `/crow on\|off\|status`, como no Codex | `systemMessage` quando muda |
299
+ | qualquer um | — | `crow-skills mode on\|off` num terminal | segmento tmux `▸▸ crow on` |
300
+
301
+ O guia de cada agente diz para obedecer ao anúncio mais recente e, sem hook (não instalado ou não aprovado), ler o arquivo de modo no início da sessão. O modelo nunca muda o modo por conta própria (no Claude Code, o comando tem `disable-model-invocation`). `mode` sem `--yes` é intencional: alternar é o pedido explícito do usuário e não altera arquivos de configuração dos CLIs.
302
+
303
+ ## Eventos (events)
304
+
305
+ ```sh
306
+ crow-skills events # resumo: sessões ativas, execuções crow, autoupdate
307
+ crow-skills events snapshot --json # crow-snapshot/1 para terminais (crow-term)
308
+ crow-skills events tail --json --limit 100
309
+ crow-skills events tail --follow # JSONL puro até Ctrl-C
310
+ ```
311
+
312
+ Os hooks gravam eventos compactos (`crow-event/1`) num JSONL rotacionado e um snapshot por sessão (host, sessão, diretório, branch, modelo, modo de permissão, modo crow, estado, ferramenta atual, última ação, subagentes em andamento, shells iniciados, bloqueio em aprovação, custo e uso quando a status line os envia). Nunca entram texto de prompt, mensagem, entrada/saída de ferramenta ou segredos. Contrato completo, campos e limites de disco em [docs/events.md](events.md).
313
+
314
+ ## Atualização automática (autoupdate)
315
+
316
+ ```sh
317
+ crow-skills autoupdate on --dry-run
318
+ crow-skills autoupdate on --yes # agenda diário e no login
319
+ crow-skills autoupdate status
320
+ crow-skills autoupdate run --yes # agora, manualmente
321
+ crow-skills autoupdate run --skills-only --yes
322
+ crow-skills autoupdate off --yes
323
+ ```
324
+
325
+ `on` instala um agendador do usuário que roda `crow-skills autoupdate run --yes --json` todo dia e no login:
326
+
327
+ | Sistema | Arquivos | Quando |
328
+ |---|---|---|
329
+ | macOS | `~/Library/LaunchAgents/com.andersonflima.crow-skills.autoupdate.plist`, carregado com `launchctl bootstrap gui/<uid>` | `RunAtLoad` (login) e `StartCalendarInterval` diário às 10:17 (roda ao acordar se o Mac dormia) |
330
+ | Linux | `~/.config/systemd/user/crow-skills-autoupdate.{service,timer}`, habilitado com `systemctl --user enable --now` | `OnStartupSec=5min` e `OnCalendar=daily` com `Persistent=true` |
331
+ | outros | — | `unsupported_platform`; agende `crow-skills autoupdate run --yes --json` por conta própria (por exemplo, cron) |
332
+
333
+ O agendador chama o launcher estável (`<prefixo do Homebrew>/bin/crow-skills`, `<prefixo do npm>/bin/crow-skills` ou `bin/crow-skills` do checkout), não o caminho versionado. Um arquivo de agendador que já existe e não foi gravado pelo crow-skills é recusado (`unmanaged_conflict`); `off` não remove um arquivo editado depois da instalação (informa em `kept`). Com `--home` isolado, os arquivos são gravados mas nada é carregado.
255
334
 
256
- Sem superfície que mostre um valor externo (documentado em 2026-10-23, Gemini CLI 0.65.0, agy 1.4.4, Devin CLI 3000.11.92):
335
+ Cada execução:
257
336
 
258
- - Gemini CLI: `ui.footer.items` aceita só itens nativos; hooks podem injetar contexto, não um item de rodapé.
259
- - Antigravity (`agy`, agente `gemini` do instalador): sem configuração de status line ou rodapé. No ledger, o host dele é `agy`; `gemini` no ledger significa Gemini CLI.
260
- - Devin CLI: sem status line ou rodapé configurável; hooks e plugins existem, mas não exibem um valor persistente.
337
+ 1. Atualiza o próprio crow-skills conforme a instalação: Homebrew (`brew upgrade andersonflima/tap/crow-skills`), npm global (`npm install -g @andespindola/crow-skills@latest`). Checkout Git só com `autoupdate on --git-pull`, e só se estiver limpo em `main`/`master` (`git pull --ff-only`); caso contrário, é pulado com o motivo. Saída de brew/npm/git não é guardada nem impressa, só código de saída e versões.
338
+ 2. Se a versão mudou, a versão nova (o launcher) faz o passo seguinte, para usar o snapshot novo como fonte.
339
+ 3. Para cada agente com skills gerenciadas (claude, codex/`~/.agents/skills`, gemini, devin, uniflow), roda o equivalente a `update <skills> --agents <agente> --global --yes`: regenera guia, integrações e hooks; a [identidade do pacote](#origem-e-versões) evita `source_mismatch` depois do upgrade. Skills editadas localmente (`modified`), ausentes ou instaladas de outra origem (`other_origin`, por exemplo de um clone Git) ficam como estão e aparecem em `kept`; nada é sobrescrito. Uma reaplicação dos hooks troca as entradas do crow-skills no lugar, sem mudar a posição das suas. Uma recusa num agente (por exemplo, guia editado) aparece em `error` e não interrompe os outros.
261
340
 
262
- Para esses, use o segmento tmux ou `crow-skills progress --watch` num painel ao lado.
341
+ O resultado fica em `~/.local/state/crow-skills/autoupdate/state.json` (`lastRun` e as últimas 20 execuções), aparece em `autoupdate status`, em `status`/`doctor` (doctor `healthy:false` se a última execução falhou ou o agendador foi alterado/removido) e em `events snapshot`. Duas execuções simultâneas são recusadas (`busy`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/crow-skills",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Versioned, complementary agent skills with a protected multi-agent installer",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
package/release.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "README.md": {
4
4
  "executable": false,
5
5
  "kind": "file",
6
- "sha256": "32eddd05da22e1f5cc1771af32e207d51f2167ca16ee1388a0648917921bc046"
6
+ "sha256": "066198363ec3e5fff1e61d7279277c1b6b95d29b4c3702339f670291273ddd2e"
7
7
  },
8
8
  "bin/npm-crow-skills.cjs": {
9
9
  "executable": true,
@@ -18,7 +18,7 @@
18
18
  "crow_skills/__init__.py": {
19
19
  "executable": false,
20
20
  "kind": "file",
21
- "sha256": "0a226e15403a704aed44b620d6d7ae1348e200319516a5c6f4016520995f69d2"
21
+ "sha256": "7b88ebadac00992d9ad895edb5fa5ea0c951240fe01a064fbabfb951db39d9d6"
22
22
  },
23
23
  "crow_skills/__main__.py": {
24
24
  "executable": false,
@@ -30,20 +30,35 @@
30
30
  "kind": "file",
31
31
  "sha256": "b14c37d2f1becfe38c74411fc413608b375c05bd6961a0757e3ec085ec2e1f66"
32
32
  },
33
+ "crow_skills/autoupdate.py": {
34
+ "executable": false,
35
+ "kind": "file",
36
+ "sha256": "aaafc556e530997dd3de2e075fe4fd70c1886f61435cf7bf23fb89d13c627466"
37
+ },
33
38
  "crow_skills/cli.py": {
34
39
  "executable": false,
35
40
  "kind": "file",
36
- "sha256": "fd3c4e63be95f0a616932438f1d2648facffabf825a89bb15d9f1a466d33b075"
41
+ "sha256": "25f4b9aaa79183c82bc2482d68a0e3f2c2f10f554128898204e379a08ba6475e"
42
+ },
43
+ "crow_skills/events.py": {
44
+ "executable": false,
45
+ "kind": "file",
46
+ "sha256": "fca208df99180ef52a50d2ff1c83a97bb61995c7362f8361470f055a3abe5811"
37
47
  },
38
48
  "crow_skills/guide.py": {
39
49
  "executable": false,
40
50
  "kind": "file",
41
- "sha256": "cabfe0809c0fc607b7deac0cd8df9025acaadddf4deb05f45288158dc51b0391"
51
+ "sha256": "9130cb9b59a340aaf674c0b062c38849d59a7789643cc30ed1e5091dff31b7a7"
52
+ },
53
+ "crow_skills/hook.py": {
54
+ "executable": false,
55
+ "kind": "file",
56
+ "sha256": "4bb291feddf654e72e8758a18712f97d3190e00f1975c51acee555660e487c43"
42
57
  },
43
58
  "crow_skills/integrations.py": {
44
59
  "executable": false,
45
60
  "kind": "file",
46
- "sha256": "fa2b53ef54e157cadb5579f0a10f7267026e749d255a40787279b66c495e1c1e"
61
+ "sha256": "0f4edef91c9e18a667ef1aabd788bbccaedf1e6a111d12a07fb100eafc47c19a"
47
62
  },
48
63
  "crow_skills/npm_entry.py": {
49
64
  "executable": false,
@@ -53,17 +68,17 @@
53
68
  "crow_skills/progress.py": {
54
69
  "executable": false,
55
70
  "kind": "file",
56
- "sha256": "c7521b069781dfcb3c083ab14cfcb6de6d2e71199963d595149dcdf2807aa802"
71
+ "sha256": "6cc3fa04d59b3c50c7ce104a3eb0155320e0e050539f969356f350891da03a04"
57
72
  },
58
73
  "crow_skills/source.py": {
59
74
  "executable": false,
60
75
  "kind": "file",
61
- "sha256": "b140a538967dc6c101ae3a8c7121f56ef2b256715c631b3f7adba3d981f2b978"
76
+ "sha256": "bd9ad8841369d512a7fab08d805767278ec40c5e7cf67aa9979a6a0c5a898c32"
62
77
  },
63
78
  "crow_skills/storage.py": {
64
79
  "executable": false,
65
80
  "kind": "file",
66
- "sha256": "bf3c4bcb83888b74c72773aa1d0c0def4b3ba08f0c7bdbb918d2c549438e4d83"
81
+ "sha256": "e3a7a41bcb3aa52530bbc1770165308b61a42017a8d8962fdb6a271ce2b5188f"
67
82
  },
68
83
  "docs/cli-security.md": {
69
84
  "executable": false,
@@ -73,12 +88,12 @@
73
88
  "docs/cli.md": {
74
89
  "executable": false,
75
90
  "kind": "file",
76
- "sha256": "eb9eefccb081f1f473eb7312c0b0735c13297d5b2a010b254abb7dad98cf3fef"
91
+ "sha256": "caad657540d1d340e84d03d29ed02120d0013cbd72b724ad4bdd31d9c4aafc3b"
77
92
  },
78
93
  "package.json": {
79
94
  "executable": false,
80
95
  "kind": "file",
81
- "sha256": "7abd07ab9e8af66d7bcc19a3306b8c09a7d8cfc3f9d41a03ebafd39469cc467b"
96
+ "sha256": "a9dd894cfd877032d709848afe7c2b7458e305f5c00a285d2fede76f41184ad5"
82
97
  },
83
98
  "skills/crow-accessibility/SKILL.md": {
84
99
  "executable": false,
@@ -108,7 +123,7 @@
108
123
  "skills/crow-behaviour/SKILL.md": {
109
124
  "executable": false,
110
125
  "kind": "file",
111
- "sha256": "0e1360266fb7b5943f4fc0f9710b2294db08e14400a742d441deb23567a0ea2b"
126
+ "sha256": "19c871dc3002c263e88522ac91045707f10692acd24e2db2fd707bb2db7eb48b"
112
127
  },
113
128
  "skills/crow-behaviour/agents/openai.yaml": {
114
129
  "executable": false,
@@ -128,7 +143,7 @@
128
143
  "skills/crow-behaviour/references/progress-ledger.md": {
129
144
  "executable": false,
130
145
  "kind": "file",
131
- "sha256": "70a03809def8c65fa1c6390d57158cfdcd553246c4a91382feb35927a84b3af9"
146
+ "sha256": "882e3c8cc513d7c7b4087b72681d540fc126768fdbeefbad21e5ec121c9262e6"
132
147
  },
133
148
  "skills/crow-behaviour/references/quality-patterns.md": {
134
149
  "executable": false,
@@ -138,7 +153,7 @@
138
153
  "skills/crow-behaviour/scripts/crow_ledger.py": {
139
154
  "executable": true,
140
155
  "kind": "file",
141
- "sha256": "68e6d5f567564eeb7f55f887f59f1d9857f59e64d9b09a41241ac6aa70134f62"
156
+ "sha256": "bb008110b6c451e65bc5de956febc07be459d66f68e027b243feb257abb59d66"
142
157
  },
143
158
  "skills/crow-browser/SKILL.md": {
144
159
  "executable": false,
@@ -631,7 +646,7 @@
631
646
  "sha256": "e37132ef8b060548191fbf14a5a18a9dd3acd84ea9a35e802174455b9e374d3d"
632
647
  }
633
648
  },
634
- "revision": "2d294571f175113574a22446529025303243d271",
649
+ "revision": "985e61cec06a7f6feaaafd355f7015d33514b943",
635
650
  "schema_version": 1,
636
- "version": "0.7.1"
651
+ "version": "0.8.0"
637
652
  }