@korso/shepherd-ui 0.2.1 → 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.
@@ -112,8 +112,8 @@ export function ConnectAgent({ workspaceId, hubUrl }) {
112
112
  }
113
113
  }
114
114
  const command = installCommand(tool, directHubUrl, rawToken ?? TOKEN_PLACEHOLDER);
115
- return (_jsxs("section", { className: "shepherd-connect-agent", "aria-labelledby": headingId, children: [_jsx("h3", { id: headingId, children: "Connect your agent" }), _jsx("label", { htmlFor: "connect-tool", children: "Tool" }), _jsx("select", { id: "connect-tool", value: tool, onChange: (e) => setTool(e.target.value), children: TOOLS.map((t) => (_jsx("option", { value: t.id, children: t.label }, t.id))) }), _jsxs("div", { className: "generate", children: [_jsx("label", { htmlFor: "token-name", children: "Token name (optional)" }), _jsx("input", { id: "token-name", type: "text", value: name, onChange: (e) => setName(e.target.value), placeholder: "e.g. laptop" }), _jsx("button", { type: "button", onClick: () => void generate(), disabled: busy, children: "Generate token" })] }), error && _jsx("p", { role: "alert", children: error }), status && _jsx("p", { role: "status", children: status }), rawToken && (_jsx("p", { className: "token-once", role: "status", children: "Copy this token now \u2014 it won't be shown again." })), _jsx("pre", { "data-testid": "install-command", children: command }), _jsx("h4", { children: "Existing tokens" }), loading ? (_jsx("p", { role: "status", children: "Loading\u2026" })) : tokens.length === 0 ? (_jsx("p", { children: "No tokens yet." })) : (_jsx("ul", { children: tokens.map((t) => {
116
- const name = t.name ?? t.id;
117
- return (_jsxs("li", { children: [_jsx("span", { children: name }), t.revokedAt ? (_jsx("span", { className: "revoked", children: "revoked" })) : (_jsx("button", { type: "button", "aria-label": `Revoke token ${name}`, onClick: () => void revoke(t.id), disabled: revokingId === t.id, children: "Revoke" }))] }, t.id));
118
- }) }))] }));
115
+ return (_jsxs("section", { className: "shepherd-connect-agent", "aria-labelledby": headingId, children: [_jsxs("div", { className: "card-head", children: [_jsx("h3", { id: headingId, children: "Connect your agent" }), _jsx("p", { className: "card-sub", children: "Generate a token, then paste the command into your coding tool." })] }), _jsxs("div", { className: "card-body", children: [_jsxs("div", { className: "field", children: [_jsx("label", { htmlFor: "connect-tool", children: "Tool" }), _jsx("select", { id: "connect-tool", value: tool, onChange: (e) => setTool(e.target.value), children: TOOLS.map((t) => (_jsx("option", { value: t.id, children: t.label }, t.id))) })] }), _jsxs("div", { className: "field generate", children: [_jsx("label", { htmlFor: "token-name", children: "Token name (optional)" }), _jsxs("div", { className: "field__row", children: [_jsx("input", { id: "token-name", type: "text", value: name, onChange: (e) => setName(e.target.value), placeholder: "e.g. laptop" }), _jsx("button", { type: "button", onClick: () => void generate(), disabled: busy, children: "Generate token" })] })] }), error && _jsx("p", { role: "alert", children: error }), status && _jsx("p", { role: "status", children: status }), rawToken && (_jsx("p", { className: "token-once", role: "status", children: "Copy this token now \u2014 it won't be shown again." })), _jsx("pre", { "data-testid": "install-command", children: command }), _jsx("h4", { children: "Existing tokens" }), loading ? (_jsx("p", { role: "status", children: "Loading\u2026" })) : tokens.length === 0 ? (_jsx("p", { children: "No tokens yet." })) : (_jsx("ul", { children: tokens.map((t) => {
116
+ const name = t.name ?? t.id;
117
+ return (_jsxs("li", { children: [_jsx("span", { children: name }), t.revokedAt ? (_jsx("span", { className: "revoked", children: "revoked" })) : (_jsx("button", { type: "button", "aria-label": `Revoke token ${name}`, onClick: () => void revoke(t.id), disabled: revokingId === t.id, children: "Revoke" }))] }, t.id));
118
+ }) }))] })] }));
119
119
  }
@@ -76,8 +76,8 @@ export function Members({ workspaceId, refreshKey = 0, canRemove = false, onLeft
76
76
  setLeaving(false);
77
77
  }
78
78
  }
79
- return (_jsxs("section", { className: "shepherd-members", "aria-labelledby": headingId, children: [_jsx("h3", { id: headingId, children: "Members" }), error && _jsx("p", { role: "alert", children: error }), status && _jsx("p", { role: "status", children: status }), loading ? (_jsx("p", { role: "status", children: "Loading\u2026" })) : members.length === 0 ? (_jsx("p", { children: "No members." })) : (_jsx("ul", { children: members.map((m) => {
80
- const display = m.displayName ?? m.githubLogin ?? m.accountId;
81
- return (_jsxs("li", { children: [_jsx("span", { children: display }), _jsx("span", { className: "role", children: m.role }), canRemove && (_jsx("button", { type: "button", "aria-label": `Remove ${display}`, onClick: () => void remove(m.accountId, display), disabled: removingId === m.accountId, children: "Remove" }))] }, m.accountId));
82
- }) })), _jsx("button", { type: "button", onClick: () => void leave(), disabled: leaving, children: "Leave workspace" })] }));
79
+ return (_jsxs("section", { className: "shepherd-members", "aria-labelledby": headingId, children: [_jsx("div", { className: "card-head", children: _jsx("h3", { id: headingId, children: "Members" }) }), _jsxs("div", { className: "card-body", children: [error && _jsx("p", { role: "alert", children: error }), status && _jsx("p", { role: "status", children: status }), loading ? (_jsx("p", { role: "status", children: "Loading\u2026" })) : members.length === 0 ? (_jsx("p", { children: "No members." })) : (_jsx("ul", { children: members.map((m) => {
80
+ const display = m.displayName ?? m.githubLogin ?? m.accountId;
81
+ return (_jsxs("li", { children: [_jsx("span", { children: display }), _jsx("span", { className: "role", children: m.role }), canRemove && (_jsx("button", { type: "button", "aria-label": `Remove ${display}`, onClick: () => void remove(m.accountId, display), disabled: removingId === m.accountId, children: "Remove" }))] }, m.accountId));
82
+ }) })), _jsx("button", { type: "button", onClick: () => void leave(), disabled: leaving, children: "Leave workspace" })] })] }));
83
83
  }
@@ -92,5 +92,5 @@ export function Workspaces({ workspaces, selected, onChanged, onSelect }) {
92
92
  const joinLink = invite
93
93
  ? `${window.location.origin}/join/${encodeURIComponent(invite.code)}`
94
94
  : null;
95
- return (_jsxs("section", { className: "shepherd-workspaces", "aria-labelledby": headingId, children: [_jsx("h3", { id: headingId, children: "Workspace management" }), error && _jsx("p", { role: "alert", children: error }), workspaces.length > 1 && onSelect && (_jsxs("div", { className: "switcher", children: [_jsx("label", { htmlFor: "ws-switcher", children: "Active workspace" }), _jsx("select", { id: "ws-switcher", value: selected?.id ?? "", onChange: (e) => onSelect(e.target.value), children: workspaces.map((w) => (_jsx("option", { value: w.id, children: w.name }, w.id))) })] })), _jsxs("div", { className: "create", children: [_jsx("label", { htmlFor: "ws-name", children: "Workspace name" }), _jsx("input", { id: "ws-name", type: "text", value: name, onChange: (e) => setName(e.target.value) }), _jsx("button", { type: "button", onClick: () => void create(), disabled: busy, children: "Create workspace" })] }), _jsxs("div", { className: "join", children: [_jsx("label", { htmlFor: "invite-code", children: "Invite code" }), _jsx("input", { id: "invite-code", type: "text", value: code, onChange: (e) => setCode(e.target.value) }), _jsx("button", { type: "button", onClick: () => void join(), disabled: busy, children: "Join" })] }), isAdmin && selected && (_jsxs("div", { className: "admin", children: [_jsxs("div", { className: "invites", children: [_jsx("button", { type: "button", onClick: () => void createInvite(), disabled: busy, children: "Create invite" }), invite && (_jsxs("div", { className: "invite-result", children: [_jsx("code", { children: invite.code }), _jsx("a", { href: joinLink ?? undefined, children: joinLink }), _jsxs("span", { className: "invite-uses", children: [invite.useCount, " / ", invite.maxUses, " uses"] }), _jsx("button", { type: "button", onClick: () => void revokeInvite(), disabled: busy, children: "Revoke invite" })] }))] }), _jsx(Members, { workspaceId: selected.id, refreshKey: membersRefreshKey, onLeft: onChanged, canRemove: true })] }))] }));
95
+ return (_jsxs("section", { className: "shepherd-workspaces", "aria-labelledby": headingId, children: [_jsxs("div", { className: "card-head", children: [_jsx("h3", { id: headingId, children: "Workspace management" }), _jsx("p", { className: "card-sub", children: "Create a workspace to get started, or join an existing one with an invite code." })] }), _jsxs("div", { className: "card-body", children: [error && _jsx("p", { role: "alert", children: error }), workspaces.length > 1 && onSelect && (_jsxs("div", { className: "field switcher", children: [_jsx("label", { htmlFor: "ws-switcher", children: "Active workspace" }), _jsx("select", { id: "ws-switcher", value: selected?.id ?? "", onChange: (e) => onSelect(e.target.value), children: workspaces.map((w) => (_jsx("option", { value: w.id, children: w.name }, w.id))) })] })), _jsxs("div", { className: "field create", children: [_jsx("label", { htmlFor: "ws-name", children: "Workspace name" }), _jsx("p", { className: "helper", children: "Start a fresh workspace \u2014 you'll be its admin." }), _jsxs("div", { className: "field__row", children: [_jsx("input", { id: "ws-name", type: "text", placeholder: "e.g. Acme Engineering", value: name, onChange: (e) => setName(e.target.value) }), _jsx("button", { type: "button", onClick: () => void create(), disabled: busy, children: "Create workspace" })] })] }), _jsxs("div", { className: "field join", children: [_jsx("label", { htmlFor: "invite-code", children: "Invite code" }), _jsx("p", { className: "helper", children: "Paste an invite code someone shared to join their workspace." }), _jsxs("div", { className: "field__row", children: [_jsx("input", { id: "invite-code", type: "text", placeholder: "Invite code", value: code, onChange: (e) => setCode(e.target.value) }), _jsx("button", { type: "button", onClick: () => void join(), disabled: busy, children: "Join" })] })] }), isAdmin && selected && (_jsxs("div", { className: "admin", children: [_jsxs("div", { className: "invites", children: [_jsx("button", { type: "button", onClick: () => void createInvite(), disabled: busy, children: "Create invite" }), invite && (_jsxs("div", { className: "invite-result", children: [_jsx("code", { children: invite.code }), _jsx("a", { href: joinLink ?? undefined, children: joinLink }), _jsxs("span", { className: "invite-uses", children: [invite.useCount, " / ", invite.maxUses, " uses"] }), _jsx("button", { type: "button", onClick: () => void revokeInvite(), disabled: busy, children: "Revoke invite" })] }))] }), _jsx(Members, { workspaceId: selected.id, refreshKey: membersRefreshKey, onLeft: onChanged, canRemove: true })] }))] })] }));
96
96
  }
package/dist/lib/index.js CHANGED
@@ -1,374 +1,398 @@
1
- import { u as O, d as N, D as $ } from "./Dashboard-B7nioe5N.js";
1
+ import { u as j, d as C, D as W } from "./Dashboard-B7nioe5N.js";
2
2
  import { E as Y, S as Z, a as ee, c as ne } from "./Dashboard-B7nioe5N.js";
3
- import { jsxs as y, jsx as e } from "react/jsx-runtime";
4
- import { useId as U, useState as a, useEffect as H, useCallback as F } from "react";
5
- function K({ workspaceId: c, refreshKey: t = 0, canRemove: i = !1, onLeft: k }) {
6
- const m = O(), C = U(), [g, b] = a([]), [u, p] = a(null), [h, o] = a(null), [w, d] = a(!0), [s, v] = a(null), [R, S] = a(!1);
7
- async function I({ keepError: l = !1 } = {}) {
8
- l || p(null);
3
+ import { jsxs as r, jsx as e } from "react/jsx-runtime";
4
+ import { useId as O, useState as i, useEffect as _, useCallback as $ } from "react";
5
+ function A({ workspaceId: d, refreshKey: a = 0, canRemove: l = !1, onLeft: k }) {
6
+ const p = j(), N = O(), [g, b] = i([]), [u, v] = i(null), [m, s] = i(null), [w, h] = i(!0), [c, f] = i(null), [R, S] = i(!1);
7
+ async function I({ keepError: o = !1 } = {}) {
8
+ o || v(null);
9
9
  try {
10
- const f = await m.listMembers(c);
11
- b(f.members);
12
- } catch (f) {
13
- p(N(f));
10
+ const y = await p.listMembers(d);
11
+ b(y.members);
12
+ } catch (y) {
13
+ v(C(y));
14
14
  } finally {
15
- d(!1);
15
+ h(!1);
16
16
  }
17
17
  }
18
- H(() => {
19
- d(!0), I();
20
- }, [m, c, t]);
21
- async function L(l, f) {
22
- if (!s) {
23
- v(l), p(null), o(null), b((E) => E.filter((r) => r.accountId !== l));
18
+ _(() => {
19
+ h(!0), I();
20
+ }, [p, d, a]);
21
+ async function L(o, y) {
22
+ if (!c) {
23
+ f(o), v(null), s(null), b((E) => E.filter((t) => t.accountId !== o));
24
24
  try {
25
- await m.removeMember(c, l), o(`Removed ${f}`);
25
+ await p.removeMember(d, o), s(`Removed ${y}`);
26
26
  } catch (E) {
27
- p(N(E)), I({ keepError: !0 });
27
+ v(C(E)), I({ keepError: !0 });
28
28
  } finally {
29
- v(null);
29
+ f(null);
30
30
  }
31
31
  }
32
32
  }
33
33
  async function x() {
34
34
  if (!R) {
35
- S(!0), p(null), o(null);
35
+ S(!0), v(null), s(null);
36
36
  try {
37
- await m.leave(c), o("Left workspace"), k == null || k();
38
- } catch (l) {
39
- p(N(l));
37
+ await p.leave(d), s("Left workspace"), k == null || k();
38
+ } catch (o) {
39
+ v(C(o));
40
40
  } finally {
41
41
  S(!1);
42
42
  }
43
43
  }
44
44
  }
45
- return /* @__PURE__ */ y("section", { className: "shepherd-members", "aria-labelledby": C, children: [
46
- /* @__PURE__ */ e("h3", { id: C, children: "Members" }),
47
- u && /* @__PURE__ */ e("p", { role: "alert", children: u }),
48
- h && /* @__PURE__ */ e("p", { role: "status", children: h }),
49
- w ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : g.length === 0 ? /* @__PURE__ */ e("p", { children: "No members." }) : /* @__PURE__ */ e("ul", { children: g.map((l) => {
50
- const f = l.displayName ?? l.githubLogin ?? l.accountId;
51
- return /* @__PURE__ */ y("li", { children: [
52
- /* @__PURE__ */ e("span", { children: f }),
53
- /* @__PURE__ */ e("span", { className: "role", children: l.role }),
54
- i && /* @__PURE__ */ e(
55
- "button",
56
- {
57
- type: "button",
58
- "aria-label": `Remove ${f}`,
59
- onClick: () => void L(l.accountId, f),
60
- disabled: s === l.accountId,
61
- children: "Remove"
62
- }
63
- )
64
- ] }, l.accountId);
65
- }) }),
66
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void x(), disabled: R, children: "Leave workspace" })
45
+ return /* @__PURE__ */ r("section", { className: "shepherd-members", "aria-labelledby": N, children: [
46
+ /* @__PURE__ */ e("div", { className: "card-head", children: /* @__PURE__ */ e("h3", { id: N, children: "Members" }) }),
47
+ /* @__PURE__ */ r("div", { className: "card-body", children: [
48
+ u && /* @__PURE__ */ e("p", { role: "alert", children: u }),
49
+ m && /* @__PURE__ */ e("p", { role: "status", children: m }),
50
+ w ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : g.length === 0 ? /* @__PURE__ */ e("p", { children: "No members." }) : /* @__PURE__ */ e("ul", { children: g.map((o) => {
51
+ const y = o.displayName ?? o.githubLogin ?? o.accountId;
52
+ return /* @__PURE__ */ r("li", { children: [
53
+ /* @__PURE__ */ e("span", { children: y }),
54
+ /* @__PURE__ */ e("span", { className: "role", children: o.role }),
55
+ l && /* @__PURE__ */ e(
56
+ "button",
57
+ {
58
+ type: "button",
59
+ "aria-label": `Remove ${y}`,
60
+ onClick: () => void L(o.accountId, y),
61
+ disabled: c === o.accountId,
62
+ children: "Remove"
63
+ }
64
+ )
65
+ ] }, o.accountId);
66
+ }) }),
67
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void x(), disabled: R, children: "Leave workspace" })
68
+ ] })
67
69
  ] });
68
70
  }
69
- function M({ workspaces: c, selected: t, onChanged: i, onSelect: k }) {
70
- const m = O(), C = U(), [g, b] = a(""), [u, p] = a(""), [h, o] = a(null), [w, d] = a(null), [s, v] = a(!1), [R, S] = a(0), I = (t == null ? void 0 : t.role) === "admin";
71
+ function F({ workspaces: d, selected: a, onChanged: l, onSelect: k }) {
72
+ const p = j(), N = O(), [g, b] = i(""), [u, v] = i(""), [m, s] = i(null), [w, h] = i(null), [c, f] = i(!1), [R, S] = i(0), I = (a == null ? void 0 : a.role) === "admin";
71
73
  async function L() {
72
- if (!(!g.trim() || s)) {
73
- v(!0), d(null);
74
+ if (!(!g.trim() || c)) {
75
+ f(!0), h(null);
74
76
  try {
75
- await m.createWorkspace({ name: g.trim() }), b(""), i();
76
- } catch (r) {
77
- d(N(r));
77
+ await p.createWorkspace({ name: g.trim() }), b(""), l();
78
+ } catch (t) {
79
+ h(C(t));
78
80
  } finally {
79
- v(!1);
81
+ f(!1);
80
82
  }
81
83
  }
82
84
  }
83
85
  async function x() {
84
- if (!(!u.trim() || s)) {
85
- v(!0), d(null);
86
+ if (!(!u.trim() || c)) {
87
+ f(!0), h(null);
86
88
  try {
87
- await m.redeemInvite(u.trim()), p(""), i(), S((r) => r + 1);
88
- } catch (r) {
89
- d(N(r));
89
+ await p.redeemInvite(u.trim()), v(""), l(), S((t) => t + 1);
90
+ } catch (t) {
91
+ h(C(t));
90
92
  } finally {
91
- v(!1);
93
+ f(!1);
92
94
  }
93
95
  }
94
96
  }
95
- async function l() {
96
- if (!(!t || s)) {
97
- v(!0), d(null);
97
+ async function o() {
98
+ if (!(!a || c)) {
99
+ f(!0), h(null);
98
100
  try {
99
- const r = await m.createInvite(t.id, {});
100
- o(r), S((j) => j + 1);
101
- } catch (r) {
102
- d(N(r));
101
+ const t = await p.createInvite(a.id, {});
102
+ s(t), S((H) => H + 1);
103
+ } catch (t) {
104
+ h(C(t));
103
105
  } finally {
104
- v(!1);
106
+ f(!1);
105
107
  }
106
108
  }
107
109
  }
108
- async function f() {
109
- if (!(!t || !h || s)) {
110
- v(!0), d(null);
110
+ async function y() {
111
+ if (!(!a || !m || c)) {
112
+ f(!0), h(null);
111
113
  try {
112
- await m.revokeInvite(t.id, h.code), o(null);
113
- } catch (r) {
114
- d(N(r));
114
+ await p.revokeInvite(a.id, m.code), s(null);
115
+ } catch (t) {
116
+ h(C(t));
115
117
  } finally {
116
- v(!1);
118
+ f(!1);
117
119
  }
118
120
  }
119
121
  }
120
- H(() => {
121
- o(null);
122
- }, [t == null ? void 0 : t.id]);
123
- const E = h ? `${window.location.origin}/join/${encodeURIComponent(h.code)}` : null;
124
- return /* @__PURE__ */ y("section", { className: "shepherd-workspaces", "aria-labelledby": C, children: [
125
- /* @__PURE__ */ e("h3", { id: C, children: "Workspace management" }),
126
- w && /* @__PURE__ */ e("p", { role: "alert", children: w }),
127
- c.length > 1 && k && /* @__PURE__ */ y("div", { className: "switcher", children: [
128
- /* @__PURE__ */ e("label", { htmlFor: "ws-switcher", children: "Active workspace" }),
129
- /* @__PURE__ */ e(
130
- "select",
131
- {
132
- id: "ws-switcher",
133
- value: (t == null ? void 0 : t.id) ?? "",
134
- onChange: (r) => k(r.target.value),
135
- children: c.map((r) => /* @__PURE__ */ e("option", { value: r.id, children: r.name }, r.id))
136
- }
137
- )
138
- ] }),
139
- /* @__PURE__ */ y("div", { className: "create", children: [
140
- /* @__PURE__ */ e("label", { htmlFor: "ws-name", children: "Workspace name" }),
141
- /* @__PURE__ */ e(
142
- "input",
143
- {
144
- id: "ws-name",
145
- type: "text",
146
- value: g,
147
- onChange: (r) => b(r.target.value)
148
- }
149
- ),
150
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void L(), disabled: s, children: "Create workspace" })
122
+ _(() => {
123
+ s(null);
124
+ }, [a == null ? void 0 : a.id]);
125
+ const E = m ? `${window.location.origin}/join/${encodeURIComponent(m.code)}` : null;
126
+ return /* @__PURE__ */ r("section", { className: "shepherd-workspaces", "aria-labelledby": N, children: [
127
+ /* @__PURE__ */ r("div", { className: "card-head", children: [
128
+ /* @__PURE__ */ e("h3", { id: N, children: "Workspace management" }),
129
+ /* @__PURE__ */ e("p", { className: "card-sub", children: "Create a workspace to get started, or join an existing one with an invite code." })
151
130
  ] }),
152
- /* @__PURE__ */ y("div", { className: "join", children: [
153
- /* @__PURE__ */ e("label", { htmlFor: "invite-code", children: "Invite code" }),
154
- /* @__PURE__ */ e(
155
- "input",
156
- {
157
- id: "invite-code",
158
- type: "text",
159
- value: u,
160
- onChange: (r) => p(r.target.value)
161
- }
162
- ),
163
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void x(), disabled: s, children: "Join" })
164
- ] }),
165
- I && t && /* @__PURE__ */ y("div", { className: "admin", children: [
166
- /* @__PURE__ */ y("div", { className: "invites", children: [
167
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void l(), disabled: s, children: "Create invite" }),
168
- h && /* @__PURE__ */ y("div", { className: "invite-result", children: [
169
- /* @__PURE__ */ e("code", { children: h.code }),
170
- /* @__PURE__ */ e("a", { href: E ?? void 0, children: E }),
171
- /* @__PURE__ */ y("span", { className: "invite-uses", children: [
172
- h.useCount,
173
- " / ",
174
- h.maxUses,
175
- " uses"
176
- ] }),
177
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void f(), disabled: s, children: "Revoke invite" })
131
+ /* @__PURE__ */ r("div", { className: "card-body", children: [
132
+ w && /* @__PURE__ */ e("p", { role: "alert", children: w }),
133
+ d.length > 1 && k && /* @__PURE__ */ r("div", { className: "field switcher", children: [
134
+ /* @__PURE__ */ e("label", { htmlFor: "ws-switcher", children: "Active workspace" }),
135
+ /* @__PURE__ */ e(
136
+ "select",
137
+ {
138
+ id: "ws-switcher",
139
+ value: (a == null ? void 0 : a.id) ?? "",
140
+ onChange: (t) => k(t.target.value),
141
+ children: d.map((t) => /* @__PURE__ */ e("option", { value: t.id, children: t.name }, t.id))
142
+ }
143
+ )
144
+ ] }),
145
+ /* @__PURE__ */ r("div", { className: "field create", children: [
146
+ /* @__PURE__ */ e("label", { htmlFor: "ws-name", children: "Workspace name" }),
147
+ /* @__PURE__ */ e("p", { className: "helper", children: "Start a fresh workspace — you'll be its admin." }),
148
+ /* @__PURE__ */ r("div", { className: "field__row", children: [
149
+ /* @__PURE__ */ e(
150
+ "input",
151
+ {
152
+ id: "ws-name",
153
+ type: "text",
154
+ placeholder: "e.g. Acme Engineering",
155
+ value: g,
156
+ onChange: (t) => b(t.target.value)
157
+ }
158
+ ),
159
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void L(), disabled: c, children: "Create workspace" })
178
160
  ] })
179
161
  ] }),
180
- /* @__PURE__ */ e(
181
- K,
182
- {
183
- workspaceId: t.id,
184
- refreshKey: R,
185
- onLeft: i,
186
- canRemove: !0
187
- }
188
- )
162
+ /* @__PURE__ */ r("div", { className: "field join", children: [
163
+ /* @__PURE__ */ e("label", { htmlFor: "invite-code", children: "Invite code" }),
164
+ /* @__PURE__ */ e("p", { className: "helper", children: "Paste an invite code someone shared to join their workspace." }),
165
+ /* @__PURE__ */ r("div", { className: "field__row", children: [
166
+ /* @__PURE__ */ e(
167
+ "input",
168
+ {
169
+ id: "invite-code",
170
+ type: "text",
171
+ placeholder: "Invite code",
172
+ value: u,
173
+ onChange: (t) => v(t.target.value)
174
+ }
175
+ ),
176
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void x(), disabled: c, children: "Join" })
177
+ ] })
178
+ ] }),
179
+ I && a && /* @__PURE__ */ r("div", { className: "admin", children: [
180
+ /* @__PURE__ */ r("div", { className: "invites", children: [
181
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void o(), disabled: c, children: "Create invite" }),
182
+ m && /* @__PURE__ */ r("div", { className: "invite-result", children: [
183
+ /* @__PURE__ */ e("code", { children: m.code }),
184
+ /* @__PURE__ */ e("a", { href: E ?? void 0, children: E }),
185
+ /* @__PURE__ */ r("span", { className: "invite-uses", children: [
186
+ m.useCount,
187
+ " / ",
188
+ m.maxUses,
189
+ " uses"
190
+ ] }),
191
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void y(), disabled: c, children: "Revoke invite" })
192
+ ] })
193
+ ] }),
194
+ /* @__PURE__ */ e(
195
+ A,
196
+ {
197
+ workspaceId: a.id,
198
+ refreshKey: R,
199
+ onLeft: l,
200
+ canRemove: !0
201
+ }
202
+ )
203
+ ] })
189
204
  ] })
190
205
  ] });
191
206
  }
192
- const P = [
207
+ const K = [
193
208
  { id: "claude", label: "Claude Code" },
194
209
  { id: "codex", label: "Codex" },
195
210
  { id: "pi", label: "Pi" },
196
211
  { id: "generic", label: "Generic (JSON)" }
197
- ], A = "shp_<paste-after-generating>", D = {
212
+ ], M = "shp_<paste-after-generating>", D = {
198
213
  claude: "claude mcp add shepherd -s user \\",
199
214
  codex: "codex mcp add shepherd \\",
200
215
  pi: "pi mcp add shepherd \\"
201
216
  };
202
- function B(c, t, i) {
203
- return c === "generic" ? JSON.stringify(
217
+ function B(d, a, l) {
218
+ return d === "generic" ? JSON.stringify(
204
219
  {
205
220
  mcpServers: {
206
221
  shepherd: {
207
222
  command: "npx",
208
223
  args: ["-y", "@korso/shepherd"],
209
- env: { HUB_URL: t, SHEPHERD_TOKEN: i }
224
+ env: { HUB_URL: a, SHEPHERD_TOKEN: l }
210
225
  }
211
226
  }
212
227
  },
213
228
  null,
214
229
  2
215
230
  ) : [
216
- D[c],
217
- ` -e HUB_URL=${t} \\`,
218
- ` -e SHEPHERD_TOKEN=${i} \\`,
231
+ D[d],
232
+ ` -e HUB_URL=${a} \\`,
233
+ ` -e SHEPHERD_TOKEN=${l} \\`,
219
234
  " -- npx -y @korso/shepherd"
220
235
  ].join(`
221
236
  `);
222
237
  }
223
- function J({ workspaceId: c, hubUrl: t }) {
224
- const i = O(), k = t ?? i.baseUrl, m = U(), [C, g] = a("claude"), [b, u] = a(""), [p, h] = a(null), [o, w] = a([]), [d, s] = a(null), [v, R] = a(null), [S, I] = a(!1), [L, x] = a(!0), [l, f] = a(null);
238
+ function G({ workspaceId: d, hubUrl: a }) {
239
+ const l = j(), k = a ?? l.baseUrl, p = O(), [N, g] = i("claude"), [b, u] = i(""), [v, m] = i(null), [s, w] = i([]), [h, c] = i(null), [f, R] = i(null), [S, I] = i(!1), [L, x] = i(!0), [o, y] = i(null);
225
240
  async function E() {
226
241
  try {
227
- const n = await i.listTokens(c);
242
+ const n = await l.listTokens(d);
228
243
  w(n.tokens);
229
244
  } catch (n) {
230
- s(N(n));
245
+ c(C(n));
231
246
  } finally {
232
247
  x(!1);
233
248
  }
234
249
  }
235
- H(() => {
250
+ _(() => {
236
251
  x(!0), E();
237
- }, [i, c]), H(() => {
238
- h(null);
239
- }, [c]);
240
- async function r() {
241
- I(!0), s(null);
252
+ }, [l, d]), _(() => {
253
+ m(null);
254
+ }, [d]);
255
+ async function t() {
256
+ I(!0), c(null);
242
257
  try {
243
- const n = await i.mintToken(
244
- c,
258
+ const n = await l.mintToken(
259
+ d,
245
260
  b.trim() ? { name: b.trim() } : {}
246
261
  );
247
- h(n.token), u(""), await E();
262
+ m(n.token), u(""), await E();
248
263
  } catch (n) {
249
- s(N(n));
264
+ c(C(n));
250
265
  } finally {
251
266
  I(!1);
252
267
  }
253
268
  }
254
- async function j(n) {
255
- if (!l) {
256
- f(n), s(null), R(null);
269
+ async function H(n) {
270
+ if (!o) {
271
+ y(n), c(null), R(null);
257
272
  try {
258
- await i.revokeToken(c, n), w((T) => T.filter((_) => _.id !== n)), R("Token revoked");
273
+ await l.revokeToken(d, n), w((T) => T.filter((U) => U.id !== n)), R("Token revoked");
259
274
  } catch (T) {
260
- s(N(T));
275
+ c(C(T));
261
276
  } finally {
262
- f(null);
277
+ y(null);
263
278
  }
264
279
  }
265
280
  }
266
- const W = B(C, k, p ?? A);
267
- return /* @__PURE__ */ y("section", { className: "shepherd-connect-agent", "aria-labelledby": m, children: [
268
- /* @__PURE__ */ e("h3", { id: m, children: "Connect your agent" }),
269
- /* @__PURE__ */ e("label", { htmlFor: "connect-tool", children: "Tool" }),
270
- /* @__PURE__ */ e(
271
- "select",
272
- {
273
- id: "connect-tool",
274
- value: C,
275
- onChange: (n) => g(n.target.value),
276
- children: P.map((n) => /* @__PURE__ */ e("option", { value: n.id, children: n.label }, n.id))
277
- }
278
- ),
279
- /* @__PURE__ */ y("div", { className: "generate", children: [
280
- /* @__PURE__ */ e("label", { htmlFor: "token-name", children: "Token name (optional)" }),
281
- /* @__PURE__ */ e(
282
- "input",
283
- {
284
- id: "token-name",
285
- type: "text",
286
- value: b,
287
- onChange: (n) => u(n.target.value),
288
- placeholder: "e.g. laptop"
289
- }
290
- ),
291
- /* @__PURE__ */ e("button", { type: "button", onClick: () => void r(), disabled: S, children: "Generate token" })
281
+ const P = B(N, k, v ?? M);
282
+ return /* @__PURE__ */ r("section", { className: "shepherd-connect-agent", "aria-labelledby": p, children: [
283
+ /* @__PURE__ */ r("div", { className: "card-head", children: [
284
+ /* @__PURE__ */ e("h3", { id: p, children: "Connect your agent" }),
285
+ /* @__PURE__ */ e("p", { className: "card-sub", children: "Generate a token, then paste the command into your coding tool." })
292
286
  ] }),
293
- d && /* @__PURE__ */ e("p", { role: "alert", children: d }),
294
- v && /* @__PURE__ */ e("p", { role: "status", children: v }),
295
- p && /* @__PURE__ */ e("p", { className: "token-once", role: "status", children: "Copy this token now — it won't be shown again." }),
296
- /* @__PURE__ */ e("pre", { "data-testid": "install-command", children: W }),
297
- /* @__PURE__ */ e("h4", { children: "Existing tokens" }),
298
- L ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : o.length === 0 ? /* @__PURE__ */ e("p", { children: "No tokens yet." }) : /* @__PURE__ */ e("ul", { children: o.map((n) => {
299
- const T = n.name ?? n.id;
300
- return /* @__PURE__ */ y("li", { children: [
301
- /* @__PURE__ */ e("span", { children: T }),
302
- n.revokedAt ? /* @__PURE__ */ e("span", { className: "revoked", children: "revoked" }) : /* @__PURE__ */ e(
303
- "button",
287
+ /* @__PURE__ */ r("div", { className: "card-body", children: [
288
+ /* @__PURE__ */ r("div", { className: "field", children: [
289
+ /* @__PURE__ */ e("label", { htmlFor: "connect-tool", children: "Tool" }),
290
+ /* @__PURE__ */ e(
291
+ "select",
304
292
  {
305
- type: "button",
306
- "aria-label": `Revoke token ${T}`,
307
- onClick: () => void j(n.id),
308
- disabled: l === n.id,
309
- children: "Revoke"
293
+ id: "connect-tool",
294
+ value: N,
295
+ onChange: (n) => g(n.target.value),
296
+ children: K.map((n) => /* @__PURE__ */ e("option", { value: n.id, children: n.label }, n.id))
310
297
  }
311
298
  )
312
- ] }, n.id);
313
- }) })
299
+ ] }),
300
+ /* @__PURE__ */ r("div", { className: "field generate", children: [
301
+ /* @__PURE__ */ e("label", { htmlFor: "token-name", children: "Token name (optional)" }),
302
+ /* @__PURE__ */ r("div", { className: "field__row", children: [
303
+ /* @__PURE__ */ e(
304
+ "input",
305
+ {
306
+ id: "token-name",
307
+ type: "text",
308
+ value: b,
309
+ onChange: (n) => u(n.target.value),
310
+ placeholder: "e.g. laptop"
311
+ }
312
+ ),
313
+ /* @__PURE__ */ e("button", { type: "button", onClick: () => void t(), disabled: S, children: "Generate token" })
314
+ ] })
315
+ ] }),
316
+ h && /* @__PURE__ */ e("p", { role: "alert", children: h }),
317
+ f && /* @__PURE__ */ e("p", { role: "status", children: f }),
318
+ v && /* @__PURE__ */ e("p", { className: "token-once", role: "status", children: "Copy this token now — it won't be shown again." }),
319
+ /* @__PURE__ */ e("pre", { "data-testid": "install-command", children: P }),
320
+ /* @__PURE__ */ e("h4", { children: "Existing tokens" }),
321
+ L ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : s.length === 0 ? /* @__PURE__ */ e("p", { children: "No tokens yet." }) : /* @__PURE__ */ e("ul", { children: s.map((n) => {
322
+ const T = n.name ?? n.id;
323
+ return /* @__PURE__ */ r("li", { children: [
324
+ /* @__PURE__ */ e("span", { children: T }),
325
+ n.revokedAt ? /* @__PURE__ */ e("span", { className: "revoked", children: "revoked" }) : /* @__PURE__ */ e(
326
+ "button",
327
+ {
328
+ type: "button",
329
+ "aria-label": `Revoke token ${T}`,
330
+ onClick: () => void H(n.id),
331
+ disabled: o === n.id,
332
+ children: "Revoke"
333
+ }
334
+ )
335
+ ] }, n.id);
336
+ }) })
337
+ ] })
314
338
  ] });
315
339
  }
316
- function z({ hubUrl: c }) {
317
- const t = O(), [i, k] = a({ status: "loading" }), [m, C] = a(null), g = F(async () => {
340
+ function z({ hubUrl: d }) {
341
+ const a = j(), [l, k] = i({ status: "loading" }), [p, N] = i(null), g = $(async () => {
318
342
  try {
319
- const o = await t.listWorkspaces();
320
- k({ status: "ready", workspaces: o.workspaces }), C(
343
+ const s = await a.listWorkspaces();
344
+ k({ status: "ready", workspaces: s.workspaces }), N(
321
345
  (w) => {
322
- var d;
323
- return w && o.workspaces.some((s) => s.id === w) ? w : ((d = o.workspaces[0]) == null ? void 0 : d.id) ?? null;
346
+ var h;
347
+ return w && s.workspaces.some((c) => c.id === w) ? w : ((h = s.workspaces[0]) == null ? void 0 : h.id) ?? null;
324
348
  }
325
349
  );
326
- } catch (o) {
327
- k({ status: "error", message: N(o) });
350
+ } catch (s) {
351
+ k({ status: "error", message: C(s) });
328
352
  }
329
- }, [t]);
330
- H(() => {
353
+ }, [a]);
354
+ _(() => {
331
355
  g();
332
356
  }, [g]);
333
- const b = i.status === "ready" ? i.workspaces : [], u = b.find((o) => o.id === m) ?? null;
334
- if (i.status === "loading")
357
+ const b = l.status === "ready" ? l.workspaces : [], u = b.find((s) => s.id === p) ?? null;
358
+ if (l.status === "loading")
335
359
  return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) });
336
- if (i.status === "error")
337
- return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e("p", { role: "alert", children: i.message }) });
338
- const p = b.length > 0, h = /* @__PURE__ */ y("section", { className: "shepherd-config", "aria-labelledby": "config-heading", children: [
360
+ if (l.status === "error")
361
+ return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e("p", { role: "alert", children: l.message }) });
362
+ const v = b.length > 0, m = /* @__PURE__ */ r("section", { className: "shepherd-config", "aria-labelledby": "config-heading", children: [
339
363
  /* @__PURE__ */ e("h2", { id: "config-heading", children: "Configuration" }),
340
364
  /* @__PURE__ */ e(
341
- M,
365
+ F,
342
366
  {
343
367
  workspaces: b,
344
368
  selected: u,
345
369
  onChanged: () => {
346
370
  g();
347
371
  },
348
- onSelect: C
372
+ onSelect: N
349
373
  }
350
374
  ),
351
- u && /* @__PURE__ */ e(J, { workspaceId: u.id, hubUrl: c })
375
+ u && /* @__PURE__ */ e(G, { workspaceId: u.id, hubUrl: d })
352
376
  ] });
353
377
  return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e(
354
- $,
378
+ W,
355
379
  {
356
380
  workspaceId: u == null ? void 0 : u.id,
357
- config: h,
358
- hasWorkspace: p
381
+ config: m,
382
+ hasWorkspace: v
359
383
  }
360
384
  ) });
361
385
  }
362
386
  export {
363
- J as ConnectAgent,
364
- $ as Dashboard,
387
+ G as ConnectAgent,
388
+ W as Dashboard,
365
389
  Y as EmptyState,
366
- K as Members,
390
+ A as Members,
367
391
  Z as ShepherdClientError,
368
392
  ee as ShepherdClientProvider,
369
393
  z as ShepherdRoot,
370
- M as Workspaces,
394
+ F as Workspaces,
371
395
  ne as createShepherdClient,
372
- N as describeError,
373
- O as useShepherdClient
396
+ C as describeError,
397
+ j as useShepherdClient
374
398
  };
@@ -12,9 +12,7 @@
12
12
  }
13
13
  .wrap { max-width:1100px; margin:0 auto; padding:40px 44px; }
14
14
 
15
- header { display:flex; align-items:center; gap:12px; padding-bottom:18px; border-bottom:1px solid var(--line); }
16
- /* Chat view: the card supplies its own border, so the header rule is redundant. */
17
- #board:has(#panel-chat:not([hidden])) header { border-bottom:0; }
15
+ header { display:flex; align-items:center; gap:12px; padding-bottom:18px; }
18
16
  .brand { font-size:17px; font-weight:600; }
19
17
  .vitals { color:var(--ink3); font-size:12.5px; }
20
18
  .grow { flex:1; }
@@ -181,33 +179,70 @@
181
179
  .gate button { padding:10px 16px; border-radius:8px; border:1px solid var(--ink);
182
180
  background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; }
183
181
 
184
- /* --- Multi-workspace hosted shell + config surface (functional, not polished;
185
- a dedicated styling sub-project refines this). Reuses the board's tokens. --- */
182
+ /* --- Multi-workspace hosted shell + config surface. Reuses the board's
183
+ tokens and its editorial vocabulary (uppercase micro-labels echoing the
184
+ column heads, hairline rules) so Config reads as part of the board. --- */
186
185
  .shepherd-root { max-width:1100px; margin:0 auto; padding:40px 44px; }
187
186
  .shepherd-root > main { padding-top:18px; }
188
187
  .shepherd-config { display:flex; flex-direction:column; gap:24px; }
189
188
  .shepherd-config h2 { font-size:16px; margin:0 0 4px; }
189
+
190
+ /* Every config card shares one shell: a header band sitting on a hairline
191
+ above a padded body. Nested cards (Members) reuse the same anatomy. */
190
192
  .shepherd-workspaces, .shepherd-members, .shepherd-connect-agent {
191
- display:flex; flex-direction:column; gap:10px;
192
- padding:16px; border:1px solid var(--line); border-radius:10px; background:var(--card); }
193
- .shepherd-workspaces .switcher { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
194
- .shepherd-workspaces .role { color:var(--ink3); font-size:12px; }
195
- .shepherd-workspaces .admin, .shepherd-workspaces .invites { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
196
- /* Create-workspace + join-by-code rows: label, input, then action button on
197
- one line. A fixed-width label column aligns the two rows' inputs vertically. */
198
- .shepherd-workspaces .create, .shepherd-workspaces .join {
199
- display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
200
- .shepherd-workspaces .create > label, .shepherd-workspaces .join > label,
201
- .shepherd-workspaces .switcher > label { min-width:104px; color:var(--ink2); }
202
- .shepherd-workspaces .create > input, .shepherd-workspaces .join > input {
203
- flex:1; min-width:180px; }
193
+ border:1px solid var(--line); border-radius:12px; background:var(--card); overflow:hidden; }
194
+ .shepherd-config .card-head { padding:18px 20px 14px; border-bottom:1px solid var(--line2); }
195
+ .shepherd-config .card-head h3 { font-size:14px; font-weight:600; margin:0; }
196
+ .shepherd-config .card-sub { margin:3px 0 0; font-size:12.5px; color:var(--ink3); }
197
+ .shepherd-config .card-body { padding:16px 20px 18px; display:flex; flex-direction:column; gap:16px; }
198
+ .shepherd-config .card-body > [role="alert"] { margin:0; color:var(--drop); font-size:13px; }
199
+ .shepherd-config .card-body > [role="status"] { margin:0; color:var(--ink2); font-size:13px; }
200
+
201
+ /* A field: uppercase eyebrow label, optional helper, then input(s) + action
202
+ on one row. Labels borrow the board's .colhead h2 treatment. */
203
+ .shepherd-config .field { display:flex; flex-direction:column; gap:8px; }
204
+ .shepherd-config .card-body label {
205
+ font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
206
+ .shepherd-config .helper { margin:0; font-size:12.5px; color:var(--ink2); }
207
+ .shepherd-config .field > select { width:100%; }
208
+ .shepherd-config .field__row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
209
+ .shepherd-config .field__row > input { flex:1; min-width:200px; }
210
+
211
+ /* Admin zone (invites + roster) is set off from create/join by a hairline. */
212
+ .shepherd-workspaces .admin { display:flex; flex-direction:column; gap:14px;
213
+ padding-top:16px; border-top:1px solid var(--line2); }
214
+ .shepherd-workspaces .invites { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
215
+
204
216
  .shepherd-config input, .shepherd-config select {
205
- padding:8px 10px; border-radius:8px; border:1px solid var(--line);
206
- background:var(--bg); color:var(--ink); }
217
+ padding:9px 12px; border-radius:8px; border:1px solid var(--line);
218
+ background:var(--bg); color:var(--ink); font:inherit;
219
+ transition:border-color .12s ease, box-shadow .12s ease; }
220
+ .shepherd-config input::placeholder { color:var(--ink3); }
221
+ .shepherd-config input:focus, .shepherd-config select:focus {
222
+ outline:none; border-color:var(--terr); box-shadow:0 0 0 3px rgba(122,106,72,.14); }
207
223
  .shepherd-config button {
208
- padding:8px 14px; border-radius:8px; border:1px solid var(--ink);
209
- background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; }
224
+ padding:9px 16px; border-radius:8px; border:1px solid var(--ink);
225
+ background:var(--ink); color:var(--bg); font-weight:600; cursor:pointer; font:inherit;
226
+ white-space:nowrap; transition:background .12s ease; }
227
+ .shepherd-config button:hover:not(:disabled) { background:#413a2a; }
210
228
  .shepherd-config button:disabled { opacity:.55; cursor:default; }
229
+
230
+ /* Token / member rows: leading name grows, meta + action ride the right. */
231
+ .shepherd-config ul { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; }
232
+ .shepherd-config li { display:flex; align-items:center; gap:10px; padding:8px 12px;
233
+ border:1px solid var(--line2); border-radius:8px; background:var(--bg); font-size:13px; }
234
+ .shepherd-config li > span:first-child { flex:1; min-width:0; font-weight:500; }
235
+ .shepherd-config li button { padding:5px 12px; }
236
+ .shepherd-config .role { color:var(--ink3); font-size:12px; }
237
+
238
+ /* Install command block. */
239
+ .shepherd-connect-agent pre { margin:0; padding:12px 14px; border-radius:8px;
240
+ border:1px solid var(--line); background:var(--bg); color:var(--ink);
241
+ font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px; line-height:1.5;
242
+ overflow-x:auto; white-space:pre-wrap; word-break:break-word; }
243
+ .shepherd-connect-agent h4 { margin:6px 0 0; font-size:11px; font-weight:600;
244
+ letter-spacing:.05em; text-transform:uppercase; color:var(--ink3); }
245
+
211
246
  .shepherd-config .invite-result, .shepherd-connect-agent .token-once {
212
247
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px;
213
248
  word-break:break-all; padding:8px 10px; border-radius:8px;
@@ -0,0 +1 @@
1
+ :root{--bg:#ece0c6;--ink:#322c20;--ink2:#6f6450;--ink3:#9c917a;--line:#d7c9ac;--line2:#e0d4b9;--live:#3d8b58;--drop:#bd4f3a;--chip:#e3d6ba;--terr:#7a6a48;--card:#f5ecd9}*{box-sizing:border-box}html,body{height:100%}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}.wrap{max-width:1100px;margin:0 auto;padding:40px 44px}header{display:flex;align-items:center;gap:12px;padding-bottom:18px}.brand{font-size:17px;font-weight:600}.vitals{color:var(--ink3);font-size:12.5px}.grow{flex:1}.status{font-size:12px;color:var(--ink3)}.status--ok{color:var(--live)}.status--warn{color:var(--terr)}.status--error{color:var(--drop)}.freshness{font-size:12px;color:var(--ink3)}.repo{position:relative}.repo-trig{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-family:inherit;color:var(--ink);-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid var(--line);border-radius:8px;padding:4px 10px;background:#fffaee66;cursor:pointer}.repo-trig .slash{color:var(--ink3)}.repo-menu{position:absolute;top:36px;left:0;min-width:200px;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:5px;box-shadow:0 8px 24px #32281424;z-index:5}.repo-mi{display:flex;justify-content:space-between;gap:14px;padding:7px 9px;width:100%;text-align:left;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:inherit;color:inherit;background:transparent;border-radius:7px;font-size:13px;cursor:pointer}.repo-mi:hover{background:var(--chip)}.repo-mi.on{background:var(--chip);font-weight:600}.repo-mi .ct{font-size:11px;color:var(--ink3)}.repo-mi.all{border-top:1px solid var(--line2);margin-top:4px;padding-top:9px;color:var(--ink2)}.tabs{display:flex;gap:4px;margin-left:auto}.tab{font-size:13px;color:var(--ink2);padding:5px 11px;border:0;border-radius:7px;background:transparent;cursor:pointer;font:inherit}.tab--active{background:var(--ink);color:var(--bg)}.crew{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:26px 0 32px}.person{display:inline-flex;align-items:center;gap:9px;padding:5px 13px 5px 5px;border:1px solid var(--line);border-radius:999px;background:var(--card);font-size:13px}.person--idle{opacity:.55}.avatar{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:10px;font-weight:700;color:#fff;flex:none}.person__name{font-weight:600}.person__doing{color:var(--ink3);font-size:12px}.board{display:grid;grid-template-columns:1fr 1px 1fr;gap:0}.board__rule{background:var(--line)}.col{padding:0 36px}.col:first-child{padding-left:0}.col:last-child{padding-right:0}.colhead{display:flex;align-items:center;gap:8px;margin-bottom:6px}.colhead h2{font-size:12px;font-weight:600;letter-spacing:.03em;margin:0;text-transform:uppercase;color:var(--ink2)}.colhead .n{font-size:11px;color:var(--ink3);background:var(--chip);border-radius:999px;padding:1px 8px}.task{padding:16px 0;border-bottom:1px solid var(--line2)}.task__r1{display:flex;align-items:center;gap:8px}.task__who{font-size:13.5px;font-weight:600}.task__tag{font-size:11px;color:var(--ink3)}.task__repo{font-size:11px;color:var(--terr);background:#7a6a481a;border-radius:4px;padding:0 6px}.task__stat{margin-left:auto;font-size:11px;font-weight:500;color:var(--ink3)}.task__stat--drop{color:var(--drop)}.livedot{width:7px;height:7px;border-radius:50%;background:var(--live);margin-left:auto}.task__intent{font-size:13.5px;margin:5px 0 0;line-height:1.45}.terr{margin-top:8px;display:flex;flex-wrap:wrap;gap:6px;align-items:center}.terr__lbl{font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink3)}.glob{font-family:ui-monospace,Menlo,monospace;font-size:11px;color:var(--terr);background:#7a6a481f;border:1px solid rgba(122,106,72,.22);border-radius:5px;padding:1px 7px}.task__meta{font-size:11.5px;color:var(--ink3);margin-top:6px}.terrx{margin-top:8px}.terrx summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:6px;flex-wrap:wrap;-webkit-user-select:none;user-select:none}.terrx summary::-webkit-details-marker{display:none}.terrx .terr--full{margin-top:8px}.glob--more{cursor:pointer;color:var(--ink2);background:var(--chip);border:1px solid var(--line)}.glob--more .tw{color:var(--ink3);display:inline-block;transition:transform .15s}.terrx[open] summary .glob--more .tw{transform:rotate(90deg)}.grp{padding:16px 0;border-bottom:1px solid var(--line2)}.grp__head{display:flex;align-items:center;gap:8px}.grp__who{font-size:13.5px;font-weight:600}.grp__tag,.grp__count{font-size:11px;color:var(--ink3)}.grp__dot{width:7px;height:7px;border-radius:50%;background:var(--live);margin-left:auto}.claims{margin:10px 0 0 6px;padding-left:14px;border-left:1px solid var(--line)}.claim{padding:6px 0}.claim+.claim{border-top:1px solid var(--line2);margin-top:6px}.fold{margin-top:10px}.fold summary{list-style:none;cursor:pointer;font-size:12px;color:var(--ink2);display:inline-flex;align-items:center;gap:6px;-webkit-user-select:none;user-select:none}.fold summary::-webkit-details-marker{display:none}.fold summary .tw{display:inline-block;color:var(--ink3);transition:transform .15s}.fold[open] summary .tw{transform:rotate(90deg)}.fold__body{margin:8px 0 0 6px;padding-left:14px;border-left:1px dashed var(--line)}.covered{font-size:10.5px;color:var(--ink3);font-style:italic;margin-top:4px}.day{font-size:11px;color:var(--ink3);padding:18px 0 2px;font-weight:600}.more{margin-top:20px;font-size:12.5px;color:var(--ink2);padding:7px 13px;border:1px solid var(--line);border-radius:8px;background:#fffaee59;cursor:pointer}.empty{color:var(--ink3);font-style:italic;padding:14px 0}.chat-wrap{background:var(--card);border:1px solid var(--line);border-radius:12px;display:flex;flex-direction:column;overflow:hidden;height:calc(100vh - 150px);min-height:320px}.chat{flex:1;overflow-y:auto;padding:16px}.chat{scrollbar-width:thin;scrollbar-color:var(--line) transparent}.chat::-webkit-scrollbar{width:10px}.chat::-webkit-scrollbar-track{background:transparent}.chat::-webkit-scrollbar-thumb{background:var(--line);border-radius:999px;border:3px solid var(--card);background-clip:padding-box}.chat::-webkit-scrollbar-thumb:hover{background:var(--ink3);background-clip:padding-box}.chat__note{padding:9px 16px;font-size:11.5px;color:var(--ink3)}.msg{display:flex;gap:11px;padding:9px 0}.msg__avatar{flex:none;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:700;color:#fff}.msg__body{min-width:0;flex:1}.msg__head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.msg__who{font-weight:600}.msg__human{font-size:12px;color:var(--ink3)}.msg__to{font-size:11.5px;color:var(--terr)}.msg__time{font-size:11.5px;color:var(--ink3);margin-left:auto}.msg__text{margin-top:3px;padding:8px 12px;border-radius:4px 12px 12px;background:var(--chip);white-space:pre-wrap;word-break:break-word}.msg--targeted .msg__text{box-shadow:inset 3px 0 0 var(--terr)}.msg--me,.msg--me .msg__head{flex-direction:row-reverse}.msg--me .msg__time{margin-left:0;margin-right:auto}.msg--me .msg__body{display:flex;flex-direction:column;align-items:flex-end}.msg--me .msg__text{border-radius:12px 4px 12px 12px;background:#d4e7d2}.msg--me.msg--targeted .msg__text{box-shadow:inset -3px 0 0 var(--terr)}.composer{position:relative;border-top:1px solid var(--line);padding:10px 12px}.chat-form{display:flex;gap:8px}.chat-input{flex:1;padding:9px 12px;border-radius:8px;border:1px solid var(--line);background:var(--bg);color:var(--ink);font:inherit}.chat-input:focus{outline:none;border-color:var(--terr)}.chat-send{padding:9px 16px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer;font:inherit}.chat-send:disabled{opacity:.5;cursor:default}.mention-pop{position:absolute;left:12px;right:12px;bottom:56px;z-index:6;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:5px;box-shadow:0 8px 24px #32281429;max-height:200px;overflow-y:auto}.mention-mi{display:flex;align-items:center;gap:9px;width:100%;text-align:left;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:inherit;color:inherit;background:transparent;border-radius:7px;padding:6px 8px;font-size:13px;cursor:pointer}.mention-mi:hover,.mention-mi.on{background:var(--chip)}.mention-mi .ma{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:9px;font-weight:700;color:#fff;flex:none}.gate{max-width:420px;margin:12vh auto 0;text-align:center}.gate h1{font-size:19px;margin:0 0 6px}.gate p{color:var(--ink2);margin:0 0 20px}.gate form{display:flex;gap:8px}.gate input{flex:1;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--card);color:var(--ink)}.gate button{padding:10px 16px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer}.shepherd-root{max-width:1100px;margin:0 auto;padding:40px 44px}.shepherd-root>main{padding-top:18px}.shepherd-config{display:flex;flex-direction:column;gap:24px}.shepherd-config h2{font-size:16px;margin:0 0 4px}.shepherd-workspaces,.shepherd-members,.shepherd-connect-agent{border:1px solid var(--line);border-radius:12px;background:var(--card);overflow:hidden}.shepherd-config .card-head{padding:18px 20px 14px;border-bottom:1px solid var(--line2)}.shepherd-config .card-head h3{font-size:14px;font-weight:600;margin:0}.shepherd-config .card-sub{margin:3px 0 0;font-size:12.5px;color:var(--ink3)}.shepherd-config .card-body{padding:16px 20px 18px;display:flex;flex-direction:column;gap:16px}.shepherd-config .card-body>[role=alert]{margin:0;color:var(--drop);font-size:13px}.shepherd-config .card-body>[role=status]{margin:0;color:var(--ink2);font-size:13px}.shepherd-config .field{display:flex;flex-direction:column;gap:8px}.shepherd-config .card-body label{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--ink3)}.shepherd-config .helper{margin:0;font-size:12.5px;color:var(--ink2)}.shepherd-config .field>select{width:100%}.shepherd-config .field__row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.shepherd-config .field__row>input{flex:1;min-width:200px}.shepherd-workspaces .admin{display:flex;flex-direction:column;gap:14px;padding-top:16px;border-top:1px solid var(--line2)}.shepherd-workspaces .invites{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.shepherd-config input,.shepherd-config select{padding:9px 12px;border-radius:8px;border:1px solid var(--line);background:var(--bg);color:var(--ink);font:inherit;transition:border-color .12s ease,box-shadow .12s ease}.shepherd-config input::placeholder{color:var(--ink3)}.shepherd-config input:focus,.shepherd-config select:focus{outline:none;border-color:var(--terr);box-shadow:0 0 0 3px #7a6a4824}.shepherd-config button{padding:9px 16px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer;font:inherit;white-space:nowrap;transition:background .12s ease}.shepherd-config button:hover:not(:disabled){background:#413a2a}.shepherd-config button:disabled{opacity:.55;cursor:default}.shepherd-config ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.shepherd-config li{display:flex;align-items:center;gap:10px;padding:8px 12px;border:1px solid var(--line2);border-radius:8px;background:var(--bg);font-size:13px}.shepherd-config li>span:first-child{flex:1;min-width:0;font-weight:500}.shepherd-config li button{padding:5px 12px}.shepherd-config .role{color:var(--ink3);font-size:12px}.shepherd-connect-agent pre{margin:0;padding:12px 14px;border-radius:8px;border:1px solid var(--line);background:var(--bg);color:var(--ink);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;overflow-x:auto;white-space:pre-wrap;word-break:break-word}.shepherd-connect-agent h4{margin:6px 0 0;font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--ink3)}.shepherd-config .invite-result,.shepherd-connect-agent .token-once{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all;padding:8px 10px;border-radius:8px;background:var(--chip);border:1px solid var(--line2)}.shepherd-config .revoked{color:var(--ink3);text-decoration:line-through}.shepherd-empty-state{text-align:center;color:var(--ink2);padding:48px 24px}.shepherd-empty-state button{margin-top:14px}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Shepherd</title>
7
- <script type="module" crossorigin src="/assets/index-D6rTsbVM.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-DnhlP_lc.css">
7
+ <script type="module" crossorigin src="/assets/index-COMbJ-a4.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CcGvL65Q.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@korso/shepherd-ui",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Auth-agnostic React UI library for the Shepherd wallboard (Dashboard, client, provider). Host injects auth; the library never reads tokens.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/Korsoai/shepherd.git",
12
+ "url": "git+https://github.com/Korso-AI/shepherd.git",
13
13
  "directory": "packages/ui"
14
14
  },
15
15
  "exports": {
@@ -1 +0,0 @@
1
- :root{--bg:#ece0c6;--ink:#322c20;--ink2:#6f6450;--ink3:#9c917a;--line:#d7c9ac;--line2:#e0d4b9;--live:#3d8b58;--drop:#bd4f3a;--chip:#e3d6ba;--terr:#7a6a48;--card:#f5ecd9}*{box-sizing:border-box}html,body{height:100%}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}.wrap{max-width:1100px;margin:0 auto;padding:40px 44px}header{display:flex;align-items:center;gap:12px;padding-bottom:18px;border-bottom:1px solid var(--line)}#board:has(#panel-chat:not([hidden])) header{border-bottom:0}.brand{font-size:17px;font-weight:600}.vitals{color:var(--ink3);font-size:12.5px}.grow{flex:1}.status{font-size:12px;color:var(--ink3)}.status--ok{color:var(--live)}.status--warn{color:var(--terr)}.status--error{color:var(--drop)}.freshness{font-size:12px;color:var(--ink3)}.repo{position:relative}.repo-trig{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-family:inherit;color:var(--ink);-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid var(--line);border-radius:8px;padding:4px 10px;background:#fffaee66;cursor:pointer}.repo-trig .slash{color:var(--ink3)}.repo-menu{position:absolute;top:36px;left:0;min-width:200px;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:5px;box-shadow:0 8px 24px #32281424;z-index:5}.repo-mi{display:flex;justify-content:space-between;gap:14px;padding:7px 9px;width:100%;text-align:left;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:inherit;color:inherit;background:transparent;border-radius:7px;font-size:13px;cursor:pointer}.repo-mi:hover{background:var(--chip)}.repo-mi.on{background:var(--chip);font-weight:600}.repo-mi .ct{font-size:11px;color:var(--ink3)}.repo-mi.all{border-top:1px solid var(--line2);margin-top:4px;padding-top:9px;color:var(--ink2)}.tabs{display:flex;gap:4px;margin-left:auto}.tab{font-size:13px;color:var(--ink2);padding:5px 11px;border:0;border-radius:7px;background:transparent;cursor:pointer;font:inherit}.tab--active{background:var(--ink);color:var(--bg)}.crew{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:26px 0 32px}.person{display:inline-flex;align-items:center;gap:9px;padding:5px 13px 5px 5px;border:1px solid var(--line);border-radius:999px;background:var(--card);font-size:13px}.person--idle{opacity:.55}.avatar{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:10px;font-weight:700;color:#fff;flex:none}.person__name{font-weight:600}.person__doing{color:var(--ink3);font-size:12px}.board{display:grid;grid-template-columns:1fr 1px 1fr;gap:0}.board__rule{background:var(--line)}.col{padding:0 36px}.col:first-child{padding-left:0}.col:last-child{padding-right:0}.colhead{display:flex;align-items:center;gap:8px;margin-bottom:6px}.colhead h2{font-size:12px;font-weight:600;letter-spacing:.03em;margin:0;text-transform:uppercase;color:var(--ink2)}.colhead .n{font-size:11px;color:var(--ink3);background:var(--chip);border-radius:999px;padding:1px 8px}.task{padding:16px 0;border-bottom:1px solid var(--line2)}.task__r1{display:flex;align-items:center;gap:8px}.task__who{font-size:13.5px;font-weight:600}.task__tag{font-size:11px;color:var(--ink3)}.task__repo{font-size:11px;color:var(--terr);background:#7a6a481a;border-radius:4px;padding:0 6px}.task__stat{margin-left:auto;font-size:11px;font-weight:500;color:var(--ink3)}.task__stat--drop{color:var(--drop)}.livedot{width:7px;height:7px;border-radius:50%;background:var(--live);margin-left:auto}.task__intent{font-size:13.5px;margin:5px 0 0;line-height:1.45}.terr{margin-top:8px;display:flex;flex-wrap:wrap;gap:6px;align-items:center}.terr__lbl{font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink3)}.glob{font-family:ui-monospace,Menlo,monospace;font-size:11px;color:var(--terr);background:#7a6a481f;border:1px solid rgba(122,106,72,.22);border-radius:5px;padding:1px 7px}.task__meta{font-size:11.5px;color:var(--ink3);margin-top:6px}.terrx{margin-top:8px}.terrx summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:6px;flex-wrap:wrap;-webkit-user-select:none;user-select:none}.terrx summary::-webkit-details-marker{display:none}.terrx .terr--full{margin-top:8px}.glob--more{cursor:pointer;color:var(--ink2);background:var(--chip);border:1px solid var(--line)}.glob--more .tw{color:var(--ink3);display:inline-block;transition:transform .15s}.terrx[open] summary .glob--more .tw{transform:rotate(90deg)}.grp{padding:16px 0;border-bottom:1px solid var(--line2)}.grp__head{display:flex;align-items:center;gap:8px}.grp__who{font-size:13.5px;font-weight:600}.grp__tag,.grp__count{font-size:11px;color:var(--ink3)}.grp__dot{width:7px;height:7px;border-radius:50%;background:var(--live);margin-left:auto}.claims{margin:10px 0 0 6px;padding-left:14px;border-left:1px solid var(--line)}.claim{padding:6px 0}.claim+.claim{border-top:1px solid var(--line2);margin-top:6px}.fold{margin-top:10px}.fold summary{list-style:none;cursor:pointer;font-size:12px;color:var(--ink2);display:inline-flex;align-items:center;gap:6px;-webkit-user-select:none;user-select:none}.fold summary::-webkit-details-marker{display:none}.fold summary .tw{display:inline-block;color:var(--ink3);transition:transform .15s}.fold[open] summary .tw{transform:rotate(90deg)}.fold__body{margin:8px 0 0 6px;padding-left:14px;border-left:1px dashed var(--line)}.covered{font-size:10.5px;color:var(--ink3);font-style:italic;margin-top:4px}.day{font-size:11px;color:var(--ink3);padding:18px 0 2px;font-weight:600}.more{margin-top:20px;font-size:12.5px;color:var(--ink2);padding:7px 13px;border:1px solid var(--line);border-radius:8px;background:#fffaee59;cursor:pointer}.empty{color:var(--ink3);font-style:italic;padding:14px 0}.chat-wrap{background:var(--card);border:1px solid var(--line);border-radius:12px;display:flex;flex-direction:column;overflow:hidden;height:calc(100vh - 150px);min-height:320px}.chat{flex:1;overflow-y:auto;padding:16px}.chat{scrollbar-width:thin;scrollbar-color:var(--line) transparent}.chat::-webkit-scrollbar{width:10px}.chat::-webkit-scrollbar-track{background:transparent}.chat::-webkit-scrollbar-thumb{background:var(--line);border-radius:999px;border:3px solid var(--card);background-clip:padding-box}.chat::-webkit-scrollbar-thumb:hover{background:var(--ink3);background-clip:padding-box}.chat__note{padding:9px 16px;font-size:11.5px;color:var(--ink3)}.msg{display:flex;gap:11px;padding:9px 0}.msg__avatar{flex:none;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:700;color:#fff}.msg__body{min-width:0;flex:1}.msg__head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.msg__who{font-weight:600}.msg__human{font-size:12px;color:var(--ink3)}.msg__to{font-size:11.5px;color:var(--terr)}.msg__time{font-size:11.5px;color:var(--ink3);margin-left:auto}.msg__text{margin-top:3px;padding:8px 12px;border-radius:4px 12px 12px;background:var(--chip);white-space:pre-wrap;word-break:break-word}.msg--targeted .msg__text{box-shadow:inset 3px 0 0 var(--terr)}.msg--me,.msg--me .msg__head{flex-direction:row-reverse}.msg--me .msg__time{margin-left:0;margin-right:auto}.msg--me .msg__body{display:flex;flex-direction:column;align-items:flex-end}.msg--me .msg__text{border-radius:12px 4px 12px 12px;background:#d4e7d2}.msg--me.msg--targeted .msg__text{box-shadow:inset -3px 0 0 var(--terr)}.composer{position:relative;border-top:1px solid var(--line);padding:10px 12px}.chat-form{display:flex;gap:8px}.chat-input{flex:1;padding:9px 12px;border-radius:8px;border:1px solid var(--line);background:var(--bg);color:var(--ink);font:inherit}.chat-input:focus{outline:none;border-color:var(--terr)}.chat-send{padding:9px 16px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer;font:inherit}.chat-send:disabled{opacity:.5;cursor:default}.mention-pop{position:absolute;left:12px;right:12px;bottom:56px;z-index:6;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:5px;box-shadow:0 8px 24px #32281429;max-height:200px;overflow-y:auto}.mention-mi{display:flex;align-items:center;gap:9px;width:100%;text-align:left;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:inherit;color:inherit;background:transparent;border-radius:7px;padding:6px 8px;font-size:13px;cursor:pointer}.mention-mi:hover,.mention-mi.on{background:var(--chip)}.mention-mi .ma{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:9px;font-weight:700;color:#fff;flex:none}.gate{max-width:420px;margin:12vh auto 0;text-align:center}.gate h1{font-size:19px;margin:0 0 6px}.gate p{color:var(--ink2);margin:0 0 20px}.gate form{display:flex;gap:8px}.gate input{flex:1;padding:10px 12px;border-radius:8px;border:1px solid var(--line);background:var(--card);color:var(--ink)}.gate button{padding:10px 16px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer}.shepherd-root{max-width:1100px;margin:0 auto;padding:40px 44px}.shepherd-root>main{padding-top:18px}.shepherd-config{display:flex;flex-direction:column;gap:24px}.shepherd-config h2{font-size:16px;margin:0 0 4px}.shepherd-workspaces,.shepherd-members,.shepherd-connect-agent{display:flex;flex-direction:column;gap:10px;padding:16px;border:1px solid var(--line);border-radius:10px;background:var(--card)}.shepherd-workspaces .switcher{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.shepherd-workspaces .role{color:var(--ink3);font-size:12px}.shepherd-workspaces .admin,.shepherd-workspaces .invites,.shepherd-workspaces .create,.shepherd-workspaces .join{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.shepherd-workspaces .create>label,.shepherd-workspaces .join>label,.shepherd-workspaces .switcher>label{min-width:104px;color:var(--ink2)}.shepherd-workspaces .create>input,.shepherd-workspaces .join>input{flex:1;min-width:180px}.shepherd-config input,.shepherd-config select{padding:8px 10px;border-radius:8px;border:1px solid var(--line);background:var(--bg);color:var(--ink)}.shepherd-config button{padding:8px 14px;border-radius:8px;border:1px solid var(--ink);background:var(--ink);color:var(--bg);font-weight:600;cursor:pointer}.shepherd-config button:disabled{opacity:.55;cursor:default}.shepherd-config .invite-result,.shepherd-connect-agent .token-once{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all;padding:8px 10px;border-radius:8px;background:var(--chip);border:1px solid var(--line2)}.shepherd-config .revoked{color:var(--ink3);text-decoration:line-through}.shepherd-empty-state{text-align:center;color:var(--ink2);padding:48px 24px}.shepherd-empty-state button{margin-top:14px}