@scp-dev/dashboard 0.3.0 → 0.4.1
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/dist/public/index.html +1 -1
- package/dist/public/selfhost.js +51 -141
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/dist/public/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>scp relay</title><link rel="stylesheet" href="/app.css?v=1oq5q70"><script src="/selfhost.js?v=
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>scp relay</title><link rel="stylesheet" href="/app.css?v=1oq5q70"><script src="/selfhost.js?v=196tpsk" defer></script></head><body></body></html>
|
package/dist/public/selfhost.js
CHANGED
|
@@ -1,96 +1,6 @@
|
|
|
1
|
-
(()=>{var f=((e)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var U=86400000;var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
kind TEXT NOT NULL,
|
|
5
|
-
harness TEXT,
|
|
6
|
-
model TEXT,
|
|
7
|
-
cwd TEXT,
|
|
8
|
-
parent TEXT,
|
|
9
|
-
labels TEXT NOT NULL DEFAULT '{}',
|
|
10
|
-
status_state TEXT,
|
|
11
|
-
status_note TEXT,
|
|
12
|
-
token_hash TEXT,
|
|
13
|
-
connections INTEGER NOT NULL DEFAULT 0,
|
|
14
|
-
last_seen INTEGER,
|
|
15
|
-
last_received_at INTEGER,
|
|
16
|
-
last_received_hop INTEGER,
|
|
17
|
-
created_at INTEGER NOT NULL,
|
|
18
|
-
session TEXT,
|
|
19
|
-
hook_seen INTEGER,
|
|
20
|
-
hook_ended INTEGER,
|
|
21
|
-
process TEXT,
|
|
22
|
-
stop_blocks INTEGER
|
|
23
|
-
)`,"CREATE UNIQUE INDEX IF NOT EXISTS endpoints_token ON endpoints (token_hash)",`CREATE TABLE IF NOT EXISTS messages (
|
|
24
|
-
id TEXT PRIMARY KEY,
|
|
25
|
-
thread TEXT NOT NULL,
|
|
26
|
-
reply_to TEXT,
|
|
27
|
-
kind TEXT NOT NULL,
|
|
28
|
-
from_ep TEXT NOT NULL,
|
|
29
|
-
to_addr TEXT NOT NULL,
|
|
30
|
-
body TEXT NOT NULL,
|
|
31
|
-
mime TEXT NOT NULL,
|
|
32
|
-
data_class TEXT NOT NULL,
|
|
33
|
-
attachments TEXT NOT NULL,
|
|
34
|
-
hop INTEGER NOT NULL,
|
|
35
|
-
created_at INTEGER NOT NULL,
|
|
36
|
-
expires_at INTEGER NOT NULL,
|
|
37
|
-
sender_tty INTEGER,
|
|
38
|
-
require_reply INTEGER
|
|
39
|
-
)`,"CREATE INDEX IF NOT EXISTS messages_thread ON messages (thread)","CREATE INDEX IF NOT EXISTS messages_reply_to ON messages (reply_to)","CREATE INDEX IF NOT EXISTS messages_created ON messages (created_at)",`CREATE TABLE IF NOT EXISTS deliveries (
|
|
40
|
-
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
41
|
-
message_id TEXT NOT NULL,
|
|
42
|
-
endpoint TEXT NOT NULL,
|
|
43
|
-
acked_at INTEGER,
|
|
44
|
-
expires_at INTEGER NOT NULL,
|
|
45
|
-
offered_until INTEGER,
|
|
46
|
-
offered_hold TEXT,
|
|
47
|
-
injected_at INTEGER,
|
|
48
|
-
nudged_at INTEGER,
|
|
49
|
-
deferred_at INTEGER,
|
|
50
|
-
deferred_ack INTEGER
|
|
51
|
-
)`,"CREATE INDEX IF NOT EXISTS deliveries_inbox ON deliveries (endpoint, acked_at, seq)","CREATE INDEX IF NOT EXISTS deliveries_message ON deliveries (message_id)","CREATE INDEX IF NOT EXISTS deliveries_expires ON deliveries (expires_at)",`CREATE TABLE IF NOT EXISTS idempotency (
|
|
52
|
-
from_ep TEXT NOT NULL,
|
|
53
|
-
client_id TEXT NOT NULL,
|
|
54
|
-
payload_hash TEXT NOT NULL,
|
|
55
|
-
result TEXT NOT NULL,
|
|
56
|
-
created_at INTEGER NOT NULL,
|
|
57
|
-
PRIMARY KEY (from_ep, client_id)
|
|
58
|
-
)`,"CREATE TABLE IF NOT EXISTS pair_events (from_ep TEXT NOT NULL, to_ep TEXT NOT NULL, at INTEGER NOT NULL)","CREATE INDEX IF NOT EXISTS pair_events_pair ON pair_events (from_ep, to_ep, at)","CREATE TABLE IF NOT EXISTS blocks (pair TEXT PRIMARY KEY, until INTEGER NOT NULL)",`CREATE TABLE IF NOT EXISTS audit (
|
|
59
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
60
|
-
at INTEGER NOT NULL,
|
|
61
|
-
event TEXT NOT NULL,
|
|
62
|
-
endpoint TEXT,
|
|
63
|
-
ref TEXT,
|
|
64
|
-
detail TEXT NOT NULL DEFAULT '{}'
|
|
65
|
-
)`,"CREATE INDEX IF NOT EXISTS audit_at ON audit (at)",`CREATE TABLE IF NOT EXISTS grants (
|
|
66
|
-
token_hash TEXT PRIMARY KEY,
|
|
67
|
-
issuer TEXT NOT NULL,
|
|
68
|
-
under TEXT NOT NULL,
|
|
69
|
-
name TEXT,
|
|
70
|
-
labels TEXT,
|
|
71
|
-
caps TEXT,
|
|
72
|
-
groups TEXT,
|
|
73
|
-
used_by TEXT,
|
|
74
|
-
created_at INTEGER NOT NULL,
|
|
75
|
-
expires_at INTEGER NOT NULL,
|
|
76
|
-
revoked_at INTEGER,
|
|
77
|
-
spent_cwd TEXT,
|
|
78
|
-
title TEXT,
|
|
79
|
-
bound_process TEXT
|
|
80
|
-
)`,"CREATE TABLE IF NOT EXISTS groups (name TEXT PRIMARY KEY, owner TEXT NOT NULL, tree TEXT, rules TEXT, pinned INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, id TEXT)","CREATE TABLE IF NOT EXISTS group_members (name TEXT NOT NULL, endpoint TEXT NOT NULL, added_by TEXT NOT NULL, at INTEGER NOT NULL, PRIMARY KEY (name, endpoint))","CREATE TABLE IF NOT EXISTS policy_binds (policy TEXT NOT NULL, name TEXT NOT NULL, grp TEXT NOT NULL, PRIMARY KEY (policy, name))","CREATE TABLE IF NOT EXISTS policy_loads (policy TEXT PRIMARY KEY, at INTEGER NOT NULL)","CREATE INDEX IF NOT EXISTS group_members_endpoint ON group_members (endpoint)","CREATE TABLE IF NOT EXISTS admins (subject TEXT NOT NULL, scope_kind TEXT NOT NULL, scope TEXT NOT NULL, scope_id TEXT, granted_at INTEGER NOT NULL, revoked_at INTEGER)","CREATE TABLE IF NOT EXISTS tree_events (tree TEXT NOT NULL, at INTEGER NOT NULL)","CREATE INDEX IF NOT EXISTS tree_events_tree ON tree_events (tree, at)",`CREATE TABLE IF NOT EXISTS spawn_via (
|
|
81
|
-
spawner TEXT NOT NULL, name TEXT NOT NULL, runner TEXT NOT NULL, address TEXT, machine TEXT, ref TEXT, attach TEXT,
|
|
82
|
-
created_at INTEGER NOT NULL, ended_at INTEGER, PRIMARY KEY (spawner, name)
|
|
83
|
-
)`,"CREATE INDEX IF NOT EXISTS spawn_via_address ON spawn_via(address)","CREATE TABLE IF NOT EXISTS relay_migrations (name TEXT PRIMARY KEY, at INTEGER NOT NULL)",`CREATE TABLE IF NOT EXISTS activity (
|
|
84
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
85
|
-
at INTEGER NOT NULL,
|
|
86
|
-
endpoint TEXT NOT NULL,
|
|
87
|
-
kind TEXT NOT NULL,
|
|
88
|
-
tool TEXT,
|
|
89
|
-
summary TEXT,
|
|
90
|
-
agent TEXT
|
|
91
|
-
)`,"CREATE TABLE IF NOT EXISTS peek_turns (id INTEGER PRIMARY KEY AUTOINCREMENT, endpoint TEXT NOT NULL, at INTEGER NOT NULL, role TEXT NOT NULL, text TEXT NOT NULL)","CREATE INDEX IF NOT EXISTS peek_turns_endpoint ON peek_turns (endpoint, id)","CREATE TRIGGER IF NOT EXISTS audit_no_update BEFORE UPDATE ON audit BEGIN SELECT RAISE(ABORT, 'audit is append-only'); END",`CREATE TRIGGER IF NOT EXISTS audit_no_delete BEFORE DELETE ON audit
|
|
92
|
-
WHEN OLD.at > CAST(strftime('%s', 'now') AS INTEGER) * 1000 - ${te.auditKeepS*1000}
|
|
93
|
-
BEGIN SELECT RAISE(ABORT, 'audit is append-only'); END`];var xn=`stderr (last ${te.stderrBytes/1024} KB):`,lt=4,Dn=new RegExp(`^[0-9a-z]{${lt},}$`);var In=`COALESCE(wake IN (${Re.map((e)=>`'${e}'`).join(", ")}), 0)`;class k{value;constructor(e){this.value=e}toString(){return this.value}}var ht={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){if(e instanceof k)return e.value;if(Array.isArray(e))return e.map(Ne).join("");if(e===null||e===void 0||e===!1)return"";return String(e).replace(/[&<>"']/g,(t)=>ht[t])}function r(e,...t){let n=e[0];for(let o=0;o<t.length;o++)n+=Ne(t[o])+e[o+1];return new k(n)}function R(e){let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return(t>>>0).toString(36)}function re(e,t){let n=e.email?r`<nav class="nav" aria-label="Main">
|
|
1
|
+
(()=>{var f=((e)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var U=86400000;var at=(e)=>{let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return t>>>0};function dt(e){let t=e.split(/[^\p{L}\p{N}]+/u).filter(Boolean);return(t.length>1?t[0][0]+t[1][0]:(t[0]??e).slice(0,1)).toUpperCase()||"?"}function ee(e){let t=(d)=>d.split("@")[0]||d,n=new Map;for(let d of e)n.set(t(d.email),(n.get(t(d.email))??0)+1);let o=e.map((d)=>({id:d.user_id,name:n.get(t(d.email))>1?d.email:t(d.email)}));o.sort((d,l)=>d.name.localeCompare(l.name));let i=new Set,s=new Map;for(let{id:d,name:l}of o){let a=at(l)%8;for(let c=0;c<8&&i.has(a);c++)a=(a+1)%8;i.add(a),s.set(d,{name:l,initials:dt(l),tone:a})}return s}function B(e,t){return{...e,machines:e.machines.map(({actor:n,...o})=>({...o,identity:n!==null&&t.get(n)||null}))}}var lt=["inbox.wait","ask","scopes","groups"],fn=[...lt,"peek","judge","holds"],te={bodyBytes:65536,recipients:16,attachments:16,ttlDefaultS:604800,ttlMaxS:2592000,purgeAfterS:604800,inboxMax:1000,inboxPage:100,waitMaxS:50,causalWindowS:120,pairBurstWindowS:10,onlineWithinS:60,hookOnlineS:300,hookIdleS:1800,hookEndedGraceS:30,restartGraceS:60,injectMessages:5,injectBytes:7168,pushBytes:20480,pushes:20,pushGapS:30,pushQuietS:3,pushGraceS:6,stopBlocks:3,directiveHolds:5,injectHoldS:10,deferredShowS:600,deferredSettleMs:2000,listOfflineWithinS:86400,historicAfterS:3600,handleBoundS:2592000,endpointRetireS:86400,endpointRetireMax:1000,idempotencyS:86400,auditKeepS:2592000,noteChars:280,handbackBytes:16384,stderrBytes:1024,activityKeep:5000,activitySummaryChars:200,textField:512,lineageMax:16,depthMax:32,fanOutMax:32,fanOutTotal:64,grantTtlS:604800,groupIdleS:86400,policyLoadsKept:8,titleRefreshTurns:5,wakeDebounceS:60,wakeBackoffMaxS:900,wakeRefChars:512,wakeEtaMaxS:3600};var Re=["codex-queue"];var Se=new Set(["cli","hook","mcp","shell"]);var In=`harness IN (${[...Se].map((e)=>`'${e}'`).join(", ")})`;var ne="_gone_",ct=["scope_refused"],ut=86400;var Te="CAST(strftime('%s', 'now') AS INTEGER) * 1000",pt=ct.map((e)=>`'${e}'`).join(", "),Mn=`CREATE TRIGGER IF NOT EXISTS audit_no_delete BEFORE DELETE ON audit
|
|
2
|
+
WHEN OLD.at > ${Te} - ${te.auditKeepS*1000} AND NOT (OLD.event IN (${pt}) AND OLD.at <= ${Te} - ${ut*1000})
|
|
3
|
+
BEGIN SELECT RAISE(ABORT, 'audit is append-only'); END`;var $n=`stderr (last ${te.stderrBytes/1024} KB):`,ht=4,Cn=new RegExp(`^[0-9a-z]{${ht},}$`);var Un=`COALESCE(wake IN (${Re.map((e)=>`'${e}'`).join(", ")}), 0)`;class k{value;constructor(e){this.value=e}toString(){return this.value}}var Et={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ae(e){if(e instanceof k)return e.value;if(Array.isArray(e))return e.map(Ae).join("");if(e===null||e===void 0||e===!1)return"";return String(e).replace(/[&<>"']/g,(t)=>Et[t])}function r(e,...t){let n=e[0];for(let o=0;o<t.length;o++)n+=Ae(t[o])+e[o+1];return new k(n)}function R(e){let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return(t>>>0).toString(36)}function re(e,t){let n=e.email?r`<nav class="nav" aria-label="Main">
|
|
94
4
|
<a href="/orgs" ${e.nav==="orgs"?r`aria-current="page"`:""}>Orgs</a>
|
|
95
5
|
<a href="/device" ${e.nav==="device"?r`aria-current="page"`:""}>Device</a>
|
|
96
6
|
<form method="post" action="/sign-out"><input type="hidden" name="csrf" value="${e.csrf}"><button class="linkish" type="submit">Sign out</button></form>
|
|
@@ -103,7 +13,7 @@
|
|
|
103
13
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
104
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
105
15
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap">
|
|
106
|
-
<link rel="stylesheet" href="/app.css?v=${R(
|
|
16
|
+
<link rel="stylesheet" href="/app.css?v=${R(wt)}">
|
|
107
17
|
${e.head??""}
|
|
108
18
|
</head>
|
|
109
19
|
${e.bare?r`<body class="bare">${t}</body>
|
|
@@ -118,7 +28,7 @@ ${n}
|
|
|
118
28
|
<a class="mini-link" href="https://scp.dev/spec">Spec</a>
|
|
119
29
|
</div></footer>
|
|
120
30
|
</body>
|
|
121
|
-
</html>`}`}`}var
|
|
31
|
+
</html>`}`}`}var wt=`
|
|
122
32
|
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
|
|
123
33
|
:root{--bg:#fff;--surface:#f7f7f6;--fg:#0b0b0b;--ink:#555;--dim:#6b6b6b;--faint:#a8a8a8;--line:rgb(0 0 0/.12);--line-soft:rgb(0 0 0/.065);--acc:#4746d4;--acc-soft:rgb(71 70 212/.09);--warn:#b4321f;--head:rgb(255 255 255/.82);
|
|
124
34
|
--sans:"Geist",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Arial,sans-serif;--mono:"Geist Mono",ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;--gutter:clamp(1rem,4vw,3rem);--headh:4rem}
|
|
@@ -305,23 +215,23 @@ table.orgs td.end,table.orgs th.end{text-align:right}
|
|
|
305
215
|
.harnesses .more{line-height:1}
|
|
306
216
|
.foot-in{display:flex;flex-wrap:wrap;justify-content:space-between;gap:1rem;padding-block:2rem}
|
|
307
217
|
@media (prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}
|
|
308
|
-
`;var ks=30*U;var Rs=["default-src 'none'","style-src 'self' https://fonts.googleapis.com","font-src https://fonts.gstatic.com","script-src 'self' https://challenges.cloudflare.com","frame-src https://challenges.cloudflare.com","connect-src 'self' https://challenges.cloudflare.com","img-src 'self' data:","form-action 'self'","frame-ancestors 'none'","base-uri 'none'"].join("; ");var L=8000;function O(e,t){if(!e)return"never";let n=Math.max(0,Math.round((t-Date.parse(e))/1000));if(n<5)return"just now";if(n<60)return`${n}s ago`;if(n<3600)return`${Math.floor(n/60)}m ago`;if(n<86400)return`${Math.floor(n/3600)}h ago`;return`${Math.floor(n/86400)}d ago`}function E(e){let[,t="",...n]=e.split("/");return{machine:t,handle:n.join("/")||t}}function X(e,t=!1){let n=new Map(e.machines.map((s)=>[s.name,{name:s.name,machine:s,endpoints:[],away:0}])),o=(s)=>{let d=n.get(s);if(!d)d={name:s,machine:null,endpoints:[],away:0},n.set(s,d);return d},i=new Map(e.endpoints.filter((s)=>s.kind==="agent").map((s)=>[s.address,s]));for(let s of i.values()){let d=s,l=new Set([s.address]);for(let u=t?i.get(d.parent??""):void 0;u&&!l.has(u.address);u=i.get(u.parent??""))l.add(u.address),d=u;let a=E(s.address).machine,c=t?E(d.address).machine:a;if(o(c).endpoints.push(s),c!==a)o(a).away++}return[...n.values()]}var x=(e)=>e.wake&&e.wake!=="none"?e.wake:null,wt=r`<svg class="bolt" viewBox="0 0 16 16" aria-hidden="true"><path d="M9.5 1 3 9h4.5L6.5 15 13 7H8.5z" fill="currentColor"/></svg>`;function G(e){if(e.startsWith("hook:"))return`a message runs its ${e.slice(5)} wake hook`;if(e==="spawn-resume")return"a message resumes it through its spawn";return`a message wakes it via ${e}`}function bt(e){let t=x(e),n=e.waking?"hibernated, its machine is waking":t?`${e.presence}, ${G(t)}`:e.presence==="idle"?"idle, reads messages at its next turn":e.presence;return{cell:r`<span class="dot ${e.presence}${t?" wake":""}" aria-hidden="true"></span><span class="mini">${e.waking?"waking":e.presence}</span>${t?r` <span class="wake-badge">${wt}<span class="sr">${G(t)}</span></span>`:""}`,tip:n}}var le={claude:'<path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z" fill="currentColor"/>',codex:'<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="currentColor"/>',opencode:'<path d="M21.6 24H2.4V0h19.2zM16.8 4.8H7.2v14.4h9.6z" fill="currentColor"/><path d="M16.8 9.6H7.2v9.6h9.6z" fill="currentColor" opacity=".45"/>',gemini:'<path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" fill="currentColor"/>',agy:'<path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" fill="currentColor"/>',grok:'<g transform="translate(1.2 1.2) scale(.9)"><path d="M6.469 8.776 16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9 2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z" fill="currentColor"/></g>',muse:'<g transform="translate(-1.2 -1.2) scale(1.1)"><path d="M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z" fill="currentColor"/></g>',pi:'<path d="M0 0h18v6H0zM0 6h6v18H0zM12 6h6v6h-6zM6 12h6v6H6zM18 12h6v12h-6z" fill="currentColor"/>',t3code:'<path d="M5.177,18.414V7.823H1V5.362H12.374V7.823H8.197V18.414H5.177ZM17.593,18.638C16.686,18.638 15.784,18.52 14.889,18.283C13.994,18.035 13.236,17.687 12.615,17.239L13.789,14.927C14.287,15.288 14.865,15.574 15.523,15.785C16.182,15.996 16.847,16.102 17.518,16.102C18.277,16.102 18.873,15.953 19.308,15.654C19.743,15.356 19.961,14.946 19.961,14.424C19.961,13.927 19.768,13.535 19.383,13.249C18.998,12.963 18.376,12.82 17.518,12.82H16.139V10.825L19.774,6.705L20.11,7.786H13.267V5.362H22.403V7.32L18.786,11.441L17.257,10.564H18.134C19.737,10.564 20.949,10.925 21.769,11.646C22.59,12.367 23,13.293 23,14.424C23,15.157 22.807,15.847 22.422,16.494C22.037,17.127 21.446,17.643 20.651,18.041C19.855,18.439 18.836,18.638 17.593,18.638Z" fill="currentColor"/>',generic:'<g transform="scale(1.5)"><rect x="1.75" y="2.75" width="12.5" height="10.5" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M4.5 6.25 6.5 8l-2 1.75M8 10h3" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></g>'},yt={"claude-code":"claude","claude-desktop":"claude","claude-cowork":"claude","claude-desktop-chat":"claude","codex-desktop":"codex",claude:"claude",codex:"codex",opencode:"opencode",gemini:"gemini",agy:"agy",antigravity:"agy",grok:"grok",muse:"muse",xai:"grok",pi:"pi",t3code:"t3code",t3:"t3code"},V=(e)=>yt[(e??"").toLowerCase()]??"generic",q=(e)=>{let t=V(e);return r`<svg class="hicon h-${t}" width="12" height="12" viewBox="0 0 24 24" role="img" aria-label="${e??"unknown harness"}">${new k(le[t])}</svg>`},vt=r`<svg width="8" height="8" viewBox="0 0 8 8" aria-hidden="true"><path d="M2 .75 6.5 4 2 7.25z" fill="currentColor"/></svg>`,J=(e)=>e.startsWith(ne)?"(ended)":e,S=(e)=>J(E(e).handle),_t=(e)=>Object.entries(e).filter(([t])=>t!=="machine"),Oe={online:0,idle:1,hibernated:1,offline:2},oe=(e,t)=>(Oe[e.presence]??3)-(Oe[t.presence]??3)||E(e.address).handle.localeCompare(E(t.address).handle);function xe(e){let t=new Set(e.map((a)=>a.address)),n=new Map,o=[];for(let a of e)if(a.parent&&a.parent!==a.address&&t.has(a.parent))n.set(a.parent,[...n.get(a.parent)??[],a]);else o.push(a);let i=[],s=new Set,d=(a,c)=>{for(let u of a.sort(oe)){if(s.has(u.address))continue;s.add(u.address),i.push({e:u,depth:c.length,anc:c,kids:0}),d(n.get(u.address)??[],[...c,u.address])}};d(o,[]),d(e.filter((a)=>!s.has(a.address)),[]);let l=new Map(i.map((a)=>[a.e.address,a]));for(let a of i)if(a.anc.length)l.get(a.anc.at(-1)).kids++;return i}var ae=(e)=>e.presence!=="offline";function kt(e){let t=e.filter((a)=>a.kind==="agent"),n=new Set(t.map((a)=>a.address)),o=new Map,i=[];for(let a of t)if(a.parent&&a.parent!==a.address&&n.has(a.parent))o.set(a.parent,[...o.get(a.parent)??[],a]);else i.push(a);let s=new Set,d=(a)=>{s.add(a.address);let c=[],u=[...o.get(a.address)??[]];while(u.length){let w=u.pop();if(s.has(w.address))continue;s.add(w.address),c.push(w),u.push(...o.get(w.address)??[])}return{root:a,kids:c.filter(ae).sort(oe)}},l=i.map(d);for(let a of t)if(!s.has(a.address))l.push(d(a));return l.filter((a)=>ae(a.root)||a.kids.length).sort((a,c)=>c.kids.length-a.kids.length||oe(a.root,c.root))}var Rt=3,de=(e)=>r`<span class="cell ${e.presence}${x(e)?" wake":""}" title="${S(e.address)}, ${e.presence}"></span>`;function De({root:e,kids:t}){let{machine:n}=E(e.address);return r`<div class="strip-row"><span class="strip-who" title="${e.address}">${q(e.harness)}<span class="mono strip-name">${S(e.address)}</span><span class="mini">${n}</span></span>
|
|
309
|
-
<span class="cells">${ae(e)?de(e):""}${t.map(de)}</span>${t.length?r`<span class="mini push">${t.length}</span>`:""}</div>`}function
|
|
310
|
-
<span class="cells">${t.map((n)=>de(n.root))}</span></div>`]}function
|
|
311
|
-
<td class="agent" title="${
|
|
218
|
+
`;var Ns=30*U;var As=["default-src 'none'","style-src 'self' https://fonts.googleapis.com","font-src https://fonts.gstatic.com","script-src 'self' https://challenges.cloudflare.com","frame-src https://challenges.cloudflare.com","connect-src 'self' https://challenges.cloudflare.com","img-src 'self' data:","form-action 'self'","frame-ancestors 'none'","base-uri 'none'"].join("; ");var L=8000;function O(e,t){if(!e)return"never";let n=Math.max(0,Math.round((t-Date.parse(e))/1000));if(n<5)return"just now";if(n<60)return`${n}s ago`;if(n<3600)return`${Math.floor(n/60)}m ago`;if(n<86400)return`${Math.floor(n/3600)}h ago`;return`${Math.floor(n/86400)}d ago`}function E(e){let[,t="",...n]=e.split("/");return{machine:t,handle:n.join("/")||t}}function X(e,t=!1){let n=new Map(e.machines.map((s)=>[s.name,{name:s.name,machine:s,endpoints:[],away:0}])),o=(s)=>{let d=n.get(s);if(!d)d={name:s,machine:null,endpoints:[],away:0},n.set(s,d);return d},i=new Map(e.endpoints.filter((s)=>s.kind==="agent").map((s)=>[s.address,s]));for(let s of i.values()){let d=s,l=new Set([s.address]);for(let u=t?i.get(d.parent??""):void 0;u&&!l.has(u.address);u=i.get(u.parent??""))l.add(u.address),d=u;let a=E(s.address).machine,c=t?E(d.address).machine:a;if(o(c).endpoints.push(s),c!==a)o(a).away++}return[...n.values()]}var x=(e)=>e.wake&&e.wake!=="none"?e.wake:null,vt=r`<svg class="bolt" viewBox="0 0 16 16" aria-hidden="true"><path d="M9.5 1 3 9h4.5L6.5 15 13 7H8.5z" fill="currentColor"/></svg>`;function G(e){if(e.startsWith("hook:"))return`a message runs its ${e.slice(5)} wake hook`;if(e==="spawn-resume")return"a message resumes it through its spawn";return`a message wakes it via ${e}`}function kt(e){let t=x(e),n=e.waking?"hibernated, its machine is waking":t?`${e.presence}, ${G(t)}`:e.presence==="idle"?"idle, reads messages at its next turn":e.presence;return{cell:r`<span class="dot ${e.presence}${t?" wake":""}" aria-hidden="true"></span><span class="mini">${e.waking?"waking":e.presence}</span>${t?r` <span class="wake-badge">${vt}<span class="sr">${G(t)}</span></span>`:""}`,tip:n}}var le={claude:'<path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z" fill="currentColor"/>',codex:'<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="currentColor"/>',opencode:'<path d="M21.6 24H2.4V0h19.2zM16.8 4.8H7.2v14.4h9.6z" fill="currentColor"/><path d="M16.8 9.6H7.2v9.6h9.6z" fill="currentColor" opacity=".45"/>',gemini:'<path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" fill="currentColor"/>',agy:'<path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" fill="currentColor"/>',grok:'<g transform="translate(1.2 1.2) scale(.9)"><path d="M6.469 8.776 16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9 2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z" fill="currentColor"/></g>',muse:'<g transform="translate(-1.2 -1.2) scale(1.1)"><path d="M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z" fill="currentColor"/></g>',pi:'<path d="M0 0h18v6H0zM0 6h6v18H0zM12 6h6v6h-6zM6 12h6v6H6zM18 12h6v12h-6z" fill="currentColor"/>',t3code:'<path d="M5.177,18.414V7.823H1V5.362H12.374V7.823H8.197V18.414H5.177ZM17.593,18.638C16.686,18.638 15.784,18.52 14.889,18.283C13.994,18.035 13.236,17.687 12.615,17.239L13.789,14.927C14.287,15.288 14.865,15.574 15.523,15.785C16.182,15.996 16.847,16.102 17.518,16.102C18.277,16.102 18.873,15.953 19.308,15.654C19.743,15.356 19.961,14.946 19.961,14.424C19.961,13.927 19.768,13.535 19.383,13.249C18.998,12.963 18.376,12.82 17.518,12.82H16.139V10.825L19.774,6.705L20.11,7.786H13.267V5.362H22.403V7.32L18.786,11.441L17.257,10.564H18.134C19.737,10.564 20.949,10.925 21.769,11.646C22.59,12.367 23,13.293 23,14.424C23,15.157 22.807,15.847 22.422,16.494C22.037,17.127 21.446,17.643 20.651,18.041C19.855,18.439 18.836,18.638 17.593,18.638Z" fill="currentColor"/>',generic:'<g transform="scale(1.5)"><rect x="1.75" y="2.75" width="12.5" height="10.5" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M4.5 6.25 6.5 8l-2 1.75M8 10h3" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></g>'},Rt={"claude-code":"claude","claude-desktop":"claude","claude-cowork":"claude","claude-desktop-chat":"claude","codex-desktop":"codex",claude:"claude",codex:"codex",opencode:"opencode",gemini:"gemini",agy:"agy",antigravity:"agy",grok:"grok",muse:"muse",xai:"grok",pi:"pi",t3code:"t3code",t3:"t3code"},V=(e)=>Rt[(e??"").toLowerCase()]??"generic",q=(e)=>{let t=V(e);return r`<svg class="hicon h-${t}" width="12" height="12" viewBox="0 0 24 24" role="img" aria-label="${e??"unknown harness"}">${new k(le[t])}</svg>`},St=r`<svg width="8" height="8" viewBox="0 0 8 8" aria-hidden="true"><path d="M2 .75 6.5 4 2 7.25z" fill="currentColor"/></svg>`,J=(e)=>e.startsWith(ne)?"(ended)":e,S=(e)=>J(E(e).handle),Tt=(e)=>Object.entries(e).filter(([t])=>t!=="machine"),xe={online:0,idle:1,hibernated:1,offline:2},oe=(e,t)=>(xe[e.presence]??3)-(xe[t.presence]??3)||E(e.address).handle.localeCompare(E(t.address).handle);function De(e){let t=new Set(e.map((a)=>a.address)),n=new Map,o=[];for(let a of e)if(a.parent&&a.parent!==a.address&&t.has(a.parent))n.set(a.parent,[...n.get(a.parent)??[],a]);else o.push(a);let i=[],s=new Set,d=(a,c)=>{for(let u of a.sort(oe)){if(s.has(u.address))continue;s.add(u.address),i.push({e:u,depth:c.length,anc:c,kids:0}),d(n.get(u.address)??[],[...c,u.address])}};d(o,[]),d(e.filter((a)=>!s.has(a.address)),[]);let l=new Map(i.map((a)=>[a.e.address,a]));for(let a of i)if(a.anc.length)l.get(a.anc.at(-1)).kids++;return i}var ae=(e)=>e.presence!=="offline";function Nt(e){let t=e.filter((a)=>a.kind==="agent"),n=new Set(t.map((a)=>a.address)),o=new Map,i=[];for(let a of t)if(a.parent&&a.parent!==a.address&&n.has(a.parent))o.set(a.parent,[...o.get(a.parent)??[],a]);else i.push(a);let s=new Set,d=(a)=>{s.add(a.address);let c=[],u=[...o.get(a.address)??[]];while(u.length){let w=u.pop();if(s.has(w.address))continue;s.add(w.address),c.push(w),u.push(...o.get(w.address)??[])}return{root:a,kids:c.filter(ae).sort(oe)}},l=i.map(d);for(let a of t)if(!s.has(a.address))l.push(d(a));return l.filter((a)=>ae(a.root)||a.kids.length).sort((a,c)=>c.kids.length-a.kids.length||oe(a.root,c.root))}var At=3,de=(e)=>r`<span class="cell ${e.presence}${x(e)?" wake":""}" title="${S(e.address)}, ${e.presence}"></span>`;function Ie({root:e,kids:t}){let{machine:n}=E(e.address);return r`<div class="strip-row"><span class="strip-who" title="${e.address}">${q(e.harness)}<span class="mono strip-name">${S(e.address)}</span><span class="mini">${n}</span></span>
|
|
219
|
+
<span class="cells">${ae(e)?de(e):""}${t.map(de)}</span>${t.length?r`<span class="mini push">${t.length}</span>`:""}</div>`}function Lt(e){let t=e.filter((n)=>!n.kids.length);if(t.length<=At)return e.map(Ie);return[...e.filter((n)=>n.kids.length).map(Ie),r`<div class="strip-row"><span class="strip-who"><span class="mono strip-name">${t.length} solo agents</span></span>
|
|
220
|
+
<span class="cells">${t.map((n)=>de(n.root))}</span></div>`]}function $e(e,t){return r`<div class="strip" aria-label="Agents per orchestrator">${Lt(Nt(e.endpoints))}</div><p class="mini strip-key"><span class="cell online"></span>online <span class="cell idle wake"></span>wakeable <span class="cell idle"></span>next turn <a class="mini-link push" href="/orgs/${t}/graph">Graph</a></p>`}function Ot({e,depth:t,anc:n,kids:o},i,s,d){let l=S(e.address),{machine:a}=E(e.address),c=e.parent?S(e.parent):null,u=Tt(e.labels),w=e.status?e.status.note?`${e.status.state}: ${e.status.note}`:e.status.state:"none",it=e.presence==="online"?"now":O(e.last_seen,s),_e=kt(e),rt=o?r`<button class="caret" type="button" data-tree="${e.address}" aria-expanded="${String(!i.has(e.address))}" aria-label="${o} under ${l}">${St}</button>`:r`<span class="caret" aria-hidden="true"></span>`,ot=[l,e.harness??"unknown harness",c?`sub of ${c}`:""].filter(Boolean).join(", ");return r`<tr${t?r` class="sub d${Math.min(t,4)}" data-anc="${n.join(" ")}"${n.some((C)=>i.has(C))?" hidden":""}`:""}>
|
|
221
|
+
<td class="agent" title="${ot}">${rt}${q(e.harness)}<span class="mono">${l}</span>${a!==d?r` <span class="tag" title="runs on ${a}">${a}</span>`:""}${c&&!t?r` <span class="mini">sub of ${c}</span>`:""}</td>
|
|
312
222
|
<td class="small" title="${e.title??""}">${e.title??""}</td>
|
|
313
|
-
<td title="${
|
|
223
|
+
<td title="${_e.tip}">${_e.cell}</td>
|
|
314
224
|
<td title="${w}">${e.status?r`<span class="role">${e.status.state}</span>${e.status.note?r` <span class="small">${e.status.note}</span>`:""}`:r`<span class="mini">none</span>`}</td>
|
|
315
225
|
<td title="${u.map(([C,Q])=>`${C}=${Q}`).join(", ")}">${u.map(([C,Q])=>r`<span class="tag">${C}=${Q}</span>`)}</td>
|
|
316
|
-
<td class="mono end" title="${e.last_seen??"never"}">${
|
|
317
|
-
</tr>`}var
|
|
226
|
+
<td class="mono end" title="${e.last_seen??"never"}">${it}</td>
|
|
227
|
+
</tr>`}var xt=r`<colgroup><col class="c-agent"><col class="c-title"><col class="c-presence"><col class="c-status"><col class="c-labels"><col class="c-seen"></colgroup>`,Me=(e,t,n,o)=>{let i=new Set(e.filter((s)=>s.kids&&s.e.presence==="offline").map((s)=>s.e.address));return r`<div class="table"><table class="agents">${xt}${n?r`<thead><tr><th>Agent</th><th>Title</th><th>Presence</th><th>Status</th><th>Labels</th><th class="end">Seen</th></tr></thead>`:""}<tbody>${e.map((s)=>Ot(s,i,t,o))}</tbody></table></div>`};function Dt(e,t){let n=e.machine,o=n?n.online?"online":"offline":e.endpoints.some((d)=>d.presence==="online")?"online":"offline",i=De(e.endpoints.filter((d)=>d.presence!=="offline")),s=De(e.endpoints.filter((d)=>d.presence==="offline"));return r`<div class="machine">
|
|
318
228
|
<div class="machine-head">
|
|
319
229
|
<span class="dot ${o}" aria-hidden="true"></span><h3 class="mono">${e.name}</h3>
|
|
320
230
|
${n?r`<span class="role">${n.kind}</span>`:""}
|
|
321
231
|
<span class="mini">${o==="online"?"online":`seen ${O(n?.last_seen??null,t)}`}</span>
|
|
322
232
|
<span class="mini push">${e.endpoints.length} ${e.endpoints.length===1?"agent":"agents"}</span>
|
|
323
233
|
</div>
|
|
324
|
-
${e.endpoints.length?r`${i.length?
|
|
234
|
+
${e.endpoints.length?r`${i.length?Me(i,t,!0,e.name):""}${s.length?r`<details class="offline" data-key="${e.name}"><summary class="mini"><span class="when-shut">show</span><span class="when-open">hide</span> ${s.length} offline</summary>${Me(s,t,!i.length,e.name)}</details>`:""}`:r`<p class="empty">${e.away?`Its ${e.away===1?"agent shows":"agents show"} under a parent on another machine.`:"No agents on this machine right now."}</p>`}
|
|
325
235
|
</div>`}function z(e){switch(e.kind){case"session_start":return"started a session";case"session_end":return"ended its session";case"stop":return e.summary?`finished a turn: ${e.summary}`:"finished a turn";case"tool":return[e.tool,e.summary].filter(Boolean).join(": ")||"used a tool";default:return e.summary??e.kind}}var ce=(e)=>[...e].sort((t,n)=>n.at.localeCompare(t.at));function ue(e,t){return r`<section class="block"><div class="block-head"><h2>Recent activity</h2>${Y(t)}</div>
|
|
326
236
|
${e.length?r`<div class="table"><table class="activity"><colgroup><col class="c-when"><col class="c-who"><col></colgroup><thead><tr><th>When</th><th>Agent</th><th>What</th></tr></thead>
|
|
327
237
|
<tbody>${ce(e).map((n)=>{let{machine:o,handle:i}=E(n.endpoint),s=`${o}/${J(i)}`,d=z(n);return r`<tr><td class="mono" title="${n.at}">${O(n.at,t)}</td><td class="mono" title="${n.agent?`${s} ${n.agent}`:s}">${s}${n.agent?r` <span class="mini">${n.agent}</span>`:""}</td><td class="small" title="${d}">${d}</td></tr>`})}</tbody></table></div>`:r`<p class="empty">No activity yet. Hooks report tool use and turns as agents work.</p>`}</section>`}var j=(e)=>r`<div class="cmd"><code><span class="prompt" aria-hidden="true">$ </span>${e}</code><button class="btn btn-ghost btn-small" type="button" data-copy="${e}">Copy</button></div>`,Y=(e)=>r`<span class="mini push live-stamp"><span class="dot online pulse" aria-hidden="true"></span><span data-feed>polling</span>, updated ${new Date(e).toISOString().slice(11,19)} UTC</span>`;function pe(e){return r`<section class="block onboard"><h2>Connect your first machine</h2>
|
|
@@ -337,10 +247,10 @@ table.orgs td.end,table.orgs th.end{text-align:right}
|
|
|
337
247
|
${j("swarm up --token <token> --machine <name>")}
|
|
338
248
|
<p class="small">Or set <code>SCP_TOKEN</code> in its environment. Its agents show the label <span class="tag">token=<name></span>.</p>
|
|
339
249
|
</div>
|
|
340
|
-
</section>`}var P=()=>
|
|
250
|
+
</section>`}var P=()=>_("The hub did not answer. This page retries on its own.",!0)||r``;function he(e,t,n){if(!e)return P();let o=X(e,!0);if(!o.length)return pe(t);let i=o.reduce((d,l)=>d+l.endpoints.length,0),s=o.filter((d)=>d.machine?.online||d.endpoints.some((l)=>l.presence==="online")).length;return r`<section class="block"><div class="block-head"><h2>Machines</h2>
|
|
341
251
|
<span class="mini">${o.length} ${o.length===1?"machine":"machines"}, ${s} online, ${i} ${i===1?"agent":"agents"}</span>
|
|
342
252
|
${Y(n)}</div>
|
|
343
|
-
${o.map((d)=>
|
|
253
|
+
${o.map((d)=>Dt(d,n))}
|
|
344
254
|
</section>`}var K=`
|
|
345
255
|
const chosen = new Map();
|
|
346
256
|
const fold = (root) => {
|
|
@@ -421,31 +331,31 @@ if (live) {
|
|
|
421
331
|
}
|
|
422
332
|
const tab = document.querySelector('.tabs [aria-current="page"]');
|
|
423
333
|
if (tab) tab.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
424
|
-
`;var
|
|
334
|
+
`;var ni=7*U;var Ce=[["overview","Overview",""],["activity","Activity","/activity"],["sessions","Sessions","/sessions"],["graph","Graph","/graph"],["tokens","Tokens and devices","/tokens"],["members","Members","/members"]],Ht=(e,t,n)=>r`<nav class="tabs" aria-label="${e}">${t.map(([o,i])=>r`<a href="${o}"${o===n?r` aria-current="page"`:""}>${i}</a>`)}</nav>`;function ge(e,t){let n=`/orgs/${e.org.handle}`;return r`<div class="org-head">
|
|
425
335
|
<p class="label"><a class="mini-link" href="/orgs">Orgs</a> / ${e.org.handle}</p>
|
|
426
336
|
<div class="org-title"><h1>${e.org.name}</h1><span class="mini">you are <span class="role">${e.role}</span></span></div>
|
|
427
337
|
</div>
|
|
428
|
-
${
|
|
338
|
+
${Ht("Organization",Ce.map(([,o,i])=>[n+i,o]),n+Ce.find(([o])=>o===t)[2])}`}function He(e,t,n,o={}){let i=r`<script src="/app.js?v=${R(K)}" defer></script>`,s=o.live?r`${i}<noscript><meta http-equiv="refresh" content="${Math.round(L/1000)}"></noscript>`:i,d=o.live?r`<div class="tab-body" data-live="${L}" data-events="/orgs/${e.org.handle}/events">${n}</div>`:r`<div class="tab-body">${n}</div>`;return{head:s,nav:"orgs",body:r`${ge(e,t)}${d}`}}var _=(e,t=!1)=>e?r`<p class="notice${t?" err":""}" role="${t?"alert":"status"}">${e}</p>`:"";function Wt(e,t){let n=e.endpoints.filter((s)=>s.kind==="agent"),o=n.filter((s)=>s.presence==="idle"),i=X(e);return{online:n.filter((s)=>s.presence==="online").length,wakeable:o.filter((s)=>x(s)).length,nextTurn:o.filter((s)=>!x(s)).length,offline:n.filter((s)=>s.presence==="offline").length,machines:i.length,machinesOnline:i.filter((s)=>s.machine?.online||s.endpoints.some((d)=>d.presence==="online")).length,messages:t?t.edges.filter((s)=>s.kind==="message").reduce((s,d)=>s+(d.count??0),0):null,minutes:t?.minutes??15}}var W=(e,t,n,o="")=>r`<div class="tile${o?` ${o}`:""}"><p class="tile-label">${e}</p><p class="tile-value">${t}</p><p class="mini">${n}</p></div>`;function Ft(e){return r`<div class="tiles">
|
|
429
339
|
${W("Online",e.online,e.online===1?"agent working":"agents working","on")}
|
|
430
340
|
${W("Idle, wakeable",e.wakeable,"a message wakes them")}
|
|
431
341
|
${W("Idle, next turn",e.nextTurn,"read at their next turn")}
|
|
432
342
|
${W("Machines",e.machines,`${e.machinesOnline} online`)}
|
|
433
343
|
${W("Messages",e.messages??"-",`last ${e.minutes} min`)}
|
|
434
|
-
</div>`}function
|
|
344
|
+
</div>`}function Bt(e,t){if(e.status)return{lead:r`<span class="role">${e.status.state}</span>`,text:e.status.note??""};let n=t.get(e.address);if(n?.summary)return{lead:r`<span class="mini">tl;dr</span>`,text:n.summary};if(e.title)return{lead:"",text:e.title};return null}var me=6,Pe={online:0,idle:1,hibernated:1,offline:2};function jt(e,t,n){let o=new Map,i=ce(e.activity);for(let a of i)if(a.kind==="stop"&&a.summary&&!o.has(a.endpoint))o.set(a.endpoint,a);let s=e.endpoints.filter((a)=>a.kind==="agent"&&a.presence!=="offline").map((a)=>({e:a,g:Bt(a,o)})).sort((a,c)=>(Pe[a.e.presence]??3)-(Pe[c.e.presence]??3)||Number(!a.g)-Number(!c.g)||(c.e.last_seen??"").localeCompare(a.e.last_seen??"")),d=s.slice(0,me),l=i[0];return r`<section class="panel now"><div class="panel-head"><h2>Happening now</h2><a class="mini-link push" href="/orgs/${n}/sessions">All sessions</a></div>
|
|
435
345
|
${d.length?r`<ul class="now-list">${d.map(({e:a,g:c})=>{let u=x(a);return r`<li><div class="now-who">${q(a.harness)}<span class="mono">${S(a.address)}</span><span class="mini">${E(a.address).machine}</span><span class="push mini"><span class="dot ${a.presence}${u?" wake":""}" aria-hidden="true"></span>${a.presence}</span></div>
|
|
436
346
|
<p class="now-what small" title="${c?.text??""}">${c?r`${c.lead}${c.lead&&c.text?" ":""}${c.text}`:r`<span class="mini">no status yet</span>`}</p></li>`})}</ul>${s.length>me?r`<p class="mini more-line">and ${s.length-me} more on the <a class="mini-link" href="/orgs/${n}/sessions">Sessions</a> tab</p>`:""}`:r`<p class="empty">No agent is online or idle right now.</p>`}
|
|
437
347
|
${l?r`<p class="mini last-line"><span class="what" title="${z(l)}">Last activity ${O(l.at,t)}: ${S(l.endpoint)}, ${z(l)}</span><a class="mini-link" href="/orgs/${n}/activity">All activity</a></p>`:""}
|
|
438
|
-
</section>`}var F=(e,t,n=`${t}s`)=>`${e} ${e===1?t:n}`;function
|
|
348
|
+
</section>`}var F=(e,t,n=`${t}s`)=>`${e} ${e===1?t:n}`;function We(e,t,n,o,i){if(!e)return P();if(!e.machines.length&&!e.endpoints.length)return pe(o);let s=Wt(e,t),d=n.holds?r`<p class="notice held" role="status">${F(n.holds,"message")} held by the relay judge, waiting for review. <a href="/orgs/${o}/members#judge">Review</a></p>`:"";return r`<div class="block-head summary-head"><p class="mini">${F(s.online+s.wakeable+s.nextTurn,"agent")} live, ${s.offline} offline</p>${Y(i)}</div>
|
|
439
349
|
${d}
|
|
440
|
-
${
|
|
350
|
+
${Ft(s)}
|
|
441
351
|
<div class="panels">
|
|
442
|
-
${
|
|
352
|
+
${jt(e,i,o)}
|
|
443
353
|
<section class="panel"><div class="panel-head"><h2>Fleet</h2></div>
|
|
444
|
-
${
|
|
354
|
+
${$e(e,o)}
|
|
445
355
|
<p class="small fleet-line">${F(s.machines,"machine")}, ${s.machinesOnline} online. ${F(n.devices,"device")} and ${F(n.tokens,"API token")} signed in. <a class="mini-link" href="/orgs/${o}/tokens">Manage</a></p>
|
|
446
356
|
</section>
|
|
447
|
-
</div>`}var
|
|
448
|
-
${
|
|
357
|
+
</div>`}var Gt=["claude","codex","opencode","gemini","agy","grok","muse","pi","t3code"],Xt='<g transform="scale(1.5)"><circle cx="8" cy="5.25" r="2.75" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="M2.75 14c.5-3 2.6-4.75 5.25-4.75S12.75 11 13.25 14" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></g>',Vt='<path d="M3 3h10v4H7v6H3zM29 29H19v-4h6v-6h4z"/><rect x="11" y="11" width="10" height="10"/>';function Fe(e){let t=e.split("/");return t.length>=3?{machine:t[1],handle:t.slice(2).join("/")}:{machine:"",handle:""}}function Jt(e,t){if(!t||e.length<=t.length+1||!e.startsWith(t))return e;return"-_./:".includes(e[t.length])?e.slice(t.length+1):e}function Be(e){if(!e)return r``;let t=e.nodes.map((i)=>{let{machine:s,handle:d}=Fe(i.address),l=i.kind==="human"?"human":J(d),a=i.parent?Fe(i.parent):null;return{address:i.address,kind:i.kind,machine:s,name:l,label:l===d&&a&&a.machine===s?Jt(d,a.handle):l,icon:i.kind==="human"?"human":V(i.harness),harness:i.harness,title:i.title,presence:i.presence,status:i.status,wake:i.wake&&i.wake!=="none"?i.wake:null,how:i.waking?"its machine is waking":i.wake&&i.wake!=="none"?G(i.wake):null,parent:i.parent,historic:i.historic===!0}}),n=e.machines.filter((i)=>i.kind!=="revoked").map((i)=>({name:i.name,online:i.online,identity:i.identity??null})),o=JSON.stringify({minutes:e.minutes,machines:n,nodes:t,edges:e.edges}).replace(/</g,"\\u003c");return r`<script type="application/json" data-graph-data>${new k(o)}</script>`}var je=r`<div class="graph-canvas"><svg class="graph-svg" role="group" aria-label="Agents by machine"></svg><div class="graph-tip" role="tooltip" hidden></div></div>`,Ge=r`<span class="trails" role="group" aria-label="Message trail speed">trails <span class="seg">${["1","0.5","0.25"].map((e)=>r`<button type="button" data-trail="${e}" aria-pressed="${e==="1"?"true":"false"}">${e}x</button>`)}</span></span>`,Xe=(e)=>r`<label class="mini"><input type="checkbox" data-graph-nextturn> show next-turn idle</label><label class="mini"><input type="checkbox" data-graph-offline> show offline</label>${e?r`<label class="mini"><input type="checkbox" data-graph-historic> show historic</label>`:""}`,Ve=r`<p class="mini graph-legend"><span class="key spawn" aria-hidden="true"></span>spawned <span class="key msg" aria-hidden="true"></span>messages, last <span data-graph-minutes>15</span> min</p>`,fe=()=>r`<script src="/app.js?v=${R(K)}" defer></script><script src="/graph.js?v=${R(tn())}" defer></script><link rel="stylesheet" href="/graph.css?v=${R(zt)}">`;function Je(e,t,n={}){return r`<div class="graph gfull" data-graph data-full data-events="/orgs/${e.handle}/events" aria-label="Live graph of agents and their links">
|
|
358
|
+
${je}
|
|
449
359
|
<header class="g-over g-left">
|
|
450
360
|
<a class="mini-link" href="/orgs/${e.handle}/graph">Back to the dashboard</a>
|
|
451
361
|
<h1 title="${e.name}">${e.name}</h1>
|
|
@@ -453,27 +363,27 @@ if (tab) tab.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
|
453
363
|
<p class="mini" data-graph-stream></p>
|
|
454
364
|
</header>
|
|
455
365
|
<div class="g-over g-right">
|
|
456
|
-
${
|
|
457
|
-
${
|
|
458
|
-
<span class="mini">${
|
|
366
|
+
${Ve}
|
|
367
|
+
${Xe(n.historic===!0)}
|
|
368
|
+
<span class="mini">${Ge}</span>
|
|
459
369
|
</div>
|
|
460
|
-
<div hidden data-live="${L}">${
|
|
370
|
+
<div hidden data-live="${L}">${Be(t)}</div>
|
|
461
371
|
${t?"":r`<p class="g-empty mini">The hub did not answer. This page retries on its own.</p>`}
|
|
462
|
-
</div>`}function
|
|
372
|
+
</div>`}function ze(e,t,n={}){return r`${ge(e,"graph")}
|
|
463
373
|
<div class="graph gfull gtab" data-graph data-full data-events="/orgs/${e.org.handle}/events" aria-label="Live graph of agents and their links">
|
|
464
|
-
${
|
|
374
|
+
${je}
|
|
465
375
|
<div class="g-over g-left">
|
|
466
376
|
<p class="mini" data-graph-counts></p>
|
|
467
377
|
<p class="mini" data-graph-stream></p>
|
|
468
378
|
</div>
|
|
469
379
|
<div class="g-over g-right">
|
|
470
|
-
${
|
|
471
|
-
<span class="g-acts">${
|
|
472
|
-
<span class="mini">${
|
|
380
|
+
${Ve}
|
|
381
|
+
<span class="g-acts">${Xe(n.historic===!0)}<a class="mini-link" href="/orgs/${e.org.handle}/graph/full">Full screen</a></span>
|
|
382
|
+
<span class="mini">${Ge}</span>
|
|
473
383
|
</div>
|
|
474
|
-
<div hidden data-live="${L}">${
|
|
384
|
+
<div hidden data-live="${L}">${Be(t)}</div>
|
|
475
385
|
${t?"":r`<p class="g-empty mini">The hub did not answer. This page retries on its own.</p>`}
|
|
476
|
-
</div>`}var
|
|
386
|
+
</div>`}var zt=`
|
|
477
387
|
:root{--id-0:#2f6fdb;--id-1:#c2410c;--id-2:#0f8a6c;--id-3:#a3369e;--id-4:#a16207;--id-5:#6d4fd6;--id-6:#be123c;--id-7:#3f7d20}
|
|
478
388
|
@media (prefers-color-scheme:dark){:root{--id-0:#7aa9ff;--id-1:#f59a63;--id-2:#3fc6a0;--id-3:#e27ad9;--id-4:#e3b341;--id-5:#a991ff;--id-6:#fb7185;--id-7:#8fd16a}}
|
|
479
389
|
.g-over label{display:inline-flex;align-items:center;gap:.375rem;cursor:pointer}
|
|
@@ -558,14 +468,14 @@ body.bare{overflow:hidden;height:100dvh;min-height:0}
|
|
|
558
468
|
.g-right{top:1rem;right:1rem;justify-items:end}
|
|
559
469
|
.g-empty{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}
|
|
560
470
|
@media (max-width:40rem){.g-right{top:auto;bottom:1rem}}
|
|
561
|
-
`,
|
|
471
|
+
`,Yt=`function drawn(n, o, talks) {
|
|
562
472
|
if (n.historic) return !!o.historic;
|
|
563
473
|
if (n.presence === "offline") return o.offline || (n.kind === "human" && talks.has(n.address));
|
|
564
474
|
if (n.presence === "idle" && n.kind === "agent" && !n.wake) return o.nextTurn;
|
|
565
475
|
return true;
|
|
566
|
-
}`,
|
|
476
|
+
}`,Kt=`function slot(e, w, h, min) {
|
|
567
477
|
return { x0: e.x0, x1: Math.max(e.x1, e.x0 + w, e.x0 + min), y0: e.y0 - h, y1: e.y1 };
|
|
568
|
-
}`,
|
|
478
|
+
}`,Zt=`function bands(items, o) {
|
|
569
479
|
const byKey = new Map();
|
|
570
480
|
for (const it of items) { if (!byKey.has(it.key)) byKey.set(it.key, { key: it.key, items: [] }); byKey.get(it.key).items.push(it); }
|
|
571
481
|
const groups = [...byKey.values()];
|
|
@@ -602,7 +512,7 @@ body.bare{overflow:hidden;height:100dvh;min-height:0}
|
|
|
602
512
|
y += Math.max(...row.groups.map((g) => g.h)) + o.groupGap;
|
|
603
513
|
});
|
|
604
514
|
return { places, bands: rects, hub, width, height: Math.max(y - o.groupGap, 1) };
|
|
605
|
-
}`,
|
|
515
|
+
}`,Qt={gap:14,ring:84,reach:160,span:2.4,wide:1.4,sub:1.6,apart:64,aspect:1.8},en=`function cluster(ns, B, o) {
|
|
606
516
|
const at = new Map(ns.map((n, i) => [n.address, i]));
|
|
607
517
|
const by = (a, b) => (ns[a].address < ns[b].address ? -1 : ns[a].address > ns[b].address ? 1 : 0);
|
|
608
518
|
const kids = ns.map(() => []);
|
|
@@ -692,24 +602,24 @@ function collide(P, B, mob) {
|
|
|
692
602
|
else { const s = (dy >= 0 ? 1 : -1) * (oy + 0.5); P[i].y -= s * mi / sum; P[j].y += s * mj / sum; }
|
|
693
603
|
}
|
|
694
604
|
return hit;
|
|
695
|
-
}`,
|
|
605
|
+
}`,tn=()=>`(() => {
|
|
696
606
|
const root = document.querySelector("[data-graph]");
|
|
697
607
|
const live = document.querySelector("[data-live]");
|
|
698
608
|
if (!root || !live) return;
|
|
699
609
|
const bar = document.querySelector("[data-view-bar]");
|
|
700
610
|
const full = root.hasAttribute("data-full");
|
|
701
611
|
const NS = "http://www.w3.org/2000/svg";
|
|
702
|
-
const ICONS = ${JSON.stringify({...le,human:
|
|
703
|
-
const MARK = ${JSON.stringify(
|
|
704
|
-
const COLORED = new Set(${JSON.stringify(
|
|
612
|
+
const ICONS = ${JSON.stringify({...le,human:Xt})};
|
|
613
|
+
const MARK = ${JSON.stringify(Vt)};
|
|
614
|
+
const COLORED = new Set(${JSON.stringify(Gt)});
|
|
705
615
|
const BOLT = "M9.5 1 3 9h4.5L6.5 15 13 7H8.5z";
|
|
706
616
|
const R = 16, PAD = 20, HEAD = 26, ID_LINE = 14, GAP = 26, BAND_GAP = 44, LABEL_MAX = 176, NAME_MAX = 220, ID_MAX = 200, MIN_W = 96, CAP = 1.6;
|
|
707
617
|
const TRAILS = [1, 0.5, 0.25];
|
|
708
|
-
const LAYOUT = ${JSON.stringify(
|
|
709
|
-
${
|
|
618
|
+
const LAYOUT = ${JSON.stringify(Qt)};
|
|
619
|
+
${Kt}
|
|
620
|
+
${en}
|
|
621
|
+
${Zt}
|
|
710
622
|
${Yt}
|
|
711
|
-
${Jt}
|
|
712
|
-
${Xt}
|
|
713
623
|
const svg = root.querySelector(".graph-svg");
|
|
714
624
|
const canvas = root.querySelector(".graph-canvas");
|
|
715
625
|
const tip = root.querySelector(".graph-tip");
|
|
@@ -1300,9 +1210,9 @@ setStream(false);
|
|
|
1300
1210
|
update();
|
|
1301
1211
|
connect();
|
|
1302
1212
|
})();
|
|
1303
|
-
`;var
|
|
1213
|
+
`;var Ye={overview:"",agents:"/sessions",devices:"/tokens",machines:"/tokens",settings:"/members",judge:"/members"};function Ke(e){if(!e?.startsWith("/")||/[\u0000-\u001f\u007f\\]/.test(e))return"/";let t="https://relay.invalid";try{let n=new URL(e,t);return n.origin===t&&n.pathname.replace(/\/+$/,"")!=="/sign-in"?n.pathname+n.search+n.hash:"/"}catch{return"/"}}function Ze(e,t){let n=e.replace(/\/+$/,"")||"/",o=`/orgs/${t.org.handle}`;if(n==="/"||n==="/orgs"||n==="/sign-in")return{redirect:o};if(n==="/device")return{page:"device"};if(n===o)return{tab:"overview"};if(!n.startsWith(`${o}/`))return{page:"not-found"};let i=n.slice(o.length+1);if(Object.hasOwn(Ye,i))return{redirect:o+Ye[i]};if(["activity","sessions","graph","graph/full","tokens","members"].includes(i))return{tab:i};return{page:"not-found"}}function T(e,t,n){return re({...t,email:e.signedIn?e.member.name:null,csrf:e.csrf},n)}function nn(e,t,n,o){let i=n.graph?B(n.graph,ee(e.members.map((s)=>({user_id:s.id,email:s.name})))):null;switch(t){case"overview":{let s={devices:e.devices,tokens:e.tokens,holds:null};return We(n.overview,i,s,e.org.handle,o)}case"activity":return n.overview?ue(n.overview.activity,o):P();case"sessions":return he(n.overview,e.org.handle,o);case"tokens":return r`${_("Tokens and devices are managed with the scp-relay token CLI.")}`;case"members":return r`${_("Members are managed with the scp-relay account CLI.")}`;case"graph":return ze({org:e.org,role:e.member.role},i,{historic:!0})}}function Qe(e,t,n,o){let i={org:e.org,role:e.member.role},s=t==="overview"?e.org.name:`${e.org.name} ${t==="graph/full"?"graph":t}`;if(t==="graph/full"){let u=n.graph?B(n.graph,ee(e.members.map((w)=>({user_id:w.id,email:w.name})))):null;return T(e,{title:s,bare:!0,head:fe()},Je(e.org,u,{historic:!0}))}let d=nn(e,t,n,o);if(t==="graph")return T(e,{title:s,nav:"orgs",head:fe()},d);let l=t==="overview"||t==="activity"||t==="sessions",{body:a,...c}=He(i,t,d,{live:l});return T(e,{...c,title:s},a)}function N(e,t="",n){return T(e,{title:"Sign in",narrow:!0},r`<p class="label">Self-hosted relay</p><h1>Sign in</h1>
|
|
1304
1214
|
<p class="lead">Use a relay token or sign in with a device code.</p>
|
|
1305
|
-
${
|
|
1215
|
+
${_(t,!0)}
|
|
1306
1216
|
<form class="form" data-sign-in method="post" action="/v1/dashboard/sign-in">
|
|
1307
1217
|
<input type="hidden" name="csrf" value="${e.csrf}">
|
|
1308
1218
|
<label class="field"><span>Token</span><input type="password" name="token" placeholder="scp_t_... or scp_d_..." required autofocus autocomplete="off"></label>
|
|
@@ -1312,7 +1222,7 @@ connect();
|
|
|
1312
1222
|
<input type="hidden" name="csrf" value="${e.csrf}">
|
|
1313
1223
|
<div class="acts"><button class="btn btn-ghost" type="submit"${n?r` disabled`:""}>Sign in with a device code</button></div>
|
|
1314
1224
|
</form>
|
|
1315
|
-
${n?r`<section class="block"><h2>Approve this device</h2><p class="small">Run this command on the relay, replacing the account and member placeholders:</p><pre><code>scp-relay device approve ${n.user_code} --account <handle> --member <name></code></pre><p class="mini" role="status">Waiting for approval.</p></section>`:""}`)}var Ee=(e)=>`'${e.replace(/'/g,"'\\''")}'`;function
|
|
1225
|
+
${n?r`<section class="block"><h2>Approve this device</h2><p class="small">Run this command on the relay, replacing the account and member placeholders:</p><pre><code>scp-relay device approve ${n.user_code} --account <handle> --member <name></code></pre><p class="mini" role="status">Waiting for approval.</p></section>`:""}`)}var Ee=(e)=>`'${e.replace(/'/g,"'\\''")}'`;function et(e,t="<user_code>"){return T(e,{title:"Device",nav:"device",narrow:!0},r`<p class="label">Device sign-in</p><h1>Approve a device</h1>
|
|
1316
1226
|
<p class="lead">Approve the code shown on the device by running this command on the relay:</p>
|
|
1317
1227
|
<pre><code>scp-relay device approve ${Ee(t)} --account ${Ee(e.org.handle)} --member ${Ee(e.member.name)}</code></pre>
|
|
1318
|
-
<p class="small">Only approve a code for a device you recognize.</p>`)}function
|
|
1228
|
+
<p class="small">Only approve a code for a device you recognize.</p>`)}function tt(e){return T(e,{title:"Not found",narrow:!0},r`<h1>Not found</h1><p class="lead">This page does not exist.</p><a href="/">Return home</a>`)}function we(e,t){return T(e,{title:"Dashboard unavailable",narrow:!0},r`<h1>Dashboard unavailable</h1>${_(t,!0)}<a href="">Reload</a>`)}var m={signedIn:!1,csrf:""},D=0,be=!1;class M extends Error{}async function I(e,t){let n=await fetch(`/v1/dashboard/${e}`,{method:t?"POST":"GET",credentials:"same-origin",cache:"no-store",headers:t?{accept:"application/json","content-type":"application/json"}:{accept:"application/json"},...t?{body:JSON.stringify({...t,csrf:m.csrf})}:{}}),o=await n.json();if(!n.ok){let i=o&&typeof o==="object"?o:{};if(n.status===401&&i.error==="signed_out")throw new M;throw Error(typeof i.message==="string"?i.message:i.error==="invalid_token"?"The token is not valid.":"The relay could not complete the request.")}return o}function b(e){let t=new DOMParser().parseFromString(e,"text/html"),n=[...t.querySelectorAll("script[src]")];document.head.replaceWith(t.head),document.body.replaceWith(t.body);for(let o of n){let i=document.createElement("script");for(let s of o.attributes)i.setAttribute(s.name,s.value);i.async=!1,o.replaceWith(i)}}function ye(){location.replace(`/sign-in?next=${encodeURIComponent(location.pathname+location.search)}`)}async function nt(e){try{return await I(e)}catch(t){if(t instanceof M)throw t;return null}}function sn(){try{return localStorage.getItem("scp.graph.historic")==="1"}catch{return!1}}async function rn(e){let t=["overview","activity","sessions","graph","graph/full"].includes(e),n=["overview","graph","graph/full"].includes(e),[o,i]=await Promise.all([t?nt("overview"):null,n?nt(sn()?"graph?historic=1":"graph"):null]);return{overview:o,graph:i}}var Z=(e)=>e instanceof Error?e.message:"The relay could not complete the request.",st=()=>location.replace(Ke(new URLSearchParams(location.search).get("next")));async function on(e,t){let n=Date.now()+e.expires_in*1000,o=Math.max(1,e.interval)*1000;while(t===D){if(await new Promise((s)=>setTimeout(s,o)),t!==D)return;if(Date.now()>=n)break;let i=await I("device/poll",{device_code:e.device_code});if(t!==D)return;if(i.status==="ok"){st();return}if(i.status!=="pending"){b(N(m,i.status==="denied"?"Device sign-in was denied.":"The device code expired. Try again."));return}}if(t===D)b(N(m,"The device code expired. Try again."))}document.addEventListener("submit",(e)=>{let t=e.target;if(!(t instanceof HTMLFormElement))return;let n=t.getAttribute("action")==="/sign-out",o=t.hasAttribute("data-sign-in"),i=t.hasAttribute("data-device");if(!n&&!o&&!i)return;if(e.preventDefault(),be)return;be=!0;let s=++D;for(let d of t.querySelectorAll("button"))d.disabled=!0;(async()=>{try{if(n)await I("sign-out",{}),location.replace("/sign-in");else if(o){let d=new FormData(t).get("token");await I("sign-in",{token:typeof d==="string"?d:""}),st()}else{let d=await I("device",{});b(N(m,"",d)),on(d,s).catch((l)=>{if(s===D)b(N(m,Z(l)))})}}catch(d){if(d instanceof M)ye();else b(m.signedIn?we(m,Z(d)):N(m,Z(d)))}finally{be=!1}})()});async function an(){if(m=await I("session"),!m.signedIn){b(N(m));return}let e=m,t=Ze(location.pathname,e);if("redirect"in t){location.replace(t.redirect);return}if("page"in t){b(t.page==="device"?et(e,new URLSearchParams(location.search).get("user_code")??void 0):tt(e));return}let n=async()=>Qe(e,t.tab,await rn(t.tab),Date.now());window.scpRegion=async()=>{try{return new DOMParser().parseFromString(await n(),"text/html").querySelector("[data-live]")}catch(o){if(o instanceof M)ye();return null}},b(await n())}an().catch((e)=>{if(e instanceof M)ye();else b(we(m,Z(e)))});})();
|
package/dist/server.js
CHANGED