@scp-dev/dashboard 0.4.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.
@@ -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=6h9eza" defer></script></head><body></body></html>
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>
@@ -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 ot=(e)=>{let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return t>>>0};function at(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=ot(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:at(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 dt=["inbox.wait","ask","scopes","groups"],pn=[...dt,"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 Ln=`harness IN (${[...Se].map((e)=>`'${e}'`).join(", ")})`;var ne="_gone_",On=[`CREATE TABLE IF NOT EXISTS endpoints (
2
- id TEXT PRIMARY KEY,
3
- handle TEXT NOT NULL UNIQUE,
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={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};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={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};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(gt)}">
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 gt=`
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>`},_t=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),vt=(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 St(e){let t=e.filter((n)=>!n.kids.length);if(t.length<=Rt)return e.map(De);return[...e.filter((n)=>n.kids.length).map(De),r`<div class="strip-row"><span class="strip-who"><span class="mono strip-name">${t.length} solo agents</span></span>
310
- <span class="cells">${t.map((n)=>de(n.root))}</span></div>`]}function Me(e,t){return r`<div class="strip" aria-label="Agents per orchestrator">${St(kt(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 Tt({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=vt(e.labels),w=e.status?e.status.note?`${e.status.state}: ${e.status.note}`:e.status.state:"none",st=e.presence==="online"?"now":O(e.last_seen,s),_e=bt(e),it=o?r`<button class="caret" type="button" data-tree="${e.address}" aria-expanded="${String(!i.has(e.address))}" aria-label="${o} under ${l}">${_t}</button>`:r`<span class="caret" aria-hidden="true"></span>`,rt=[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":""}`:""}>
311
- <td class="agent" title="${rt}">${it}${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>
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
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"}">${st}</td>
317
- </tr>`}var Nt=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>`,Ie=(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">${Nt}${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)=>Tt(s,i,t,o))}</tbody></table></div>`};function At(e,t){let n=e.machine,o=n?n.online?"online":"offline":e.endpoints.some((d)=>d.presence==="online")?"online":"offline",i=xe(e.endpoints.filter((d)=>d.presence!=="offline")),s=xe(e.endpoints.filter((d)=>d.presence==="offline"));return r`<div class="machine">
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?Ie(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>${Ie(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>`}
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>
@@ -340,7 +250,7 @@ table.orgs td.end,table.orgs th.end{text-align:right}
340
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)=>At(d,n))}
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 Zs=7*U;var $e=[["overview","Overview",""],["activity","Activity","/activity"],["sessions","Sessions","/sessions"],["graph","Graph","/graph"],["tokens","Tokens and devices","/tokens"],["members","Members","/members"]],Mt=(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">
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
- ${Mt("Organization",$e.map(([,o,i])=>[n+i,o]),n+$e.find(([o])=>o===t)[2])}`}function Ue(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 Ut(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 Ht(e){return r`<div class="tiles">
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 qt(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,qe={online:0,idle:1,hibernated:1,offline:2};function Pt(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:qt(a,o)})).sort((a,c)=>(qe[a.e.presence]??3)-(qe[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>
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 Pe(e,t,n,o,i){if(!e)return P();if(!e.machines.length&&!e.endpoints.length)return pe(o);let s=Ut(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>
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
- ${Ht(s)}
350
+ ${Ft(s)}
441
351
  <div class="panels">
442
- ${Pt(e,i,o)}
352
+ ${jt(e,i,o)}
443
353
  <section class="panel"><div class="panel-head"><h2>Fleet</h2></div>
444
- ${Me(e,o)}
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 Wt=["claude","codex","opencode","gemini","agy","grok","muse","pi","t3code"],Ft='<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>',Bt='<path d="M3 3h10v4H7v6H3zM29 29H19v-4h6v-6h4z"/><rect x="11" y="11" width="10" height="10"/>';function We(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 Fe(e){if(!e)return r``;let t=e.nodes.map((i)=>{let{machine:s,handle:d}=We(i.address),l=i.kind==="human"?"human":J(d),a=i.parent?We(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 Be=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>`,je=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>`,Ge=(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>`:""}`,Xe=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(Kt())}" defer></script><link rel="stylesheet" href="/graph.css?v=${R(Gt)}">`;function Ve(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">
448
- ${Be}
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
- ${Xe}
457
- ${Ge(n.historic===!0)}
458
- <span class="mini">${je}</span>
366
+ ${Ve}
367
+ ${Xe(n.historic===!0)}
368
+ <span class="mini">${Ge}</span>
459
369
  </div>
460
- <div hidden data-live="${L}">${Fe(t)}</div>
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 Je(e,t,n={}){return r`${ge(e,"graph")}
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
- ${Be}
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
- ${Xe}
471
- <span class="g-acts">${Ge(n.historic===!0)}<a class="mini-link" href="/orgs/${e.org.handle}/graph/full">Full screen</a></span>
472
- <span class="mini">${je}</span>
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}">${Fe(t)}</div>
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 Gt=`
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
- `,Xt=`function drawn(n, o, talks) {
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
- }`,Vt=`function slot(e, w, h, min) {
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
- }`,Jt=`function bands(items, o) {
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
- }`,zt={gap:14,ring:84,reach:160,span:2.4,wide:1.4,sub:1.6,apart:64,aspect:1.8},Yt=`function cluster(ns, B, o) {
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
- }`,Kt=()=>`(() => {
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:Ft})};
703
- const MARK = ${JSON.stringify(Bt)};
704
- const COLORED = new Set(${JSON.stringify(Wt)});
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(zt)};
709
- ${Vt}
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,7 +1210,7 @@ setStream(false);
1300
1210
  update();
1301
1211
  connect();
1302
1212
  })();
1303
- `;var ze={overview:"",agents:"/sessions",devices:"/tokens",machines:"/tokens",settings:"/members",judge:"/members"};function Ye(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 Ke(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(ze,i))return{redirect:o+ze[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 Zt(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 Pe(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 Je({org:e.org,role:e.member.role},i,{historic:!0})}}function Ze(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()},Ve(e.org,u,{historic:!0}))}let d=Zt(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}=Ue(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>
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">
@@ -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 &lt;handle&gt; --member &lt;name&gt;</code></pre><p class="mini" role="status">Waiting for approval.</p></section>`:""}`)}var Ee=(e)=>`'${e.replace(/'/g,"'\\''")}'`;function Qe(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>
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 &lt;handle&gt; --member &lt;name&gt;</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 et(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 tt(e){try{return await I(e)}catch(t){if(t instanceof M)throw t;return null}}function Qt(){try{return localStorage.getItem("scp.graph.historic")==="1"}catch{return!1}}async function en(e){let t=["overview","activity","sessions","graph","graph/full"].includes(e),n=["overview","graph","graph/full"].includes(e),[o,i]=await Promise.all([t?tt("overview"):null,n?tt(Qt()?"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.",nt=()=>location.replace(Ye(new URLSearchParams(location.search).get("next")));async function tn(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"){nt();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:""}),nt()}else{let d=await I("device",{});b(N(m,"",d)),tn(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 nn(){if(m=await I("session"),!m.signedIn){b(N(m));return}let e=m,t=Ke(location.pathname,e);if("redirect"in t){location.replace(t.redirect);return}if("page"in t){b(t.page==="device"?Qe(e,new URLSearchParams(location.search).get("user_code")??void 0):et(e));return}let n=async()=>Ze(e,t.tab,await en(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())}nn().catch((e)=>{if(e instanceof M)ye();else b(we(m,Z(e)))});})();
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
@@ -395,7 +395,7 @@ Flags: --help, --version, --health`);
395
395
  return;
396
396
  }
397
397
  if (args.includes("--version")) {
398
- console.log("0.4.0");
398
+ console.log("0.4.1");
399
399
  return;
400
400
  }
401
401
  const options = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scp-dev/dashboard",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Optional dashboard for the SCP relay",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",