camox 0.63.0 → 0.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/createApp.d.ts +28 -28
- package/dist/core/createLayout.d.ts +1 -1
- package/dist/core/derivedRoutes.js +3 -30
- package/dist/core/editing/createEditableBlock.d.ts +604 -604
- package/dist/features/canvas/canvasCamera.js +11 -2
- package/dist/features/canvas/useCanvasCamera.js +14 -10
- package/dist/features/page/CuratedPageContent.js +2 -1
- package/dist/features/page/UnplacedBlockContent.js +52 -0
- package/dist/features/preview/components/PreviewPanel.js +40 -12
- package/dist/features/preview/components/SidebarStack.js +78 -9
- package/dist/features/preview/strayCaretGuard.js +34 -0
- package/dist/features/provider/CoreCamoxProvider.js +5 -3
- package/dist/features/routes/pageRuntime.d.ts +2 -0
- package/dist/features/routes/pageRuntime.js +8 -5
- package/dist/features/runtime/pageApp.js +111 -74
- package/dist/features/runtime/pageClient.js +22 -2
- package/dist/features/runtime/runtime.d.ts +10 -0
- package/dist/features/runtime/runtime.js +314 -4
- package/dist/features/runtime/runtimeRoutes.d.ts +5 -0
- package/dist/features/runtime/runtimeRoutes.js +5 -0
- package/dist/features/studio/components/ChatWidget.js +88 -62
- package/dist/features/studio/components/ConnectAgent.js +313 -0
- package/dist/features/studio/components/Patrol.js +455 -205
- package/dist/features/studio/components/ReviewDraftSheet.js +431 -334
- package/dist/features/studio/components/Squareling.js +74 -41
- package/dist/features/studio/components/ThreadComposer.js +130 -107
- package/dist/features/studio/components/ThreadMessages.js +82 -13
- package/dist/features/studio/components/clientLogoPaths.js +10 -0
- package/dist/features/studio/findingSentence.js +37 -0
- package/dist/features/studio/reportSentence.js +15 -0
- package/dist/features/studio/studioStore.js +23 -1
- package/dist/features/studio/workingSentence.js +8 -0
- package/dist/lib/api-client.d.ts +1 -0
- package/dist/lib/auth.js +34 -32
- package/dist/lib/queries.js +9 -1
- package/dist/lib/server-auth-cookie.js +17 -4
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -1
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +15 -4
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { AuthContext } from "../../../lib/auth.js";
|
|
2
|
+
import { CLIENT_LOGO_PATHS } from "./clientLogoPaths.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Button } from "@camox/ui/button";
|
|
7
|
+
import { Check, Copy, ExternalLink } from "lucide-react";
|
|
8
|
+
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@camox/ui/dialog";
|
|
9
|
+
import { Avatar, AvatarFallback, AvatarGroup } from "@camox/ui/avatar";
|
|
10
|
+
|
|
11
|
+
//#region src/features/studio/components/ConnectAgent.tsx
|
|
12
|
+
/**
|
|
13
|
+
* Common AI apps that take a remote MCP server, with their guide to adding one. In the logo row
|
|
14
|
+
* each one overlaps the one before it, so the last is on top.
|
|
15
|
+
*/
|
|
16
|
+
const CLIENTS = [
|
|
17
|
+
{
|
|
18
|
+
name: "GitHub Copilot",
|
|
19
|
+
Logo: pathLogo(CLIENT_LOGO_PATHS.copilot),
|
|
20
|
+
docs: "https://code.visualstudio.com/docs/agent-customization/mcp-servers"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "Grok Bot",
|
|
24
|
+
Logo: GrokBotLogo,
|
|
25
|
+
docs: "https://composio.dev/blog/how-to-add-mcp-servers-to-grok-bot"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "ChatGPT",
|
|
29
|
+
Logo: pathLogo(CLIENT_LOGO_PATHS.chatgpt),
|
|
30
|
+
docs: "https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt-beta"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "Claude",
|
|
34
|
+
Logo: pathLogo(CLIENT_LOGO_PATHS.claude, "#D97757"),
|
|
35
|
+
docs: "https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp"
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
/** A logo drawn as one path on a 24×24 box, in the brand's color or the text's. */
|
|
39
|
+
function pathLogo(d, color = "currentColor") {
|
|
40
|
+
return function PathLogo({ className }) {
|
|
41
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
42
|
+
viewBox: "0 0 24 24",
|
|
43
|
+
"aria-hidden": true,
|
|
44
|
+
className,
|
|
45
|
+
fill: color,
|
|
46
|
+
children: /* @__PURE__ */ jsx("path", { d })
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Grok Bot's mark, drawn after its app icon: a rounded blob with two slanted eyes cut out. */
|
|
51
|
+
function GrokBotLogo(t0) {
|
|
52
|
+
const $ = c(11);
|
|
53
|
+
const { className } = t0;
|
|
54
|
+
const mask = React.useId();
|
|
55
|
+
let t1;
|
|
56
|
+
let t2;
|
|
57
|
+
let t3;
|
|
58
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
59
|
+
t1 = /* @__PURE__ */ jsx("path", {
|
|
60
|
+
fill: "white",
|
|
61
|
+
d: "M0.5 9.5C5 5.5 12 3.2 17.5 4c4 .6 6 4 6 8.5V19c0 2.5-2 4.5-4.5 4.5H5C2.5 23.5.5 21.5.5 19Z"
|
|
62
|
+
});
|
|
63
|
+
t2 = /* @__PURE__ */ jsx("ellipse", {
|
|
64
|
+
fill: "black",
|
|
65
|
+
cx: "11",
|
|
66
|
+
cy: "14",
|
|
67
|
+
rx: "1.7",
|
|
68
|
+
ry: "3.6",
|
|
69
|
+
transform: "rotate(-35 11 14)"
|
|
70
|
+
});
|
|
71
|
+
t3 = /* @__PURE__ */ jsx("ellipse", {
|
|
72
|
+
fill: "black",
|
|
73
|
+
cx: "17.6",
|
|
74
|
+
cy: "10.4",
|
|
75
|
+
rx: "1.6",
|
|
76
|
+
ry: "3.3",
|
|
77
|
+
transform: "rotate(-35 17.6 10.4)"
|
|
78
|
+
});
|
|
79
|
+
$[0] = t1;
|
|
80
|
+
$[1] = t2;
|
|
81
|
+
$[2] = t3;
|
|
82
|
+
} else {
|
|
83
|
+
t1 = $[0];
|
|
84
|
+
t2 = $[1];
|
|
85
|
+
t3 = $[2];
|
|
86
|
+
}
|
|
87
|
+
let t4;
|
|
88
|
+
if ($[3] !== mask) {
|
|
89
|
+
t4 = /* @__PURE__ */ jsxs("mask", {
|
|
90
|
+
id: mask,
|
|
91
|
+
children: [
|
|
92
|
+
t1,
|
|
93
|
+
t2,
|
|
94
|
+
t3
|
|
95
|
+
]
|
|
96
|
+
});
|
|
97
|
+
$[3] = mask;
|
|
98
|
+
$[4] = t4;
|
|
99
|
+
} else t4 = $[4];
|
|
100
|
+
const t5 = `url(#${mask})`;
|
|
101
|
+
let t6;
|
|
102
|
+
if ($[5] !== t5) {
|
|
103
|
+
t6 = /* @__PURE__ */ jsx("rect", {
|
|
104
|
+
width: "24",
|
|
105
|
+
height: "24",
|
|
106
|
+
mask: t5
|
|
107
|
+
});
|
|
108
|
+
$[5] = t5;
|
|
109
|
+
$[6] = t6;
|
|
110
|
+
} else t6 = $[6];
|
|
111
|
+
let t7;
|
|
112
|
+
if ($[7] !== className || $[8] !== t4 || $[9] !== t6) {
|
|
113
|
+
t7 = /* @__PURE__ */ jsxs("svg", {
|
|
114
|
+
viewBox: "0 0 24 24",
|
|
115
|
+
"aria-hidden": true,
|
|
116
|
+
className,
|
|
117
|
+
fill: "currentColor",
|
|
118
|
+
children: [t4, t6]
|
|
119
|
+
});
|
|
120
|
+
$[7] = className;
|
|
121
|
+
$[8] = t4;
|
|
122
|
+
$[9] = t6;
|
|
123
|
+
$[10] = t7;
|
|
124
|
+
} else t7 = $[10];
|
|
125
|
+
return t7;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Under the Chat widget's composer, what invites a member to connect their own AI to Camox as a
|
|
129
|
+
* Connected Agent (ADR 0030): the logos of common AI apps, opening a dialog with the link to
|
|
130
|
+
* Camox's MCP server and each app's guide to adding an MCP server.
|
|
131
|
+
*/
|
|
132
|
+
function ConnectAgent() {
|
|
133
|
+
const $ = c(5);
|
|
134
|
+
const [open, setOpen] = React.useState(false);
|
|
135
|
+
let t0;
|
|
136
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
137
|
+
t0 = () => setOpen(true);
|
|
138
|
+
$[0] = t0;
|
|
139
|
+
} else t0 = $[0];
|
|
140
|
+
let t1;
|
|
141
|
+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
142
|
+
t1 = /* @__PURE__ */ jsxs("button", {
|
|
143
|
+
type: "button",
|
|
144
|
+
onClick: t0,
|
|
145
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground mx-2 mb-2 flex items-center gap-2.5 rounded-md px-2 py-1.5 text-sm transition-colors",
|
|
146
|
+
children: [/* @__PURE__ */ jsx(AvatarGroup, { children: CLIENTS.map(_temp) }), "Connect your AI"]
|
|
147
|
+
});
|
|
148
|
+
$[1] = t1;
|
|
149
|
+
} else t1 = $[1];
|
|
150
|
+
let t2;
|
|
151
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
152
|
+
t2 = /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx(ConnectAgentContent, {}) });
|
|
153
|
+
$[2] = t2;
|
|
154
|
+
} else t2 = $[2];
|
|
155
|
+
let t3;
|
|
156
|
+
if ($[3] !== open) {
|
|
157
|
+
t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, /* @__PURE__ */ jsx(Dialog, {
|
|
158
|
+
open,
|
|
159
|
+
onOpenChange: setOpen,
|
|
160
|
+
children: t2
|
|
161
|
+
})] });
|
|
162
|
+
$[3] = open;
|
|
163
|
+
$[4] = t3;
|
|
164
|
+
} else t3 = $[4];
|
|
165
|
+
return t3;
|
|
166
|
+
}
|
|
167
|
+
function _temp(client) {
|
|
168
|
+
return /* @__PURE__ */ jsx(Avatar, {
|
|
169
|
+
size: "sm",
|
|
170
|
+
children: /* @__PURE__ */ jsx(AvatarFallback, {
|
|
171
|
+
className: "bg-background text-foreground",
|
|
172
|
+
children: /* @__PURE__ */ jsx(client.Logo, { className: "size-3.5" })
|
|
173
|
+
})
|
|
174
|
+
}, client.name);
|
|
175
|
+
}
|
|
176
|
+
function ConnectAgentContent() {
|
|
177
|
+
const $ = c(23);
|
|
178
|
+
const { apiUrl } = React.useContext(AuthContext);
|
|
179
|
+
const url = `${apiUrl}/mcp`;
|
|
180
|
+
const [copied, setCopied] = React.useState(false);
|
|
181
|
+
let t0;
|
|
182
|
+
let t1;
|
|
183
|
+
if ($[0] !== copied) {
|
|
184
|
+
t0 = () => {
|
|
185
|
+
if (!copied) return;
|
|
186
|
+
const timeout = setTimeout(() => setCopied(false), 2e3);
|
|
187
|
+
return () => clearTimeout(timeout);
|
|
188
|
+
};
|
|
189
|
+
t1 = [copied];
|
|
190
|
+
$[0] = copied;
|
|
191
|
+
$[1] = t0;
|
|
192
|
+
$[2] = t1;
|
|
193
|
+
} else {
|
|
194
|
+
t0 = $[1];
|
|
195
|
+
t1 = $[2];
|
|
196
|
+
}
|
|
197
|
+
React.useEffect(t0, t1);
|
|
198
|
+
let t2;
|
|
199
|
+
if ($[3] !== url) {
|
|
200
|
+
t2 = async () => {
|
|
201
|
+
await navigator.clipboard.writeText(url);
|
|
202
|
+
setCopied(true);
|
|
203
|
+
};
|
|
204
|
+
$[3] = url;
|
|
205
|
+
$[4] = t2;
|
|
206
|
+
} else t2 = $[4];
|
|
207
|
+
const copy = t2;
|
|
208
|
+
let t3;
|
|
209
|
+
if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
|
|
210
|
+
t3 = /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Connect your AI to Camox's MCP server" }), /* @__PURE__ */ jsx(DialogDescription, { children: "Add this URL to your AI as a remote MCP server, then sign in to Camox. Your AI can then ask Camox's agent for changes, with what it knows about your business." })] });
|
|
211
|
+
$[5] = t3;
|
|
212
|
+
} else t3 = $[5];
|
|
213
|
+
let t4;
|
|
214
|
+
if ($[6] !== copy || $[7] !== url) {
|
|
215
|
+
t4 = /* @__PURE__ */ jsx("button", {
|
|
216
|
+
type: "button",
|
|
217
|
+
onClick: copy,
|
|
218
|
+
className: "bg-muted hover:bg-muted/70 truncate rounded-lg border px-3 py-3 text-left font-mono text-sm transition-colors",
|
|
219
|
+
children: url
|
|
220
|
+
});
|
|
221
|
+
$[6] = copy;
|
|
222
|
+
$[7] = url;
|
|
223
|
+
$[8] = t4;
|
|
224
|
+
} else t4 = $[8];
|
|
225
|
+
let t5;
|
|
226
|
+
if ($[9] !== copied) {
|
|
227
|
+
t5 = copied ? /* @__PURE__ */ jsx(Check, { "data-icon": "inline-start" }) : /* @__PURE__ */ jsx(Copy, { "data-icon": "inline-start" });
|
|
228
|
+
$[9] = copied;
|
|
229
|
+
$[10] = t5;
|
|
230
|
+
} else t5 = $[10];
|
|
231
|
+
const t6 = copied ? "Copied" : "Copy MCP URL";
|
|
232
|
+
let t7;
|
|
233
|
+
if ($[11] !== copy || $[12] !== t5 || $[13] !== t6) {
|
|
234
|
+
t7 = /* @__PURE__ */ jsxs(Button, {
|
|
235
|
+
size: "lg",
|
|
236
|
+
onClick: copy,
|
|
237
|
+
children: [t5, t6]
|
|
238
|
+
});
|
|
239
|
+
$[11] = copy;
|
|
240
|
+
$[12] = t5;
|
|
241
|
+
$[13] = t6;
|
|
242
|
+
$[14] = t7;
|
|
243
|
+
} else t7 = $[14];
|
|
244
|
+
let t8;
|
|
245
|
+
if ($[15] !== t4 || $[16] !== t7) {
|
|
246
|
+
t8 = /* @__PURE__ */ jsxs("div", {
|
|
247
|
+
className: "flex flex-col gap-2",
|
|
248
|
+
children: [t4, t7]
|
|
249
|
+
});
|
|
250
|
+
$[15] = t4;
|
|
251
|
+
$[16] = t7;
|
|
252
|
+
$[17] = t8;
|
|
253
|
+
} else t8 = $[17];
|
|
254
|
+
let t9;
|
|
255
|
+
if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
|
|
256
|
+
t9 = /* @__PURE__ */ jsx("p", {
|
|
257
|
+
className: "text-muted-foreground text-xs font-medium",
|
|
258
|
+
children: "How to add an MCP server in"
|
|
259
|
+
});
|
|
260
|
+
$[18] = t9;
|
|
261
|
+
} else t9 = $[18];
|
|
262
|
+
let t10;
|
|
263
|
+
let t11;
|
|
264
|
+
if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
|
|
265
|
+
t10 = /* @__PURE__ */ jsxs("div", {
|
|
266
|
+
className: "flex flex-col gap-2",
|
|
267
|
+
children: [t9, /* @__PURE__ */ jsx("ul", {
|
|
268
|
+
className: "grid grid-cols-2 gap-1",
|
|
269
|
+
children: CLIENTS.map(_temp2)
|
|
270
|
+
})]
|
|
271
|
+
});
|
|
272
|
+
t11 = /* @__PURE__ */ jsx("p", {
|
|
273
|
+
className: "text-muted-foreground text-xs",
|
|
274
|
+
children: "It acts as you, with your permissions. It can't publish: you review and publish here."
|
|
275
|
+
});
|
|
276
|
+
$[19] = t10;
|
|
277
|
+
$[20] = t11;
|
|
278
|
+
} else {
|
|
279
|
+
t10 = $[19];
|
|
280
|
+
t11 = $[20];
|
|
281
|
+
}
|
|
282
|
+
let t12;
|
|
283
|
+
if ($[21] !== t8) {
|
|
284
|
+
t12 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
|
+
t3,
|
|
286
|
+
t8,
|
|
287
|
+
t10,
|
|
288
|
+
t11
|
|
289
|
+
] });
|
|
290
|
+
$[21] = t8;
|
|
291
|
+
$[22] = t12;
|
|
292
|
+
} else t12 = $[22];
|
|
293
|
+
return t12;
|
|
294
|
+
}
|
|
295
|
+
function _temp2(client) {
|
|
296
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
|
|
297
|
+
href: client.docs,
|
|
298
|
+
target: "_blank",
|
|
299
|
+
rel: "noreferrer",
|
|
300
|
+
className: "hover:bg-muted flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors",
|
|
301
|
+
children: [
|
|
302
|
+
/* @__PURE__ */ jsx(client.Logo, { className: "size-4 shrink-0" }),
|
|
303
|
+
/* @__PURE__ */ jsx("span", {
|
|
304
|
+
className: "flex-1 truncate",
|
|
305
|
+
children: client.name
|
|
306
|
+
}),
|
|
307
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "text-muted-foreground size-3.5 shrink-0" })
|
|
308
|
+
]
|
|
309
|
+
}) }, client.name);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
//#endregion
|
|
313
|
+
export { ConnectAgent };
|