@korso/shepherd-ui 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/ConnectAgent.js +47 -1
- package/dist/lib/index.js +320 -282
- package/package.json +1 -1
|
@@ -25,6 +25,45 @@ const ENV_FLAG = {
|
|
|
25
25
|
claude: "-e",
|
|
26
26
|
codex: "--env",
|
|
27
27
|
};
|
|
28
|
+
// The shepherd-inbox-hook bin: delivers teammate announcements out-of-band AND
|
|
29
|
+
// nudges the agent to run `link` before its first write in an unlinked repo.
|
|
30
|
+
// Neither `claude mcp add` nor `codex mcp add` can install hooks, so the
|
|
31
|
+
// snippet is a paste-into-config block surfaced next to the install command.
|
|
32
|
+
// Cursor has no hook mechanism; Pi uses the bundled extension (see the
|
|
33
|
+
// @korso/shepherd README) — neither gets a snippet here.
|
|
34
|
+
const HOOK_COMMAND = "npx -y --package=@korso/shepherd shepherd-inbox-hook";
|
|
35
|
+
function hookSnippet(tool) {
|
|
36
|
+
if (tool === "claude") {
|
|
37
|
+
// SessionStart front-loads the link ask; PreToolUse delivers announcements
|
|
38
|
+
// and re-nudges right before a write in a still-unlinked repo.
|
|
39
|
+
return {
|
|
40
|
+
target: "~/.claude/settings.json",
|
|
41
|
+
snippet: JSON.stringify({
|
|
42
|
+
hooks: {
|
|
43
|
+
SessionStart: [{ hooks: [{ type: "command", command: HOOK_COMMAND }] }],
|
|
44
|
+
PreToolUse: [
|
|
45
|
+
{ matcher: "*", hooks: [{ type: "command", command: HOOK_COMMAND }] },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
}, null, 2),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (tool === "codex") {
|
|
52
|
+
// Codex's PreToolUse only fires for Bash, so UserPromptSubmit is the
|
|
53
|
+
// frequent event there; hooks must be feature-flagged on.
|
|
54
|
+
return {
|
|
55
|
+
target: "~/.codex/config.toml",
|
|
56
|
+
snippet: [
|
|
57
|
+
"[features]",
|
|
58
|
+
"hooks = true",
|
|
59
|
+
"",
|
|
60
|
+
"[[hooks.UserPromptSubmit]]",
|
|
61
|
+
'command = ["npx", "-y", "--package=@korso/shepherd", "shepherd-inbox-hook"]',
|
|
62
|
+
].join("\n"),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
28
67
|
// "created 3d ago · never used" / "created 3d ago · last used 2h ago" — helps
|
|
29
68
|
// an operator tell which tokens are still active before revoking one.
|
|
30
69
|
function tokenMeta(token, nowMs) {
|
|
@@ -105,6 +144,7 @@ export function ConnectAgent({ hubUrl }) {
|
|
|
105
144
|
async function generate() {
|
|
106
145
|
setBusy(true);
|
|
107
146
|
setError(null);
|
|
147
|
+
setStatus(null);
|
|
108
148
|
try {
|
|
109
149
|
const res = await client.mintAccountToken(name.trim() ? { name: name.trim() } : {});
|
|
110
150
|
setRawToken(res.token);
|
|
@@ -137,12 +177,18 @@ export function ConnectAgent({ hubUrl }) {
|
|
|
137
177
|
}
|
|
138
178
|
}
|
|
139
179
|
const command = installCommand(tool, directHubUrl, rawToken ?? TOKEN_PLACEHOLDER);
|
|
180
|
+
const hook = hookSnippet(tool);
|
|
140
181
|
async function copyCommand() {
|
|
141
182
|
await navigator.clipboard.writeText(command);
|
|
142
183
|
setCopied(true);
|
|
143
184
|
setTimeout(() => setCopied(false), 2000);
|
|
144
185
|
}
|
|
145
|
-
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 \u2014 it works across all your workspaces \u2014 then paste the command into your coding tool." }), _jsx("p", { className: "card-sub", children: "The first time the agent opens a repo, it'll ask which workspace to coordinate that repo with." })] }), _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),
|
|
186
|
+
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 \u2014 it works across all your workspaces \u2014 then paste the command into your coding tool." }), _jsx("p", { className: "card-sub", children: "The first time the agent opens a repo, it'll ask which workspace to coordinate that repo with." })] }), _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), onKeyDown: (e) => {
|
|
187
|
+
if (e.key === "Enter" && !busy) {
|
|
188
|
+
e.preventDefault();
|
|
189
|
+
void generate();
|
|
190
|
+
}
|
|
191
|
+
}, 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." })), _jsxs("div", { className: "install-command", children: [_jsx("pre", { "data-testid": "install-command", children: command }), _jsx("button", { type: "button", className: "install-command__copy", "aria-label": copied ? "Copied" : "Copy command", title: copied ? "Copied" : "Copy", onClick: () => void copyCommand(), children: copied ? (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M20 6 9 17l-5-5" }) })) : (_jsxs("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }), _jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] })) })] }), hook && (_jsxs("div", { className: "hook-setup", children: [_jsxs("p", { className: "card-sub", children: ["Recommended: merge this into ", _jsx("code", { children: hook.target }), " \u2014 it delivers teammate announcements to the agent and reminds it to link each repo before its first write."] }), _jsx("div", { className: "install-command", children: _jsx("pre", { "data-testid": "hook-snippet", children: hook.snippet }) })] })), _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) => {
|
|
146
192
|
const name = t.name ?? t.id;
|
|
147
193
|
return (_jsxs("li", { children: [_jsx("span", { children: name }), _jsx("span", { className: "token-meta", children: tokenMeta(t, Date.now()) }), 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));
|
|
148
194
|
}) }))] })] }));
|
package/dist/lib/index.js
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { u as
|
|
2
|
-
import { E as
|
|
3
|
-
import { jsxs as n, jsx as e, Fragment as
|
|
4
|
-
import { useId as $, useRef as
|
|
5
|
-
function
|
|
1
|
+
import { u as j, d as S, S as Y, f as P, D as J } from "./Dashboard-D7tbhMwK.js";
|
|
2
|
+
import { E as ve, a as fe, c as ye } from "./Dashboard-D7tbhMwK.js";
|
|
3
|
+
import { jsxs as n, jsx as e, Fragment as G } from "react/jsx-runtime";
|
|
4
|
+
import { useId as $, useRef as W, useState as i, useEffect as A, useCallback as M } from "react";
|
|
5
|
+
function U(t) {
|
|
6
6
|
return (t.trim()[0] ?? "?").toUpperCase();
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function V({
|
|
9
9
|
workspaces: t,
|
|
10
10
|
selected: a,
|
|
11
11
|
onSelect: o,
|
|
12
|
-
onChanged:
|
|
13
|
-
onMembersChanged:
|
|
12
|
+
onChanged: h,
|
|
13
|
+
onMembersChanged: r
|
|
14
14
|
}) {
|
|
15
|
-
const
|
|
16
|
-
function
|
|
17
|
-
y(!1),
|
|
15
|
+
const p = j(), c = $(), b = W(null), [s, y] = i(!1), [v, f] = i("menu"), [N, k] = i(""), [m, C] = i(""), [E, l] = i(null), [g, x] = i(!1);
|
|
16
|
+
function _() {
|
|
17
|
+
y(!1), f("menu"), k(""), C(""), l(null);
|
|
18
18
|
}
|
|
19
19
|
A(() => {
|
|
20
|
-
if (!
|
|
21
|
-
function d(
|
|
22
|
-
b.current && !b.current.contains(
|
|
20
|
+
if (!s) return;
|
|
21
|
+
function d(D) {
|
|
22
|
+
b.current && !b.current.contains(D.target) && _();
|
|
23
23
|
}
|
|
24
|
-
function
|
|
25
|
-
|
|
24
|
+
function R(D) {
|
|
25
|
+
D.key === "Escape" && _();
|
|
26
26
|
}
|
|
27
|
-
return document.addEventListener("mousedown", d), document.addEventListener("keydown",
|
|
28
|
-
document.removeEventListener("mousedown", d), document.removeEventListener("keydown",
|
|
27
|
+
return document.addEventListener("mousedown", d), document.addEventListener("keydown", R), () => {
|
|
28
|
+
document.removeEventListener("mousedown", d), document.removeEventListener("keydown", R);
|
|
29
29
|
};
|
|
30
|
-
}, [
|
|
31
|
-
async function
|
|
32
|
-
if (!(!
|
|
33
|
-
|
|
30
|
+
}, [s]);
|
|
31
|
+
async function I() {
|
|
32
|
+
if (!(!N.trim() || g)) {
|
|
33
|
+
x(!0), l(null);
|
|
34
34
|
try {
|
|
35
|
-
const d = await
|
|
36
|
-
o(d.id),
|
|
35
|
+
const d = await p.createWorkspace({ name: N.trim() });
|
|
36
|
+
o(d.id), h(), _();
|
|
37
37
|
} catch (d) {
|
|
38
|
-
|
|
38
|
+
l(S(d));
|
|
39
39
|
} finally {
|
|
40
|
-
|
|
40
|
+
x(!1);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
async function T() {
|
|
45
|
-
if (!(!
|
|
46
|
-
|
|
45
|
+
if (!(!m.trim() || g)) {
|
|
46
|
+
x(!0), l(null);
|
|
47
47
|
try {
|
|
48
|
-
const d = await
|
|
49
|
-
o(d.workspace.id),
|
|
48
|
+
const d = await p.redeemInvite(m.trim());
|
|
49
|
+
o(d.workspace.id), h(), r == null || r(), _();
|
|
50
50
|
} catch (d) {
|
|
51
|
-
|
|
51
|
+
l(S(d));
|
|
52
52
|
} finally {
|
|
53
|
-
|
|
53
|
+
x(!1);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -62,35 +62,35 @@ function J({
|
|
|
62
62
|
type: "button",
|
|
63
63
|
className: "ws-trig" + (w ? "" : " ws-trig--empty"),
|
|
64
64
|
"aria-haspopup": "menu",
|
|
65
|
-
"aria-expanded":
|
|
66
|
-
"aria-controls":
|
|
67
|
-
onClick: () =>
|
|
65
|
+
"aria-expanded": s,
|
|
66
|
+
"aria-controls": s ? c : void 0,
|
|
67
|
+
onClick: () => s ? _() : y(!0),
|
|
68
68
|
children: [
|
|
69
|
-
w ? /* @__PURE__ */ e("span", { className: "ws-avatar", "aria-hidden": "true", children:
|
|
69
|
+
w ? /* @__PURE__ */ e("span", { className: "ws-avatar", "aria-hidden": "true", children: U(L) }) : /* @__PURE__ */ e("span", { className: "ws-plus", "aria-hidden": "true", children: "+" }),
|
|
70
70
|
/* @__PURE__ */ e("span", { className: "ws-name", children: L }),
|
|
71
71
|
/* @__PURE__ */ e("span", { className: "ws-caret", "aria-hidden": "true", children: "▾" })
|
|
72
72
|
]
|
|
73
73
|
}
|
|
74
74
|
),
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
s && /* @__PURE__ */ n("div", { className: "ws-menu", id: c, role: "menu", children: [
|
|
76
|
+
v === "menu" && /* @__PURE__ */ n(G, { children: [
|
|
77
77
|
/* @__PURE__ */ e("p", { className: "ws-menu__head", children: w ? "Switch workspace" : "Your workspaces" }),
|
|
78
78
|
t.length === 0 ? /* @__PURE__ */ e("p", { className: "ws-menu__none", children: "None yet" }) : /* @__PURE__ */ e("ul", { className: "ws-menu__list", children: t.map((d) => {
|
|
79
|
-
const
|
|
79
|
+
const R = d.id === (a == null ? void 0 : a.id);
|
|
80
80
|
return /* @__PURE__ */ e("li", { children: /* @__PURE__ */ n(
|
|
81
81
|
"button",
|
|
82
82
|
{
|
|
83
83
|
type: "button",
|
|
84
84
|
role: "menuitemradio",
|
|
85
|
-
"aria-checked":
|
|
86
|
-
className: "ws-mi" + (
|
|
85
|
+
"aria-checked": R,
|
|
86
|
+
className: "ws-mi" + (R ? " ws-mi--on" : ""),
|
|
87
87
|
onClick: () => {
|
|
88
|
-
o(d.id),
|
|
88
|
+
o(d.id), _();
|
|
89
89
|
},
|
|
90
90
|
children: [
|
|
91
|
-
/* @__PURE__ */ e("span", { className: "ws-avatar ws-avatar--sm", "aria-hidden": "true", children:
|
|
91
|
+
/* @__PURE__ */ e("span", { className: "ws-avatar ws-avatar--sm", "aria-hidden": "true", children: U(d.name) }),
|
|
92
92
|
/* @__PURE__ */ e("span", { className: "ws-mi__name", children: d.name }),
|
|
93
|
-
|
|
93
|
+
R && /* @__PURE__ */ e("span", { className: "ws-mi__check", "aria-hidden": "true", children: "✓" })
|
|
94
94
|
]
|
|
95
95
|
}
|
|
96
96
|
) }, d.id);
|
|
@@ -103,7 +103,7 @@ function J({
|
|
|
103
103
|
role: "menuitem",
|
|
104
104
|
className: "ws-action",
|
|
105
105
|
onClick: () => {
|
|
106
|
-
|
|
106
|
+
l(null), f("create");
|
|
107
107
|
},
|
|
108
108
|
children: "+ Create workspace"
|
|
109
109
|
}
|
|
@@ -115,19 +115,19 @@ function J({
|
|
|
115
115
|
role: "menuitem",
|
|
116
116
|
className: "ws-action",
|
|
117
117
|
onClick: () => {
|
|
118
|
-
|
|
118
|
+
l(null), f("join");
|
|
119
119
|
},
|
|
120
120
|
children: "⎘ Join with a code"
|
|
121
121
|
}
|
|
122
122
|
)
|
|
123
123
|
] })
|
|
124
124
|
] }),
|
|
125
|
-
|
|
125
|
+
v === "create" && /* @__PURE__ */ n(
|
|
126
126
|
"form",
|
|
127
127
|
{
|
|
128
128
|
className: "ws-form",
|
|
129
129
|
onSubmit: (d) => {
|
|
130
|
-
d.preventDefault(),
|
|
130
|
+
d.preventDefault(), I();
|
|
131
131
|
},
|
|
132
132
|
children: [
|
|
133
133
|
/* @__PURE__ */ e("label", { htmlFor: `${c}-name`, children: "New workspace name" }),
|
|
@@ -137,19 +137,19 @@ function J({
|
|
|
137
137
|
id: `${c}-name`,
|
|
138
138
|
type: "text",
|
|
139
139
|
placeholder: "e.g. Acme Engineering",
|
|
140
|
-
value:
|
|
140
|
+
value: N,
|
|
141
141
|
autoFocus: !0,
|
|
142
142
|
onChange: (d) => k(d.target.value)
|
|
143
143
|
}
|
|
144
144
|
),
|
|
145
145
|
/* @__PURE__ */ n("div", { className: "ws-form__row", children: [
|
|
146
|
-
/* @__PURE__ */ e("button", { type: "button", className: "ws-form__back", onClick: () =>
|
|
147
|
-
/* @__PURE__ */ e("button", { type: "submit", disabled:
|
|
146
|
+
/* @__PURE__ */ e("button", { type: "button", className: "ws-form__back", onClick: () => f("menu"), children: "Back" }),
|
|
147
|
+
/* @__PURE__ */ e("button", { type: "submit", disabled: g || !N.trim(), children: "Create" })
|
|
148
148
|
] })
|
|
149
149
|
]
|
|
150
150
|
}
|
|
151
151
|
),
|
|
152
|
-
|
|
152
|
+
v === "join" && /* @__PURE__ */ n(
|
|
153
153
|
"form",
|
|
154
154
|
{
|
|
155
155
|
className: "ws-form",
|
|
@@ -164,14 +164,14 @@ function J({
|
|
|
164
164
|
id: `${c}-code`,
|
|
165
165
|
type: "text",
|
|
166
166
|
placeholder: "Paste an invite code",
|
|
167
|
-
value:
|
|
167
|
+
value: m,
|
|
168
168
|
autoFocus: !0,
|
|
169
|
-
onChange: (d) =>
|
|
169
|
+
onChange: (d) => C(d.target.value)
|
|
170
170
|
}
|
|
171
171
|
),
|
|
172
172
|
/* @__PURE__ */ n("div", { className: "ws-form__row", children: [
|
|
173
|
-
/* @__PURE__ */ e("button", { type: "button", className: "ws-form__back", onClick: () =>
|
|
174
|
-
/* @__PURE__ */ e("button", { type: "submit", disabled:
|
|
173
|
+
/* @__PURE__ */ e("button", { type: "button", className: "ws-form__back", onClick: () => f("menu"), children: "Back" }),
|
|
174
|
+
/* @__PURE__ */ e("button", { type: "submit", disabled: g || !m.trim(), children: "Join" })
|
|
175
175
|
] })
|
|
176
176
|
]
|
|
177
177
|
}
|
|
@@ -180,30 +180,30 @@ function J({
|
|
|
180
180
|
] })
|
|
181
181
|
] });
|
|
182
182
|
}
|
|
183
|
-
function
|
|
183
|
+
function X({
|
|
184
184
|
workspaceName: t,
|
|
185
185
|
busy: a,
|
|
186
186
|
error: o,
|
|
187
|
-
onConfirm:
|
|
188
|
-
onCancel:
|
|
187
|
+
onConfirm: h,
|
|
188
|
+
onCancel: r
|
|
189
189
|
}) {
|
|
190
|
-
const
|
|
190
|
+
const p = $(), c = $(), [b, s] = i(""), y = W(null);
|
|
191
191
|
A(() => {
|
|
192
|
-
var
|
|
193
|
-
(
|
|
192
|
+
var f;
|
|
193
|
+
(f = y.current) == null || f.focus();
|
|
194
194
|
}, []), A(() => {
|
|
195
|
-
function
|
|
196
|
-
|
|
195
|
+
function f(N) {
|
|
196
|
+
N.key === "Escape" && !a && r();
|
|
197
197
|
}
|
|
198
|
-
return document.addEventListener("keydown",
|
|
199
|
-
}, [a,
|
|
200
|
-
const
|
|
198
|
+
return document.addEventListener("keydown", f), () => document.removeEventListener("keydown", f);
|
|
199
|
+
}, [a, r]);
|
|
200
|
+
const v = b === t;
|
|
201
201
|
return /* @__PURE__ */ e(
|
|
202
202
|
"div",
|
|
203
203
|
{
|
|
204
204
|
className: "shepherd-modal__backdrop",
|
|
205
205
|
onClick: () => {
|
|
206
|
-
a ||
|
|
206
|
+
a || r();
|
|
207
207
|
},
|
|
208
208
|
children: /* @__PURE__ */ n(
|
|
209
209
|
"div",
|
|
@@ -211,17 +211,17 @@ function V({
|
|
|
211
211
|
className: "shepherd-modal",
|
|
212
212
|
role: "dialog",
|
|
213
213
|
"aria-modal": "true",
|
|
214
|
-
"aria-labelledby":
|
|
214
|
+
"aria-labelledby": p,
|
|
215
215
|
"aria-describedby": c,
|
|
216
|
-
onClick: (
|
|
216
|
+
onClick: (f) => f.stopPropagation(),
|
|
217
217
|
children: [
|
|
218
|
-
/* @__PURE__ */ e("h3", { id:
|
|
218
|
+
/* @__PURE__ */ e("h3", { id: p, children: "Delete workspace" }),
|
|
219
219
|
/* @__PURE__ */ n("p", { id: c, className: "shepherd-modal__body", children: [
|
|
220
220
|
"This permanently deletes ",
|
|
221
221
|
/* @__PURE__ */ e("b", { children: t }),
|
|
222
222
|
" and all of its data — agents, sessions, tasks, announcements, change history, tokens, invites, and members. This cannot be undone."
|
|
223
223
|
] }),
|
|
224
|
-
/* @__PURE__ */ n("label", { htmlFor: `${
|
|
224
|
+
/* @__PURE__ */ n("label", { htmlFor: `${p}-input`, className: "shepherd-modal__label", children: [
|
|
225
225
|
"Type ",
|
|
226
226
|
/* @__PURE__ */ e("b", { children: t }),
|
|
227
227
|
" to confirm"
|
|
@@ -229,25 +229,25 @@ function V({
|
|
|
229
229
|
/* @__PURE__ */ e(
|
|
230
230
|
"input",
|
|
231
231
|
{
|
|
232
|
-
id: `${
|
|
232
|
+
id: `${p}-input`,
|
|
233
233
|
ref: y,
|
|
234
234
|
type: "text",
|
|
235
235
|
value: b,
|
|
236
236
|
autoComplete: "off",
|
|
237
237
|
disabled: a,
|
|
238
|
-
onChange: (
|
|
238
|
+
onChange: (f) => s(f.target.value)
|
|
239
239
|
}
|
|
240
240
|
),
|
|
241
241
|
o && /* @__PURE__ */ e("p", { role: "alert", children: o }),
|
|
242
242
|
/* @__PURE__ */ n("div", { className: "shepherd-modal__actions", children: [
|
|
243
|
-
/* @__PURE__ */ e("button", { type: "button", onClick:
|
|
243
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: r, disabled: a, children: "Cancel" }),
|
|
244
244
|
/* @__PURE__ */ e(
|
|
245
245
|
"button",
|
|
246
246
|
{
|
|
247
247
|
type: "button",
|
|
248
248
|
className: "danger",
|
|
249
|
-
onClick:
|
|
250
|
-
disabled: !
|
|
249
|
+
onClick: h,
|
|
250
|
+
disabled: !v || a,
|
|
251
251
|
children: a ? "Deleting…" : "Delete workspace"
|
|
252
252
|
}
|
|
253
253
|
)
|
|
@@ -258,40 +258,40 @@ function V({
|
|
|
258
258
|
}
|
|
259
259
|
);
|
|
260
260
|
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
async function
|
|
261
|
+
function q({ workspace: t, onLeft: a, onDeleted: o }) {
|
|
262
|
+
const h = j(), r = $(), [p, c] = i(null), [b, s] = i(!1), [y, v] = i(!1), [f, N] = i(!1), [k, m] = i(!1), [C, E] = i(null), l = t.role === "admin";
|
|
263
|
+
async function g() {
|
|
264
264
|
if (!b) {
|
|
265
|
-
|
|
265
|
+
s(!0), c(null), v(!1);
|
|
266
266
|
try {
|
|
267
|
-
await
|
|
268
|
-
} catch (
|
|
269
|
-
c(
|
|
267
|
+
await h.leave(t.id), a == null || a();
|
|
268
|
+
} catch (_) {
|
|
269
|
+
c(S(_)), _ instanceof Y && _.status === 409 && v(!0);
|
|
270
270
|
} finally {
|
|
271
|
-
|
|
271
|
+
s(!1);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
|
-
async function
|
|
275
|
+
async function x() {
|
|
276
276
|
if (!k) {
|
|
277
|
-
|
|
277
|
+
m(!0), E(null);
|
|
278
278
|
try {
|
|
279
|
-
await
|
|
280
|
-
} catch (
|
|
281
|
-
E(
|
|
279
|
+
await h.deleteWorkspace(t.id), N(!1), o == null || o();
|
|
280
|
+
} catch (_) {
|
|
281
|
+
E(S(_));
|
|
282
282
|
} finally {
|
|
283
|
-
|
|
283
|
+
m(!1);
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
-
return /* @__PURE__ */ n("section", { className: "shepherd-general", "aria-labelledby":
|
|
287
|
+
return /* @__PURE__ */ n("section", { className: "shepherd-general", "aria-labelledby": r, children: [
|
|
288
288
|
/* @__PURE__ */ n("div", { className: "card-head", children: [
|
|
289
|
-
/* @__PURE__ */ e("h3", { id:
|
|
289
|
+
/* @__PURE__ */ e("h3", { id: r, children: "General" }),
|
|
290
290
|
/* @__PURE__ */ e("p", { className: "card-sub", children: "Your active workspace and its settings." })
|
|
291
291
|
] }),
|
|
292
292
|
/* @__PURE__ */ n("div", { className: "card-body", children: [
|
|
293
|
-
|
|
294
|
-
y &&
|
|
293
|
+
p && /* @__PURE__ */ e("p", { role: "alert", children: p }),
|
|
294
|
+
y && l && /* @__PURE__ */ e("p", { className: "helper", children: "You're the last admin, so you can't leave. To remove this workspace entirely, delete it below." }),
|
|
295
295
|
/* @__PURE__ */ n("div", { className: "field", children: [
|
|
296
296
|
/* @__PURE__ */ e("label", { children: "Workspace name" }),
|
|
297
297
|
/* @__PURE__ */ e("p", { className: "readonly-value", children: t.name })
|
|
@@ -303,9 +303,9 @@ function M({ workspace: t, onLeft: a, onDeleted: o }) {
|
|
|
303
303
|
/* @__PURE__ */ n("div", { className: "field leave", children: [
|
|
304
304
|
/* @__PURE__ */ e("label", { children: "Leave workspace" }),
|
|
305
305
|
/* @__PURE__ */ e("p", { className: "helper", children: "Remove yourself from this workspace. You'll need a new invite to rejoin." }),
|
|
306
|
-
/* @__PURE__ */ e("button", { type: "button", className: "danger", onClick: () => void
|
|
306
|
+
/* @__PURE__ */ e("button", { type: "button", className: "danger", onClick: () => void g(), disabled: b, children: "Leave workspace" })
|
|
307
307
|
] }),
|
|
308
|
-
|
|
308
|
+
l && /* @__PURE__ */ n("div", { className: "field delete", children: [
|
|
309
309
|
/* @__PURE__ */ e("label", { children: "Delete workspace" }),
|
|
310
310
|
/* @__PURE__ */ e("p", { className: "helper", children: "Permanently delete this workspace and all of its data. This cannot be undone." }),
|
|
311
311
|
/* @__PURE__ */ e(
|
|
@@ -314,7 +314,7 @@ function M({ workspace: t, onLeft: a, onDeleted: o }) {
|
|
|
314
314
|
type: "button",
|
|
315
315
|
className: "danger",
|
|
316
316
|
onClick: () => {
|
|
317
|
-
E(null),
|
|
317
|
+
E(null), N(!0);
|
|
318
318
|
},
|
|
319
319
|
disabled: k,
|
|
320
320
|
children: "Delete workspace"
|
|
@@ -322,123 +322,123 @@ function M({ workspace: t, onLeft: a, onDeleted: o }) {
|
|
|
322
322
|
)
|
|
323
323
|
] })
|
|
324
324
|
] }),
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
f && /* @__PURE__ */ e(
|
|
326
|
+
X,
|
|
327
327
|
{
|
|
328
328
|
workspaceName: t.name,
|
|
329
329
|
busy: k,
|
|
330
|
-
error:
|
|
331
|
-
onConfirm: () => void
|
|
330
|
+
error: C,
|
|
331
|
+
onConfirm: () => void x(),
|
|
332
332
|
onCancel: () => {
|
|
333
|
-
k ||
|
|
333
|
+
k || N(!1);
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
336
|
)
|
|
337
337
|
] });
|
|
338
338
|
}
|
|
339
|
-
function
|
|
340
|
-
const
|
|
341
|
-
async function
|
|
342
|
-
|
|
339
|
+
function z({ workspaceId: t, refreshKey: a = 0, canRemove: o = !1 }) {
|
|
340
|
+
const h = j(), r = $(), [p, c] = i([]), [b, s] = i(null), [y, v] = i(null), [f, N] = i(!0), [k, m] = i(null);
|
|
341
|
+
async function C({ keepError: l = !1 } = {}) {
|
|
342
|
+
l || s(null);
|
|
343
343
|
try {
|
|
344
|
-
const
|
|
345
|
-
c(
|
|
346
|
-
} catch (
|
|
347
|
-
|
|
344
|
+
const g = await h.listMembers(t);
|
|
345
|
+
c(g.members);
|
|
346
|
+
} catch (g) {
|
|
347
|
+
s(S(g));
|
|
348
348
|
} finally {
|
|
349
|
-
|
|
349
|
+
N(!1);
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
A(() => {
|
|
353
|
-
|
|
354
|
-
}, [
|
|
355
|
-
async function E(
|
|
353
|
+
N(!0), C();
|
|
354
|
+
}, [h, t, a]);
|
|
355
|
+
async function E(l, g) {
|
|
356
356
|
if (!k) {
|
|
357
|
-
|
|
357
|
+
m(l), s(null), v(null), c((x) => x.filter((_) => _.accountId !== l));
|
|
358
358
|
try {
|
|
359
|
-
await
|
|
360
|
-
} catch (
|
|
361
|
-
|
|
359
|
+
await h.removeMember(t, l), v(`Removed ${g}`);
|
|
360
|
+
} catch (x) {
|
|
361
|
+
s(S(x)), C({ keepError: !0 });
|
|
362
362
|
} finally {
|
|
363
|
-
|
|
363
|
+
m(null);
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
-
return /* @__PURE__ */ n("section", { className: "shepherd-members", "aria-labelledby":
|
|
368
|
-
/* @__PURE__ */ e("div", { className: "card-head", children: /* @__PURE__ */ e("h3", { id:
|
|
367
|
+
return /* @__PURE__ */ n("section", { className: "shepherd-members", "aria-labelledby": r, children: [
|
|
368
|
+
/* @__PURE__ */ e("div", { className: "card-head", children: /* @__PURE__ */ e("h3", { id: r, children: "Members" }) }),
|
|
369
369
|
/* @__PURE__ */ n("div", { className: "card-body", children: [
|
|
370
370
|
b && /* @__PURE__ */ e("p", { role: "alert", children: b }),
|
|
371
371
|
y && /* @__PURE__ */ e("p", { role: "status", children: y }),
|
|
372
|
-
|
|
373
|
-
const
|
|
372
|
+
f ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : p.length === 0 ? /* @__PURE__ */ e("p", { children: "No members." }) : /* @__PURE__ */ e("ul", { children: p.map((l) => {
|
|
373
|
+
const g = l.displayName ?? l.githubLogin ?? l.email ?? l.accountId;
|
|
374
374
|
return /* @__PURE__ */ n("li", { children: [
|
|
375
|
-
/* @__PURE__ */ e("span", { children:
|
|
376
|
-
/* @__PURE__ */ e("span", { className: "role", children:
|
|
375
|
+
/* @__PURE__ */ e("span", { children: g }),
|
|
376
|
+
/* @__PURE__ */ e("span", { className: "role", children: l.role }),
|
|
377
377
|
o && /* @__PURE__ */ e(
|
|
378
378
|
"button",
|
|
379
379
|
{
|
|
380
380
|
type: "button",
|
|
381
|
-
"aria-label": `Remove ${
|
|
382
|
-
onClick: () => void E(
|
|
383
|
-
disabled: k ===
|
|
381
|
+
"aria-label": `Remove ${g}`,
|
|
382
|
+
onClick: () => void E(l.accountId, g),
|
|
383
|
+
disabled: k === l.accountId,
|
|
384
384
|
children: "Remove"
|
|
385
385
|
}
|
|
386
386
|
)
|
|
387
|
-
] },
|
|
387
|
+
] }, l.accountId);
|
|
388
388
|
}) })
|
|
389
389
|
] })
|
|
390
390
|
] });
|
|
391
391
|
}
|
|
392
|
-
function
|
|
393
|
-
const o =
|
|
392
|
+
function Q({ workspaceId: t, onMembersChanged: a }) {
|
|
393
|
+
const o = j(), h = $(), [r, p] = i(null), [c, b] = i(null), [s, y] = i(!1), [v, f] = i(""), [N, k] = i(null), [m, C] = i(!1), [E, l] = i(null);
|
|
394
394
|
A(() => {
|
|
395
|
-
|
|
395
|
+
p(null), k(null);
|
|
396
396
|
}, [t]);
|
|
397
|
-
async function
|
|
398
|
-
if (!
|
|
397
|
+
async function g() {
|
|
398
|
+
if (!s) {
|
|
399
399
|
y(!0), b(null);
|
|
400
400
|
try {
|
|
401
401
|
const w = await o.createInvite(t, {});
|
|
402
|
-
|
|
402
|
+
p(w), a == null || a();
|
|
403
403
|
} catch (w) {
|
|
404
|
-
b(
|
|
404
|
+
b(S(w));
|
|
405
405
|
} finally {
|
|
406
406
|
y(!1);
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
409
|
}
|
|
410
|
-
async function
|
|
411
|
-
if (!(!
|
|
410
|
+
async function x() {
|
|
411
|
+
if (!(!r || s)) {
|
|
412
412
|
y(!0), b(null);
|
|
413
413
|
try {
|
|
414
|
-
await o.revokeInvite(t,
|
|
414
|
+
await o.revokeInvite(t, r.code), p(null);
|
|
415
415
|
} catch (w) {
|
|
416
|
-
b(
|
|
416
|
+
b(S(w));
|
|
417
417
|
} finally {
|
|
418
418
|
y(!1);
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
|
-
async function
|
|
423
|
-
if (!(!
|
|
424
|
-
|
|
422
|
+
async function _() {
|
|
423
|
+
if (!(!v.trim() || m)) {
|
|
424
|
+
C(!0), k(null);
|
|
425
425
|
try {
|
|
426
|
-
const w = await o.inviteByEmail(t,
|
|
427
|
-
k(`Invite sent to ${w.email}.`),
|
|
426
|
+
const w = await o.inviteByEmail(t, v.trim());
|
|
427
|
+
k(`Invite sent to ${w.email}.`), f(""), a == null || a();
|
|
428
428
|
} catch (w) {
|
|
429
|
-
k(
|
|
429
|
+
k(S(w));
|
|
430
430
|
} finally {
|
|
431
|
-
|
|
431
|
+
C(!1);
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
|
-
const
|
|
435
|
+
const I = r ? `${window.location.origin}/shepherd/join/${encodeURIComponent(r.code)}` : null;
|
|
436
436
|
async function T(w, L) {
|
|
437
|
-
await navigator.clipboard.writeText(L),
|
|
437
|
+
await navigator.clipboard.writeText(L), l(w), setTimeout(() => l((d) => d === w ? null : d), 2e3);
|
|
438
438
|
}
|
|
439
|
-
return /* @__PURE__ */ n("section", { className: "shepherd-invites", "aria-labelledby":
|
|
439
|
+
return /* @__PURE__ */ n("section", { className: "shepherd-invites", "aria-labelledby": h, children: [
|
|
440
440
|
/* @__PURE__ */ n("div", { className: "card-head", children: [
|
|
441
|
-
/* @__PURE__ */ e("h3", { id:
|
|
441
|
+
/* @__PURE__ */ e("h3", { id: h, children: "Invite people" }),
|
|
442
442
|
/* @__PURE__ */ e("p", { className: "card-sub", children: "Share a code, or send a one-time join link by email." })
|
|
443
443
|
] }),
|
|
444
444
|
/* @__PURE__ */ n("div", { className: "card-body", children: [
|
|
@@ -446,48 +446,48 @@ function q({ workspaceId: t, onMembersChanged: a }) {
|
|
|
446
446
|
/* @__PURE__ */ n("div", { className: "field invites", children: [
|
|
447
447
|
/* @__PURE__ */ e("label", { children: "Invite by code" }),
|
|
448
448
|
/* @__PURE__ */ e("p", { className: "helper", children: "Anyone with the code can join this workspace." }),
|
|
449
|
-
|
|
449
|
+
r && /* @__PURE__ */ n("div", { className: "invite-result", children: [
|
|
450
450
|
/* @__PURE__ */ n("div", { className: "invite-result__head", children: [
|
|
451
451
|
/* @__PURE__ */ e("span", { className: "invite-result__eyebrow", children: "Invite code" }),
|
|
452
|
-
/* @__PURE__ */ e("span", { className: "invite-uses", children:
|
|
452
|
+
/* @__PURE__ */ e("span", { className: "invite-uses", children: r.maxUses === null ? `${r.useCount} uses` : `${r.useCount} / ${r.maxUses} uses` }),
|
|
453
453
|
/* @__PURE__ */ e(
|
|
454
454
|
"button",
|
|
455
455
|
{
|
|
456
456
|
type: "button",
|
|
457
457
|
className: "link-btn",
|
|
458
458
|
"aria-label": "Revoke invite",
|
|
459
|
-
onClick: () => void
|
|
460
|
-
disabled:
|
|
459
|
+
onClick: () => void x(),
|
|
460
|
+
disabled: s,
|
|
461
461
|
children: "Revoke"
|
|
462
462
|
}
|
|
463
463
|
)
|
|
464
464
|
] }),
|
|
465
465
|
/* @__PURE__ */ n("div", { className: "invite-result__copyrow", children: [
|
|
466
|
-
/* @__PURE__ */ e("code", { children:
|
|
466
|
+
/* @__PURE__ */ e("code", { children: r.code }),
|
|
467
467
|
/* @__PURE__ */ e(
|
|
468
468
|
"button",
|
|
469
469
|
{
|
|
470
470
|
type: "button",
|
|
471
471
|
className: "copy-btn",
|
|
472
|
-
onClick: () => void T("code",
|
|
472
|
+
onClick: () => void T("code", r.code),
|
|
473
473
|
children: E === "code" ? "Copied" : "Copy"
|
|
474
474
|
}
|
|
475
475
|
)
|
|
476
476
|
] }),
|
|
477
|
-
|
|
478
|
-
/* @__PURE__ */ e("a", { href:
|
|
477
|
+
I && /* @__PURE__ */ n("div", { className: "invite-result__copyrow invite-result__copyrow--link", children: [
|
|
478
|
+
/* @__PURE__ */ e("a", { href: I, children: I }),
|
|
479
479
|
/* @__PURE__ */ e(
|
|
480
480
|
"button",
|
|
481
481
|
{
|
|
482
482
|
type: "button",
|
|
483
483
|
className: "copy-btn",
|
|
484
|
-
onClick: () => void T("link",
|
|
484
|
+
onClick: () => void T("link", I),
|
|
485
485
|
children: E === "link" ? "Copied" : "Copy link"
|
|
486
486
|
}
|
|
487
487
|
)
|
|
488
488
|
] })
|
|
489
489
|
] }),
|
|
490
|
-
/* @__PURE__ */ e("button", { type: "button", onClick: () => void
|
|
490
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: () => void g(), disabled: s, children: "Create invite" })
|
|
491
491
|
] }),
|
|
492
492
|
/* @__PURE__ */ n("div", { className: "field email-invite", children: [
|
|
493
493
|
/* @__PURE__ */ e("label", { htmlFor: "invite-email", children: "Invite by email" }),
|
|
@@ -499,44 +499,71 @@ function q({ workspaceId: t, onMembersChanged: a }) {
|
|
|
499
499
|
id: "invite-email",
|
|
500
500
|
type: "email",
|
|
501
501
|
placeholder: "name@example.com",
|
|
502
|
-
value:
|
|
503
|
-
onChange: (w) =>
|
|
502
|
+
value: v,
|
|
503
|
+
onChange: (w) => f(w.target.value)
|
|
504
504
|
}
|
|
505
505
|
),
|
|
506
|
-
/* @__PURE__ */ e("button", { type: "button", onClick: () => void
|
|
506
|
+
/* @__PURE__ */ e("button", { type: "button", onClick: () => void _(), disabled: m, children: "Send invite" })
|
|
507
507
|
] }),
|
|
508
|
-
|
|
508
|
+
N && /* @__PURE__ */ e("p", { className: "email-invite__status", children: N })
|
|
509
509
|
] })
|
|
510
510
|
] })
|
|
511
511
|
] });
|
|
512
512
|
}
|
|
513
|
-
const
|
|
513
|
+
const Z = [
|
|
514
514
|
{ id: "claude", label: "Claude Code" },
|
|
515
515
|
{ id: "codex", label: "Codex" },
|
|
516
516
|
{ id: "pi", label: "Pi" },
|
|
517
517
|
{ id: "cursor", label: "Cursor" },
|
|
518
518
|
{ id: "generic", label: "Generic (JSON)" }
|
|
519
|
-
],
|
|
519
|
+
], ee = "shp_<paste-after-generating>", ne = {
|
|
520
520
|
claude: "claude mcp add shepherd -s user",
|
|
521
521
|
codex: "codex mcp add shepherd"
|
|
522
|
-
},
|
|
522
|
+
}, te = {
|
|
523
523
|
claude: "-e",
|
|
524
524
|
codex: "--env"
|
|
525
|
-
};
|
|
526
|
-
function
|
|
527
|
-
|
|
528
|
-
|
|
525
|
+
}, F = "npx -y --package=@korso/shepherd shepherd-inbox-hook";
|
|
526
|
+
function ae(t) {
|
|
527
|
+
return t === "claude" ? {
|
|
528
|
+
target: "~/.claude/settings.json",
|
|
529
|
+
snippet: JSON.stringify(
|
|
530
|
+
{
|
|
531
|
+
hooks: {
|
|
532
|
+
SessionStart: [{ hooks: [{ type: "command", command: F }] }],
|
|
533
|
+
PreToolUse: [
|
|
534
|
+
{ matcher: "*", hooks: [{ type: "command", command: F }] }
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
null,
|
|
539
|
+
2
|
|
540
|
+
)
|
|
541
|
+
} : t === "codex" ? {
|
|
542
|
+
target: "~/.codex/config.toml",
|
|
543
|
+
snippet: [
|
|
544
|
+
"[features]",
|
|
545
|
+
"hooks = true",
|
|
546
|
+
"",
|
|
547
|
+
"[[hooks.UserPromptSubmit]]",
|
|
548
|
+
'command = ["npx", "-y", "--package=@korso/shepherd", "shepherd-inbox-hook"]'
|
|
549
|
+
].join(`
|
|
550
|
+
`)
|
|
551
|
+
} : null;
|
|
529
552
|
}
|
|
530
|
-
function
|
|
553
|
+
function ie(t, a) {
|
|
554
|
+
const o = `created ${P(t.createdAt, a)}`, h = t.lastUsedAt ? `last used ${P(t.lastUsedAt, a)}` : "never used";
|
|
555
|
+
return `${o} · ${h}`;
|
|
556
|
+
}
|
|
557
|
+
function re(t, a, o) {
|
|
531
558
|
if (t === "generic" || t === "pi" || t === "cursor") {
|
|
532
|
-
const
|
|
533
|
-
return t !== "generic" && (
|
|
559
|
+
const p = { HUB_URL: a, SHEPHERD_TOKEN: o };
|
|
560
|
+
return t !== "generic" && (p.PROGRAM = t), JSON.stringify(
|
|
534
561
|
{
|
|
535
562
|
mcpServers: {
|
|
536
563
|
shepherd: {
|
|
537
564
|
command: "npx",
|
|
538
565
|
args: ["-y", "--package=@korso/shepherd", "shepherd-mcp"],
|
|
539
|
-
env:
|
|
566
|
+
env: p
|
|
540
567
|
}
|
|
541
568
|
}
|
|
542
569
|
},
|
|
@@ -544,60 +571,60 @@ function te(t, a, o) {
|
|
|
544
571
|
2
|
|
545
572
|
);
|
|
546
573
|
}
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
`${
|
|
550
|
-
`${
|
|
574
|
+
const h = te[t], r = [
|
|
575
|
+
ne[t],
|
|
576
|
+
`${h} HUB_URL=${a}`,
|
|
577
|
+
`${h} SHEPHERD_TOKEN=${o}`
|
|
551
578
|
];
|
|
552
|
-
return t === "codex" &&
|
|
579
|
+
return t === "codex" && r.push(`${h} PROGRAM=codex`), r.push("-- npx -y --package=@korso/shepherd shepherd-mcp"), r.join(" ");
|
|
553
580
|
}
|
|
554
|
-
function
|
|
555
|
-
const a =
|
|
581
|
+
function se({ hubUrl: t }) {
|
|
582
|
+
const a = j(), o = t ?? a.baseUrl, h = $(), [r, p] = i("claude"), [c, b] = i(""), [s, y] = i(null), [v, f] = i([]), [N, k] = i(null), [m, C] = i(null), [E, l] = i(!1), [g, x] = i(!1), [_, I] = i(!0), [T, w] = i(null);
|
|
556
583
|
async function L() {
|
|
557
584
|
try {
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
} catch (
|
|
561
|
-
k(
|
|
585
|
+
const u = await a.listAccountTokens();
|
|
586
|
+
f(u.tokens);
|
|
587
|
+
} catch (u) {
|
|
588
|
+
k(S(u));
|
|
562
589
|
} finally {
|
|
563
|
-
|
|
590
|
+
I(!1);
|
|
564
591
|
}
|
|
565
592
|
}
|
|
566
593
|
A(() => {
|
|
567
|
-
|
|
594
|
+
I(!0), L();
|
|
568
595
|
}, [a]);
|
|
569
596
|
async function d() {
|
|
570
|
-
|
|
597
|
+
l(!0), k(null), C(null);
|
|
571
598
|
try {
|
|
572
|
-
const
|
|
599
|
+
const u = await a.mintAccountToken(
|
|
573
600
|
c.trim() ? { name: c.trim() } : {}
|
|
574
601
|
);
|
|
575
|
-
y(
|
|
576
|
-
} catch (
|
|
577
|
-
k(
|
|
602
|
+
y(u.token), b(""), await L();
|
|
603
|
+
} catch (u) {
|
|
604
|
+
k(S(u));
|
|
578
605
|
} finally {
|
|
579
|
-
|
|
606
|
+
l(!1);
|
|
580
607
|
}
|
|
581
608
|
}
|
|
582
|
-
async function
|
|
609
|
+
async function R(u) {
|
|
583
610
|
if (!T) {
|
|
584
|
-
w(
|
|
611
|
+
w(u), k(null), C(null);
|
|
585
612
|
try {
|
|
586
|
-
await a.revokeAccountToken(
|
|
587
|
-
} catch (
|
|
588
|
-
k(
|
|
613
|
+
await a.revokeAccountToken(u), f((O) => O.filter((K) => K.id !== u)), C("Token revoked");
|
|
614
|
+
} catch (O) {
|
|
615
|
+
k(S(O));
|
|
589
616
|
} finally {
|
|
590
617
|
w(null);
|
|
591
618
|
}
|
|
592
619
|
}
|
|
593
620
|
}
|
|
594
|
-
const
|
|
595
|
-
async function
|
|
596
|
-
await navigator.clipboard.writeText(
|
|
621
|
+
const D = re(r, o, s ?? ee), B = ae(r);
|
|
622
|
+
async function H() {
|
|
623
|
+
await navigator.clipboard.writeText(D), x(!0), setTimeout(() => x(!1), 2e3);
|
|
597
624
|
}
|
|
598
|
-
return /* @__PURE__ */ n("section", { className: "shepherd-connect-agent", "aria-labelledby":
|
|
625
|
+
return /* @__PURE__ */ n("section", { className: "shepherd-connect-agent", "aria-labelledby": h, children: [
|
|
599
626
|
/* @__PURE__ */ n("div", { className: "card-head", children: [
|
|
600
|
-
/* @__PURE__ */ e("h3", { id:
|
|
627
|
+
/* @__PURE__ */ e("h3", { id: h, children: "Connect your agent" }),
|
|
601
628
|
/* @__PURE__ */ e("p", { className: "card-sub", children: "Generate a token — it works across all your workspaces — then paste the command into your coding tool." }),
|
|
602
629
|
/* @__PURE__ */ e("p", { className: "card-sub", children: "The first time the agent opens a repo, it'll ask which workspace to coordinate that repo with." })
|
|
603
630
|
] }),
|
|
@@ -608,9 +635,9 @@ function ae({ hubUrl: t }) {
|
|
|
608
635
|
"select",
|
|
609
636
|
{
|
|
610
637
|
id: "connect-tool",
|
|
611
|
-
value:
|
|
612
|
-
onChange: (
|
|
613
|
-
children:
|
|
638
|
+
value: r,
|
|
639
|
+
onChange: (u) => p(u.target.value),
|
|
640
|
+
children: Z.map((u) => /* @__PURE__ */ e("option", { value: u.id, children: u.label }, u.id))
|
|
614
641
|
}
|
|
615
642
|
)
|
|
616
643
|
] }),
|
|
@@ -623,27 +650,30 @@ function ae({ hubUrl: t }) {
|
|
|
623
650
|
id: "token-name",
|
|
624
651
|
type: "text",
|
|
625
652
|
value: c,
|
|
626
|
-
onChange: (
|
|
653
|
+
onChange: (u) => b(u.target.value),
|
|
654
|
+
onKeyDown: (u) => {
|
|
655
|
+
u.key === "Enter" && !E && (u.preventDefault(), d());
|
|
656
|
+
},
|
|
627
657
|
placeholder: "e.g. laptop"
|
|
628
658
|
}
|
|
629
659
|
),
|
|
630
660
|
/* @__PURE__ */ e("button", { type: "button", onClick: () => void d(), disabled: E, children: "Generate token" })
|
|
631
661
|
] })
|
|
632
662
|
] }),
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
663
|
+
N && /* @__PURE__ */ e("p", { role: "alert", children: N }),
|
|
664
|
+
m && /* @__PURE__ */ e("p", { role: "status", children: m }),
|
|
665
|
+
s && /* @__PURE__ */ e("p", { className: "token-once", role: "status", children: "Copy this token now — it won't be shown again." }),
|
|
636
666
|
/* @__PURE__ */ n("div", { className: "install-command", children: [
|
|
637
|
-
/* @__PURE__ */ e("pre", { "data-testid": "install-command", children:
|
|
667
|
+
/* @__PURE__ */ e("pre", { "data-testid": "install-command", children: D }),
|
|
638
668
|
/* @__PURE__ */ e(
|
|
639
669
|
"button",
|
|
640
670
|
{
|
|
641
671
|
type: "button",
|
|
642
672
|
className: "install-command__copy",
|
|
643
|
-
"aria-label":
|
|
644
|
-
title:
|
|
645
|
-
onClick: () => void
|
|
646
|
-
children:
|
|
673
|
+
"aria-label": g ? "Copied" : "Copy command",
|
|
674
|
+
title: g ? "Copied" : "Copy",
|
|
675
|
+
onClick: () => void H(),
|
|
676
|
+
children: g ? /* @__PURE__ */ e(
|
|
647
677
|
"svg",
|
|
648
678
|
{
|
|
649
679
|
width: "15",
|
|
@@ -678,114 +708,122 @@ function ae({ hubUrl: t }) {
|
|
|
678
708
|
}
|
|
679
709
|
)
|
|
680
710
|
] }),
|
|
711
|
+
B && /* @__PURE__ */ n("div", { className: "hook-setup", children: [
|
|
712
|
+
/* @__PURE__ */ n("p", { className: "card-sub", children: [
|
|
713
|
+
"Recommended: merge this into ",
|
|
714
|
+
/* @__PURE__ */ e("code", { children: B.target }),
|
|
715
|
+
" — it delivers teammate announcements to the agent and reminds it to link each repo before its first write."
|
|
716
|
+
] }),
|
|
717
|
+
/* @__PURE__ */ e("div", { className: "install-command", children: /* @__PURE__ */ e("pre", { "data-testid": "hook-snippet", children: B.snippet }) })
|
|
718
|
+
] }),
|
|
681
719
|
/* @__PURE__ */ e("h4", { children: "Existing tokens" }),
|
|
682
|
-
|
|
683
|
-
const
|
|
720
|
+
_ ? /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) : v.length === 0 ? /* @__PURE__ */ e("p", { children: "No tokens yet." }) : /* @__PURE__ */ e("ul", { children: v.map((u) => {
|
|
721
|
+
const O = u.name ?? u.id;
|
|
684
722
|
return /* @__PURE__ */ n("li", { children: [
|
|
685
|
-
/* @__PURE__ */ e("span", { children:
|
|
686
|
-
/* @__PURE__ */ e("span", { className: "token-meta", children:
|
|
687
|
-
|
|
723
|
+
/* @__PURE__ */ e("span", { children: O }),
|
|
724
|
+
/* @__PURE__ */ e("span", { className: "token-meta", children: ie(u, Date.now()) }),
|
|
725
|
+
u.revokedAt ? /* @__PURE__ */ e("span", { className: "revoked", children: "revoked" }) : /* @__PURE__ */ e(
|
|
688
726
|
"button",
|
|
689
727
|
{
|
|
690
728
|
type: "button",
|
|
691
|
-
"aria-label": `Revoke token ${
|
|
692
|
-
onClick: () => void
|
|
693
|
-
disabled: T ===
|
|
729
|
+
"aria-label": `Revoke token ${O}`,
|
|
730
|
+
onClick: () => void R(u.id),
|
|
731
|
+
disabled: T === u.id,
|
|
694
732
|
children: "Revoke"
|
|
695
733
|
}
|
|
696
734
|
)
|
|
697
|
-
] },
|
|
735
|
+
] }, u.id);
|
|
698
736
|
}) })
|
|
699
737
|
] })
|
|
700
738
|
] });
|
|
701
739
|
}
|
|
702
|
-
const
|
|
740
|
+
const le = [
|
|
703
741
|
{ id: "general", label: "General" },
|
|
704
742
|
{ id: "members", label: "Members" },
|
|
705
743
|
{ id: "agent", label: "Agent" }
|
|
706
744
|
];
|
|
707
|
-
function
|
|
745
|
+
function oe({
|
|
708
746
|
workspace: t,
|
|
709
747
|
hubUrl: a,
|
|
710
748
|
membersRefreshKey: o,
|
|
711
|
-
onMembersChanged:
|
|
712
|
-
onLeft:
|
|
713
|
-
onDeleted:
|
|
749
|
+
onMembersChanged: h,
|
|
750
|
+
onLeft: r,
|
|
751
|
+
onDeleted: p
|
|
714
752
|
}) {
|
|
715
|
-
const [c, b] = i("general"),
|
|
753
|
+
const [c, b] = i("general"), s = t.role === "admin";
|
|
716
754
|
return /* @__PURE__ */ n("div", { className: "config-layout", children: [
|
|
717
|
-
/* @__PURE__ */ e("nav", { className: "config-nav", "aria-label": "Configuration sections", children:
|
|
755
|
+
/* @__PURE__ */ e("nav", { className: "config-nav", "aria-label": "Configuration sections", children: le.map(({ id: y, label: v }) => /* @__PURE__ */ e(
|
|
718
756
|
"button",
|
|
719
757
|
{
|
|
720
758
|
type: "button",
|
|
721
759
|
className: "config-nav__item" + (c === y ? " config-nav__item--on" : ""),
|
|
722
760
|
"aria-current": c === y ? "page" : void 0,
|
|
723
761
|
onClick: () => b(y),
|
|
724
|
-
children:
|
|
762
|
+
children: v
|
|
725
763
|
},
|
|
726
764
|
y
|
|
727
765
|
)) }),
|
|
728
766
|
/* @__PURE__ */ n("div", { className: "config-panel", children: [
|
|
729
|
-
c === "general" && /* @__PURE__ */ e(
|
|
730
|
-
c === "members" && /* @__PURE__ */ n(
|
|
767
|
+
c === "general" && /* @__PURE__ */ e(q, { workspace: t, onLeft: r, onDeleted: p }),
|
|
768
|
+
c === "members" && /* @__PURE__ */ n(G, { children: [
|
|
731
769
|
/* @__PURE__ */ e(
|
|
732
|
-
|
|
770
|
+
z,
|
|
733
771
|
{
|
|
734
772
|
workspaceId: t.id,
|
|
735
773
|
refreshKey: o,
|
|
736
|
-
canRemove:
|
|
774
|
+
canRemove: s
|
|
737
775
|
}
|
|
738
776
|
),
|
|
739
|
-
|
|
777
|
+
s && /* @__PURE__ */ e(Q, { workspaceId: t.id, onMembersChanged: h })
|
|
740
778
|
] }),
|
|
741
|
-
c === "agent" && /* @__PURE__ */ e(
|
|
779
|
+
c === "agent" && /* @__PURE__ */ e(se, { hubUrl: a })
|
|
742
780
|
] })
|
|
743
781
|
] });
|
|
744
782
|
}
|
|
745
|
-
function
|
|
746
|
-
const a =
|
|
783
|
+
function he({ hubUrl: t }) {
|
|
784
|
+
const a = j(), [o, h] = i({ status: "loading" }), [r, p] = i(null), [c, b] = i(0), s = M(async () => {
|
|
747
785
|
try {
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
(
|
|
786
|
+
const m = await a.listWorkspaces();
|
|
787
|
+
h({ status: "ready", workspaces: m.workspaces }), p(
|
|
788
|
+
(C) => {
|
|
751
789
|
var E;
|
|
752
|
-
return
|
|
790
|
+
return C && m.workspaces.some((l) => l.id === C) ? C : ((E = m.workspaces[0]) == null ? void 0 : E.id) ?? null;
|
|
753
791
|
}
|
|
754
792
|
);
|
|
755
|
-
} catch (
|
|
756
|
-
|
|
793
|
+
} catch (m) {
|
|
794
|
+
h({ status: "error", message: S(m) });
|
|
757
795
|
}
|
|
758
796
|
}, [a]);
|
|
759
797
|
A(() => {
|
|
760
|
-
|
|
761
|
-
}, [
|
|
762
|
-
const y = o.status === "ready" ? o.workspaces : [],
|
|
798
|
+
s();
|
|
799
|
+
}, [s]);
|
|
800
|
+
const y = o.status === "ready" ? o.workspaces : [], v = y.find((m) => m.id === r) ?? null;
|
|
763
801
|
if (o.status === "loading")
|
|
764
802
|
return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e("p", { role: "status", children: "Loading…" }) });
|
|
765
803
|
if (o.status === "error")
|
|
766
804
|
return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e("p", { role: "alert", children: o.message }) });
|
|
767
|
-
const
|
|
768
|
-
|
|
805
|
+
const f = y.length > 0, N = /* @__PURE__ */ e(
|
|
806
|
+
V,
|
|
769
807
|
{
|
|
770
808
|
workspaces: y,
|
|
771
|
-
selected:
|
|
772
|
-
onSelect:
|
|
809
|
+
selected: v,
|
|
810
|
+
onSelect: p,
|
|
773
811
|
onChanged: () => {
|
|
774
|
-
|
|
812
|
+
s();
|
|
775
813
|
},
|
|
776
|
-
onMembersChanged: () => b((
|
|
814
|
+
onMembersChanged: () => b((m) => m + 1)
|
|
777
815
|
}
|
|
778
816
|
), k = /* @__PURE__ */ n("section", { className: "shepherd-config", "aria-labelledby": "config-heading", children: [
|
|
779
817
|
/* @__PURE__ */ e("h2", { id: "config-heading", children: "Configuration" }),
|
|
780
|
-
|
|
781
|
-
|
|
818
|
+
v ? /* @__PURE__ */ e(
|
|
819
|
+
oe,
|
|
782
820
|
{
|
|
783
|
-
workspace:
|
|
821
|
+
workspace: v,
|
|
784
822
|
hubUrl: t,
|
|
785
823
|
membersRefreshKey: c,
|
|
786
|
-
onMembersChanged: () => b((
|
|
787
|
-
onLeft: () => void
|
|
788
|
-
onDeleted: () => void
|
|
824
|
+
onMembersChanged: () => b((m) => m + 1),
|
|
825
|
+
onLeft: () => void s(),
|
|
826
|
+
onDeleted: () => void s()
|
|
789
827
|
}
|
|
790
828
|
) : /* @__PURE__ */ n("p", { className: "config-none", children: [
|
|
791
829
|
"You're not in a workspace yet. Use the ",
|
|
@@ -794,28 +832,28 @@ function ce({ hubUrl: t }) {
|
|
|
794
832
|
] })
|
|
795
833
|
] });
|
|
796
834
|
return /* @__PURE__ */ e("div", { className: "shepherd-root", children: /* @__PURE__ */ e(
|
|
797
|
-
|
|
835
|
+
J,
|
|
798
836
|
{
|
|
799
|
-
workspaceId:
|
|
837
|
+
workspaceId: v == null ? void 0 : v.id,
|
|
800
838
|
config: k,
|
|
801
|
-
switcher:
|
|
802
|
-
hasWorkspace:
|
|
839
|
+
switcher: N,
|
|
840
|
+
hasWorkspace: f
|
|
803
841
|
}
|
|
804
842
|
) });
|
|
805
843
|
}
|
|
806
844
|
export {
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
845
|
+
oe as ConfigPanel,
|
|
846
|
+
se as ConnectAgent,
|
|
847
|
+
J as Dashboard,
|
|
848
|
+
ve as EmptyState,
|
|
849
|
+
q as GeneralSettings,
|
|
850
|
+
Q as Invites,
|
|
851
|
+
z as Members,
|
|
852
|
+
Y as ShepherdClientError,
|
|
853
|
+
fe as ShepherdClientProvider,
|
|
854
|
+
he as ShepherdRoot,
|
|
855
|
+
V as WorkspaceSwitcher,
|
|
856
|
+
ye as createShepherdClient,
|
|
857
|
+
S as describeError,
|
|
858
|
+
j as useShepherdClient
|
|
821
859
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@korso/shepherd-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
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": "AGPL-3.0-only",
|