@mcoda/agent-setup 0.1.66 → 0.1.70
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/README.md +10 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +296 -68
- package/dist/server/service.d.ts.map +1 -1
- package/dist/server/service.js +35 -17
- package/examples/express-server/README.md +4 -0
- package/examples/nextjs-mcoda-agent-setup/README.md +1 -0
- package/examples/vite-react-mcoda-agent-setup/README.md +1 -0
- package/package.json +6 -2
- package/styles/react.css +570 -0
package/README.md
CHANGED
|
@@ -11,4 +11,13 @@ The package provides:
|
|
|
11
11
|
- an optional React setup page
|
|
12
12
|
|
|
13
13
|
The default server runtime uses mcoda package APIs directly and does not require
|
|
14
|
-
a preinstalled or configured `mcoda` CLI/client tool.
|
|
14
|
+
a preinstalled or configured `mcoda` CLI/client tool. When an admin submits a
|
|
15
|
+
real mswarm API key through `configureMswarmApiKey()`, subsequent cloud and
|
|
16
|
+
self-hosted catalog reads use the real mswarm API via `MswarmApi`.
|
|
17
|
+
|
|
18
|
+
React consumers can use the packaged default stylesheet:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { McodaAgentSetupPage } from "@mcoda/agent-setup/react";
|
|
22
|
+
import "@mcoda/agent-setup/react/styles.css";
|
|
23
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC,iCAAiC,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,qBAAqB,EAAE,OAAO,qBAAqB,CAAC;IACpD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;CAC7C;AAUD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,KAAK,CAAC,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|
package/dist/react/index.js
CHANGED
|
@@ -22,9 +22,11 @@ export function McodaAgentSetupPage(props) {
|
|
|
22
22
|
const [apiKey, setApiKey] = React.useState("");
|
|
23
23
|
const [busy, setBusy] = React.useState(false);
|
|
24
24
|
const [error, setError] = React.useState(null);
|
|
25
|
+
const [statusMessage, setStatusMessage] = React.useState(null);
|
|
25
26
|
const refresh = React.useCallback(async () => {
|
|
26
27
|
setBusy(true);
|
|
27
28
|
setError(null);
|
|
29
|
+
setStatusMessage(null);
|
|
28
30
|
try {
|
|
29
31
|
const next = await props.client.fetchSnapshot();
|
|
30
32
|
setSnapshot(next);
|
|
@@ -45,11 +47,13 @@ export function McodaAgentSetupPage(props) {
|
|
|
45
47
|
return;
|
|
46
48
|
setBusy(true);
|
|
47
49
|
setError(null);
|
|
50
|
+
setStatusMessage(null);
|
|
48
51
|
try {
|
|
49
52
|
const next = await props.client.configureMswarmApiKey({ apiKey });
|
|
50
53
|
setApiKey("");
|
|
51
54
|
setSnapshot(next);
|
|
52
55
|
setAssignments(next.assignments);
|
|
56
|
+
setStatusMessage("mswarm API key saved and agent catalogs synced.");
|
|
53
57
|
}
|
|
54
58
|
catch (caught) {
|
|
55
59
|
setError(caught instanceof Error ? caught.message : String(caught));
|
|
@@ -61,10 +65,12 @@ export function McodaAgentSetupPage(props) {
|
|
|
61
65
|
const syncAgents = async () => {
|
|
62
66
|
setBusy(true);
|
|
63
67
|
setError(null);
|
|
68
|
+
setStatusMessage(null);
|
|
64
69
|
try {
|
|
65
70
|
const next = await props.client.syncAgents();
|
|
66
71
|
setSnapshot(next);
|
|
67
72
|
setAssignments(next.assignments);
|
|
73
|
+
setStatusMessage("Cloud and self-hosted agent catalogs synced.");
|
|
68
74
|
}
|
|
69
75
|
catch (caught) {
|
|
70
76
|
setError(caught instanceof Error ? caught.message : String(caught));
|
|
@@ -76,10 +82,12 @@ export function McodaAgentSetupPage(props) {
|
|
|
76
82
|
const saveAssignments = async () => {
|
|
77
83
|
setBusy(true);
|
|
78
84
|
setError(null);
|
|
85
|
+
setStatusMessage(null);
|
|
79
86
|
try {
|
|
80
87
|
const next = await props.client.updateAssignments({ assignments });
|
|
81
88
|
setSnapshot(next);
|
|
82
89
|
setAssignments(next.assignments);
|
|
90
|
+
setStatusMessage("Stage assignments saved.");
|
|
83
91
|
}
|
|
84
92
|
catch (caught) {
|
|
85
93
|
setError(caught instanceof Error ? caught.message : String(caught));
|
|
@@ -88,11 +96,18 @@ export function McodaAgentSetupPage(props) {
|
|
|
88
96
|
setBusy(false);
|
|
89
97
|
}
|
|
90
98
|
};
|
|
91
|
-
return React.createElement("section", { className: joinClasses("mcoda-agent-setup", props.className) }, React.createElement("header", { className: "mcoda-agent-setup__header" }, React.createElement("h1", null, props.title ?? "mcoda Agent Setup"), React.createElement("
|
|
92
|
-
|
|
93
|
-
:
|
|
99
|
+
return React.createElement("section", { className: joinClasses("mcoda-agent-setup", props.className) }, React.createElement("header", { className: "mcoda-agent-setup__header" }, React.createElement("div", { className: "mcoda-agent-setup__title-block" }, React.createElement("p", { className: "mcoda-agent-setup__eyebrow" }, "Runtime routing"), React.createElement("h1", null, props.title ?? "mcoda Agent Setup"), React.createElement("p", null, "Configure mswarm access and assign cloud or self-hosted mcoda agents to each runtime stage.")), React.createElement("button", {
|
|
100
|
+
type: "button",
|
|
101
|
+
className: "mcoda-agent-setup__button mcoda-agent-setup__button--secondary",
|
|
102
|
+
disabled: busy,
|
|
103
|
+
onClick: refresh,
|
|
104
|
+
}, busy ? "Refreshing" : "Refresh")), error
|
|
105
|
+
? React.createElement("p", { className: "mcoda-agent-setup__alert mcoda-agent-setup__alert--error" }, error)
|
|
106
|
+
: null, statusMessage
|
|
107
|
+
? React.createElement("p", { className: "mcoda-agent-setup__alert mcoda-agent-setup__alert--success" }, statusMessage)
|
|
108
|
+
: null, React.createElement("div", { className: "mcoda-agent-setup__overview" }, snapshot
|
|
94
109
|
? React.createElement(components.AgentCatalogSummary, { snapshot })
|
|
95
|
-
: React.createElement("
|
|
110
|
+
: React.createElement("div", { className: "mcoda-agent-setup__empty-state" }, busy ? "Loading settings." : "No settings loaded."), React.createElement(components.MswarmAccessCard, {
|
|
96
111
|
apiKey,
|
|
97
112
|
busy,
|
|
98
113
|
labels,
|
|
@@ -100,7 +115,7 @@ export function McodaAgentSetupPage(props) {
|
|
|
100
115
|
onApiKeyChange: setApiKey,
|
|
101
116
|
onSaveKey: saveKey,
|
|
102
117
|
onSyncAgents: syncAgents,
|
|
103
|
-
}), snapshot
|
|
118
|
+
})), snapshot
|
|
104
119
|
? React.createElement(components.StageAgentAssignments, {
|
|
105
120
|
stages,
|
|
106
121
|
snapshot,
|
|
@@ -115,27 +130,61 @@ export function McodaAgentSetupPage(props) {
|
|
|
115
130
|
export function AgentCatalogSummary(props) {
|
|
116
131
|
const { snapshot } = props;
|
|
117
132
|
const warningEntries = Object.entries(snapshot.catalog.errors);
|
|
118
|
-
return React.createElement("
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
return React.createElement("section", { className: "mcoda-agent-setup__summary" }, React.createElement("div", { className: "mcoda-agent-setup__card-heading" }, React.createElement("div", null, React.createElement("h2", null, "Catalog Snapshot"), React.createElement("p", null, `Fetched ${formatTimestamp(snapshot.fetchedAt)}`)), React.createElement("span", {
|
|
134
|
+
className: snapshot.mswarmApiKeyConfigured
|
|
135
|
+
? "mcoda-agent-setup__badge mcoda-agent-setup__badge--success"
|
|
136
|
+
: "mcoda-agent-setup__badge mcoda-agent-setup__badge--warning",
|
|
137
|
+
}, snapshot.mswarmApiKeyConfigured ? "Configured" : "Missing key")), React.createElement("div", { className: "mcoda-agent-setup__metric-grid" }, React.createElement(MetricCard, {
|
|
138
|
+
label: "Provider",
|
|
139
|
+
value: snapshot.provider,
|
|
140
|
+
detail: "active runtime",
|
|
141
|
+
}), React.createElement(MetricCard, {
|
|
142
|
+
label: "mswarm key",
|
|
143
|
+
value: snapshot.mswarmApiKeyLast4
|
|
144
|
+
? `****${snapshot.mswarmApiKeyLast4}`
|
|
145
|
+
: snapshot.mswarmApiKeyConfigured
|
|
146
|
+
? "Configured"
|
|
147
|
+
: "Missing",
|
|
148
|
+
detail: `set ${formatTimestamp(snapshot.mswarmConfiguredAt)}`,
|
|
149
|
+
}), React.createElement(MetricCard, {
|
|
150
|
+
label: "Synced agents",
|
|
151
|
+
value: String(snapshot.catalog.localAgents.length),
|
|
152
|
+
detail: "mcoda registry entries",
|
|
153
|
+
}), React.createElement(MetricCard, {
|
|
154
|
+
label: "Cloud agents",
|
|
155
|
+
value: String(snapshot.catalog.cloudAgents.length),
|
|
156
|
+
detail: "mswarm cloud catalog",
|
|
157
|
+
}), React.createElement(MetricCard, {
|
|
158
|
+
label: "Self-hosted",
|
|
159
|
+
value: String(snapshot.catalog.selfHostedAgents.length),
|
|
160
|
+
detail: `${snapshot.catalog.selfHostedServers.length} servers`,
|
|
161
|
+
})), warningEntries.length
|
|
162
|
+
? React.createElement("ul", { className: "mcoda-agent-setup__warnings", "aria-label": "Catalog warnings" }, warningEntries.map(([key, value]) => React.createElement("li", { key }, `${key}: ${value}`)))
|
|
122
163
|
: null);
|
|
123
164
|
}
|
|
124
165
|
export function MswarmAccessCard(props) {
|
|
125
166
|
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
126
|
-
return React.createElement("section", { className: "mcoda-agent-setup__access" }, React.createElement("h2", null, "mswarm Access"), React.createElement("
|
|
167
|
+
return React.createElement("section", { className: "mcoda-agent-setup__access" }, React.createElement("div", { className: "mcoda-agent-setup__card-heading" }, React.createElement("div", null, React.createElement("h2", null, "mswarm Access"), React.createElement("p", null, props.snapshot?.mswarmApiKeyConfigured
|
|
168
|
+
? "Replace the stored key or resync the catalog."
|
|
169
|
+
: "Add a key to load real cloud and self-hosted agents."))), React.createElement("label", { className: "mcoda-agent-setup__field" }, React.createElement("span", null, "API key"), React.createElement("input", {
|
|
127
170
|
type: "password",
|
|
128
171
|
value: props.apiKey,
|
|
129
172
|
autoComplete: "off",
|
|
130
173
|
onChange: (event) => props.onApiKeyChange(event.target.value),
|
|
131
174
|
placeholder: props.snapshot?.mswarmApiKeyConfigured
|
|
132
175
|
? "Replace mswarm API key"
|
|
133
|
-
: "
|
|
134
|
-
}), React.createElement("button", {
|
|
176
|
+
: "sk_prod_mswarm_...",
|
|
177
|
+
})), React.createElement("div", { className: "mcoda-agent-setup__action-row" }, React.createElement("button", {
|
|
135
178
|
type: "button",
|
|
179
|
+
className: "mcoda-agent-setup__button mcoda-agent-setup__button--primary",
|
|
136
180
|
disabled: props.busy || !props.apiKey.trim(),
|
|
137
181
|
onClick: props.onSaveKey,
|
|
138
|
-
}, labels.saveKey), React.createElement("button", {
|
|
182
|
+
}, labels.saveKey), React.createElement("button", {
|
|
183
|
+
type: "button",
|
|
184
|
+
className: "mcoda-agent-setup__button mcoda-agent-setup__button--secondary",
|
|
185
|
+
disabled: props.busy,
|
|
186
|
+
onClick: props.onSyncAgents,
|
|
187
|
+
}, labels.syncAgents)));
|
|
139
188
|
}
|
|
140
189
|
export function StageAgentAssignments(props) {
|
|
141
190
|
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
@@ -161,46 +210,76 @@ export function StageAgentAssignments(props) {
|
|
|
161
210
|
nextSources[stage.stageKey] = "cloud";
|
|
162
211
|
}
|
|
163
212
|
}
|
|
164
|
-
setSources((current) => ({ ...
|
|
165
|
-
setServers((current) => ({ ...
|
|
213
|
+
setSources((current) => ({ ...current, ...nextSources }));
|
|
214
|
+
setServers((current) => ({ ...current, ...nextServers }));
|
|
166
215
|
}, [props.assignments, props.snapshot.catalog.cloudAgents, props.snapshot.catalog.selfHostedServers, props.stages]);
|
|
167
|
-
return React.createElement("section", { className: "mcoda-agent-setup__assignments" }, React.createElement("h2", null, "Stage Assignments"), React.createElement("
|
|
216
|
+
return React.createElement("section", { className: "mcoda-agent-setup__assignments" }, React.createElement("div", { className: "mcoda-agent-setup__card-heading" }, React.createElement("div", null, React.createElement("h2", null, "Stage Assignments"), React.createElement("p", null, "Select the agent that should run each app workflow stage.")), React.createElement("button", {
|
|
217
|
+
type: "button",
|
|
218
|
+
className: "mcoda-agent-setup__button mcoda-agent-setup__button--success",
|
|
219
|
+
disabled: props.busy,
|
|
220
|
+
onClick: props.onSaveAssignments,
|
|
221
|
+
}, labels.saveAssignments)), React.createElement("div", { className: "mcoda-agent-setup__stage-table-wrap" }, React.createElement("table", { className: "mcoda-agent-setup__stage-table" }, React.createElement("thead", null, React.createElement("tr", null, React.createElement("th", null, "Stage"), React.createElement("th", null, "Source"), React.createElement("th", null, "Self-hosted server"), React.createElement("th", null, "Agent"), React.createElement("th", null, "Status"))), React.createElement("tbody", null, props.stages.map((stage) => {
|
|
222
|
+
const selectedSlug = props.assignments[stage.stageKey] ?? "";
|
|
168
223
|
const source = sources[stage.stageKey] ??
|
|
169
224
|
(stage.preferredSource === "self_hosted" ? "self_hosted" : "cloud");
|
|
170
225
|
const serverId = servers[stage.stageKey];
|
|
171
|
-
const server = props.snapshot.catalog.selfHostedServers.find((candidate) => candidate.id === serverId);
|
|
226
|
+
const server = props.snapshot.catalog.selfHostedServers.find((candidate) => candidate.id === serverId) ?? props.snapshot.catalog.selfHostedServers[0];
|
|
172
227
|
const agents = source === "cloud"
|
|
173
228
|
? props.snapshot.catalog.cloudAgents
|
|
174
229
|
: server?.agents ?? [];
|
|
175
|
-
|
|
230
|
+
const allSelectableAgents = [
|
|
231
|
+
...props.snapshot.catalog.cloudAgents,
|
|
232
|
+
...props.snapshot.catalog.selfHostedServers.flatMap((candidate) => candidate.agents),
|
|
233
|
+
];
|
|
234
|
+
const selectedAgent = allSelectableAgents.find((agent) => agent.slug === selectedSlug);
|
|
235
|
+
const agentSelectValue = agents.some((agent) => agent.slug === selectedSlug)
|
|
236
|
+
? selectedSlug
|
|
237
|
+
: "";
|
|
238
|
+
const onSourceChange = (value) => {
|
|
239
|
+
setSources((current) => ({ ...current, [stage.stageKey]: value }));
|
|
240
|
+
const nextSlug = value === "cloud"
|
|
241
|
+
? props.snapshot.catalog.cloudAgents[0]?.slug
|
|
242
|
+
: firstSelfHostedAgentSlug(props.snapshot.catalog.selfHostedServers);
|
|
243
|
+
props.onAssignmentChange(stage.stageKey, nextSlug ?? null);
|
|
244
|
+
};
|
|
245
|
+
const onServerChange = (value) => {
|
|
246
|
+
setServers((current) => ({ ...current, [stage.stageKey]: value }));
|
|
247
|
+
const nextServer = props.snapshot.catalog.selfHostedServers.find((candidate) => candidate.id === value);
|
|
248
|
+
props.onAssignmentChange(stage.stageKey, nextServer?.agents[0]?.slug ?? null);
|
|
249
|
+
};
|
|
250
|
+
return React.createElement("tr", { key: stage.stageKey }, React.createElement("td", { className: "mcoda-agent-setup__stage-cell" }, React.createElement("strong", null, stage.displayName), stage.description
|
|
176
251
|
? React.createElement("p", null, stage.description)
|
|
177
|
-
: null), React.createElement(sourceSelect, {
|
|
252
|
+
: null, React.createElement("code", null, stage.stageKey)), React.createElement("td", null, React.createElement(sourceSelect, {
|
|
178
253
|
value: source,
|
|
179
254
|
labels,
|
|
180
|
-
onChange:
|
|
181
|
-
}), source === "self_hosted"
|
|
255
|
+
onChange: onSourceChange,
|
|
256
|
+
})), React.createElement("td", null, source === "self_hosted"
|
|
182
257
|
? React.createElement(serverSelect, {
|
|
183
258
|
servers: props.snapshot.catalog.selfHostedServers,
|
|
184
|
-
value:
|
|
185
|
-
onChange:
|
|
259
|
+
value: server?.id ?? "",
|
|
260
|
+
onChange: onServerChange,
|
|
186
261
|
})
|
|
187
|
-
: null, React.createElement(agentSelect, {
|
|
262
|
+
: React.createElement("span", { className: "mcoda-agent-setup__muted-pill" }, "Cloud catalog")), React.createElement("td", null, React.createElement(agentSelect, {
|
|
188
263
|
agents,
|
|
189
|
-
value:
|
|
264
|
+
value: agentSelectValue,
|
|
190
265
|
onChange: (slug) => props.onAssignmentChange(stage.stageKey, slug || null),
|
|
191
|
-
}))
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}, labels.saveAssignments));
|
|
266
|
+
})), React.createElement("td", null, React.createElement(AgentStatusBadge, {
|
|
267
|
+
agent: selectedAgent,
|
|
268
|
+
slug: selectedSlug,
|
|
269
|
+
})));
|
|
270
|
+
})))));
|
|
197
271
|
}
|
|
198
272
|
export function AgentSourceSelect(props) {
|
|
199
273
|
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
200
|
-
return React.createElement("
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
274
|
+
return React.createElement("div", { className: "mcoda-agent-setup__source", role: "group", "aria-label": "Agent source" }, React.createElement("button", {
|
|
275
|
+
type: "button",
|
|
276
|
+
"aria-pressed": props.value === "cloud",
|
|
277
|
+
onClick: () => props.onChange("cloud"),
|
|
278
|
+
}, labels.cloud), React.createElement("button", {
|
|
279
|
+
type: "button",
|
|
280
|
+
"aria-pressed": props.value === "self_hosted",
|
|
281
|
+
onClick: () => props.onChange("self_hosted"),
|
|
282
|
+
}, labels.selfHosted));
|
|
204
283
|
}
|
|
205
284
|
export function SelfHostedServerSelect(props) {
|
|
206
285
|
const [query, setQuery] = React.useState("");
|
|
@@ -219,16 +298,27 @@ export function SelfHostedServerSelect(props) {
|
|
|
219
298
|
})
|
|
220
299
|
: null, React.createElement("select", {
|
|
221
300
|
value: props.value,
|
|
301
|
+
disabled: filteredServers.length === 0,
|
|
222
302
|
onChange: (event) => props.onChange(event.target.value),
|
|
223
|
-
}, React.createElement("option", { value: "" }, "Select server"), filteredServers.map((server) => React.createElement("option", { key: server.id, value: server.id }, `${server.label} (${server.agentCount})`))));
|
|
303
|
+
}, React.createElement("option", { value: "" }, filteredServers.length ? "Select server" : "No servers synced"), filteredServers.map((server) => React.createElement("option", { key: server.id, value: server.id }, `${server.label} (${server.agentCount})`))));
|
|
224
304
|
}
|
|
225
305
|
export function AgentSearchSelect(props) {
|
|
226
306
|
const [query, setQuery] = React.useState("");
|
|
227
307
|
const [scrollTop, setScrollTop] = React.useState(0);
|
|
228
308
|
const [activeIndex, setActiveIndex] = React.useState(0);
|
|
309
|
+
const [open, setOpen] = React.useState(false);
|
|
310
|
+
const triggerRef = React.useRef(null);
|
|
311
|
+
const panelRef = React.useRef(null);
|
|
312
|
+
const searchRef = React.useRef(null);
|
|
313
|
+
const [panelFrame, setPanelFrame] = React.useState({
|
|
314
|
+
left: 0,
|
|
315
|
+
maxHeight: 420,
|
|
316
|
+
top: 0,
|
|
317
|
+
width: 360,
|
|
318
|
+
});
|
|
229
319
|
const filtered = React.useMemo(() => filterAgentOptions(props.agents, query), [props.agents, query]);
|
|
230
|
-
const rowHeight = props.rowHeight ??
|
|
231
|
-
const viewportHeight = props.viewportHeight ??
|
|
320
|
+
const rowHeight = props.rowHeight ?? 64;
|
|
321
|
+
const viewportHeight = Math.min(props.viewportHeight ?? 320, panelFrame.maxHeight - 74);
|
|
232
322
|
const windowed = getVirtualAgentWindow(filtered, {
|
|
233
323
|
scrollTop,
|
|
234
324
|
rowHeight,
|
|
@@ -237,10 +327,62 @@ export function AgentSearchSelect(props) {
|
|
|
237
327
|
const selected = props.agents.find((agent) => agent.slug === props.value);
|
|
238
328
|
React.useEffect(() => {
|
|
239
329
|
setActiveIndex(0);
|
|
330
|
+
setScrollTop(0);
|
|
240
331
|
}, [query, props.agents]);
|
|
332
|
+
React.useEffect(() => {
|
|
333
|
+
if (!open)
|
|
334
|
+
return;
|
|
335
|
+
const updatePanelFrame = () => {
|
|
336
|
+
const trigger = triggerRef.current;
|
|
337
|
+
if (!trigger)
|
|
338
|
+
return;
|
|
339
|
+
const rect = trigger.getBoundingClientRect();
|
|
340
|
+
const viewportWidth = window.innerWidth;
|
|
341
|
+
const viewportHeight = window.innerHeight;
|
|
342
|
+
const width = Math.min(Math.max(rect.width, 380), Math.max(280, viewportWidth - 16));
|
|
343
|
+
const left = Math.min(Math.max(8, rect.left), Math.max(8, viewportWidth - width - 8));
|
|
344
|
+
const spaceBelow = viewportHeight - rect.bottom - 12;
|
|
345
|
+
const spaceAbove = rect.top - 12;
|
|
346
|
+
const openBelow = spaceBelow >= 280 || spaceBelow >= spaceAbove;
|
|
347
|
+
const maxHeight = Math.min(420, Math.max(openBelow ? spaceBelow : spaceAbove, 180));
|
|
348
|
+
const top = openBelow
|
|
349
|
+
? Math.min(rect.bottom + 6, viewportHeight - maxHeight - 8)
|
|
350
|
+
: Math.max(8, rect.top - maxHeight - 6);
|
|
351
|
+
setPanelFrame({ left, maxHeight, top, width });
|
|
352
|
+
};
|
|
353
|
+
updatePanelFrame();
|
|
354
|
+
searchRef.current?.focus();
|
|
355
|
+
window.addEventListener("resize", updatePanelFrame);
|
|
356
|
+
window.addEventListener("scroll", updatePanelFrame, true);
|
|
357
|
+
return () => {
|
|
358
|
+
window.removeEventListener("resize", updatePanelFrame);
|
|
359
|
+
window.removeEventListener("scroll", updatePanelFrame, true);
|
|
360
|
+
};
|
|
361
|
+
}, [open]);
|
|
362
|
+
React.useEffect(() => {
|
|
363
|
+
if (!open)
|
|
364
|
+
return;
|
|
365
|
+
const onPointerDown = (event) => {
|
|
366
|
+
const target = event.target;
|
|
367
|
+
if (triggerRef.current?.contains(target) ||
|
|
368
|
+
panelRef.current?.contains(target)) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
setOpen(false);
|
|
372
|
+
};
|
|
373
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
374
|
+
return () => document.removeEventListener("mousedown", onPointerDown);
|
|
375
|
+
}, [open]);
|
|
376
|
+
const selectAgent = (agent) => {
|
|
377
|
+
props.onChange(agent.slug);
|
|
378
|
+
setOpen(false);
|
|
379
|
+
setQuery("");
|
|
380
|
+
};
|
|
241
381
|
const onKeyDown = (event) => {
|
|
242
382
|
if (event.key === "Escape") {
|
|
383
|
+
setOpen(false);
|
|
243
384
|
setQuery("");
|
|
385
|
+
triggerRef.current?.focus();
|
|
244
386
|
return;
|
|
245
387
|
}
|
|
246
388
|
if (event.key === "ArrowDown") {
|
|
@@ -255,38 +397,124 @@ export function AgentSearchSelect(props) {
|
|
|
255
397
|
}
|
|
256
398
|
if (event.key === "Enter" && filtered[activeIndex]) {
|
|
257
399
|
event.preventDefault();
|
|
258
|
-
|
|
400
|
+
selectAgent(filtered[activeIndex]);
|
|
259
401
|
}
|
|
260
402
|
};
|
|
261
|
-
return React.createElement("div", { className: "mcoda-agent-setup__agent-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
403
|
+
return React.createElement("div", { className: "mcoda-agent-setup__agent-combobox" }, React.createElement("button", {
|
|
404
|
+
ref: triggerRef,
|
|
405
|
+
type: "button",
|
|
406
|
+
className: "mcoda-agent-setup__agent-trigger",
|
|
407
|
+
"aria-haspopup": "listbox",
|
|
408
|
+
"aria-expanded": open,
|
|
409
|
+
disabled: props.agents.length === 0,
|
|
410
|
+
onClick: () => setOpen((current) => !current),
|
|
411
|
+
}, React.createElement("span", { className: "mcoda-agent-setup__agent-trigger-main" }, selected
|
|
412
|
+
? React.createElement(React.Fragment, null, React.createElement("strong", null, agentTitle(selected)), React.createElement("small", null, agentMetadata(selected)))
|
|
413
|
+
: React.createElement("strong", null, props.agents.length ? "Select agent" : "No agents synced")), React.createElement("span", { className: "mcoda-agent-setup__chevron" }, "⌄")), open
|
|
414
|
+
? React.createElement("div", {
|
|
415
|
+
className: "mcoda-agent-setup__agent-panel",
|
|
416
|
+
ref: panelRef,
|
|
417
|
+
style: {
|
|
418
|
+
left: panelFrame.left,
|
|
419
|
+
maxHeight: panelFrame.maxHeight,
|
|
420
|
+
top: panelFrame.top,
|
|
421
|
+
width: panelFrame.width,
|
|
422
|
+
},
|
|
423
|
+
}, React.createElement("div", { className: "mcoda-agent-setup__agent-panel-search" }, React.createElement("input", {
|
|
424
|
+
ref: searchRef,
|
|
425
|
+
value: query,
|
|
426
|
+
onChange: (event) => setQuery(event.target.value),
|
|
427
|
+
onKeyDown,
|
|
428
|
+
"aria-label": "Search agents",
|
|
429
|
+
placeholder: "Search agent, model, provider, or slug",
|
|
430
|
+
})), React.createElement("div", { className: "mcoda-agent-setup__agent-count" }, filtered.length
|
|
431
|
+
? `Showing all ${filtered.length} agents`
|
|
432
|
+
: "No agents match this search"), React.createElement("div", {
|
|
433
|
+
className: "mcoda-agent-setup__agent-list",
|
|
434
|
+
role: "listbox",
|
|
435
|
+
style: { maxHeight: viewportHeight, overflowY: "auto" },
|
|
436
|
+
onKeyDown,
|
|
437
|
+
onScroll: (event) => setScrollTop(event.currentTarget.scrollTop),
|
|
438
|
+
}, React.createElement("div", { style: { height: windowed.beforeHeight } }), windowed.items.map((agent, index) => {
|
|
439
|
+
const absoluteIndex = windowed.startIndex + index;
|
|
440
|
+
const active = absoluteIndex === activeIndex;
|
|
441
|
+
return React.createElement("button", {
|
|
442
|
+
key: agent.slug,
|
|
443
|
+
type: "button",
|
|
444
|
+
className: agent.slug === props.value || active
|
|
445
|
+
? "mcoda-agent-setup__agent-row mcoda-agent-setup__agent-row--selected"
|
|
446
|
+
: "mcoda-agent-setup__agent-row",
|
|
447
|
+
role: "option",
|
|
448
|
+
"aria-selected": agent.slug === props.value,
|
|
449
|
+
style: { minHeight: rowHeight },
|
|
450
|
+
onMouseEnter: () => setActiveIndex(absoluteIndex),
|
|
451
|
+
onClick: () => selectAgent(agent),
|
|
452
|
+
}, React.createElement("span", { className: "mcoda-agent-setup__agent-row-main" }, React.createElement("strong", null, agentTitle(agent)), React.createElement("small", null, agentMetadata(agent)), React.createElement("code", null, agent.slug)), agent.slug === props.value
|
|
453
|
+
? React.createElement("span", { className: "mcoda-agent-setup__selected-mark" }, "Selected")
|
|
454
|
+
: null);
|
|
455
|
+
}), React.createElement("div", { style: { height: windowed.afterHeight } })))
|
|
456
|
+
: null);
|
|
457
|
+
}
|
|
458
|
+
function MetricCard(props) {
|
|
459
|
+
return React.createElement("div", { className: "mcoda-agent-setup__metric" }, React.createElement("span", null, props.label), React.createElement("strong", null, props.value), React.createElement("small", null, props.detail));
|
|
460
|
+
}
|
|
461
|
+
function AgentStatusBadge(props) {
|
|
462
|
+
const kind = props.agent?.managedKind;
|
|
463
|
+
const sourceLabel = kind === "cloud"
|
|
464
|
+
? "Cloud"
|
|
465
|
+
: kind === "self_hosted"
|
|
466
|
+
? "Self-hosted"
|
|
467
|
+
: props.agent
|
|
468
|
+
? "Local"
|
|
469
|
+
: props.slug
|
|
470
|
+
? "Missing"
|
|
471
|
+
: "Unset";
|
|
472
|
+
const className = kind === "cloud"
|
|
473
|
+
? "mcoda-agent-setup__badge mcoda-agent-setup__badge--info"
|
|
474
|
+
: kind === "self_hosted"
|
|
475
|
+
? "mcoda-agent-setup__badge mcoda-agent-setup__badge--success"
|
|
476
|
+
: props.agent
|
|
477
|
+
? "mcoda-agent-setup__badge"
|
|
478
|
+
: "mcoda-agent-setup__badge mcoda-agent-setup__badge--warning";
|
|
479
|
+
return React.createElement("span", { className }, sourceLabel);
|
|
480
|
+
}
|
|
481
|
+
function firstSelfHostedAgentSlug(servers) {
|
|
482
|
+
return servers.find((server) => server.agents.length > 0)?.agents[0]?.slug ?? null;
|
|
483
|
+
}
|
|
484
|
+
function agentTitle(agent) {
|
|
485
|
+
return agent.displayName ?? prettySlug(agent.slug);
|
|
486
|
+
}
|
|
487
|
+
function agentMetadata(agent) {
|
|
488
|
+
return ([
|
|
489
|
+
agent.defaultModel ?? agent.model,
|
|
490
|
+
agent.provider,
|
|
491
|
+
agent.healthStatus && agent.healthStatus !== "-" ? agent.healthStatus : null,
|
|
492
|
+
]
|
|
493
|
+
.filter(Boolean)
|
|
494
|
+
.join(" / ") || agent.slug);
|
|
495
|
+
}
|
|
496
|
+
function prettySlug(slug) {
|
|
497
|
+
return slug
|
|
498
|
+
.replace(/^mswarm-cloud-/, "")
|
|
499
|
+
.replace(/^mswarm-self-hosted-/, "")
|
|
500
|
+
.replace(/^mcoda-/, "")
|
|
501
|
+
.replace(/[-_]+/g, " ");
|
|
502
|
+
}
|
|
503
|
+
function formatTimestamp(value) {
|
|
504
|
+
if (!value)
|
|
505
|
+
return "never";
|
|
506
|
+
const parsed = Date.parse(value);
|
|
507
|
+
if (Number.isNaN(parsed))
|
|
508
|
+
return value;
|
|
509
|
+
const deltaMinutes = Math.max(0, Math.round((Date.now() - parsed) / 60000));
|
|
510
|
+
if (deltaMinutes < 1)
|
|
511
|
+
return "just now";
|
|
512
|
+
if (deltaMinutes < 60)
|
|
513
|
+
return `${deltaMinutes}m ago`;
|
|
514
|
+
const deltaHours = Math.round(deltaMinutes / 60);
|
|
515
|
+
if (deltaHours < 24)
|
|
516
|
+
return `${deltaHours}h ago`;
|
|
517
|
+
return `${Math.round(deltaHours / 24)}d ago`;
|
|
290
518
|
}
|
|
291
519
|
function joinClasses(...values) {
|
|
292
520
|
return values.filter(Boolean).join(" ");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,4BAA4B,EAC5B,sBAAsB,EAGvB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,4BAA4B,EAC5B,sBAAsB,EAGvB,MAAM,aAAa,CAAC;AAIrB,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,4BAA4B,GACpC,sBAAsB,CAoLxB"}
|
package/dist/server/service.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defaultMcodaStageDefinitions } from "../defaultStages.js";
|
|
2
2
|
import { buildCloudAgentOptions, buildSelfHostedServerOptions, } from "../headless/catalog.js";
|
|
3
3
|
import { createProgrammaticMcodaRuntimeAdapter } from "./programmaticRuntime.js";
|
|
4
|
+
const REMOTE_ATTEMPTS = 3;
|
|
4
5
|
export function createMcodaAgentSetupService(options) {
|
|
5
6
|
const runtime = options.mcoda ?? createProgrammaticMcodaRuntimeAdapter();
|
|
6
7
|
const stages = options.defaultStages ?? defaultMcodaStageDefinitions;
|
|
@@ -8,29 +9,43 @@ export function createMcodaAgentSetupService(options) {
|
|
|
8
9
|
const authorize = async (request) => {
|
|
9
10
|
await options.authorize?.(request);
|
|
10
11
|
};
|
|
11
|
-
const capture = async (errors, key, fn, fallback) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
const capture = async (errors, key, fn, fallback, attempts = 1) => {
|
|
13
|
+
let lastError;
|
|
14
|
+
for (let attempt = 1; attempt <= Math.max(1, attempts); attempt += 1) {
|
|
15
|
+
try {
|
|
16
|
+
return await fn();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
lastError = error;
|
|
20
|
+
if (attempt < attempts) {
|
|
21
|
+
await sleep(150 * attempt);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
22
24
|
}
|
|
25
|
+
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
26
|
+
errors[key] = message;
|
|
27
|
+
options.logger?.warn?.(`mcoda agent setup ${key} failed`, {
|
|
28
|
+
error: message,
|
|
29
|
+
});
|
|
30
|
+
return fallback;
|
|
31
|
+
};
|
|
32
|
+
const captureRemote = async (errors, key, fn, fallback) => {
|
|
33
|
+
return capture(errors, key, fn, fallback, REMOTE_ATTEMPTS);
|
|
23
34
|
};
|
|
24
35
|
const buildSnapshot = async (extraErrors = {}) => {
|
|
25
36
|
const settings = await options.settingsStore.load();
|
|
26
37
|
const errors = { ...extraErrors };
|
|
27
38
|
const [localAgents, cloudCatalogAgents, selfHostedCatalogAgents] = await Promise.all([
|
|
28
39
|
capture(errors, "local_agents", () => runtime.listLocalAgents({ refreshHealth: true }), []),
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
captureRemote(errors, "cloud_agents", () => runtime.listCloudAgents(), []),
|
|
41
|
+
captureRemote(errors, "self_hosted_agents", () => runtime.listSelfHostedAgents({ includeUnreachable: true }), []),
|
|
31
42
|
]);
|
|
32
|
-
const cloudAgents =
|
|
33
|
-
|
|
43
|
+
const cloudAgents = errors.cloud_agents === undefined
|
|
44
|
+
? buildCloudAgentOptions(localAgents, cloudCatalogAgents)
|
|
45
|
+
: [];
|
|
46
|
+
const selfHostedServers = errors.self_hosted_agents === undefined
|
|
47
|
+
? buildSelfHostedServerOptions(localAgents, selfHostedCatalogAgents)
|
|
48
|
+
: [];
|
|
34
49
|
const catalog = {
|
|
35
50
|
localAgents,
|
|
36
51
|
cloudAgents,
|
|
@@ -112,14 +127,17 @@ export function createMcodaAgentSetupService(options) {
|
|
|
112
127
|
};
|
|
113
128
|
async function syncCatalogs() {
|
|
114
129
|
const errors = {};
|
|
115
|
-
await
|
|
116
|
-
await
|
|
130
|
+
await captureRemote(errors, "cloud_agent_sync", () => runtime.syncCloudAgents({ pruneMissing: true }), []);
|
|
131
|
+
await captureRemote(errors, "self_hosted_agent_sync", () => runtime.syncSelfHostedAgents({
|
|
117
132
|
pruneMissing: true,
|
|
118
133
|
includeUnreachable: true,
|
|
119
134
|
}), []);
|
|
120
135
|
return errors;
|
|
121
136
|
}
|
|
122
137
|
}
|
|
138
|
+
function sleep(ms) {
|
|
139
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
123
141
|
function initialAssignments(stages) {
|
|
124
142
|
return Object.fromEntries(stages.map((stage) => [stage.stageKey, stage.defaultAgentSlug ?? null]));
|
|
125
143
|
}
|
|
@@ -32,3 +32,7 @@ app.all("/api/mcoda/*", async (req, res) => {
|
|
|
32
32
|
|
|
33
33
|
app.listen(3000);
|
|
34
34
|
```
|
|
35
|
+
|
|
36
|
+
This uses the real programmatic mcoda/mswarm runtime by default. After the
|
|
37
|
+
frontend posts a real mswarm API key to `/api/mcoda/mswarm-api-key`, cloud and
|
|
38
|
+
self-hosted agents are fetched and synced from the real mswarm server.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/agent-setup",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.70",
|
|
4
4
|
"description": "Turnkey mcoda/mswarm agent setup SDK for applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,11 +21,15 @@
|
|
|
21
21
|
"./react": {
|
|
22
22
|
"types": "./dist/react/index.d.ts",
|
|
23
23
|
"import": "./dist/react/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./react/styles.css": {
|
|
26
|
+
"default": "./styles/react.css"
|
|
24
27
|
}
|
|
25
28
|
},
|
|
26
29
|
"files": [
|
|
27
30
|
"dist",
|
|
28
31
|
"examples",
|
|
32
|
+
"styles",
|
|
29
33
|
"!dist/**/__tests__/**",
|
|
30
34
|
"!dist/**/*.test.*",
|
|
31
35
|
"README.md",
|
|
@@ -58,7 +62,7 @@
|
|
|
58
62
|
"access": "public"
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
61
|
-
"@mcoda/core": "0.1.
|
|
65
|
+
"@mcoda/core": "0.1.70"
|
|
62
66
|
},
|
|
63
67
|
"peerDependencies": {
|
|
64
68
|
"react": ">=18.2.0 || >=19.0.0",
|
package/styles/react.css
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
.mcoda-agent-setup {
|
|
2
|
+
--mcoda-surface: #ffffff;
|
|
3
|
+
--mcoda-page: #f8fafc;
|
|
4
|
+
--mcoda-border: #e2e8f0;
|
|
5
|
+
--mcoda-border-strong: #cbd5e1;
|
|
6
|
+
--mcoda-text: #0f172a;
|
|
7
|
+
--mcoda-muted: #64748b;
|
|
8
|
+
--mcoda-faint: #94a3b8;
|
|
9
|
+
--mcoda-blue: #2563eb;
|
|
10
|
+
--mcoda-blue-soft: #eff6ff;
|
|
11
|
+
--mcoda-emerald: #059669;
|
|
12
|
+
--mcoda-emerald-soft: #ecfdf5;
|
|
13
|
+
--mcoda-amber: #d97706;
|
|
14
|
+
--mcoda-amber-soft: #fffbeb;
|
|
15
|
+
--mcoda-rose: #e11d48;
|
|
16
|
+
--mcoda-rose-soft: #fff1f2;
|
|
17
|
+
color: var(--mcoda-text);
|
|
18
|
+
display: grid;
|
|
19
|
+
gap: 16px;
|
|
20
|
+
width: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.mcoda-agent-setup *,
|
|
24
|
+
.mcoda-agent-setup *::before,
|
|
25
|
+
.mcoda-agent-setup *::after {
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.mcoda-agent-setup button,
|
|
30
|
+
.mcoda-agent-setup input,
|
|
31
|
+
.mcoda-agent-setup select {
|
|
32
|
+
font: inherit;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.mcoda-agent-setup__header,
|
|
36
|
+
.mcoda-agent-setup__summary,
|
|
37
|
+
.mcoda-agent-setup__access,
|
|
38
|
+
.mcoda-agent-setup__assignments,
|
|
39
|
+
.mcoda-agent-setup__empty-state,
|
|
40
|
+
.mcoda-agent-setup__alert {
|
|
41
|
+
background: var(--mcoda-surface);
|
|
42
|
+
border: 1px solid var(--mcoda-border);
|
|
43
|
+
border-radius: 8px;
|
|
44
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.mcoda-agent-setup__header {
|
|
48
|
+
align-items: center;
|
|
49
|
+
display: flex;
|
|
50
|
+
gap: 16px;
|
|
51
|
+
justify-content: space-between;
|
|
52
|
+
padding: 18px 20px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.mcoda-agent-setup__title-block {
|
|
56
|
+
min-width: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.mcoda-agent-setup__eyebrow {
|
|
60
|
+
color: var(--mcoda-blue);
|
|
61
|
+
font-size: 10px;
|
|
62
|
+
font-weight: 800;
|
|
63
|
+
letter-spacing: 0;
|
|
64
|
+
margin: 0 0 4px;
|
|
65
|
+
text-transform: uppercase;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.mcoda-agent-setup__header h1,
|
|
69
|
+
.mcoda-agent-setup__card-heading h2,
|
|
70
|
+
.mcoda-agent-setup__assignments h2 {
|
|
71
|
+
color: var(--mcoda-text);
|
|
72
|
+
font-size: 18px;
|
|
73
|
+
font-weight: 750;
|
|
74
|
+
line-height: 1.2;
|
|
75
|
+
margin: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.mcoda-agent-setup__header p,
|
|
79
|
+
.mcoda-agent-setup__card-heading p {
|
|
80
|
+
color: var(--mcoda-muted);
|
|
81
|
+
font-size: 13px;
|
|
82
|
+
line-height: 1.45;
|
|
83
|
+
margin: 4px 0 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.mcoda-agent-setup__button {
|
|
87
|
+
align-items: center;
|
|
88
|
+
border: 1px solid transparent;
|
|
89
|
+
border-radius: 8px;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
font-size: 13px;
|
|
93
|
+
font-weight: 700;
|
|
94
|
+
gap: 8px;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
min-height: 38px;
|
|
97
|
+
padding: 0 14px;
|
|
98
|
+
transition:
|
|
99
|
+
background-color 140ms ease,
|
|
100
|
+
border-color 140ms ease,
|
|
101
|
+
color 140ms ease;
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.mcoda-agent-setup__button:disabled {
|
|
106
|
+
background: #f1f5f9;
|
|
107
|
+
color: var(--mcoda-faint);
|
|
108
|
+
cursor: not-allowed;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.mcoda-agent-setup__button--primary {
|
|
112
|
+
background: #0f172a;
|
|
113
|
+
color: #ffffff;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.mcoda-agent-setup__button--primary:hover:not(:disabled) {
|
|
117
|
+
background: #1e293b;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.mcoda-agent-setup__button--secondary {
|
|
121
|
+
background: var(--mcoda-blue-soft);
|
|
122
|
+
border-color: #bfdbfe;
|
|
123
|
+
color: #1d4ed8;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.mcoda-agent-setup__button--secondary:hover:not(:disabled) {
|
|
127
|
+
background: #dbeafe;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.mcoda-agent-setup__button--success {
|
|
131
|
+
background: var(--mcoda-emerald);
|
|
132
|
+
color: #ffffff;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.mcoda-agent-setup__button--success:hover:not(:disabled) {
|
|
136
|
+
background: #047857;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.mcoda-agent-setup__alert {
|
|
140
|
+
font-size: 13px;
|
|
141
|
+
margin: 0;
|
|
142
|
+
padding: 12px 14px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.mcoda-agent-setup__alert--error {
|
|
146
|
+
background: var(--mcoda-rose-soft);
|
|
147
|
+
border-color: #fecdd3;
|
|
148
|
+
color: #be123c;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.mcoda-agent-setup__alert--success {
|
|
152
|
+
background: var(--mcoda-emerald-soft);
|
|
153
|
+
border-color: #a7f3d0;
|
|
154
|
+
color: #047857;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.mcoda-agent-setup__overview {
|
|
158
|
+
display: grid;
|
|
159
|
+
gap: 16px;
|
|
160
|
+
grid-template-columns: minmax(0, 1.4fr) minmax(300px, 0.75fr);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.mcoda-agent-setup__summary,
|
|
164
|
+
.mcoda-agent-setup__access,
|
|
165
|
+
.mcoda-agent-setup__assignments,
|
|
166
|
+
.mcoda-agent-setup__empty-state {
|
|
167
|
+
padding: 18px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.mcoda-agent-setup__card-heading {
|
|
171
|
+
align-items: flex-start;
|
|
172
|
+
display: flex;
|
|
173
|
+
gap: 14px;
|
|
174
|
+
justify-content: space-between;
|
|
175
|
+
margin-bottom: 16px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.mcoda-agent-setup__metric-grid {
|
|
179
|
+
display: grid;
|
|
180
|
+
gap: 12px;
|
|
181
|
+
grid-template-columns: repeat(5, minmax(120px, 1fr));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.mcoda-agent-setup__metric {
|
|
185
|
+
background: #f8fafc;
|
|
186
|
+
border: 1px solid #edf2f7;
|
|
187
|
+
border-radius: 8px;
|
|
188
|
+
min-width: 0;
|
|
189
|
+
padding: 12px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.mcoda-agent-setup__metric span,
|
|
193
|
+
.mcoda-agent-setup__field span,
|
|
194
|
+
.mcoda-agent-setup__stage-table th {
|
|
195
|
+
color: var(--mcoda-faint);
|
|
196
|
+
display: block;
|
|
197
|
+
font-size: 10px;
|
|
198
|
+
font-weight: 800;
|
|
199
|
+
letter-spacing: 0;
|
|
200
|
+
text-transform: uppercase;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.mcoda-agent-setup__metric strong {
|
|
204
|
+
color: var(--mcoda-text);
|
|
205
|
+
display: block;
|
|
206
|
+
font-size: 22px;
|
|
207
|
+
font-weight: 800;
|
|
208
|
+
line-height: 1.1;
|
|
209
|
+
margin-top: 8px;
|
|
210
|
+
overflow: hidden;
|
|
211
|
+
text-overflow: ellipsis;
|
|
212
|
+
white-space: nowrap;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.mcoda-agent-setup__metric small {
|
|
216
|
+
color: var(--mcoda-muted);
|
|
217
|
+
display: block;
|
|
218
|
+
font-size: 12px;
|
|
219
|
+
margin-top: 6px;
|
|
220
|
+
overflow: hidden;
|
|
221
|
+
text-overflow: ellipsis;
|
|
222
|
+
white-space: nowrap;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.mcoda-agent-setup__badge {
|
|
226
|
+
background: #f1f5f9;
|
|
227
|
+
border: 1px solid #e2e8f0;
|
|
228
|
+
border-radius: 999px;
|
|
229
|
+
color: #475569;
|
|
230
|
+
display: inline-flex;
|
|
231
|
+
font-size: 10px;
|
|
232
|
+
font-weight: 800;
|
|
233
|
+
letter-spacing: 0;
|
|
234
|
+
line-height: 1;
|
|
235
|
+
padding: 6px 8px;
|
|
236
|
+
text-transform: uppercase;
|
|
237
|
+
white-space: nowrap;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.mcoda-agent-setup__badge--success {
|
|
241
|
+
background: var(--mcoda-emerald-soft);
|
|
242
|
+
border-color: #a7f3d0;
|
|
243
|
+
color: #047857;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.mcoda-agent-setup__badge--warning {
|
|
247
|
+
background: var(--mcoda-amber-soft);
|
|
248
|
+
border-color: #fde68a;
|
|
249
|
+
color: #b45309;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.mcoda-agent-setup__badge--info {
|
|
253
|
+
background: var(--mcoda-blue-soft);
|
|
254
|
+
border-color: #bfdbfe;
|
|
255
|
+
color: #1d4ed8;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.mcoda-agent-setup__warnings {
|
|
259
|
+
background: var(--mcoda-amber-soft);
|
|
260
|
+
border: 1px solid #fde68a;
|
|
261
|
+
border-radius: 8px;
|
|
262
|
+
color: #92400e;
|
|
263
|
+
font-size: 12px;
|
|
264
|
+
margin: 14px 0 0;
|
|
265
|
+
padding: 10px 12px 10px 28px;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.mcoda-agent-setup__access {
|
|
269
|
+
align-content: start;
|
|
270
|
+
display: grid;
|
|
271
|
+
gap: 14px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.mcoda-agent-setup__field {
|
|
275
|
+
display: grid;
|
|
276
|
+
gap: 8px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.mcoda-agent-setup__field input,
|
|
280
|
+
.mcoda-agent-setup__server-select input,
|
|
281
|
+
.mcoda-agent-setup__server-select select,
|
|
282
|
+
.mcoda-agent-setup__agent-panel-search input {
|
|
283
|
+
background: #ffffff;
|
|
284
|
+
border: 1px solid var(--mcoda-border);
|
|
285
|
+
border-radius: 8px;
|
|
286
|
+
color: var(--mcoda-text);
|
|
287
|
+
min-height: 40px;
|
|
288
|
+
outline: none;
|
|
289
|
+
padding: 0 12px;
|
|
290
|
+
width: 100%;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.mcoda-agent-setup__field input:focus,
|
|
294
|
+
.mcoda-agent-setup__server-select input:focus,
|
|
295
|
+
.mcoda-agent-setup__server-select select:focus,
|
|
296
|
+
.mcoda-agent-setup__agent-panel-search input:focus,
|
|
297
|
+
.mcoda-agent-setup__agent-trigger:focus-visible,
|
|
298
|
+
.mcoda-agent-setup__button:focus-visible,
|
|
299
|
+
.mcoda-agent-setup__source button:focus-visible {
|
|
300
|
+
border-color: #60a5fa;
|
|
301
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
|
|
302
|
+
outline: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.mcoda-agent-setup__action-row {
|
|
306
|
+
display: flex;
|
|
307
|
+
flex-wrap: wrap;
|
|
308
|
+
gap: 10px;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.mcoda-agent-setup__stage-table-wrap {
|
|
312
|
+
border: 1px solid var(--mcoda-border);
|
|
313
|
+
border-radius: 8px;
|
|
314
|
+
overflow-x: auto;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.mcoda-agent-setup__stage-table {
|
|
318
|
+
border-collapse: collapse;
|
|
319
|
+
min-width: 980px;
|
|
320
|
+
table-layout: fixed;
|
|
321
|
+
width: 100%;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.mcoda-agent-setup__stage-table th {
|
|
325
|
+
background: #f8fafc;
|
|
326
|
+
border-bottom: 1px solid var(--mcoda-border);
|
|
327
|
+
padding: 12px;
|
|
328
|
+
text-align: left;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.mcoda-agent-setup__stage-table td {
|
|
332
|
+
border-bottom: 1px solid #f1f5f9;
|
|
333
|
+
padding: 12px;
|
|
334
|
+
vertical-align: top;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.mcoda-agent-setup__stage-table tr:last-child td {
|
|
338
|
+
border-bottom: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.mcoda-agent-setup__stage-table th:nth-child(1),
|
|
342
|
+
.mcoda-agent-setup__stage-table td:nth-child(1) {
|
|
343
|
+
width: 22%;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.mcoda-agent-setup__stage-table th:nth-child(2),
|
|
347
|
+
.mcoda-agent-setup__stage-table td:nth-child(2) {
|
|
348
|
+
width: 15%;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.mcoda-agent-setup__stage-table th:nth-child(3),
|
|
352
|
+
.mcoda-agent-setup__stage-table td:nth-child(3) {
|
|
353
|
+
width: 18%;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.mcoda-agent-setup__stage-table th:nth-child(4),
|
|
357
|
+
.mcoda-agent-setup__stage-table td:nth-child(4) {
|
|
358
|
+
width: 34%;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.mcoda-agent-setup__stage-cell strong {
|
|
362
|
+
color: var(--mcoda-text);
|
|
363
|
+
display: block;
|
|
364
|
+
font-size: 14px;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.mcoda-agent-setup__stage-cell p {
|
|
368
|
+
color: var(--mcoda-muted);
|
|
369
|
+
font-size: 12px;
|
|
370
|
+
line-height: 1.4;
|
|
371
|
+
margin: 4px 0 8px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.mcoda-agent-setup__stage-cell code,
|
|
375
|
+
.mcoda-agent-setup__agent-row code {
|
|
376
|
+
color: var(--mcoda-faint);
|
|
377
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
378
|
+
font-size: 11px;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.mcoda-agent-setup__source {
|
|
382
|
+
background: #f1f5f9;
|
|
383
|
+
border: 1px solid var(--mcoda-border);
|
|
384
|
+
border-radius: 8px;
|
|
385
|
+
display: inline-flex;
|
|
386
|
+
gap: 4px;
|
|
387
|
+
padding: 4px;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.mcoda-agent-setup__source button {
|
|
391
|
+
background: transparent;
|
|
392
|
+
border: 0;
|
|
393
|
+
border-radius: 6px;
|
|
394
|
+
color: var(--mcoda-muted);
|
|
395
|
+
cursor: pointer;
|
|
396
|
+
font-size: 12px;
|
|
397
|
+
font-weight: 800;
|
|
398
|
+
min-height: 30px;
|
|
399
|
+
padding: 0 10px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.mcoda-agent-setup__source button[aria-pressed="true"] {
|
|
403
|
+
background: #ffffff;
|
|
404
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.1);
|
|
405
|
+
color: var(--mcoda-blue);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.mcoda-agent-setup__server-select {
|
|
409
|
+
display: grid;
|
|
410
|
+
gap: 8px;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.mcoda-agent-setup__muted-pill {
|
|
414
|
+
background: #f8fafc;
|
|
415
|
+
border: 1px solid var(--mcoda-border);
|
|
416
|
+
border-radius: 8px;
|
|
417
|
+
color: var(--mcoda-muted);
|
|
418
|
+
display: inline-flex;
|
|
419
|
+
font-size: 13px;
|
|
420
|
+
font-weight: 650;
|
|
421
|
+
min-height: 40px;
|
|
422
|
+
padding: 10px 12px;
|
|
423
|
+
width: 100%;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.mcoda-agent-setup__agent-combobox {
|
|
427
|
+
min-width: 0;
|
|
428
|
+
position: relative;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.mcoda-agent-setup__agent-trigger {
|
|
432
|
+
align-items: center;
|
|
433
|
+
background: #ffffff;
|
|
434
|
+
border: 1px solid var(--mcoda-border);
|
|
435
|
+
border-radius: 8px;
|
|
436
|
+
color: var(--mcoda-text);
|
|
437
|
+
cursor: pointer;
|
|
438
|
+
display: flex;
|
|
439
|
+
gap: 10px;
|
|
440
|
+
justify-content: space-between;
|
|
441
|
+
min-height: 44px;
|
|
442
|
+
padding: 8px 10px;
|
|
443
|
+
text-align: left;
|
|
444
|
+
width: 100%;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.mcoda-agent-setup__agent-trigger:disabled {
|
|
448
|
+
background: #f8fafc;
|
|
449
|
+
color: var(--mcoda-faint);
|
|
450
|
+
cursor: not-allowed;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.mcoda-agent-setup__agent-trigger-main {
|
|
454
|
+
min-width: 0;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.mcoda-agent-setup__agent-trigger-main strong,
|
|
458
|
+
.mcoda-agent-setup__agent-row-main strong {
|
|
459
|
+
display: block;
|
|
460
|
+
font-size: 13px;
|
|
461
|
+
overflow: hidden;
|
|
462
|
+
text-overflow: ellipsis;
|
|
463
|
+
white-space: nowrap;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.mcoda-agent-setup__agent-trigger-main small,
|
|
467
|
+
.mcoda-agent-setup__agent-row-main small {
|
|
468
|
+
color: var(--mcoda-muted);
|
|
469
|
+
display: block;
|
|
470
|
+
font-size: 11px;
|
|
471
|
+
margin-top: 3px;
|
|
472
|
+
overflow: hidden;
|
|
473
|
+
text-overflow: ellipsis;
|
|
474
|
+
white-space: nowrap;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.mcoda-agent-setup__chevron {
|
|
478
|
+
color: var(--mcoda-faint);
|
|
479
|
+
font-size: 16px;
|
|
480
|
+
line-height: 1;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.mcoda-agent-setup__agent-panel {
|
|
484
|
+
background: #ffffff;
|
|
485
|
+
border: 1px solid var(--mcoda-border);
|
|
486
|
+
border-radius: 8px;
|
|
487
|
+
box-shadow: 0 24px 44px rgba(15, 23, 42, 0.18);
|
|
488
|
+
overflow: hidden;
|
|
489
|
+
position: fixed;
|
|
490
|
+
z-index: 90;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.mcoda-agent-setup__agent-panel-search {
|
|
494
|
+
border-bottom: 1px solid #f1f5f9;
|
|
495
|
+
padding: 8px;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.mcoda-agent-setup__agent-count {
|
|
499
|
+
color: var(--mcoda-muted);
|
|
500
|
+
font-size: 12px;
|
|
501
|
+
font-weight: 650;
|
|
502
|
+
padding: 8px 12px;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.mcoda-agent-setup__agent-list {
|
|
506
|
+
overflow-y: auto;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.mcoda-agent-setup__agent-row {
|
|
510
|
+
align-items: flex-start;
|
|
511
|
+
background: #ffffff;
|
|
512
|
+
border: 0;
|
|
513
|
+
border-top: 1px solid #f1f5f9;
|
|
514
|
+
color: var(--mcoda-text);
|
|
515
|
+
cursor: pointer;
|
|
516
|
+
display: flex;
|
|
517
|
+
gap: 12px;
|
|
518
|
+
justify-content: space-between;
|
|
519
|
+
padding: 9px 12px;
|
|
520
|
+
text-align: left;
|
|
521
|
+
width: 100%;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.mcoda-agent-setup__agent-row:hover,
|
|
525
|
+
.mcoda-agent-setup__agent-row--selected {
|
|
526
|
+
background: var(--mcoda-blue-soft);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.mcoda-agent-setup__agent-row-main {
|
|
530
|
+
min-width: 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.mcoda-agent-setup__selected-mark {
|
|
534
|
+
color: var(--mcoda-blue);
|
|
535
|
+
flex: none;
|
|
536
|
+
font-size: 10px;
|
|
537
|
+
font-weight: 800;
|
|
538
|
+
margin-top: 3px;
|
|
539
|
+
text-transform: uppercase;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.mcoda-agent-setup__empty-state {
|
|
543
|
+
color: var(--mcoda-muted);
|
|
544
|
+
font-size: 14px;
|
|
545
|
+
padding: 28px;
|
|
546
|
+
text-align: center;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
@media (max-width: 1100px) {
|
|
550
|
+
.mcoda-agent-setup__overview,
|
|
551
|
+
.mcoda-agent-setup__metric-grid {
|
|
552
|
+
grid-template-columns: 1fr;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.mcoda-agent-setup__metric-grid {
|
|
556
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
@media (max-width: 720px) {
|
|
561
|
+
.mcoda-agent-setup__header,
|
|
562
|
+
.mcoda-agent-setup__card-heading {
|
|
563
|
+
align-items: stretch;
|
|
564
|
+
flex-direction: column;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.mcoda-agent-setup__metric-grid {
|
|
568
|
+
grid-template-columns: 1fr;
|
|
569
|
+
}
|
|
570
|
+
}
|