agents-city 0.3.0-beta.21
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 +2021 -0
- package/README.md +1999 -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 +116 -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/exit +5 -0
- package/bin/hall +73 -0
- package/bin/hall.html +426 -0
- package/bin/logs +3 -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 +1428 -0
- package/bin/setup.py +753 -0
- package/bin/skills +3 -0
- package/bin/test +131 -0
- package/bin/test-adapter.py +183 -0
- package/bin/test-admision.py +99 -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 +206 -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 +544 -0
- package/bin/test-crecimiento.py +164 -0
- package/bin/test-demo.py +308 -0
- package/bin/test-doctor.py +106 -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-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 +1386 -0
- package/bin/test-security.py +150 -0
- package/bin/test-serve.py +1057 -0
- package/bin/test-stress.py +64 -0
- package/bin/test-widgets.py +143 -0
- package/bin/test-workspace.py +188 -0
- package/bin/testlib.py +95 -0
- package/bin/tokens.py +14 -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 +264 -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 +1867 -0
- package/city/web/src/main.ts +2225 -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 +99 -0
- package/docs/glossary.md +55 -0
- package/docs/map-live-layers.md +73 -0
- package/docs/security.md +231 -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/admision.py +165 -0
- package/plugin/scripts/apaga.py +232 -0
- package/plugin/scripts/avatar.py +211 -0
- package/plugin/scripts/broker.py +531 -0
- package/plugin/scripts/cage.py +252 -0
- package/plugin/scripts/capabilities.py +197 -0
- package/plugin/scripts/card.py +312 -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 +526 -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 +172 -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 +51 -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 +1349 -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 +364 -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,248 @@
|
|
|
1
|
+
{
|
|
2
|
+
"building-a": {
|
|
3
|
+
"alto": 1.293,
|
|
4
|
+
"ancho": 0.94,
|
|
5
|
+
"ancla": 0.75,
|
|
6
|
+
"pxUnidad": 75.294
|
|
7
|
+
},
|
|
8
|
+
"building-b": {
|
|
9
|
+
"alto": 1.293,
|
|
10
|
+
"ancho": 0.97,
|
|
11
|
+
"ancla": 0.75,
|
|
12
|
+
"pxUnidad": 75.294
|
|
13
|
+
},
|
|
14
|
+
"building-c": {
|
|
15
|
+
"alto": 0.893,
|
|
16
|
+
"ancho": 1.09,
|
|
17
|
+
"ancla": 0.75,
|
|
18
|
+
"pxUnidad": 75.294
|
|
19
|
+
},
|
|
20
|
+
"building-d": {
|
|
21
|
+
"alto": 1.293,
|
|
22
|
+
"ancho": 0.9,
|
|
23
|
+
"ancla": 0.75,
|
|
24
|
+
"pxUnidad": 75.294
|
|
25
|
+
},
|
|
26
|
+
"building-e": {
|
|
27
|
+
"alto": 0.893,
|
|
28
|
+
"ancho": 1.64,
|
|
29
|
+
"ancla": 0.75,
|
|
30
|
+
"pxUnidad": 75.294
|
|
31
|
+
},
|
|
32
|
+
"building-f": {
|
|
33
|
+
"alto": 1.693,
|
|
34
|
+
"ancho": 1.03,
|
|
35
|
+
"ancla": 0.75,
|
|
36
|
+
"pxUnidad": 75.294
|
|
37
|
+
},
|
|
38
|
+
"building-g": {
|
|
39
|
+
"alto": 1.693,
|
|
40
|
+
"ancho": 0.97,
|
|
41
|
+
"ancla": 0.75,
|
|
42
|
+
"pxUnidad": 75.294
|
|
43
|
+
},
|
|
44
|
+
"building-h": {
|
|
45
|
+
"alto": 1.293,
|
|
46
|
+
"ancho": 1.008,
|
|
47
|
+
"ancla": 0.75,
|
|
48
|
+
"pxUnidad": 75.294
|
|
49
|
+
},
|
|
50
|
+
"building-i": {
|
|
51
|
+
"alto": 1.68,
|
|
52
|
+
"ancho": 1.302,
|
|
53
|
+
"ancla": 0.75,
|
|
54
|
+
"pxUnidad": 75.294
|
|
55
|
+
},
|
|
56
|
+
"building-j": {
|
|
57
|
+
"alto": 1.693,
|
|
58
|
+
"ancho": 2.084,
|
|
59
|
+
"ancla": 0.75,
|
|
60
|
+
"pxUnidad": 75.294
|
|
61
|
+
},
|
|
62
|
+
"building-k": {
|
|
63
|
+
"alto": 1.47,
|
|
64
|
+
"ancho": 2.084,
|
|
65
|
+
"ancla": 0.75,
|
|
66
|
+
"pxUnidad": 75.294
|
|
67
|
+
},
|
|
68
|
+
"building-l": {
|
|
69
|
+
"alto": 2.27,
|
|
70
|
+
"ancho": 1.402,
|
|
71
|
+
"ancla": 0.75,
|
|
72
|
+
"pxUnidad": 75.294
|
|
73
|
+
},
|
|
74
|
+
"building-m": {
|
|
75
|
+
"alto": 3.15,
|
|
76
|
+
"ancho": 1.242,
|
|
77
|
+
"ancla": 0.75,
|
|
78
|
+
"pxUnidad": 75.294
|
|
79
|
+
},
|
|
80
|
+
"building-n": {
|
|
81
|
+
"alto": 2.48,
|
|
82
|
+
"ancho": 2.32,
|
|
83
|
+
"ancla": 0.75,
|
|
84
|
+
"pxUnidad": 75.294
|
|
85
|
+
},
|
|
86
|
+
"building-skyscraper-a": {
|
|
87
|
+
"alto": 2.88,
|
|
88
|
+
"ancho": 1.36,
|
|
89
|
+
"ancla": 0.75,
|
|
90
|
+
"pxUnidad": 75.294
|
|
91
|
+
},
|
|
92
|
+
"building-skyscraper-b": {
|
|
93
|
+
"alto": 4.48,
|
|
94
|
+
"ancho": 1.36,
|
|
95
|
+
"ancla": 0.75,
|
|
96
|
+
"pxUnidad": 75.294
|
|
97
|
+
},
|
|
98
|
+
"building-skyscraper-c": {
|
|
99
|
+
"alto": 4.08,
|
|
100
|
+
"ancho": 1.388,
|
|
101
|
+
"ancla": 0.75,
|
|
102
|
+
"pxUnidad": 75.294
|
|
103
|
+
},
|
|
104
|
+
"building-skyscraper-d": {
|
|
105
|
+
"alto": 5.47,
|
|
106
|
+
"ancho": 1.388,
|
|
107
|
+
"ancla": 0.75,
|
|
108
|
+
"pxUnidad": 75.294
|
|
109
|
+
},
|
|
110
|
+
"building-skyscraper-e": {
|
|
111
|
+
"alto": 4.08,
|
|
112
|
+
"ancho": 1.295,
|
|
113
|
+
"ancla": 0.75,
|
|
114
|
+
"pxUnidad": 75.294
|
|
115
|
+
},
|
|
116
|
+
"detail-awning": {
|
|
117
|
+
"alto": 0.4,
|
|
118
|
+
"ancho": 0.4,
|
|
119
|
+
"ancla": 0.75,
|
|
120
|
+
"pxUnidad": 75.294
|
|
121
|
+
},
|
|
122
|
+
"detail-awning-wide": {
|
|
123
|
+
"alto": 0.4,
|
|
124
|
+
"ancho": 0.8,
|
|
125
|
+
"ancla": 0.75,
|
|
126
|
+
"pxUnidad": 75.294
|
|
127
|
+
},
|
|
128
|
+
"detail-overhang": {
|
|
129
|
+
"alto": 0.4,
|
|
130
|
+
"ancho": 0.5,
|
|
131
|
+
"ancla": 0.75,
|
|
132
|
+
"pxUnidad": 75.294
|
|
133
|
+
},
|
|
134
|
+
"detail-overhang-wide": {
|
|
135
|
+
"alto": 0.4,
|
|
136
|
+
"ancho": 1,
|
|
137
|
+
"ancla": 0.75,
|
|
138
|
+
"pxUnidad": 75.294
|
|
139
|
+
},
|
|
140
|
+
"detail-parasol-a": {
|
|
141
|
+
"alto": 0.45,
|
|
142
|
+
"ancho": 0.4,
|
|
143
|
+
"ancla": 0.75,
|
|
144
|
+
"pxUnidad": 75.294
|
|
145
|
+
},
|
|
146
|
+
"detail-parasol-b": {
|
|
147
|
+
"alto": 0.45,
|
|
148
|
+
"ancho": 0.4,
|
|
149
|
+
"ancla": 0.75,
|
|
150
|
+
"pxUnidad": 75.294
|
|
151
|
+
},
|
|
152
|
+
"low-detail-building-a": {
|
|
153
|
+
"alto": 2,
|
|
154
|
+
"ancho": 0.5,
|
|
155
|
+
"ancla": 0.75,
|
|
156
|
+
"pxUnidad": 75.294
|
|
157
|
+
},
|
|
158
|
+
"low-detail-building-b": {
|
|
159
|
+
"alto": 2.225,
|
|
160
|
+
"ancho": 0.5,
|
|
161
|
+
"ancla": 0.75,
|
|
162
|
+
"pxUnidad": 75.294
|
|
163
|
+
},
|
|
164
|
+
"low-detail-building-c": {
|
|
165
|
+
"alto": 2.25,
|
|
166
|
+
"ancho": 0.5,
|
|
167
|
+
"ancla": 0.75,
|
|
168
|
+
"pxUnidad": 75.294
|
|
169
|
+
},
|
|
170
|
+
"low-detail-building-d": {
|
|
171
|
+
"alto": 1.75,
|
|
172
|
+
"ancho": 0.5,
|
|
173
|
+
"ancla": 0.75,
|
|
174
|
+
"pxUnidad": 75.294
|
|
175
|
+
},
|
|
176
|
+
"low-detail-building-e": {
|
|
177
|
+
"alto": 1.8,
|
|
178
|
+
"ancho": 0.5,
|
|
179
|
+
"ancla": 0.75,
|
|
180
|
+
"pxUnidad": 75.294
|
|
181
|
+
},
|
|
182
|
+
"low-detail-building-f": {
|
|
183
|
+
"alto": 2,
|
|
184
|
+
"ancho": 0.5,
|
|
185
|
+
"ancla": 0.75,
|
|
186
|
+
"pxUnidad": 75.294
|
|
187
|
+
},
|
|
188
|
+
"low-detail-building-g": {
|
|
189
|
+
"alto": 2,
|
|
190
|
+
"ancho": 0.5,
|
|
191
|
+
"ancla": 0.75,
|
|
192
|
+
"pxUnidad": 75.294
|
|
193
|
+
},
|
|
194
|
+
"low-detail-building-h": {
|
|
195
|
+
"alto": 2.1,
|
|
196
|
+
"ancho": 0.5,
|
|
197
|
+
"ancla": 0.75,
|
|
198
|
+
"pxUnidad": 75.294
|
|
199
|
+
},
|
|
200
|
+
"low-detail-building-i": {
|
|
201
|
+
"alto": 1.775,
|
|
202
|
+
"ancho": 0.5,
|
|
203
|
+
"ancla": 0.75,
|
|
204
|
+
"pxUnidad": 75.294
|
|
205
|
+
},
|
|
206
|
+
"low-detail-building-j": {
|
|
207
|
+
"alto": 1.75,
|
|
208
|
+
"ancho": 0.5,
|
|
209
|
+
"ancla": 0.75,
|
|
210
|
+
"pxUnidad": 75.294
|
|
211
|
+
},
|
|
212
|
+
"low-detail-building-k": {
|
|
213
|
+
"alto": 1.55,
|
|
214
|
+
"ancho": 0.5,
|
|
215
|
+
"ancla": 0.75,
|
|
216
|
+
"pxUnidad": 75.294
|
|
217
|
+
},
|
|
218
|
+
"low-detail-building-l": {
|
|
219
|
+
"alto": 1.85,
|
|
220
|
+
"ancho": 0.5,
|
|
221
|
+
"ancla": 0.75,
|
|
222
|
+
"pxUnidad": 75.294
|
|
223
|
+
},
|
|
224
|
+
"low-detail-building-m": {
|
|
225
|
+
"alto": 1.975,
|
|
226
|
+
"ancho": 0.5,
|
|
227
|
+
"ancla": 0.75,
|
|
228
|
+
"pxUnidad": 75.294
|
|
229
|
+
},
|
|
230
|
+
"low-detail-building-n": {
|
|
231
|
+
"alto": 0.7,
|
|
232
|
+
"ancho": 0.5,
|
|
233
|
+
"ancla": 0.75,
|
|
234
|
+
"pxUnidad": 75.294
|
|
235
|
+
},
|
|
236
|
+
"low-detail-building-wide-a": {
|
|
237
|
+
"alto": 1.1,
|
|
238
|
+
"ancho": 1,
|
|
239
|
+
"ancla": 0.75,
|
|
240
|
+
"pxUnidad": 75.294
|
|
241
|
+
},
|
|
242
|
+
"low-detail-building-wide-b": {
|
|
243
|
+
"alto": 1.15,
|
|
244
|
+
"ancho": 1,
|
|
245
|
+
"ancla": 0.75,
|
|
246
|
+
"pxUnidad": 75.294
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
function Z(e,a){return Object.fromEntries([...e].sort().map(i=>[i,a[i]||"blank"]))}function K(e,a,i,o){let t=[...e].sort();return t.length?`<div class="agenteRoles">${t.map(r=>{let n=a[r]||"blank",c=i.some(p=>p.id===n)?i:[{id:n,name:`${n} (city-defined)`,summary:"Role defined in this city rather than the built-in catalogue.",trade:n,domains:[]},...i];return`<div class="agenteRol">
|
|
2
|
+
<div><code>${o(r)}</code><span>support agent \xB7 member</span></div>
|
|
3
|
+
<select data-repo-role="${o(r)}" aria-label="Operating role for ${o(r)}">
|
|
4
|
+
${c.map(p=>{let h=p.domains.filter(m=>m!=="custom").join(", "),y=h?` \xB7 ${h}`:"";return`<option value="${o(p.id)}"${p.id===n?" selected":""}
|
|
5
|
+
title="${o(p.summary)}">${o(p.name)}${o(y)}</option>`}).join("")}
|
|
6
|
+
</select>
|
|
7
|
+
</div>`}).join("")}</div>`:'<p class="prosa">No repo agents in this city.</p>'}var N="agents-city-map-activity/1";function ee(e){if(!e||typeof e!="object")return!1;let a=e;return a.protocol===N&&a.type==="map.nav"&&typeof a.view=="string"}function F(e){if(!e||typeof e!="object")return!1;let a=e;return a.protocol==="agents-city-activity/1"&&typeof a.id=="string"&&typeof a.seq=="number"&&typeof a.kind=="string"&&typeof a.actor=="string"&&typeof a.summary=="string"&&typeof a.title=="string"&&Array.isArray(a.details)}function te(e){return e.kind==="conversation.user"||e.kind==="conversation.agent"||e.kind==="runtime.session.started"||e.kind==="runtime.session.ended"}function ne(e){return e.kind==="conversation.agent"||e.kind==="conversation.agent.commentary"?!!e.summary.trim():e.kind==="committee.opened"||e.kind==="committee.position.revealed"||e.kind==="committee.synthesis.published"||e.kind.startsWith("committee.floor.")||e.kind==="committee.decision.recorded"||e.kind.startsWith("committee.verification.")||e.kind==="committee.replanned"||e.kind==="committee.closed"||e.kind==="committee.command.rejected"&&e.tone==="error"}var q=window.PASE,ie=new URLSearchParams(location.search).get("city")??"";async function f(e,a){let i=e+(e.includes("?")?"&":"?")+"PASE="+encodeURIComponent(q);return ie&&(i+="&city="+encodeURIComponent(ie)),(await fetch(i,{headers:{"X-City-Pase":q,"Content-Type":"application/json"},...a})).json()}function d(e,a=document){let i=a.querySelector(e);if(!i)throw new Error(`no element matches ${e}`);return i}function b(e,a=document){return[...a.querySelectorAll(e)]}function s(e){return String(e??"").replace(/[&<>"']/g,a=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[a])}var z=e=>e.replace(l.casa,"~"),ae=0;function v(e,a=!1){let i=d("#toast");i.textContent=e,i.className="ver"+(a?" mal":""),clearTimeout(ae),ae=window.setTimeout(()=>{i.className=""},3200)}var re=e=>new Promise(a=>setTimeout(a,e)),l,j="mapa",ve=[["resumen","Overview"],["mapa","The map"],["puesto","My seat"],["barrios","Districts & houses"],["red","Roads"],["committee","Committee"],["gente","Agents & skills"]];async function M(){l=await f("/api/estado"),w(),he(),ce(l.live_bus)}function he(){let e=document.querySelector("#livePanel header"),a=document.getElementById("demoControles");if(!e||!l.demo){a?.remove();return}if(a)return;let i=document.createElement("div");i.id="demoControles",i.innerHTML='<span>guided committee</span><button id="demoReplay" type="button" title="Play the guided committee from the top">\u27F3 replay</button><button id="demoPausa" type="button" title="Pause or resume mid-scene">\u23F8 pause</button>',e.appendChild(i);let o=d("#demoPausa",i),t=r=>f("/api/demo",{method:"POST",body:JSON.stringify({action:r})});d("#demoReplay",i).onclick=async()=>{let r=await t("restart");o.textContent="\u23F8 pause",r.ok||v("Could not restart the demo",!0)},o.onclick=async()=>{let r=o.textContent?.includes("resume")??!1,n=await t(r?"resume":"pause");if(!n.running){o.textContent="\u23F8 pause",v("Nothing playing \u2014 hit replay",!0);return}o.textContent=n.paused?"\u25B6 resume":"\u23F8 pause"}}var T=null,V="",k=[],H=!1,_=0,P=null,le=!1,A=!1,D=null;function ce(e){if(!e?.online||!e.url){H=!1,E(),G();return}if(e.url===V&&T&&(T.readyState===WebSocket.OPEN||T.readyState===WebSocket.CONNECTING))return;let a=T;a&&(a.onclose=null,a.close()),V=e.url;let i=new WebSocket(e.url);T=i,H=!1,E(),i.onopen=()=>{T===i&&(H=!0,_=0,E())},i.onmessage=o=>{if(T!==i)return;let t;try{t=JSON.parse(String(o.data))}catch{return}if(t.type==="activity.state")k=Array.isArray(t.events)?t.events.filter(F):[],k.sort((r,n)=>r.seq-n.seq),P===null&&(P=ye()),E(!0);else if(t.type==="activity.event"&&F(t.event)){let r=t.event;k.some(n=>n.id===r.id)||k.push(r),k=k.sort((n,c)=>n.seq-c.seq).slice(-200),!le&&r.kind==="committee.opened"&&r.thread&&(P=r.thread),E(!0),de(r)}},i.onclose=()=>{T===i&&(T=null,H=!1,E(),G())},i.onerror=()=>{}}function de(e){let a=e.kind.startsWith("committee.");if(!ne(e)&&!te(e)&&!a)return;let i=document.querySelector("#cityMapFrame");if(!i)return;if(i.dataset.ready!=="1"){D=e;return}let o=new URL(i.src,location.href).origin;i.contentWindow?.postMessage({protocol:N,type:"activity.event",event:e},o)}function G(){_||(_=window.setTimeout(async()=>{_=0;try{ce(await f("/api/live"))}catch{G()}},1500))}function E(e=!1){let a=document.querySelector("#liveDot"),i=document.querySelector("#liveState"),o=document.querySelector("#liveEvents"),t=document.querySelector("#liveFilter"),r=document.querySelector("#liveContext"),n=document.querySelector("#liveWorkToggle");if(!a||!i||!o||!t||!r||!n)return;a.classList.toggle("on",H),i.textContent=H?"websocket live":V?"reconnecting":"session offline";let c=new Map;for(let g of k)g.thread&&(g.kind==="committee.opened"||g.kind==="conversation.user")&&!Y(g)&&!c.has(g.thread)&&c.set(g.thread,g.summary);t.innerHTML='<option value="">all conversations</option>'+[...c.entries()].reverse().map(([g,L])=>`<option value="${s(g)}">${s(L.slice(0,54)||g)}</option>`).join("");let p=P||"";t.value=[...t.options].some(g=>g.value===p)?p:"",t.onchange=()=>{P=t.value,le=!0,E(!0)},n.classList.toggle("on",A),n.setAttribute("aria-pressed",String(A)),n.textContent=A?"hide work":"show work",n.onclick=()=>{A=!A,E(!0)},be(t.value,r);let y=(t.value?k.filter(g=>g.thread===t.value):k).filter(g=>!Y(g)&&(A||!$e(g)||g.tone==="error"));if(!y.length){o.innerHTML=`<li class="liveEmpty">${H?"The bus is live. Questions, positions and moderated replies will appear here.":"Start the city session. Its visible conversation will appear here as it happens."}</li>`;return}let m=o.scrollHeight-o.scrollTop-o.clientHeight<90;o.innerHTML=y.map(fe).join(""),(e||m)&&(o.scrollTop=o.scrollHeight)}function fe(e){let a=new Date(e.at),i=Number.isNaN(a.getTime())?"":a.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),o=e.role==="chair"?"chair":e.role==="member"?"member":"system",t=pe(e.actor),r=e.target&&!["committee","seat"].includes(e.target)?`to ${e.target}`:e.target==="committee"?"to the committee":"",n=e.summary.trim(),c=we(n),p=c!==n,h=e.details.length?`<details class="liveEvidence"><summary>${e.details.length} ${e.details.length===1?"detail":"details"}</summary><ul>${e.details.map(m=>`<li>${s(m)}</li>`).join("")}</ul></details>`:"",y=p?`<details class="liveFull"><summary>read full message</summary><p>${s(n)}</p></details>`:"";return`<li class="liveTurn ${o} ${s(e.tone)}">
|
|
8
|
+
<div class="liveAvatar${l?.avatars?.[e.actor]?" conCara":""}"
|
|
9
|
+
style="--actor-hue:${me(e.actor)}" aria-hidden="true">
|
|
10
|
+
${ue(e.actor,e.role==="chair")}
|
|
11
|
+
</div>
|
|
12
|
+
<article class="liveBubble">
|
|
13
|
+
<div class="liveMeta"><span class="liveActor">${s(e.actor)}</span>
|
|
14
|
+
${t?`<span class="liveRole">${s(t)}</span>`:""}
|
|
15
|
+
${r?`<span>${s(r)}</span>`:""}<span class="liveWhen">${s(i)}</span></div>
|
|
16
|
+
<div class="liveHeading">${ge(e.kind)}<h3>${s(Te(e))}</h3></div>
|
|
17
|
+
<p>${s(c)}</p>${y}${h}
|
|
18
|
+
</article>
|
|
19
|
+
</li>`}function ye(){return[...k].reverse().find(e=>!!e.thread&&(e.kind==="committee.opened"||e.kind==="conversation.user"&&!Y(e)))?.thread||""}function be(e,a){let i=e?l?.deliberations?.find(m=>m.id===e):void 0,o=e?k.filter(m=>m.thread===e):[],t=o.find(m=>m.kind==="committee.opened");if(!i&&!t){a.innerHTML="",a.hidden=!0;return}let r=t?.details.find(m=>m.startsWith("Invited:"))?.slice(8).split(",").map(m=>m.trim()).filter(Boolean)||[],n=i?.participants||r,c=i?.received??new Set(o.filter(m=>m.kind==="committee.position.submitted").map(m=>m.actor)).size,p=i?.total??n.length,h=o.at(-1)?.phase||i?.status||"starting",y=["seat",...n];a.hidden=!1,a.innerHTML=`<div class="livePeople">${y.map(m=>`<span class="livePerson${l?.avatars?.[m]?" conCara":""}" title="${s(m==="seat"?"seat \xB7 chair":`${m} \xB7 ${pe(m)||"member"}`)}" style="--actor-hue:${me(m)}">${ue(m,m==="seat")}</span>`).join("")}</div><span class="liveContextText"><b>seat moderates</b> \xB7 ${s(c)}/${s(p)} positions \xB7 ${s(h)}</span>`}function Y(e){if(e.kind!=="conversation.user")return!1;let a=e.summary.trimStart();return a.startsWith("[Agents City authenticated local bus]")||a.startsWith("<channel")&&a.slice(0,500).includes("plugin:city:city-bus")}function $e(e){return e.kind==="work.command.started"||e.kind==="work.command.completed"||e.kind==="runtime.turn.started"||e.kind==="runtime.turn.completed"||e.kind==="runtime.gateway.ready"||e.kind==="runtime.session.started"||e.kind==="runtime.session.ended"}function pe(e){return e==="seat"?"chair":l?.skills?.[e]?.role||""}function ue(e,a){let i=l?.avatars?.[e];return i&&i.startsWith("data:image/svg+xml;base64,")?`<img class="liveCara" src="${s(i)}" alt="">`:a?ge("chair"):s(ke(e))}function ke(e){let a=e.split(/[-_.\s]+/).filter(Boolean);return(a.length>1?a.slice(0,2).map(o=>o[0]).join(""):e.slice(0,2)).toUpperCase()}function me(e){let a=17;for(let i of e)a=(a*31+i.charCodeAt(0))%360;return a}function we(e){if(e.length<=520)return e;let a=e.slice(0,520).lastIndexOf(" ");return e.slice(0,a>360?a:520).trimEnd()+"\u2026"}function Te(e){return e.kind==="conversation.user"?e.actor==="seat"?"Question":"Brief received":e.kind==="conversation.agent.commentary"?"Working note":e.kind==="conversation.agent"?"Response":e.kind==="committee.opened"?"Question to the committee":e.kind==="committee.position.submitted"?"Position sealed":e.kind==="committee.positions.revealed"?"Blind round complete":e.kind==="committee.position.revealed"?"Position":e.kind==="committee.synthesis.published"?"Chair synthesis":e.kind==="committee.floor.requested"?"Requests the floor":e.kind==="committee.floor.granted"?"Floor granted":e.kind==="committee.floor.denied"?"Floor denied":e.kind==="committee.floor.spoke"?"Intervention":e.kind==="committee.decision.recorded"?"Decision":e.kind.startsWith("committee.verification.")?"Verification":e.kind==="committee.closed"?"Committee closed":e.title}function ge(e){return e==="chair"?'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 17h16l-1.4-9-4.1 3L12 5l-2.5 6-4.1-3L4 17Zm1 2h14"/></svg>':e.includes("question")||e==="committee.opened"||e==="conversation.user"?'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h14v10H9l-4 4V5Zm5 4a2 2 0 1 1 3.4 1.4c-.9.6-1.4 1-1.4 2.1M12 14.7v.1"/></svg>':e.includes("decision")||e.includes("verification")||e==="committee.closed"?'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg>':e.includes("floor")?'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 11V5a1.5 1.5 0 0 1 3 0v5-7a1.5 1.5 0 0 1 3 0v7-5a1.5 1.5 0 0 1 3 0v7l1-2a1.5 1.5 0 0 1 2.6 1.5L17 18a4 4 0 0 1-3.5 2H10a5 5 0 0 1-5-5v-3.5a1.5 1.5 0 0 1 3 0V13"/></svg>':e.includes("command")||e.includes("work.")?'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6 8 4 4-4 4m6 0h6"/></svg>':'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 6h14v12H5zM8 10h8m-8 4h5"/></svg>'}function Ee(){d("#rail").innerHTML=ve.map(([i,o])=>{let t=i==="gente"?String(Object.keys(l.skills).length):i==="committee"?String(l.deliberations.length):i==="red"?String(l.roads.length):i==="barrios"?String(l.parcelas.length):"";return`<li class="${i===j?"aqui":""}" data-s="${i}">
|
|
20
|
+
<span>${o}</span>${t?`<span class="n">${t}</span>`:""}</li>`}).join(""),b("#rail li").forEach(i=>{i.onclick=()=>{j=i.dataset.s??"mapa",w()}}),d("#dondeDatos").textContent=z(l.datos);let e=d("#ciudades");l.ciudades.length>1?(e.innerHTML=`<select id="cambiaCiudad" title="which city this hall manages">
|
|
21
|
+
${l.ciudades.map(i=>`<option value="${s(i.ruta)}" ${i.actual?"selected":""}>
|
|
22
|
+
${s(i.nombre)}</option>`).join("")}</select>`,d("#cambiaCiudad").onchange=i=>{let o=i.target.value;location.href="/?PASE="+encodeURIComponent(q)+"&city="+encodeURIComponent(o)}):e.innerHTML="";let a=d("#alWizard");a.onclick=async i=>{i.preventDefault();let o=window.prompt("Name of the new city");if(!o?.trim())return;let t=await f("/api/ciudades",{method:"POST",body:JSON.stringify({name:o})});if(t.error||!t.city)return v(t.error??"Could not create the city",!0);location.href="/?PASE="+encodeURIComponent(q)+"&city="+encodeURIComponent(t.city)}}function w(){Ee(),d(".cuerpo").style.padding="",d("#lienzo").style.maxWidth="",x[j](),d(".cuerpo").scrollTop=0}var x={};x.resumen=()=>{let e=l.tarjetas.find(r=>r.user===l.yo),a=l.parcelas.filter(r=>r.unidad==="none"||r.unidad==="mine").length,i=[{ok:!!e,txt:e?`Your card exists \u2014 you are <b>${s(e.agent)}</b>`:"Take your seat: role, folders, one goal",ir:"puesto"},{ok:!!(e&&e.goals_defined),txt:e&&e.goals_defined?`Your goal: <b>${s(e.objetivo?e.objetivo.title:"")}</b>`:"Set <b>one goal</b>, with the command that measures it",ir:"puesto"},{ok:l.parcelas.length>0&&a===0,txt:l.parcelas.length===0?"No houses yet \u2014 pick your folders and they appear":a?`<b>${a}</b> of ${l.parcelas.length} houses sit in no real district \u2014 assign them`:"Every house has its district",ir:"barrios"}],o=l.tmux.includes(l.sesion);d("#lienzo").innerHTML=`
|
|
23
|
+
<div><span class="sub">your city</span>
|
|
24
|
+
<h1 style="margin-top:6px">${s(l.city_name)}</h1>
|
|
25
|
+
<p class="de mono" style="margin-top:5px">${s(l.address)}</p>
|
|
26
|
+
<p class="prosa" style="margin-top:8px">Domain: <b>${s(l.domain)}</b>. Growth is
|
|
27
|
+
counted with <code class="mono">${s(l.grow||"nothing yet")}</code>.</p></div>
|
|
28
|
+
<div class="cifras">
|
|
29
|
+
<div class="cifra"><b>${Object.keys(l.skills).length}</b><span>repo agents</span></div>
|
|
30
|
+
<div class="cifra"><b>${l.parcelas.length}</b><span>houses</span></div>
|
|
31
|
+
<div class="cifra"><b>${l.roads.length}</b><span>roads</span></div>
|
|
32
|
+
<div class="cifra"><b>${l.deliberations.length}</b><span>committee acts</span></div>
|
|
33
|
+
<div class="cifra"><b>${Object.values(l.skills).reduce((r,n)=>r+n.skills.length,0)}</b><span>skills recognised</span></div>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="luces">
|
|
36
|
+
<span class="luz ${l.tarjetas.length?"on":""}">data repo</span>
|
|
37
|
+
<span class="luz ${l.gh?"on":"neutra"}">github${l.gh?"":" \u2014 optional"}</span>
|
|
38
|
+
<span class="luz ${l.plugin?"on":""}">plugin installed</span>
|
|
39
|
+
<span class="luz ${o?"on":"neutra"}">tmux session${o?" up":""}</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div><span class="sub">what is left</span>
|
|
42
|
+
<div class="tareas" style="margin-top:9px">${i.map(r=>`
|
|
43
|
+
<div class="tarea ${r.ok?"hecha":""}">${r.txt}
|
|
44
|
+
${r.ok?"":`<button class="bt mini ir" data-ir="${r.ir}">go</button>`}</div>`).join("")}
|
|
45
|
+
</div></div>
|
|
46
|
+
<div><span class="sub">work</span>
|
|
47
|
+
<div style="display:flex;flex-direction:column;gap:9px;margin-top:9px">
|
|
48
|
+
<div class="orden"><span class="et2">your day</span>
|
|
49
|
+
<code>${o?"tmux attach -t "+s(l.sesion):"one window per folder, an agent in each"}</code>
|
|
50
|
+
${o?`<button class="bt mini" data-copia="tmux attach -t ${s(l.sesion)}">copy</button>`:'<button class="bt mini ppal" id="abreSesion">open my session</button>'}
|
|
51
|
+
</div>
|
|
52
|
+
<div class="orden"><span class="et2">the map</span>
|
|
53
|
+
<code>${l.mapa?s(l.mapa):"not drawn yet"}</code>
|
|
54
|
+
<button class="bt mini ${l.mapa?"":"ppal"}" data-ir="mapa">${l.mapa?"open":"draw it"}</button></div>
|
|
55
|
+
</div></div>`,Q();let t=document.querySelector("#abreSesion");t&&(t.onclick=async()=>{t.disabled=!0,t.textContent="building\u2026";let r=await f("/api/sesion",{method:"POST",body:JSON.stringify({user:l.yo})});await re(1500),await M(),v(r.ok&&r.attach?`Session built \u2014 attach with: ${r.attach}`:"Could not build it",!r.ok)})};x.mapa=()=>{if(l.mapa){d(".cuerpo").style.padding="0",d("#lienzo").style.maxWidth="none";let e=new URL(l.mapa,location.href);e.searchParams.set("embed","1"),e.searchParams.set("parent_origin",location.origin),d("#lienzo").innerHTML=`<iframe id="cityMapFrame" src="${s(e.toString())}" title="the map"
|
|
56
|
+
allow="fullscreen" allowfullscreen
|
|
57
|
+
style="width:100%;height:calc(100vh - 2px);border:0;display:block"></iframe>`;let a=d("#cityMapFrame");a.onload=()=>{a.dataset.ready="1";let i=new URL(a.src,location.href).origin;if(a.contentWindow?.postMessage({protocol:N,type:"map.config",roads:l.roads.map(o=>({name:o.name,address:o.address})),agents:(l.agents??[]).map(o=>({name:o.name,kind:o.kind})),avatars:l.avatars??{}},i),D){let o=D;D=null,de(o)}};return}d("#lienzo").innerHTML=`<div><span class="sub">the map</span>
|
|
58
|
+
<h1 style="margin-top:6px">Not drawn yet</h1>
|
|
59
|
+
<p class="prosa" style="margin-top:8px">The map can be served independently.
|
|
60
|
+
Locally the hall runs it for you: first time bakes the front end
|
|
61
|
+
and seeds the local database, which takes about a minute.</p></div>
|
|
62
|
+
<div><button class="bt ppal" id="arrancaMapa">Draw my city</button></div>
|
|
63
|
+
<p class="cargando" id="mapaEspera" style="display:none">baking the map \u2014 first time takes a minute</p>`,d("#arrancaMapa").onclick=async()=>{d("#arrancaMapa").disabled=!0,d("#mapaEspera").style.display="",await f("/api/mapa",{method:"POST",body:"{}"});for(let e=0;e<60;e++)if(await re(3e3),l=await f("/api/estado"),l.mapa){w();return}v("It did not come up \u2014 run ./bin/city by hand and look at its output",!0),w()}};x.puesto=()=>{Me()};async function Me(){let e=l.tarjetas.find(u=>u.user===l.yo);d("#lienzo").innerHTML=`<div><span class="sub">my seat</span>
|
|
64
|
+
<h1 style="margin-top:6px">${s(l.yo)}</h1>
|
|
65
|
+
<p class="prosa" style="margin-top:8px">First choose the work domain, then your
|
|
66
|
+
chair role inside it, the folders you answer for, and one goal. The seat stays
|
|
67
|
+
the boss even when its professional role is blank. Saving writes your card \u2014
|
|
68
|
+
<code class="mono">${s(z(l.datos))}/${s(l.yo)}.md</code> \u2014 the same file
|
|
69
|
+
every other door writes.</p></div>
|
|
70
|
+
<div><span class="sub">work domain</span><div class="rolejilla" id="domains" style="margin-top:9px">
|
|
71
|
+
<p class="cargando">reading the domain packs</p></div></div>
|
|
72
|
+
<div><span class="sub">role</span><div class="rolejilla" id="roles" style="margin-top:9px">
|
|
73
|
+
<p class="cargando">reading the role files</p></div></div>
|
|
74
|
+
<div><span class="sub">folders</span><div id="carpetas" style="margin-top:9px">
|
|
75
|
+
<p class="cargando">indexing this disk \u2014 first run can take a minute</p></div></div>
|
|
76
|
+
<div><span class="sub">role of each support agent</span>
|
|
77
|
+
<p class="prosa" style="margin-top:8px">The seat above is the chair. Each
|
|
78
|
+
selected repo below adopts its own specialist role; it never gains chair or
|
|
79
|
+
road authority. Blank means no preset role knowledge.</p>
|
|
80
|
+
<div id="agentRoles" style="margin-top:9px"></div></div>
|
|
81
|
+
<div><span class="sub">one goal \u2014 optional</span><div class="campos" id="meta" style="margin-top:9px"></div></div>
|
|
82
|
+
<div style="display:flex;gap:10px;align-items:center">
|
|
83
|
+
<button class="bt ppal" id="guardaPuesto">Save my seat</button>
|
|
84
|
+
<span class="cargando" id="puestoEstado" style="display:none">writing</span></div>`;let a=(await f("/api/domains")).domains,i=l.domain||l.kind||"software",o=e?e.role:"",t=[],r=()=>{d("#roles").innerHTML=t.map(u=>`
|
|
85
|
+
<button class="rol ${u.id===o?"on":""}" data-r="${s(u.id)}">
|
|
86
|
+
<h3>${s(u.name)}</h3><span class="de">${s(u.id)} \xB7 ${s(u.trade.toLowerCase())}</span>
|
|
87
|
+
<p>${s(u.summary)}</p></button>`).join(""),b("#roles .rol").forEach(u=>{u.onclick=()=>{o=u.dataset.r??"",r()}})},n=async()=>{t=(await f("/api/roles?domain="+encodeURIComponent(i))).roles,t.some(u=>u.id===o)||(o=""),r()},c=()=>{d("#domains").innerHTML=a.map(u=>`
|
|
88
|
+
<button class="rol ${u.id===i?"on":""}" data-d="${s(u.id)}">
|
|
89
|
+
<h3>${s(u.name)}</h3><span class="de">${s(u.id)}</span>
|
|
90
|
+
<p>${s(u.summary)}</p></button>`).join(""),b("#domains .rol").forEach(u=>{u.onclick=()=>{i=u.dataset.d??"software",c(),n()}})};c(),await n();let[p,h]=await Promise.all([f("/api/misrepos?user="+encodeURIComponent(l.yo)),f("/api/roles?scope=agent")]),{repos:y}=p,m=h.roles,g=new Set(e&&e.repos.length?e.repos:y.filter(u=>u.mio).map(u=>u.nombre)),L={...e?.repo_roles||{}},R=()=>{d("#agentRoles").innerHTML=K(g,L,m,s),b("#agentRoles [data-repo-role]").forEach(u=>{u.onchange=()=>{L[u.dataset.repoRole??""]=u.value||"blank"}})},B="",I=()=>{let u=y.filter($=>!B||$.nombre.toLowerCase().includes(B));d("#carpetas").innerHTML=`<div class="lista">
|
|
91
|
+
<div class="barra">
|
|
92
|
+
<input class="mono" id="fl" placeholder="filter ${y.length} repos\u2026" value="${s(B)}">
|
|
93
|
+
<button class="mini2" id="rescan" title="the index caches for a day \u2014 this rebuilds it now">rescan disk</button>
|
|
94
|
+
<button class="mini2" id="nada">none</button>
|
|
95
|
+
<span class="de" style="font-family:var(--mono);font-size:11px;color:var(--tinta3)">${g.size} picked</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="filas">${u.map($=>`
|
|
98
|
+
<div class="fila ${g.has($.nombre)?"on":""}" data-n="${s($.nombre)}">
|
|
99
|
+
<span class="caja">${g.has($.nombre)?"[x]":"[ ]"}</span>
|
|
100
|
+
<span class="et">${s($.nombre)}</span>
|
|
101
|
+
<span class="de">${s($.cuando||"\u2014")} ${s(z($.ruta))}</span></div>`).join("")||'<div class="fila"><span class="de" style="margin:0">nothing matches</span></div>'}
|
|
102
|
+
</div></div>
|
|
103
|
+
<p class="pista" style="margin-top:6px;font-size:11.5px;color:var(--tinta3);font-style:italic">
|
|
104
|
+
Ticked by your commits this year. Owning <b>no</b> folders is a real answer for a
|
|
105
|
+
cross-cutting role \u2014 your city is simply empty, and your work is the roads.</p>`;let X=d("#fl");X.oninput=()=>{B=X.value.toLowerCase(),I();let $=d("#fl");$.focus(),$.setSelectionRange($.value.length,$.value.length)},d("#rescan").onclick=async()=>{let $=d("#rescan");$.textContent="scanning\u2026",$.disabled=!0,{repos:y}=await f("/api/misrepos?refresh=1&user="+encodeURIComponent(l.yo)),I(),v(`${y.length} repos on this disk`)},d("#nada").onclick=()=>{u.forEach($=>g.delete($.nombre)),I()},b("#carpetas .fila[data-n]").forEach($=>{$.onclick=()=>{let U=$.dataset.n??"";g.has(U)?g.delete(U):g.add(U),I()}}),R()};I();let S=e&&e.objetivo||{};d("#meta").innerHTML=`
|
|
106
|
+
<div class="campo"><label>The goal, in one line</label>
|
|
107
|
+
<input type="text" id="g_title" value="${s(S.title)}" placeholder="Concrete enough to argue with \u2014 empty skips it">
|
|
108
|
+
</div>
|
|
109
|
+
<div class="dos">
|
|
110
|
+
<div class="campo"><label>How it is measured</label>
|
|
111
|
+
<input type="text" id="g_signal" value="${s(S.signal)}"></div>
|
|
112
|
+
<div class="campo"><label>The command that returns it, if a command can</label>
|
|
113
|
+
<input type="text" class="mono" id="g_command" value="${s(S.command)}"
|
|
114
|
+
placeholder="empty for a qualitative goal"></div>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="campo"><label>\u2026or who judges it, and how often</label>
|
|
117
|
+
<input type="text" id="g_manual" value="${s(S.manual)}"
|
|
118
|
+
placeholder="in prose: the architect reads the AGENTS.md files on Fridays">
|
|
119
|
+
<p class="pista">A goal judged by a person is a real goal \u2014 plenty of quality
|
|
120
|
+
is prose, not a number. Used when the command is empty.</p></div>
|
|
121
|
+
<div class="dos">
|
|
122
|
+
<div class="campo"><label>What it returns today</label>
|
|
123
|
+
<input type="text" class="mono" id="g_baseline" value="${s(S.baseline)}"></div>
|
|
124
|
+
<div class="campo"><label>Where it has to get to</label>
|
|
125
|
+
<input type="text" class="mono" id="g_target" value="${s(S.target)}"></div>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="campo" style="max-width:240px"><label>By when</label>
|
|
128
|
+
<input type="text" id="g_by" value="${s(S.by??"this quarter")}"></div>`;let C=u=>d(u).value.trim();d("#guardaPuesto").onclick=async()=>{if(!o){v("Pick a role \u2014 it is the name your seat answers to",!0);return}d("#puestoEstado").style.display="";let u=await f("/api/ficha",{method:"POST",body:JSON.stringify({user:l.yo,domain:i,role:o,repos:[...g],repo_roles:Z(g,L),objetivo:{title:C("#g_title"),signal:C("#g_signal"),command:C("#g_command"),manual:C("#g_manual"),baseline:C("#g_baseline"),target:C("#g_target"),by:C("#g_by")||"this quarter"}})});await M(),v(u.ok?`Card written \u2014 you are ${u.user??l.yo}`:u.error??"It could not write",!u.ok)}}x.barrios=()=>{let e=l.unidades.map(r=>({...r})),a=new Set(l.lab),i={};for(let r of l.parcelas)(i[r.repo]=i[r.repo]??[]).push({ruta:r.ruta,unidad:r.unidad,nombre:r.nombre});let o=r=>r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,20),t=()=>{let r=new Set([...e.map(n=>n.id),"none"]);d("#lienzo").innerHTML=`<div><span class="sub">districts & houses</span>
|
|
129
|
+
<h1 style="margin-top:6px">The modelling no tool can do for you</h1>
|
|
130
|
+
<p class="prosa" style="margin-top:8px">A house is <b>not a repo</b> \u2014 it is a
|
|
131
|
+
parcel, a slice of one serving a single business unit. Split the interesting
|
|
132
|
+
repos, give every house its district, and the map can say
|
|
133
|
+
\u201Cthis change touches banking\u201D instead of \u201Cthis change touches src/lib\u201D.</p></div>
|
|
134
|
+
|
|
135
|
+
<div><span class="sub">districts</span>
|
|
136
|
+
<div class="tabla" id="unidades" style="margin-top:9px"></div>
|
|
137
|
+
<div style="display:flex;gap:9px;margin-top:9px">
|
|
138
|
+
<input type="text" id="nuevaU" placeholder="another district\u2026" style="flex:1">
|
|
139
|
+
<button class="bt" id="masU">Add</button></div></div>
|
|
140
|
+
|
|
141
|
+
<div><span class="sub">houses</span><div id="parcelas" style="margin-top:9px"></div></div>
|
|
142
|
+
|
|
143
|
+
<div style="display:flex;gap:10px;align-items:center">
|
|
144
|
+
<button class="bt ppal" id="guardaBarrios">Save districts & houses</button>
|
|
145
|
+
<span style="font-size:12px;color:var(--tinta3);font-style:italic">
|
|
146
|
+
writes units.yml and parcels.yml \u2014 reseed the map to see it drawn</span></div>`,d("#unidades").innerHTML=e.map((n,c)=>`
|
|
147
|
+
<div class="tr">
|
|
148
|
+
<input type="text" value="${s(n.name)}" data-i="${c}" style="flex:1">
|
|
149
|
+
<span class="id">${s(n.id)}</span>
|
|
150
|
+
<span class="pips" data-i="${c}">${l.paleta.map(p=>`
|
|
151
|
+
<button class="pip ${p.hex===n.color?"on":""}" data-c="${p.hex}"
|
|
152
|
+
style="background:#${p.hex}" title="${s(p.nombre)}"></button>`).join("")}</span>
|
|
153
|
+
<button class="x" data-x="${c}">\xD7</button></div>`).join("")||'<div class="tr" style="color:var(--tinta3);font-size:12.5px">No districts yet \u2014 everything sits in \u201Cno unit\u201D.</div>',d("#parcelas").innerHTML=Object.keys(i).sort().map(n=>`
|
|
154
|
+
<div class="repoBloque" data-repo="${s(n)}">
|
|
155
|
+
<div class="repoCab"><span>${s(n)}</span>
|
|
156
|
+
<button class="bt mini" data-split="${s(n)}">split</button>
|
|
157
|
+
<label class="lab"><input type="checkbox" data-lab="${s(n)}"
|
|
158
|
+
${a.has(n)?"checked":""}> lab</label></div>
|
|
159
|
+
${(i[n]??[]).map((c,p)=>`
|
|
160
|
+
<div class="parcela">
|
|
161
|
+
<input type="text" value="${s(c.nombre)}" data-k="nombre" data-r="${s(n)}" data-j="${p}" title="name on the map">
|
|
162
|
+
<input type="text" class="mono" value="${s(c.ruta)}" data-k="ruta" data-r="${s(n)}" data-j="${p}"
|
|
163
|
+
placeholder="glob inside the repo \u2014 empty = the whole repo">
|
|
164
|
+
<select data-k="unidad" data-r="${s(n)}" data-j="${p}">
|
|
165
|
+
${[...e.map(h=>h.id),"none"].map(h=>`
|
|
166
|
+
<option value="${s(h)}" ${(r.has(c.unidad)?c.unidad:"none")===h?"selected":""}>${s(h)}</option>`).join("")}
|
|
167
|
+
</select>
|
|
168
|
+
${(i[n]??[]).length>1?`<button class="x" data-quita="${s(n)}" data-j="${p}">\xD7</button>`:"<span></span>"}
|
|
169
|
+
</div>`).join("")}
|
|
170
|
+
</div>`).join("")||'<p class="prosa">No houses yet. Pick your folders in <b>My seat</b> and each becomes one.</p>',b("#unidades input[data-i]").forEach(n=>{n.oninput=()=>{let c=e[Number(n.dataset.i)];if(!c)return;c.name=n.value,c.id=o(n.value)||c.id;let p=n.closest(".tr")?.querySelector(".id");p&&(p.textContent=c.id)}}),b("#unidades .pip").forEach(n=>{n.onclick=()=>{let c=n.closest(".pips"),p=e[Number(c?.dataset.i)];p&&(p.color=n.dataset.c??p.color,t())}}),b("#unidades .x[data-x]").forEach(n=>{n.onclick=()=>{e.splice(Number(n.dataset.x),1),t()}}),d("#masU").onclick=()=>{let n=d("#nuevaU").value.trim();if(!n)return;let c=e.map(h=>h.color),p=l.paleta.find(h=>!c.includes(h.hex))??l.paleta[0];e.push({id:o(n),name:n,color:p?p.hex:"c8b48a"}),t()},d("#nuevaU").onkeydown=n=>{n.key==="Enter"&&d("#masU").click()},b("#parcelas [data-k]").forEach(n=>{n.onchange=()=>{let c=i[n.dataset.r??""]?.[Number(n.dataset.j)];if(!c)return;let p=n.dataset.k;c[p]=n.value}}),b("#parcelas [data-split]").forEach(n=>{n.onclick=()=>{let c=n.dataset.split??"";(i[c]=i[c]??[]).push({ruta:"",unidad:"none",nombre:`${c} \xB7 new slice`}),t()}}),b("#parcelas [data-quita]").forEach(n=>{n.onclick=()=>{i[n.dataset.quita??""]?.splice(Number(n.dataset.j),1),t()}}),b("#parcelas [data-lab]").forEach(n=>{n.onchange=()=>{let c=n.dataset.lab??"";n.checked?a.add(c):a.delete(c)}}),d("#guardaBarrios").onclick=async()=>{let n=await f("/api/unidades",{method:"POST",body:JSON.stringify({unidades:e})}),c=await f("/api/parcelas",{method:"POST",body:JSON.stringify({repos:i,lab:[...a]})});await M();let p=n.error??c.error;v(p??"Districts and houses written",!!p)}};t()};x.red=()=>{let e=new Set(l.roads.map(o=>o.id)),a=l.ciudades.filter(o=>!o.actual&&o.id&&!e.has(o.id)),i=JSON.stringify(l.invitation);d("#lienzo").innerHTML=`<div><span class="sub">roads</span>
|
|
171
|
+
<h1 style="margin-top:6px">Cities this one may reach</h1>
|
|
172
|
+
<p class="prosa" style="margin-top:8px">A road joins city seats. It may stay on
|
|
173
|
+
this machine or continue over the remote bus; the city sees one explicit
|
|
174
|
+
connection either way.</p></div>
|
|
175
|
+
<div class="gente">${l.roads.map(o=>`<div class="persona"><h3>${s(o.name)}</h3>
|
|
176
|
+
<span class="ag">${s(o.address)}</span>
|
|
177
|
+
<span class="rp">${o.local?"local road":"remote road"}</span>
|
|
178
|
+
<button class="bt mini" data-road-close="${s(o.id)}">close</button></div>`).join("")||'<p class="prosa">No roads yet. This city is isolated on purpose.</p>'}</div>
|
|
179
|
+
<div><span class="sub">other cities on this machine</span>
|
|
180
|
+
<div class="gente" style="margin-top:9px">${a.map(o=>`<div class="persona"><h3>${s(o.nombre)}</h3>
|
|
181
|
+
<span class="ag">${s(o.slug??o.ruta)}</span>
|
|
182
|
+
<button class="bt mini ppal" data-road-open="${s(o.id)}">open road</button></div>`).join("")||'<p class="prosa">No unconnected local cities.</p>'}</div></div>
|
|
183
|
+
<div class="orden"><span class="et2">remote invitation \xB7 public, no token</span>
|
|
184
|
+
<code>${s(i)}</code>
|
|
185
|
+
<button class="bt mini" data-copia="${s(i)}">copy</button>
|
|
186
|
+
</div>`,Q(),b("[data-road-open]").forEach(o=>{o.onclick=async()=>{let t=await f("/api/roads",{method:"POST",body:JSON.stringify({action:"connect",target:o.dataset.roadOpen})});if(t.error)return v(t.error,!0);await M(),v("Road open at both local cities")}}),b("[data-road-close]").forEach(o=>{o.onclick=async()=>{let t=await f("/api/roads",{method:"POST",body:JSON.stringify({action:"disconnect",target:o.dataset.roadClose})});if(t.error)return v(t.error,!0);await M(),v("Road closed")}})};x.committee=()=>{d("#lienzo").innerHTML=`<div><span class="sub">committee</span>
|
|
187
|
+
<h1 style="margin-top:6px">Decisions with a visible chain of custody</h1>
|
|
188
|
+
<p class="prosa" style="margin-top:8px">The seat selects relevant repo agents,
|
|
189
|
+
gathers isolated positions, controls the floor, decides and assigns an
|
|
190
|
+
independent verification. This view is read-only; the vendor-neutral CLI
|
|
191
|
+
drives the protocol.</p></div>
|
|
192
|
+
<div class="orden"><span class="et2">start</span>
|
|
193
|
+
<code>agents-city committee schema open</code>
|
|
194
|
+
<button class="bt mini" data-copia="agents-city committee schema open">copy</button>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="gente">${l.deliberations.map(e=>`<div class="persona">
|
|
197
|
+
<h3>${s(e.question)}</h3>
|
|
198
|
+
<span class="ag">${s(e.status)} \xB7 revision ${e.revision} \xB7
|
|
199
|
+
${e.received}/${e.total} positions</span>
|
|
200
|
+
<span class="rp">${s(e.decision||e.desired_outcome)}</span>
|
|
201
|
+
<span class="de">${s(e.participants.join(", ")||"no participants")}
|
|
202
|
+
${e.contributors.length?` \xB7 decisive ${s(e.contributors.join(", "))}`:""}
|
|
203
|
+
${e.verifier?` \xB7 verifier ${s(e.verifier)} ${s(e.verification)}`:""}</span>
|
|
204
|
+
<code class="mono">${s(z(e.act))}</code>
|
|
205
|
+
</div>`).join("")||'<p class="prosa">No committee acts yet. Open one only when the seat needs specialised evidence.</p>'}</div>`,Q()};function xe(e){let a=e.toLowerCase();if(!a)return{ancho:.5,texto:"default",defecto:!0};for(let[i,o]of[["fable",1],["opus",.8],["sonnet",.55],["haiku",.35]])if(a.includes(i))return{ancho:o,texto:a,defecto:!1};return{ancho:.6,texto:a,defecto:!1}}var se={low:1,medium:2,high:3,xhigh:4,max:5},Le=["haiku","sonnet","opus","fable"];function W(e,a){return e.concat(a&&!e.includes(a)?[a]:[]).map(i=>`<option value="${s(i)}"${i===a?" selected":""}>${s(i||"default")}</option>`).join("")}function oe(e){return e?.startsWith("data:image/svg+xml;base64,")?`<img class="rpgCara" src="${s(e)}" alt="">`:""}function J(e,a=""){let i=Math.round(Math.max(0,Math.min(1,e))*100);return`<span class="barra${a?" "+a:""}"><span class="llena" style="width:${i}%"></span></span>`}x.gente=()=>{let e=l.tarjetas.find(t=>t.user===l.yo),a=l.agents??[],i=t=>{let r=xe(t.model),n=se[t.effort]??0,c=t.growth,p=Math.min(1,Math.log2(c.floors+1)/8),h=l.skills[t.name]?.skills??[],y=t.runtime==="claude",m=W([""].concat(Le),t.model)+'<option value="__otro__">custom\u2026</option>',g=W([""].concat(Object.keys(se)),t.effort),L=W(["claude","codex","opencode","kimi"],t.runtime);return`
|
|
206
|
+
<div class="fichaRPG">
|
|
207
|
+
<div class="rpgCab">${oe(t.avatar)}
|
|
208
|
+
<div><h3>${s(t.name)}</h3>
|
|
209
|
+
<span class="rpgTags"><span class="kindChip ${s(t.kind)}">${s(t.kind)}</span>
|
|
210
|
+
<span class="rpgRol">${s(t.role)}</span>
|
|
211
|
+
<span class="rpgHogar">${t.legacy?"repo":`workspace \xB7 ${t.mounts|0} ${t.mounts===1?"mount":"mounts"}`}</span></span></div>
|
|
212
|
+
<span class="rpgBotones">
|
|
213
|
+
<button class="rpgMini rpgDado" type="button" data-agente="${s(t.slug)}"
|
|
214
|
+
title="Reroll this agent's face \u2014 deterministic, persisted on the card">\u{1F3B2}</button>
|
|
215
|
+
<button class="rpgMini rpgIns" type="button" data-agente="${s(t.slug)}"
|
|
216
|
+
data-file="CLAUDE.md" title="Instructions the Claude runtime reads">CLAUDE.md</button>
|
|
217
|
+
<button class="rpgMini rpgIns" type="button" data-agente="${s(t.slug)}"
|
|
218
|
+
data-file="AGENTS.md" title="Instructions Codex, OpenCode and Kimi read">AGENTS.md</button>
|
|
219
|
+
</span>
|
|
220
|
+
</div>
|
|
221
|
+
<div class="rpgFila"><label>engine</label>
|
|
222
|
+
${J(r.ancho,r.defecto?"defecto":"")}
|
|
223
|
+
<select class="rpgSel" data-agente="${s(t.slug)}" data-campo="model"
|
|
224
|
+
${y?"":'disabled title="This window runs its own CLI; its model lives in its own flags"'}>
|
|
225
|
+
${m}</select></div>
|
|
226
|
+
<div class="rpgFila"><label>effort</label>
|
|
227
|
+
${J(n/5,n?"":"defecto")}
|
|
228
|
+
<select class="rpgSel" data-agente="${s(t.slug)}" data-campo="effort"
|
|
229
|
+
${y?"":'disabled title="This window runs its own CLI; its effort lives in its own flags"'}>
|
|
230
|
+
${g}</select></div>
|
|
231
|
+
<div class="rpgFila"><label>provider</label>
|
|
232
|
+
<span class="rpgDato"><span class="cliDot ${t.cli.connected?"on":t.cli.installed?"idle":"off"}" title="${s(t.cli.connected?"connected: this agent\u2019s window is alive right now":t.cli.installed?"installed on this machine, not in use by this agent":`${t.cli.binary} is not installed`)}"></span>${s(t.cli.connected?"connected":t.cli.installed?"idle":"missing")} \xB7 ${s(t.cli.binary)}
|
|
233
|
+
<button class="rpgMini rpgTest" type="button" data-agente="${s(t.slug)}"
|
|
234
|
+
title="Run the engine for real: --version, and the login state on Claude">test</button></span>
|
|
235
|
+
<select class="rpgSel" data-agente="${s(t.slug)}" data-campo="runtime">
|
|
236
|
+
${L}</select></div>
|
|
237
|
+
<div class="rpgFila"><label>growth</label>
|
|
238
|
+
${J(p)}
|
|
239
|
+
<span class="rpgDato">${c.floors|0} floors \xB7 ${c.bricks|0} bricks \xB7 ${c.activity30|0}/30d</span></div>
|
|
240
|
+
<div class="rpgSkills"><label>skills \xB7 ${h.length}</label>
|
|
241
|
+
${h.length?h.map(R=>`<code class="mono" title="${s(R.description)}">${s(R.name)}${R.removable&&R.dir?`<button class="rpgQuitar" type="button" data-agente="${s(t.slug)}"
|
|
242
|
+
data-skill="${s(R.dir)}" title="Remove this skill from the agent's home">\xD7</button>`:""}</code>`).join(" "):'<span class="rpgDato">none discovered</span>'}
|
|
243
|
+
<label class="rpgMini rpgSubir"
|
|
244
|
+
title="Install a skill zip into this agent's own home \u2014 the Claude runtime reads skills; other engines ignore them">
|
|
245
|
+
+ zip<input type="file" accept=".zip" data-agente="${s(t.slug)}"></label></div>
|
|
246
|
+
</div>`};d("#lienzo").innerHTML=`<div><span class="sub">agents & skills</span>
|
|
247
|
+
<h1 style="margin-top:6px">One seat, support agents behind it</h1>
|
|
248
|
+
<p class="prosa" style="margin-top:8px">Every number on a card is real: the
|
|
249
|
+
engine comes from the card keys the launcher resolves, growth from what the
|
|
250
|
+
agent actually produced, skills from live read-only recognition \u2014 Agents
|
|
251
|
+
City copies and installs nothing. Engine changes persist to the card and
|
|
252
|
+
apply the next time the session opens.</p></div>
|
|
253
|
+
<div class="fichasRPG">
|
|
254
|
+
<div class="fichaRPG rpgSeat">
|
|
255
|
+
<div class="rpgCab">${oe(l.avatars?.seat)}
|
|
256
|
+
<div><h3>seat</h3>
|
|
257
|
+
<span class="rpgTags"><span class="kindChip coordinator">chair</span>
|
|
258
|
+
<span class="rpgRol">${s(e?.role??"not configured")}</span></span></div>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="rpgFila"><span class="rpgDato">${s(l.address)}</span></div>
|
|
261
|
+
<div class="rpgFila"><span class="rpgDato">${s(e?.objetivo?.title??"No goal yet")}</span></div>
|
|
262
|
+
</div>
|
|
263
|
+
${a.map(i).join("")}
|
|
264
|
+
</div>`;let o=async(t,r)=>{let n;try{n=await f("/api/agente",{method:"POST",body:JSON.stringify(t)})}catch(c){v(String(c),!0),w();return}if(!n.ok||!n.agent){v(n.error||"Could not save",!0),w();return}l.agents=(l.agents??[]).map(c=>c.slug===n.agent.slug?n.agent:c),l.avatars&&(l.avatars[n.agent.name]=n.agent.avatar),v(r),w()};b(".rpgSel").forEach(t=>{t.onchange=async()=>{let r=t.value;if(r==="__otro__"){let n=window.prompt("Model alias (resolved by the CLI at launch):","");if(n===null){w();return}r=n.trim().toLowerCase()}await o({agent:t.dataset.agente??"",[t.dataset.campo??"model"]:r},"Saved \u2014 applies next session")}}),b(".rpgDado").forEach(t=>{t.onclick=()=>o({agent:t.dataset.agente??"",avatar:Math.random().toString(36).slice(2,8)},"New look \u2014 same identity, everywhere, forever")}),b(".rpgTest").forEach(t=>{t.onclick=async()=>{t.disabled=!0;try{let r=await f("/api/motor",{method:"POST",body:JSON.stringify({agent:t.dataset.agente??""})});if(r.error){v(r.error,!0);return}let n=[r.version,r.detail].filter(Boolean).join(" \xB7 ");v(r.ok?`${r.binary} works \u2014 ${n}`:`${r.binary}: ${r.detail||"failed"}`,!r.ok)}catch(r){v(String(r),!0)}finally{t.disabled=!1}}}),b(".rpgQuitar").forEach(t=>{t.onclick=async()=>{let r=t.dataset.skill??"";if(!window.confirm(`Remove the skill ${r} from this agent's home?`))return;let n=await f("/api/skill",{method:"POST",body:JSON.stringify({agent:t.dataset.agente??"",remove:r})});if(!n.ok){v(n.error||"Could not remove",!0);return}v(`Skill ${r} removed`),M()}}),b(".rpgIns").forEach(t=>{t.onclick=()=>void Se(t.dataset.agente??"",t.dataset.file??"")}),b(".rpgSubir input").forEach(t=>{t.onchange=async()=>{let r=t.files?.[0];if(r){t.disabled=!0;try{let n=await Re(r),c=r.name.replace(/\.zip$/i,"").toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,""),p=await f("/api/skill",{method:"POST",body:JSON.stringify({agent:t.dataset.agente??"",name:c,zip:n})});if(!p.ok){v(p.error||"Could not install",!0);return}v(`Skill ${p.skill} installed \u2014 the Claude runtime reads it next session`),M()}catch(n){v(String(n),!0)}finally{t.disabled=!1,t.value=""}}}})};function Re(e){return new Promise((a,i)=>{let o=new FileReader;o.onerror=()=>i(o.error),o.onload=()=>a(String(o.result).split(",",2)[1]??""),o.readAsDataURL(e)})}var O=null;async function Se(e,a){let i=await f(`/api/instrucciones?agent=${encodeURIComponent(e)}&file=${encodeURIComponent(a)}`);if(i.error){v(i.error,!0);return}O={agent:e,file:a},d("#edTitulo").textContent=`${e} \xB7 ${a}`,d("#edLector").textContent=`read by ${i.reader??"?"}${i.exists?"":" \xB7 new file"}`,d("#edRuta").textContent=i.home?`${i.home}/${a}`:"",d("#edTexto").value=i.content??"",d("#editorIns").hidden=!1,d("#edTexto").focus()}document.getElementById("edCerrar")?.addEventListener("click",()=>{d("#editorIns").hidden=!0,O=null});document.getElementById("edGuardar")?.addEventListener("click",async()=>{if(!O)return;let e=await f("/api/instrucciones",{method:"POST",body:JSON.stringify({...O,content:d("#edTexto").value})});if(!e.ok){v(e.error||"Could not save",!0);return}v("Saved"),d("#editorIns").hidden=!0,O=null});function Q(){b("[data-copia]").forEach(e=>{e.onclick=async()=>{try{await navigator.clipboard.writeText(e.dataset.copia??""),v("Copied")}catch{v("Could not copy \u2014 select it by hand",!0)}}}),b("[data-ir]").forEach(e=>{e.onclick=()=>{j=e.dataset.ir??"mapa",w()}})}function Ce(){let e=document.getElementById("app"),a=document.getElementById("liveResize"),i=document.getElementById("livePanel");if(!e||!a||!i)return;let o="hall-live-width",t=n=>{n===null?e.style.removeProperty("--live-ancho"):e.style.setProperty("--live-ancho",`${Math.round(n)}px`)},r=n=>Math.max(340,Math.min(n,Math.max(420,window.innerWidth*.6)));try{let n=Number(localStorage.getItem(o));n>0&&t(r(n))}catch{}a.addEventListener("pointerdown",n=>{n.preventDefault();let c=n.clientX,p=i.getBoundingClientRect().width;e.classList.add("liveResizing"),a.setPointerCapture(n.pointerId);let h=m=>t(r(p+(c-m.clientX))),y=()=>{e.classList.remove("liveResizing"),a.removeEventListener("pointermove",h),a.removeEventListener("pointerup",y),a.removeEventListener("pointercancel",y);try{localStorage.setItem(o,String(Math.round(i.getBoundingClientRect().width)))}catch{}};a.addEventListener("pointermove",h),a.addEventListener("pointerup",y),a.addEventListener("pointercancel",y)}),a.addEventListener("dblclick",()=>{t(null);try{localStorage.removeItem(o)}catch{}})}window.addEventListener("message",e=>{if(!ee(e.data))return;let a=document.querySelector("#cityMapFrame");if(!a||e.source!==a.contentWindow||e.origin!==new URL(a.src,location.href).origin)return;let i=e.data.view;i!=="committee"&&i!=="red"||(j=i,w())});Ce();M();
|