@korso/shepherd-ui 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Chat.js +4 -1
- package/dist/config/ConnectAgent.js +31 -8
- package/dist/lib/{Dashboard-D7tbhMwK.js → Dashboard-BSGZuM-A.js} +216 -199
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/index.js +235 -214
- package/dist/lib/selfhost.js +1 -1
- package/dist/lib/styles.css +8 -0
- package/dist/selfhost/assets/{index-dBmCZSQx.css → index-0s8wNrl-.css} +1 -1
- package/dist/selfhost/assets/{index--_PPE03M.js → index-BK1xPf0V.js} +7 -7
- package/dist/selfhost/index.html +2 -2
- package/package.json +1 -1
package/dist/components/Chat.js
CHANGED
|
@@ -56,6 +56,9 @@ export function Chat({ announcements, selectedRepo, nowMs }) {
|
|
|
56
56
|
return (
|
|
57
57
|
// The feed has no stable id; index is acceptable because the list is
|
|
58
58
|
// append-only oldest->newest and rows are never reordered in place.
|
|
59
|
-
_jsxs("div", { className: className, children: [_jsx("div", { className: "msg__avatar", style: { background: colorForName(a.fromAgentName) }, children: initialsFor(a.fromAgentName) }), _jsxs("div", { className: "msg__body", children: [_jsxs("div", { className: "msg__head", children: [_jsx("span", { className: "msg__who", style: { color: colorForName(a.fromAgentName) }, children: a.fromAgentName }), a.fromHuman ? _jsx("span", { className: "msg__human", children: a.fromHuman }) : null, a.targetAgentName !== null ? (_jsx("span", { className: "msg__to", children: `→ @${a.targetAgentName}` })) : a.
|
|
59
|
+
_jsxs("div", { className: className, children: [_jsx("div", { className: "msg__avatar", style: { background: colorForName(a.fromAgentName) }, children: initialsFor(a.fromAgentName) }), _jsxs("div", { className: "msg__body", children: [_jsxs("div", { className: "msg__head", children: [_jsx("span", { className: "msg__who", style: { color: colorForName(a.fromAgentName) }, children: a.fromAgentName }), a.fromHuman ? _jsx("span", { className: "msg__human", children: a.fromHuman }) : null, a.targetAgentName !== null ? (_jsx("span", { className: "msg__to", children: `→ @${a.targetAgentName}` })) : a.targetMemberName !== null ? (
|
|
60
|
+
// An agent addressed a specific workspace member by name;
|
|
61
|
+
// legacy/collective operator messages fall through to "admin".
|
|
62
|
+
_jsx("span", { className: "msg__to", children: `→ @${a.targetMemberName}` })) : a.toAdmin ? (_jsx("span", { className: "msg__to", children: "\u2192 admin" })) : null, _jsx("span", { className: "msg__time", children: formatRelative(a.createdAt, nowMs) })] }), _jsx("div", { className: "msg__text", children: a.body })] })] }, i));
|
|
60
63
|
})) }));
|
|
61
64
|
}
|
|
@@ -27,12 +27,14 @@ const ENV_FLAG = {
|
|
|
27
27
|
};
|
|
28
28
|
// The shepherd-inbox-hook bin: delivers teammate announcements out-of-band AND
|
|
29
29
|
// nudges the agent to run `link` before its first write in an unlinked repo.
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
// Cursor
|
|
33
|
-
//
|
|
30
|
+
// The MCP server installs this ITSELF the first time the agent runs (once per
|
|
31
|
+
// machine, additive-only, `SHEPHERD_NO_AUTO_HOOKS=1` to opt out) — Claude,
|
|
32
|
+
// Codex, and Cursor get their config merged, Pi gets the bundled extension
|
|
33
|
+
// file copied in. So the dashboard's job is to SAY that, name where the write
|
|
34
|
+
// lands, and keep the manual equivalent as a collapsed reference for users who
|
|
35
|
+
// opted out or want to audit the change.
|
|
34
36
|
const HOOK_COMMAND = "npx -y --package=@korso/shepherd shepherd-inbox-hook";
|
|
35
|
-
function
|
|
37
|
+
function hookSetup(tool) {
|
|
36
38
|
if (tool === "claude") {
|
|
37
39
|
// SessionStart front-loads the link ask; PreToolUse delivers announcements
|
|
38
40
|
// and re-nudges right before a write in a still-unlinked repo.
|
|
@@ -62,6 +64,27 @@ function hookSnippet(tool) {
|
|
|
62
64
|
].join("\n"),
|
|
63
65
|
};
|
|
64
66
|
}
|
|
67
|
+
if (tool === "pi") {
|
|
68
|
+
// Pi delivery is a bundled extension FILE, not a config edit — the
|
|
69
|
+
// auto-install copies it into place; there is nothing to paste manually.
|
|
70
|
+
return {
|
|
71
|
+
target: "~/.pi/agent/extensions/shepherd-inbox.js",
|
|
72
|
+
snippet: null,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (tool === "cursor") {
|
|
76
|
+
// Only beforeSubmitPrompt is wired: it is the one Cursor event verified
|
|
77
|
+
// (spike, Cursor 3.9.16) to inject the hook's output into model context.
|
|
78
|
+
return {
|
|
79
|
+
target: "~/.cursor/hooks.json",
|
|
80
|
+
snippet: JSON.stringify({
|
|
81
|
+
version: 1,
|
|
82
|
+
hooks: {
|
|
83
|
+
beforeSubmitPrompt: [{ command: HOOK_COMMAND }],
|
|
84
|
+
},
|
|
85
|
+
}, null, 2),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
65
88
|
return null;
|
|
66
89
|
}
|
|
67
90
|
// "created 3d ago · never used" / "created 3d ago · last used 2h ago" — helps
|
|
@@ -177,18 +200,18 @@ export function ConnectAgent({ hubUrl }) {
|
|
|
177
200
|
}
|
|
178
201
|
}
|
|
179
202
|
const command = installCommand(tool, directHubUrl, rawToken ?? TOKEN_PLACEHOLDER);
|
|
180
|
-
const hook =
|
|
203
|
+
const hook = hookSetup(tool);
|
|
181
204
|
async function copyCommand() {
|
|
182
205
|
await navigator.clipboard.writeText(command);
|
|
183
206
|
setCopied(true);
|
|
184
207
|
setTimeout(() => setCopied(false), 2000);
|
|
185
208
|
}
|
|
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
|
|
209
|
+
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 changes files in a repo, Shepherd asks which workspace to coordinate that repo with \u2014 once per repo, right in your 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), onKeyDown: (e) => {
|
|
187
210
|
if (e.key === "Enter" && !busy) {
|
|
188
211
|
e.preventDefault();
|
|
189
212
|
void generate();
|
|
190
213
|
}
|
|
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: ["
|
|
214
|
+
}, 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: ["Message delivery sets itself up: the first time the agent runs, Shepherd adds its inbox hook to ", _jsx("code", { children: hook.target }), " ", "automatically \u2014 it delivers teammate announcements and reminds the agent to link each repo before its first write. Happens at most once; set ", _jsx("code", { children: "SHEPHERD_NO_AUTO_HOOKS=1" }), " to opt out."] }), hook.snippet && (_jsxs("details", { className: "hook-reference", children: [_jsx("summary", { children: "What gets added (manual equivalent)" }), _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) => {
|
|
192
215
|
const name = t.name ?? t.id;
|
|
193
216
|
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));
|
|
194
217
|
}) }))] })] }));
|