@mcoda/agent-setup 0.1.66
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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +14 -0
- package/dist/client.d.ts +20 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +83 -0
- package/dist/defaultStages.d.ts +18 -0
- package/dist/defaultStages.d.ts.map +1 -0
- package/dist/defaultStages.js +56 -0
- package/dist/headless/catalog.d.ts +24 -0
- package/dist/headless/catalog.d.ts.map +1 -0
- package/dist/headless/catalog.js +231 -0
- package/dist/headless/index.d.ts +4 -0
- package/dist/headless/index.d.ts.map +1 -0
- package/dist/headless/index.js +2 -0
- package/dist/headless/normalization.d.ts +12 -0
- package/dist/headless/normalization.d.ts.map +1 -0
- package/dist/headless/normalization.js +105 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/react/index.d.ts +68 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +295 -0
- package/dist/server/cliRuntime.d.ts +12 -0
- package/dist/server/cliRuntime.d.ts.map +1 -0
- package/dist/server/cliRuntime.js +130 -0
- package/dist/server/httpHandlers.d.ts +13 -0
- package/dist/server/httpHandlers.d.ts.map +1 -0
- package/dist/server/httpHandlers.js +130 -0
- package/dist/server/inMemoryRuntime.d.ts +8 -0
- package/dist/server/inMemoryRuntime.d.ts.map +1 -0
- package/dist/server/inMemoryRuntime.js +89 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/programmaticRuntime.d.ts +15 -0
- package/dist/server/programmaticRuntime.d.ts.map +1 -0
- package/dist/server/programmaticRuntime.js +136 -0
- package/dist/server/service.d.ts +3 -0
- package/dist/server/service.d.ts.map +1 -0
- package/dist/server/service.js +143 -0
- package/dist/server/settingsStore.d.ts +3 -0
- package/dist/server/settingsStore.d.ts.map +1 -0
- package/dist/server/settingsStore.js +34 -0
- package/dist/types.d.ts +207 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/examples/express-server/README.md +34 -0
- package/examples/nextjs-mcoda-agent-setup/README.md +63 -0
- package/examples/vite-react-mcoda-agent-setup/README.md +26 -0
- package/package.json +84 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { McodaAgentCatalogEntry, McodaAgentSetupClient, McodaAgentSetupSnapshot, McodaSelfHostedServer, McodaStageDefinition } from "../types.js";
|
|
3
|
+
export interface McodaAgentSetupPageProps {
|
|
4
|
+
client: McodaAgentSetupClient;
|
|
5
|
+
stages?: McodaStageDefinition[];
|
|
6
|
+
title?: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
labels?: Partial<McodaAgentSetupLabels>;
|
|
9
|
+
components?: Partial<McodaAgentSetupComponentOverrides>;
|
|
10
|
+
}
|
|
11
|
+
export interface McodaAgentSetupLabels {
|
|
12
|
+
saveKey: string;
|
|
13
|
+
syncAgents: string;
|
|
14
|
+
saveAssignments: string;
|
|
15
|
+
cloud: string;
|
|
16
|
+
selfHosted: string;
|
|
17
|
+
}
|
|
18
|
+
export interface McodaAgentSetupComponentOverrides {
|
|
19
|
+
AgentCatalogSummary: typeof AgentCatalogSummary;
|
|
20
|
+
MswarmAccessCard: typeof MswarmAccessCard;
|
|
21
|
+
StageAgentAssignments: typeof StageAgentAssignments;
|
|
22
|
+
AgentSourceSelect: typeof AgentSourceSelect;
|
|
23
|
+
SelfHostedServerSelect: typeof SelfHostedServerSelect;
|
|
24
|
+
AgentSearchSelect: typeof AgentSearchSelect;
|
|
25
|
+
}
|
|
26
|
+
export declare function McodaAgentSetupPage(props: McodaAgentSetupPageProps): React.ReactElement;
|
|
27
|
+
export declare function AgentCatalogSummary(props: {
|
|
28
|
+
snapshot: McodaAgentSetupSnapshot;
|
|
29
|
+
}): React.ReactElement;
|
|
30
|
+
export declare function MswarmAccessCard(props: {
|
|
31
|
+
apiKey: string;
|
|
32
|
+
busy?: boolean;
|
|
33
|
+
labels?: Partial<McodaAgentSetupLabels>;
|
|
34
|
+
snapshot?: McodaAgentSetupSnapshot | null;
|
|
35
|
+
onApiKeyChange: (value: string) => void;
|
|
36
|
+
onSaveKey: () => void;
|
|
37
|
+
onSyncAgents: () => void;
|
|
38
|
+
}): React.ReactElement;
|
|
39
|
+
export declare function StageAgentAssignments(props: {
|
|
40
|
+
stages: McodaStageDefinition[];
|
|
41
|
+
snapshot: McodaAgentSetupSnapshot;
|
|
42
|
+
assignments: Record<string, string | null>;
|
|
43
|
+
labels?: Partial<McodaAgentSetupLabels>;
|
|
44
|
+
busy?: boolean;
|
|
45
|
+
onAssignmentChange: (stageKey: string, slug: string | null) => void;
|
|
46
|
+
onSaveAssignments: () => void;
|
|
47
|
+
}): React.ReactElement;
|
|
48
|
+
export declare function AgentSourceSelect(props: {
|
|
49
|
+
value: "cloud" | "self_hosted";
|
|
50
|
+
labels?: Partial<McodaAgentSetupLabels>;
|
|
51
|
+
onChange: (value: "cloud" | "self_hosted") => void;
|
|
52
|
+
}): React.ReactElement;
|
|
53
|
+
export declare function SelfHostedServerSelect(props: {
|
|
54
|
+
servers: McodaSelfHostedServer[];
|
|
55
|
+
value: string;
|
|
56
|
+
onChange: (value: string) => void;
|
|
57
|
+
}): React.ReactElement;
|
|
58
|
+
export declare function AgentSearchSelect(props: {
|
|
59
|
+
agents: McodaAgentCatalogEntry[];
|
|
60
|
+
value: string;
|
|
61
|
+
onChange: (value: string) => void;
|
|
62
|
+
rowHeight?: number;
|
|
63
|
+
viewportHeight?: number;
|
|
64
|
+
}): React.ReactElement;
|
|
65
|
+
export { createMcodaAgentSetupClient } from "../client.js";
|
|
66
|
+
export { defaultMcodaStageDefinitions } from "../defaultStages.js";
|
|
67
|
+
export type * from "../types.js";
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { defaultMcodaStageDefinitions } from "../defaultStages.js";
|
|
3
|
+
import { filterAgentOptions, getVirtualAgentWindow, } from "../headless/catalog.js";
|
|
4
|
+
const DEFAULT_LABELS = {
|
|
5
|
+
saveKey: "Save Key",
|
|
6
|
+
syncAgents: "Sync Agents",
|
|
7
|
+
saveAssignments: "Save Assignments",
|
|
8
|
+
cloud: "Cloud",
|
|
9
|
+
selfHosted: "Self-hosted",
|
|
10
|
+
};
|
|
11
|
+
export function McodaAgentSetupPage(props) {
|
|
12
|
+
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
13
|
+
const stages = props.stages ?? defaultMcodaStageDefinitions;
|
|
14
|
+
const components = {
|
|
15
|
+
AgentCatalogSummary,
|
|
16
|
+
MswarmAccessCard,
|
|
17
|
+
StageAgentAssignments,
|
|
18
|
+
...(props.components ?? {}),
|
|
19
|
+
};
|
|
20
|
+
const [snapshot, setSnapshot] = React.useState(null);
|
|
21
|
+
const [assignments, setAssignments] = React.useState({});
|
|
22
|
+
const [apiKey, setApiKey] = React.useState("");
|
|
23
|
+
const [busy, setBusy] = React.useState(false);
|
|
24
|
+
const [error, setError] = React.useState(null);
|
|
25
|
+
const refresh = React.useCallback(async () => {
|
|
26
|
+
setBusy(true);
|
|
27
|
+
setError(null);
|
|
28
|
+
try {
|
|
29
|
+
const next = await props.client.fetchSnapshot();
|
|
30
|
+
setSnapshot(next);
|
|
31
|
+
setAssignments(next.assignments);
|
|
32
|
+
}
|
|
33
|
+
catch (caught) {
|
|
34
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setBusy(false);
|
|
38
|
+
}
|
|
39
|
+
}, [props.client]);
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
void refresh();
|
|
42
|
+
}, [refresh]);
|
|
43
|
+
const saveKey = async () => {
|
|
44
|
+
if (!apiKey.trim())
|
|
45
|
+
return;
|
|
46
|
+
setBusy(true);
|
|
47
|
+
setError(null);
|
|
48
|
+
try {
|
|
49
|
+
const next = await props.client.configureMswarmApiKey({ apiKey });
|
|
50
|
+
setApiKey("");
|
|
51
|
+
setSnapshot(next);
|
|
52
|
+
setAssignments(next.assignments);
|
|
53
|
+
}
|
|
54
|
+
catch (caught) {
|
|
55
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
setBusy(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const syncAgents = async () => {
|
|
62
|
+
setBusy(true);
|
|
63
|
+
setError(null);
|
|
64
|
+
try {
|
|
65
|
+
const next = await props.client.syncAgents();
|
|
66
|
+
setSnapshot(next);
|
|
67
|
+
setAssignments(next.assignments);
|
|
68
|
+
}
|
|
69
|
+
catch (caught) {
|
|
70
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
setBusy(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const saveAssignments = async () => {
|
|
77
|
+
setBusy(true);
|
|
78
|
+
setError(null);
|
|
79
|
+
try {
|
|
80
|
+
const next = await props.client.updateAssignments({ assignments });
|
|
81
|
+
setSnapshot(next);
|
|
82
|
+
setAssignments(next.assignments);
|
|
83
|
+
}
|
|
84
|
+
catch (caught) {
|
|
85
|
+
setError(caught instanceof Error ? caught.message : String(caught));
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
setBusy(false);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
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("button", { type: "button", disabled: busy, onClick: refresh }, "Refresh")), error
|
|
92
|
+
? React.createElement("p", { className: "mcoda-agent-setup__error" }, error)
|
|
93
|
+
: null, snapshot
|
|
94
|
+
? React.createElement(components.AgentCatalogSummary, { snapshot })
|
|
95
|
+
: React.createElement("p", null, busy ? "Loading" : "No snapshot loaded"), React.createElement(components.MswarmAccessCard, {
|
|
96
|
+
apiKey,
|
|
97
|
+
busy,
|
|
98
|
+
labels,
|
|
99
|
+
snapshot,
|
|
100
|
+
onApiKeyChange: setApiKey,
|
|
101
|
+
onSaveKey: saveKey,
|
|
102
|
+
onSyncAgents: syncAgents,
|
|
103
|
+
}), snapshot
|
|
104
|
+
? React.createElement(components.StageAgentAssignments, {
|
|
105
|
+
stages,
|
|
106
|
+
snapshot,
|
|
107
|
+
assignments,
|
|
108
|
+
labels,
|
|
109
|
+
onAssignmentChange: (stageKey, slug) => setAssignments((current) => ({ ...current, [stageKey]: slug })),
|
|
110
|
+
onSaveAssignments: saveAssignments,
|
|
111
|
+
busy,
|
|
112
|
+
})
|
|
113
|
+
: null);
|
|
114
|
+
}
|
|
115
|
+
export function AgentCatalogSummary(props) {
|
|
116
|
+
const { snapshot } = props;
|
|
117
|
+
const warningEntries = Object.entries(snapshot.catalog.errors);
|
|
118
|
+
return React.createElement("div", { className: "mcoda-agent-setup__summary" }, React.createElement("div", null, `Provider: ${snapshot.provider}`), React.createElement("div", null, `mswarm Key: ${snapshot.mswarmApiKeyConfigured
|
|
119
|
+
? `configured${snapshot.mswarmApiKeyLast4 ? ` (${snapshot.mswarmApiKeyLast4})` : ""}`
|
|
120
|
+
: "missing"}`), React.createElement("div", null, `Synced Agents: ${snapshot.catalog.localAgents.length}`), React.createElement("div", null, `Cloud Agents: ${snapshot.catalog.cloudAgents.length}`), React.createElement("div", null, `Self-hosted Servers: ${snapshot.catalog.selfHostedServers.length}`), warningEntries.length
|
|
121
|
+
? React.createElement("ul", { className: "mcoda-agent-setup__warnings" }, warningEntries.map(([key, value]) => React.createElement("li", { key }, `${key}: ${value}`)))
|
|
122
|
+
: null);
|
|
123
|
+
}
|
|
124
|
+
export function MswarmAccessCard(props) {
|
|
125
|
+
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
126
|
+
return React.createElement("section", { className: "mcoda-agent-setup__access" }, React.createElement("h2", null, "mswarm Access"), React.createElement("input", {
|
|
127
|
+
type: "password",
|
|
128
|
+
value: props.apiKey,
|
|
129
|
+
autoComplete: "off",
|
|
130
|
+
onChange: (event) => props.onApiKeyChange(event.target.value),
|
|
131
|
+
placeholder: props.snapshot?.mswarmApiKeyConfigured
|
|
132
|
+
? "Replace mswarm API key"
|
|
133
|
+
: "mswarm API key",
|
|
134
|
+
}), React.createElement("button", {
|
|
135
|
+
type: "button",
|
|
136
|
+
disabled: props.busy || !props.apiKey.trim(),
|
|
137
|
+
onClick: props.onSaveKey,
|
|
138
|
+
}, labels.saveKey), React.createElement("button", { type: "button", disabled: props.busy, onClick: props.onSyncAgents }, labels.syncAgents));
|
|
139
|
+
}
|
|
140
|
+
export function StageAgentAssignments(props) {
|
|
141
|
+
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
142
|
+
const sourceSelect = AgentSourceSelect;
|
|
143
|
+
const serverSelect = SelfHostedServerSelect;
|
|
144
|
+
const agentSelect = AgentSearchSelect;
|
|
145
|
+
const [sources, setSources] = React.useState({});
|
|
146
|
+
const [servers, setServers] = React.useState({});
|
|
147
|
+
React.useEffect(() => {
|
|
148
|
+
const nextSources = {};
|
|
149
|
+
const nextServers = {};
|
|
150
|
+
for (const stage of props.stages) {
|
|
151
|
+
const assignment = props.assignments[stage.stageKey];
|
|
152
|
+
if (!assignment)
|
|
153
|
+
continue;
|
|
154
|
+
const selfHostedServer = props.snapshot.catalog.selfHostedServers.find((server) => server.agents.some((agent) => agent.slug === assignment));
|
|
155
|
+
if (selfHostedServer) {
|
|
156
|
+
nextSources[stage.stageKey] = "self_hosted";
|
|
157
|
+
nextServers[stage.stageKey] = selfHostedServer.id;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (props.snapshot.catalog.cloudAgents.some((agent) => agent.slug === assignment)) {
|
|
161
|
+
nextSources[stage.stageKey] = "cloud";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
setSources((current) => ({ ...nextSources, ...current }));
|
|
165
|
+
setServers((current) => ({ ...nextServers, ...current }));
|
|
166
|
+
}, [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("div", { className: "mcoda-agent-setup__stage-list" }, props.stages.map((stage) => {
|
|
168
|
+
const source = sources[stage.stageKey] ??
|
|
169
|
+
(stage.preferredSource === "self_hosted" ? "self_hosted" : "cloud");
|
|
170
|
+
const serverId = servers[stage.stageKey];
|
|
171
|
+
const server = props.snapshot.catalog.selfHostedServers.find((candidate) => candidate.id === serverId);
|
|
172
|
+
const agents = source === "cloud"
|
|
173
|
+
? props.snapshot.catalog.cloudAgents
|
|
174
|
+
: server?.agents ?? [];
|
|
175
|
+
return React.createElement("div", { className: "mcoda-agent-setup__stage-row", key: stage.stageKey }, React.createElement("div", null, React.createElement("strong", null, stage.displayName), stage.description
|
|
176
|
+
? React.createElement("p", null, stage.description)
|
|
177
|
+
: null), React.createElement(sourceSelect, {
|
|
178
|
+
value: source,
|
|
179
|
+
labels,
|
|
180
|
+
onChange: (value) => setSources((current) => ({ ...current, [stage.stageKey]: value })),
|
|
181
|
+
}), source === "self_hosted"
|
|
182
|
+
? React.createElement(serverSelect, {
|
|
183
|
+
servers: props.snapshot.catalog.selfHostedServers,
|
|
184
|
+
value: serverId ?? "",
|
|
185
|
+
onChange: (value) => setServers((current) => ({ ...current, [stage.stageKey]: value })),
|
|
186
|
+
})
|
|
187
|
+
: null, React.createElement(agentSelect, {
|
|
188
|
+
agents,
|
|
189
|
+
value: props.assignments[stage.stageKey] ?? "",
|
|
190
|
+
onChange: (slug) => props.onAssignmentChange(stage.stageKey, slug || null),
|
|
191
|
+
}));
|
|
192
|
+
})), React.createElement("button", {
|
|
193
|
+
type: "button",
|
|
194
|
+
disabled: props.busy,
|
|
195
|
+
onClick: props.onSaveAssignments,
|
|
196
|
+
}, labels.saveAssignments));
|
|
197
|
+
}
|
|
198
|
+
export function AgentSourceSelect(props) {
|
|
199
|
+
const labels = { ...DEFAULT_LABELS, ...(props.labels ?? {}) };
|
|
200
|
+
return React.createElement("select", {
|
|
201
|
+
value: props.value,
|
|
202
|
+
onChange: (event) => props.onChange(event.target.value === "self_hosted" ? "self_hosted" : "cloud"),
|
|
203
|
+
}, React.createElement("option", { value: "cloud" }, labels.cloud), React.createElement("option", { value: "self_hosted" }, labels.selfHosted));
|
|
204
|
+
}
|
|
205
|
+
export function SelfHostedServerSelect(props) {
|
|
206
|
+
const [query, setQuery] = React.useState("");
|
|
207
|
+
const filteredServers = props.servers.length > 8 && query.trim()
|
|
208
|
+
? props.servers.filter((server) => [server.label, server.id, server.nodeId, server.serverName, server.remoteSlugPrefix]
|
|
209
|
+
.filter(Boolean)
|
|
210
|
+
.join(" ")
|
|
211
|
+
.toLowerCase()
|
|
212
|
+
.includes(query.trim().toLowerCase()))
|
|
213
|
+
: props.servers;
|
|
214
|
+
return React.createElement("div", { className: "mcoda-agent-setup__server-select" }, props.servers.length > 8
|
|
215
|
+
? React.createElement("input", {
|
|
216
|
+
value: query,
|
|
217
|
+
onChange: (event) => setQuery(event.target.value),
|
|
218
|
+
placeholder: "Search server",
|
|
219
|
+
})
|
|
220
|
+
: null, React.createElement("select", {
|
|
221
|
+
value: props.value,
|
|
222
|
+
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})`))));
|
|
224
|
+
}
|
|
225
|
+
export function AgentSearchSelect(props) {
|
|
226
|
+
const [query, setQuery] = React.useState("");
|
|
227
|
+
const [scrollTop, setScrollTop] = React.useState(0);
|
|
228
|
+
const [activeIndex, setActiveIndex] = React.useState(0);
|
|
229
|
+
const filtered = React.useMemo(() => filterAgentOptions(props.agents, query), [props.agents, query]);
|
|
230
|
+
const rowHeight = props.rowHeight ?? 40;
|
|
231
|
+
const viewportHeight = props.viewportHeight ?? 240;
|
|
232
|
+
const windowed = getVirtualAgentWindow(filtered, {
|
|
233
|
+
scrollTop,
|
|
234
|
+
rowHeight,
|
|
235
|
+
viewportHeight,
|
|
236
|
+
});
|
|
237
|
+
const selected = props.agents.find((agent) => agent.slug === props.value);
|
|
238
|
+
React.useEffect(() => {
|
|
239
|
+
setActiveIndex(0);
|
|
240
|
+
}, [query, props.agents]);
|
|
241
|
+
const onKeyDown = (event) => {
|
|
242
|
+
if (event.key === "Escape") {
|
|
243
|
+
setQuery("");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (event.key === "ArrowDown") {
|
|
247
|
+
event.preventDefault();
|
|
248
|
+
setActiveIndex((current) => Math.min(filtered.length - 1, current + 1));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (event.key === "ArrowUp") {
|
|
252
|
+
event.preventDefault();
|
|
253
|
+
setActiveIndex((current) => Math.max(0, current - 1));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (event.key === "Enter" && filtered[activeIndex]) {
|
|
257
|
+
event.preventDefault();
|
|
258
|
+
props.onChange(filtered[activeIndex].slug);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
return React.createElement("div", { className: "mcoda-agent-setup__agent-search", onKeyDown }, React.createElement("input", {
|
|
262
|
+
value: query,
|
|
263
|
+
onChange: (event) => setQuery(event.target.value),
|
|
264
|
+
"aria-label": "Search agents",
|
|
265
|
+
placeholder: "Search agent, model, provider, or slug",
|
|
266
|
+
}), selected
|
|
267
|
+
? React.createElement("div", { className: "mcoda-agent-setup__selected-agent" }, selected.displayName ?? selected.slug)
|
|
268
|
+
: null, React.createElement("div", null, `Showing all ${filtered.length} agents`), React.createElement("div", {
|
|
269
|
+
className: "mcoda-agent-setup__agent-list",
|
|
270
|
+
role: "listbox",
|
|
271
|
+
style: { maxHeight: viewportHeight, overflowY: "auto" },
|
|
272
|
+
onScroll: (event) => setScrollTop(event.currentTarget.scrollTop),
|
|
273
|
+
}, React.createElement("div", { style: { height: windowed.beforeHeight } }), windowed.items.map((agent) => {
|
|
274
|
+
const absoluteIndex = filtered.findIndex((candidate) => candidate.slug === agent.slug);
|
|
275
|
+
const active = absoluteIndex === activeIndex;
|
|
276
|
+
return (React.createElement("button", {
|
|
277
|
+
key: agent.slug,
|
|
278
|
+
type: "button",
|
|
279
|
+
className: agent.slug === props.value || active
|
|
280
|
+
? "mcoda-agent-setup__agent-row mcoda-agent-setup__agent-row--selected"
|
|
281
|
+
: "mcoda-agent-setup__agent-row",
|
|
282
|
+
role: "option",
|
|
283
|
+
"aria-selected": agent.slug === props.value,
|
|
284
|
+
style: { minHeight: rowHeight },
|
|
285
|
+
onClick: () => props.onChange(agent.slug),
|
|
286
|
+
}, React.createElement("span", null, agent.displayName ?? agent.slug), React.createElement("small", null, [agent.model ?? agent.defaultModel, agent.provider, agent.healthStatus]
|
|
287
|
+
.filter(Boolean)
|
|
288
|
+
.join(" / ")), React.createElement("code", null, agent.slug)));
|
|
289
|
+
}), React.createElement("div", { style: { height: windowed.afterHeight } })));
|
|
290
|
+
}
|
|
291
|
+
function joinClasses(...values) {
|
|
292
|
+
return values.filter(Boolean).join(" ");
|
|
293
|
+
}
|
|
294
|
+
export { createMcodaAgentSetupClient } from "../client.js";
|
|
295
|
+
export { defaultMcodaStageDefinitions } from "../defaultStages.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { McodaRuntimeAdapter } from "../types.js";
|
|
2
|
+
export interface CliMcodaRuntimeAdapterInput {
|
|
3
|
+
command?: string;
|
|
4
|
+
cwd?: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
runCommand?: (command: string, args: string[], options: {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}) => Promise<unknown>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createCliMcodaRuntimeAdapter(input?: CliMcodaRuntimeAdapterInput): McodaRuntimeAdapter;
|
|
12
|
+
//# sourceMappingURL=cliRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliRuntime.d.ts","sourceRoot":"","sources":["../../src/server/cliRuntime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAIV,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC1C,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,GAAE,2BAAgC,GACtC,mBAAmB,CA4GrB"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { normalizeAgentCatalogEntries } from "../headless/normalization.js";
|
|
3
|
+
import { isCloudAgent, isSelfHostedAgent } from "../headless/catalog.js";
|
|
4
|
+
export function createCliMcodaRuntimeAdapter(input = {}) {
|
|
5
|
+
const command = input.command ?? "mcoda";
|
|
6
|
+
const run = input.runCommand ??
|
|
7
|
+
((cmd, args, options) => runJsonCommand(cmd, args, options));
|
|
8
|
+
const runAgents = async (args, fallback) => normalizeAgentCatalogEntries(await run(command, args, {
|
|
9
|
+
cwd: input.cwd,
|
|
10
|
+
timeoutMs: input.timeoutMs,
|
|
11
|
+
}), fallback);
|
|
12
|
+
const listLocal = async (options) => runAgents([
|
|
13
|
+
"agent",
|
|
14
|
+
"list",
|
|
15
|
+
"--json",
|
|
16
|
+
...(options?.refreshHealth ? ["--refresh-health"] : []),
|
|
17
|
+
], {
|
|
18
|
+
source: "local_registry",
|
|
19
|
+
synced: true,
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
runtime: {
|
|
23
|
+
mode: "cli_fallback",
|
|
24
|
+
requiresMcodaCli: true,
|
|
25
|
+
},
|
|
26
|
+
async configureMswarmApiKey() {
|
|
27
|
+
throw new Error("The CLI mcoda runtime adapter does not configure mswarm API keys until mcoda exposes a stdin-safe secret command.");
|
|
28
|
+
},
|
|
29
|
+
async listCloudAgents(options) {
|
|
30
|
+
return runAgents([
|
|
31
|
+
"cloud",
|
|
32
|
+
"agent",
|
|
33
|
+
"list",
|
|
34
|
+
"--json",
|
|
35
|
+
...(options?.provider ? ["--provider", options.provider] : []),
|
|
36
|
+
], {
|
|
37
|
+
source: "cloud_catalog",
|
|
38
|
+
synced: false,
|
|
39
|
+
managedKind: "cloud",
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
async syncCloudAgents(options) {
|
|
43
|
+
await run(command, [
|
|
44
|
+
"cloud",
|
|
45
|
+
"agent",
|
|
46
|
+
"sync",
|
|
47
|
+
"--prune",
|
|
48
|
+
"--json",
|
|
49
|
+
...(options?.provider ? ["--provider", options.provider] : []),
|
|
50
|
+
], {
|
|
51
|
+
cwd: input.cwd,
|
|
52
|
+
timeoutMs: input.timeoutMs,
|
|
53
|
+
});
|
|
54
|
+
return (await listLocal(options)).filter(isCloudAgent);
|
|
55
|
+
},
|
|
56
|
+
async listSelfHostedAgents(options) {
|
|
57
|
+
return runAgents([
|
|
58
|
+
"self-hosted",
|
|
59
|
+
"agent",
|
|
60
|
+
"list",
|
|
61
|
+
"--provider",
|
|
62
|
+
options?.provider ?? "mcoda",
|
|
63
|
+
"--json",
|
|
64
|
+
], {
|
|
65
|
+
source: "self_hosted_catalog",
|
|
66
|
+
synced: false,
|
|
67
|
+
managedKind: "self_hosted",
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
async syncSelfHostedAgents(options) {
|
|
71
|
+
await run(command, [
|
|
72
|
+
"self-hosted",
|
|
73
|
+
"agent",
|
|
74
|
+
"sync",
|
|
75
|
+
"--provider",
|
|
76
|
+
options?.provider ?? "mcoda",
|
|
77
|
+
"--prune",
|
|
78
|
+
"--json",
|
|
79
|
+
], {
|
|
80
|
+
cwd: input.cwd,
|
|
81
|
+
timeoutMs: input.timeoutMs,
|
|
82
|
+
});
|
|
83
|
+
return (await listLocal(options)).filter(isSelfHostedAgent);
|
|
84
|
+
},
|
|
85
|
+
listLocalAgents: listLocal,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function runJsonCommand(command, args, options) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const child = spawn(command, args, {
|
|
91
|
+
cwd: options.cwd,
|
|
92
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
93
|
+
});
|
|
94
|
+
let stdout = "";
|
|
95
|
+
let stderr = "";
|
|
96
|
+
const timeout = options.timeoutMs
|
|
97
|
+
? setTimeout(() => {
|
|
98
|
+
child.kill("SIGTERM");
|
|
99
|
+
reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
|
|
100
|
+
}, options.timeoutMs)
|
|
101
|
+
: undefined;
|
|
102
|
+
child.stdout.setEncoding("utf8");
|
|
103
|
+
child.stderr.setEncoding("utf8");
|
|
104
|
+
child.stdout.on("data", (chunk) => {
|
|
105
|
+
stdout += chunk;
|
|
106
|
+
});
|
|
107
|
+
child.stderr.on("data", (chunk) => {
|
|
108
|
+
stderr += chunk;
|
|
109
|
+
});
|
|
110
|
+
child.on("error", (error) => {
|
|
111
|
+
if (timeout)
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
reject(error);
|
|
114
|
+
});
|
|
115
|
+
child.on("close", (code) => {
|
|
116
|
+
if (timeout)
|
|
117
|
+
clearTimeout(timeout);
|
|
118
|
+
if (code !== 0) {
|
|
119
|
+
reject(new Error(stderr.trim() || `Command failed with exit code ${code}`));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
resolve(stdout.trim() ? JSON.parse(stdout) : {});
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
reject(new Error(`Command did not return valid JSON: ${error instanceof Error ? error.message : String(error)}`));
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { McodaAgentSetupHttpRequest, McodaAgentSetupHttpResponse, McodaAgentSetupService } from "../types.js";
|
|
2
|
+
export interface McodaAgentSetupHttpHandlers {
|
|
3
|
+
getAgentSettings(request?: unknown): Promise<McodaAgentSetupHttpResponse>;
|
|
4
|
+
postMswarmApiKey(body: unknown, request?: unknown): Promise<McodaAgentSetupHttpResponse>;
|
|
5
|
+
postAgentsSync(body?: unknown, request?: unknown): Promise<McodaAgentSetupHttpResponse>;
|
|
6
|
+
patchAgentSettings(body: unknown, request?: unknown): Promise<McodaAgentSetupHttpResponse>;
|
|
7
|
+
postAgentsTest(body: unknown, request?: unknown): Promise<McodaAgentSetupHttpResponse>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createMcodaAgentSetupHttpHandlers(service: McodaAgentSetupService): McodaAgentSetupHttpHandlers;
|
|
10
|
+
export declare function createMcodaAgentSetupHttpHandler(service: McodaAgentSetupService, options?: {
|
|
11
|
+
basePath?: string;
|
|
12
|
+
}): (request: McodaAgentSetupHttpRequest) => Promise<McodaAgentSetupHttpResponse>;
|
|
13
|
+
//# sourceMappingURL=httpHandlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpHandlers.d.ts","sourceRoot":"","sources":["../../src/server/httpHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,2BAA2B;IAC1C,gBAAgB,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1E,gBAAgB,CACd,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACxC,cAAc,CACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACxC,kBAAkB,CAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACxC,cAAc,CACZ,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACzC;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,sBAAsB,GAC9B,2BAA2B,CA0E7B;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,sBAAsB,EAC/B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,CAAC,OAAO,EAAE,0BAA0B,KAAK,OAAO,CAAC,2BAA2B,CAAC,CA8B/E"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export function createMcodaAgentSetupHttpHandlers(service) {
|
|
2
|
+
return {
|
|
3
|
+
async getAgentSettings(request) {
|
|
4
|
+
return jsonResponse(200, await service.fetchSnapshot(request));
|
|
5
|
+
},
|
|
6
|
+
async postMswarmApiKey(body, request) {
|
|
7
|
+
const record = asRecord(body);
|
|
8
|
+
return jsonResponse(200, await service.configureMswarmApiKey({
|
|
9
|
+
apiKey: stringValue(record.mswarm_api_key) ??
|
|
10
|
+
stringValue(record.mswarmApiKey) ??
|
|
11
|
+
stringValue(record.apiKey) ??
|
|
12
|
+
"",
|
|
13
|
+
reasonCode: stringValue(record.reason_code) ??
|
|
14
|
+
stringValue(record.reasonCode) ??
|
|
15
|
+
undefined,
|
|
16
|
+
metadata: asOptionalRecord(record.metadata),
|
|
17
|
+
}, request));
|
|
18
|
+
},
|
|
19
|
+
async postAgentsSync(body, request) {
|
|
20
|
+
const record = asRecord(body);
|
|
21
|
+
return jsonResponse(200, await service.syncAgents({
|
|
22
|
+
reasonCode: stringValue(record.reason_code) ??
|
|
23
|
+
stringValue(record.reasonCode) ??
|
|
24
|
+
undefined,
|
|
25
|
+
metadata: asOptionalRecord(record.metadata),
|
|
26
|
+
}, request));
|
|
27
|
+
},
|
|
28
|
+
async patchAgentSettings(body, request) {
|
|
29
|
+
const record = asRecord(body);
|
|
30
|
+
return jsonResponse(200, await service.updateAssignments({
|
|
31
|
+
assignments: asStringNullRecord(record.assignments),
|
|
32
|
+
reasonCode: stringValue(record.reason_code) ??
|
|
33
|
+
stringValue(record.reasonCode) ??
|
|
34
|
+
undefined,
|
|
35
|
+
metadata: asOptionalRecord(record.metadata),
|
|
36
|
+
}, request));
|
|
37
|
+
},
|
|
38
|
+
async postAgentsTest(body, request) {
|
|
39
|
+
const record = asRecord(body);
|
|
40
|
+
return jsonResponse(200, await service.testAgent({
|
|
41
|
+
slug: stringValue(record.slug) ?? "",
|
|
42
|
+
prompt: stringValue(record.prompt) ?? undefined,
|
|
43
|
+
timeoutMs: numberValue(record.timeout_ms) ?? numberValue(record.timeoutMs) ?? undefined,
|
|
44
|
+
}, request));
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function createMcodaAgentSetupHttpHandler(service, options = {}) {
|
|
49
|
+
const handlers = createMcodaAgentSetupHttpHandlers(service);
|
|
50
|
+
const basePath = normalizePath(options.basePath ?? "/api/mcoda");
|
|
51
|
+
return async (request) => {
|
|
52
|
+
try {
|
|
53
|
+
const method = request.method.trim().toUpperCase();
|
|
54
|
+
const route = normalizeRoute(request.path ?? request.url ?? "/", basePath);
|
|
55
|
+
const rawRequest = request.raw ?? request;
|
|
56
|
+
if (method === "GET" && route === "/agent-settings") {
|
|
57
|
+
return handlers.getAgentSettings(rawRequest);
|
|
58
|
+
}
|
|
59
|
+
if (method === "POST" && route === "/mswarm-api-key") {
|
|
60
|
+
return handlers.postMswarmApiKey(request.body, rawRequest);
|
|
61
|
+
}
|
|
62
|
+
if (method === "POST" && route === "/agents/sync") {
|
|
63
|
+
return handlers.postAgentsSync(request.body, rawRequest);
|
|
64
|
+
}
|
|
65
|
+
if (method === "PATCH" && route === "/agent-settings") {
|
|
66
|
+
return handlers.patchAgentSettings(request.body, rawRequest);
|
|
67
|
+
}
|
|
68
|
+
if (method === "POST" && route === "/agents/test") {
|
|
69
|
+
return handlers.postAgentsTest(request.body, rawRequest);
|
|
70
|
+
}
|
|
71
|
+
return jsonResponse(404, { error: "not found" });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return jsonResponse(400, {
|
|
75
|
+
error: error instanceof Error ? error.message : String(error),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function jsonResponse(status, body) {
|
|
81
|
+
return {
|
|
82
|
+
status,
|
|
83
|
+
headers: {
|
|
84
|
+
"content-type": "application/json",
|
|
85
|
+
},
|
|
86
|
+
body,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function normalizeRoute(pathOrUrl, basePath) {
|
|
90
|
+
let pathname = pathOrUrl;
|
|
91
|
+
try {
|
|
92
|
+
pathname = new URL(pathOrUrl, "http://localhost").pathname;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
pathname = pathOrUrl.split("?")[0] ?? pathOrUrl;
|
|
96
|
+
}
|
|
97
|
+
const normalized = normalizePath(pathname);
|
|
98
|
+
if (normalized === basePath)
|
|
99
|
+
return "/";
|
|
100
|
+
if (normalized.startsWith(`${basePath}/`)) {
|
|
101
|
+
return normalized.slice(basePath.length) || "/";
|
|
102
|
+
}
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
105
|
+
function normalizePath(pathname) {
|
|
106
|
+
const prefixed = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
107
|
+
return prefixed.replace(/\/+$/, "") || "/";
|
|
108
|
+
}
|
|
109
|
+
function asRecord(value) {
|
|
110
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
111
|
+
? value
|
|
112
|
+
: {};
|
|
113
|
+
}
|
|
114
|
+
function asOptionalRecord(value) {
|
|
115
|
+
const record = asRecord(value);
|
|
116
|
+
return Object.keys(record).length ? record : undefined;
|
|
117
|
+
}
|
|
118
|
+
function asStringNullRecord(value) {
|
|
119
|
+
const record = asRecord(value);
|
|
120
|
+
return Object.fromEntries(Object.entries(record).map(([key, entry]) => [
|
|
121
|
+
key,
|
|
122
|
+
typeof entry === "string" && entry.trim() ? entry : null,
|
|
123
|
+
]));
|
|
124
|
+
}
|
|
125
|
+
function stringValue(value) {
|
|
126
|
+
return typeof value === "string" && value.trim() ? value : null;
|
|
127
|
+
}
|
|
128
|
+
function numberValue(value) {
|
|
129
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
130
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { McodaAgentCatalogEntry, McodaRuntimeAdapter } from "../types.js";
|
|
2
|
+
export interface InMemoryMcodaRuntimeAdapterInput {
|
|
3
|
+
cloudAgents?: McodaAgentCatalogEntry[];
|
|
4
|
+
selfHostedAgents?: McodaAgentCatalogEntry[];
|
|
5
|
+
localAgents?: McodaAgentCatalogEntry[];
|
|
6
|
+
}
|
|
7
|
+
export declare function createInMemoryMcodaRuntimeAdapter(input?: InMemoryMcodaRuntimeAdapterInput): McodaRuntimeAdapter;
|
|
8
|
+
//# sourceMappingURL=inMemoryRuntime.d.ts.map
|