agents-city 0.1.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/.claude-plugin/marketplace.json +16 -0
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.es.md +2226 -0
- package/README.md +2196 -0
- package/benchmarks/committee/README.md +39 -0
- package/benchmarks/committee/metrics.py +51 -0
- package/benchmarks/committee/run.py +64 -0
- package/benchmarks/committee/traces/01-single.json +8 -0
- package/benchmarks/committee/traces/02-mesh.json +16 -0
- package/benchmarks/committee/traces/03-chair.json +15 -0
- package/benchmarks/latency/README.md +35 -0
- package/benchmarks/latency/fake-claude-cli.mjs +119 -0
- package/benchmarks/latency/fake-native-server.mjs +340 -0
- package/benchmarks/latency/fake-tui.py +91 -0
- package/benchmarks/latency/live.py +380 -0
- package/benchmarks/stress/README.md +20 -0
- package/benchmarks/stress/run.py +487 -0
- package/bin/agents +4 -0
- package/bin/agents-city.js +119 -0
- package/bin/benchmark +17 -0
- package/bin/bus +6 -0
- package/bin/cities +3 -0
- package/bin/city +86 -0
- package/bin/committee +6 -0
- package/bin/demo +200 -0
- package/bin/doctor +3 -0
- package/bin/exit +5 -0
- package/bin/hall +73 -0
- package/bin/hall.html +498 -0
- package/bin/logs +3 -0
- package/bin/navegador.mjs +243 -0
- package/bin/report.py +14 -0
- package/bin/reset +3 -0
- package/bin/road +3 -0
- package/bin/seat +10 -0
- package/bin/serve.py +1579 -0
- package/bin/setup.py +753 -0
- package/bin/shortcut +3 -0
- package/bin/skills +3 -0
- package/bin/test +133 -0
- package/bin/test-actualiza.py +130 -0
- package/bin/test-adapter.py +183 -0
- package/bin/test-admision.py +99 -0
- package/bin/test-atajos.py +301 -0
- package/bin/test-avatar.py +58 -0
- package/bin/test-benchmark.py +40 -0
- package/bin/test-broker.py +334 -0
- package/bin/test-cage.py +374 -0
- package/bin/test-card.py +402 -0
- package/bin/test-channel.py +379 -0
- package/bin/test-cities.py +453 -0
- package/bin/test-claude-runtime.py +252 -0
- package/bin/test-committee.py +340 -0
- package/bin/test-contracts.py +551 -0
- package/bin/test-crecimiento.py +164 -0
- package/bin/test-demo.py +308 -0
- package/bin/test-doctor.py +139 -0
- package/bin/test-domains.py +151 -0
- package/bin/test-evidencia.py +50 -0
- package/bin/test-exit.py +128 -0
- package/bin/test-hall-protocol.py +93 -0
- package/bin/test-launch.py +169 -0
- package/bin/test-live-feed.py +508 -0
- package/bin/test-navegador.py +140 -0
- package/bin/test-pairing.py +99 -0
- package/bin/test-parcels.py +283 -0
- package/bin/test-runtime-failures.py +252 -0
- package/bin/test-runtime-ui.py +488 -0
- package/bin/test-runtime.py +268 -0
- package/bin/test-rutas.py +80 -0
- package/bin/test-seat.py +1598 -0
- package/bin/test-security.py +150 -0
- package/bin/test-serve.py +1251 -0
- package/bin/test-stress.py +64 -0
- package/bin/test-widgets.py +143 -0
- package/bin/test-workspace.py +251 -0
- package/bin/testlib.py +118 -0
- package/bin/tokens.py +14 -0
- package/bin/update +3 -0
- package/bus/scripts/deploy.sh +60 -0
- package/bus/scripts/mint-token.sh +68 -0
- package/bus/scripts/setup-dev.sh +79 -0
- package/bus/scripts/test-channel.ts +8 -0
- package/bus/scripts/test-hub.ts +266 -0
- package/bus/scripts/test-local.sh +40 -0
- package/bus/scripts/test-queue.ts +132 -0
- package/bus/worker/package-lock.json +1971 -0
- package/bus/worker/package.json +17 -0
- package/bus/worker/src/index.ts +485 -0
- package/bus/worker/tsconfig.json +13 -0
- package/bus/worker/wrangler.toml +32 -0
- package/city/oven/README.md +59 -0
- package/city/oven/collect.py +43 -0
- package/city/oven/oven.html +4 -0
- package/city/scripts/history.py +120 -0
- package/city/scripts/seed.py +442 -0
- package/city/web/assets/modelos/License.txt +28 -0
- package/city/web/assets/modelos/PROCEDENCIA.txt +3 -0
- package/city/web/assets/modelos/building-a.glb +0 -0
- package/city/web/assets/modelos/building-b.glb +0 -0
- package/city/web/assets/modelos/building-c.glb +0 -0
- package/city/web/assets/modelos/building-d.glb +0 -0
- package/city/web/assets/modelos/building-e.glb +0 -0
- package/city/web/assets/modelos/building-f.glb +0 -0
- package/city/web/assets/modelos/building-g.glb +0 -0
- package/city/web/assets/modelos/building-h.glb +0 -0
- package/city/web/assets/sprites/building-a.png +0 -0
- package/city/web/assets/sprites/building-b.png +0 -0
- package/city/web/assets/sprites/building-c.png +0 -0
- package/city/web/assets/sprites/building-d.png +0 -0
- package/city/web/assets/sprites/building-e.png +0 -0
- package/city/web/assets/sprites/building-f.png +0 -0
- package/city/web/assets/sprites/building-g.png +0 -0
- package/city/web/assets/sprites/building-h.png +0 -0
- package/city/web/assets/sprites/building-i.png +0 -0
- package/city/web/assets/sprites/building-j.png +0 -0
- package/city/web/assets/sprites/building-k.png +0 -0
- package/city/web/assets/sprites/building-l.png +0 -0
- package/city/web/assets/sprites/building-m.png +0 -0
- package/city/web/assets/sprites/building-n.png +0 -0
- package/city/web/assets/sprites/building-skyscraper-a.png +0 -0
- package/city/web/assets/sprites/building-skyscraper-b.png +0 -0
- package/city/web/assets/sprites/building-skyscraper-c.png +0 -0
- package/city/web/assets/sprites/building-skyscraper-d.png +0 -0
- package/city/web/assets/sprites/building-skyscraper-e.png +0 -0
- package/city/web/assets/sprites/catalogo.json +47 -0
- package/city/web/assets/sprites/detail-awning-wide.png +0 -0
- package/city/web/assets/sprites/detail-awning.png +0 -0
- package/city/web/assets/sprites/detail-overhang-wide.png +0 -0
- package/city/web/assets/sprites/detail-overhang.png +0 -0
- package/city/web/assets/sprites/detail-parasol-a.png +0 -0
- package/city/web/assets/sprites/detail-parasol-b.png +0 -0
- package/city/web/assets/sprites/low-detail-building-a.png +0 -0
- package/city/web/assets/sprites/low-detail-building-b.png +0 -0
- package/city/web/assets/sprites/low-detail-building-c.png +0 -0
- package/city/web/assets/sprites/low-detail-building-d.png +0 -0
- package/city/web/assets/sprites/low-detail-building-e.png +0 -0
- package/city/web/assets/sprites/low-detail-building-f.png +0 -0
- package/city/web/assets/sprites/low-detail-building-g.png +0 -0
- package/city/web/assets/sprites/low-detail-building-h.png +0 -0
- package/city/web/assets/sprites/low-detail-building-i.png +0 -0
- package/city/web/assets/sprites/low-detail-building-j.png +0 -0
- package/city/web/assets/sprites/low-detail-building-k.png +0 -0
- package/city/web/assets/sprites/low-detail-building-l.png +0 -0
- package/city/web/assets/sprites/low-detail-building-m.png +0 -0
- package/city/web/assets/sprites/low-detail-building-n.png +0 -0
- package/city/web/assets/sprites/low-detail-building-wide-a.png +0 -0
- package/city/web/assets/sprites/low-detail-building-wide-b.png +0 -0
- package/city/web/assets/sprites/medidas.json +248 -0
- package/city/web/dist/city.js +939 -0
- package/city/web/dist/index.html +294 -0
- package/city/web/dist/modelos/License.txt +28 -0
- package/city/web/dist/modelos/PROCEDENCIA.txt +3 -0
- package/city/web/dist/modelos/building-a.glb +0 -0
- package/city/web/dist/modelos/building-b.glb +0 -0
- package/city/web/dist/modelos/building-c.glb +0 -0
- package/city/web/dist/modelos/building-d.glb +0 -0
- package/city/web/dist/modelos/building-e.glb +0 -0
- package/city/web/dist/modelos/building-f.glb +0 -0
- package/city/web/dist/modelos/building-g.glb +0 -0
- package/city/web/dist/modelos/building-h.glb +0 -0
- package/city/web/dist/sprites/building-a.png +0 -0
- package/city/web/dist/sprites/building-b.png +0 -0
- package/city/web/dist/sprites/building-c.png +0 -0
- package/city/web/dist/sprites/building-d.png +0 -0
- package/city/web/dist/sprites/building-e.png +0 -0
- package/city/web/dist/sprites/building-f.png +0 -0
- package/city/web/dist/sprites/building-g.png +0 -0
- package/city/web/dist/sprites/building-h.png +0 -0
- package/city/web/dist/sprites/building-i.png +0 -0
- package/city/web/dist/sprites/building-j.png +0 -0
- package/city/web/dist/sprites/building-k.png +0 -0
- package/city/web/dist/sprites/building-l.png +0 -0
- package/city/web/dist/sprites/building-m.png +0 -0
- package/city/web/dist/sprites/building-n.png +0 -0
- package/city/web/dist/sprites/building-skyscraper-a.png +0 -0
- package/city/web/dist/sprites/building-skyscraper-b.png +0 -0
- package/city/web/dist/sprites/building-skyscraper-c.png +0 -0
- package/city/web/dist/sprites/building-skyscraper-d.png +0 -0
- package/city/web/dist/sprites/building-skyscraper-e.png +0 -0
- package/city/web/dist/sprites/catalogo.json +47 -0
- package/city/web/dist/sprites/detail-awning-wide.png +0 -0
- package/city/web/dist/sprites/detail-awning.png +0 -0
- package/city/web/dist/sprites/detail-overhang-wide.png +0 -0
- package/city/web/dist/sprites/detail-overhang.png +0 -0
- package/city/web/dist/sprites/detail-parasol-a.png +0 -0
- package/city/web/dist/sprites/detail-parasol-b.png +0 -0
- package/city/web/dist/sprites/low-detail-building-a.png +0 -0
- package/city/web/dist/sprites/low-detail-building-b.png +0 -0
- package/city/web/dist/sprites/low-detail-building-c.png +0 -0
- package/city/web/dist/sprites/low-detail-building-d.png +0 -0
- package/city/web/dist/sprites/low-detail-building-e.png +0 -0
- package/city/web/dist/sprites/low-detail-building-f.png +0 -0
- package/city/web/dist/sprites/low-detail-building-g.png +0 -0
- package/city/web/dist/sprites/low-detail-building-h.png +0 -0
- package/city/web/dist/sprites/low-detail-building-i.png +0 -0
- package/city/web/dist/sprites/low-detail-building-j.png +0 -0
- package/city/web/dist/sprites/low-detail-building-k.png +0 -0
- package/city/web/dist/sprites/low-detail-building-l.png +0 -0
- package/city/web/dist/sprites/low-detail-building-m.png +0 -0
- package/city/web/dist/sprites/low-detail-building-n.png +0 -0
- package/city/web/dist/sprites/low-detail-building-wide-a.png +0 -0
- package/city/web/dist/sprites/low-detail-building-wide-b.png +0 -0
- package/city/web/dist/sprites/medidas.json +248 -0
- package/city/web/dist-hall/hall.js +1363 -0
- package/city/web/index.html +294 -0
- package/city/web/package.json +18 -0
- package/city/web/sella.py +21 -0
- package/city/web/src/activity-actors.ts +47 -0
- package/city/web/src/activity.ts +172 -0
- package/city/web/src/ayuntamiento.ts +580 -0
- package/city/web/src/draw.ts +640 -0
- package/city/web/src/game-speech.ts +79 -0
- package/city/web/src/hall.ts +1959 -0
- package/city/web/src/main.ts +2252 -0
- package/city/web/src/oven.ts +124 -0
- package/city/web/src/people.ts +244 -0
- package/city/web/src/presencia.ts +193 -0
- package/city/web/src/puertas.ts +180 -0
- package/city/web/src/repo-roles.ts +59 -0
- package/city/worker/package.json +16 -0
- package/city/worker/schema.sql +117 -0
- package/city/worker/src/index.ts +702 -0
- package/city/worker/src/square.ts +218 -0
- package/city/worker/wrangler.toml +58 -0
- package/demo/ada.md +50 -0
- package/demo/bruno.md +62 -0
- package/demo/camila.md +56 -0
- package/demo/city/ada.md +40 -0
- package/demo/city/city.yml +8 -0
- package/demo/city/parcels.yml +15 -0
- package/demo/city/roads.json +4 -0
- package/demo/city/units.yml +10 -0
- package/demo/clinica/city.yml +8 -0
- package/demo/clinica/parcels.yml +15 -0
- package/demo/clinica/roads.json +4 -0
- package/demo/clinica/units.yml +9 -0
- package/demo/clinica/vera.md +46 -0
- package/demo/dante.md +54 -0
- package/demo/despacho/city.yml +8 -0
- package/demo/despacho/marta.md +46 -0
- package/demo/despacho/parcels.yml +15 -0
- package/demo/despacho/roads.json +4 -0
- package/demo/despacho/units.yml +9 -0
- package/demo/elsa.md +50 -0
- package/demo/farid.md +52 -0
- package/demo/greta.md +50 -0
- package/demo/hugo.md +49 -0
- package/demo/iris.md +49 -0
- package/demo/jonas.md +51 -0
- package/demo/kira.md +51 -0
- package/demo/luca.md +49 -0
- package/demo/parcels.yml +92 -0
- package/demo/seed.py +20 -0
- package/demo/show.py +161 -0
- package/demo/stories.py +824 -0
- package/demo/units.yml +33 -0
- package/docs/agents-first.md +106 -0
- package/docs/glossary.md +55 -0
- package/docs/map-live-layers.md +73 -0
- package/docs/security.md +265 -0
- package/docs/self-host.md +151 -0
- package/docs/testing.md +205 -0
- package/package.json +73 -0
- package/plugin/.claude-plugin/plugin.json +62 -0
- package/plugin/.mcp.json +15 -0
- package/plugin/channel/activity-cli.ts +16 -0
- package/plugin/channel/adapter-prompts.ts +113 -0
- package/plugin/channel/adapter.js +4292 -0
- package/plugin/channel/adapter.ts +133 -0
- package/plugin/channel/bus.js +20188 -0
- package/plugin/channel/bus.ts +131 -0
- package/plugin/channel/city-config.ts +125 -0
- package/plugin/channel/claude-channel.ts +58 -0
- package/plugin/channel/cli-args.ts +75 -0
- package/plugin/channel/client.js +4200 -0
- package/plugin/channel/client.ts +38 -0
- package/plugin/channel/committee/activity.ts +256 -0
- package/plugin/channel/committee/collection.ts +154 -0
- package/plugin/channel/committee/decision.ts +175 -0
- package/plugin/channel/committee/floor.ts +135 -0
- package/plugin/channel/committee/guards.ts +30 -0
- package/plugin/channel/committee/history.ts +38 -0
- package/plugin/channel/committee/render.ts +102 -0
- package/plugin/channel/committee/service.ts +72 -0
- package/plugin/channel/committee/storage.ts +92 -0
- package/plugin/channel/committee/types.ts +163 -0
- package/plugin/channel/committee/view.ts +63 -0
- package/plugin/channel/committee-cli.ts +109 -0
- package/plugin/channel/delivery-metrics.ts +61 -0
- package/plugin/channel/delivery-queue.ts +118 -0
- package/plugin/channel/hub/activity-controller.ts +72 -0
- package/plugin/channel/hub/activity-feed.ts +169 -0
- package/plugin/channel/hub/committee-controller.ts +60 -0
- package/plugin/channel/hub/connections.ts +48 -0
- package/plugin/channel/hub/diagnostics.ts +67 -0
- package/plugin/channel/hub/envelope-validity.ts +109 -0
- package/plugin/channel/hub/envelopes.ts +66 -0
- package/plugin/channel/hub/lifecycle.ts +91 -0
- package/plugin/channel/hub/local-roads.ts +89 -0
- package/plugin/channel/hub/remote-roads.ts +165 -0
- package/plugin/channel/hub/road-controller.ts +99 -0
- package/plugin/channel/hub-client.ts +149 -0
- package/plugin/channel/local-hub.js +5995 -0
- package/plugin/channel/local-hub.ts +349 -0
- package/plugin/channel/map-reporter.ts +48 -0
- package/plugin/channel/package-lock.json +1731 -0
- package/plugin/channel/package.json +19 -0
- package/plugin/channel/protocol.ts +98 -0
- package/plugin/channel/road-cli.ts +18 -0
- package/plugin/channel/run.sh +15 -0
- package/plugin/channel/runtime/claude.ts +458 -0
- package/plugin/channel/runtime/codex-config.ts +77 -0
- package/plugin/channel/runtime/codex.ts +669 -0
- package/plugin/channel/runtime/command.ts +62 -0
- package/plugin/channel/runtime/factory.ts +15 -0
- package/plugin/channel/runtime/json-rpc.ts +154 -0
- package/plugin/channel/runtime/kimi.ts +277 -0
- package/plugin/channel/runtime/opencode.ts +248 -0
- package/plugin/channel/runtime/process.ts +84 -0
- package/plugin/channel/runtime/types.ts +45 -0
- package/plugin/channel/runtime-files.ts +73 -0
- package/plugin/channel/runtime-gateway.js +6396 -0
- package/plugin/channel/runtime-gateway.ts +358 -0
- package/plugin/channel/runtime-metrics.ts +52 -0
- package/plugin/channel/runtime-subscription.ts +180 -0
- package/plugin/channel/terminal-delivery.ts +131 -0
- package/plugin/channel/untrusted.ts +60 -0
- package/plugin/commands/committee.md +31 -0
- package/plugin/commands/exit.md +32 -0
- package/plugin/commands/goals.md +20 -0
- package/plugin/commands/join.md +18 -0
- package/plugin/commands/notice.md +20 -0
- package/plugin/commands/propose.md +19 -0
- package/plugin/commands/round.md +17 -0
- package/plugin/commands/session.md +22 -0
- package/plugin/commands/settings.md +25 -0
- package/plugin/commands/setup.md +21 -0
- package/plugin/commands/team.md +23 -0
- package/plugin/domains/custom.md +27 -0
- package/plugin/domains/finance.md +31 -0
- package/plugin/domains/healthcare.md +34 -0
- package/plugin/domains/legal.md +31 -0
- package/plugin/domains/marketing.md +33 -0
- package/plugin/domains/operations.md +31 -0
- package/plugin/domains/research.md +32 -0
- package/plugin/domains/sales.md +30 -0
- package/plugin/domains/software.md +37 -0
- package/plugin/hooks/activity.sh +6 -0
- package/plugin/hooks/digging.sh +68 -0
- package/plugin/hooks/growth.sh +42 -0
- package/plugin/hooks/hooks.json +106 -0
- package/plugin/hooks/notice-on-pr.sh +35 -0
- package/plugin/hooks/notice-on-stop.sh +80 -0
- package/plugin/hooks/notice-pending.sh +58 -0
- package/plugin/hooks/solo-en-ciudad.sh +23 -0
- package/plugin/hooks/tokens.sh +47 -0
- package/plugin/roles/examples/account-executive.md +25 -0
- package/plugin/roles/examples/ai-manager.md +34 -0
- package/plugin/roles/examples/associate.md +24 -0
- package/plugin/roles/examples/brand-lead.md +20 -0
- package/plugin/roles/examples/cfo.md +20 -0
- package/plugin/roles/examples/city-lead.md +25 -0
- package/plugin/roles/examples/clinical-director.md +26 -0
- package/plugin/roles/examples/clinical-ops.md +25 -0
- package/plugin/roles/examples/clinician.md +25 -0
- package/plugin/roles/examples/compliance.md +27 -0
- package/plugin/roles/examples/content.md +24 -0
- package/plugin/roles/examples/controller.md +27 -0
- package/plugin/roles/examples/cpto.md +41 -0
- package/plugin/roles/examples/customer-success.md +25 -0
- package/plugin/roles/examples/data-engineer.md +37 -0
- package/plugin/roles/examples/data.md +60 -0
- package/plugin/roles/examples/dev.md +37 -0
- package/plugin/roles/examples/devops.md +39 -0
- package/plugin/roles/examples/enablement.md +24 -0
- package/plugin/roles/examples/ethics.md +24 -0
- package/plugin/roles/examples/fin-analytics.md +27 -0
- package/plugin/roles/examples/health-compliance.md +25 -0
- package/plugin/roles/examples/health-data.md +26 -0
- package/plugin/roles/examples/knowledge.md +25 -0
- package/plugin/roles/examples/lifecycle.md +26 -0
- package/plugin/roles/examples/llm-engineer.md +34 -0
- package/plugin/roles/examples/managing-partner.md +20 -0
- package/plugin/roles/examples/methods.md +23 -0
- package/plugin/roles/examples/operations-lead.md +23 -0
- package/plugin/roles/examples/ops.md +24 -0
- package/plugin/roles/examples/patient-safety.md +26 -0
- package/plugin/roles/examples/performance.md +27 -0
- package/plugin/roles/examples/po.md +36 -0
- package/plugin/roles/examples/process-owner.md +23 -0
- package/plugin/roles/examples/product-design.md +39 -0
- package/plugin/roles/examples/program-manager.md +24 -0
- package/plugin/roles/examples/quality.md +25 -0
- package/plugin/roles/examples/research-director.md +24 -0
- package/plugin/roles/examples/research-ops.md +25 -0
- package/plugin/roles/examples/researcher.md +25 -0
- package/plugin/roles/examples/revenue-lead.md +25 -0
- package/plugin/roles/examples/revops.md +26 -0
- package/plugin/roles/examples/seo.md +27 -0
- package/plugin/roles/examples/specialist.md +24 -0
- package/plugin/scripts/actualiza.py +198 -0
- package/plugin/scripts/admision.py +165 -0
- package/plugin/scripts/apaga.py +232 -0
- package/plugin/scripts/atajos.py +506 -0
- package/plugin/scripts/avatar.py +211 -0
- package/plugin/scripts/broker.py +531 -0
- package/plugin/scripts/cage.py +492 -0
- package/plugin/scripts/capabilities.py +210 -0
- package/plugin/scripts/card.py +322 -0
- package/plugin/scripts/cities.py +520 -0
- package/plugin/scripts/city-env.sh +90 -0
- package/plugin/scripts/city-runtime.sh +87 -0
- package/plugin/scripts/city-session.sh +552 -0
- package/plugin/scripts/city_env.py +67 -0
- package/plugin/scripts/crecimiento.py +140 -0
- package/plugin/scripts/deliberations.py +48 -0
- package/plugin/scripts/doctor.py +294 -0
- package/plugin/scripts/domains.py +201 -0
- package/plugin/scripts/evidencia.py +64 -0
- package/plugin/scripts/find-repos.sh +111 -0
- package/plugin/scripts/gh.py +159 -0
- package/plugin/scripts/hall_protocol.py +147 -0
- package/plugin/scripts/hook_activity.py +139 -0
- package/plugin/scripts/launch.py +94 -0
- package/plugin/scripts/logs.py +98 -0
- package/plugin/scripts/pairing.py +185 -0
- package/plugin/scripts/parcels.py +132 -0
- package/plugin/scripts/read-card.py +55 -0
- package/plugin/scripts/report.py +201 -0
- package/plugin/scripts/reset.py +180 -0
- package/plugin/scripts/roads.py +230 -0
- package/plugin/scripts/roles.py +274 -0
- package/plugin/scripts/runtime_log.py +69 -0
- package/plugin/scripts/runtime_processes.py +132 -0
- package/plugin/scripts/rutas.py +83 -0
- package/plugin/scripts/seat.py +1696 -0
- package/plugin/scripts/tokens.py +194 -0
- package/plugin/scripts/trust-repos.py +59 -0
- package/plugin/scripts/ui.py +280 -0
- package/plugin/scripts/units.py +80 -0
- package/plugin/scripts/workspace.py +561 -0
- package/plugin/skills/city/SKILL.md +191 -0
- package/templates/blank.md +39 -0
- package/templates/finance.md +44 -0
- package/templates/legal.md +45 -0
- package/templates/marketing.md +48 -0
- package/templates/product.md +45 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""The city's door on the desktop: a real icon, a real bundle, a real command.
|
|
3
|
+
|
|
4
|
+
./bin/test-atajos.py
|
|
5
|
+
|
|
6
|
+
Everything lands in a throwaway "desktop" pointed at by CITY_DESKTOP, so this
|
|
7
|
+
never writes to the machine's real one. The load-bearing cases: the icon is a
|
|
8
|
+
valid PNG drawn from the city's own identity (no image library involved), the
|
|
9
|
+
shortcut runs the same front-door command a person would type, and removing it
|
|
10
|
+
leaves nothing behind.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import contextlib
|
|
14
|
+
import os
|
|
15
|
+
import shutil
|
|
16
|
+
import struct
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
import tempfile
|
|
20
|
+
|
|
21
|
+
AQUI = os.path.dirname(os.path.abspath(__file__))
|
|
22
|
+
RAIZ = os.path.dirname(AQUI)
|
|
23
|
+
sys.path.insert(0, os.path.join(RAIZ, "plugin", "scripts"))
|
|
24
|
+
sys.path.insert(0, AQUI)
|
|
25
|
+
|
|
26
|
+
import atajos # noqa: E402
|
|
27
|
+
from testlib import afirma, comprueba, resumen # noqa: E402
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@contextlib.contextmanager
|
|
31
|
+
def entorno(**claves):
|
|
32
|
+
"""Set env vars for a block and put the caller's own back afterwards.
|
|
33
|
+
|
|
34
|
+
Written once because these suites run inside somebody's real shell: a test
|
|
35
|
+
that leaves CITY_DESKTOP pointing at a deleted temp dir breaks the NEXT one.
|
|
36
|
+
"""
|
|
37
|
+
previos = {k: os.environ.get(k) for k in claves}
|
|
38
|
+
os.environ.update({k: v for k, v in claves.items() if v is not None})
|
|
39
|
+
try:
|
|
40
|
+
yield
|
|
41
|
+
finally:
|
|
42
|
+
for k, v in previos.items():
|
|
43
|
+
if v is None:
|
|
44
|
+
os.environ.pop(k, None)
|
|
45
|
+
else:
|
|
46
|
+
os.environ[k] = v
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _ciudad(base, nombre="Aurora Games", ident="city_test_v1"):
|
|
50
|
+
datos = os.path.join(base, "city")
|
|
51
|
+
os.makedirs(datos, exist_ok=True)
|
|
52
|
+
with open(os.path.join(datos, "city.yml"), "w", encoding="utf-8") as f:
|
|
53
|
+
f.write(f"id: {ident}\nname: {nombre}\nslug: aurora\nowner: ana\n")
|
|
54
|
+
return datos
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def el_icono():
|
|
58
|
+
print(" the icon, drawn from the city's own identity")
|
|
59
|
+
datos_png = atajos.icono_png("city_test_v1", 64)
|
|
60
|
+
afirma("· it is a real PNG, header and all", datos_png.startswith(b"\x89PNG\r\n\x1a\n"))
|
|
61
|
+
ancho, alto = struct.unpack(">II", datos_png[16:24])
|
|
62
|
+
comprueba("· at the size asked for", (ancho, alto), (64, 64))
|
|
63
|
+
afirma("· and it ends with the chunk that closes a PNG", datos_png.endswith(b"IEND\xaeB`\x82"))
|
|
64
|
+
# Same city, same colour, forever: derived from the identity, never stored
|
|
65
|
+
# and never random, so an icon does not change under somebody's cursor.
|
|
66
|
+
comprueba(
|
|
67
|
+
"· one city always gets the same colour",
|
|
68
|
+
atajos.color_de("city_test_v1"),
|
|
69
|
+
atajos.color_de("city_test_v1"),
|
|
70
|
+
)
|
|
71
|
+
distintos = {atajos.color_de(f"city_{i}") for i in range(40)}
|
|
72
|
+
afirma("· and different cities do not all look alike", len(distintos) > 1, str(distintos))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def el_atajo():
|
|
76
|
+
print(" the shortcut itself")
|
|
77
|
+
base = tempfile.mkdtemp(prefix="agents-city-atajo-")
|
|
78
|
+
mesa = os.path.join(base, "Desktop")
|
|
79
|
+
os.makedirs(mesa)
|
|
80
|
+
try:
|
|
81
|
+
with entorno(CITY_DESKTOP=mesa):
|
|
82
|
+
datos = _ciudad(base)
|
|
83
|
+
ruta, mal = atajos.crea(datos)
|
|
84
|
+
afirma("· it lands on the desktop, named after the city", not mal and os.path.exists(ruta),
|
|
85
|
+
f"{ruta} {mal}")
|
|
86
|
+
# Where a person reads the name differs by desktop: macOS shows the
|
|
87
|
+
# bundle's filename, GNOME and KDE show the entry's `Name=` field and
|
|
88
|
+
# never the filename. Assert the one the person actually sees.
|
|
89
|
+
# The command inside must be the front door, not a private re-launcher.
|
|
90
|
+
if sys.platform == "darwin":
|
|
91
|
+
afirma("· carrying the city's name where a person reads it",
|
|
92
|
+
"Aurora Games" in os.path.basename(ruta), os.path.basename(ruta))
|
|
93
|
+
guion = open(os.path.join(ruta, "Contents", "MacOS", "abrir-ciudad")).read()
|
|
94
|
+
info = os.path.join(ruta, "Contents", "Info.plist")
|
|
95
|
+
afirma("· the bundle has the Info.plist macOS needs to launch it",
|
|
96
|
+
os.path.isfile(info))
|
|
97
|
+
import plistlib
|
|
98
|
+
|
|
99
|
+
leido = plistlib.load(open(info, "rb"))
|
|
100
|
+
comprueba("· whose display name is the city's", leido["CFBundleDisplayName"],
|
|
101
|
+
"Aurora Games")
|
|
102
|
+
afirma("· and an icon file, when this machine can build one",
|
|
103
|
+
("CFBundleIconFile" in leido)
|
|
104
|
+
== os.path.isfile(os.path.join(ruta, "Contents", "Resources", "city.icns")),
|
|
105
|
+
str(sorted(os.listdir(os.path.join(ruta, "Contents", "Resources")))))
|
|
106
|
+
afirma("· double-clicking it opens a terminal, where a tmux city can live",
|
|
107
|
+
"osascript" in guion and "Terminal" in guion, guion)
|
|
108
|
+
else:
|
|
109
|
+
guion = open(ruta).read()
|
|
110
|
+
afirma("· carrying the city's name where a person reads it",
|
|
111
|
+
"Name=Aurora Games" in guion, guion)
|
|
112
|
+
afirma("· it is a desktop entry with a name and an icon",
|
|
113
|
+
"Name=Aurora Games" in guion and "Icon=" in guion, guion)
|
|
114
|
+
afirma("· that opens in a terminal, where a tmux city can live",
|
|
115
|
+
"Terminal=true" in guion, guion)
|
|
116
|
+
afirma("· running exactly the command a person would type",
|
|
117
|
+
"agents-city seat --city 'Aurora Games'" in guion, guion)
|
|
118
|
+
|
|
119
|
+
# The hall variant, for somebody who wants the map and not the tmux.
|
|
120
|
+
atajos.quita(datos)
|
|
121
|
+
ruta_hall, _ = atajos.crea(datos, hall=True)
|
|
122
|
+
guion_hall = (
|
|
123
|
+
open(os.path.join(ruta_hall, "Contents", "MacOS", "abrir-ciudad")).read()
|
|
124
|
+
if sys.platform == "darwin"
|
|
125
|
+
else open(ruta_hall).read()
|
|
126
|
+
)
|
|
127
|
+
afirma("· --hall makes the same door open the browser instead",
|
|
128
|
+
"agents-city hall --city" in guion_hall, guion_hall)
|
|
129
|
+
|
|
130
|
+
# Removing it leaves nothing: a shortcut you cannot take back is litter.
|
|
131
|
+
comprueba("· removing it says so", atajos.quita(datos), True)
|
|
132
|
+
comprueba("· and leaves an empty desktop behind", os.listdir(mesa), [])
|
|
133
|
+
comprueba("· removing one that is not there is not an error",
|
|
134
|
+
atajos.quita(datos), False)
|
|
135
|
+
finally:
|
|
136
|
+
shutil.rmtree(base, ignore_errors=True)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def caminos_infelices():
|
|
140
|
+
print(" what it refuses")
|
|
141
|
+
base = tempfile.mkdtemp(prefix="agents-city-atajo-")
|
|
142
|
+
try:
|
|
143
|
+
# No desktop is a real answer on a server, and it must not be a crash.
|
|
144
|
+
with entorno(CITY_DESKTOP=os.path.join(base, "nowhere")):
|
|
145
|
+
datos = _ciudad(base)
|
|
146
|
+
ruta, mal = atajos.crea(datos)
|
|
147
|
+
afirma("· a machine with no Desktop gets an explanation, not a traceback",
|
|
148
|
+
not ruta and "Desktop" in mal, f"{ruta} {mal}")
|
|
149
|
+
# …and can still put it somewhere it chooses.
|
|
150
|
+
elegido = os.path.join(base, "elsewhere")
|
|
151
|
+
os.makedirs(elegido)
|
|
152
|
+
ruta, mal = atajos.crea(datos, carpeta=elegido)
|
|
153
|
+
afirma("· --to writes it wherever it was asked for",
|
|
154
|
+
not mal and ruta.startswith(elegido), f"{ruta} {mal}")
|
|
155
|
+
ruta, mal = atajos.crea(os.path.join(base, "no-such-city"), carpeta=elegido)
|
|
156
|
+
afirma("· a city that does not exist is refused", not ruta and "no city" in mal, mal)
|
|
157
|
+
|
|
158
|
+
# A name with a quote in it must not break out of the door's quoting.
|
|
159
|
+
raro = _ciudad(base, nombre="Ana's City", ident="city_quote_v1")
|
|
160
|
+
comprueba(
|
|
161
|
+
"· a quote in a city name is quoted for the shell, never passed raw",
|
|
162
|
+
atajos.orden_de_ciudad(raro),
|
|
163
|
+
"agents-city seat --city 'Ana'\\''s City'",
|
|
164
|
+
)
|
|
165
|
+
ruta, mal = atajos.crea(raro, carpeta=elegido)
|
|
166
|
+
guion = (
|
|
167
|
+
open(os.path.join(ruta, "Contents", "MacOS", "abrir-ciudad")).read()
|
|
168
|
+
if sys.platform == "darwin"
|
|
169
|
+
else open(ruta).read()
|
|
170
|
+
)
|
|
171
|
+
afirma(
|
|
172
|
+
"· and the written door never carries the unquoted form",
|
|
173
|
+
"--city 'Ana's City'" not in guion and "Ana" in guion,
|
|
174
|
+
guion,
|
|
175
|
+
)
|
|
176
|
+
if sys.platform == "darwin":
|
|
177
|
+
# The command travels inside an AppleScript string, so its
|
|
178
|
+
# backslashes are escaped once more; AppleScript unescapes them and
|
|
179
|
+
# Terminal receives exactly the shell-quoted line asserted above.
|
|
180
|
+
afirma(
|
|
181
|
+
"· macOS escapes it once more for AppleScript, and no further",
|
|
182
|
+
"'Ana'\\\\''s City'" in guion,
|
|
183
|
+
guion,
|
|
184
|
+
)
|
|
185
|
+
finally:
|
|
186
|
+
shutil.rmtree(base, ignore_errors=True)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def cada_escritorio():
|
|
190
|
+
"""Every desktop's writer, exercised on whatever machine runs this.
|
|
191
|
+
|
|
192
|
+
`crea` picks one by platform, so a suite that only ever calls `crea` tests
|
|
193
|
+
one third of this file and lets the other two rot until CI meets them. Each
|
|
194
|
+
writer is therefore called directly here — this is the tombstone of a Linux
|
|
195
|
+
break that a Mac could not see.
|
|
196
|
+
"""
|
|
197
|
+
print(" all three desktops, from whichever one we are on")
|
|
198
|
+
base = tempfile.mkdtemp(prefix="agents-city-todos-")
|
|
199
|
+
try:
|
|
200
|
+
datos = _ciudad(base, nombre="Aurora Games", ident="city_all_v1")
|
|
201
|
+
mesa = os.path.join(base, "Desktop")
|
|
202
|
+
os.makedirs(mesa)
|
|
203
|
+
orden = atajos.orden_de_ciudad(datos)
|
|
204
|
+
with entorno(XDG_DATA_HOME=os.path.join(base, "share")):
|
|
205
|
+
entrada = atajos._crea_linux(datos, mesa, "Aurora Games", orden, "city_all_v1")
|
|
206
|
+
texto = open(entrada, encoding="utf-8").read()
|
|
207
|
+
afirma("· the Linux entry names the city where GNOME and KDE read it",
|
|
208
|
+
"Name=Aurora Games" in texto, texto)
|
|
209
|
+
icono = [ln[5:] for ln in texto.splitlines() if ln.startswith("Icon=")]
|
|
210
|
+
afirma("· and points at an icon file that is really there",
|
|
211
|
+
icono and os.path.isfile(icono[0]), str(icono))
|
|
212
|
+
afirma("· running the same front-door command as every other desktop",
|
|
213
|
+
orden in texto, texto)
|
|
214
|
+
|
|
215
|
+
paquete = atajos._crea_mac(datos, mesa, "Aurora Games", orden, "city_all_v1")
|
|
216
|
+
arranque = os.path.join(paquete, "Contents", "MacOS", "abrir-ciudad")
|
|
217
|
+
afirma("· the macOS bundle is a folder with an executable inside",
|
|
218
|
+
os.path.isfile(arranque) and os.access(arranque, os.X_OK), paquete)
|
|
219
|
+
afirma("· running that same command",
|
|
220
|
+
orden in open(arranque, encoding="utf-8").read())
|
|
221
|
+
finally:
|
|
222
|
+
shutil.rmtree(base, ignore_errors=True)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def windows_bajo_wsl():
|
|
226
|
+
"""On Windows the product runs inside WSL, and that changes everything here.
|
|
227
|
+
|
|
228
|
+
A `~/Desktop` inside WSL is the Linux home's desktop, which nobody looks at:
|
|
229
|
+
the desktop with icons on it belongs to Windows. So the shortcut has to be a
|
|
230
|
+
Windows one, crossing back into WSL to start the city.
|
|
231
|
+
"""
|
|
232
|
+
print(" Windows, which is WSL wearing a Linux coat")
|
|
233
|
+
base = tempfile.mkdtemp(prefix="agents-city-wsl-")
|
|
234
|
+
try:
|
|
235
|
+
datos = _ciudad(base, nombre="Aurora Games", ident="city_wsl_v1")
|
|
236
|
+
mesa = os.path.join(base, "Desktop")
|
|
237
|
+
os.makedirs(mesa)
|
|
238
|
+
|
|
239
|
+
# Detection: WSL announces itself in the environment and in /proc.
|
|
240
|
+
with entorno(WSL_DISTRO_NAME="Ubuntu"):
|
|
241
|
+
afirma("· a WSL environment is recognised as Windows", atajos.en_wsl())
|
|
242
|
+
|
|
243
|
+
# The icon Windows needs: an ICO, which since Vista may simply wrap a
|
|
244
|
+
# PNG — so the same hand-written image serves both desktops.
|
|
245
|
+
crudo = atajos.ico("city_wsl_v1", 256)
|
|
246
|
+
reserva, tipo, cuantos = struct.unpack("<HHH", crudo[:6])
|
|
247
|
+
afirma("· the Windows icon is a valid single-image ICO",
|
|
248
|
+
(reserva, tipo, cuantos) == (0, 1, 1), str((reserva, tipo, cuantos)))
|
|
249
|
+
tam, desplazamiento = struct.unpack("<II", crudo[14:22])
|
|
250
|
+
afirma("· whose directory points at the PNG it carries",
|
|
251
|
+
crudo[desplazamiento:desplazamiento + 8] == b"\x89PNG\r\n\x1a\n"
|
|
252
|
+
and desplazamiento + tam == len(crudo),
|
|
253
|
+
f"offset {desplazamiento} size {tam} total {len(crudo)}")
|
|
254
|
+
|
|
255
|
+
# With no interop (a WSL with no powershell.exe reachable), it still
|
|
256
|
+
# writes a door: a .cmd, which double-clicks fine and only lacks an icon.
|
|
257
|
+
ruta = atajos._crea_wsl(
|
|
258
|
+
datos, mesa, "Aurora Games", atajos.orden_de_ciudad(datos), "city_wsl_v1"
|
|
259
|
+
)
|
|
260
|
+
guion = open(ruta, encoding="utf-8").read()
|
|
261
|
+
afirma("· without interop it still writes a double-clickable .cmd",
|
|
262
|
+
ruta.endswith(".cmd") and os.path.isfile(ruta), ruta)
|
|
263
|
+
afirma("· that crosses back into WSL to open the city",
|
|
264
|
+
"wsl.exe" in guion and "agents-city seat --city 'Aurora Games'" in guion, guion)
|
|
265
|
+
afirma("· in a login shell, so the PATH holds the command it runs",
|
|
266
|
+
"bash -lic" in guion, guion)
|
|
267
|
+
afirma("· with CRLF line endings, which is what cmd.exe reads",
|
|
268
|
+
"\r\n" in open(ruta, newline="", encoding="utf-8").read(), repr(guion))
|
|
269
|
+
# And removing it finds the Windows shapes too, not only the Unix ones.
|
|
270
|
+
with entorno(CITY_DESKTOP=mesa):
|
|
271
|
+
comprueba("· removal knows about .cmd and .lnk as well",
|
|
272
|
+
atajos.quita(datos), True)
|
|
273
|
+
comprueba("· and leaves the desktop clean", os.listdir(mesa), [])
|
|
274
|
+
finally:
|
|
275
|
+
shutil.rmtree(base, ignore_errors=True)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def la_puerta():
|
|
279
|
+
print(" the command in the front door")
|
|
280
|
+
ayuda = subprocess.run(
|
|
281
|
+
[sys.executable, os.path.join(RAIZ, "plugin", "scripts", "atajos.py"), "--help"],
|
|
282
|
+
capture_output=True,
|
|
283
|
+
text=True,
|
|
284
|
+
timeout=60,
|
|
285
|
+
)
|
|
286
|
+
afirma("· `agents-city shortcut --help` explains itself",
|
|
287
|
+
"shortcut" in ayuda.stdout and "--remove" in ayuda.stdout, ayuda.stdout)
|
|
288
|
+
front = open(os.path.join(RAIZ, "bin", "agents-city.js"), encoding="utf-8").read()
|
|
289
|
+
afirma("· and the npm front door lists it", "shortcut:" in front)
|
|
290
|
+
afirma("· pointing at the one implementation", "bin/shortcut" in front)
|
|
291
|
+
guion = open(os.path.join(RAIZ, "bin", "shortcut"), encoding="utf-8").read()
|
|
292
|
+
afirma("· which holds no logic of its own", "atajos.py" in guion and "def " not in guion)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
el_icono()
|
|
296
|
+
el_atajo()
|
|
297
|
+
caminos_infelices()
|
|
298
|
+
cada_escritorio()
|
|
299
|
+
windows_bajo_wsl()
|
|
300
|
+
la_puerta()
|
|
301
|
+
sys.exit(resumen("atajos"))
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Deterministic agent avatars: same name → same face, self-contained SVG.
|
|
3
|
+
|
|
4
|
+
Pure. The load-bearing cases: determinism, distinctness, symmetry, that the
|
|
5
|
+
output is a self-contained SVG with no external reference (Hall CSP), and that
|
|
6
|
+
the kind tints the border.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
AQUI = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
RAIZ = os.path.dirname(AQUI)
|
|
14
|
+
sys.path.insert(0, os.path.join(RAIZ, "plugin", "scripts"))
|
|
15
|
+
sys.path.insert(0, AQUI)
|
|
16
|
+
|
|
17
|
+
import avatar # noqa: E402
|
|
18
|
+
from testlib import afirma, comprueba, resumen # noqa: E402
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def determinismo():
|
|
22
|
+
comprueba("same name and kind produce identical SVG",
|
|
23
|
+
avatar.svg("nova", "code"), avatar.svg("nova", "code"))
|
|
24
|
+
afirma("different names produce different faces",
|
|
25
|
+
avatar.svg("nova") != avatar.svg("store-service"))
|
|
26
|
+
afirma("the empty/None name is handled, not crashed",
|
|
27
|
+
avatar.svg(None).startswith("<svg") and avatar.svg("").startswith("<svg"))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def autocontenido():
|
|
31
|
+
s = avatar.svg("nova")
|
|
32
|
+
afirma("it is an svg element", s.startswith("<svg") and s.endswith("</svg>"))
|
|
33
|
+
afirma("it references no external asset (Hall CSP)",
|
|
34
|
+
"http://www.w3.org/2000/svg" in s
|
|
35
|
+
and "https://" not in s.replace("http://www.w3.org/2000/svg", "")
|
|
36
|
+
and "url(" not in s and "<image" not in s and "<script" not in s)
|
|
37
|
+
afirma("a hostile name cannot break out of the aria-label",
|
|
38
|
+
"<script>" not in avatar.svg('<script>x</script>'))
|
|
39
|
+
afirma("data_uri is a base64 svg data URI",
|
|
40
|
+
avatar.data_uri("nova").startswith("data:image/svg+xml;base64,"))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def clase_y_simetria():
|
|
44
|
+
afirma("kind tints the border colour",
|
|
45
|
+
avatar.TINTE_CLASE["knowledge"] in avatar.svg("x", "knowledge"))
|
|
46
|
+
afirma("an unknown kind falls back to the default tint",
|
|
47
|
+
avatar._TINTE_DEFECTO in avatar.svg("x", "nonsense"))
|
|
48
|
+
# Symmetry: the on-cells are mirrored left↔right, so the set is closed under
|
|
49
|
+
# (row, col) -> (row, 4-col).
|
|
50
|
+
encendidas = avatar._celdas_encendidas(avatar._digest("nova"))
|
|
51
|
+
afirma("the cell pattern is left-right symmetric",
|
|
52
|
+
all((f, avatar._CELDAS - 1 - c) in encendidas for (f, c) in encendidas))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
determinismo()
|
|
56
|
+
autocontenido()
|
|
57
|
+
clase_y_simetria()
|
|
58
|
+
sys.exit(resumen("avatar"))
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""The governance benchmark stays honest and machine-readable."""
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
AQUI = os.path.dirname(os.path.abspath(__file__))
|
|
9
|
+
RAIZ = os.path.dirname(AQUI)
|
|
10
|
+
sys.path.insert(0, AQUI)
|
|
11
|
+
from testlib import afirma, comprueba, resumen # noqa: E402
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
print('\n committee governance benchmark')
|
|
16
|
+
result = subprocess.run(
|
|
17
|
+
[sys.executable, os.path.join(RAIZ, 'benchmarks', 'committee', 'run.py'),
|
|
18
|
+
'--json'], capture_output=True, text=True)
|
|
19
|
+
afirma('· the benchmark runs without a model account',
|
|
20
|
+
result.returncode == 0, result.stderr.strip())
|
|
21
|
+
report = json.loads(result.stdout)
|
|
22
|
+
comprueba('· its scope refuses an unsupported quality claim',
|
|
23
|
+
report.get('scope'), 'protocol structure, not task-answer quality')
|
|
24
|
+
rows = {row['strategy']: row for row in report['results']}
|
|
25
|
+
afirma('· free mesh exposes lateral edges and pre-barrier influence',
|
|
26
|
+
rows['free-mesh']['lateral_member_edges'] > 0
|
|
27
|
+
and rows['free-mesh']['pre_barrier_leaks'] > 0)
|
|
28
|
+
afirma('· a single agent cannot independently verify itself',
|
|
29
|
+
rows['single-agent']['closures_without_pass'] == 1
|
|
30
|
+
and rows['single-agent']['self_verified_closures'] == 1
|
|
31
|
+
and rows['single-agent']['unattributed_decisions'] == 1)
|
|
32
|
+
afirma('· the chaired trace satisfies every measured invariant',
|
|
33
|
+
rows['chair-mediated']['protocol_violations'] == 0)
|
|
34
|
+
afirma('· that result includes evidence from distinct repo roles',
|
|
35
|
+
rows['chair-mediated']['evidence_sources'] >= 3)
|
|
36
|
+
return resumen('benchmark')
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == '__main__':
|
|
40
|
+
sys.exit(main())
|