@getcatalystiq/agent-plane-ui 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-P4N2P42X.js → chunk-OOBDCC6Q.js} +75 -2
- package/dist/{chunk-4XBBDUSZ.cjs → chunk-VBGYWQUF.cjs} +81 -0
- package/dist/editor.cjs +291 -21
- package/dist/editor.d.cts +50 -1
- package/dist/editor.d.ts +50 -1
- package/dist/editor.js +271 -2
- package/dist/index.cjs +570 -622
- package/dist/index.js +11 -87
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React3 from 'react';
|
|
2
2
|
import { createContext, useRef, useMemo, useContext } from 'react';
|
|
3
|
-
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
4
|
import useSWR from 'swr';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -193,8 +193,81 @@ var Input = React3.forwardRef(
|
|
|
193
193
|
}
|
|
194
194
|
);
|
|
195
195
|
Input.displayName = "Input";
|
|
196
|
+
function FormField({ label, children, error, hint }) {
|
|
197
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
198
|
+
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
199
|
+
children,
|
|
200
|
+
hint && !error && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: hint }),
|
|
201
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-1", children: error })
|
|
202
|
+
] });
|
|
203
|
+
}
|
|
196
204
|
function Skeleton({ className, ...props }) {
|
|
197
205
|
return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted/50", className), ...props });
|
|
198
206
|
}
|
|
207
|
+
function Dialog({ open, onOpenChange, children }) {
|
|
208
|
+
React3.useEffect(() => {
|
|
209
|
+
if (!open) return;
|
|
210
|
+
function onKeyDown(e) {
|
|
211
|
+
if (e.key === "Escape") onOpenChange(false);
|
|
212
|
+
}
|
|
213
|
+
document.addEventListener("keydown", onKeyDown);
|
|
214
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
215
|
+
}, [open, onOpenChange]);
|
|
216
|
+
React3.useEffect(() => {
|
|
217
|
+
if (!open) return;
|
|
218
|
+
const prev = document.body.style.overflow;
|
|
219
|
+
document.body.style.overflow = "hidden";
|
|
220
|
+
return () => {
|
|
221
|
+
document.body.style.overflow = prev;
|
|
222
|
+
};
|
|
223
|
+
}, [open]);
|
|
224
|
+
if (!open) return null;
|
|
225
|
+
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
|
|
226
|
+
/* @__PURE__ */ jsx(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
className: "absolute inset-0 bg-black/60 animate-dialog-overlay",
|
|
230
|
+
onClick: () => onOpenChange(false)
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
children
|
|
234
|
+
] });
|
|
235
|
+
}
|
|
236
|
+
function DialogContent({ className, children, ...props }) {
|
|
237
|
+
return /* @__PURE__ */ jsx(
|
|
238
|
+
"div",
|
|
239
|
+
{
|
|
240
|
+
className: cn(
|
|
241
|
+
"relative z-10 w-full bg-background border border-border rounded-xl shadow-2xl mx-4 max-h-[85vh] overflow-y-auto animate-dialog-content",
|
|
242
|
+
className
|
|
243
|
+
),
|
|
244
|
+
onClick: (e) => e.stopPropagation(),
|
|
245
|
+
...props,
|
|
246
|
+
children
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
function DialogHeader({ className, children, ...props }) {
|
|
251
|
+
return /* @__PURE__ */ jsx("div", { className: cn("px-6 pt-6 pb-0", className), ...props, children });
|
|
252
|
+
}
|
|
253
|
+
function DialogBody({ className, children, ...props }) {
|
|
254
|
+
return /* @__PURE__ */ jsx("div", { className: cn("px-6 py-4", className), ...props, children });
|
|
255
|
+
}
|
|
256
|
+
function DialogFooter({ className, children, ...props }) {
|
|
257
|
+
return /* @__PURE__ */ jsx(
|
|
258
|
+
"div",
|
|
259
|
+
{
|
|
260
|
+
className: cn("flex items-center justify-end gap-2 px-6 py-4 border-t border-border bg-muted/30 rounded-b-xl", className),
|
|
261
|
+
...props,
|
|
262
|
+
children
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
function DialogTitle({ className, children, ...props }) {
|
|
267
|
+
return /* @__PURE__ */ jsx("h2", { className: cn("text-base font-semibold", className), ...props, children });
|
|
268
|
+
}
|
|
269
|
+
function DialogDescription({ className, children, ...props }) {
|
|
270
|
+
return /* @__PURE__ */ jsx("p", { className: cn("text-sm text-muted-foreground mt-1", className), ...props, children });
|
|
271
|
+
}
|
|
199
272
|
|
|
200
|
-
export { AgentPlaneProvider, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Skeleton, badgeVariants, buttonVariants, cn, supportsClaudeRunner, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
|
273
|
+
export { AgentPlaneProvider, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FormField, Input, Skeleton, badgeVariants, buttonVariants, cn, supportsClaudeRunner, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
|
@@ -217,9 +217,82 @@ var Input = React3__namespace.forwardRef(
|
|
|
217
217
|
}
|
|
218
218
|
);
|
|
219
219
|
Input.displayName = "Input";
|
|
220
|
+
function FormField({ label, children, error, hint }) {
|
|
221
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
222
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
223
|
+
children,
|
|
224
|
+
hint && !error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1", children: hint }),
|
|
225
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive mt-1", children: error })
|
|
226
|
+
] });
|
|
227
|
+
}
|
|
220
228
|
function Skeleton({ className, ...props }) {
|
|
221
229
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("animate-pulse rounded-md bg-muted/50", className), ...props });
|
|
222
230
|
}
|
|
231
|
+
function Dialog({ open, onOpenChange, children }) {
|
|
232
|
+
React3__namespace.useEffect(() => {
|
|
233
|
+
if (!open) return;
|
|
234
|
+
function onKeyDown(e) {
|
|
235
|
+
if (e.key === "Escape") onOpenChange(false);
|
|
236
|
+
}
|
|
237
|
+
document.addEventListener("keydown", onKeyDown);
|
|
238
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
239
|
+
}, [open, onOpenChange]);
|
|
240
|
+
React3__namespace.useEffect(() => {
|
|
241
|
+
if (!open) return;
|
|
242
|
+
const prev = document.body.style.overflow;
|
|
243
|
+
document.body.style.overflow = "hidden";
|
|
244
|
+
return () => {
|
|
245
|
+
document.body.style.overflow = prev;
|
|
246
|
+
};
|
|
247
|
+
}, [open]);
|
|
248
|
+
if (!open) return null;
|
|
249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
251
|
+
"div",
|
|
252
|
+
{
|
|
253
|
+
className: "absolute inset-0 bg-black/60 animate-dialog-overlay",
|
|
254
|
+
onClick: () => onOpenChange(false)
|
|
255
|
+
}
|
|
256
|
+
),
|
|
257
|
+
children
|
|
258
|
+
] });
|
|
259
|
+
}
|
|
260
|
+
function DialogContent({ className, children, ...props }) {
|
|
261
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
262
|
+
"div",
|
|
263
|
+
{
|
|
264
|
+
className: cn(
|
|
265
|
+
"relative z-10 w-full bg-background border border-border rounded-xl shadow-2xl mx-4 max-h-[85vh] overflow-y-auto animate-dialog-content",
|
|
266
|
+
className
|
|
267
|
+
),
|
|
268
|
+
onClick: (e) => e.stopPropagation(),
|
|
269
|
+
...props,
|
|
270
|
+
children
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
function DialogHeader({ className, children, ...props }) {
|
|
275
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("px-6 pt-6 pb-0", className), ...props, children });
|
|
276
|
+
}
|
|
277
|
+
function DialogBody({ className, children, ...props }) {
|
|
278
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("px-6 py-4", className), ...props, children });
|
|
279
|
+
}
|
|
280
|
+
function DialogFooter({ className, children, ...props }) {
|
|
281
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
282
|
+
"div",
|
|
283
|
+
{
|
|
284
|
+
className: cn("flex items-center justify-end gap-2 px-6 py-4 border-t border-border bg-muted/30 rounded-b-xl", className),
|
|
285
|
+
...props,
|
|
286
|
+
children
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
function DialogTitle({ className, children, ...props }) {
|
|
291
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h2", { className: cn("text-base font-semibold", className), ...props, children });
|
|
292
|
+
}
|
|
293
|
+
function DialogDescription({ className, children, ...props }) {
|
|
294
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm text-muted-foreground mt-1", className), ...props, children });
|
|
295
|
+
}
|
|
223
296
|
|
|
224
297
|
exports.AgentPlaneProvider = AgentPlaneProvider;
|
|
225
298
|
exports.Badge = Badge;
|
|
@@ -229,6 +302,14 @@ exports.CardContent = CardContent;
|
|
|
229
302
|
exports.CardDescription = CardDescription;
|
|
230
303
|
exports.CardHeader = CardHeader;
|
|
231
304
|
exports.CardTitle = CardTitle;
|
|
305
|
+
exports.Dialog = Dialog;
|
|
306
|
+
exports.DialogBody = DialogBody;
|
|
307
|
+
exports.DialogContent = DialogContent;
|
|
308
|
+
exports.DialogDescription = DialogDescription;
|
|
309
|
+
exports.DialogFooter = DialogFooter;
|
|
310
|
+
exports.DialogHeader = DialogHeader;
|
|
311
|
+
exports.DialogTitle = DialogTitle;
|
|
312
|
+
exports.FormField = FormField;
|
|
232
313
|
exports.Input = Input;
|
|
233
314
|
exports.Skeleton = Skeleton;
|
|
234
315
|
exports.badgeVariants = badgeVariants;
|
package/dist/editor.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVBGYWQUF_cjs = require('./chunk-VBGYWQUF.cjs');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var CodeMirror = require('@uiw/react-codemirror');
|
|
6
6
|
var langMarkdown = require('@codemirror/lang-markdown');
|
|
@@ -263,7 +263,7 @@ function FileTreeEditor({
|
|
|
263
263
|
}),
|
|
264
264
|
!readOnly && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingLeft: `${(depth + 1) * 16 + 8}px` }, className: "py-1 pr-2", children: addingFileInDir === node.fullPath ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
|
|
265
265
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
266
|
-
|
|
266
|
+
chunkVBGYWQUF_cjs.Input,
|
|
267
267
|
{
|
|
268
268
|
value: newFileName,
|
|
269
269
|
onChange: (e) => setNewFileName(e.target.value),
|
|
@@ -273,7 +273,7 @@ function FileTreeEditor({
|
|
|
273
273
|
autoFocus: true
|
|
274
274
|
}
|
|
275
275
|
),
|
|
276
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
276
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Button, { onClick: () => addFileInDir(node.fullPath), size: "sm", className: "h-6 text-xs px-2", children: "+" })
|
|
277
277
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
278
278
|
"button",
|
|
279
279
|
{
|
|
@@ -292,10 +292,10 @@ function FileTreeEditor({
|
|
|
292
292
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
293
293
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
294
294
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold", children: title }),
|
|
295
|
-
isDirty && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
296
|
-
readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
295
|
+
isDirty && !readOnly && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "destructive", className: "text-xs", children: "Unsaved changes" }),
|
|
296
|
+
readOnly && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "secondary", className: "text-xs", children: "Read-only" })
|
|
297
297
|
] }),
|
|
298
|
-
!readOnly && !hideSave && /* @__PURE__ */ jsxRuntime.jsx(
|
|
298
|
+
!readOnly && !hideSave && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Button, { onClick: handleSave, disabled: saving || !isDirty, size: "sm", children: saving ? "Saving..." : saveLabel })
|
|
299
299
|
] }),
|
|
300
300
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4 min-h-[500px]", children: [
|
|
301
301
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-64 shrink-0 border border-border rounded-md overflow-hidden", children: [
|
|
@@ -315,7 +315,7 @@ function FileTreeEditor({
|
|
|
315
315
|
] }),
|
|
316
316
|
showAddFolder && !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 border-b border-border flex gap-1", children: [
|
|
317
317
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
318
|
-
|
|
318
|
+
chunkVBGYWQUF_cjs.Input,
|
|
319
319
|
{
|
|
320
320
|
value: newFolderName,
|
|
321
321
|
onChange: (e) => setNewFolderName(e.target.value),
|
|
@@ -325,7 +325,7 @@ function FileTreeEditor({
|
|
|
325
325
|
autoFocus: true
|
|
326
326
|
}
|
|
327
327
|
),
|
|
328
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
328
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Button, { onClick: addFolder, size: "sm", className: "h-7 text-xs px-2", children: "Add" })
|
|
329
329
|
] }),
|
|
330
330
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm overflow-y-auto", children: [
|
|
331
331
|
tree.rootFiles.map((file) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -382,9 +382,9 @@ function FileTreeEditor({
|
|
|
382
382
|
] });
|
|
383
383
|
}
|
|
384
384
|
function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
385
|
-
const { LinkComponent, basePath } =
|
|
386
|
-
const client =
|
|
387
|
-
const { data: pluginFiles, error, isLoading } =
|
|
385
|
+
const { LinkComponent, basePath } = chunkVBGYWQUF_cjs.useNavigation();
|
|
386
|
+
const client = chunkVBGYWQUF_cjs.useAgentPlaneClient();
|
|
387
|
+
const { data: pluginFiles, error, isLoading } = chunkVBGYWQUF_cjs.useApi(
|
|
388
388
|
`marketplace-${marketplaceId}-plugin-files-${pluginName}`,
|
|
389
389
|
(c) => c.pluginMarketplaces.getPluginFiles(marketplaceId, pluginName)
|
|
390
390
|
);
|
|
@@ -442,9 +442,9 @@ function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
|
442
442
|
}
|
|
443
443
|
if (isLoading || !pluginFiles) {
|
|
444
444
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
445
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
446
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
447
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
445
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Skeleton, { className: "h-8 w-48" }),
|
|
446
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Skeleton, { className: "h-4 w-96" }),
|
|
447
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Skeleton, { className: "h-[500px] rounded-lg" })
|
|
448
448
|
] });
|
|
449
449
|
}
|
|
450
450
|
const tabs = [
|
|
@@ -464,7 +464,7 @@ function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
|
464
464
|
) }),
|
|
465
465
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
466
466
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold", children: pluginName }),
|
|
467
|
-
readOnly ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
467
|
+
readOnly ? /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "outline", children: "Read-only" }) : /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "secondary", children: "Editable" })
|
|
468
468
|
] })
|
|
469
469
|
] }),
|
|
470
470
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end border-b border-border", children: [
|
|
@@ -487,7 +487,7 @@ function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
|
487
487
|
!readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 ml-auto pb-2", children: [
|
|
488
488
|
saveError && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: saveError }),
|
|
489
489
|
success && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-green-500", children: success }),
|
|
490
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
490
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Button, { size: "sm", onClick: handleSaveAll, disabled: saving, children: saving ? "Pushing to GitHub..." : "Save All to GitHub" })
|
|
491
491
|
] })
|
|
492
492
|
] }),
|
|
493
493
|
activeTab === "agents" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -518,12 +518,12 @@ function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
|
518
518
|
savedVersion
|
|
519
519
|
}
|
|
520
520
|
),
|
|
521
|
-
activeTab === "connectors" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
522
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
523
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
524
|
-
readOnly && /* @__PURE__ */ jsxRuntime.jsx(
|
|
521
|
+
activeTab === "connectors" && /* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.Card, { children: [
|
|
522
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.CardHeader, { className: "flex flex-row items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
523
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.CardTitle, { className: "text-base", children: "Connectors (.mcp.json)" }),
|
|
524
|
+
readOnly && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "secondary", className: "text-xs", children: "Read-only" })
|
|
525
525
|
] }) }),
|
|
526
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
526
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.CardContent, { children: [
|
|
527
527
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-border rounded-md overflow-hidden", children: [
|
|
528
528
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-1.5 bg-muted/50 border-b border-border text-xs text-muted-foreground", children: ".mcp.json" }),
|
|
529
529
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -548,6 +548,276 @@ function PluginEditorPage({ marketplaceId, pluginName }) {
|
|
|
548
548
|
] })
|
|
549
549
|
] });
|
|
550
550
|
}
|
|
551
|
+
var FILE_MAP = [
|
|
552
|
+
{ path: "SOUL.md", field: "soul_md" },
|
|
553
|
+
{ path: "IDENTITY.md", field: "identity_md" },
|
|
554
|
+
{ path: "STYLE.md", field: "style_md" },
|
|
555
|
+
{ path: "AGENTS.md", field: "agents_md" },
|
|
556
|
+
{ path: "HEARTBEAT.md", field: "heartbeat_md" },
|
|
557
|
+
{ path: "USER_TEMPLATE.md", field: "user_template_md" },
|
|
558
|
+
{ path: "examples/good-outputs.md", field: "examples_good_md" },
|
|
559
|
+
{ path: "examples/bad-outputs.md", field: "examples_bad_md" }
|
|
560
|
+
];
|
|
561
|
+
function agentToFiles(agent) {
|
|
562
|
+
const files = [];
|
|
563
|
+
for (const { path, field } of FILE_MAP) {
|
|
564
|
+
const value = agent[field];
|
|
565
|
+
if (typeof value === "string" && value.length > 0) {
|
|
566
|
+
files.push({ path, content: value });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return files;
|
|
570
|
+
}
|
|
571
|
+
function filesToPayload(files) {
|
|
572
|
+
const payload = {};
|
|
573
|
+
for (const { path, field } of FILE_MAP) {
|
|
574
|
+
const file = files.find((f) => f.path === path);
|
|
575
|
+
payload[field] = file ? file.content : null;
|
|
576
|
+
}
|
|
577
|
+
return payload;
|
|
578
|
+
}
|
|
579
|
+
function AgentIdentityTab({
|
|
580
|
+
agent,
|
|
581
|
+
FileTreeEditor: FileTreeEditor2,
|
|
582
|
+
onSaved,
|
|
583
|
+
onGenerateSoul,
|
|
584
|
+
onImportSoul,
|
|
585
|
+
onExportSoul,
|
|
586
|
+
onPublishSoul
|
|
587
|
+
}) {
|
|
588
|
+
const client = chunkVBGYWQUF_cjs.useAgentPlaneClient();
|
|
589
|
+
const [saving, setSaving] = react.useState(false);
|
|
590
|
+
const [error, setError] = react.useState("");
|
|
591
|
+
const [generating, setGenerating] = react.useState(false);
|
|
592
|
+
const [publishing, setPublishing] = react.useState(false);
|
|
593
|
+
const [importOpen, setImportOpen] = react.useState(false);
|
|
594
|
+
const [savedVersion, setSavedVersion] = react.useState(0);
|
|
595
|
+
const [overrideFiles, setOverrideFiles] = react.useState(null);
|
|
596
|
+
const initialFiles = react.useMemo(() => agentToFiles(agent), [agent]);
|
|
597
|
+
const editorFiles = overrideFiles ?? initialFiles;
|
|
598
|
+
const handleSave = react.useCallback(
|
|
599
|
+
async (files) => {
|
|
600
|
+
setSaving(true);
|
|
601
|
+
setError("");
|
|
602
|
+
try {
|
|
603
|
+
const payload = filesToPayload(files);
|
|
604
|
+
await client.agents.update(agent.id, payload);
|
|
605
|
+
setOverrideFiles(null);
|
|
606
|
+
setSavedVersion((v) => v + 1);
|
|
607
|
+
onSaved?.();
|
|
608
|
+
} catch (err) {
|
|
609
|
+
setError(err instanceof Error ? err.message : "Failed to save");
|
|
610
|
+
throw err;
|
|
611
|
+
} finally {
|
|
612
|
+
setSaving(false);
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
[agent.id, client, onSaved]
|
|
616
|
+
);
|
|
617
|
+
function applyFilesFromResponse(responseFiles) {
|
|
618
|
+
const newFiles = [];
|
|
619
|
+
for (const { path, field } of FILE_MAP) {
|
|
620
|
+
const content = responseFiles[field] ?? responseFiles[path];
|
|
621
|
+
if (content) {
|
|
622
|
+
newFiles.push({ path, content });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (newFiles.length > 0) {
|
|
626
|
+
setOverrideFiles(newFiles);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
async function handleGenerate() {
|
|
630
|
+
if (!onGenerateSoul) return;
|
|
631
|
+
setGenerating(true);
|
|
632
|
+
setError("");
|
|
633
|
+
try {
|
|
634
|
+
const data = await onGenerateSoul();
|
|
635
|
+
applyFilesFromResponse(data.files);
|
|
636
|
+
} catch (err) {
|
|
637
|
+
setError(err instanceof Error ? err.message : "Failed to generate");
|
|
638
|
+
} finally {
|
|
639
|
+
setGenerating(false);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function handleImported(responseFiles) {
|
|
643
|
+
applyFilesFromResponse(responseFiles);
|
|
644
|
+
}
|
|
645
|
+
async function handleExport() {
|
|
646
|
+
if (!onExportSoul) return;
|
|
647
|
+
setError("");
|
|
648
|
+
try {
|
|
649
|
+
const data = await onExportSoul();
|
|
650
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
651
|
+
type: "application/json"
|
|
652
|
+
});
|
|
653
|
+
const url = URL.createObjectURL(blob);
|
|
654
|
+
const a = document.createElement("a");
|
|
655
|
+
a.href = url;
|
|
656
|
+
a.download = `${data.name || "soulspec"}.json`;
|
|
657
|
+
a.click();
|
|
658
|
+
URL.revokeObjectURL(url);
|
|
659
|
+
} catch (err) {
|
|
660
|
+
setError(err instanceof Error ? err.message : "Failed to export");
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
async function handlePublish() {
|
|
664
|
+
if (!onPublishSoul) return;
|
|
665
|
+
const owner = prompt("Enter owner name for publishing:");
|
|
666
|
+
if (!owner?.trim()) return;
|
|
667
|
+
setPublishing(true);
|
|
668
|
+
setError("");
|
|
669
|
+
try {
|
|
670
|
+
await onPublishSoul(owner.trim());
|
|
671
|
+
} catch (err) {
|
|
672
|
+
setError(err instanceof Error ? err.message : "Failed to publish");
|
|
673
|
+
} finally {
|
|
674
|
+
setPublishing(false);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
const warnings = [];
|
|
678
|
+
const hasSoul = editorFiles.some(
|
|
679
|
+
(f) => f.path === "SOUL.md" && f.content.trim().length > 0
|
|
680
|
+
);
|
|
681
|
+
const hasIdentity = editorFiles.some(
|
|
682
|
+
(f) => f.path === "IDENTITY.md" && f.content.trim().length > 0
|
|
683
|
+
);
|
|
684
|
+
if (!hasSoul) warnings.push("SOUL.md is empty -- this is the core identity file");
|
|
685
|
+
if (!hasIdentity)
|
|
686
|
+
warnings.push("IDENTITY.md is empty -- consider adding behavioral traits");
|
|
687
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
688
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
689
|
+
onGenerateSoul && /* @__PURE__ */ jsxRuntime.jsx(
|
|
690
|
+
chunkVBGYWQUF_cjs.Button,
|
|
691
|
+
{
|
|
692
|
+
variant: "outline",
|
|
693
|
+
size: "sm",
|
|
694
|
+
onClick: handleGenerate,
|
|
695
|
+
disabled: generating,
|
|
696
|
+
children: generating ? "Generating..." : "Generate Soul"
|
|
697
|
+
}
|
|
698
|
+
),
|
|
699
|
+
onImportSoul && /* @__PURE__ */ jsxRuntime.jsx(
|
|
700
|
+
chunkVBGYWQUF_cjs.Button,
|
|
701
|
+
{
|
|
702
|
+
variant: "outline",
|
|
703
|
+
size: "sm",
|
|
704
|
+
onClick: () => setImportOpen(true),
|
|
705
|
+
children: "Import"
|
|
706
|
+
}
|
|
707
|
+
),
|
|
708
|
+
onExportSoul && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Button, { variant: "outline", size: "sm", onClick: handleExport, children: "Export" }),
|
|
709
|
+
onPublishSoul && /* @__PURE__ */ jsxRuntime.jsx(
|
|
710
|
+
chunkVBGYWQUF_cjs.Button,
|
|
711
|
+
{
|
|
712
|
+
variant: "outline",
|
|
713
|
+
size: "sm",
|
|
714
|
+
onClick: handlePublish,
|
|
715
|
+
disabled: publishing,
|
|
716
|
+
children: publishing ? "Publishing..." : "Publish"
|
|
717
|
+
}
|
|
718
|
+
),
|
|
719
|
+
overrideFiles && /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Badge, { variant: "destructive", className: "text-xs", children: "Unsaved generated content" })
|
|
720
|
+
] }),
|
|
721
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: error }),
|
|
722
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-muted-foreground/25 p-5", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
723
|
+
FileTreeEditor2,
|
|
724
|
+
{
|
|
725
|
+
initialFiles: editorFiles,
|
|
726
|
+
onSave: handleSave,
|
|
727
|
+
title: "SoulSpec",
|
|
728
|
+
saveLabel: saving ? "Saving..." : "Save Identity",
|
|
729
|
+
addFolderLabel: "Folder",
|
|
730
|
+
newFileTemplate: {
|
|
731
|
+
filename: "CUSTOM.md",
|
|
732
|
+
content: "# Custom\n\nAdd custom identity content...\n"
|
|
733
|
+
},
|
|
734
|
+
savedVersion
|
|
735
|
+
}
|
|
736
|
+
) }),
|
|
737
|
+
warnings.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border border-amber-600/30 bg-amber-950/20 p-3", children: [
|
|
738
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-amber-500 mb-1", children: "Validation Warnings" }),
|
|
739
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "text-xs text-amber-400/80 space-y-0.5", children: warnings.map((w) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
740
|
+
"- ",
|
|
741
|
+
w
|
|
742
|
+
] }, w)) })
|
|
743
|
+
] }),
|
|
744
|
+
onImportSoul && /* @__PURE__ */ jsxRuntime.jsx(
|
|
745
|
+
ImportSoulDialog,
|
|
746
|
+
{
|
|
747
|
+
open: importOpen,
|
|
748
|
+
onOpenChange: setImportOpen,
|
|
749
|
+
onImport: onImportSoul,
|
|
750
|
+
onImported: handleImported
|
|
751
|
+
}
|
|
752
|
+
)
|
|
753
|
+
] });
|
|
754
|
+
}
|
|
755
|
+
function ImportSoulDialog({
|
|
756
|
+
open,
|
|
757
|
+
onOpenChange,
|
|
758
|
+
onImport,
|
|
759
|
+
onImported
|
|
760
|
+
}) {
|
|
761
|
+
const [ref, setRef] = react.useState("");
|
|
762
|
+
const [loading, setLoading] = react.useState(false);
|
|
763
|
+
const [error, setError] = react.useState("");
|
|
764
|
+
async function handleImport() {
|
|
765
|
+
if (!ref.trim()) return;
|
|
766
|
+
setLoading(true);
|
|
767
|
+
setError("");
|
|
768
|
+
try {
|
|
769
|
+
const data = await onImport(ref.trim());
|
|
770
|
+
onImported(data.files);
|
|
771
|
+
onOpenChange(false);
|
|
772
|
+
setRef("");
|
|
773
|
+
} catch (err) {
|
|
774
|
+
setError(err instanceof Error ? err.message : "Failed to import");
|
|
775
|
+
} finally {
|
|
776
|
+
setLoading(false);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.DialogContent, { className: "max-w-md", children: [
|
|
780
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.DialogHeader, { children: [
|
|
781
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.DialogTitle, { children: "Import SoulSpec" }),
|
|
782
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.DialogDescription, { children: "Import a SoulSpec from the ClawSouls registry." })
|
|
783
|
+
] }),
|
|
784
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.DialogBody, { children: [
|
|
785
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive mb-3", children: error }),
|
|
786
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkVBGYWQUF_cjs.FormField, { label: "Registry Reference", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
787
|
+
chunkVBGYWQUF_cjs.Input,
|
|
788
|
+
{
|
|
789
|
+
value: ref,
|
|
790
|
+
onChange: (e) => setRef(e.target.value),
|
|
791
|
+
placeholder: "owner/name (e.g. clawsouls/surgical-coder)",
|
|
792
|
+
onKeyDown: (e) => e.key === "Enter" && handleImport(),
|
|
793
|
+
autoFocus: true
|
|
794
|
+
}
|
|
795
|
+
) })
|
|
796
|
+
] }),
|
|
797
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunkVBGYWQUF_cjs.DialogFooter, { children: [
|
|
798
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
799
|
+
chunkVBGYWQUF_cjs.Button,
|
|
800
|
+
{
|
|
801
|
+
variant: "outline",
|
|
802
|
+
size: "sm",
|
|
803
|
+
onClick: () => onOpenChange(false),
|
|
804
|
+
disabled: loading,
|
|
805
|
+
children: "Cancel"
|
|
806
|
+
}
|
|
807
|
+
),
|
|
808
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
809
|
+
chunkVBGYWQUF_cjs.Button,
|
|
810
|
+
{
|
|
811
|
+
size: "sm",
|
|
812
|
+
onClick: handleImport,
|
|
813
|
+
disabled: loading || !ref.trim(),
|
|
814
|
+
children: loading ? "Importing..." : "Import"
|
|
815
|
+
}
|
|
816
|
+
)
|
|
817
|
+
] })
|
|
818
|
+
] }) });
|
|
819
|
+
}
|
|
551
820
|
|
|
821
|
+
exports.AgentIdentityTab = AgentIdentityTab;
|
|
552
822
|
exports.FileTreeEditor = FileTreeEditor;
|
|
553
823
|
exports.PluginEditorPage = PluginEditorPage;
|
package/dist/editor.d.cts
CHANGED
|
@@ -28,4 +28,53 @@ interface PluginEditorPageProps {
|
|
|
28
28
|
}
|
|
29
29
|
declare function PluginEditorPage({ marketplaceId, pluginName }: PluginEditorPageProps): react_jsx_runtime.JSX.Element;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface Agent {
|
|
32
|
+
id: string;
|
|
33
|
+
soul_md: string | null;
|
|
34
|
+
identity_md: string | null;
|
|
35
|
+
style_md: string | null;
|
|
36
|
+
agents_md: string | null;
|
|
37
|
+
heartbeat_md: string | null;
|
|
38
|
+
user_template_md: string | null;
|
|
39
|
+
examples_good_md: string | null;
|
|
40
|
+
examples_bad_md: string | null;
|
|
41
|
+
}
|
|
42
|
+
interface AgentIdentityTabProps {
|
|
43
|
+
agent: Agent;
|
|
44
|
+
/**
|
|
45
|
+
* The FileTreeEditor component from the /editor entry point.
|
|
46
|
+
* Pass it as a prop to keep CodeMirror out of the core bundle.
|
|
47
|
+
*/
|
|
48
|
+
FileTreeEditor: React.ComponentType<{
|
|
49
|
+
initialFiles: FlatFile[];
|
|
50
|
+
onSave: (files: FlatFile[]) => Promise<void>;
|
|
51
|
+
title?: string;
|
|
52
|
+
saveLabel?: string;
|
|
53
|
+
addFolderLabel?: string;
|
|
54
|
+
newFileTemplate?: {
|
|
55
|
+
filename: string;
|
|
56
|
+
content: string;
|
|
57
|
+
};
|
|
58
|
+
savedVersion?: number;
|
|
59
|
+
}>;
|
|
60
|
+
/** Called after a successful save so the host can refresh data. */
|
|
61
|
+
onSaved?: () => void;
|
|
62
|
+
/** Generate a SoulSpec for this agent. Returns a map of field-name/path to content. */
|
|
63
|
+
onGenerateSoul?: () => Promise<{
|
|
64
|
+
files: Record<string, string>;
|
|
65
|
+
}>;
|
|
66
|
+
/** Import a SoulSpec from the ClawSouls registry. */
|
|
67
|
+
onImportSoul?: (ref: string) => Promise<{
|
|
68
|
+
files: Record<string, string>;
|
|
69
|
+
}>;
|
|
70
|
+
/** Export the current SoulSpec as JSON. Returns file map + agent name. */
|
|
71
|
+
onExportSoul?: () => Promise<{
|
|
72
|
+
files: Record<string, string>;
|
|
73
|
+
name: string;
|
|
74
|
+
}>;
|
|
75
|
+
/** Publish the SoulSpec to the ClawSouls registry. */
|
|
76
|
+
onPublishSoul?: (owner: string) => Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
declare function AgentIdentityTab({ agent, FileTreeEditor, onSaved, onGenerateSoul, onImportSoul, onExportSoul, onPublishSoul, }: AgentIdentityTabProps): react_jsx_runtime.JSX.Element;
|
|
79
|
+
|
|
80
|
+
export { AgentIdentityTab, type AgentIdentityTabProps, FileTreeEditor, type FileTreeEditorProps, type FlatFile, PluginEditorPage, type PluginEditorPageProps };
|