camox 0.54.0 → 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 (36) 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/preview/CamoxPreview.js +2 -2
  8. package/dist/features/preview/components/PreviewToolbar.js +1 -1
  9. package/dist/features/preview/components/SelectionEditor.js +2 -2
  10. package/dist/features/preview/components/SidebarStack.js +11 -13
  11. package/dist/features/preview/components/StudioEditingFallback.js +3 -3
  12. package/dist/features/routes/pageRuntime.d.ts +1 -1
  13. package/dist/features/runtime/RuntimeChrome.js +4 -4
  14. package/dist/features/studio/components/AgentSidebar.js +56 -0
  15. package/dist/features/studio/components/{ChatSidebar.js → ChatWidget.js} +60 -169
  16. package/dist/features/studio/components/DraftsControl.js +17 -17
  17. package/dist/features/studio/components/ReviewDraftSheet.js +38 -38
  18. package/dist/features/studio/components/Squareling.js +10 -8
  19. package/dist/features/studio/components/ThreadMessages.js +128 -105
  20. package/dist/features/studio/components/WorkersWidget.js +52 -0
  21. package/dist/features/studio/studioStore.js +5 -5
  22. package/dist/lib/queries.js +1 -1
  23. package/dist/package.js +1 -1
  24. package/dist/studio.css +1 -1
  25. package/package.json +4 -4
  26. package/skills/camox/SKILL.md +3 -10
  27. package/skills/camox/references/artifacts.md +2 -2
  28. package/skills/camox/references/block-definitions.md +1 -1
  29. package/skills/camox/references/layout-definitions.md +1 -1
  30. package/skills/camox/references/routed-layouts.md +2 -2
  31. package/skills/camox-cli/SKILL.md +15 -0
  32. package/skills/{camox → camox-cli}/references/cli-common.md +1 -1
  33. package/skills/{camox → camox-cli}/references/cli-content.md +2 -2
  34. package/skills/{camox → camox-cli}/references/cli-publishing.md +4 -4
  35. package/skills/camox-expand/SKILL.md +1 -1
  36. package/skills/camoxify/SKILL.md +1 -1
@@ -1,6 +1,7 @@
1
1
  import { Squareling } from "./Squareling.js";
2
2
  import { ThreadMarkdown } from "./ThreadMarkdown.js";
3
3
  import { c } from "react/compiler-runtime";
4
+ import * as React from "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  import { Avatar, AvatarFallback, AvatarImage } from "@camox/ui/avatar";
6
7
  import { Bubble, BubbleContent } from "@camox/ui/bubble";
@@ -9,38 +10,42 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
9
10
 
10
11
  //#region src/features/studio/components/ThreadMessages.tsx
11
12
  /**
12
- * A thread's messages, and the agent's squareling at work while a run is going or a message is
13
- * still `sending`: on its way to the thread, which hasn't accepted it yet. Its face says whether
14
- * the agent thinks or acts (uses its tools, or builds its code). While the end of a turn builds
15
- * the agent's code, or the agent fixes a build error, it says so in words too. Each editor's message shows its sender's
16
- * avatar, without their name. A fresh Live thread links to the draft the editor's previous one
17
- * 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.
18
20
  */
19
21
  function ThreadMessages(t0) {
20
- const $ = c(20);
21
- const { view, sending: t1, continuedIn } = t0;
22
+ const $ = c(19);
23
+ const { view, sending: t1 } = t0;
22
24
  const sending = t1 === void 0 ? false : t1;
23
25
  const working = view.running || sending;
24
- if (view.messages.length === 0 && !working) {
26
+ const empty = view.messages.length === 0 && !working;
27
+ const squareling = useSquarelingMorph(empty);
28
+ if (empty) {
25
29
  let t2;
26
- if ($[0] !== continuedIn) {
27
- t2 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
28
- $[0] = continuedIn;
30
+ if ($[0] !== squareling) {
31
+ t2 = /* @__PURE__ */ jsx(Squareling, {
32
+ ref: squareling,
33
+ status: "idle",
34
+ className: "size-10"
35
+ });
36
+ $[0] = squareling;
29
37
  $[1] = t2;
30
38
  } else t2 = $[1];
31
39
  let t3;
32
40
  if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
33
- t3 = /* @__PURE__ */ jsx("p", {
34
- "data-thread-empty": true,
35
- className: "text-muted-foreground flex min-h-0 flex-1 items-center justify-center p-4 text-center text-sm",
36
- children: "Ask Camox about your website’s content."
37
- });
41
+ t3 = /* @__PURE__ */ jsx("p", { children: "How can I help?" });
38
42
  $[2] = t3;
39
43
  } else t3 = $[2];
40
44
  let t4;
41
45
  if ($[3] !== t2) {
42
46
  t4 = /* @__PURE__ */ jsxs("div", {
43
- className: "flex min-h-0 flex-1 flex-col",
47
+ "data-thread-empty": true,
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",
44
49
  children: [t2, t3]
45
50
  });
46
51
  $[3] = t2;
@@ -49,108 +54,151 @@ function ThreadMessages(t0) {
49
54
  return t4;
50
55
  }
51
56
  let t2;
52
- if ($[5] !== continuedIn) {
53
- t2 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
54
- $[5] = continuedIn;
55
- $[6] = t2;
56
- } else t2 = $[6];
57
- let t3;
58
- if ($[7] !== view || $[8] !== working) {
59
- t3 = view.messages.map((message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
57
+ if ($[5] !== squareling || $[6] !== view || $[7] !== working) {
58
+ t2 = view.messages.map((message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
60
59
  messageId: message.id,
61
60
  scrollAnchor: message.from === "editor",
62
61
  className: "flex flex-col gap-4",
63
- children: [/* @__PURE__ */ jsx(ThreadMessageRow, { message }), working && index === view.messages.length - 1 && /* @__PURE__ */ jsx(Working, { view })]
62
+ children: [/* @__PURE__ */ jsx(ThreadMessageRow, { message }), index === view.messages.length - 1 && /* @__PURE__ */ jsx(AgentPresence, {
63
+ view,
64
+ working,
65
+ squareling
66
+ })]
64
67
  }, message.id));
65
- $[7] = view;
66
- $[8] = working;
67
- $[9] = t3;
68
- } else t3 = $[9];
69
- let t4;
70
- if ($[10] !== view || $[11] !== working) {
71
- t4 = working && view.messages.length === 0 && /* @__PURE__ */ jsx(Working, { view });
68
+ $[5] = squareling;
69
+ $[6] = view;
70
+ $[7] = working;
71
+ $[8] = t2;
72
+ } else t2 = $[8];
73
+ let t3;
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;
72
81
  $[10] = view;
73
82
  $[11] = working;
74
- $[12] = t4;
75
- } else t4 = $[12];
76
- let t5;
77
- if ($[13] !== t2 || $[14] !== t3 || $[15] !== t4) {
78
- t5 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
83
+ $[12] = t3;
84
+ } else t3 = $[12];
85
+ let t4;
86
+ if ($[13] !== t2 || $[14] !== t3) {
87
+ t4 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
79
88
  className: "flex flex-col gap-4 px-2 py-3",
80
- children: [
81
- t2,
82
- t3,
83
- t4
84
- ]
89
+ children: [t2, t3]
85
90
  }) });
86
91
  $[13] = t2;
87
92
  $[14] = t3;
88
93
  $[15] = t4;
94
+ } else t4 = $[15];
95
+ let t5;
96
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
97
+ t5 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
89
98
  $[16] = t5;
90
99
  } else t5 = $[16];
91
100
  let t6;
92
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
93
- t6 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
94
- $[17] = t6;
95
- } else t6 = $[17];
96
- let t7;
97
- if ($[18] !== t5) {
98
- t7 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
101
+ if ($[17] !== t4) {
102
+ t6 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
99
103
  className: "min-h-0 flex-1",
100
- children: [t5, t6]
104
+ children: [t4, t5]
101
105
  }) });
102
- $[18] = t5;
103
- $[19] = t7;
104
- } else t7 = $[19];
105
- return t7;
106
+ $[17] = t4;
107
+ $[18] = t6;
108
+ } else t6 = $[18];
109
+ return t6;
106
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)";
107
115
  /**
108
- * Shown in the last message, not after it: the scroller only brings a message the editor just
109
- * 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.
110
118
  */
111
- function Working(t0) {
112
- const $ = c(10);
113
- const { view: t1 } = t0;
119
+ function useSquarelingMorph(empty) {
120
+ const $ = c(2);
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;
114
158
  const { status, usingTools } = t1;
115
159
  let t2;
116
- if ($[0] !== status || $[1] !== usingTools) {
117
- t2 = squarelingStatus(status, usingTools);
160
+ if ($[0] !== status || $[1] !== usingTools || $[2] !== working) {
161
+ t2 = working ? squarelingStatus(status, usingTools) : "idle";
118
162
  $[0] = status;
119
163
  $[1] = usingTools;
120
- $[2] = t2;
121
- } else t2 = $[2];
164
+ $[2] = working;
165
+ $[3] = t2;
166
+ } else t2 = $[3];
122
167
  let t3;
123
- if ($[3] !== t2) {
168
+ if ($[4] !== squareling || $[5] !== t2) {
124
169
  t3 = /* @__PURE__ */ jsx(Squareling, {
170
+ ref: squareling,
125
171
  status: t2,
126
172
  className: "size-6"
127
173
  });
128
- $[3] = t2;
129
- $[4] = t3;
130
- } else t3 = $[4];
174
+ $[4] = squareling;
175
+ $[5] = t2;
176
+ $[6] = t3;
177
+ } else t3 = $[6];
131
178
  let t4;
132
- if ($[5] !== status) {
133
- t4 = status ? /* @__PURE__ */ jsx("span", {
179
+ if ($[7] !== status || $[8] !== working) {
180
+ t4 = working && (status ? /* @__PURE__ */ jsx("span", {
134
181
  className: "shimmer",
135
182
  children: STATUS_LINES[status]
136
183
  }) : /* @__PURE__ */ jsx("span", {
137
184
  className: "sr-only",
138
185
  children: "Working…"
139
- });
140
- $[5] = status;
141
- $[6] = t4;
142
- } else t4 = $[6];
186
+ }));
187
+ $[7] = status;
188
+ $[8] = working;
189
+ $[9] = t4;
190
+ } else t4 = $[9];
143
191
  let t5;
144
- if ($[7] !== t3 || $[8] !== t4) {
192
+ if ($[10] !== t3 || $[11] !== t4) {
145
193
  t5 = /* @__PURE__ */ jsxs("div", {
146
194
  role: "status",
147
195
  className: "text-muted-foreground flex items-center gap-2 text-sm",
148
196
  children: [t3, t4]
149
197
  });
150
- $[7] = t3;
151
- $[8] = t4;
152
- $[9] = t5;
153
- } else t5 = $[9];
198
+ $[10] = t3;
199
+ $[11] = t4;
200
+ $[12] = t5;
201
+ } else t5 = $[12];
154
202
  return t5;
155
203
  }
156
204
  function squarelingStatus(status, usingTools) {
@@ -242,31 +290,6 @@ function ThreadMessageRow(t0) {
242
290
  } else t3 = $[13];
243
291
  return t3;
244
292
  }
245
- function ContinuedIn(t0) {
246
- const $ = c(4);
247
- const { link } = t0;
248
- let t1;
249
- if ($[0] !== link.href || $[1] !== link.label || $[2] !== link.onOpen) {
250
- t1 = /* @__PURE__ */ jsxs("p", {
251
- className: "text-muted-foreground px-2 pt-3 text-center text-sm",
252
- children: [
253
- "Continued in",
254
- " ",
255
- /* @__PURE__ */ jsx("a", {
256
- href: link.href,
257
- onClick: link.onOpen,
258
- className: "text-foreground underline",
259
- children: link.label
260
- })
261
- ]
262
- });
263
- $[0] = link.href;
264
- $[1] = link.label;
265
- $[2] = link.onOpen;
266
- $[3] = t1;
267
- } else t1 = $[3];
268
- return t1;
269
- }
270
293
  const initials = (name) => name.split(" ").map((part) => part[0]).join("").toUpperCase().slice(0, 2);
271
294
  function SenderAvatar(t0) {
272
295
  const $ = c(10);
@@ -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) => {
@@ -43,7 +43,7 @@ const projectMutations = {
43
43
  };
44
44
  const draftMutations = {
45
45
  publish: () => getOrpc().drafts.publish.mutationOptions(),
46
- discard: () => getOrpc().drafts.discard.mutationOptions(),
46
+ delete: () => getOrpc().drafts.delete.mutationOptions(),
47
47
  /** Requests the draft's overview again right away, once it failed. */
48
48
  retryOverview: () => getOrpc().drafts.retryOverview.mutationOptions(),
49
49
  /** Drops the draft's copy of an entity it conflicts on, to use Live's version instead. */
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.54.0";
2
+ var version = "0.56.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };