agent-relay-server 0.21.0 → 0.22.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/docs/openapi.json +4 -1
- package/package.json +2 -2
- package/public/index.html +227 -94
- package/src/cli.ts +62 -8
- package/src/maintenance.ts +9 -4
- package/src/mcp.ts +244 -2
- package/src/routes.ts +79 -167
- package/src/workspace-actions.ts +336 -0
- package/src/workspace-phase.ts +181 -0
package/docs/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Relay API",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.21.0",
|
|
6
6
|
"description": "Real-time message bus for inter-agent communication. Agent-first: this spec is designed for machine consumption — agents can self-discover the full API surface via GET /api/spec.",
|
|
7
7
|
"license": {
|
|
8
8
|
"name": "MIT",
|
|
@@ -796,6 +796,9 @@
|
|
|
796
796
|
},
|
|
797
797
|
"workspaceMode": {
|
|
798
798
|
"type": "string"
|
|
799
|
+
},
|
|
800
|
+
"profile": {
|
|
801
|
+
"type": "string"
|
|
799
802
|
}
|
|
800
803
|
}
|
|
801
804
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Lightweight HTTP message relay for inter-agent communication across machines",
|
|
5
5
|
"module": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"CONTRIBUTING.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"agent-relay-sdk": "0.2.
|
|
36
|
+
"agent-relay-sdk": "0.2.13"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"prepack": "bun run build:dashboard:bundle >&2",
|
package/public/index.html
CHANGED
|
@@ -12099,9 +12099,11 @@ function isDashboardHidden() {
|
|
|
12099
12099
|
function notificationPeer(notification) {
|
|
12100
12100
|
return notification.threadPeer || notification.agentId || "";
|
|
12101
12101
|
}
|
|
12102
|
+
function isActiveVisibleChat(peer, state) {
|
|
12103
|
+
return Boolean(peer && state.view === "chat" && state.selectedInboxThread === peer && !isDashboardHidden());
|
|
12104
|
+
}
|
|
12102
12105
|
function notificationTargetsActiveChat(notification, state) {
|
|
12103
|
-
|
|
12104
|
-
return Boolean(state.view === "chat" && peer && state.selectedInboxThread === peer && !isDashboardHidden());
|
|
12106
|
+
return isActiveVisibleChat(notificationPeer(notification), state);
|
|
12105
12107
|
}
|
|
12106
12108
|
function lastInboundMessageId(messages) {
|
|
12107
12109
|
return messages.filter((m) => m.to === "user" && m.from !== "user").reduce((max, m) => Math.max(max, m.id), 0);
|
|
@@ -12835,7 +12837,15 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12835
12837
|
if (s.view === "messages" && s.selectedAgent) path += "&for=" + encodeURIComponent(s.selectedAgent);
|
|
12836
12838
|
if (s.view === "messages" && s.channelFilter) path += "&channel=" + encodeURIComponent(s.channelFilter);
|
|
12837
12839
|
const messages = await api("GET", path);
|
|
12838
|
-
|
|
12840
|
+
const merged = mergeFetchedMessages(get().messages, messages);
|
|
12841
|
+
set({ messages: merged });
|
|
12842
|
+
const after = get();
|
|
12843
|
+
const peer = after.selectedInboxThread;
|
|
12844
|
+
if (isActiveVisibleChat(peer, after)) {
|
|
12845
|
+
let lastId = 0;
|
|
12846
|
+
for (const m of merged) if (m.id > lastId && inboxPeer(m) === peer && isHumanInboundMessage(m) && !isSessionActivityStep(m)) lastId = m.id;
|
|
12847
|
+
if (lastId) get().markInboxThreadReadTo(peer, lastId);
|
|
12848
|
+
}
|
|
12839
12849
|
} catch {}
|
|
12840
12850
|
},
|
|
12841
12851
|
async fetchThreadHistory(peer) {
|
|
@@ -12936,7 +12946,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12936
12946
|
if (msgs.length > 500) msgs.splice(0, msgs.length - 500);
|
|
12937
12947
|
set({ messages: msgs });
|
|
12938
12948
|
const peer = inboxPeer(msg);
|
|
12939
|
-
if (isHumanInboundMessage(msg) && peer
|
|
12949
|
+
if (isHumanInboundMessage(msg) && isActiveVisibleChat(peer, s)) get().markInboxThreadReadTo(peer, msg.id);
|
|
12940
12950
|
return;
|
|
12941
12951
|
}
|
|
12942
12952
|
if (event === "message.queued" || event === "message.expired" || event === "message.delivery_updated" || event === "message.reaction_updated") {
|
|
@@ -99801,6 +99811,45 @@ function Button({ className, variant = "default", size = "default", asChild = fa
|
|
|
99801
99811
|
});
|
|
99802
99812
|
}
|
|
99803
99813
|
//#endregion
|
|
99814
|
+
//#region src/components/shared/copy-button.tsx
|
|
99815
|
+
/**
|
|
99816
|
+
* Shared copy-to-clipboard button with a transient "copied" check state.
|
|
99817
|
+
* Consolidates the duplicated clipboard + timeout pattern used across views.
|
|
99818
|
+
*/
|
|
99819
|
+
function CopyButton({ value, label = "Copy", copiedLabel = "Copied", showText = false, size, variant = "ghost", className, iconClassName, disabled, onCopied }) {
|
|
99820
|
+
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
99821
|
+
const timer = (0, import_react.useRef)(null);
|
|
99822
|
+
(0, import_react.useEffect)(() => () => {
|
|
99823
|
+
if (timer.current) clearTimeout(timer.current);
|
|
99824
|
+
}, []);
|
|
99825
|
+
async function copy(e) {
|
|
99826
|
+
e.preventDefault();
|
|
99827
|
+
e.stopPropagation();
|
|
99828
|
+
try {
|
|
99829
|
+
await navigator.clipboard?.writeText(typeof value === "function" ? value() : value);
|
|
99830
|
+
setCopied(true);
|
|
99831
|
+
onCopied?.();
|
|
99832
|
+
if (timer.current) clearTimeout(timer.current);
|
|
99833
|
+
timer.current = setTimeout(() => setCopied(false), 1400);
|
|
99834
|
+
} catch {
|
|
99835
|
+
setCopied(false);
|
|
99836
|
+
}
|
|
99837
|
+
}
|
|
99838
|
+
const resolvedSize = size ?? (showText ? "sm" : "icon-sm");
|
|
99839
|
+
const iconCls = cn$2("h-3.5 w-3.5", iconClassName);
|
|
99840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
99841
|
+
type: "button",
|
|
99842
|
+
size: resolvedSize,
|
|
99843
|
+
variant,
|
|
99844
|
+
className,
|
|
99845
|
+
disabled,
|
|
99846
|
+
title: copied ? copiedLabel : label,
|
|
99847
|
+
"aria-label": copied ? copiedLabel : label,
|
|
99848
|
+
onClick: (e) => void copy(e),
|
|
99849
|
+
children: [copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: iconCls }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: iconCls }), showText && (copied ? copiedLabel : label)]
|
|
99850
|
+
});
|
|
99851
|
+
}
|
|
99852
|
+
//#endregion
|
|
99804
99853
|
//#region \0vite/preload-helper.js
|
|
99805
99854
|
var scriptRel, assetsURL, seen, __vitePreload;
|
|
99806
99855
|
var init_preload_helper = __esmMin((() => {
|
|
@@ -108465,25 +108514,14 @@ var CodePreview = (0, import_react.memo)(function CodePreview({ content, path, m
|
|
|
108465
108514
|
const [html, setHtml] = (0, import_react.useState)("");
|
|
108466
108515
|
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
108467
108516
|
const [failed, setFailed] = (0, import_react.useState)(false);
|
|
108468
|
-
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
108469
|
-
async function copyCode() {
|
|
108470
|
-
try {
|
|
108471
|
-
await navigator.clipboard?.writeText(content);
|
|
108472
|
-
setCopied(true);
|
|
108473
|
-
window.setTimeout(() => setCopied(false), 1400);
|
|
108474
|
-
} catch {
|
|
108475
|
-
setCopied(false);
|
|
108476
|
-
}
|
|
108477
|
-
}
|
|
108478
108517
|
function copyButton() {
|
|
108479
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
108480
|
-
|
|
108518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
108519
|
+
value: content,
|
|
108520
|
+
label: "Copy code",
|
|
108521
|
+
copiedLabel: "Copied code",
|
|
108481
108522
|
size: "icon",
|
|
108482
108523
|
variant: "ghost",
|
|
108483
|
-
className: "absolute right-2 top-2 h-7 w-7 bg-background/80 opacity-0 shadow-sm backdrop-blur transition-opacity hover:bg-muted group-hover/code:opacity-100 focus-visible:opacity-100"
|
|
108484
|
-
onClick: copyCode,
|
|
108485
|
-
title: copied ? "Copied code" : "Copy code",
|
|
108486
|
-
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "h-3.5 w-3.5" })
|
|
108524
|
+
className: "absolute right-2 top-2 h-7 w-7 bg-background/80 opacity-0 shadow-sm backdrop-blur transition-opacity hover:bg-muted group-hover/code:opacity-100 focus-visible:opacity-100"
|
|
108487
108525
|
});
|
|
108488
108526
|
}
|
|
108489
108527
|
(0, import_react.useEffect)(() => {
|
|
@@ -124794,7 +124832,6 @@ function FileContent({ orchestratorId, selectedPath, line, onReadError }) {
|
|
|
124794
124832
|
const { file, loading, error } = useFileRead(orchestratorId, selectedPath);
|
|
124795
124833
|
const lineRef = (0, import_react.useRef)(null);
|
|
124796
124834
|
const [mode, setMode] = (0, import_react.useState)("raw");
|
|
124797
|
-
const [copiedPath, setCopiedPath] = (0, import_react.useState)(false);
|
|
124798
124835
|
(0, import_react.useEffect)(() => {
|
|
124799
124836
|
onReadError(error);
|
|
124800
124837
|
}, [error, onReadError]);
|
|
@@ -124816,15 +124853,6 @@ function FileContent({ orchestratorId, selectedPath, line, onReadError }) {
|
|
|
124816
124853
|
file?.content,
|
|
124817
124854
|
line
|
|
124818
124855
|
]);
|
|
124819
|
-
async function copyPath(path) {
|
|
124820
|
-
try {
|
|
124821
|
-
await navigator.clipboard?.writeText(path);
|
|
124822
|
-
setCopiedPath(true);
|
|
124823
|
-
window.setTimeout(() => setCopiedPath(false), 1400);
|
|
124824
|
-
} catch {
|
|
124825
|
-
setCopiedPath(false);
|
|
124826
|
-
}
|
|
124827
|
-
}
|
|
124828
124856
|
function selectMode(nextMode, kind) {
|
|
124829
124857
|
setMode(nextMode);
|
|
124830
124858
|
if (kind) writeModePreference(kind, nextMode);
|
|
@@ -124849,14 +124877,13 @@ function FileContent({ orchestratorId, selectedPath, line, onReadError }) {
|
|
|
124849
124877
|
className: "min-w-0 flex-1 truncate font-mono",
|
|
124850
124878
|
children: file.path
|
|
124851
124879
|
}),
|
|
124852
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
124853
|
-
|
|
124880
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
124881
|
+
value: file.path,
|
|
124882
|
+
label: "Copy path",
|
|
124883
|
+
copiedLabel: "Copied path",
|
|
124854
124884
|
size: "icon",
|
|
124855
124885
|
variant: "ghost",
|
|
124856
|
-
className: "h-7 w-7 shrink-0"
|
|
124857
|
-
onClick: () => copyPath(file.path),
|
|
124858
|
-
title: copiedPath ? "Copied path" : "Copy path",
|
|
124859
|
-
children: copiedPath ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "h-3.5 w-3.5" })
|
|
124886
|
+
className: "h-7 w-7 shrink-0"
|
|
124860
124887
|
}),
|
|
124861
124888
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
124862
124889
|
variant: "outline",
|
|
@@ -124913,14 +124940,13 @@ function FileContent({ orchestratorId, selectedPath, line, onReadError }) {
|
|
|
124913
124940
|
className: "min-w-0 flex-1 truncate font-mono",
|
|
124914
124941
|
children: file.path
|
|
124915
124942
|
}),
|
|
124916
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
124917
|
-
|
|
124943
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
124944
|
+
value: file.path,
|
|
124945
|
+
label: "Copy path",
|
|
124946
|
+
copiedLabel: "Copied path",
|
|
124918
124947
|
size: "icon",
|
|
124919
124948
|
variant: "ghost",
|
|
124920
|
-
className: "h-7 w-7 shrink-0"
|
|
124921
|
-
onClick: () => copyPath(file.path),
|
|
124922
|
-
title: copiedPath ? "Copied path" : "Copy path",
|
|
124923
|
-
children: copiedPath ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "h-3.5 w-3.5" })
|
|
124949
|
+
className: "h-7 w-7 shrink-0"
|
|
124924
124950
|
}),
|
|
124925
124951
|
file.truncated && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
124926
124952
|
variant: "secondary",
|
|
@@ -127549,6 +127575,11 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
127549
127575
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
127550
127576
|
className: "flex items-center gap-0.5 md:gap-1 shrink-0",
|
|
127551
127577
|
children: agent && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
127578
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
127579
|
+
value: agent.id,
|
|
127580
|
+
label: "Copy agent ID",
|
|
127581
|
+
size: "icon-sm"
|
|
127582
|
+
}),
|
|
127552
127583
|
voiceTts.available && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
127553
127584
|
variant: "ghost",
|
|
127554
127585
|
size: "icon-sm",
|
|
@@ -128193,6 +128224,13 @@ function AgentCard({ agent }) {
|
|
|
128193
128224
|
className: "flex gap-1 mt-2.5 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity",
|
|
128194
128225
|
onClick: (e) => e.stopPropagation(),
|
|
128195
128226
|
children: [
|
|
128227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
128228
|
+
value: agent.id,
|
|
128229
|
+
label: "Copy agent ID",
|
|
128230
|
+
size: "icon",
|
|
128231
|
+
className: "h-7 w-7",
|
|
128232
|
+
iconClassName: "w-3 h-3"
|
|
128233
|
+
}),
|
|
128196
128234
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
128197
128235
|
size: "icon",
|
|
128198
128236
|
variant: "ghost",
|
|
@@ -129392,9 +129430,6 @@ function WorkspaceActions({ workspace, expanded, onToggleDetails }) {
|
|
|
129392
129430
|
const gitState = useRelayStore((s) => s.workspaceGitState[workspace.id]);
|
|
129393
129431
|
const landed = !!gitState && gitState.available !== false && gitState.landed === true;
|
|
129394
129432
|
const mergeable = workspace.mode === "isolated" && Boolean(workspace.worktreePath) && MERGEABLE_STATUSES.has(workspace.status) && !landed;
|
|
129395
|
-
async function copyPath() {
|
|
129396
|
-
await navigator.clipboard?.writeText(openPath);
|
|
129397
|
-
}
|
|
129398
129433
|
async function merge() {
|
|
129399
129434
|
await fetchWorkspaceMergePreview(workspace.id);
|
|
129400
129435
|
await workspaceAction(workspace.id, "merge");
|
|
@@ -129417,13 +129452,13 @@ function WorkspaceActions({ workspace, expanded, onToggleDetails }) {
|
|
|
129417
129452
|
onClick: () => void openFilesAt({ path: openPath }),
|
|
129418
129453
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderOpen, { className: "h-3.5 w-3.5" })
|
|
129419
129454
|
}),
|
|
129420
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
129455
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
129456
|
+
value: openPath,
|
|
129457
|
+
label: "Copy path",
|
|
129458
|
+
copiedLabel: "Copied path",
|
|
129421
129459
|
size: "icon-sm",
|
|
129422
129460
|
variant: "ghost",
|
|
129423
|
-
|
|
129424
|
-
disabled: !openPath,
|
|
129425
|
-
onClick: () => void copyPath(),
|
|
129426
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "h-3.5 w-3.5" })
|
|
129461
|
+
disabled: !openPath
|
|
129427
129462
|
}),
|
|
129428
129463
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
129429
129464
|
size: "icon-sm",
|
|
@@ -130703,10 +130738,6 @@ function SecurityView() {
|
|
|
130703
130738
|
await api("POST", `/tokens/${encodeURIComponent(token.jti)}/revoke`);
|
|
130704
130739
|
await refresh();
|
|
130705
130740
|
}
|
|
130706
|
-
async function copy(value) {
|
|
130707
|
-
await navigator.clipboard?.writeText(value);
|
|
130708
|
-
setStatus("Copied");
|
|
130709
|
-
}
|
|
130710
130741
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
130711
130742
|
className: "space-y-4",
|
|
130712
130743
|
children: [
|
|
@@ -130936,11 +130967,12 @@ function SecurityView() {
|
|
|
130936
130967
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
130937
130968
|
className: "text-xs text-muted-foreground",
|
|
130938
130969
|
children: "New token"
|
|
130939
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
130940
|
-
|
|
130970
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
130971
|
+
value: issuedToken,
|
|
130972
|
+
label: "Copy token",
|
|
130941
130973
|
size: "sm",
|
|
130942
|
-
|
|
130943
|
-
|
|
130974
|
+
variant: "ghost",
|
|
130975
|
+
onCopied: () => setStatus("Copied")
|
|
130944
130976
|
})]
|
|
130945
130977
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
|
|
130946
130978
|
className: "block max-h-24 overflow-auto break-all text-xs",
|
|
@@ -153632,8 +153664,11 @@ function MaintenanceView() {
|
|
|
153632
153664
|
})]
|
|
153633
153665
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollArea, {
|
|
153634
153666
|
className: "h-[calc(100dvh-10rem)]",
|
|
153635
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153636
|
-
className: "
|
|
153667
|
+
children: jobs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153668
|
+
className: "rounded-md border border-border px-3 py-12 text-center text-sm text-muted-foreground",
|
|
153669
|
+
children: "No maintenance jobs registered"
|
|
153670
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153671
|
+
className: "hidden overflow-x-auto rounded-md border border-border md:block",
|
|
153637
153672
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", {
|
|
153638
153673
|
className: "w-full min-w-[980px] text-sm",
|
|
153639
153674
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", {
|
|
@@ -153668,22 +153703,117 @@ function MaintenanceView() {
|
|
|
153668
153703
|
children: "Action"
|
|
153669
153704
|
})
|
|
153670
153705
|
] })
|
|
153671
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: jobs.
|
|
153672
|
-
colSpan: 7,
|
|
153673
|
-
className: "px-3 py-12 text-center text-sm text-muted-foreground",
|
|
153674
|
-
children: "No maintenance jobs registered"
|
|
153675
|
-
}) }) : jobs.map((job) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaintenanceRow, {
|
|
153706
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: jobs.map((job) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaintenanceRow, {
|
|
153676
153707
|
job,
|
|
153677
153708
|
now,
|
|
153678
153709
|
onRun: () => void runMaintenanceJob(job.id)
|
|
153679
153710
|
}, job.id)) })]
|
|
153680
153711
|
})
|
|
153681
|
-
})
|
|
153712
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153713
|
+
className: "space-y-3 md:hidden",
|
|
153714
|
+
children: jobs.map((job) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaintenanceCard, {
|
|
153715
|
+
job,
|
|
153716
|
+
now,
|
|
153717
|
+
onRun: () => void runMaintenanceJob(job.id)
|
|
153718
|
+
}, job.id))
|
|
153719
|
+
})] })
|
|
153682
153720
|
})]
|
|
153683
153721
|
});
|
|
153684
153722
|
}
|
|
153723
|
+
function jobStatus(job) {
|
|
153724
|
+
return job.running ? "running" : job.enabled ? job.lastStatus : "disabled";
|
|
153725
|
+
}
|
|
153726
|
+
function StatusBadge({ status }) {
|
|
153727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge$1, {
|
|
153728
|
+
variant: "outline",
|
|
153729
|
+
className: cn$2("border", STATUS_CLASS[status] || STATUS_CLASS.idle),
|
|
153730
|
+
children: [statusIcon(status), status]
|
|
153731
|
+
});
|
|
153732
|
+
}
|
|
153733
|
+
function MaintenanceCard({ job, now, onRun }) {
|
|
153734
|
+
const status = jobStatus(job);
|
|
153735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153736
|
+
className: "rounded-md border border-border p-3",
|
|
153737
|
+
children: [
|
|
153738
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153739
|
+
className: "flex items-start justify-between gap-2",
|
|
153740
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153741
|
+
className: "min-w-0",
|
|
153742
|
+
children: [
|
|
153743
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153744
|
+
className: "font-medium",
|
|
153745
|
+
children: job.title
|
|
153746
|
+
}),
|
|
153747
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153748
|
+
className: "mt-0.5 text-xs text-muted-foreground",
|
|
153749
|
+
children: job.description
|
|
153750
|
+
}),
|
|
153751
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153752
|
+
className: "mt-1 font-mono text-[11px] text-muted-foreground/80",
|
|
153753
|
+
children: job.id
|
|
153754
|
+
})
|
|
153755
|
+
]
|
|
153756
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { status })]
|
|
153757
|
+
}),
|
|
153758
|
+
job.consecutiveFailures > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153759
|
+
className: "mt-2 text-xs text-red-400",
|
|
153760
|
+
children: [
|
|
153761
|
+
job.consecutiveFailures,
|
|
153762
|
+
" failure",
|
|
153763
|
+
job.consecutiveFailures === 1 ? "" : "s"
|
|
153764
|
+
]
|
|
153765
|
+
}),
|
|
153766
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
|
|
153767
|
+
className: "mt-3 grid grid-cols-3 gap-2 text-xs",
|
|
153768
|
+
children: [
|
|
153769
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
153770
|
+
className: "text-muted-foreground",
|
|
153771
|
+
children: "Last run"
|
|
153772
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: job.lastRunAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
153773
|
+
title: fmtTime$1(job.lastRunAt),
|
|
153774
|
+
children: timeAgo(now, job.lastRunAt)
|
|
153775
|
+
}) : "never" })] }),
|
|
153776
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
153777
|
+
className: "text-muted-foreground",
|
|
153778
|
+
children: "Next run"
|
|
153779
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: job.nextRunAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
153780
|
+
title: fmtTime$1(job.nextRunAt),
|
|
153781
|
+
children: nextRunText(now, job.nextRunAt)
|
|
153782
|
+
}) : "-" })] }),
|
|
153783
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
153784
|
+
className: "text-muted-foreground",
|
|
153785
|
+
children: "Duration"
|
|
153786
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: job.lastDurationMs !== void 0 ? `${job.lastDurationMs}ms` : "-" })] })
|
|
153787
|
+
]
|
|
153788
|
+
}),
|
|
153789
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153790
|
+
className: "mt-3",
|
|
153791
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153792
|
+
className: "text-xs text-muted-foreground",
|
|
153793
|
+
children: "Result"
|
|
153794
|
+
}), job.lastError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153795
|
+
className: "mt-0.5 text-xs text-red-400 line-clamp-3",
|
|
153796
|
+
children: job.lastError
|
|
153797
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153798
|
+
className: "mt-0.5 font-mono text-[11px] text-muted-foreground line-clamp-3",
|
|
153799
|
+
children: resultSummary(job)
|
|
153800
|
+
})]
|
|
153801
|
+
}),
|
|
153802
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153803
|
+
className: "mt-3 flex justify-end",
|
|
153804
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
153805
|
+
size: "sm",
|
|
153806
|
+
variant: "outline",
|
|
153807
|
+
disabled: !job.enabled || job.running,
|
|
153808
|
+
onClick: onRun,
|
|
153809
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Play, { className: "h-3.5 w-3.5" }), " Run"]
|
|
153810
|
+
})
|
|
153811
|
+
})
|
|
153812
|
+
]
|
|
153813
|
+
});
|
|
153814
|
+
}
|
|
153685
153815
|
function MaintenanceRow({ job, now, onRun }) {
|
|
153686
|
-
const status = job
|
|
153816
|
+
const status = jobStatus(job);
|
|
153687
153817
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
|
|
153688
153818
|
className: "border-t border-border align-top",
|
|
153689
153819
|
children: [
|
|
@@ -153706,11 +153836,7 @@ function MaintenanceRow({ job, now, onRun }) {
|
|
|
153706
153836
|
}),
|
|
153707
153837
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", {
|
|
153708
153838
|
className: "px-3 py-3",
|
|
153709
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
153710
|
-
variant: "outline",
|
|
153711
|
-
className: cn$2("border", STATUS_CLASS[status] || STATUS_CLASS.idle),
|
|
153712
|
-
children: [statusIcon(status), status]
|
|
153713
|
-
}), job.consecutiveFailures > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153839
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, { status }), job.consecutiveFailures > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153714
153840
|
className: "mt-1 text-xs text-red-400",
|
|
153715
153841
|
children: [
|
|
153716
153842
|
job.consecutiveFailures,
|
|
@@ -154392,7 +154518,6 @@ function AgentDiagnostics({ agent, orchestrators }) {
|
|
|
154392
154518
|
const now = useNow();
|
|
154393
154519
|
const [policyHealth, setPolicyHealth] = (0, import_react.useState)(null);
|
|
154394
154520
|
const [agentEvents, setAgentEvents] = (0, import_react.useState)([]);
|
|
154395
|
-
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
154396
154521
|
const [expandedSections, setExpandedSections] = (0, import_react.useState)({
|
|
154397
154522
|
spawn: true,
|
|
154398
154523
|
workspace: true,
|
|
@@ -154436,7 +154561,7 @@ function AgentDiagnostics({ agent, orchestrators }) {
|
|
|
154436
154561
|
[key]: !s[key]
|
|
154437
154562
|
}));
|
|
154438
154563
|
}
|
|
154439
|
-
|
|
154564
|
+
function buildDiagnosticBundle() {
|
|
154440
154565
|
const policy = policyHealth?.policy;
|
|
154441
154566
|
const state = policyHealth?.state;
|
|
154442
154567
|
const lines = [
|
|
@@ -154513,11 +154638,7 @@ function AgentDiagnostics({ agent, orchestrators }) {
|
|
|
154513
154638
|
}
|
|
154514
154639
|
const contracts = agent.meta?.contracts;
|
|
154515
154640
|
if (contracts) for (const [k, v] of Object.entries(contracts)) lines.push(`Contract ${k}: ${v}`);
|
|
154516
|
-
|
|
154517
|
-
await navigator.clipboard.writeText(lines.join("\n"));
|
|
154518
|
-
setCopied(true);
|
|
154519
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
154520
|
-
} catch {}
|
|
154641
|
+
return lines.join("\n");
|
|
154521
154642
|
}
|
|
154522
154643
|
const policy = policyHealth?.policy;
|
|
154523
154644
|
const state = policyHealth?.state;
|
|
@@ -154529,12 +154650,14 @@ function AgentDiagnostics({ agent, orchestrators }) {
|
|
|
154529
154650
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", {
|
|
154530
154651
|
className: "text-sm font-medium flex items-center gap-1.5",
|
|
154531
154652
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stethoscope, { className: "w-3.5 h-3.5 text-muted-foreground" }), "Diagnostics"]
|
|
154532
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.
|
|
154653
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
154654
|
+
value: buildDiagnosticBundle,
|
|
154655
|
+
label: "Copy Bundle",
|
|
154656
|
+
showText: true,
|
|
154533
154657
|
size: "sm",
|
|
154534
154658
|
variant: "outline",
|
|
154535
154659
|
className: "h-7 text-xs gap-1",
|
|
154536
|
-
|
|
154537
|
-
children: [copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "w-3 h-3" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "w-3 h-3" }), copied ? "Copied" : "Copy Bundle"]
|
|
154660
|
+
iconClassName: "w-3 h-3"
|
|
154538
154661
|
})]
|
|
154539
154662
|
}),
|
|
154540
154663
|
policy && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollapsibleSection, {
|
|
@@ -155727,13 +155850,21 @@ function AgentDetailDrawer() {
|
|
|
155727
155850
|
className: "space-y-1 text-sm",
|
|
155728
155851
|
children: [
|
|
155729
155852
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
155730
|
-
className: "flex justify-between gap-2 min-w-0",
|
|
155853
|
+
className: "flex items-center justify-between gap-2 min-w-0",
|
|
155731
155854
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
155732
155855
|
className: "text-muted-foreground shrink-0",
|
|
155733
155856
|
children: "ID"
|
|
155734
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.
|
|
155735
|
-
className: "
|
|
155736
|
-
children:
|
|
155857
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
155858
|
+
className: "flex min-w-0 items-center gap-1",
|
|
155859
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
155860
|
+
className: "font-mono text-xs truncate",
|
|
155861
|
+
children: agent.id
|
|
155862
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
155863
|
+
value: agent.id,
|
|
155864
|
+
label: "Copy agent ID",
|
|
155865
|
+
size: "icon-xs",
|
|
155866
|
+
className: "shrink-0 text-muted-foreground"
|
|
155867
|
+
})]
|
|
155737
155868
|
})]
|
|
155738
155869
|
}),
|
|
155739
155870
|
runtimePackage && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -157317,11 +157448,6 @@ function OrchestratorInstallModal() {
|
|
|
157317
157448
|
setLoading(false);
|
|
157318
157449
|
}
|
|
157319
157450
|
}
|
|
157320
|
-
async function copy() {
|
|
157321
|
-
if (!command) return;
|
|
157322
|
-
await navigator.clipboard.writeText(command);
|
|
157323
|
-
showNotification("Install command copied");
|
|
157324
|
-
}
|
|
157325
157451
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog, {
|
|
157326
157452
|
open,
|
|
157327
157453
|
onOpenChange: (o) => !o && set({ orchestratorInstallOpen: false }),
|
|
@@ -157390,11 +157516,14 @@ function OrchestratorInstallModal() {
|
|
|
157390
157516
|
onClick: () => set({ orchestratorInstallOpen: false }),
|
|
157391
157517
|
children: "Close"
|
|
157392
157518
|
}),
|
|
157393
|
-
command && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
157519
|
+
command && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, {
|
|
157520
|
+
value: command,
|
|
157521
|
+
label: "Copy",
|
|
157522
|
+
showText: true,
|
|
157523
|
+
size: "default",
|
|
157394
157524
|
variant: "outline",
|
|
157395
157525
|
className: "gap-1",
|
|
157396
|
-
|
|
157397
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "w-3.5 h-3.5" }), "Copy"]
|
|
157526
|
+
onCopied: () => showNotification("Install command copied")
|
|
157398
157527
|
}),
|
|
157399
157528
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
157400
157529
|
className: "gap-1",
|
|
@@ -159322,6 +159451,10 @@ if ("serviceWorker" in navigator) {
|
|
|
159322
159451
|
display: inline-flex;
|
|
159323
159452
|
}
|
|
159324
159453
|
|
|
159454
|
+
.table {
|
|
159455
|
+
display: table;
|
|
159456
|
+
}
|
|
159457
|
+
|
|
159325
159458
|
.field-sizing-content {
|
|
159326
159459
|
field-sizing: content;
|
|
159327
159460
|
}
|