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.
Files changed (440) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.es.md +2021 -0
  5. package/README.md +1999 -0
  6. package/benchmarks/committee/README.md +39 -0
  7. package/benchmarks/committee/metrics.py +51 -0
  8. package/benchmarks/committee/run.py +64 -0
  9. package/benchmarks/committee/traces/01-single.json +8 -0
  10. package/benchmarks/committee/traces/02-mesh.json +16 -0
  11. package/benchmarks/committee/traces/03-chair.json +15 -0
  12. package/benchmarks/latency/README.md +35 -0
  13. package/benchmarks/latency/fake-claude-cli.mjs +119 -0
  14. package/benchmarks/latency/fake-native-server.mjs +340 -0
  15. package/benchmarks/latency/fake-tui.py +91 -0
  16. package/benchmarks/latency/live.py +380 -0
  17. package/benchmarks/stress/README.md +20 -0
  18. package/benchmarks/stress/run.py +487 -0
  19. package/bin/agents +4 -0
  20. package/bin/agents-city.js +116 -0
  21. package/bin/benchmark +17 -0
  22. package/bin/bus +6 -0
  23. package/bin/cities +3 -0
  24. package/bin/city +86 -0
  25. package/bin/committee +6 -0
  26. package/bin/demo +200 -0
  27. package/bin/exit +5 -0
  28. package/bin/hall +73 -0
  29. package/bin/hall.html +426 -0
  30. package/bin/logs +3 -0
  31. package/bin/report.py +14 -0
  32. package/bin/reset +3 -0
  33. package/bin/road +3 -0
  34. package/bin/seat +10 -0
  35. package/bin/serve.py +1428 -0
  36. package/bin/setup.py +753 -0
  37. package/bin/skills +3 -0
  38. package/bin/test +131 -0
  39. package/bin/test-adapter.py +183 -0
  40. package/bin/test-admision.py +99 -0
  41. package/bin/test-avatar.py +58 -0
  42. package/bin/test-benchmark.py +40 -0
  43. package/bin/test-broker.py +334 -0
  44. package/bin/test-cage.py +206 -0
  45. package/bin/test-card.py +402 -0
  46. package/bin/test-channel.py +379 -0
  47. package/bin/test-cities.py +453 -0
  48. package/bin/test-claude-runtime.py +252 -0
  49. package/bin/test-committee.py +340 -0
  50. package/bin/test-contracts.py +544 -0
  51. package/bin/test-crecimiento.py +164 -0
  52. package/bin/test-demo.py +308 -0
  53. package/bin/test-doctor.py +106 -0
  54. package/bin/test-domains.py +151 -0
  55. package/bin/test-evidencia.py +50 -0
  56. package/bin/test-exit.py +128 -0
  57. package/bin/test-hall-protocol.py +93 -0
  58. package/bin/test-launch.py +169 -0
  59. package/bin/test-live-feed.py +508 -0
  60. package/bin/test-pairing.py +99 -0
  61. package/bin/test-parcels.py +283 -0
  62. package/bin/test-runtime-failures.py +252 -0
  63. package/bin/test-runtime-ui.py +488 -0
  64. package/bin/test-runtime.py +268 -0
  65. package/bin/test-rutas.py +80 -0
  66. package/bin/test-seat.py +1386 -0
  67. package/bin/test-security.py +150 -0
  68. package/bin/test-serve.py +1057 -0
  69. package/bin/test-stress.py +64 -0
  70. package/bin/test-widgets.py +143 -0
  71. package/bin/test-workspace.py +188 -0
  72. package/bin/testlib.py +95 -0
  73. package/bin/tokens.py +14 -0
  74. package/bus/scripts/deploy.sh +60 -0
  75. package/bus/scripts/mint-token.sh +68 -0
  76. package/bus/scripts/setup-dev.sh +79 -0
  77. package/bus/scripts/test-channel.ts +8 -0
  78. package/bus/scripts/test-hub.ts +266 -0
  79. package/bus/scripts/test-local.sh +40 -0
  80. package/bus/scripts/test-queue.ts +132 -0
  81. package/bus/worker/package-lock.json +1971 -0
  82. package/bus/worker/package.json +17 -0
  83. package/bus/worker/src/index.ts +485 -0
  84. package/bus/worker/tsconfig.json +13 -0
  85. package/bus/worker/wrangler.toml +32 -0
  86. package/city/oven/README.md +59 -0
  87. package/city/oven/collect.py +43 -0
  88. package/city/oven/oven.html +4 -0
  89. package/city/scripts/history.py +120 -0
  90. package/city/scripts/seed.py +442 -0
  91. package/city/web/assets/modelos/License.txt +28 -0
  92. package/city/web/assets/modelos/PROCEDENCIA.txt +3 -0
  93. package/city/web/assets/modelos/building-a.glb +0 -0
  94. package/city/web/assets/modelos/building-b.glb +0 -0
  95. package/city/web/assets/modelos/building-c.glb +0 -0
  96. package/city/web/assets/modelos/building-d.glb +0 -0
  97. package/city/web/assets/modelos/building-e.glb +0 -0
  98. package/city/web/assets/modelos/building-f.glb +0 -0
  99. package/city/web/assets/modelos/building-g.glb +0 -0
  100. package/city/web/assets/modelos/building-h.glb +0 -0
  101. package/city/web/assets/sprites/building-a.png +0 -0
  102. package/city/web/assets/sprites/building-b.png +0 -0
  103. package/city/web/assets/sprites/building-c.png +0 -0
  104. package/city/web/assets/sprites/building-d.png +0 -0
  105. package/city/web/assets/sprites/building-e.png +0 -0
  106. package/city/web/assets/sprites/building-f.png +0 -0
  107. package/city/web/assets/sprites/building-g.png +0 -0
  108. package/city/web/assets/sprites/building-h.png +0 -0
  109. package/city/web/assets/sprites/building-i.png +0 -0
  110. package/city/web/assets/sprites/building-j.png +0 -0
  111. package/city/web/assets/sprites/building-k.png +0 -0
  112. package/city/web/assets/sprites/building-l.png +0 -0
  113. package/city/web/assets/sprites/building-m.png +0 -0
  114. package/city/web/assets/sprites/building-n.png +0 -0
  115. package/city/web/assets/sprites/building-skyscraper-a.png +0 -0
  116. package/city/web/assets/sprites/building-skyscraper-b.png +0 -0
  117. package/city/web/assets/sprites/building-skyscraper-c.png +0 -0
  118. package/city/web/assets/sprites/building-skyscraper-d.png +0 -0
  119. package/city/web/assets/sprites/building-skyscraper-e.png +0 -0
  120. package/city/web/assets/sprites/catalogo.json +47 -0
  121. package/city/web/assets/sprites/detail-awning-wide.png +0 -0
  122. package/city/web/assets/sprites/detail-awning.png +0 -0
  123. package/city/web/assets/sprites/detail-overhang-wide.png +0 -0
  124. package/city/web/assets/sprites/detail-overhang.png +0 -0
  125. package/city/web/assets/sprites/detail-parasol-a.png +0 -0
  126. package/city/web/assets/sprites/detail-parasol-b.png +0 -0
  127. package/city/web/assets/sprites/low-detail-building-a.png +0 -0
  128. package/city/web/assets/sprites/low-detail-building-b.png +0 -0
  129. package/city/web/assets/sprites/low-detail-building-c.png +0 -0
  130. package/city/web/assets/sprites/low-detail-building-d.png +0 -0
  131. package/city/web/assets/sprites/low-detail-building-e.png +0 -0
  132. package/city/web/assets/sprites/low-detail-building-f.png +0 -0
  133. package/city/web/assets/sprites/low-detail-building-g.png +0 -0
  134. package/city/web/assets/sprites/low-detail-building-h.png +0 -0
  135. package/city/web/assets/sprites/low-detail-building-i.png +0 -0
  136. package/city/web/assets/sprites/low-detail-building-j.png +0 -0
  137. package/city/web/assets/sprites/low-detail-building-k.png +0 -0
  138. package/city/web/assets/sprites/low-detail-building-l.png +0 -0
  139. package/city/web/assets/sprites/low-detail-building-m.png +0 -0
  140. package/city/web/assets/sprites/low-detail-building-n.png +0 -0
  141. package/city/web/assets/sprites/low-detail-building-wide-a.png +0 -0
  142. package/city/web/assets/sprites/low-detail-building-wide-b.png +0 -0
  143. package/city/web/assets/sprites/medidas.json +248 -0
  144. package/city/web/dist/city.js +939 -0
  145. package/city/web/dist/index.html +294 -0
  146. package/city/web/dist/modelos/License.txt +28 -0
  147. package/city/web/dist/modelos/PROCEDENCIA.txt +3 -0
  148. package/city/web/dist/modelos/building-a.glb +0 -0
  149. package/city/web/dist/modelos/building-b.glb +0 -0
  150. package/city/web/dist/modelos/building-c.glb +0 -0
  151. package/city/web/dist/modelos/building-d.glb +0 -0
  152. package/city/web/dist/modelos/building-e.glb +0 -0
  153. package/city/web/dist/modelos/building-f.glb +0 -0
  154. package/city/web/dist/modelos/building-g.glb +0 -0
  155. package/city/web/dist/modelos/building-h.glb +0 -0
  156. package/city/web/dist/sprites/building-a.png +0 -0
  157. package/city/web/dist/sprites/building-b.png +0 -0
  158. package/city/web/dist/sprites/building-c.png +0 -0
  159. package/city/web/dist/sprites/building-d.png +0 -0
  160. package/city/web/dist/sprites/building-e.png +0 -0
  161. package/city/web/dist/sprites/building-f.png +0 -0
  162. package/city/web/dist/sprites/building-g.png +0 -0
  163. package/city/web/dist/sprites/building-h.png +0 -0
  164. package/city/web/dist/sprites/building-i.png +0 -0
  165. package/city/web/dist/sprites/building-j.png +0 -0
  166. package/city/web/dist/sprites/building-k.png +0 -0
  167. package/city/web/dist/sprites/building-l.png +0 -0
  168. package/city/web/dist/sprites/building-m.png +0 -0
  169. package/city/web/dist/sprites/building-n.png +0 -0
  170. package/city/web/dist/sprites/building-skyscraper-a.png +0 -0
  171. package/city/web/dist/sprites/building-skyscraper-b.png +0 -0
  172. package/city/web/dist/sprites/building-skyscraper-c.png +0 -0
  173. package/city/web/dist/sprites/building-skyscraper-d.png +0 -0
  174. package/city/web/dist/sprites/building-skyscraper-e.png +0 -0
  175. package/city/web/dist/sprites/catalogo.json +47 -0
  176. package/city/web/dist/sprites/detail-awning-wide.png +0 -0
  177. package/city/web/dist/sprites/detail-awning.png +0 -0
  178. package/city/web/dist/sprites/detail-overhang-wide.png +0 -0
  179. package/city/web/dist/sprites/detail-overhang.png +0 -0
  180. package/city/web/dist/sprites/detail-parasol-a.png +0 -0
  181. package/city/web/dist/sprites/detail-parasol-b.png +0 -0
  182. package/city/web/dist/sprites/low-detail-building-a.png +0 -0
  183. package/city/web/dist/sprites/low-detail-building-b.png +0 -0
  184. package/city/web/dist/sprites/low-detail-building-c.png +0 -0
  185. package/city/web/dist/sprites/low-detail-building-d.png +0 -0
  186. package/city/web/dist/sprites/low-detail-building-e.png +0 -0
  187. package/city/web/dist/sprites/low-detail-building-f.png +0 -0
  188. package/city/web/dist/sprites/low-detail-building-g.png +0 -0
  189. package/city/web/dist/sprites/low-detail-building-h.png +0 -0
  190. package/city/web/dist/sprites/low-detail-building-i.png +0 -0
  191. package/city/web/dist/sprites/low-detail-building-j.png +0 -0
  192. package/city/web/dist/sprites/low-detail-building-k.png +0 -0
  193. package/city/web/dist/sprites/low-detail-building-l.png +0 -0
  194. package/city/web/dist/sprites/low-detail-building-m.png +0 -0
  195. package/city/web/dist/sprites/low-detail-building-n.png +0 -0
  196. package/city/web/dist/sprites/low-detail-building-wide-a.png +0 -0
  197. package/city/web/dist/sprites/low-detail-building-wide-b.png +0 -0
  198. package/city/web/dist/sprites/medidas.json +248 -0
  199. package/city/web/dist-hall/hall.js +264 -0
  200. package/city/web/index.html +294 -0
  201. package/city/web/package.json +18 -0
  202. package/city/web/sella.py +21 -0
  203. package/city/web/src/activity-actors.ts +47 -0
  204. package/city/web/src/activity.ts +172 -0
  205. package/city/web/src/ayuntamiento.ts +580 -0
  206. package/city/web/src/draw.ts +640 -0
  207. package/city/web/src/game-speech.ts +79 -0
  208. package/city/web/src/hall.ts +1867 -0
  209. package/city/web/src/main.ts +2225 -0
  210. package/city/web/src/oven.ts +124 -0
  211. package/city/web/src/people.ts +244 -0
  212. package/city/web/src/presencia.ts +193 -0
  213. package/city/web/src/puertas.ts +180 -0
  214. package/city/web/src/repo-roles.ts +59 -0
  215. package/city/worker/package.json +16 -0
  216. package/city/worker/schema.sql +117 -0
  217. package/city/worker/src/index.ts +702 -0
  218. package/city/worker/src/square.ts +218 -0
  219. package/city/worker/wrangler.toml +58 -0
  220. package/demo/ada.md +50 -0
  221. package/demo/bruno.md +62 -0
  222. package/demo/camila.md +56 -0
  223. package/demo/city/ada.md +40 -0
  224. package/demo/city/city.yml +8 -0
  225. package/demo/city/parcels.yml +15 -0
  226. package/demo/city/roads.json +4 -0
  227. package/demo/city/units.yml +10 -0
  228. package/demo/clinica/city.yml +8 -0
  229. package/demo/clinica/parcels.yml +15 -0
  230. package/demo/clinica/roads.json +4 -0
  231. package/demo/clinica/units.yml +9 -0
  232. package/demo/clinica/vera.md +46 -0
  233. package/demo/dante.md +54 -0
  234. package/demo/despacho/city.yml +8 -0
  235. package/demo/despacho/marta.md +46 -0
  236. package/demo/despacho/parcels.yml +15 -0
  237. package/demo/despacho/roads.json +4 -0
  238. package/demo/despacho/units.yml +9 -0
  239. package/demo/elsa.md +50 -0
  240. package/demo/farid.md +52 -0
  241. package/demo/greta.md +50 -0
  242. package/demo/hugo.md +49 -0
  243. package/demo/iris.md +49 -0
  244. package/demo/jonas.md +51 -0
  245. package/demo/kira.md +51 -0
  246. package/demo/luca.md +49 -0
  247. package/demo/parcels.yml +92 -0
  248. package/demo/seed.py +20 -0
  249. package/demo/show.py +161 -0
  250. package/demo/stories.py +824 -0
  251. package/demo/units.yml +33 -0
  252. package/docs/agents-first.md +99 -0
  253. package/docs/glossary.md +55 -0
  254. package/docs/map-live-layers.md +73 -0
  255. package/docs/security.md +231 -0
  256. package/docs/self-host.md +151 -0
  257. package/docs/testing.md +205 -0
  258. package/package.json +73 -0
  259. package/plugin/.claude-plugin/plugin.json +62 -0
  260. package/plugin/.mcp.json +15 -0
  261. package/plugin/channel/activity-cli.ts +16 -0
  262. package/plugin/channel/adapter-prompts.ts +113 -0
  263. package/plugin/channel/adapter.js +4292 -0
  264. package/plugin/channel/adapter.ts +133 -0
  265. package/plugin/channel/bus.js +20188 -0
  266. package/plugin/channel/bus.ts +131 -0
  267. package/plugin/channel/city-config.ts +125 -0
  268. package/plugin/channel/claude-channel.ts +58 -0
  269. package/plugin/channel/cli-args.ts +75 -0
  270. package/plugin/channel/client.js +4200 -0
  271. package/plugin/channel/client.ts +38 -0
  272. package/plugin/channel/committee/activity.ts +256 -0
  273. package/plugin/channel/committee/collection.ts +154 -0
  274. package/plugin/channel/committee/decision.ts +175 -0
  275. package/plugin/channel/committee/floor.ts +135 -0
  276. package/plugin/channel/committee/guards.ts +30 -0
  277. package/plugin/channel/committee/history.ts +38 -0
  278. package/plugin/channel/committee/render.ts +102 -0
  279. package/plugin/channel/committee/service.ts +72 -0
  280. package/plugin/channel/committee/storage.ts +92 -0
  281. package/plugin/channel/committee/types.ts +163 -0
  282. package/plugin/channel/committee/view.ts +63 -0
  283. package/plugin/channel/committee-cli.ts +109 -0
  284. package/plugin/channel/delivery-metrics.ts +61 -0
  285. package/plugin/channel/delivery-queue.ts +118 -0
  286. package/plugin/channel/hub/activity-controller.ts +72 -0
  287. package/plugin/channel/hub/activity-feed.ts +169 -0
  288. package/plugin/channel/hub/committee-controller.ts +60 -0
  289. package/plugin/channel/hub/connections.ts +48 -0
  290. package/plugin/channel/hub/diagnostics.ts +67 -0
  291. package/plugin/channel/hub/envelope-validity.ts +109 -0
  292. package/plugin/channel/hub/envelopes.ts +66 -0
  293. package/plugin/channel/hub/lifecycle.ts +91 -0
  294. package/plugin/channel/hub/local-roads.ts +89 -0
  295. package/plugin/channel/hub/remote-roads.ts +165 -0
  296. package/plugin/channel/hub/road-controller.ts +99 -0
  297. package/plugin/channel/hub-client.ts +149 -0
  298. package/plugin/channel/local-hub.js +5995 -0
  299. package/plugin/channel/local-hub.ts +349 -0
  300. package/plugin/channel/map-reporter.ts +48 -0
  301. package/plugin/channel/package-lock.json +1731 -0
  302. package/plugin/channel/package.json +19 -0
  303. package/plugin/channel/protocol.ts +98 -0
  304. package/plugin/channel/road-cli.ts +18 -0
  305. package/plugin/channel/run.sh +15 -0
  306. package/plugin/channel/runtime/claude.ts +458 -0
  307. package/plugin/channel/runtime/codex-config.ts +77 -0
  308. package/plugin/channel/runtime/codex.ts +669 -0
  309. package/plugin/channel/runtime/command.ts +62 -0
  310. package/plugin/channel/runtime/factory.ts +15 -0
  311. package/plugin/channel/runtime/json-rpc.ts +154 -0
  312. package/plugin/channel/runtime/kimi.ts +277 -0
  313. package/plugin/channel/runtime/opencode.ts +248 -0
  314. package/plugin/channel/runtime/process.ts +84 -0
  315. package/plugin/channel/runtime/types.ts +45 -0
  316. package/plugin/channel/runtime-files.ts +73 -0
  317. package/plugin/channel/runtime-gateway.js +6396 -0
  318. package/plugin/channel/runtime-gateway.ts +358 -0
  319. package/plugin/channel/runtime-metrics.ts +52 -0
  320. package/plugin/channel/runtime-subscription.ts +180 -0
  321. package/plugin/channel/terminal-delivery.ts +131 -0
  322. package/plugin/channel/untrusted.ts +60 -0
  323. package/plugin/commands/committee.md +31 -0
  324. package/plugin/commands/exit.md +32 -0
  325. package/plugin/commands/goals.md +20 -0
  326. package/plugin/commands/join.md +18 -0
  327. package/plugin/commands/notice.md +20 -0
  328. package/plugin/commands/propose.md +19 -0
  329. package/plugin/commands/round.md +17 -0
  330. package/plugin/commands/session.md +22 -0
  331. package/plugin/commands/settings.md +25 -0
  332. package/plugin/commands/setup.md +21 -0
  333. package/plugin/commands/team.md +23 -0
  334. package/plugin/domains/custom.md +27 -0
  335. package/plugin/domains/finance.md +31 -0
  336. package/plugin/domains/healthcare.md +34 -0
  337. package/plugin/domains/legal.md +31 -0
  338. package/plugin/domains/marketing.md +33 -0
  339. package/plugin/domains/operations.md +31 -0
  340. package/plugin/domains/research.md +32 -0
  341. package/plugin/domains/sales.md +30 -0
  342. package/plugin/domains/software.md +37 -0
  343. package/plugin/hooks/activity.sh +6 -0
  344. package/plugin/hooks/digging.sh +68 -0
  345. package/plugin/hooks/growth.sh +42 -0
  346. package/plugin/hooks/hooks.json +106 -0
  347. package/plugin/hooks/notice-on-pr.sh +35 -0
  348. package/plugin/hooks/notice-on-stop.sh +80 -0
  349. package/plugin/hooks/notice-pending.sh +58 -0
  350. package/plugin/hooks/solo-en-ciudad.sh +23 -0
  351. package/plugin/hooks/tokens.sh +47 -0
  352. package/plugin/roles/examples/account-executive.md +25 -0
  353. package/plugin/roles/examples/ai-manager.md +34 -0
  354. package/plugin/roles/examples/associate.md +24 -0
  355. package/plugin/roles/examples/brand-lead.md +20 -0
  356. package/plugin/roles/examples/cfo.md +20 -0
  357. package/plugin/roles/examples/city-lead.md +25 -0
  358. package/plugin/roles/examples/clinical-director.md +26 -0
  359. package/plugin/roles/examples/clinical-ops.md +25 -0
  360. package/plugin/roles/examples/clinician.md +25 -0
  361. package/plugin/roles/examples/compliance.md +27 -0
  362. package/plugin/roles/examples/content.md +24 -0
  363. package/plugin/roles/examples/controller.md +27 -0
  364. package/plugin/roles/examples/cpto.md +41 -0
  365. package/plugin/roles/examples/customer-success.md +25 -0
  366. package/plugin/roles/examples/data-engineer.md +37 -0
  367. package/plugin/roles/examples/data.md +60 -0
  368. package/plugin/roles/examples/dev.md +37 -0
  369. package/plugin/roles/examples/devops.md +39 -0
  370. package/plugin/roles/examples/enablement.md +24 -0
  371. package/plugin/roles/examples/ethics.md +24 -0
  372. package/plugin/roles/examples/fin-analytics.md +27 -0
  373. package/plugin/roles/examples/health-compliance.md +25 -0
  374. package/plugin/roles/examples/health-data.md +26 -0
  375. package/plugin/roles/examples/knowledge.md +25 -0
  376. package/plugin/roles/examples/lifecycle.md +26 -0
  377. package/plugin/roles/examples/llm-engineer.md +34 -0
  378. package/plugin/roles/examples/managing-partner.md +20 -0
  379. package/plugin/roles/examples/methods.md +23 -0
  380. package/plugin/roles/examples/operations-lead.md +23 -0
  381. package/plugin/roles/examples/ops.md +24 -0
  382. package/plugin/roles/examples/patient-safety.md +26 -0
  383. package/plugin/roles/examples/performance.md +27 -0
  384. package/plugin/roles/examples/po.md +36 -0
  385. package/plugin/roles/examples/process-owner.md +23 -0
  386. package/plugin/roles/examples/product-design.md +39 -0
  387. package/plugin/roles/examples/program-manager.md +24 -0
  388. package/plugin/roles/examples/quality.md +25 -0
  389. package/plugin/roles/examples/research-director.md +24 -0
  390. package/plugin/roles/examples/research-ops.md +25 -0
  391. package/plugin/roles/examples/researcher.md +25 -0
  392. package/plugin/roles/examples/revenue-lead.md +25 -0
  393. package/plugin/roles/examples/revops.md +26 -0
  394. package/plugin/roles/examples/seo.md +27 -0
  395. package/plugin/roles/examples/specialist.md +24 -0
  396. package/plugin/scripts/admision.py +165 -0
  397. package/plugin/scripts/apaga.py +232 -0
  398. package/plugin/scripts/avatar.py +211 -0
  399. package/plugin/scripts/broker.py +531 -0
  400. package/plugin/scripts/cage.py +252 -0
  401. package/plugin/scripts/capabilities.py +197 -0
  402. package/plugin/scripts/card.py +312 -0
  403. package/plugin/scripts/cities.py +520 -0
  404. package/plugin/scripts/city-env.sh +90 -0
  405. package/plugin/scripts/city-runtime.sh +87 -0
  406. package/plugin/scripts/city-session.sh +526 -0
  407. package/plugin/scripts/city_env.py +67 -0
  408. package/plugin/scripts/crecimiento.py +140 -0
  409. package/plugin/scripts/deliberations.py +48 -0
  410. package/plugin/scripts/doctor.py +172 -0
  411. package/plugin/scripts/domains.py +201 -0
  412. package/plugin/scripts/evidencia.py +64 -0
  413. package/plugin/scripts/find-repos.sh +111 -0
  414. package/plugin/scripts/gh.py +159 -0
  415. package/plugin/scripts/hall_protocol.py +147 -0
  416. package/plugin/scripts/hook_activity.py +139 -0
  417. package/plugin/scripts/launch.py +94 -0
  418. package/plugin/scripts/logs.py +98 -0
  419. package/plugin/scripts/pairing.py +185 -0
  420. package/plugin/scripts/parcels.py +132 -0
  421. package/plugin/scripts/read-card.py +51 -0
  422. package/plugin/scripts/report.py +201 -0
  423. package/plugin/scripts/reset.py +180 -0
  424. package/plugin/scripts/roads.py +230 -0
  425. package/plugin/scripts/roles.py +274 -0
  426. package/plugin/scripts/runtime_log.py +69 -0
  427. package/plugin/scripts/runtime_processes.py +132 -0
  428. package/plugin/scripts/rutas.py +83 -0
  429. package/plugin/scripts/seat.py +1349 -0
  430. package/plugin/scripts/tokens.py +194 -0
  431. package/plugin/scripts/trust-repos.py +59 -0
  432. package/plugin/scripts/ui.py +280 -0
  433. package/plugin/scripts/units.py +80 -0
  434. package/plugin/scripts/workspace.py +364 -0
  435. package/plugin/skills/city/SKILL.md +191 -0
  436. package/templates/blank.md +39 -0
  437. package/templates/finance.md +44 -0
  438. package/templates/legal.md +45 -0
  439. package/templates/marketing.md +48 -0
  440. package/templates/product.md +45 -0
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env python3
2
+ """Three native runtime protocols cross the authenticated bus without tmux."""
3
+ import json
4
+ import importlib.util
5
+ import os
6
+ import socket
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+ import time
11
+ import shutil
12
+
13
+ AQUI = os.path.dirname(os.path.abspath(__file__))
14
+ RAIZ = os.path.dirname(AQUI)
15
+ sys.path.insert(0, AQUI)
16
+ from testlib import afirma, comprueba, detiene_proceso, resumen # noqa: E402
17
+
18
+ GATEWAY = os.path.join(RAIZ, 'plugin', 'channel', 'runtime-gateway.js')
19
+ CLIENT = os.path.join(RAIZ, 'plugin', 'channel', 'client.js')
20
+ FAKE = os.path.join(RAIZ, 'benchmarks', 'latency', 'fake-native-server.mjs')
21
+ PROVIDERS = ('codex', 'opencode', 'kimi')
22
+
23
+
24
+ def carga_benchmark():
25
+ path = os.path.join(RAIZ, 'benchmarks', 'latency', 'live.py')
26
+ spec = importlib.util.spec_from_file_location('agents_city_live_benchmark', path)
27
+ module = importlib.util.module_from_spec(spec)
28
+ spec.loader.exec_module(module)
29
+ return module
30
+
31
+
32
+ def puerto():
33
+ with socket.socket() as sock:
34
+ sock.bind(('127.0.0.1', 0))
35
+ return sock.getsockname()[1]
36
+
37
+
38
+ def espera(condicion, segundos=10):
39
+ limite = time.monotonic() + segundos
40
+ while time.monotonic() < limite:
41
+ if condicion():
42
+ return True
43
+ time.sleep(.05)
44
+ return False
45
+
46
+
47
+ def lee_jsonl(path):
48
+ if not os.path.exists(path):
49
+ return []
50
+ with open(path, encoding='utf-8') as stream:
51
+ return [json.loads(line) for line in stream if line.strip()]
52
+
53
+
54
+ def main(): # noqa: C901 - integration orchestration is clearer as one lifecycle
55
+ print('\n native runtime gateways over the city WebSocket')
56
+ benchmark = carga_benchmark()
57
+ afirma('· auth-like skill names are not classified as provider failures',
58
+ benchmark.FAILURE.search(
59
+ 'skills: gcloud-auth-verification, security-review, error-analysis') is None)
60
+ afirma('· a concrete missing provider credential is classified as failure',
61
+ benchmark.FAILURE.search(
62
+ 'provider managed:kimi-code has no credential configured') is not None)
63
+ if not shutil.which('node'):
64
+ afirma('· node is available', False, 'node missing')
65
+ return resumen('runtime')
66
+ base = tempfile.mkdtemp(prefix='agents-city-runtime-')
67
+ app = os.path.join(base, 'app')
68
+ city = os.path.join(app, 'alice', 'home')
69
+ repos = os.path.join(base, 'repos')
70
+ os.makedirs(city)
71
+ actors = [f'{provider}-agent' for provider in PROVIDERS]
72
+ for actor in actors:
73
+ os.makedirs(os.path.join(repos, actor))
74
+ open(os.path.join(city, 'city.yml'), 'w', encoding='utf-8').write(
75
+ 'id: city_native\nname: Home\nslug: home\nowner: alice\n')
76
+ open(os.path.join(city, 'roads.json'), 'w', encoding='utf-8').write(
77
+ '{"version": 1, "roads": []}\n')
78
+ open(os.path.join(city, 'alice.md'), 'w', encoding='utf-8').write(
79
+ f'---\nuser: alice\nagent: alice/ceo\nrepos: [{", ".join(actors)}]\n'
80
+ + ''.join(f'role.{actor}: {"seo" if actor == "codex-agent" else "blank"}\n'
81
+ for actor in actors)
82
+ + ''.join(f'runs.{provider}-agent: {provider}\n' for provider in PROVIDERS)
83
+ + '---\n')
84
+ env = dict(os.environ, AGENTS_CITY_HOME=app, AGENTS_CITY_DATA=city,
85
+ AGENTS_CITY_USER='alice', CITY_RUNTIME_AUTO='1')
86
+ for key in ('CITY_BUS_URL', 'CITY_BUS_TOKEN', 'CITY_DIR'):
87
+ env.pop(key, None)
88
+ captures, servers, gateways, streams, stream_paths = {}, [], [], [], []
89
+ endpoint_path = os.path.join(app, '.runtime', 'bus', 'city-native', 'endpoint.json')
90
+ try:
91
+ ports = {provider: puerto() for provider in PROVIDERS}
92
+ for provider in PROVIDERS:
93
+ capture = os.path.join(base, f'{provider}.jsonl')
94
+ captures[provider] = capture
95
+ server = subprocess.Popen(
96
+ ['node', FAKE, provider, str(ports[provider]), capture],
97
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
98
+ servers.append(server)
99
+ afirma('· all deterministic native protocol servers start',
100
+ espera(lambda: all(p.poll() is None for p in servers), .4))
101
+
102
+ runtime_env = dict(
103
+ env,
104
+ CITY_CODEX_APP_SERVER_URL=f'ws://127.0.0.1:{ports["codex"]}',
105
+ CITY_OPENCODE_SERVER_URL=f'http://127.0.0.1:{ports["opencode"]}',
106
+ CITY_KIMI_SERVER_URL=f'http://127.0.0.1:{ports["kimi"]}',
107
+ CITY_KIMI_SERVER_TOKEN='fake-secret',
108
+ )
109
+ for provider, actor in zip(PROVIDERS, actors, strict=True):
110
+ stream_path = os.path.join(base, f'{provider}.out')
111
+ stream = open(stream_path, 'w+', encoding='utf-8')
112
+ streams.append(stream)
113
+ stream_paths.append(stream_path)
114
+ process = subprocess.Popen(
115
+ ['node', GATEWAY, '--data', city, '--actor', actor,
116
+ '--cwd', os.path.join(repos, actor), '--command', provider,
117
+ '--auto', '1', '--interactive', '0'],
118
+ env=runtime_env, stdin=subprocess.DEVNULL,
119
+ stdout=stream, stderr=stream, text=True)
120
+ gateways.append(process)
121
+ status_dir = os.path.join(app, '.runtime', 'bus', 'city-native', 'gateways')
122
+ afirma('· Codex, OpenCode and Kimi gateways authenticate',
123
+ espera(lambda: all(os.path.exists(os.path.join(status_dir, f'{actor}.json'))
124
+ for actor in actors)),
125
+ '\n'.join(p.stderr.read() if p.poll() is not None and p.stderr else ''
126
+ for p in gateways))
127
+ afirma('· concurrent first start has no bus-handshake timeout',
128
+ all('local bus connection timed out' not in open(path, encoding='utf-8').read()
129
+ for path in stream_paths),
130
+ '\n'.join(open(path, encoding='utf-8').read() for path in stream_paths))
131
+
132
+ opened_at = time.monotonic()
133
+ opened = subprocess.run(
134
+ ['node', CLIENT, 'committee', 'open', '--input', '-'],
135
+ input=json.dumps({
136
+ 'question': 'Return the smallest evidence-backed runtime position.',
137
+ 'desiredOutcome': 'Prove native delivery for every configured engine.',
138
+ 'definitionOfDone': ['each provider accepts one assignment'],
139
+ 'participants': actors,
140
+ }), capture_output=True, text=True,
141
+ env=dict(runtime_env, CITY_BUS_ACTOR='seat'), timeout=12)
142
+ state = json.loads(opened.stdout) if opened.returncode == 0 else {}
143
+ thread = state.get('id', '')
144
+ afirma('· the chair opens one minimal multi-model task',
145
+ bool(thread), opened.stderr.strip())
146
+ delivered = espera(lambda: all(len(lee_jsonl(captures[p])) == 1
147
+ for p in PROVIDERS))
148
+ duration_ms = round((time.monotonic() - opened_at) * 1000)
149
+ afirma('· all three native APIs accept it without terminal input',
150
+ delivered, f'{duration_ms}ms')
151
+
152
+ records = {provider: lee_jsonl(captures[provider])[0]
153
+ for provider in PROVIDERS if lee_jsonl(captures[provider])}
154
+ codex_text = json.dumps(records.get('codex', {}).get('request', {}))
155
+ open_text = json.dumps(records.get('opencode', {}).get('request', {}))
156
+ kimi_text = json.dumps(records.get('kimi', {}).get('request', {}))
157
+ afirma('· Codex receives turn/start over app-server WebSocket',
158
+ thread in codex_text and 'turn/start' in codex_text, codex_text[-240:])
159
+ codex_params = records.get('codex', {}).get('request', {}).get('params', {})
160
+ afirma('· normal Codex agents keep native workspace confinement without nesting',
161
+ codex_params.get('sandboxPolicy', {}).get('type') == 'workspaceWrite'
162
+ and codex_params.get('sandboxPolicy', {}).get('networkAccess') is True,
163
+ json.dumps(codex_params))
164
+ afirma('· OpenCode receives prompt_async over its server API',
165
+ thread in open_text and 'parts' in open_text, open_text[-240:])
166
+ afirma('· Kimi receives the prompt over REST and streams events over WebSocket',
167
+ thread in kimi_text and 'content' in kimi_text, kimi_text[-240:])
168
+
169
+ runtime_dir = os.path.join(app, '.runtime', 'bus', 'city-native')
170
+ outbox = os.path.join(runtime_dir, 'outbox')
171
+ afirma('· native ACKs drain all durable actor outboxes',
172
+ espera(lambda: all(not os.path.isdir(os.path.join(outbox, actor))
173
+ or not os.listdir(os.path.join(outbox, actor))
174
+ for actor in actors)))
175
+
176
+ # Non-happy path: lose the shared hub while every provider session stays
177
+ # alive. A new command must recreate one hub; all gateways must
178
+ # reauthenticate, drain one durable assignment, and never duplicate it.
179
+ first_endpoint = json.load(open(endpoint_path, encoding='utf-8'))
180
+ afirma('· the forced outage terminates the old hub process',
181
+ detiene_proceso(int(first_endpoint['pid'])))
182
+ # A live gateway is allowed to recreate the hub immediately, so the
183
+ # observable state may jump straight from the old endpoint to a fresh
184
+ # one without an interval where endpoint.json is absent. What must
185
+ # never remain observable is the dead hub's PID.
186
+ old_hub_pid = int(first_endpoint['pid'])
187
+ def stale_endpoint_is_gone():
188
+ if not os.path.exists(endpoint_path):
189
+ return True
190
+ try:
191
+ current = json.load(open(endpoint_path, encoding='utf-8'))
192
+ return int(current.get('pid', 0)) != old_hub_pid
193
+ except (OSError, TypeError, ValueError, json.JSONDecodeError):
194
+ return False
195
+ afirma('· a forced local-bus outage never leaves the stale endpoint active',
196
+ espera(stale_endpoint_is_gone))
197
+ reopened = subprocess.run(
198
+ ['node', CLIENT, 'committee', 'open', '--input', '-'],
199
+ input=json.dumps({
200
+ 'question': 'Prove recovery after the local bus was restarted.',
201
+ 'desiredOutcome': 'Every native gateway reconnects once.',
202
+ 'definitionOfDone': ['each provider accepts one recovery assignment'],
203
+ 'participants': actors,
204
+ }), capture_output=True, text=True,
205
+ env=dict(runtime_env, CITY_BUS_ACTOR='seat'), timeout=15)
206
+ recovery = json.loads(reopened.stdout) if reopened.returncode == 0 else {}
207
+ recovered_endpoint = (
208
+ json.load(open(endpoint_path, encoding='utf-8'))
209
+ if os.path.exists(endpoint_path) else {})
210
+ afirma('· the next command recreates a fresh authenticated hub',
211
+ bool(recovery.get('id'))
212
+ and int(recovered_endpoint.get('pid', 0)) not in (0, old_hub_pid),
213
+ reopened.stderr.strip() or str(recovered_endpoint))
214
+ afirma('· all native gateways reconnect and receive exactly once',
215
+ espera(lambda: all(len(lee_jsonl(captures[p])) == 2 for p in PROVIDERS), 12),
216
+ str({p: len(lee_jsonl(captures[p])) for p in PROVIDERS}))
217
+ time.sleep(.35)
218
+ comprueba('· recovery produces no duplicate provider invocation',
219
+ {p: len(lee_jsonl(captures[p])) for p in PROVIDERS},
220
+ {p: 2 for p in PROVIDERS})
221
+ afirma('· recovery ACKs drain every durable outbox again',
222
+ espera(lambda: all(not os.path.isdir(os.path.join(outbox, actor))
223
+ or not os.listdir(os.path.join(outbox, actor))
224
+ for actor in actors)))
225
+ metrics = lee_jsonl(os.path.join(runtime_dir, 'runtime-latency.jsonl'))
226
+ transports = {row.get('transport') for row in metrics}
227
+ comprueba('· the latency ledger names every native transport', transports,
228
+ {'codex-app-server-ws', 'opencode-http-sse', 'kimi-rest-ws'})
229
+ afirma('· local bus-to-native acceptance stays below two seconds',
230
+ len(metrics) == 6
231
+ and all(row.get('totalToNativeAcceptMs', 9999) < 2000 for row in metrics),
232
+ json.dumps(metrics))
233
+ afirma('· no adapter, paste buffer or terminal metric participates',
234
+ not os.path.isdir(os.path.join(runtime_dir, 'adapters'))
235
+ and not os.path.exists(os.path.join(runtime_dir, 'delivery-latency.jsonl')))
236
+ statuses = [json.load(open(os.path.join(status_dir, f'{actor}.json'),
237
+ encoding='utf-8')) for actor in actors]
238
+ afirma('· every gateway records terminalInjection=false',
239
+ all(item.get('terminalInjection') is False for item in statuses),
240
+ str(statuses))
241
+ endpoint = json.load(open(endpoint_path, encoding='utf-8'))
242
+ comprueba('· all engines share one authenticated city WebSocket contract',
243
+ endpoint.get('protocol'), 'agents-city-bus/2')
244
+ finally:
245
+ for process in gateways + servers:
246
+ if process.poll() is None:
247
+ process.terminate()
248
+ for process in gateways + servers:
249
+ try:
250
+ process.wait(timeout=3)
251
+ except subprocess.TimeoutExpired:
252
+ process.kill()
253
+ for stream in streams:
254
+ stream.close()
255
+ hub_pid = 0
256
+ if os.path.exists(endpoint_path):
257
+ try:
258
+ endpoint = json.load(open(endpoint_path, encoding='utf-8'))
259
+ hub_pid = int(endpoint['pid'])
260
+ except (OSError, ValueError, KeyError, json.JSONDecodeError):
261
+ pass
262
+ afirma('· native cleanup leaves no orphan city hub', detiene_proceso(hub_pid), str(hub_pid))
263
+ shutil.rmtree(base, ignore_errors=True)
264
+ return resumen('runtime')
265
+
266
+
267
+ if __name__ == '__main__':
268
+ sys.exit(main())
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env python3
2
+ """Path containment, resolved twice — the primitive the cage and broker trust.
3
+
4
+ Pure, no sandbox, runs on every platform. The load-bearing cases: a missing
5
+ leaf under a symlinked parent still resolves onto the real target, and
6
+ containment is judged segment-wise and bidirectionally so `/a/bc` is never
7
+ "inside" `/a/b` and a covering ancestor is caught as well as a child.
8
+ """
9
+
10
+ import os
11
+ import shutil
12
+ import sys
13
+ import tempfile
14
+
15
+ AQUI = os.path.dirname(os.path.abspath(__file__))
16
+ RAIZ = os.path.dirname(AQUI)
17
+ sys.path.insert(0, os.path.join(RAIZ, "plugin", "scripts"))
18
+ sys.path.insert(0, AQUI)
19
+
20
+ import rutas # noqa: E402
21
+ from testlib import afirma, comprueba, resumen # noqa: E402
22
+
23
+
24
+ def contencion():
25
+ afirma("a path is inside itself", rutas.dentro_de("/a/b", "/a/b"))
26
+ afirma("a child is inside its parent", rutas.dentro_de("/a/b/c", "/a/b"))
27
+ afirma("a sibling prefix is NOT inside (/a/bc vs /a/b)",
28
+ not rutas.dentro_de("/a/bc", "/a/b"))
29
+ afirma("a parent is not inside its child", not rutas.dentro_de("/a", "/a/b"))
30
+ afirma("cubre() catches a strict ancestor", rutas.cubre("/a", "/a/b/c"))
31
+ afirma("cubre() is strict: equal paths do not cover", not rutas.cubre("/a/b", "/a/b"))
32
+ afirma("cubre() rejects a sibling prefix", not rutas.cubre("/a/b", "/a/bc"))
33
+
34
+
35
+ def bloqueo_bidireccional():
36
+ sellados = ["/home/u/.ssh", "/home/u/.git-credentials"]
37
+ afirma("a path inside a sealed dir is blocked",
38
+ rutas.motivo_bloqueo("/home/u/.ssh/id_ed25519", sellados) is not None)
39
+ afirma("a path that covers a sealed dir is blocked (would reopen it)",
40
+ rutas.motivo_bloqueo("/home/u", sellados) is not None)
41
+ afirma("an unrelated path is allowed",
42
+ rutas.motivo_bloqueo("/home/u/code/repo", sellados) is None)
43
+ afirma("the reason names inside vs covers distinctly",
44
+ "inside" in rutas.motivo_bloqueo("/home/u/.ssh/x", sellados)
45
+ and "covers" in rutas.motivo_bloqueo("/home/u", sellados))
46
+
47
+
48
+ def doble_resolucion():
49
+ base = tempfile.mkdtemp(prefix="agents-city-rutas-")
50
+ try:
51
+ real = os.path.join(base, "real")
52
+ os.makedirs(real)
53
+ enlace = os.path.join(base, "link")
54
+ os.symlink(real, enlace)
55
+ # A leaf that does not exist yet, reached through a symlinked parent,
56
+ # must still resolve onto the real directory.
57
+ pedido = os.path.join(enlace, "not-created-yet")
58
+ esperado = os.path.join(os.path.realpath(real), "not-created-yet")
59
+ comprueba("a missing leaf under a symlink resolves onto the real target",
60
+ rutas.canonicaliza(pedido), esperado)
61
+ # And the containment check sees through the symlink: a token 'allowed'
62
+ # via the link is really inside the real dir.
63
+ afirma("containment sees through the symlink",
64
+ rutas.dentro_de(pedido, real))
65
+ finally:
66
+ shutil.rmtree(base, ignore_errors=True)
67
+
68
+
69
+ def entradas_raras():
70
+ comprueba("~ expands", rutas.canonicaliza("~"), os.path.realpath(os.path.expanduser("~")))
71
+ afirma("a relative path becomes absolute",
72
+ os.path.isabs(rutas.canonicaliza("relative/thing")))
73
+ afirma("empty seal list blocks nothing", rutas.motivo_bloqueo("/anything", []) is None)
74
+
75
+
76
+ contencion()
77
+ bloqueo_bidireccional()
78
+ doble_resolucion()
79
+ entradas_raras()
80
+ sys.exit(resumen("rutas"))