@korso/shepherd-ui 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +47 -47
  2. package/dist/ShepherdRoot.js +15 -57
  3. package/dist/components/Dashboard.d.ts +16 -2
  4. package/dist/components/Dashboard.js +76 -5
  5. package/dist/config/ConnectAgent.js +4 -4
  6. package/dist/config/EmptyState.js +5 -1
  7. package/dist/config/Members.js +4 -4
  8. package/dist/config/Workspaces.js +1 -1
  9. package/dist/lib/{Dashboard-CG6KeFQ3.js → Dashboard-B7nioe5N.js} +529 -457
  10. package/dist/lib/index.d.ts +15 -1
  11. package/dist/lib/index.js +300 -359
  12. package/dist/lib/selfhost.js +1 -1
  13. package/dist/lib/styles.css +252 -209
  14. package/dist/selfhost/assets/index-COMbJ-a4.js +40 -0
  15. package/dist/selfhost/assets/index-CcGvL65Q.css +1 -0
  16. package/dist/selfhost/index.html +13 -13
  17. package/dist/useLandscapePolling.d.ts +7 -0
  18. package/dist/useLandscapePolling.js +6 -1
  19. package/package.json +67 -67
  20. package/dist/ShepherdProvider.d.ts +0 -12
  21. package/dist/ShepherdProvider.js +0 -33
  22. package/dist/ShepherdProvider.test.d.ts +0 -1
  23. package/dist/ShepherdProvider.test.js +0 -47
  24. package/dist/ShepherdRoot.routing.test.d.ts +0 -1
  25. package/dist/ShepherdRoot.routing.test.js +0 -61
  26. package/dist/ShepherdRoot.test.d.ts +0 -1
  27. package/dist/ShepherdRoot.test.js +0 -37
  28. package/dist/app/assets/index-CDOCIg6s.js +0 -11
  29. package/dist/app/index.html +0 -12
  30. package/dist/client.test.d.ts +0 -1
  31. package/dist/client.test.js +0 -298
  32. package/dist/config/ConnectAgent.test.d.ts +0 -1
  33. package/dist/config/ConnectAgent.test.js +0 -92
  34. package/dist/config/EmptyState.test.d.ts +0 -1
  35. package/dist/config/EmptyState.test.js +0 -32
  36. package/dist/config/Members.test.d.ts +0 -1
  37. package/dist/config/Members.test.js +0 -66
  38. package/dist/config/Workspaces.test.d.ts +0 -1
  39. package/dist/config/Workspaces.test.js +0 -90
  40. package/dist/index.cjs +0 -5289
  41. package/dist/index.cjs.map +0 -1
  42. package/dist/index.d.cts +0 -149
  43. package/dist/index.js.map +0 -1
  44. package/dist/selfhost/assets/index-BZmImfYZ.css +0 -1
  45. package/dist/selfhost/assets/index-CS268KSw.js +0 -40
  46. package/dist/test/setup.d.ts +0 -1
  47. package/dist/test/setup.js +0 -2
  48. package/dist/views/Chat.d.ts +0 -5
  49. package/dist/views/Chat.js +0 -60
  50. package/dist/views/Chat.test.d.ts +0 -1
  51. package/dist/views/Chat.test.js +0 -92
  52. package/dist/views/Config.d.ts +0 -12
  53. package/dist/views/Config.js +0 -6
  54. package/dist/views/Tasks.d.ts +0 -5
  55. package/dist/views/Tasks.js +0 -75
  56. package/dist/views/Tasks.test.d.ts +0 -1
  57. package/dist/views/Tasks.test.js +0 -115
  58. package/dist/views/useLandscape.d.ts +0 -14
  59. package/dist/views/useLandscape.js +0 -74
  60. package/dist/views/useLandscape.test.d.ts +0 -1
  61. package/dist/views/useLandscape.test.js +0 -101
  62. package/dist/views/wallboard.d.ts +0 -46
  63. package/dist/views/wallboard.js +0 -209
  64. package/dist/views/wallboard.test.d.ts +0 -1
  65. package/dist/views/wallboard.test.js +0 -143
@@ -1,10 +1,10 @@
1
- var _e = Object.defineProperty;
2
- var Ne = (n, t, i) => t in n ? _e(n, t, { enumerable: !0, configurable: !0, writable: !0, value: i }) : n[t] = i;
3
- var ee = (n, t, i) => Ne(n, typeof t != "symbol" ? t + "" : t, i);
4
- import { jsx as o, jsxs as m, Fragment as ye } from "react/jsx-runtime";
5
- import { createContext as ke, useContext as we, useState as k, useRef as x, useCallback as S, useEffect as X, Fragment as Ae, useLayoutEffect as Se } from "react";
1
+ var De = Object.defineProperty;
2
+ var je = (t, n, i) => n in t ? De(t, n, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[n] = i;
3
+ var le = (t, n, i) => je(t, typeof n != "symbol" ? n + "" : n, i);
4
+ import { jsx as o, jsxs as m, Fragment as F } from "react/jsx-runtime";
5
+ import { createContext as Ie, useContext as xe, useState as A, useRef as P, useCallback as R, useEffect as ne, Fragment as Le, useLayoutEffect as Me, useId as Pe } from "react";
6
6
  import { z as e } from "zod";
7
- const A = e.string(), H = e.number(), Te = e.object({
7
+ const C = e.string(), z = e.number(), Ge = e.object({
8
8
  agentName: e.string(),
9
9
  human: e.string(),
10
10
  branch: e.string(),
@@ -13,9 +13,9 @@ const A = e.string(), H = e.number(), Te = e.object({
13
13
  message: e.string().nullable(),
14
14
  paths: e.array(e.string()).min(1),
15
15
  authorIsLive: e.boolean(),
16
- authorLastActiveAt: A,
17
- updatedAt: A
18
- }), $e = e.object({
16
+ authorLastActiveAt: C,
17
+ updatedAt: C
18
+ }), Oe = e.object({
19
19
  kind: e.enum(["committed", "uncommitted"]),
20
20
  // A git object id (lowercase hex, 4–64 chars) for `committed` entries, or null
21
21
  // for `uncommitted`. This value is forwarded by the hub to OTHER clients, which
@@ -27,7 +27,7 @@ const A = e.string(), H = e.number(), Te = e.object({
27
27
  sha: e.string().regex(/^[0-9a-f]{4,64}$/).nullable(),
28
28
  message: e.string().nullable(),
29
29
  paths: e.array(e.string()).min(1).max(500)
30
- }), Z = e.object({
30
+ }), se = e.object({
31
31
  branch: e.string(),
32
32
  baseBranch: e.string(),
33
33
  head: e.string(),
@@ -36,36 +36,36 @@ const A = e.string(), H = e.number(), Te = e.object({
36
36
  // (100) committed entries + 1 uncommitted, so this ceiling is generous. If
37
37
  // MAX_COMMITS is ever raised above ~599, raise this in lockstep or the hub
38
38
  // will start 400-rejecting otherwise-valid reports.
39
- entries: e.array($e).max(600)
40
- }), q = e.object({
39
+ entries: e.array(Oe).max(600)
40
+ }), X = e.object({
41
41
  workItemId: e.string().uuid(),
42
42
  agentName: e.string(),
43
43
  human: e.string().min(1),
44
44
  intent: e.string().min(1).max(2048),
45
45
  pathGlobs: e.array(e.string().min(1).max(512)).min(1).max(64),
46
46
  // ISO timestamp string; see IsoTimestamp note above
47
- expiresAt: A
48
- }), W = e.object({
47
+ expiresAt: C
48
+ }), B = e.object({
49
49
  // bigint PK serialised as number; see DbId note above
50
- id: H,
50
+ id: z,
51
51
  fromAgentName: e.string(),
52
52
  fromHuman: e.string().min(1),
53
53
  body: e.string().min(1).max(8192),
54
54
  targetAgentName: e.string().nullable(),
55
55
  // ISO timestamp string; see IsoTimestamp note above
56
- createdAt: A
57
- }), ue = e.object({
58
- conflicts: e.array(q),
59
- activeClaims: e.array(q),
56
+ createdAt: C
57
+ }), Ne = e.object({
58
+ conflicts: e.array(X),
59
+ activeClaims: e.array(X),
60
60
  // The caller's OWN active claims. `activeClaims` deliberately excludes the
61
61
  // caller's session, so without this an agent has no way to confirm its own
62
62
  // claim is live. Optional with a default so an older client talking to a
63
63
  // newer hub (or vice-versa) never fails validation on its absence.
64
- yourClaims: e.array(q).default([]),
65
- announcements: e.array(W),
64
+ yourClaims: e.array(X).default([]),
65
+ announcements: e.array(B),
66
66
  // Per-agent change records for the workspace. Defaulted for version-skew safety.
67
- changeRecords: e.array(Te).default([])
68
- }), Ce = e.object({
67
+ changeRecords: e.array(Ge).default([])
68
+ }), Ue = e.object({
69
69
  name: e.string(),
70
70
  human: e.string(),
71
71
  program: e.string(),
@@ -75,19 +75,19 @@ const A = e.string(), H = e.number(), Te = e.object({
75
75
  // are null when the agent has no session yet.
76
76
  repo: e.string().nullable(),
77
77
  branch: e.string().nullable(),
78
- lastHeartbeatAt: A.nullable(),
78
+ lastHeartbeatAt: C.nullable(),
79
79
  presence: e.enum(["live", "offline"])
80
- }), Re = e.enum(["active", "done", "dropped"]), Ee = e.object({
80
+ }), He = e.enum(["active", "done", "dropped"]), We = e.object({
81
81
  agentName: e.string(),
82
82
  program: e.string(),
83
83
  model: e.string().nullable(),
84
84
  repo: e.string(),
85
85
  intent: e.string(),
86
86
  pathGlobs: e.array(e.string()),
87
- status: Re,
88
- createdAt: A,
89
- endedAt: A.nullable()
90
- }), De = e.object({
87
+ status: He,
88
+ createdAt: C,
89
+ endedAt: C.nullable()
90
+ }), Fe = e.object({
91
91
  fromAgentName: e.string(),
92
92
  fromHuman: e.string(),
93
93
  body: e.string(),
@@ -101,14 +101,14 @@ const A = e.string(), H = e.number(), Te = e.object({
101
101
  // fromAdmin). The dashboard renders these as "<agent> → admin". Not delivered
102
102
  // to other agents. Defaulted for version-skew safety with older hubs.
103
103
  toAdmin: e.boolean().default(!1),
104
- createdAt: A
105
- }), te = e.object({
106
- agents: e.array(Ce),
107
- tasks: e.array(Ee),
108
- announcements: e.array(De),
104
+ createdAt: C
105
+ }), de = e.object({
106
+ agents: e.array(Ue),
107
+ tasks: e.array(We),
108
+ announcements: e.array(Fe),
109
109
  // The server's clock, so the client computes "expires in / last seen" against
110
110
  // the hub rather than the (possibly skewed) browser clock.
111
- serverTime: A
111
+ serverTime: C
112
112
  });
113
113
  e.object({
114
114
  body: e.string().min(1).max(8192),
@@ -120,11 +120,11 @@ e.object({
120
120
  // Ignored for a DM (the target's own repo is used).
121
121
  repo: e.string().min(1).nullable().optional()
122
122
  });
123
- const ne = e.object({
123
+ const ue = e.object({
124
124
  ok: e.literal(!0),
125
125
  // One id per inserted row: a single id for a DM or repo-scoped broadcast, or
126
126
  // several when an all-repos broadcast fans out across repos.
127
- announcementIds: e.array(H)
127
+ announcementIds: e.array(z)
128
128
  });
129
129
  e.object({
130
130
  workspace: e.string().min(1),
@@ -138,18 +138,18 @@ e.object({
138
138
  agentName: e.string(),
139
139
  sessionId: e.string().uuid()
140
140
  });
141
- const je = e.object({
141
+ const qe = e.object({
142
142
  sessionId: e.string().uuid(),
143
143
  intent: e.string().min(1).max(2048),
144
144
  pathGlobs: e.array(e.string().min(1).max(512)).min(1).max(64),
145
145
  ttlSeconds: e.number().int().positive().optional(),
146
- changeReport: Z.optional()
146
+ changeReport: se.optional()
147
147
  });
148
148
  e.object({
149
149
  workItemId: e.string().uuid(),
150
- landscape: ue
150
+ landscape: Ne
151
151
  });
152
- const Ie = e.object({
152
+ const Ke = e.object({
153
153
  sessionId: e.string().uuid(),
154
154
  workItemId: e.string().uuid()
155
155
  });
@@ -158,9 +158,9 @@ e.object({
158
158
  // Pending announcements for the caller, delivered as a side effect of done so
159
159
  // a message lands the moment a teammate finishes a unit of work (not only on
160
160
  // their next work/sync). Defaulted for version-skew safety with older hubs.
161
- announcements: e.array(W).default([])
161
+ announcements: e.array(B).default([])
162
162
  });
163
- const xe = e.object({
163
+ const ze = e.object({
164
164
  sessionId: e.string().uuid(),
165
165
  body: e.string().min(1).max(8192),
166
166
  // absent or null => broadcast to all agents in the workspace
@@ -175,22 +175,22 @@ const xe = e.object({
175
175
  e.object({
176
176
  ok: e.literal(!0),
177
177
  // bigint PK serialised as number; see DbId note above
178
- announcementId: H,
178
+ announcementId: z,
179
179
  // Pending announcements for the caller, delivered as a side effect of announce
180
180
  // (a turn where the agent is already reading hub output) so inbound messages
181
181
  // surface promptly. Excludes the just-sent one. Defaulted for version skew.
182
- announcements: e.array(W).default([])
182
+ announcements: e.array(B).default([])
183
183
  });
184
184
  e.object({
185
185
  sessionId: e.string().uuid(),
186
- changeReport: Z.optional()
186
+ changeReport: se.optional()
187
187
  });
188
188
  e.object({
189
- landscape: ue
189
+ landscape: Ne
190
190
  });
191
- je.omit({ sessionId: !0, changeReport: !0 });
192
- xe.omit({ sessionId: !0 });
193
- Ie.omit({ sessionId: !0 });
191
+ qe.omit({ sessionId: !0, changeReport: !0 });
192
+ ze.omit({ sessionId: !0 });
193
+ Ke.omit({ sessionId: !0 });
194
194
  e.object({});
195
195
  e.object({});
196
196
  e.object({
@@ -199,7 +199,7 @@ e.object({
199
199
  // change records fresh (commits surface within ~one heartbeat interval, not
200
200
  // only when it next calls work/sync). Processed presence-style: it refreshes
201
201
  // change records but, like the rest of heartbeat, does NOT renew claim TTLs.
202
- changeReport: Z.optional(),
202
+ changeReport: se.optional(),
203
203
  // Opt-in: when set, the heartbeat returns any pending announcements for the
204
204
  // caller in the response. Delivery is now TWO-PHASE and crash-safe: this fetch
205
205
  // phase does NOT mark them delivered — the client persists them to its
@@ -215,14 +215,14 @@ e.object({
215
215
  // guarantees a message is never recorded delivered before the client holds it
216
216
  // (a lost response or a failed local append simply leaves it pending for the
217
217
  // next beat). Absent on a plain presence/fetch beat.
218
- ackAnnouncementIds: e.array(H).optional()
218
+ ackAnnouncementIds: e.array(z).optional()
219
219
  });
220
220
  e.object({
221
221
  ok: e.literal(!0),
222
222
  // Pending announcements for the caller, delivered only when the request set
223
223
  // `deliverAnnouncements`. Defaulted to [] for version-skew safety with older
224
224
  // hubs (which return just { ok: true }).
225
- announcements: e.array(W).default([])
225
+ announcements: e.array(B).default([])
226
226
  });
227
227
  e.object({
228
228
  sessionId: e.string().uuid()
@@ -230,58 +230,58 @@ e.object({
230
230
  e.object({
231
231
  ok: e.literal(!0)
232
232
  });
233
- const me = e.enum(["admin", "member"]), J = e.object({
233
+ const ke = e.enum(["admin", "member"]), ae = e.object({
234
234
  id: e.string(),
235
235
  slug: e.string(),
236
236
  name: e.string(),
237
- role: me
237
+ role: ke
238
238
  });
239
239
  e.object({
240
240
  name: e.string().min(1)
241
241
  });
242
- const Me = J, Le = e.object({
243
- workspaces: e.array(J)
242
+ const Be = ae, Ye = e.object({
243
+ workspaces: e.array(ae)
244
244
  });
245
245
  e.object({
246
246
  name: e.string().min(1).optional()
247
247
  });
248
- const Pe = e.object({
248
+ const Ve = e.object({
249
249
  // The raw shp_ token, shown once at creation and never returned again.
250
250
  token: e.string(),
251
251
  id: e.string()
252
- }), Oe = e.object({
252
+ }), Xe = e.object({
253
253
  id: e.string(),
254
254
  name: e.string().nullable(),
255
255
  // ISO timestamp string (see IsoTimestamp note above) or null when unused / not revoked.
256
- lastUsedAt: A.nullable(),
257
- createdAt: A,
258
- revokedAt: A.nullable()
259
- }), Ge = e.object({
260
- tokens: e.array(Oe)
256
+ lastUsedAt: C.nullable(),
257
+ createdAt: C,
258
+ revokedAt: C.nullable()
259
+ }), Ze = e.object({
260
+ tokens: e.array(Xe)
261
261
  });
262
262
  e.object({
263
263
  expiresInDays: e.number().int().positive().optional(),
264
264
  maxUses: e.number().int().positive().optional()
265
265
  });
266
- const Ue = e.object({
266
+ const Je = e.object({
267
267
  code: e.string(),
268
268
  // ISO timestamp string, or null when the invite never expires.
269
- expiresAt: A.nullable(),
269
+ expiresAt: C.nullable(),
270
270
  maxUses: e.number().int().positive(),
271
271
  useCount: e.number().int().nonnegative()
272
- }), He = e.object({
272
+ }), Qe = e.object({
273
273
  // The workspace the caller just joined.
274
- workspace: J
275
- }), We = e.object({
274
+ workspace: ae
275
+ }), et = e.object({
276
276
  accountId: e.string(),
277
277
  displayName: e.string().nullable(),
278
278
  githubLogin: e.string().nullable(),
279
279
  avatarUrl: e.string().nullable(),
280
- role: me
281
- }), Fe = e.object({
282
- members: e.array(We)
283
- }), qe = 5e3;
284
- class P extends Error {
280
+ role: ke
281
+ }), tt = e.object({
282
+ members: e.array(et)
283
+ }), nt = 5e3;
284
+ class H extends Error {
285
285
  /**
286
286
  * @param message - Human-readable failure description.
287
287
  * @param status - Upstream HTTP status, omitted for network/abort failures.
@@ -289,50 +289,50 @@ class P extends Error {
289
289
  constructor(i, r) {
290
290
  super(i);
291
291
  /** Upstream HTTP status for a non-2xx response; absent for transport errors. */
292
- ee(this, "status");
292
+ le(this, "status");
293
293
  this.name = "ShepherdClientError", r !== void 0 && (this.status = r);
294
294
  }
295
295
  }
296
- function wt(n) {
297
- return n instanceof Error ? n.message : "Something went wrong.";
296
+ function Lt(t) {
297
+ return t instanceof Error ? t.message : "Something went wrong.";
298
298
  }
299
- async function ze(n) {
299
+ async function st(t) {
300
300
  try {
301
- const t = await n.json();
302
- if (t !== null && typeof t == "object" && "error" in t && typeof t.error == "string")
303
- return t.error;
301
+ const n = await t.json();
302
+ if (n !== null && typeof n == "object" && "error" in n && typeof n.error == "string")
303
+ return n.error;
304
304
  } catch {
305
305
  }
306
306
  return "";
307
307
  }
308
- function At(n) {
309
- const t = n.baseUrl.replace(/\/$/, ""), i = n.timeoutMs ?? qe, r = encodeURIComponent;
308
+ function Mt(t) {
309
+ const n = t.baseUrl.replace(/\/$/, ""), i = t.timeoutMs ?? nt, r = encodeURIComponent;
310
310
  async function a(s, l, c = {}) {
311
- var v, N;
311
+ var b, N;
312
312
  const p = new AbortController(), u = setTimeout(() => p.abort(), i);
313
313
  let d;
314
314
  try {
315
- const y = {
315
+ const v = {
316
316
  "Content-Type": "application/json"
317
- }, f = await ((v = n.getAuthHeader) == null ? void 0 : v.call(n)), $ = {
317
+ }, S = await ((b = t.getAuthHeader) == null ? void 0 : b.call(t)), w = {
318
318
  method: s,
319
- headers: { ...y, ...typeof f == "string" ? { Authorization: f } : f ?? {} },
319
+ headers: { ...v, ...typeof S == "string" ? { Authorization: S } : S ?? {} },
320
320
  signal: p.signal
321
321
  };
322
- c.body !== void 0 && ($.body = JSON.stringify(c.body)), d = await fetch(`${t}${l}`, $);
323
- } catch (y) {
324
- throw new P(
325
- y instanceof Error ? y.message : String(y)
322
+ c.body !== void 0 && (w.body = JSON.stringify(c.body)), d = await fetch(`${n}${l}`, w);
323
+ } catch (v) {
324
+ throw new H(
325
+ v instanceof Error ? v.message : String(v)
326
326
  );
327
327
  } finally {
328
328
  clearTimeout(u);
329
329
  }
330
330
  if (d.status === 401)
331
- throw (N = n.onUnauthorized) == null || N.call(n), new P("Unauthorized", 401);
331
+ throw (N = t.onUnauthorized) == null || N.call(t), new H("Unauthorized", 401);
332
332
  if (!d.ok) {
333
- const y = await ze(d);
334
- throw new P(
335
- y !== "" ? `HTTP ${d.status}: ${y}` : `HTTP ${d.status}`,
333
+ const v = await st(d);
334
+ throw new H(
335
+ v !== "" ? `HTTP ${d.status}: ${v}` : `HTTP ${d.status}`,
336
336
  d.status
337
337
  );
338
338
  }
@@ -343,34 +343,34 @@ function At(n) {
343
343
  }
344
344
  return;
345
345
  }
346
- const b = c.schema.safeParse(await d.json());
347
- if (!b.success)
348
- throw new P("Invalid response schema");
349
- return b.data;
346
+ const f = c.schema.safeParse(await d.json());
347
+ if (!f.success)
348
+ throw new H("Invalid response schema");
349
+ return f.data;
350
350
  }
351
351
  return {
352
- baseUrl: t,
352
+ baseUrl: n,
353
353
  // --- multi-workspace management surface ---------------------------------
354
354
  listWorkspaces() {
355
355
  return a("GET", "/workspaces", {
356
- schema: Le
356
+ schema: Ye
357
357
  });
358
358
  },
359
359
  createWorkspace(s) {
360
360
  return a("POST", "/workspaces", {
361
361
  body: s,
362
- schema: Me
362
+ schema: Be
363
363
  });
364
364
  },
365
365
  mintToken(s, l) {
366
366
  return a("POST", `/workspaces/${r(s)}/tokens`, {
367
367
  body: l,
368
- schema: Pe
368
+ schema: Ve
369
369
  });
370
370
  },
371
371
  listTokens(s) {
372
372
  return a("GET", `/workspaces/${r(s)}/tokens`, {
373
- schema: Ge
373
+ schema: Ze
374
374
  });
375
375
  },
376
376
  revokeToken(s, l) {
@@ -382,7 +382,7 @@ function At(n) {
382
382
  createInvite(s, l) {
383
383
  return a("POST", `/workspaces/${r(s)}/invites`, {
384
384
  body: l,
385
- schema: Ue
385
+ schema: Je
386
386
  });
387
387
  },
388
388
  revokeInvite(s, l) {
@@ -393,12 +393,12 @@ function At(n) {
393
393
  },
394
394
  redeemInvite(s) {
395
395
  return a("POST", `/invites/${r(s)}/redeem`, {
396
- schema: He
396
+ schema: Qe
397
397
  });
398
398
  },
399
399
  listMembers(s) {
400
400
  return a("GET", `/workspaces/${r(s)}/members`, {
401
- schema: Fe
401
+ schema: tt
402
402
  });
403
403
  },
404
404
  removeMember(s, l) {
@@ -412,82 +412,83 @@ function At(n) {
412
412
  },
413
413
  landscape(s) {
414
414
  return a("GET", `/workspaces/${r(s)}/landscape`, {
415
- schema: te
415
+ schema: de
416
416
  });
417
417
  },
418
418
  announceTo(s, l) {
419
419
  return a("POST", `/workspaces/${r(s)}/announce`, {
420
420
  body: l,
421
- schema: ne
421
+ schema: ue
422
422
  });
423
423
  },
424
424
  // --- self-host singular aliases (implicit single workspace) -------------
425
425
  getLandscape() {
426
426
  return a("GET", "/workspace/landscape", {
427
- schema: te
427
+ schema: de
428
428
  });
429
429
  },
430
430
  announce(s) {
431
431
  return a("POST", "/workspace/announce", {
432
432
  body: s,
433
- schema: ne
433
+ schema: ue
434
434
  });
435
435
  }
436
436
  };
437
437
  }
438
- const he = ke(null);
439
- function St({
440
- client: n,
441
- children: t
438
+ const we = Ie(null);
439
+ function Pt({
440
+ client: t,
441
+ children: n
442
442
  }) {
443
- return /* @__PURE__ */ o(he.Provider, { value: n, children: t });
443
+ return /* @__PURE__ */ o(we.Provider, { value: t, children: n });
444
444
  }
445
- function pe() {
446
- const n = we(he);
447
- if (n === null)
445
+ function Ae() {
446
+ const t = xe(we);
447
+ if (t === null)
448
448
  throw new Error(
449
449
  "useShepherdClient must be used within <ShepherdClientProvider>"
450
450
  );
451
- return n;
451
+ return t;
452
452
  }
453
- const Ke = 5e3, Be = 1e3;
454
- function Ye(n) {
455
- const t = pe(), i = n == null ? void 0 : n.workspaceId, r = (n == null ? void 0 : n.pollMs) ?? Ke, [a, s] = k(
453
+ const at = 5e3, rt = 1e3;
454
+ function ot(t) {
455
+ const n = Ae(), i = t == null ? void 0 : t.workspaceId, r = (t == null ? void 0 : t.pollMs) ?? at, a = (t == null ? void 0 : t.enabled) ?? !0, [s, l] = A(
456
456
  null
457
- ), [l, c] = k("live"), [p, u] = k(null), [, d] = k(0), b = x(t);
458
- b.current = t;
459
- const v = x(0), N = S(
460
- async (f) => {
457
+ ), [c, p] = A("live"), [u, d] = A(null), [, f] = A(0), b = P(n);
458
+ b.current = n;
459
+ const N = P(0), v = R(
460
+ async (E) => {
461
461
  try {
462
462
  const w = i ? await b.current.landscape(i) : await b.current.getLandscape();
463
- if (f !== v.current) return;
464
- s(w), u(Date.now()), c("live");
463
+ if (E !== N.current) return;
464
+ l(w), d(Date.now()), p("live");
465
465
  } catch (w) {
466
- if (f !== v.current) return;
467
- w instanceof P && w.status === 401 ? c("unauthorized") : c("reconnecting");
466
+ if (E !== N.current) return;
467
+ w instanceof H && w.status === 401 ? p("unauthorized") : p("reconnecting");
468
468
  }
469
469
  },
470
470
  [i]
471
471
  );
472
- X(() => {
473
- const f = ++v.current;
474
- N(f);
472
+ ne(() => {
473
+ if (!a) return;
474
+ const E = ++N.current;
475
+ v(E);
475
476
  const w = setInterval(() => {
476
- document.visibilityState !== "hidden" && N(f);
477
- }, r), $ = setInterval(() => {
478
- d((R) => R + 1);
479
- }, Be), C = () => {
480
- document.visibilityState === "visible" && N(f);
477
+ document.visibilityState !== "hidden" && v(E);
478
+ }, r), I = setInterval(() => {
479
+ f(($) => $ + 1);
480
+ }, rt), T = () => {
481
+ document.visibilityState === "visible" && v(E);
481
482
  };
482
- return document.addEventListener("visibilitychange", C), () => {
483
- v.current++, clearInterval(w), clearInterval($), document.removeEventListener("visibilitychange", C);
483
+ return document.addEventListener("visibilitychange", T), () => {
484
+ N.current++, clearInterval(w), clearInterval(I), document.removeEventListener("visibilitychange", T);
484
485
  };
485
- }, [N, r]);
486
- const y = S(() => N(v.current), [N]);
487
- return { snapshot: a, status: l, lastUpdatedMs: p, refresh: y };
486
+ }, [v, r, a]);
487
+ const S = R(() => v(N.current), [v]);
488
+ return { snapshot: s, status: c, lastUpdatedMs: u, refresh: S };
488
489
  }
489
- function G(n, t) {
490
- const i = Math.floor((t - Date.parse(n)) / 1e3);
490
+ function q(t, n) {
491
+ const i = Math.floor((n - Date.parse(t)) / 1e3);
491
492
  if (i < 5) return "just now";
492
493
  if (i < 60) return `${i}s ago`;
493
494
  const r = Math.floor(i / 60);
@@ -495,66 +496,66 @@ function G(n, t) {
495
496
  const a = Math.floor(r / 60);
496
497
  return a < 24 ? `${a}h ago` : `${Math.floor(a / 24)}d ago`;
497
498
  }
498
- function U(n) {
499
- let t = 0;
500
- for (let i = 0; i < n.length; i++) t = (t * 31 + n.charCodeAt(i)) % 360;
501
- return `hsl(${t}, 38%, 42%)`;
499
+ function K(t) {
500
+ let n = 0;
501
+ for (let i = 0; i < t.length; i++) n = (n * 31 + t.charCodeAt(i)) % 360;
502
+ return `hsl(${n}, 38%, 42%)`;
502
503
  }
503
- function Q(n) {
504
- if (!n) return "?";
505
- const t = n.match(/[A-Z]/g);
506
- return t && t.length >= 2 ? t[0] + t[1] : n.slice(0, 2).toUpperCase();
504
+ function re(t) {
505
+ if (!t) return "?";
506
+ const n = t.match(/[A-Z]/g);
507
+ return n && n.length >= 2 ? n[0] + n[1] : t.slice(0, 2).toUpperCase();
507
508
  }
508
- const ge = "A-Za-z0-9_-";
509
- function Ve(n, t) {
510
- const r = n.slice(0, t).match(new RegExp(`(?:^|\\s)@([${ge}]*)$`));
509
+ const Se = "A-Za-z0-9_-";
510
+ function it(t, n) {
511
+ const r = t.slice(0, n).match(new RegExp(`(?:^|\\s)@([${Se}]*)$`));
511
512
  if (!r) return null;
512
513
  const a = r[1];
513
- return { start: t - a.length - 1, end: t, query: a };
514
+ return { start: n - a.length - 1, end: n, query: a };
514
515
  }
515
- function Xe(n, t) {
516
- const i = new RegExp(`(?:^|\\s)@([${ge}]+)`, "g");
516
+ function ct(t, n) {
517
+ const i = new RegExp(`(?:^|\\s)@([${Se}]+)`, "g");
517
518
  let r;
518
- for (; (r = i.exec(n)) !== null; ) {
519
- const a = r[1].toLowerCase(), s = t.find((l) => l.toLowerCase() === a);
519
+ for (; (r = i.exec(t)) !== null; ) {
520
+ const a = r[1].toLowerCase(), s = n.find((l) => l.toLowerCase() === a);
520
521
  if (s) return s;
521
522
  }
522
523
  return null;
523
524
  }
524
- function fe(n) {
525
- return [...new Set(n.map((t) => t.repo))].sort();
525
+ function Te(t) {
526
+ return [...new Set(t.map((n) => n.repo))].sort();
526
527
  }
527
- function D(n, t) {
528
- return t === null || t === "__all__" || n.repo === t;
528
+ function L(t, n) {
529
+ return n === null || n === "__all__" || t.repo === n;
529
530
  }
530
- function Ze(n, t) {
531
+ function lt(t, n) {
531
532
  return [
532
533
  ...new Set(
533
- n.filter((i) => i.presence === "live" && D(i, t)).map((i) => i.name)
534
+ t.filter((i) => i.presence === "live" && L(i, n)).map((i) => i.name)
534
535
  )
535
536
  ].sort();
536
537
  }
537
- function se(n) {
538
- const t = n.find((i) => i.status === "active");
539
- return t ? t.repo : n.length ? n[0].repo : null;
538
+ function me(t) {
539
+ const n = t.find((i) => i.status === "active");
540
+ return n ? n.repo : t.length ? t[0].repo : null;
540
541
  }
541
- function Je(n) {
542
- return n === "dropped" ? "dropped" : "done";
542
+ function dt(t) {
543
+ return t === "dropped" ? "dropped" : "done";
543
544
  }
544
- function ae(n, t) {
545
- if (!t) return "";
546
- const i = Math.floor((Date.parse(t) - Date.parse(n)) / 1e3), r = Math.floor(i / 60);
545
+ function he(t, n) {
546
+ if (!n) return "";
547
+ const i = Math.floor((Date.parse(n) - Date.parse(t)) / 1e3), r = Math.floor(i / 60);
547
548
  return r < 60 ? `active ${r}m` : `active ${Math.floor(r / 60)}h`;
548
549
  }
549
- function Qe(n, t) {
550
- const i = new Date(Date.parse(n)), r = new Date(t), a = (l) => new Date(l.getFullYear(), l.getMonth(), l.getDate()).getTime(), s = Math.round((a(r) - a(i)) / 864e5);
550
+ function ut(t, n) {
551
+ const i = new Date(Date.parse(t)), r = new Date(n), a = (l) => new Date(l.getFullYear(), l.getMonth(), l.getDate()).getTime(), s = Math.round((a(r) - a(i)) / 864e5);
551
552
  return s <= 0 ? "Today" : s === 1 ? "Yesterday" : i.toLocaleDateString(void 0, { month: "short", day: "numeric" });
552
553
  }
553
- function re(n) {
554
- let t = n.toLowerCase().replace(/\\/g, "/");
555
- t.endsWith("/") && (t = t.replace(/\/+$/, "") + "/**");
554
+ function pe(t) {
555
+ let n = t.toLowerCase().replace(/\\/g, "/");
556
+ n.endsWith("/") && (n = n.replace(/\/+$/, "") + "/**");
556
557
  const i = [];
557
- for (const r of t.split("/"))
558
+ for (const r of n.split("/"))
558
559
  if (!(r === "" || r === ".")) {
559
560
  if (r === "..") {
560
561
  i.length && i.pop();
@@ -564,43 +565,43 @@ function re(n) {
564
565
  }
565
566
  return i;
566
567
  }
567
- const oe = /[*?{}[\]]/;
568
- function et(n, t) {
569
- return n === "*" ? !0 : (oe.test(n) || !oe.test(t)) && n === t;
568
+ const ge = /[*?{}[\]]/;
569
+ function mt(t, n) {
570
+ return t === "*" ? !0 : (ge.test(t) || !ge.test(n)) && t === n;
570
571
  }
571
- function tt(n, t) {
572
+ function ht(t, n) {
572
573
  const i = /* @__PURE__ */ new Map();
573
574
  function r(a, s) {
574
- if (t.length - s === 0) {
575
- for (let b = a; b < n.length; b++) if (n[b] !== "**") return !1;
575
+ if (n.length - s === 0) {
576
+ for (let f = a; f < t.length; f++) if (t[f] !== "**") return !1;
576
577
  return !0;
577
578
  }
578
- if (n.length - a === 0) return !1;
579
- const l = a * (t.length + 1) + s, c = i.get(l);
579
+ if (t.length - a === 0) return !1;
580
+ const l = a * (n.length + 1) + s, c = i.get(l);
580
581
  if (c !== void 0) return c;
581
- const p = n[a], u = t[s];
582
+ const p = t[a], u = n[s];
582
583
  let d;
583
- return p === "**" ? d = r(a + 1, s) || r(a, s + 1) : u === "**" ? d = !1 : d = et(p, u) && r(a + 1, s + 1), i.set(l, d), d;
584
+ return p === "**" ? d = r(a + 1, s) || r(a, s + 1) : u === "**" ? d = !1 : d = mt(p, u) && r(a + 1, s + 1), i.set(l, d), d;
584
585
  }
585
586
  return r(0, 0);
586
587
  }
587
- function ie(n, t) {
588
- if (t.length === 0) return !0;
589
- const i = n.map(re);
590
- return t.every((r) => {
591
- const a = re(r);
592
- return i.some((s) => tt(s, a));
588
+ function fe(t, n) {
589
+ if (n.length === 0) return !0;
590
+ const i = t.map(pe);
591
+ return n.every((r) => {
592
+ const a = pe(r);
593
+ return i.some((s) => ht(s, a));
593
594
  });
594
595
  }
595
- function nt(n) {
596
- const t = /* @__PURE__ */ new Map();
597
- for (const a of n)
598
- t.has(a.agentName) || t.set(a.agentName, []), t.get(a.agentName).push(a);
596
+ function pt(t) {
597
+ const n = /* @__PURE__ */ new Map();
598
+ for (const a of t)
599
+ n.has(a.agentName) || n.set(a.agentName, []), n.get(a.agentName).push(a);
599
600
  const i = (a, s) => s.createdAt.localeCompare(a.createdAt), r = [];
600
- for (const [a, s] of t) {
601
+ for (const [a, s] of n) {
601
602
  const l = [...s].sort(i), c = l.map(
602
603
  (u) => l.some(
603
- (d) => d !== u && ie(d.pathGlobs, u.pathGlobs) && !ie(u.pathGlobs, d.pathGlobs)
604
+ (d) => d !== u && fe(d.pathGlobs, u.pathGlobs) && !fe(u.pathGlobs, d.pathGlobs)
604
605
  )
605
606
  ), p = l[0];
606
607
  r.push({
@@ -617,37 +618,37 @@ function nt(n) {
617
618
  return s.primaries.concat(s.narrower)[0].createdAt.localeCompare(l);
618
619
  }), r;
619
620
  }
620
- const ce = { active: 0, done: 0 };
621
- function st({
622
- repos: n,
623
- counts: t,
621
+ const be = { active: 0, done: 0 };
622
+ function gt({
623
+ repos: t,
624
+ counts: n,
624
625
  selected: i,
625
626
  onSelect: r
626
627
  }) {
627
- const [a, s] = k(!1), l = x(null);
628
- if (X(() => {
629
- var v;
628
+ const [a, s] = A(!1), l = P(null);
629
+ if (ne(() => {
630
+ var b;
630
631
  if (!a) return;
631
- const d = (v = l.current) == null ? void 0 : v.querySelector(".repo-menu");
632
+ const d = (b = l.current) == null ? void 0 : b.querySelector(".repo-menu");
632
633
  if (!d) return;
633
- const b = d.querySelector('[aria-selected="true"]') ?? d.querySelector("button");
634
- b == null || b.focus();
635
- }, [a]), n.length < 2) return null;
636
- const c = i === null || i === "__all__", p = c ? "All repos" : i, u = (d, b) => {
637
- const v = d === null ? t.__all__ ?? ce : t[d] ?? ce, N = d === null ? c : i === d, y = "repo-mi" + (N ? " on" : "") + (d === null ? " all" : "");
634
+ const f = d.querySelector('[aria-selected="true"]') ?? d.querySelector("button");
635
+ f == null || f.focus();
636
+ }, [a]), t.length < 2) return null;
637
+ const c = i === null || i === "__all__", p = c ? "All repos" : i, u = (d, f) => {
638
+ const b = d === null ? n.__all__ ?? be : n[d] ?? be, N = d === null ? c : i === d, v = "repo-mi" + (N ? " on" : "") + (d === null ? " all" : "");
638
639
  return /* @__PURE__ */ m(
639
640
  "button",
640
641
  {
641
642
  type: "button",
642
- className: y,
643
+ className: v,
643
644
  role: "option",
644
645
  "aria-selected": N,
645
- onClick: (f) => {
646
- f.stopPropagation(), s(!1), r(d);
646
+ onClick: (S) => {
647
+ S.stopPropagation(), s(!1), r(d);
647
648
  },
648
649
  children: [
649
- /* @__PURE__ */ o("span", { children: b }),
650
- /* @__PURE__ */ o("span", { className: "ct", children: `${v.active} active · ${v.done} done` })
650
+ /* @__PURE__ */ o("span", { children: f }),
651
+ /* @__PURE__ */ o("span", { className: "ct", children: `${b.active} active · ${b.done} done` })
651
652
  ]
652
653
  },
653
654
  d ?? "__all__"
@@ -671,7 +672,7 @@ function st({
671
672
  "aria-expanded": a,
672
673
  "aria-label": `Filter by repo (current: ${p})`,
673
674
  onClick: (d) => {
674
- d.stopPropagation(), s((b) => !b);
675
+ d.stopPropagation(), s((f) => !f);
675
676
  },
676
677
  children: [
677
678
  /* @__PURE__ */ o("span", { className: "slash", children: "/" }),
@@ -681,18 +682,18 @@ function st({
681
682
  }
682
683
  ),
683
684
  a && /* @__PURE__ */ m("div", { className: "repo-menu", role: "listbox", children: [
684
- n.map((d) => u(d, d)),
685
+ t.map((d) => u(d, d)),
685
686
  u(null, "All repos")
686
687
  ] })
687
688
  ]
688
689
  }
689
690
  );
690
691
  }
691
- function at({ agents: n, tasks: t, selectedRepo: i }) {
692
- const r = n.filter(
693
- (c) => c.presence === "live" && D({ repo: c.repo ?? "" }, i)
692
+ function ft({ agents: t, tasks: n, selectedRepo: i }) {
693
+ const r = t.filter(
694
+ (c) => c.presence === "live" && L({ repo: c.repo ?? "" }, i)
694
695
  ), a = /* @__PURE__ */ new Set();
695
- for (const c of t) c.status === "active" && a.add(c.agentName);
696
+ for (const c of n) c.status === "active" && a.add(c.agentName);
696
697
  const s = (c) => a.has(c.name), l = [...r].sort((c, p) => {
697
698
  const u = s(c), d = s(p);
698
699
  return u !== d ? u ? -1 : 1 : c.name.localeCompare(p.name);
@@ -702,117 +703,117 @@ function at({ agents: n, tasks: t, selectedRepo: i }) {
702
703
  {
703
704
  className: "person" + (s(c) ? "" : " person--idle"),
704
705
  children: [
705
- /* @__PURE__ */ o("div", { className: "avatar", style: { background: U(c.name) }, children: Q(c.name) }),
706
+ /* @__PURE__ */ o("div", { className: "avatar", style: { background: K(c.name) }, children: re(c.name) }),
706
707
  /* @__PURE__ */ o("span", { className: "person__name", children: c.name })
707
708
  ]
708
709
  },
709
710
  c.name
710
711
  )) });
711
712
  }
712
- function be({ globs: n }) {
713
- return n.length <= 1 ? /* @__PURE__ */ m("div", { className: "terr", children: [
713
+ function Ce({ globs: t }) {
714
+ return t.length <= 1 ? /* @__PURE__ */ m("div", { className: "terr", children: [
714
715
  /* @__PURE__ */ o("span", { className: "terr__lbl", children: "territory" }),
715
- n.map((t) => /* @__PURE__ */ o("span", { className: "glob", children: t }, t))
716
+ t.map((n) => /* @__PURE__ */ o("span", { className: "glob", children: n }, n))
716
717
  ] }) : /* @__PURE__ */ m("details", { className: "terrx", children: [
717
718
  /* @__PURE__ */ m("summary", { children: [
718
719
  /* @__PURE__ */ o("span", { className: "terr__lbl", children: "territory" }),
719
720
  /* @__PURE__ */ m("span", { className: "glob glob--more", children: [
720
721
  /* @__PURE__ */ o("span", { className: "tw", children: "▶" }),
721
- ` ${n.length} paths`
722
+ ` ${t.length} paths`
722
723
  ] })
723
724
  ] }),
724
- /* @__PURE__ */ o("div", { className: "terr terr--full", children: n.map((t) => /* @__PURE__ */ o("span", { className: "glob", children: t }, t)) })
725
+ /* @__PURE__ */ o("div", { className: "terr terr--full", children: t.map((n) => /* @__PURE__ */ o("span", { className: "glob", children: n }, n)) })
725
726
  ] });
726
727
  }
727
- const Y = (n) => `${n.agentName}|${n.repo}|${n.createdAt}`, rt = (n) => n === null || n === "__all__";
728
- function V({
729
- task: n,
730
- nowMs: t
728
+ const ee = (t) => `${t.agentName}|${t.repo}|${t.createdAt}`, bt = (t) => t === null || t === "__all__";
729
+ function te({
730
+ task: t,
731
+ nowMs: n
731
732
  }) {
732
- return /* @__PURE__ */ m(ye, { children: [
733
- /* @__PURE__ */ o("div", { className: "task__intent", children: n.intent }),
734
- /* @__PURE__ */ o(be, { globs: n.pathGlobs }),
735
- /* @__PURE__ */ o("div", { className: "task__meta", children: `started ${G(n.createdAt, t)}` })
733
+ return /* @__PURE__ */ m(F, { children: [
734
+ /* @__PURE__ */ o("div", { className: "task__intent", children: t.intent }),
735
+ /* @__PURE__ */ o(Ce, { globs: t.pathGlobs }),
736
+ /* @__PURE__ */ o("div", { className: "task__meta", children: `started ${q(t.createdAt, n)}` })
736
737
  ] });
737
738
  }
738
- function ot({
739
- task: n,
740
- nowMs: t,
739
+ function vt({
740
+ task: t,
741
+ nowMs: n,
741
742
  allRepos: i
742
743
  }) {
743
- const r = n.model || n.program;
744
+ const r = t.model || t.program;
744
745
  return /* @__PURE__ */ m("div", { className: "task", children: [
745
746
  /* @__PURE__ */ m("div", { className: "task__r1", children: [
746
- /* @__PURE__ */ o("span", { className: "task__who", children: n.agentName }),
747
- i && /* @__PURE__ */ o("span", { className: "task__repo", children: n.repo }),
747
+ /* @__PURE__ */ o("span", { className: "task__who", children: t.agentName }),
748
+ i && /* @__PURE__ */ o("span", { className: "task__repo", children: t.repo }),
748
749
  r && /* @__PURE__ */ o("span", { className: "task__tag", children: r }),
749
750
  /* @__PURE__ */ o("span", { className: "livedot", title: "active" })
750
751
  ] }),
751
- /* @__PURE__ */ o(V, { task: n, nowMs: t })
752
+ /* @__PURE__ */ o(te, { task: t, nowMs: n })
752
753
  ] });
753
754
  }
754
- function it({
755
- group: n,
756
- nowMs: t,
755
+ function _t({
756
+ group: t,
757
+ nowMs: n,
757
758
  allRepos: i
758
759
  }) {
759
- const r = n.model || n.program, a = n.primaries.length + n.narrower.length, s = n.narrower.length;
760
+ const r = t.model || t.program, a = t.primaries.length + t.narrower.length, s = t.narrower.length;
760
761
  return /* @__PURE__ */ m("div", { className: "grp", children: [
761
762
  /* @__PURE__ */ m("div", { className: "grp__head", children: [
762
- /* @__PURE__ */ o("span", { className: "grp__who", children: n.agentName }),
763
- i && /* @__PURE__ */ o("span", { className: "task__repo", children: n.repo }),
763
+ /* @__PURE__ */ o("span", { className: "grp__who", children: t.agentName }),
764
+ i && /* @__PURE__ */ o("span", { className: "task__repo", children: t.repo }),
764
765
  r && /* @__PURE__ */ o("span", { className: "grp__tag", children: r }),
765
766
  /* @__PURE__ */ o("span", { className: "grp__count", children: `· ${a} active` }),
766
767
  /* @__PURE__ */ o("span", { className: "grp__dot", title: "live" })
767
768
  ] }),
768
- /* @__PURE__ */ o("div", { className: "claims", children: n.primaries.map((l) => /* @__PURE__ */ o("div", { className: "claim", children: /* @__PURE__ */ o(V, { task: l, nowMs: t }) }, Y(l))) }),
769
+ /* @__PURE__ */ o("div", { className: "claims", children: t.primaries.map((l) => /* @__PURE__ */ o("div", { className: "claim", children: /* @__PURE__ */ o(te, { task: l, nowMs: n }) }, ee(l))) }),
769
770
  s > 0 && /* @__PURE__ */ m("details", { className: "fold", children: [
770
771
  /* @__PURE__ */ m("summary", { children: [
771
772
  /* @__PURE__ */ o("span", { className: "tw", children: "▶" }),
772
773
  ` +${s} narrower claim${s > 1 ? "s" : ""}`
773
774
  ] }),
774
- /* @__PURE__ */ o("div", { className: "fold__body", children: n.narrower.map((l) => /* @__PURE__ */ m("div", { className: "claim", children: [
775
- /* @__PURE__ */ o(V, { task: l, nowMs: t }),
775
+ /* @__PURE__ */ o("div", { className: "fold__body", children: t.narrower.map((l) => /* @__PURE__ */ m("div", { className: "claim", children: [
776
+ /* @__PURE__ */ o(te, { task: l, nowMs: n }),
776
777
  /* @__PURE__ */ o("div", { className: "covered", children: "⊂ covered by a claim above" })
777
- ] }, Y(l))) })
778
+ ] }, ee(l))) })
778
779
  ] })
779
780
  ] });
780
781
  }
781
- function ct({
782
- tasks: n,
783
- nowMs: t,
782
+ function yt({
783
+ tasks: t,
784
+ nowMs: n,
784
785
  selectedRepo: i
785
786
  }) {
786
- const r = rt(i), a = n.filter(
787
- (s) => s.status === "active" && D(s, i)
787
+ const r = bt(i), a = t.filter(
788
+ (s) => s.status === "active" && L(s, i)
788
789
  );
789
790
  if (a.length === 0) {
790
791
  const s = r ? "Nothing active right now." : `Nothing active in ${i}.`;
791
792
  return /* @__PURE__ */ o("div", { id: "active-list", children: /* @__PURE__ */ o("div", { className: "empty", children: s }) });
792
793
  }
793
- return /* @__PURE__ */ o("div", { id: "active-list", children: nt(a).map((s) => {
794
- const l = s.primaries.length === 1 && s.narrower.length === 0, c = Y(s.primaries.concat(s.narrower)[0]);
794
+ return /* @__PURE__ */ o("div", { id: "active-list", children: pt(a).map((s) => {
795
+ const l = s.primaries.length === 1 && s.narrower.length === 0, c = ee(s.primaries.concat(s.narrower)[0]);
795
796
  return l ? /* @__PURE__ */ o(
796
- ot,
797
+ vt,
797
798
  {
798
799
  task: s.primaries[0],
799
- nowMs: t,
800
+ nowMs: n,
800
801
  allRepos: r
801
802
  },
802
803
  c
803
- ) : /* @__PURE__ */ o(it, { group: s, nowMs: t, allRepos: r }, c);
804
+ ) : /* @__PURE__ */ o(_t, { group: s, nowMs: n, allRepos: r }, c);
804
805
  }) });
805
806
  }
806
- const lt = (n) => `${n.agentName}|${n.repo}|${n.createdAt}`, dt = (n) => n === null || n === "__all__";
807
- function ut({
808
- tasks: n,
809
- nowMs: t,
807
+ const Nt = (t) => `${t.agentName}|${t.repo}|${t.createdAt}`, kt = (t) => t === null || t === "__all__";
808
+ function wt({
809
+ tasks: t,
810
+ nowMs: n,
810
811
  selectedRepo: i,
811
812
  doneShown: r,
812
813
  onLoadMore: a
813
814
  }) {
814
- const s = dt(i), l = n.filter(
815
- (u) => u.status !== "active" && D(u, i)
815
+ const s = kt(i), l = t.filter(
816
+ (u) => u.status !== "active" && L(u, i)
816
817
  );
817
818
  if (l.length === 0) {
818
819
  const u = s ? "No finished tasks yet." : `No finished tasks in ${i} yet.`;
@@ -822,11 +823,11 @@ function ut({
822
823
  let p = null;
823
824
  return /* @__PURE__ */ m("div", { id: "done-list", children: [
824
825
  c.map((u) => {
825
- const d = Qe(u.endedAt ?? u.createdAt, t), b = d !== p ? d : null;
826
+ const d = ut(u.endedAt ?? u.createdAt, n), f = d !== p ? d : null;
826
827
  p = d;
827
- const v = u.status === "dropped", N = v ? `went offline ${G(u.endedAt ?? u.createdAt, t)} — no done signal` : `finished ${G(u.endedAt ?? u.createdAt, t)}${ae(u.createdAt, u.endedAt) ? " · " + ae(u.createdAt, u.endedAt) : ""}`;
828
- return /* @__PURE__ */ m(Ae, { children: [
829
- b !== null && /* @__PURE__ */ o("div", { className: "day", children: b }),
828
+ const b = u.status === "dropped", N = b ? `went offline ${q(u.endedAt ?? u.createdAt, n)} — no done signal` : `finished ${q(u.endedAt ?? u.createdAt, n)}${he(u.createdAt, u.endedAt) ? " · " + he(u.createdAt, u.endedAt) : ""}`;
829
+ return /* @__PURE__ */ m(Le, { children: [
830
+ f !== null && /* @__PURE__ */ o("div", { className: "day", children: f }),
830
831
  /* @__PURE__ */ m("div", { className: "task", children: [
831
832
  /* @__PURE__ */ m("div", { className: "task__r1", children: [
832
833
  /* @__PURE__ */ o("span", { className: "task__who", children: u.agentName }),
@@ -834,16 +835,16 @@ function ut({
834
835
  /* @__PURE__ */ o(
835
836
  "span",
836
837
  {
837
- className: "task__stat" + (v ? " task__stat--drop" : ""),
838
- children: Je(u.status)
838
+ className: "task__stat" + (b ? " task__stat--drop" : ""),
839
+ children: dt(u.status)
839
840
  }
840
841
  )
841
842
  ] }),
842
843
  /* @__PURE__ */ o("div", { className: "task__intent", children: u.intent }),
843
- /* @__PURE__ */ o(be, { globs: u.pathGlobs }),
844
+ /* @__PURE__ */ o(Ce, { globs: u.pathGlobs }),
844
845
  /* @__PURE__ */ o("div", { className: "task__meta", children: N })
845
846
  ] })
846
- ] }, lt(u));
847
+ ] }, Nt(u));
847
848
  }),
848
849
  l.length > r && /* @__PURE__ */ o(
849
850
  "div",
@@ -860,12 +861,12 @@ function ut({
860
861
  )
861
862
  ] });
862
863
  }
863
- const mt = 80;
864
- function ht({ announcements: n, selectedRepo: t, nowMs: i }) {
865
- const r = x(null), a = x(!0), s = r.current;
866
- s && (a.current = s.scrollHeight - s.scrollTop - s.clientHeight < mt);
867
- const l = [...n].filter((c) => D(c, t)).reverse();
868
- return Se(() => {
864
+ const At = 80;
865
+ function St({ announcements: t, selectedRepo: n, nowMs: i }) {
866
+ const r = P(null), a = P(!0), s = r.current;
867
+ s && (a.current = s.scrollHeight - s.scrollTop - s.clientHeight < At);
868
+ const l = [...t].filter((c) => L(c, n)).reverse();
869
+ return Me(() => {
869
870
  a.current && r.current && (r.current.scrollTop = r.current.scrollHeight);
870
871
  }, [l.length]), /* @__PURE__ */ o("div", { id: "chat", className: "chat", ref: r, children: l.length === 0 ? /* @__PURE__ */ o("div", { className: "empty", children: "No announcements yet — agents will post here as they coordinate." }) : l.map((c, p) => {
871
872
  const d = "msg" + (c.targetAgentName !== null || c.toAdmin ? " msg--targeted" : "") + (c.fromAdmin ? " msg--me" : "");
@@ -877,8 +878,8 @@ function ht({ announcements: n, selectedRepo: t, nowMs: i }) {
877
878
  "div",
878
879
  {
879
880
  className: "msg__avatar",
880
- style: { background: U(c.fromAgentName) },
881
- children: Q(c.fromAgentName)
881
+ style: { background: K(c.fromAgentName) },
882
+ children: re(c.fromAgentName)
882
883
  }
883
884
  ),
884
885
  /* @__PURE__ */ m("div", { className: "msg__body", children: [
@@ -887,13 +888,13 @@ function ht({ announcements: n, selectedRepo: t, nowMs: i }) {
887
888
  "span",
888
889
  {
889
890
  className: "msg__who",
890
- style: { color: U(c.fromAgentName) },
891
+ style: { color: K(c.fromAgentName) },
891
892
  children: c.fromAgentName
892
893
  }
893
894
  ),
894
895
  c.fromHuman ? /* @__PURE__ */ o("span", { className: "msg__human", children: c.fromHuman }) : null,
895
896
  c.targetAgentName !== null ? /* @__PURE__ */ o("span", { className: "msg__to", children: `→ @${c.targetAgentName}` }) : c.toAdmin ? /* @__PURE__ */ o("span", { className: "msg__to", children: "→ admin" }) : null,
896
- /* @__PURE__ */ o("span", { className: "msg__time", children: G(c.createdAt, i) })
897
+ /* @__PURE__ */ o("span", { className: "msg__time", children: q(c.createdAt, i) })
897
898
  ] }),
898
899
  /* @__PURE__ */ o("div", { className: "msg__text", children: c.body })
899
900
  ] })
@@ -901,64 +902,64 @@ function ht({ announcements: n, selectedRepo: t, nowMs: i }) {
901
902
  );
902
903
  }) });
903
904
  }
904
- const pt = 8;
905
- function gt({ agents: n, selectedRepo: t, workspaceId: i, onSent: r }) {
906
- const a = pe(), s = x(null), [l, c] = k(""), [p, u] = k([]), [d, b] = k(0), [v, N] = k(null), [y, f] = k(!1), [w, $] = k(!1), C = Ze(
907
- n.map((h) => ({ name: h.name, presence: h.presence, repo: h.repo ?? "" })),
908
- t
909
- ), R = p.length > 0, T = S(() => {
905
+ const Tt = 8;
906
+ function Ct({ agents: t, selectedRepo: n, workspaceId: i, onSent: r }) {
907
+ const a = Ae(), s = P(null), [l, c] = A(""), [p, u] = A([]), [d, f] = A(0), [b, N] = A(null), [v, S] = A(!1), [E, w] = A(!1), I = lt(
908
+ t.map((h) => ({ name: h.name, presence: h.presence, repo: h.repo ?? "" })),
909
+ n
910
+ ), T = p.length > 0, $ = R(() => {
910
911
  u([]), N(null);
911
- }, []), M = S(
912
- (h, _) => {
913
- const g = Ve(h, _);
914
- if (!g) {
915
- T();
912
+ }, []), W = R(
913
+ (h, y) => {
914
+ const k = it(h, y);
915
+ if (!k) {
916
+ $();
916
917
  return;
917
918
  }
918
- const E = g.query.toLowerCase(), j = C.filter((ve) => ve.toLowerCase().startsWith(E)).slice(0, pt);
919
- u(j), N({ start: g.start, end: g.end }), b(0);
919
+ const M = k.query.toLowerCase(), D = I.filter((G) => G.toLowerCase().startsWith(M)).slice(0, Tt);
920
+ u(D), N({ start: k.start, end: k.end }), f(0);
920
921
  },
921
- [C, T]
922
- ), L = S(
922
+ [I, $]
923
+ ), _ = R(
923
924
  (h) => {
924
- if (!v) return;
925
- const _ = "@" + h + " ", g = l.slice(0, v.start) + _ + l.slice(v.end), E = v.start + _.length;
926
- c(g), T(), requestAnimationFrame(() => {
927
- const j = s.current;
928
- j && (j.focus(), j.setSelectionRange(E, E));
925
+ if (!b) return;
926
+ const y = "@" + h + " ", k = l.slice(0, b.start) + y + l.slice(b.end), M = b.start + y.length;
927
+ c(k), $(), requestAnimationFrame(() => {
928
+ const D = s.current;
929
+ D && (D.focus(), D.setSelectionRange(M, M));
929
930
  });
930
931
  },
931
- [v, l, T]
932
- ), O = S(
932
+ [b, l, $]
933
+ ), U = R(
933
934
  (h) => {
934
- var g;
935
+ var k;
935
936
  c(h);
936
- const _ = ((g = s.current) == null ? void 0 : g.selectionStart) ?? h.length;
937
- M(h, _);
937
+ const y = ((k = s.current) == null ? void 0 : k.selectionStart) ?? h.length;
938
+ W(h, y);
938
939
  },
939
- [M]
940
- ), I = S(
940
+ [W]
941
+ ), Y = R(
941
942
  (h) => {
942
- R && (h.key === "ArrowDown" ? (h.preventDefault(), b((_) => (_ + 1) % p.length)) : h.key === "ArrowUp" ? (h.preventDefault(), b((_) => (_ - 1 + p.length) % p.length)) : h.key === "Enter" || h.key === "Tab" ? (h.preventDefault(), L(p[d])) : h.key === "Escape" && (h.preventDefault(), T()));
943
+ T && (h.key === "ArrowDown" ? (h.preventDefault(), f((y) => (y + 1) % p.length)) : h.key === "ArrowUp" ? (h.preventDefault(), f((y) => (y - 1 + p.length) % p.length)) : h.key === "Enter" || h.key === "Tab" ? (h.preventDefault(), _(p[d])) : h.key === "Escape" && (h.preventDefault(), $()));
943
944
  },
944
- [R, p, d, L, T]
945
- ), F = S(
945
+ [T, p, d, _, $]
946
+ ), V = R(
946
947
  async (h) => {
947
948
  h.preventDefault();
948
- const _ = l.trim();
949
- if (!_) return;
950
- const g = Xe(_, C), E = t === null || t === "__all__" ? null : t;
951
- f(!0), $(!1);
949
+ const y = l.trim();
950
+ if (!y) return;
951
+ const k = ct(y, I), M = n === null || n === "__all__" ? null : n;
952
+ S(!0), w(!1);
952
953
  try {
953
- const j = { body: _, targetAgentName: g, repo: E };
954
- await (i !== void 0 ? a.announceTo(i, j) : a.announce(j)), c(""), T(), await r();
954
+ const D = { body: y, targetAgentName: k, repo: M };
955
+ await (i !== void 0 ? a.announceTo(i, D) : a.announce(D)), c(""), $(), await r();
955
956
  } catch {
956
- $(!0);
957
+ w(!0);
957
958
  } finally {
958
- f(!1);
959
+ S(!1);
959
960
  }
960
961
  },
961
- [l, C, t, i, a, T, r]
962
+ [l, I, n, i, a, $, r]
962
963
  );
963
964
  return /* @__PURE__ */ m("div", { className: "composer", children: [
964
965
  /* @__PURE__ */ o(
@@ -968,20 +969,20 @@ function gt({ agents: n, selectedRepo: t, workspaceId: i, onSent: r }) {
968
969
  className: "mention-pop",
969
970
  role: "listbox",
970
971
  "aria-label": "Agents to mention",
971
- hidden: !R,
972
- children: p.map((h, _) => /* @__PURE__ */ m(
972
+ hidden: !T,
973
+ children: p.map((h, y) => /* @__PURE__ */ m(
973
974
  "button",
974
975
  {
975
- id: `mention-opt-${_}`,
976
+ id: `mention-opt-${y}`,
976
977
  type: "button",
977
978
  role: "option",
978
- "aria-selected": _ === d,
979
- className: "mention-mi" + (_ === d ? " on" : ""),
980
- onMouseDown: (g) => {
981
- g.preventDefault(), L(h);
979
+ "aria-selected": y === d,
980
+ className: "mention-mi" + (y === d ? " on" : ""),
981
+ onMouseDown: (k) => {
982
+ k.preventDefault(), _(h);
982
983
  },
983
984
  children: [
984
- /* @__PURE__ */ o("div", { className: "ma", style: { background: U(h) }, children: Q(h) }),
985
+ /* @__PURE__ */ o("div", { className: "ma", style: { background: K(h) }, children: re(h) }),
985
986
  /* @__PURE__ */ o("span", { children: h })
986
987
  ]
987
988
  },
@@ -995,7 +996,7 @@ function gt({ agents: n, selectedRepo: t, workspaceId: i, onSent: r }) {
995
996
  id: "chat-form",
996
997
  className: "chat-form",
997
998
  onSubmit: (h) => {
998
- F(h);
999
+ V(h);
999
1000
  },
1000
1001
  children: [
1001
1002
  /* @__PURE__ */ o(
@@ -1008,24 +1009,37 @@ function gt({ agents: n, selectedRepo: t, workspaceId: i, onSent: r }) {
1008
1009
  "aria-label": "Message the team",
1009
1010
  placeholder: "Message the team… use @name to direct it",
1010
1011
  role: "combobox",
1011
- "aria-expanded": R,
1012
+ "aria-expanded": T,
1012
1013
  "aria-controls": "mention-pop",
1013
1014
  "aria-autocomplete": "list",
1014
- "aria-activedescendant": R ? `mention-opt-${d}` : void 0,
1015
+ "aria-activedescendant": T ? `mention-opt-${d}` : void 0,
1015
1016
  ref: s,
1016
1017
  value: l,
1017
- onChange: (h) => O(h.target.value),
1018
- onKeyDown: I
1018
+ onChange: (h) => U(h.target.value),
1019
+ onKeyDown: Y
1019
1020
  }
1020
1021
  ),
1021
- /* @__PURE__ */ o("button", { id: "chat-send", className: "chat-send", type: "submit", disabled: y, children: "Send" })
1022
+ /* @__PURE__ */ o("button", { id: "chat-send", className: "chat-send", type: "submit", disabled: v, children: "Send" })
1022
1023
  ]
1023
1024
  }
1024
1025
  ),
1025
- w ? /* @__PURE__ */ o("div", { className: "chat__note", role: "status", children: "send failed — retry" }) : null
1026
+ E ? /* @__PURE__ */ o("div", { className: "chat__note", role: "status", children: "send failed — retry" }) : null
1027
+ ] });
1028
+ }
1029
+ function ve({
1030
+ title: t = "No workspace yet",
1031
+ children: n,
1032
+ onGetStarted: i,
1033
+ ctaLabel: r = "Go to Config"
1034
+ }) {
1035
+ const a = Pe();
1036
+ return /* @__PURE__ */ m("section", { className: "shepherd-empty-state", "aria-labelledby": a, children: [
1037
+ /* @__PURE__ */ o("h2", { id: a, children: t }),
1038
+ /* @__PURE__ */ o("p", { children: n ?? "Create a workspace or join one with an invite code to get started." }),
1039
+ i && /* @__PURE__ */ o("button", { type: "button", onClick: i, children: r })
1026
1040
  ] });
1027
1041
  }
1028
- const le = "shepherd.tab", z = "shepherd.repo", K = 10, ft = {
1042
+ const _e = "shepherd.tab", Z = "shepherd.repo", J = 10, $t = {
1029
1043
  live: { text: "live", kind: "ok" },
1030
1044
  reconnecting: { text: "reconnecting…", kind: "warn" },
1031
1045
  // app.js cleared the token and re-prompted on 401; in the auth-agnostic port
@@ -1033,152 +1047,199 @@ const le = "shepherd.tab", z = "shepherd.repo", K = 10, ft = {
1033
1047
  // only surfaces the rejected state.
1034
1048
  unauthorized: { text: "token rejected", kind: "error" }
1035
1049
  };
1036
- function de(n) {
1050
+ function ye(t) {
1037
1051
  try {
1038
- return localStorage.getItem(n);
1052
+ return localStorage.getItem(t);
1039
1053
  } catch {
1040
1054
  return null;
1041
1055
  }
1042
1056
  }
1043
- function B(n, t) {
1057
+ function Q(t, n) {
1044
1058
  try {
1045
- localStorage.setItem(n, t);
1059
+ localStorage.setItem(t, n);
1046
1060
  } catch {
1047
1061
  }
1048
1062
  }
1049
- function bt(n, t, i) {
1050
- const r = fe(t.tasks);
1051
- let a = n;
1052
- if (a === null && r.length >= 2 && (a = se(t.tasks)), a !== null && a !== "__all__" && !r.includes(a) && (a = "__all__"), i && a !== null && a !== "__all__") {
1053
- const s = t.tasks.some(
1063
+ function Rt(t, n, i) {
1064
+ const r = Te(n.tasks);
1065
+ let a = t;
1066
+ if (a === null && r.length >= 2 && (a = me(n.tasks)), a !== null && a !== "__all__" && !r.includes(a) && (a = "__all__"), i && a !== null && a !== "__all__") {
1067
+ const s = n.tasks.some(
1054
1068
  (c) => c.status === "active" && c.repo === a
1055
- ), l = t.tasks.some((c) => c.status === "active");
1056
- !s && l && (a = se(t.tasks));
1069
+ ), l = n.tasks.some((c) => c.status === "active");
1070
+ !s && l && (a = me(n.tasks));
1057
1071
  }
1058
1072
  return a;
1059
1073
  }
1060
- function vt(n) {
1061
- const t = {}, i = (r, a) => {
1062
- const s = t[r] ?? (t[r] = { active: 0, done: 0 });
1074
+ function Et(t) {
1075
+ const n = {}, i = (r, a) => {
1076
+ const s = n[r] ?? (n[r] = { active: 0, done: 0 });
1063
1077
  s[a]++;
1064
1078
  };
1065
- for (const r of n.tasks) {
1079
+ for (const r of t.tasks) {
1066
1080
  const a = r.status === "active" ? "active" : "done";
1067
1081
  i(r.repo, a), i("__all__", a);
1068
1082
  }
1069
- return t;
1083
+ return n;
1070
1084
  }
1071
- function Tt({ workspaceId: n } = {}) {
1072
- const { snapshot: t, status: i, lastUpdatedMs: r, refresh: a } = Ye({ workspaceId: n }), [s, l] = k(
1073
- () => de(le) === "chat" ? "chat" : "tasks"
1074
- ), [c, p] = k(
1075
- () => de(z)
1076
- ), [u, d] = k(K), b = x(!0), v = S((g) => {
1077
- l(g), B(le, g);
1078
- }, []), N = S((g) => {
1079
- const E = g === null ? "__all__" : g;
1080
- p(E), B(z, E), d(K);
1081
- }, []), y = S(() => {
1082
- d((g) => g + K);
1083
- }, []), f = t ? bt(c, t, b.current) : c;
1084
- X(() => {
1085
- t && (b.current = !1, f !== c && (p(f), f !== null && f !== "__all__" && B(z, f)));
1086
- }, [t, f, c]);
1087
- const w = t ? Date.parse(t.serverTime) : Date.now(), $ = t ? fe(t.tasks) : [], C = t ? vt(t) : {}, R = t ? t.agents.filter(
1088
- (g) => g.presence === "live" && D({ repo: g.repo ?? "" }, f)
1089
- ).length : 0, T = t ? t.tasks.filter((g) => g.status === "active" && D(g, f)).length : 0, M = ft[i], L = r === null ? "" : `updated ${Math.floor((Date.now() - r) / 1e3)}s ago`, O = (t == null ? void 0 : t.agents) ?? [], I = (t == null ? void 0 : t.tasks) ?? [], F = (t == null ? void 0 : t.announcements) ?? [], h = I.filter(
1090
- (g) => g.status === "active" && D(g, f)
1091
- ).length, _ = I.filter(
1092
- (g) => g.status !== "active" && D(g, f)
1093
- ).length;
1085
+ function Gt({
1086
+ workspaceId: t,
1087
+ config: n,
1088
+ hasWorkspace: i
1089
+ } = {}) {
1090
+ const r = n != null, a = i === !1, { snapshot: s, status: l, lastUpdatedMs: c, refresh: p } = ot({
1091
+ workspaceId: t,
1092
+ // A no-workspace board has nothing to poll; keep it off the hub.
1093
+ enabled: !a
1094
+ }), [u, d] = A(() => {
1095
+ if (r && a) return "config";
1096
+ const g = ye(_e);
1097
+ return g === "chat" ? "chat" : g === "config" && r ? "config" : "tasks";
1098
+ }), f = r ? [
1099
+ { id: "tasks", label: "Tasks" },
1100
+ { id: "chat", label: "Chat" },
1101
+ { id: "config", label: "Config" }
1102
+ ] : [
1103
+ { id: "tasks", label: "Tasks" },
1104
+ { id: "chat", label: "Chat" }
1105
+ ], b = P([]), N = R(
1106
+ (g, x) => {
1107
+ var ce;
1108
+ const O = f.length - 1;
1109
+ let j = null;
1110
+ switch (g.key) {
1111
+ case "ArrowRight":
1112
+ j = x === O ? 0 : x + 1;
1113
+ break;
1114
+ case "ArrowLeft":
1115
+ j = x === 0 ? O : x - 1;
1116
+ break;
1117
+ case "Home":
1118
+ j = 0;
1119
+ break;
1120
+ case "End":
1121
+ j = O;
1122
+ break;
1123
+ default:
1124
+ return;
1125
+ }
1126
+ g.preventDefault();
1127
+ const ie = f[j];
1128
+ ie && (T(ie.id), (ce = b.current[j]) == null || ce.focus());
1129
+ },
1130
+ // `tabs` is rebuilt each render but its identity only matters by length,
1131
+ // which is stable for a given `hasConfig`; `onTab` is stable.
1132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1133
+ [r]
1134
+ ), [v, S] = A(
1135
+ () => ye(Z)
1136
+ ), [E, w] = A(J), I = P(!0), T = R((g) => {
1137
+ d(g), Q(_e, g);
1138
+ }, []), $ = R((g) => {
1139
+ const x = g === null ? "__all__" : g;
1140
+ S(x), Q(Z, x), w(J);
1141
+ }, []), W = R(() => {
1142
+ w((g) => g + J);
1143
+ }, []), _ = s ? Rt(v, s, I.current) : v;
1144
+ ne(() => {
1145
+ s && (I.current = !1, _ !== v && (S(_), _ !== null && _ !== "__all__" && Q(Z, _)));
1146
+ }, [s, _, v]);
1147
+ const U = s ? Date.parse(s.serverTime) : Date.now(), Y = s ? Te(s.tasks) : [], V = s ? Et(s) : {}, h = s ? s.agents.filter(
1148
+ (g) => g.presence === "live" && L({ repo: g.repo ?? "" }, _)
1149
+ ).length : 0, y = s ? s.tasks.filter((g) => g.status === "active" && L(g, _)).length : 0, k = $t[l], M = c === null ? "" : `updated ${Math.floor((Date.now() - c) / 1e3)}s ago`, D = (s == null ? void 0 : s.agents) ?? [], G = (s == null ? void 0 : s.tasks) ?? [], $e = (s == null ? void 0 : s.announcements) ?? [], Re = G.filter(
1150
+ (g) => g.status === "active" && L(g, _)
1151
+ ).length, Ee = G.filter(
1152
+ (g) => g.status !== "active" && L(g, _)
1153
+ ).length, oe = !a && u !== "config";
1094
1154
  return /* @__PURE__ */ m("div", { id: "board", children: [
1095
1155
  /* @__PURE__ */ m("header", { children: [
1096
- /* @__PURE__ */ o("span", { className: "brand", children: "Shepherd" }),
1097
- /* @__PURE__ */ o(
1098
- st,
1099
- {
1100
- repos: $,
1101
- counts: C,
1102
- selected: f,
1103
- onSelect: N
1104
- }
1105
- ),
1106
- /* @__PURE__ */ m("span", { className: "vitals", children: [
1107
- /* @__PURE__ */ o("b", { id: "vitals-online", children: R }),
1108
- " online · ",
1109
- /* @__PURE__ */ o("b", { id: "vitals-active", children: T }),
1110
- " active"
1111
- ] }),
1112
- /* @__PURE__ */ o("span", { className: "grow" }),
1113
- /* @__PURE__ */ o("span", { id: "status", className: "status" + (M.kind ? ` status--${M.kind}` : ""), children: M.text }),
1114
- /* @__PURE__ */ o("span", { id: "freshness", className: "freshness", children: L }),
1115
- /* @__PURE__ */ m("nav", { className: "tabs", role: "tablist", "aria-label": "Dashboard views", children: [
1156
+ /* @__PURE__ */ o("h1", { className: "brand", style: { margin: 0, font: "inherit" }, children: "Shepherd" }),
1157
+ oe && /* @__PURE__ */ m(F, { children: [
1116
1158
  /* @__PURE__ */ o(
1117
- "button",
1159
+ gt,
1118
1160
  {
1119
- className: "tab" + (s === "tasks" ? " tab--active" : ""),
1120
- "data-tab": "tasks",
1121
- type: "button",
1122
- role: "tab",
1123
- id: "tab-tasks",
1124
- "aria-controls": "panel-tasks",
1125
- "aria-selected": s === "tasks",
1126
- onClick: () => v("tasks"),
1127
- children: "Tasks"
1161
+ repos: Y,
1162
+ counts: V,
1163
+ selected: _,
1164
+ onSelect: $
1128
1165
  }
1129
1166
  ),
1167
+ /* @__PURE__ */ m("span", { className: "vitals", children: [
1168
+ /* @__PURE__ */ o("b", { id: "vitals-online", children: h }),
1169
+ " online · ",
1170
+ /* @__PURE__ */ o("b", { id: "vitals-active", children: y }),
1171
+ " active"
1172
+ ] })
1173
+ ] }),
1174
+ /* @__PURE__ */ o("span", { className: "grow" }),
1175
+ oe && /* @__PURE__ */ m(F, { children: [
1130
1176
  /* @__PURE__ */ o(
1131
- "button",
1177
+ "span",
1132
1178
  {
1133
- className: "tab" + (s === "chat" ? " tab--active" : ""),
1134
- "data-tab": "chat",
1135
- type: "button",
1136
- role: "tab",
1137
- id: "tab-chat",
1138
- "aria-controls": "panel-chat",
1139
- "aria-selected": s === "chat",
1140
- onClick: () => v("chat"),
1141
- children: "Chat"
1179
+ id: "status",
1180
+ className: "status" + (k.kind ? ` status--${k.kind}` : ""),
1181
+ children: k.text
1142
1182
  }
1143
- )
1144
- ] })
1183
+ ),
1184
+ /* @__PURE__ */ o("span", { id: "freshness", className: "freshness", children: M })
1185
+ ] }),
1186
+ /* @__PURE__ */ o("nav", { className: "tabs", role: "tablist", "aria-label": "Shepherd views", children: f.map(({ id: g, label: x }, O) => /* @__PURE__ */ o(
1187
+ "button",
1188
+ {
1189
+ ref: (j) => {
1190
+ b.current[O] = j;
1191
+ },
1192
+ className: "tab" + (u === g ? " tab--active" : ""),
1193
+ "data-tab": g,
1194
+ type: "button",
1195
+ role: "tab",
1196
+ id: `tab-${g}`,
1197
+ "aria-controls": `panel-${g}`,
1198
+ "aria-selected": u === g,
1199
+ tabIndex: u === g ? 0 : -1,
1200
+ onClick: () => T(g),
1201
+ onKeyDown: (j) => N(j, O),
1202
+ children: x
1203
+ },
1204
+ g
1205
+ )) })
1145
1206
  ] }),
1146
- /* @__PURE__ */ m(
1207
+ /* @__PURE__ */ o(
1147
1208
  "section",
1148
1209
  {
1149
1210
  id: "panel-tasks",
1150
1211
  role: "tabpanel",
1151
1212
  "aria-labelledby": "tab-tasks",
1152
- hidden: s !== "tasks",
1153
- children: [
1154
- /* @__PURE__ */ o(at, { agents: O, tasks: I, selectedRepo: f }),
1213
+ hidden: u !== "tasks",
1214
+ children: a ? /* @__PURE__ */ o(ve, { onGetStarted: () => T("config") }) : /* @__PURE__ */ m(F, { children: [
1215
+ /* @__PURE__ */ o(ft, { agents: D, tasks: G, selectedRepo: _ }),
1155
1216
  /* @__PURE__ */ m("div", { className: "board", children: [
1156
1217
  /* @__PURE__ */ m("div", { className: "col", children: [
1157
1218
  /* @__PURE__ */ m("div", { className: "colhead", children: [
1158
1219
  /* @__PURE__ */ o("h2", { children: "Active" }),
1159
- /* @__PURE__ */ o("span", { className: "n", id: "active-count", children: h })
1220
+ /* @__PURE__ */ o("span", { className: "n", id: "active-count", children: Re })
1160
1221
  ] }),
1161
- /* @__PURE__ */ o(ct, { tasks: I, nowMs: w, selectedRepo: f })
1222
+ /* @__PURE__ */ o(yt, { tasks: G, nowMs: U, selectedRepo: _ })
1162
1223
  ] }),
1163
1224
  /* @__PURE__ */ o("div", { className: "board__rule" }),
1164
1225
  /* @__PURE__ */ m("div", { className: "col", children: [
1165
1226
  /* @__PURE__ */ m("div", { className: "colhead", children: [
1166
1227
  /* @__PURE__ */ o("h2", { children: "Done" }),
1167
- /* @__PURE__ */ o("span", { className: "n", id: "done-count", children: _ })
1228
+ /* @__PURE__ */ o("span", { className: "n", id: "done-count", children: Ee })
1168
1229
  ] }),
1169
1230
  /* @__PURE__ */ o(
1170
- ut,
1231
+ wt,
1171
1232
  {
1172
- tasks: I,
1173
- nowMs: w,
1174
- selectedRepo: f,
1175
- doneShown: u,
1176
- onLoadMore: y
1233
+ tasks: G,
1234
+ nowMs: U,
1235
+ selectedRepo: _,
1236
+ doneShown: E,
1237
+ onLoadMore: W
1177
1238
  }
1178
1239
  )
1179
1240
  ] })
1180
1241
  ] })
1181
- ]
1242
+ ] })
1182
1243
  }
1183
1244
  ),
1184
1245
  /* @__PURE__ */ o(
@@ -1187,28 +1248,39 @@ function Tt({ workspaceId: n } = {}) {
1187
1248
  id: "panel-chat",
1188
1249
  role: "tabpanel",
1189
1250
  "aria-labelledby": "tab-chat",
1190
- hidden: s !== "chat",
1191
- children: /* @__PURE__ */ m("div", { className: "chat-wrap", children: [
1192
- /* @__PURE__ */ o(ht, { announcements: F, selectedRepo: f, nowMs: w }),
1251
+ hidden: u !== "chat",
1252
+ children: a ? /* @__PURE__ */ o(ve, { onGetStarted: () => T("config") }) : /* @__PURE__ */ m("div", { className: "chat-wrap", children: [
1253
+ /* @__PURE__ */ o(St, { announcements: $e, selectedRepo: _, nowMs: U }),
1193
1254
  /* @__PURE__ */ o(
1194
- gt,
1255
+ Ct,
1195
1256
  {
1196
- agents: O,
1197
- selectedRepo: f,
1198
- workspaceId: n,
1199
- onSent: a
1257
+ agents: D,
1258
+ selectedRepo: _,
1259
+ workspaceId: t,
1260
+ onSent: p
1200
1261
  }
1201
1262
  )
1202
1263
  ] })
1203
1264
  }
1265
+ ),
1266
+ r && /* @__PURE__ */ o(
1267
+ "section",
1268
+ {
1269
+ id: "panel-config",
1270
+ role: "tabpanel",
1271
+ "aria-labelledby": "tab-config",
1272
+ hidden: u !== "config",
1273
+ children: n
1274
+ }
1204
1275
  )
1205
1276
  ] });
1206
1277
  }
1207
1278
  export {
1208
- Tt as D,
1209
- P as S,
1210
- St as a,
1211
- At as c,
1212
- wt as d,
1213
- pe as u
1279
+ Gt as D,
1280
+ ve as E,
1281
+ H as S,
1282
+ Pt as a,
1283
+ Mt as c,
1284
+ Lt as d,
1285
+ Ae as u
1214
1286
  };