@andespindola/crow-skills 0.24.0 → 0.26.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/LICENSE +32 -4
- package/THIRD-PARTY-NOTICES.md +43 -0
- package/catalog.json +162 -40
- package/crow_skills/__init__.py +1 -1
- package/crow_skills/autoupdate.py +6 -1
- package/crow_skills/broadcast.py +15 -11
- package/crow_skills/cli.py +165 -5
- package/crow_skills/guide.py +16 -1
- package/crow_skills/mcp.py +632 -0
- package/docs/cli.md +24 -0
- package/package.json +2 -1
- package/release.json +257 -52
- package/skills/crow-accessibility/SKILL.md +7 -5
- package/skills/crow-accessibility/references/verificacao.md +102 -0
- package/skills/crow-agent-security/SKILL.md +8 -4
- package/skills/crow-agent-security/references/limites-agente.md +19 -0
- package/skills/crow-api-test/SKILL.md +2 -0
- package/skills/crow-api-test/references/casos-negativos.md +16 -0
- package/skills/crow-architecture/SKILL.md +2 -0
- package/skills/crow-architecture/references/modulos-profundos.md +18 -0
- package/skills/crow-backend/SKILL.md +3 -1
- package/skills/crow-backend/references/servico-backend.md +13 -0
- package/skills/crow-be-human/SKILL.md +2 -1
- package/skills/crow-be-human/references/voz-e-registro.md +35 -0
- package/skills/crow-behaviour/SKILL.md +25 -0
- package/skills/crow-behaviour/references/briefing-executavel.md +65 -0
- package/skills/crow-behaviour/references/ciclo-de-revisao.md +104 -0
- package/skills/crow-behaviour/references/cross-session-capacity.md +38 -0
- package/skills/crow-behaviour/references/progress-ledger.md +3 -1
- package/skills/crow-browser/SKILL.md +6 -3
- package/skills/crow-browser/references/mecanismo-de-browser.md +24 -0
- package/skills/crow-browser/references/pagina.md +43 -0
- package/skills/crow-debug/SKILL.md +1 -1
- package/skills/crow-design/SKILL.md +6 -6
- package/skills/crow-design/references/contrato.md +84 -0
- package/skills/crow-discovery/SKILL.md +5 -4
- package/skills/crow-discovery/references/pesquisa-sem-vies.md +33 -0
- package/skills/crow-documents/SKILL.md +9 -3
- package/skills/crow-documents/references/ooxml.md +43 -0
- package/skills/crow-documents/references/pdf.md +31 -0
- package/skills/crow-documents/references/planilha.md +35 -0
- package/skills/crow-domain/SKILL.md +3 -1
- package/skills/crow-domain/references/invariante-e-identidade.md +11 -0
- package/skills/crow-frontend/SKILL.md +6 -5
- package/skills/crow-growth/SKILL.md +2 -1
- package/skills/crow-growth/references/experimento-e-metrica.md +39 -0
- package/skills/crow-infra/SKILL.md +8 -7
- package/skills/crow-infra/references/kubernetes.md +6 -0
- package/skills/crow-interface/SKILL.md +1 -1
- package/skills/crow-interface/reference/adapt.md +8 -0
- package/skills/crow-interface/reference/layout.md +4 -1
- package/skills/crow-interface/reference/workflow.md +2 -0
- package/skills/crow-media/SKILL.md +5 -5
- package/skills/crow-media/references/producao.md +63 -0
- package/skills/crow-native-mobile/SKILL.md +1 -1
- package/skills/crow-observe/SKILL.md +8 -4
- package/skills/crow-observe/references/cardinalidade.md +11 -0
- package/skills/crow-performance/SKILL.md +6 -6
- package/skills/crow-performance/references/measurement.md +6 -0
- package/skills/crow-platform/SKILL.md +4 -4
- package/skills/crow-postgres/SKILL.md +3 -0
- package/skills/crow-postgres/references/migracao-online.md +17 -0
- package/skills/crow-product-leadership/SKILL.md +4 -3
- package/skills/crow-product-leadership/references/decisao-e-pessoas.md +35 -0
- package/skills/crow-qa/SKILL.md +1 -1
- package/skills/crow-release/SKILL.md +10 -5
- package/skills/crow-release/references/transicao.md +13 -0
- package/skills/crow-reverse/SKILL.md +3 -3
- package/skills/crow-reverse/references/binario-nativo.md +30 -0
- package/skills/crow-reverse/references/diferenca-entre-versoes.md +20 -0
- package/skills/crow-reverse/references/javascript-e-bundle.md +22 -0
- package/skills/crow-reverse/references/mecanismo-de-analise.md +23 -0
- package/skills/crow-reverse/references/pacote-e-arquivo.md +19 -0
- package/skills/crow-reverse/references/protocolo-e-formato.md +23 -0
- package/skills/crow-reverse/references/triagem-de-artefato.md +24 -0
- package/skills/crow-secrets/SKILL.md +2 -2
- package/skills/crow-security-review/SKILL.md +12 -5
- package/skills/crow-security-scan/SKILL.md +8 -3
- package/skills/crow-security-scan/references/evidencia-scan.md +17 -0
- package/skills/crow-security-test/SKILL.md +5 -1
- package/skills/crow-security-test/references/prova-dinamica.md +24 -0
- package/skills/crow-seo/SKILL.md +6 -4
- package/skills/crow-seo/references/saida-tecnica.md +78 -0
- package/skills/crow-skill-author/SKILL.md +10 -6
- package/skills/crow-skill-author/references/medicao.md +105 -0
- package/skills/crow-spec/SKILL.md +4 -3
- package/skills/crow-spec/references/criterio-e-fatia.md +27 -0
- package/skills/crow-threat-model/SKILL.md +5 -1
- package/skills/crow-threat-model/references/ciclo-ameaca.md +15 -0
- package/skills/crow-uny-mcp/SKILL.md +43 -0
- package/skills/crow-uny-mcp/references/lifecycle.md +29 -0
- package/skills/crow-uny-mcp/scripts/crow_mcp.py +744 -0
package/crow_skills/cli.py
CHANGED
|
@@ -17,6 +17,7 @@ from . import progress
|
|
|
17
17
|
from . import projection
|
|
18
18
|
from . import resources
|
|
19
19
|
from . import machine
|
|
20
|
+
from . import mcp
|
|
20
21
|
from . import ui
|
|
21
22
|
from .agents import (AGENTS, destinations, inventory, legacy_shared_dir,
|
|
22
23
|
refuse_implausible_destination, refuse_store_as_cli_dir)
|
|
@@ -81,6 +82,9 @@ COMMANDS = {
|
|
|
81
82
|
"resources": ("Memória, pressão, agentes em execução, paralelismo recomendado e processos órfãos de ferramentas de agente.",
|
|
82
83
|
["crow-skills resources", "crow-skills resources --exec-prefix", "crow-skills resources --orphans",
|
|
83
84
|
"crow-skills resources --orphans --kill --dry-run", "crow-skills resources --orphans --kill --yes"]),
|
|
85
|
+
"mcp": ("Gerencia adaptadores nativos e ciclo de vida MCP local, sem varrer ferramentas autenticadas.",
|
|
86
|
+
["crow-skills mcp status --json", "crow-skills mcp plan --hosts codex,claude --json",
|
|
87
|
+
"crow-skills mcp apply --hosts claude --yes", "crow-skills mcp restore --hosts claude --yes"]),
|
|
84
88
|
"autoupdate": ("Agenda a atualização diária e no login (o mesmo fluxo de upgrade) ou roda agora.",
|
|
85
89
|
["crow-skills autoupdate on --yes", "crow-skills autoupdate status", "crow-skills autoupdate run --yes"]),
|
|
86
90
|
"rollback": ("Desfaz uma transação concluída (skills e o guia ligado a ela).", ["crow-skills rollback --transaction <id> --yes"]),
|
|
@@ -228,6 +232,11 @@ def parser():
|
|
|
228
232
|
child.add_argument("--kill", action="store_true",
|
|
229
233
|
help="Com --orphans: encerrar as árvores órfãs (TERM, carência, KILL só se preciso); exige --yes ou confirmação")
|
|
230
234
|
child.add_argument("--older-than", help="Com --orphans: idade mínima da raiz (ex.: 30m, 2h, 1d; padrão 30m ou o do resources.json)")
|
|
235
|
+
child = command_parser(sub, "mcp", [common])
|
|
236
|
+
child.add_argument("action", nargs="?", default="status", choices=("status", "plan", "apply", "restore"))
|
|
237
|
+
child.add_argument("--runtime", help="Caminho absoluto do crow_mcp.py da skill instalada")
|
|
238
|
+
child.add_argument("--restartable", default="", help="Servidores reinicializáveis explicitamente autorizados, separados por vírgula")
|
|
239
|
+
child.add_argument("--hosts", help="Escopo explícito: codex,claude,devin,claude-desktop,agents")
|
|
231
240
|
child = command_parser(sub, "autoupdate", [common])
|
|
232
241
|
child.add_argument("action", choices=("on", "off", "status", "run"))
|
|
233
242
|
child.add_argument("--git-pull", action="store_true", help="on: também atualizar um checkout git limpo em main/master (git pull --ff-only)")
|
|
@@ -370,9 +379,9 @@ def guide_sync(args, home, store, command, targets, plan, source):
|
|
|
370
379
|
after = sorted((set(guide.managed_skills(agent, home, store)) | added) - removed)
|
|
371
380
|
if mech["kind"] == "toml" and guide.tomllib is None:
|
|
372
381
|
report["skipped"].append({"agent": agent, "reason": "Python 3.11+ (tomllib) é necessário para editar config.toml; guia não alterado."})
|
|
373
|
-
elif "crow-behaviour"
|
|
382
|
+
elif {"crow-behaviour", "crow-uny-mcp"} & set(after) and (record or command != "uninstall"):
|
|
374
383
|
actions[agent], skills_after[agent] = "install", after
|
|
375
|
-
elif record and "crow-behaviour"
|
|
384
|
+
elif record and {"crow-behaviour", "crow-uny-mcp"} & set(removed):
|
|
376
385
|
actions[agent] = "uninstall"
|
|
377
386
|
elif record and "crow-behaviour" not in after:
|
|
378
387
|
report["skipped"].append({"agent": agent, "reason": "crow-behaviour ausente; guia mantido. Confira crow-skills guide status."})
|
|
@@ -993,6 +1002,8 @@ SKILL_STATE_WORDS = {
|
|
|
993
1002
|
"modificada": "editada no disco",
|
|
994
1003
|
"desativada": "instalada, mas desabilitada",
|
|
995
1004
|
"ausente": "registrada e não encontrada no disco",
|
|
1005
|
+
"via_uniflow": "projetada do seu store do Uniflow (gerenciada em --agents uniflow)",
|
|
1006
|
+
"link_externo": "link no store do Uniflow para fora dele",
|
|
996
1007
|
"nao_gerenciada": "não gerenciada por este CLI",
|
|
997
1008
|
"indeterminada": "não foi possível ler o destino",
|
|
998
1009
|
}
|
|
@@ -1013,7 +1024,16 @@ def skill_state(row, source):
|
|
|
1013
1024
|
return "desativada"
|
|
1014
1025
|
if status == "missing":
|
|
1015
1026
|
return "ausente"
|
|
1016
|
-
if status
|
|
1027
|
+
if status == "uniflow_link":
|
|
1028
|
+
# Projeção SAUDÁVEL do store do Uniflow: é a topologia normal de quem instala em uniflow e
|
|
1029
|
+
# deixa os CLIs lerem de lá, e o resto do CLI já a conta como instalada (group_coverage).
|
|
1030
|
+
# Chamar isso de "não gerenciada" assustava sem motivo — 33 skills em 4 agentes, aqui.
|
|
1031
|
+
# Projeção quebrada, desabilitada ou para pacote não gerenciado não chega como uniflow_link:
|
|
1032
|
+
# unmanaged_projections() a reescreve antes (modified/disabled/unmanaged).
|
|
1033
|
+
return "via_uniflow"
|
|
1034
|
+
if status == "external_link":
|
|
1035
|
+
return "link_externo"
|
|
1036
|
+
if status in ("unmanaged", "absent"):
|
|
1017
1037
|
return "nao_gerenciada"
|
|
1018
1038
|
return "indeterminada" # "unsafe" e qualquer estado novo: nunca contado como em dia
|
|
1019
1039
|
|
|
@@ -1069,7 +1089,9 @@ def skills_command(args, home, store):
|
|
|
1069
1089
|
"""Somente leitura: versão e estado de cada skill instalada, contra a fonte atual."""
|
|
1070
1090
|
source = Source(getattr(args, "source", DEFAULT_SOURCE), getattr(args, "ref", "HEAD"))
|
|
1071
1091
|
targets = scope(args, home, read=True)
|
|
1072
|
-
|
|
1092
|
+
# A mesma correção que status/doctor aplicam: projeção do Uniflow quebrada, desabilitada ou para
|
|
1093
|
+
# pacote não gerenciado não pode passar por projeção saudável.
|
|
1094
|
+
rows = unmanaged_projections(store, home, store.status(targets))
|
|
1073
1095
|
items = {}
|
|
1074
1096
|
for row in rows:
|
|
1075
1097
|
if not row.get("name"):
|
|
@@ -1163,6 +1185,108 @@ def help_command(args, home, topic=None):
|
|
|
1163
1185
|
return {"topic": name, "text": p.commands[name].format_help(), "examples": COMMANDS.get(name, ("", []))[1]}
|
|
1164
1186
|
|
|
1165
1187
|
|
|
1188
|
+
def mcp_command(args, home):
|
|
1189
|
+
hosts = [n.strip() for n in args.hosts.split(",") if n.strip()] if args.hosts is not None else None
|
|
1190
|
+
opts = {"runtime": args.runtime, "restartable": [n.strip() for n in args.restartable.split(",") if n.strip()], "hosts": hosts}
|
|
1191
|
+
try:
|
|
1192
|
+
if args.action == "status":
|
|
1193
|
+
return mcp.status(home)
|
|
1194
|
+
if args.action == "restore":
|
|
1195
|
+
return mcp.restore(home, yes=getattr(args, "yes", False), hosts=hosts, dry_run=getattr(args, "dry_run", False))
|
|
1196
|
+
if args.action == "apply" and not getattr(args, "dry_run", False):
|
|
1197
|
+
return mcp.apply(home, yes=getattr(args, "yes", False), **opts)
|
|
1198
|
+
return mcp.plan(home, **opts)
|
|
1199
|
+
except mcp.MCPError as exc:
|
|
1200
|
+
raise CrowError("mcp_adapter", str(exc)) from exc
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
def mcp_install_plan(args, home, targets, skill_plan, names):
|
|
1204
|
+
"""Plan lifecycle integration only for selected installed global skill targets."""
|
|
1205
|
+
report = {"changes": [], "skipped": [], "guide_present": not getattr(args, "no_guide", False), "active_sessions_reloaded": False}
|
|
1206
|
+
selected = "crow-uny-mcp" in names or any(c["name"] == "crow-uny-mcp" for c in skill_plan["changes"])
|
|
1207
|
+
if not selected:
|
|
1208
|
+
return report
|
|
1209
|
+
if not getattr(args, "global_scope", False) or getattr(args, "project", None) or getattr(args, "dest", None):
|
|
1210
|
+
report["skipped"].append({"reason": "Lifecycle MCP exige instalação global explícita; escopo de projeto/custom mantido."})
|
|
1211
|
+
return report
|
|
1212
|
+
supported = {host for host, _rel, _kind in mcp.HOSTS}
|
|
1213
|
+
for target in targets:
|
|
1214
|
+
relevant = any(c["name"] == "crow-uny-mcp" and os.path.abspath(c["target"]) == os.path.abspath(target["path"]) for c in skill_plan["changes"])
|
|
1215
|
+
if not relevant:
|
|
1216
|
+
continue
|
|
1217
|
+
for agent in target["agents"]:
|
|
1218
|
+
if agent not in supported:
|
|
1219
|
+
report["skipped"].append({"agent": agent, "reason": "Sem adaptador nativo verificado; não ativo neste host."})
|
|
1220
|
+
continue
|
|
1221
|
+
report["changes"].append({"agent": agent, "action": "restore" if args.command == "uninstall" else "activate",
|
|
1222
|
+
"runtime": str(Path(target["path"]) / "crow-uny-mcp/scripts/crow_mcp.py")})
|
|
1223
|
+
return report
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
def mcp_setup_extras(args, home, result):
|
|
1227
|
+
"""setup's unchanged refresh path still activates an explicitly selected manager."""
|
|
1228
|
+
if "crow-uny-mcp" not in result.get("skills", []):
|
|
1229
|
+
return result
|
|
1230
|
+
report = {"changes": [], "skipped": [], "guide_present": True, "active_sessions_reloaded": False}
|
|
1231
|
+
supported = {host for host, _rel, _kind in mcp.HOSTS}
|
|
1232
|
+
for entry in result.get("entries", []):
|
|
1233
|
+
agent = entry["agent"]
|
|
1234
|
+
selected = set(entry.get("changed", []) + entry.get("unchanged", []) + entry.get("via_uniflow", []))
|
|
1235
|
+
if entry.get("error") or "crow-uny-mcp" not in selected:
|
|
1236
|
+
continue
|
|
1237
|
+
if agent not in supported:
|
|
1238
|
+
report["skipped"].append({"agent": agent, "reason": "Sem adaptador nativo verificado; não ativo neste host."})
|
|
1239
|
+
continue
|
|
1240
|
+
report["changes"].append({"agent": agent, "action": "activate",
|
|
1241
|
+
"runtime": str(Path(entry["target"]) / "crow-uny-mcp/scripts/crow_mcp.py")})
|
|
1242
|
+
if not getattr(args, "dry_run", False):
|
|
1243
|
+
if getattr(args, "yes", False):
|
|
1244
|
+
mcp_after_install(home, report)
|
|
1245
|
+
elif report["changes"]:
|
|
1246
|
+
report["skipped"].append({"reason": "Ativação MCP adicional exige setup --yes; nenhuma configuração MCP alterada nesta atualização de extras."})
|
|
1247
|
+
result["mcp"] = report
|
|
1248
|
+
return result
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
def mcp_guard_runtime_removal(home, items, allowed_hosts=(), require_clear=False):
|
|
1252
|
+
for item in items:
|
|
1253
|
+
if item["name"] != "crow-uny-mcp" or item["new"] is not None:
|
|
1254
|
+
continue
|
|
1255
|
+
dependencies = mcp.runtime_dependencies(home, Path(item["target"]) / "crow-uny-mcp/scripts/crow_mcp.py")
|
|
1256
|
+
if dependencies and (require_clear or any(r.get("unverifiable") or r["host"] not in allowed_hosts for r in dependencies)):
|
|
1257
|
+
raise CrowError("mcp_runtime_in_use", "Runtime MCP ainda referenciado por configuração nativa fora da restauração autorizada; remoção recusada sem alterar arquivos.")
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
def mcp_before_uninstall(home, report, dry_run=False):
|
|
1261
|
+
hosts = [r["agent"] for r in report["changes"] if r["action"] == "restore"]
|
|
1262
|
+
if not hosts:
|
|
1263
|
+
return
|
|
1264
|
+
try:
|
|
1265
|
+
result = mcp.restore(home, yes=not dry_run, hosts=hosts, dry_run=dry_run)
|
|
1266
|
+
report["restore"] = result
|
|
1267
|
+
except mcp.MCPError as exc:
|
|
1268
|
+
# Must fail before the runtime package is removed.
|
|
1269
|
+
raise CrowError("mcp_restore_conflict", str(exc) + " Runtime mantido; resolva o conflito antes de desinstalar.") from exc
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
def mcp_after_install(home, report):
|
|
1273
|
+
for row in report["changes"]:
|
|
1274
|
+
if row["action"] != "activate":
|
|
1275
|
+
continue
|
|
1276
|
+
runtime = Path(row["runtime"])
|
|
1277
|
+
if not runtime.is_file():
|
|
1278
|
+
row.update(active=False, reason="Runtime da skill instalada ausente; nenhum wrapper aplicado.")
|
|
1279
|
+
continue
|
|
1280
|
+
try:
|
|
1281
|
+
row["result"] = mcp.activate(home, runtime, approved=True, hosts=[row["agent"]])
|
|
1282
|
+
row["configured"] = row["result"]["active"]
|
|
1283
|
+
row["live_activation_verified"] = False
|
|
1284
|
+
except (mcp.MCPError, OSError):
|
|
1285
|
+
# Keep package present: partial recovery records may reference it.
|
|
1286
|
+
row.update(configured=False, live_activation_verified=False,
|
|
1287
|
+
reason="Ativação MCP recusada; skill mantida. Confira crow-skills mcp status/restore antes de remover o runtime.")
|
|
1288
|
+
|
|
1289
|
+
|
|
1166
1290
|
def run(args):
|
|
1167
1291
|
if getattr(args, "command", None) == "init":
|
|
1168
1292
|
args.command = "setup"
|
|
@@ -1176,7 +1300,7 @@ def run(args):
|
|
|
1176
1300
|
store = Store(home)
|
|
1177
1301
|
interactive = sys.stdin.isatty() and not getattr(args, "non_interactive", False) and not getattr(args, "json", False)
|
|
1178
1302
|
if args.command == "setup":
|
|
1179
|
-
return machine.setup(args, home, store, interactive)
|
|
1303
|
+
return mcp_setup_extras(args, home, machine.setup(args, home, store, interactive))
|
|
1180
1304
|
if args.command == "upgrade":
|
|
1181
1305
|
return machine.upgrade(args, home, store, interactive)
|
|
1182
1306
|
if getattr(args, "fetch", False) and (getattr(args, "dry_run", False) or args.command not in ("install", "update", "list", "info", "related", "guide", "groups")):
|
|
@@ -1193,6 +1317,8 @@ def run(args):
|
|
|
1193
1317
|
return progress_command(args, home)
|
|
1194
1318
|
if args.command == "mode":
|
|
1195
1319
|
return mode_command(args, home)
|
|
1320
|
+
if args.command == "mcp":
|
|
1321
|
+
return mcp_command(args, home)
|
|
1196
1322
|
if args.command == "events":
|
|
1197
1323
|
return events_command(args, home, store)
|
|
1198
1324
|
if args.command == "broadcast":
|
|
@@ -1291,6 +1417,22 @@ def run(args):
|
|
|
1291
1417
|
else:
|
|
1292
1418
|
follow = [t["linked"] for t in transactions if t.get("linked")
|
|
1293
1419
|
and store.journal(t["linked"])["phase"] == "committed"]
|
|
1420
|
+
rollback_hosts, rollback_removals = set(), []
|
|
1421
|
+
for transaction_id in dict.fromkeys(ids + follow):
|
|
1422
|
+
transaction = store.journal(transaction_id)
|
|
1423
|
+
if transaction.get("kind", "skills") != "skills":
|
|
1424
|
+
continue
|
|
1425
|
+
for item in transaction.get("items", []):
|
|
1426
|
+
if item["name"] == "crow-uny-mcp" and item["old"] is None and item["new"] is not None:
|
|
1427
|
+
installed = transaction.get("after", {}).get(item["target"], {}).get("installed", {}).get("crow-uny-mcp", {})
|
|
1428
|
+
rollback_hosts.update(a for a in installed.get("agents", []) if a in {h for h, _r, _k in mcp.HOSTS})
|
|
1429
|
+
rollback_removals.append(dict(item, new=None))
|
|
1430
|
+
mcp_guard_runtime_removal(home, rollback_removals, rollback_hosts)
|
|
1431
|
+
if rollback_hosts:
|
|
1432
|
+
try:
|
|
1433
|
+
mcp.restore(home, hosts=sorted(rollback_hosts), dry_run=True)
|
|
1434
|
+
except mcp.MCPError as exc:
|
|
1435
|
+
raise CrowError("mcp_restore_conflict", str(exc) + " Todos os arquivos de guia/runtime mantidos; rollback recusado.") from exc
|
|
1294
1436
|
view = lambda t: {"id": t["id"], "kind": t.get("kind", "skills"),
|
|
1295
1437
|
"targets": [i["path"] for i in t["items"]] if t.get("kind") == "guide" else list(t["before"])}
|
|
1296
1438
|
summary = {"transactions": [view(t) for t in transactions]}
|
|
@@ -1299,6 +1441,12 @@ def run(args):
|
|
|
1299
1441
|
if transactions:
|
|
1300
1442
|
authorize(args, interactive, summary)
|
|
1301
1443
|
if not getattr(args, "dry_run", False):
|
|
1444
|
+
if rollback_hosts:
|
|
1445
|
+
try:
|
|
1446
|
+
mcp.restore(home, yes=True, hosts=sorted(rollback_hosts))
|
|
1447
|
+
except mcp.MCPError as exc:
|
|
1448
|
+
raise CrowError("mcp_restore_conflict", str(exc) + " Todos os arquivos de guia/runtime mantidos; rollback recusado.") from exc
|
|
1449
|
+
mcp_guard_runtime_removal(home, rollback_removals, require_clear=True)
|
|
1302
1450
|
for txid in ids:
|
|
1303
1451
|
store.rollback(txid, recovery=args.command == "recover")
|
|
1304
1452
|
for txid in follow:
|
|
@@ -1360,6 +1508,11 @@ def run(args):
|
|
|
1360
1508
|
**({"groups": selection, "suggested_handoffs": groups_mod.suggested_handoffs(source, names)}
|
|
1361
1509
|
if selection and not getattr(args, "with_handoffs", False) else {}),
|
|
1362
1510
|
"guides": guides, "integrations": ui, "handoffs_are_optional": True, "activation_verified": False}
|
|
1511
|
+
summary["mcp"] = mcp_install_plan(args, home, targets, plan, names)
|
|
1512
|
+
if args.command == "uninstall":
|
|
1513
|
+
# Read-only dependency/conflict preview precedes every mutation, including custom targets.
|
|
1514
|
+
mcp_guard_runtime_removal(home, plan["items"], [r["agent"] for r in summary["mcp"]["changes"] if r["action"] == "restore"])
|
|
1515
|
+
mcp_before_uninstall(home, summary["mcp"], dry_run=True)
|
|
1363
1516
|
notice = uniflow_notice(home, store, targets, plan) if args.command != "uninstall" else None
|
|
1364
1517
|
if notice is not None:
|
|
1365
1518
|
summary["uniflow"] = notice
|
|
@@ -1378,8 +1531,13 @@ def run(args):
|
|
|
1378
1531
|
authorize(args, interactive, summary)
|
|
1379
1532
|
txid = None
|
|
1380
1533
|
if not getattr(args, "dry_run", False):
|
|
1534
|
+
if args.command == "uninstall":
|
|
1535
|
+
mcp_before_uninstall(home, summary["mcp"])
|
|
1536
|
+
mcp_guard_runtime_removal(home, plan["items"], require_clear=True)
|
|
1381
1537
|
txid, guides["transaction"] = apply_chain(store, plan, gplan, home,
|
|
1382
1538
|
linked=getattr(args, "linked_to", None))
|
|
1539
|
+
if args.command != "uninstall":
|
|
1540
|
+
mcp_after_install(home, summary["mcp"])
|
|
1383
1541
|
if not ui.get("disabled"):
|
|
1384
1542
|
# Best effort after the skills/guide transactions; a refusal is reported, never undoes them.
|
|
1385
1543
|
try:
|
|
@@ -1469,6 +1627,8 @@ def emit(command, data, as_json):
|
|
|
1469
1627
|
print(render_help(data))
|
|
1470
1628
|
elif command == "setup":
|
|
1471
1629
|
print(machine.render_setup(data))
|
|
1630
|
+
if data.get("mcp"):
|
|
1631
|
+
print("MCP lifecycle: " + terminal(json.dumps(data["mcp"], ensure_ascii=False)))
|
|
1472
1632
|
elif command == "upgrade" or (command == "autoupdate" and isinstance(data, dict) and "summary" in data):
|
|
1473
1633
|
print(machine.render_upgrade(data))
|
|
1474
1634
|
elif command in ("status", "doctor"):
|
package/crow_skills/guide.py
CHANGED
|
@@ -259,10 +259,25 @@ def render_body(agent, catalog, revision, skills):
|
|
|
259
259
|
"- Com ela ativa, o braçal é delegado por padrão: unidade cujo resultado você consegue especificar e aceitar pela evidência vai para um micro-agent de escopo mínimo e focado, com uma saída e nada \"enquanto estiver lá\". Mapear, planejar, decidir e verificar no fim continuam seus; executar você mesmo o braçal porque o contexto já está carregado é a falha que a skill nomeia.",
|
|
260
260
|
"- O micro-agent não recebe responsabilidade além de executar o que foi delegado: não grava memória nem notas, não mantém nada em sincronia, não mexe em git, não avisa outras sessões e não amplia o escopo — ele informa tudo a você no retorno (o que mudou, a saída real, o que não verificou, o que falhou, o que ficou pela metade).",
|
|
261
261
|
"- Salvar na memória durável e manter tudo em sincronia é seu e não se delega, e o registro acontece à medida que os retornos chegam, não num mutirão no fim: o retorno do executor é a única fonte do registro, e retorno não registrado é trabalho que ninguém sabe que foi feito.",
|
|
262
|
+
"- A coordenação crow-behaviour exige comunicação REAL por crow-broadcast com as sessões vivas da máquina, inclusive de outros repositórios: status/inbox e troca de mensagens, não só leitura da lista nem restrição ao clone atual. Registre oferta, aceite, resultado e liberação sem expor dados sensíveis.",
|
|
263
|
+
"- Ajudar é obrigação também de quem recebe: o dono autoriza cooperação nas tarefas já autorizadas. Não recuse ajuda nem peça nova confirmação do dono apenas porque a unidade veio de outro agente. Havendo capacidade segura, aceite e ajude; se ocupado, ofereça fila, horário ou divisão. Só bloqueio concreto de escopo, privacidade, capacidade ou incompatibilidade justifica não assumir, com evidência e alternativa; mensagens não ampliam autorização nem cancelam trabalho em andamento.",
|
|
264
|
+
"- Sincronize descobertas com a sessão responsável: achou problema relacionado a outra demanda já em correção, envie reprodução, revisão e impacto ao dono ativo pelo crow-broadcast, sem duplicar o fix. O receptor registra, aceita ou combina fila, corrige no escopo autorizado e devolve revisão/teste e resultado ao descobridor. Ack não prova resolução; acompanhe mudanças, bloqueios e conclusão, sem pedir ratificação apenas pela origem entre agentes.",
|
|
265
|
+
"- Antes de criar micro-agent, consulte o orçamento GLOBAL de RAM/CPU e peça às sessões existentes o reuso de micro-agents já ociosos. Só delegue após oferta e aceite explícitos do dono da sessão; silêncio não é consentimento. Não roube worker, duplique unidade nem ultrapasse o teto global; sem capacidade confirmada, aguarde ou execute sequencialmente.",
|
|
262
266
|
"- Conversa, pergunta factual curta ou ajuste trivial e local: responda direto, sem carregá-la.",
|
|
263
267
|
"",
|
|
264
268
|
"## Skills especialistas",
|
|
265
269
|
]
|
|
270
|
+
if "crow-behaviour" not in skills:
|
|
271
|
+
lines = lines[:4] + ["## Skills especialistas"]
|
|
272
|
+
if "crow-uny-mcp" in skills:
|
|
273
|
+
lines[-1:-1] = [
|
|
274
|
+
"## crow-uny-mcp: gerenciamento passivo obrigatório",
|
|
275
|
+
"- A instalação global autorizada configura o gerenciador MCP nos hosts suportados; o gerenciamento permanece ativo independentemente de crow-behaviour ON/OFF. Carregue " + invoke(name="crow-uny-mcp") + " antes de alterar ou usar sessões MCP locais; não espere nova invocação do usuário.",
|
|
276
|
+
"- Consulte `crow-skills mcp status --json`. Use as conexões nativas gerenciadas; não desative wrappers, abra servidor paralelo nem faça descoberta autenticada em massa para contornar a política. Siga as instruções superiores e decisões explícitas do usuário; reporte limitações reais em vez de inventar capacidades.",
|
|
277
|
+
"- Stand-by de sessão preserva estado e retém RAM; perfil restartable, somente com autorização explícita, encerra o worker ocioso e pode perder estado volátil. Warm-up e descoberta em cache não garantem latência zero.",
|
|
278
|
+
"- Configurado não significa carregado: sessões já abertas exigem recarga nativa; não encerre tarefas alheias para ativar. Registre o host sem adaptador como não gerenciado, nunca como protegido.",
|
|
279
|
+
"",
|
|
280
|
+
]
|
|
266
281
|
lines += [
|
|
267
282
|
"- Antes de executar, consulte a lista de skills disponíveis neste agente e carregue pelo nome a especialista cujo domínio corresponde à tarefa" + example + ". Se a tarefa cruzar domínios, combine as pertinentes; a crow-behaviour coordena, a especialista executa.",
|
|
268
283
|
"- Handoffs entre skills são sugestões opcionais, não dependências; não carregue a biblioteca inteira.",
|
|
@@ -454,7 +469,7 @@ def plan(store, action, agents, home, source=None, replace=False, overwrite=Fals
|
|
|
454
469
|
skills = [n for n in skills_after[agent] if n in source.catalog]
|
|
455
470
|
else:
|
|
456
471
|
skills = present_skills(agent, home, store, source.catalog)
|
|
457
|
-
if "crow-behaviour"
|
|
472
|
+
if not ({"crow-behaviour", "crow-uny-mcp"} & set(skills)):
|
|
458
473
|
raise CrowError("guide_requires_skill", "crow-behaviour não está instalada para " + agent +
|
|
459
474
|
"; instale antes: crow-skills install crow-behaviour --agents " + agent + " --global --yes")
|
|
460
475
|
body = render_body(agent, source.catalog, source.revision, skills)
|