camox 0.53.1 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/features/canvas/CamoxCanvas.js +14 -11
  2. package/dist/features/canvas/CanvasLoadingScreen.js +1 -1
  3. package/dist/features/canvas/sidebar/CanvasViewHeader.js +1 -1
  4. package/dist/features/canvas/sidebar/{CanvasSidebar.js → ContentSidebar.js} +5 -5
  5. package/dist/features/canvas/sidebar/{CanvasSidebarFrame.js → ContentSidebarFrame.js} +4 -4
  6. package/dist/features/canvas/sidebar/{CanvasSidebarSkeleton.js → ContentSidebarSkeleton.js} +7 -7
  7. package/dist/features/og/documentFonts.js +49 -0
  8. package/dist/features/og/imageResponse.d.ts +14 -5
  9. package/dist/features/og/imageResponse.js +20 -21
  10. package/dist/features/og/pageImage.js +7 -4
  11. package/dist/features/preview/CamoxPreview.js +2 -2
  12. package/dist/features/preview/components/BlockActionsPopover.js +1 -1
  13. package/dist/features/preview/components/IconFieldEditor.js +1 -1
  14. package/dist/features/preview/components/LinkFieldEditor.js +1 -1
  15. package/dist/features/preview/components/PagePicker.js +1 -1
  16. package/dist/features/preview/components/PreviewToolbar.js +1 -1
  17. package/dist/features/preview/components/SelectionEditor.js +136 -110
  18. package/dist/features/preview/components/SidebarStack.js +110 -83
  19. package/dist/features/preview/components/StudioEditingFallback.js +3 -3
  20. package/dist/features/routes/pageRuntime.d.ts +1 -1
  21. package/dist/features/runtime/RuntimeChrome.js +4 -4
  22. package/dist/features/runtime/runtime.d.ts +5 -0
  23. package/dist/features/runtime/runtime.js +15 -4
  24. package/dist/features/studio/components/AgentSidebar.js +56 -0
  25. package/dist/features/studio/components/ChatWidget.js +237 -0
  26. package/dist/features/studio/components/DraftsControl.js +17 -17
  27. package/dist/features/studio/components/ReviewDraftSheet.js +38 -38
  28. package/dist/features/studio/components/Squareling.js +116 -0
  29. package/dist/features/studio/components/ThreadMessages.js +190 -165
  30. package/dist/features/studio/components/WorkersWidget.js +52 -0
  31. package/dist/features/studio/studioStore.js +5 -5
  32. package/dist/features/vite/bundlerLogs.js +1 -0
  33. package/dist/features/vite/runtimeDev.js +11 -0
  34. package/dist/features/vite/vite.js +3 -1
  35. package/dist/lib/queries.js +1 -1
  36. package/dist/package.js +1 -1
  37. package/dist/studio.css +1 -1
  38. package/package.json +5 -5
  39. package/skills/camox/SKILL.md +3 -10
  40. package/skills/camox/references/artifacts.md +2 -2
  41. package/skills/camox/references/block-definitions.md +1 -1
  42. package/skills/camox/references/layout-definitions.md +12 -17
  43. package/skills/camox/references/routed-layouts.md +2 -2
  44. package/skills/camox-cli/SKILL.md +15 -0
  45. package/skills/{camox → camox-cli}/references/cli-common.md +1 -1
  46. package/skills/{camox → camox-cli}/references/cli-content.md +2 -2
  47. package/skills/{camox → camox-cli}/references/cli-publishing.md +4 -4
  48. package/skills/camox-expand/SKILL.md +1 -1
  49. package/skills/camoxify/SKILL.md +1 -1
  50. package/dist/features/og/defaultFonts.js +0 -31
  51. package/dist/features/og/geist-variable-ttf-base64.js +0 -21
  52. package/dist/features/studio/components/ChatSidebar.js +0 -364
@@ -0,0 +1,116 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+
5
+ //#region src/features/studio/components/Squareling.tsx
6
+ /**
7
+ * Camox's agent, drawn from the logo's shapes: its square, the soft corner, and the knockout as
8
+ * eyes, looking right like the mark. Its face and motion say what the agent is doing. The
9
+ * animations live in `studio.css`.
10
+ */
11
+ function Squareling(t0) {
12
+ const $ = c(18);
13
+ const { status, className, ref } = t0;
14
+ let t1;
15
+ if ($[0] !== className) {
16
+ t1 = cn("squareling shrink-0 overflow-visible", className);
17
+ $[0] = className;
18
+ $[1] = t1;
19
+ } else t1 = $[1];
20
+ let t2;
21
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
22
+ t2 = /* @__PURE__ */ jsx("path", {
23
+ d: "M20 12H80Q88 12 88 20V64Q88 88 64 88H20Q12 88 12 80V20Q12 12 20 12Z",
24
+ className: "fill-emerald-500"
25
+ });
26
+ $[2] = t2;
27
+ } else t2 = $[2];
28
+ let t3;
29
+ if ($[3] !== status) {
30
+ t3 = (status === "idle" || status === "thinking") && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
31
+ className: "squareling-eye",
32
+ x: "50",
33
+ y: "36",
34
+ width: "11",
35
+ height: "17"
36
+ }), /* @__PURE__ */ jsx("rect", {
37
+ className: "squareling-eye",
38
+ x: "69",
39
+ y: "36",
40
+ width: "11",
41
+ height: "17"
42
+ })] });
43
+ $[3] = status;
44
+ $[4] = t3;
45
+ } else t3 = $[4];
46
+ let t4;
47
+ if ($[5] !== status) {
48
+ t4 = status === "acting" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
49
+ x: "50",
50
+ y: "44",
51
+ width: "11",
52
+ height: "6"
53
+ }), /* @__PURE__ */ jsx("rect", {
54
+ x: "69",
55
+ y: "44",
56
+ width: "11",
57
+ height: "6"
58
+ })] });
59
+ $[5] = status;
60
+ $[6] = t4;
61
+ } else t4 = $[6];
62
+ let t5;
63
+ if ($[7] !== status) {
64
+ t5 = status === "fixing" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
65
+ x: "50",
66
+ y: "36",
67
+ width: "11",
68
+ height: "17"
69
+ }), /* @__PURE__ */ jsx("rect", {
70
+ x: "69",
71
+ y: "44",
72
+ width: "11",
73
+ height: "6"
74
+ })] });
75
+ $[7] = status;
76
+ $[8] = t5;
77
+ } else t5 = $[8];
78
+ let t6;
79
+ if ($[9] !== t3 || $[10] !== t4 || $[11] !== t5) {
80
+ t6 = /* @__PURE__ */ jsxs("g", {
81
+ className: "squareling-body",
82
+ children: [t2, /* @__PURE__ */ jsxs("g", {
83
+ className: "squareling-eyes fill-neutral-950",
84
+ children: [
85
+ t3,
86
+ t4,
87
+ t5
88
+ ]
89
+ })]
90
+ });
91
+ $[9] = t3;
92
+ $[10] = t4;
93
+ $[11] = t5;
94
+ $[12] = t6;
95
+ } else t6 = $[12];
96
+ let t7;
97
+ if ($[13] !== ref || $[14] !== status || $[15] !== t1 || $[16] !== t6) {
98
+ t7 = /* @__PURE__ */ jsx("svg", {
99
+ ref,
100
+ viewBox: "0 0 100 100",
101
+ "aria-hidden": true,
102
+ "data-squareling": status,
103
+ className: t1,
104
+ children: t6
105
+ });
106
+ $[13] = ref;
107
+ $[14] = status;
108
+ $[15] = t1;
109
+ $[16] = t6;
110
+ $[17] = t7;
111
+ } else t7 = $[17];
112
+ return t7;
113
+ }
114
+
115
+ //#endregion
116
+ export { Squareling };
@@ -1,5 +1,7 @@
1
+ import { Squareling } from "./Squareling.js";
1
2
  import { ThreadMarkdown } from "./ThreadMarkdown.js";
2
3
  import { c } from "react/compiler-runtime";
4
+ import * as React from "react";
3
5
  import { jsx, jsxs } from "react/jsx-runtime";
4
6
  import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
5
7
  import { Bubble, BubbleContent } from "@camox/ui/bubble";
@@ -8,143 +10,208 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
8
10
 
9
11
  //#region src/features/studio/components/ThreadMessages.tsx
10
12
  /**
11
- * A thread's messages, and "Working…" while a run is going or a message is still `sending`: on
12
- * its way to the thread, which hasn't accepted it yet. While the end of a turn builds the
13
- * agent's code, or the agent fixes a build error, it says so instead. A draft's thread is shared, so it shows
14
- * senders' names too (`showSenders`). A fresh Live thread links to the draft the editor's
15
- * previous one continued in (`continuedIn`).
13
+ * A thread's messages, and the agent's squareling, which always lives in it. An empty thread has
14
+ * it greet the editor; when the first message arrives, it moves to the end of the thread, and
15
+ * stays there after each message. While a run is going or a message is still `sending` (on its
16
+ * way to the thread, which hasn't accepted it yet), its face says whether the agent thinks or
17
+ * acts (uses its tools, or builds its code). While the end of a turn builds the agent's code, or
18
+ * the agent fixes a build error, it says so in words too. Each editor's message shows its
19
+ * sender's avatar, without their name.
16
20
  */
17
21
  function ThreadMessages(t0) {
18
- const $ = c(28);
19
- const { view, sending: t1, showSenders: t2, continuedIn } = t0;
22
+ const $ = c(19);
23
+ const { view, sending: t1 } = t0;
20
24
  const sending = t1 === void 0 ? false : t1;
21
- const showSenders = t2 === void 0 ? false : t2;
22
25
  const working = view.running || sending;
23
- if (view.messages.length === 0 && !working) {
26
+ const empty = view.messages.length === 0 && !working;
27
+ const squareling = useSquarelingMorph(empty);
28
+ if (empty) {
29
+ let t2;
30
+ if ($[0] !== squareling) {
31
+ t2 = /* @__PURE__ */ jsx(Squareling, {
32
+ ref: squareling,
33
+ status: "idle",
34
+ className: "size-10"
35
+ });
36
+ $[0] = squareling;
37
+ $[1] = t2;
38
+ } else t2 = $[1];
24
39
  let t3;
25
- if ($[0] !== continuedIn) {
26
- t3 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
27
- $[0] = continuedIn;
28
- $[1] = t3;
29
- } else t3 = $[1];
30
- let t4;
31
40
  if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
32
- t4 = /* @__PURE__ */ jsx("p", {
41
+ t3 = /* @__PURE__ */ jsx("p", { children: "How can I help?" });
42
+ $[2] = t3;
43
+ } else t3 = $[2];
44
+ let t4;
45
+ if ($[3] !== t2) {
46
+ t4 = /* @__PURE__ */ jsxs("div", {
33
47
  "data-thread-empty": true,
34
- className: "text-muted-foreground flex min-h-0 flex-1 items-center justify-center p-4 text-center text-sm",
35
- children: "Ask Camox about your website’s content."
48
+ className: "text-muted-foreground flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-4 text-center text-sm",
49
+ children: [t2, t3]
36
50
  });
37
- $[2] = t4;
38
- } else t4 = $[2];
39
- let t5;
40
- if ($[3] !== t3) {
41
- t5 = /* @__PURE__ */ jsxs("div", {
42
- className: "flex min-h-0 flex-1 flex-col",
43
- children: [t3, t4]
44
- });
45
- $[3] = t3;
46
- $[4] = t5;
47
- } else t5 = $[4];
48
- return t5;
51
+ $[3] = t2;
52
+ $[4] = t4;
53
+ } else t4 = $[4];
54
+ return t4;
49
55
  }
56
+ let t2;
57
+ if ($[5] !== squareling || $[6] !== view || $[7] !== working) {
58
+ t2 = view.messages.map((message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
59
+ messageId: message.id,
60
+ scrollAnchor: message.from === "editor",
61
+ className: "flex flex-col gap-4",
62
+ children: [/* @__PURE__ */ jsx(ThreadMessageRow, { message }), index === view.messages.length - 1 && /* @__PURE__ */ jsx(AgentPresence, {
63
+ view,
64
+ working,
65
+ squareling
66
+ })]
67
+ }, message.id));
68
+ $[5] = squareling;
69
+ $[6] = view;
70
+ $[7] = working;
71
+ $[8] = t2;
72
+ } else t2 = $[8];
50
73
  let t3;
51
- if ($[5] !== continuedIn) {
52
- t3 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
53
- $[5] = continuedIn;
54
- $[6] = t3;
55
- } else t3 = $[6];
74
+ if ($[9] !== squareling || $[10] !== view || $[11] !== working) {
75
+ t3 = view.messages.length === 0 && /* @__PURE__ */ jsx(AgentPresence, {
76
+ view,
77
+ working,
78
+ squareling
79
+ });
80
+ $[9] = squareling;
81
+ $[10] = view;
82
+ $[11] = working;
83
+ $[12] = t3;
84
+ } else t3 = $[12];
56
85
  let t4;
57
- if ($[7] !== showSenders || $[8] !== view.messages || $[9] !== view.status || $[10] !== working) {
58
- let t5;
59
- if ($[12] !== showSenders || $[13] !== view.messages.length || $[14] !== view.status || $[15] !== working) {
60
- t5 = (message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
61
- messageId: message.id,
62
- scrollAnchor: message.from === "editor",
63
- className: "flex flex-col gap-4",
64
- children: [/* @__PURE__ */ jsx(ThreadMessageRow, {
65
- message,
66
- showSender: showSenders
67
- }), working && index === view.messages.length - 1 && /* @__PURE__ */ jsx(Working, { status: view.status })]
68
- }, message.id);
69
- $[12] = showSenders;
70
- $[13] = view.messages.length;
71
- $[14] = view.status;
72
- $[15] = working;
73
- $[16] = t5;
74
- } else t5 = $[16];
75
- t4 = view.messages.map(t5);
76
- $[7] = showSenders;
77
- $[8] = view.messages;
78
- $[9] = view.status;
79
- $[10] = working;
80
- $[11] = t4;
81
- } else t4 = $[11];
82
- let t5;
83
- if ($[17] !== view.messages.length || $[18] !== view.status || $[19] !== working) {
84
- t5 = working && view.messages.length === 0 && /* @__PURE__ */ jsx(Working, { status: view.status });
85
- $[17] = view.messages.length;
86
- $[18] = view.status;
87
- $[19] = working;
88
- $[20] = t5;
89
- } else t5 = $[20];
90
- let t6;
91
- if ($[21] !== t3 || $[22] !== t4 || $[23] !== t5) {
92
- t6 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
86
+ if ($[13] !== t2 || $[14] !== t3) {
87
+ t4 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
93
88
  className: "flex flex-col gap-4 px-2 py-3",
94
- children: [
95
- t3,
96
- t4,
97
- t5
98
- ]
89
+ children: [t2, t3]
99
90
  }) });
100
- $[21] = t3;
101
- $[22] = t4;
102
- $[23] = t5;
103
- $[24] = t6;
104
- } else t6 = $[24];
105
- let t7;
106
- if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
107
- t7 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
108
- $[25] = t7;
109
- } else t7 = $[25];
110
- let t8;
111
- if ($[26] !== t6) {
112
- t8 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
91
+ $[13] = t2;
92
+ $[14] = t3;
93
+ $[15] = t4;
94
+ } else t4 = $[15];
95
+ let t5;
96
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
97
+ t5 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
98
+ $[16] = t5;
99
+ } else t5 = $[16];
100
+ let t6;
101
+ if ($[17] !== t4) {
102
+ t6 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
113
103
  className: "min-h-0 flex-1",
114
- children: [t6, t7]
104
+ children: [t4, t5]
115
105
  }) });
116
- $[26] = t6;
117
- $[27] = t8;
118
- } else t8 = $[27];
119
- return t8;
106
+ $[17] = t4;
107
+ $[18] = t6;
108
+ } else t6 = $[18];
109
+ return t6;
120
110
  }
111
+ /** How long the greeting's squareling takes to reach the end of the thread, in ms. */
112
+ const MORPH_DURATION = 350;
113
+ /** A strong ease-in-out, for moving across the screen. */
114
+ const MORPH_EASING = "cubic-bezier(0.77, 0, 0.175, 1)";
121
115
  /**
122
- * Shown in the last message, not after it: the scroller only brings a message the editor just
123
- * sent into view when it's appended last, and it arrives while the agent is already working.
116
+ * Moves the squareling from where the greeting showed it to the end of the thread, as the first
117
+ * message arrives, so it reads as the same one. Without motion for editors who reduce it.
124
118
  */
125
- function Working(t0) {
119
+ function useSquarelingMorph(empty) {
126
120
  const $ = c(2);
127
- const { status } = t0;
128
- const t1 = status ? STATUS_LINES[status] : "Working…";
121
+ const node = React.useRef(null);
122
+ const greeting = React.useRef(null);
123
+ let t0;
124
+ if ($[0] !== empty) {
125
+ t0 = () => {
126
+ const element = node.current;
127
+ if (!element) return;
128
+ if (empty) {
129
+ greeting.current = element.getBoundingClientRect();
130
+ return;
131
+ }
132
+ const from = greeting.current;
133
+ greeting.current = null;
134
+ if (!from || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
135
+ const to = element.getBoundingClientRect();
136
+ if (to.width === 0) return;
137
+ const dx = from.left + from.width / 2 - (to.left + to.width / 2);
138
+ const dy = from.top + from.height / 2 - (to.top + to.height / 2);
139
+ element.animate([{ transform: `translate(${dx}px, ${dy}px) scale(${from.width / to.width})` }, { transform: "none" }], {
140
+ duration: MORPH_DURATION,
141
+ easing: MORPH_EASING
142
+ });
143
+ };
144
+ $[0] = empty;
145
+ $[1] = t0;
146
+ } else t0 = $[1];
147
+ React.useLayoutEffect(t0);
148
+ return node;
149
+ }
150
+ /**
151
+ * The squareling at the end of the thread: idle between turns, at work during one. Shown in the
152
+ * last message, not after it: the scroller only brings a message the editor just sent into view
153
+ * when it's appended last, and it arrives while the agent is already working.
154
+ */
155
+ function AgentPresence(t0) {
156
+ const $ = c(13);
157
+ const { view: t1, working, squareling } = t0;
158
+ const { status, usingTools } = t1;
129
159
  let t2;
130
- if ($[0] !== t1) {
131
- t2 = /* @__PURE__ */ jsx("p", {
160
+ if ($[0] !== status || $[1] !== usingTools || $[2] !== working) {
161
+ t2 = working ? squarelingStatus(status, usingTools) : "idle";
162
+ $[0] = status;
163
+ $[1] = usingTools;
164
+ $[2] = working;
165
+ $[3] = t2;
166
+ } else t2 = $[3];
167
+ let t3;
168
+ if ($[4] !== squareling || $[5] !== t2) {
169
+ t3 = /* @__PURE__ */ jsx(Squareling, {
170
+ ref: squareling,
171
+ status: t2,
172
+ className: "size-6"
173
+ });
174
+ $[4] = squareling;
175
+ $[5] = t2;
176
+ $[6] = t3;
177
+ } else t3 = $[6];
178
+ let t4;
179
+ if ($[7] !== status || $[8] !== working) {
180
+ t4 = working && (status ? /* @__PURE__ */ jsx("span", {
181
+ className: "shimmer",
182
+ children: STATUS_LINES[status]
183
+ }) : /* @__PURE__ */ jsx("span", {
184
+ className: "sr-only",
185
+ children: "Working…"
186
+ }));
187
+ $[7] = status;
188
+ $[8] = working;
189
+ $[9] = t4;
190
+ } else t4 = $[9];
191
+ let t5;
192
+ if ($[10] !== t3 || $[11] !== t4) {
193
+ t5 = /* @__PURE__ */ jsxs("div", {
132
194
  role: "status",
133
- className: "shimmer text-muted-foreground text-sm",
134
- children: t1
195
+ className: "text-muted-foreground flex items-center gap-2 text-sm",
196
+ children: [t3, t4]
135
197
  });
136
- $[0] = t1;
137
- $[1] = t2;
138
- } else t2 = $[1];
139
- return t2;
198
+ $[10] = t3;
199
+ $[11] = t4;
200
+ $[12] = t5;
201
+ } else t5 = $[12];
202
+ return t5;
203
+ }
204
+ function squarelingStatus(status, usingTools) {
205
+ if (status === "fixing") return "fixing";
206
+ return status === "building" || usingTools ? "acting" : "thinking";
140
207
  }
141
208
  const STATUS_LINES = {
142
209
  building: "Building…",
143
210
  fixing: "Fixing a build error…"
144
211
  };
145
212
  function ThreadMessageRow(t0) {
146
- const $ = c(20);
147
- const { message, showSender } = t0;
213
+ const $ = c(14);
214
+ const { message } = t0;
148
215
  if (message.from === "stopped" || message.from === "failed") {
149
216
  const t1 = message.from === "stopped" ? `Stopped by ${message.sender.name}` : "Camox couldn’t finish this. Send your message again to retry.";
150
217
  let t2;
@@ -198,18 +265,8 @@ function ThreadMessageRow(t0) {
198
265
  $[8] = t1;
199
266
  } else t1 = $[8];
200
267
  let t2;
201
- if ($[9] !== message.sender || $[10] !== showSender) {
202
- t2 = showSender && /* @__PURE__ */ jsx(MessageHeader, {
203
- className: "text-muted-foreground text-xs",
204
- children: message.sender.name
205
- });
206
- $[9] = message.sender;
207
- $[10] = showSender;
208
- $[11] = t2;
209
- } else t2 = $[11];
210
- let t3;
211
- if ($[12] !== message.text) {
212
- t3 = /* @__PURE__ */ jsx(Bubble, {
268
+ if ($[9] !== message.text) {
269
+ t2 = /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
213
270
  align: "end",
214
271
  variant: "muted",
215
272
  className: "max-w-full",
@@ -217,53 +274,21 @@ function ThreadMessageRow(t0) {
217
274
  className: "whitespace-pre-wrap",
218
275
  children: message.text
219
276
  })
277
+ }) });
278
+ $[9] = message.text;
279
+ $[10] = t2;
280
+ } else t2 = $[10];
281
+ let t3;
282
+ if ($[11] !== t1 || $[12] !== t2) {
283
+ t3 = /* @__PURE__ */ jsxs(Message, {
284
+ align: "end",
285
+ children: [t1, t2]
220
286
  });
221
- $[12] = message.text;
287
+ $[11] = t1;
288
+ $[12] = t2;
222
289
  $[13] = t3;
223
290
  } else t3 = $[13];
224
- let t4;
225
- if ($[14] !== t2 || $[15] !== t3) {
226
- t4 = /* @__PURE__ */ jsxs(MessageContent, { children: [t2, t3] });
227
- $[14] = t2;
228
- $[15] = t3;
229
- $[16] = t4;
230
- } else t4 = $[16];
231
- let t5;
232
- if ($[17] !== t1 || $[18] !== t4) {
233
- t5 = /* @__PURE__ */ jsxs(Message, {
234
- align: "end",
235
- children: [t1, t4]
236
- });
237
- $[17] = t1;
238
- $[18] = t4;
239
- $[19] = t5;
240
- } else t5 = $[19];
241
- return t5;
242
- }
243
- function ContinuedIn(t0) {
244
- const $ = c(4);
245
- const { link } = t0;
246
- let t1;
247
- if ($[0] !== link.href || $[1] !== link.label || $[2] !== link.onOpen) {
248
- t1 = /* @__PURE__ */ jsxs("p", {
249
- className: "text-muted-foreground px-2 pt-3 text-center text-sm",
250
- children: [
251
- "Continued in",
252
- " ",
253
- /* @__PURE__ */ jsx("a", {
254
- href: link.href,
255
- onClick: link.onOpen,
256
- className: "text-foreground underline",
257
- children: link.label
258
- })
259
- ]
260
- });
261
- $[0] = link.href;
262
- $[1] = link.label;
263
- $[2] = link.onOpen;
264
- $[3] = t1;
265
- } else t1 = $[3];
266
- return t1;
291
+ return t3;
267
292
  }
268
293
  const initials = (name) => name.split(" ").map((part) => part[0]).join("").toUpperCase().slice(0, 2);
269
294
  function SenderAvatar(t0) {
@@ -0,0 +1,52 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES } from "../../preview/components/SidebarStack.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/features/studio/components/WorkersWidget.tsx
7
+ /** The Agent Sidebar's Workers widget, over the Chat widget. A placeholder for now. */
8
+ function WorkersWidget(t0) {
9
+ const $ = c(6);
10
+ const { className } = t0;
11
+ let t1;
12
+ if ($[0] !== className) {
13
+ t1 = cn("flex flex-col", className);
14
+ $[0] = className;
15
+ $[1] = t1;
16
+ } else t1 = $[1];
17
+ let t2;
18
+ let t3;
19
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
20
+ t2 = /* @__PURE__ */ jsx("header", {
21
+ className: cn("bg-background flex h-11 min-w-0 shrink-0 items-center justify-center px-3", BOTTOM_CARD_EDGES),
22
+ children: /* @__PURE__ */ jsx("h2", {
23
+ className: "truncate text-sm font-medium",
24
+ children: "Workers"
25
+ })
26
+ });
27
+ t3 = /* @__PURE__ */ jsx("div", {
28
+ className: cn("bg-background text-muted-foreground flex min-h-0 flex-1 items-center justify-center p-4 text-sm", CARD_BODY_EDGES),
29
+ children: "No workers yet"
30
+ });
31
+ $[2] = t2;
32
+ $[3] = t3;
33
+ } else {
34
+ t2 = $[2];
35
+ t3 = $[3];
36
+ }
37
+ let t4;
38
+ if ($[4] !== t1) {
39
+ t4 = /* @__PURE__ */ jsxs("section", {
40
+ "aria-label": "Workers",
41
+ "data-workers-widget": true,
42
+ className: t1,
43
+ children: [t2, t3]
44
+ });
45
+ $[4] = t1;
46
+ $[5] = t4;
47
+ } else t4 = $[5];
48
+ return t4;
49
+ }
50
+
51
+ //#endregion
52
+ export { WorkersWidget };
@@ -9,7 +9,7 @@ const studioStore = createStore({
9
9
  open: false,
10
10
  startRenaming: false
11
11
  },
12
- isDiscardDraftDialogOpen: false,
12
+ isDeleteDraftDialogOpen: false,
13
13
  localeDialog: null,
14
14
  websiteLocation: null
15
15
  },
@@ -64,16 +64,16 @@ const studioStore = createStore({
64
64
  }
65
65
  };
66
66
  },
67
- openDiscardDraftDialog: (context) => {
67
+ openDeleteDraftDialog: (context) => {
68
68
  return {
69
69
  ...context,
70
- isDiscardDraftDialogOpen: true
70
+ isDeleteDraftDialogOpen: true
71
71
  };
72
72
  },
73
- closeDiscardDraftDialog: (context) => {
73
+ closeDeleteDraftDialog: (context) => {
74
74
  return {
75
75
  ...context,
76
- isDiscardDraftDialogOpen: false
76
+ isDeleteDraftDialogOpen: false
77
77
  };
78
78
  },
79
79
  openLocaleDialog: (context, event) => {
@@ -10,6 +10,7 @@ function withoutExpectedCamoxLogs(onLog) {
10
10
  function isExpectedCamoxLog(log) {
11
11
  if (log.code === "MODULE_LEVEL_DIRECTIVE") return log.message.includes("\"use client\"");
12
12
  if (log.code === "INEFFECTIVE_DYNAMIC_IMPORT") return log.message.includes("virtual:camox/app");
13
+ if (log.code === "SOURCEMAP_BROKEN") return log.message.includes("(@tailwindcss/vite:");
13
14
  return false;
14
15
  }
15
16
 
@@ -30,6 +30,8 @@ const VIRTUAL_BLOCK_CHUNKS = "virtual:camox/block-chunks";
30
30
  const RESOLVED_VIRTUAL_BLOCK_CHUNKS = "\0" + VIRTUAL_BLOCK_CHUNKS;
31
31
  const VIRTUAL_APP_STYLESHEET_URL = "virtual:camox/app-stylesheet-url";
32
32
  const RESOLVED_VIRTUAL_APP_STYLESHEET_URL = "\0" + VIRTUAL_APP_STYLESHEET_URL;
33
+ const VIRTUAL_APP_STYLESHEET = "virtual:camox/app-stylesheet";
34
+ const RESOLVED_VIRTUAL_APP_STYLESHEET = "\0" + VIRTUAL_APP_STYLESHEET;
33
35
  const VIRTUAL_STUDIO_CSS = "virtual:camox-studio-css";
34
36
  const RESOLVED_VIRTUAL_STUDIO_CSS = "\0" + VIRTUAL_STUDIO_CSS;
35
37
  const VIRTUAL_OVERLAY_CSS = "virtual:camox-overlay-css";
@@ -197,6 +199,11 @@ function generateVirtualAppStylesheetUrl() {
197
199
  export default stylesheetUrl;
198
200
  `;
199
201
  }
202
+ /** The app's compiled stylesheet as text, which page images render with. */
203
+ function generateVirtualAppStylesheet() {
204
+ return `export { default } from "/src/styles.css?inline";
205
+ `;
206
+ }
200
207
  function generateVirtualCamoxServer(runtimeBasePath) {
201
208
  return `import {
202
209
  handleCamoxRequest as handleRuntimeRequest,
@@ -227,6 +234,8 @@ const options = {
227
234
  developmentDraft: __CAMOX_DEVELOPMENT_DRAFT__,
228
235
  getCamoxApp: async () => camoxApp,
229
236
  getDocument: async () => camoxDocument,
237
+ // Loaded by the first page image, so the stylesheet stays out of the Worker's main chunk.
238
+ getImageStylesheet: () => import("virtual:camox/app-stylesheet").then((module) => module.default),
230
239
  projectUuid: __CAMOX_PROJECT_ID__,
231
240
  renderPage,
232
241
  renderStudio,
@@ -272,6 +281,7 @@ function resolveRuntimeDevId(id, importer) {
272
281
  if (id === VIRTUAL_RENDERER_CLIENT) return RESOLVED_VIRTUAL_RENDERER_CLIENT;
273
282
  if (id === VIRTUAL_RENDERER_CLIENT_URL) return RESOLVED_VIRTUAL_RENDERER_CLIENT_URL;
274
283
  if (id === VIRTUAL_APP_STYLESHEET_URL) return RESOLVED_VIRTUAL_APP_STYLESHEET_URL;
284
+ if (id === VIRTUAL_APP_STYLESHEET) return RESOLVED_VIRTUAL_APP_STYLESHEET;
275
285
  if (id === VIRTUAL_BLOCK_CHUNKS) return RESOLVED_VIRTUAL_BLOCK_CHUNKS;
276
286
  if (id === VIRTUAL_STUDIO_CSS) return RESOLVED_VIRTUAL_STUDIO_CSS;
277
287
  if (id === VIRTUAL_OVERLAY_CSS) return RESOLVED_VIRTUAL_OVERLAY_CSS;
@@ -291,6 +301,7 @@ function loadRuntimeDevModule(id, options = {}) {
291
301
  if (id === RESOLVED_VIRTUAL_RENDERER_CLIENT) return generateVirtualRendererClient();
292
302
  if (id === RESOLVED_VIRTUAL_RENDERER_CLIENT_URL) return generateVirtualRendererClientUrl();
293
303
  if (id === RESOLVED_VIRTUAL_APP_STYLESHEET_URL) return generateVirtualAppStylesheetUrl();
304
+ if (id === RESOLVED_VIRTUAL_APP_STYLESHEET) return generateVirtualAppStylesheet();
294
305
  if (id === RESOLVED_VIRTUAL_STUDIO_CSS) {
295
306
  const cssUrl = `/@fs/${resolve(sdkRoot, "dist/studio.css").replaceAll("\\", "/").replace(/^\/+/, "")}`;
296
307
  return `export default ${JSON.stringify(cssUrl)};`;
@@ -123,7 +123,8 @@ const CAMOX_OPTIMIZED_DEPS = [
123
123
  "camox > @shikijs/themes/github-dark-high-contrast",
124
124
  "camox > @shikijs/themes/github-light",
125
125
  "camox > @sinclair/typebox",
126
- "camox > @takumi-rs/image-response",
126
+ "camox > takumi-js/helpers",
127
+ "camox > takumi-js/response",
127
128
  "camox > @tanstack/react-form",
128
129
  "camox > @tanstack/react-query",
129
130
  "camox > @tanstack/react-router",
@@ -189,6 +190,7 @@ function camox(options) {
189
190
  return {
190
191
  name: "camox",
191
192
  enforce: "pre",
193
+ sharedDuringBuild: true,
192
194
  resolveId(id, importer) {
193
195
  if (hostedProject) {
194
196
  const forbidden = forbiddenImport(hostedProject, id, importer);