agents-city 0.5.8 → 0.5.10
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 +1 -1
- package/README.es.md +29 -0
- package/README.md +28 -0
- package/bin/hall +83 -3
- package/bin/hall.html +223 -159
- package/bin/serve.py +109 -2
- package/bin/test-atajos.py +68 -0
- package/bin/test-contracts.py +127 -0
- package/bin/test-seat.py +139 -42
- package/bin/test-serve.py +46 -0
- package/city/web/dist/index.html +76 -60
- package/city/web/dist-hall/hall.js +309 -289
- package/city/web/index.html +76 -60
- package/city/web/src/bienvenida.ts +18 -1
- package/city/web/src/desconectado.ts +103 -0
- package/city/web/src/es.ts +23 -0
- package/city/web/src/hall.ts +62 -9
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/scripts/apaga.py +22 -2
- package/plugin/scripts/atajos.py +25 -8
- package/plugin/scripts/city-session.sh +43 -0
- package/plugin/scripts/conciencia.py +158 -0
- package/plugin/scripts/doctor.py +6 -0
- package/plugin/scripts/runtime_processes.py +10 -0
- package/plugin/scripts/seat.py +17 -78
package/README.es.md
CHANGED
|
@@ -619,6 +619,35 @@ agents-city setup --no-browser
|
|
|
619
619
|
| `--tui` | usa onboarding de terminal y abre la sesión |
|
|
620
620
|
| `--no-browser` | mantiene el Hall en terminal e imprime su URL |
|
|
621
621
|
|
|
622
|
+
### `agents-city hall`
|
|
623
|
+
|
|
624
|
+
El ayuntamiento corre **desacoplado**, como el bus de la ciudad y todo lo demás
|
|
625
|
+
que vive mucho en este producto. Cerrar la ventana desde la que lo lanzaste deja
|
|
626
|
+
de ser una forma de romper la página que alguien está mirando, y `agents-city
|
|
627
|
+
hall` dos veces te devuelve la dirección que ya está sirviendo en vez de abrir
|
|
628
|
+
un segundo. Se para con `agents-city exit`; `--foreground` sirve en la ventana y
|
|
629
|
+
muere con ella.
|
|
630
|
+
|
|
631
|
+
Su dirección sobrevive a un reinicio. El token se acuñaba por proceso, y eso
|
|
632
|
+
hacía desechable cada pestaña — cierras el ayuntamiento, lo vuelves a abrir, y la
|
|
633
|
+
página que alguien tenía queda rechazada para siempre, sin más vuelta que leer
|
|
634
|
+
una URL nueva en una terminal. Se guarda en `~/.agents-city/.runtime/hall.pase`,
|
|
635
|
+
modo 0600, en la misma clase que el token del bus que este producto ya guarda.
|
|
636
|
+
|
|
637
|
+
Si la ciudad está corriendo se dice en **todas** las pantallas, no en una
|
|
638
|
+
portada a la que quizá no vuelvas: abierta o no, cuántos agentes están conectados
|
|
639
|
+
de verdad y — sólo cuando falta — que esta ciudad corre sin ninguna de sus reglas.
|
|
640
|
+
Esa última luz hubo que ganársela: antes adivinaba si existía un directorio, y ese
|
|
641
|
+
directorio es la caché del *marketplace*, que aparece en cuanto alguien lo añade.
|
|
642
|
+
Así que una máquina sin el plugin enseñaba un «installed» en verde, y por eso su
|
|
643
|
+
dueño podía pasarse una tarde sin ver que no se estaba aplicando nada. Ahora se lo
|
|
644
|
+
pregunta a Claude.
|
|
645
|
+
|
|
646
|
+
Y cuando el ayuntamiento no contesta, la página lo dice con sus palabras: qué ha
|
|
647
|
+
pasado, que no se ha perdido nada, el comando que lo vuelve a abrir y un botón
|
|
648
|
+
que reintenta — más un reintento silencioso cada pocos segundos, para que una
|
|
649
|
+
pestaña abierta se recupere sola cuando el ayuntamiento vuelve.
|
|
650
|
+
|
|
622
651
|
### `agents-city seat`
|
|
623
652
|
|
|
624
653
|
Configura lo solicitado, garantiza tmux/plugin y abre o reanuda la sesión de la
|
package/README.md
CHANGED
|
@@ -610,6 +610,34 @@ agents-city setup --no-browser
|
|
|
610
610
|
| `--tui` | use terminal onboarding and open the session |
|
|
611
611
|
| `--no-browser` | keep the Hall in the terminal and print its URL |
|
|
612
612
|
|
|
613
|
+
### `agents-city hall`
|
|
614
|
+
|
|
615
|
+
The town hall runs **detached**, like the city bus and every other long-lived
|
|
616
|
+
piece of this product. Closing the window that started it is not a way to break
|
|
617
|
+
the page somebody is looking at, and `agents-city hall` run twice hands back the
|
|
618
|
+
address that is already serving rather than starting a second one. Stop it with
|
|
619
|
+
`agents-city exit`; `--foreground` serves in the window and stops with it.
|
|
620
|
+
|
|
621
|
+
Its address survives a restart. The token used to be minted per process, which
|
|
622
|
+
made every tab disposable — close the hall, open it again, and the page somebody
|
|
623
|
+
had is permanently refused, with no way back except reading a new URL out of a
|
|
624
|
+
terminal. It is stored at `~/.agents-city/.runtime/hall.pase`, mode 0600, in the
|
|
625
|
+
same class as the bus token this product already keeps.
|
|
626
|
+
|
|
627
|
+
Whether the city is running is said on **every** screen, not on the front page
|
|
628
|
+
somebody may never return to: open or not, how many agents are actually
|
|
629
|
+
connected, and — only when it is missing — that this city is running with none of
|
|
630
|
+
its rules. That last light is the one that had to be earned: it used to be a
|
|
631
|
+
guess at whether a directory existed, and that directory is the *marketplace's*
|
|
632
|
+
cache, which appears the moment somebody adds the marketplace. So a machine with
|
|
633
|
+
no city plugin showed a green "installed", which is why its owner could spend an
|
|
634
|
+
afternoon unable to see that nothing was being enforced. It asks Claude now.
|
|
635
|
+
|
|
636
|
+
And when the hall is not answering, the page says so in its own words: what
|
|
637
|
+
happened, that nothing was lost, the command that opens it again, and a button
|
|
638
|
+
that retries — plus a quiet retry every few seconds, so a page left open
|
|
639
|
+
recovers by itself when the hall comes back.
|
|
640
|
+
|
|
613
641
|
### `agents-city seat`
|
|
614
642
|
|
|
615
643
|
Configures requested settings, ensures tmux/plugin, and opens or resumes the city
|
package/bin/hall
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
./bin/hall open it
|
|
5
5
|
./bin/hall --city lab open one known city
|
|
6
6
|
./bin/hall --no-browser print the address instead
|
|
7
|
+
./bin/hall --foreground serve here, and stop when this window closes
|
|
8
|
+
|
|
9
|
+
It runs detached, like the city bus and every other long-lived piece of this
|
|
10
|
+
product. Closing the window that started it is not a way to break the page
|
|
11
|
+
somebody is looking at, and its address survives a restart, so a tab left open
|
|
12
|
+
overnight still works in the morning.
|
|
7
13
|
|
|
8
14
|
One page on localhost: the selected city's identity, owner seat (role, folders,
|
|
9
15
|
goal), repo support agents, recognised skills, roads, districts and houses. It
|
|
@@ -51,10 +57,72 @@ def asegura_build():
|
|
|
51
57
|
return True
|
|
52
58
|
|
|
53
59
|
|
|
60
|
+
def vivo():
|
|
61
|
+
"""The URL of a Hall already serving on this machine, or ''.
|
|
62
|
+
|
|
63
|
+
Asked, not assumed: a marker file outlives a process that was killed, and
|
|
64
|
+
handing somebody a URL that answers nothing is exactly the broken tab this
|
|
65
|
+
change exists to remove.
|
|
66
|
+
"""
|
|
67
|
+
import json
|
|
68
|
+
import urllib.error
|
|
69
|
+
import urllib.request
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
with open(serve.marcador(), encoding='utf-8') as f:
|
|
73
|
+
url = str(json.load(f).get('url') or '')
|
|
74
|
+
if not url:
|
|
75
|
+
return ''
|
|
76
|
+
with urllib.request.urlopen(url, timeout=2) as r:
|
|
77
|
+
return url if r.status == 200 else ''
|
|
78
|
+
except (OSError, ValueError, urllib.error.URLError):
|
|
79
|
+
return ''
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def despega(datos, abrir):
|
|
83
|
+
"""Start the Hall detached, and wait until it can actually answer.
|
|
84
|
+
|
|
85
|
+
Detached because every other long-lived piece of this product already is —
|
|
86
|
+
the bus hub, the gateways, the adapters — and the Hall was the one that died
|
|
87
|
+
with whichever terminal happened to start it. Closing a window is not
|
|
88
|
+
supposed to be a way to break the page somebody is looking at.
|
|
89
|
+
|
|
90
|
+
It waits for the address to serve rather than printing one optimistically: a
|
|
91
|
+
URL that is not up yet is the same broken tab, one second earlier.
|
|
92
|
+
"""
|
|
93
|
+
import subprocess
|
|
94
|
+
import time
|
|
95
|
+
import webbrowser
|
|
96
|
+
|
|
97
|
+
subprocess.Popen(
|
|
98
|
+
[sys.executable, os.path.join(AQUI, 'serve.py'), datos],
|
|
99
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True,
|
|
100
|
+
)
|
|
101
|
+
limite = time.monotonic() + 25
|
|
102
|
+
while time.monotonic() < limite:
|
|
103
|
+
url = vivo()
|
|
104
|
+
if url:
|
|
105
|
+
print(f'\n The town hall\n\n {url}\n')
|
|
106
|
+
print(' It keeps running when you close this window.')
|
|
107
|
+
print(' Stop it with: agents-city exit\n')
|
|
108
|
+
if abrir:
|
|
109
|
+
try:
|
|
110
|
+
webbrowser.open(url)
|
|
111
|
+
except Exception:
|
|
112
|
+
pass
|
|
113
|
+
return 0
|
|
114
|
+
time.sleep(0.2)
|
|
115
|
+
print(' The hall did not come up. Run it here to see why:', file=sys.stderr)
|
|
116
|
+
print(f' {os.path.basename(sys.argv[0])} --foreground', file=sys.stderr)
|
|
117
|
+
return 1
|
|
118
|
+
|
|
119
|
+
|
|
54
120
|
if __name__ == '__main__':
|
|
55
121
|
ap = argparse.ArgumentParser(description='Open one personal city in the local Hall')
|
|
56
122
|
ap.add_argument('--city', default='', help='known city name, id or path')
|
|
57
123
|
ap.add_argument('--no-browser', action='store_true', help='print the URL only')
|
|
124
|
+
ap.add_argument('--foreground', action='store_true',
|
|
125
|
+
help='serve in this window and stop when it closes')
|
|
58
126
|
a = ap.parse_args()
|
|
59
127
|
if not asegura_build():
|
|
60
128
|
sys.exit(1)
|
|
@@ -68,6 +136,18 @@ if __name__ == '__main__':
|
|
|
68
136
|
print(f" This city belongs to {owner!r}, not {usuario!r}.", file=sys.stderr)
|
|
69
137
|
sys.exit(1)
|
|
70
138
|
cities.selecciona(usuario, datos)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
139
|
+
if a.foreground:
|
|
140
|
+
sys.exit(0 if serve.sirve(datos, abrir=not a.no_browser, pagina='hall') else 0)
|
|
141
|
+
# Already open: hand back the same address rather than starting a second
|
|
142
|
+
# hall and leaving somebody with two of them and no way to tell which.
|
|
143
|
+
ya = vivo()
|
|
144
|
+
if ya:
|
|
145
|
+
print(f'\n The town hall is already open\n\n {ya}\n')
|
|
146
|
+
if not a.no_browser:
|
|
147
|
+
import webbrowser
|
|
148
|
+
try:
|
|
149
|
+
webbrowser.open(ya)
|
|
150
|
+
except Exception:
|
|
151
|
+
pass
|
|
152
|
+
sys.exit(0)
|
|
153
|
+
sys.exit(despega(datos, abrir=not a.no_browser))
|