camox 0.53.1 → 0.54.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.
@@ -1,3 +1,4 @@
1
+ import { Squareling } from "./Squareling.js";
1
2
  import { ThreadMarkdown } from "./ThreadMarkdown.js";
2
3
  import { c } from "react/compiler-runtime";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -8,143 +9,161 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
8
9
 
9
10
  //#region src/features/studio/components/ThreadMessages.tsx
10
11
  /**
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`).
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`).
16
18
  */
17
19
  function ThreadMessages(t0) {
18
- const $ = c(28);
19
- const { view, sending: t1, showSenders: t2, continuedIn } = t0;
20
+ const $ = c(20);
21
+ const { view, sending: t1, continuedIn } = t0;
20
22
  const sending = t1 === void 0 ? false : t1;
21
- const showSenders = t2 === void 0 ? false : t2;
22
23
  const working = view.running || sending;
23
24
  if (view.messages.length === 0 && !working) {
24
- let t3;
25
+ let t2;
25
26
  if ($[0] !== continuedIn) {
26
- t3 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
27
+ t2 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
27
28
  $[0] = continuedIn;
28
- $[1] = t3;
29
- } else t3 = $[1];
30
- let t4;
29
+ $[1] = t2;
30
+ } else t2 = $[1];
31
+ let t3;
31
32
  if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
32
- t4 = /* @__PURE__ */ jsx("p", {
33
+ t3 = /* @__PURE__ */ jsx("p", {
33
34
  "data-thread-empty": true,
34
35
  className: "text-muted-foreground flex min-h-0 flex-1 items-center justify-center p-4 text-center text-sm",
35
36
  children: "Ask Camox about your website’s content."
36
37
  });
37
- $[2] = t4;
38
- } else t4 = $[2];
39
- let t5;
40
- if ($[3] !== t3) {
41
- t5 = /* @__PURE__ */ jsxs("div", {
38
+ $[2] = t3;
39
+ } else t3 = $[2];
40
+ let t4;
41
+ if ($[3] !== t2) {
42
+ t4 = /* @__PURE__ */ jsxs("div", {
42
43
  className: "flex min-h-0 flex-1 flex-col",
43
- children: [t3, t4]
44
+ children: [t2, t3]
44
45
  });
45
- $[3] = t3;
46
- $[4] = t5;
47
- } else t5 = $[4];
48
- return t5;
46
+ $[3] = t2;
47
+ $[4] = t4;
48
+ } else t4 = $[4];
49
+ return t4;
49
50
  }
50
- let t3;
51
+ let t2;
51
52
  if ($[5] !== continuedIn) {
52
- t3 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
53
+ t2 = continuedIn && /* @__PURE__ */ jsx(ContinuedIn, { link: continuedIn });
53
54
  $[5] = continuedIn;
54
- $[6] = t3;
55
- } else t3 = $[6];
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, {
60
+ messageId: message.id,
61
+ scrollAnchor: message.from === "editor",
62
+ className: "flex flex-col gap-4",
63
+ children: [/* @__PURE__ */ jsx(ThreadMessageRow, { message }), working && index === view.messages.length - 1 && /* @__PURE__ */ jsx(Working, { view })]
64
+ }, message.id));
65
+ $[7] = view;
66
+ $[8] = working;
67
+ $[9] = t3;
68
+ } else t3 = $[9];
56
69
  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];
70
+ if ($[10] !== view || $[11] !== working) {
71
+ t4 = working && view.messages.length === 0 && /* @__PURE__ */ jsx(Working, { view });
72
+ $[10] = view;
73
+ $[11] = working;
74
+ $[12] = t4;
75
+ } else t4 = $[12];
82
76
  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, {
77
+ if ($[13] !== t2 || $[14] !== t3 || $[15] !== t4) {
78
+ t5 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
93
79
  className: "flex flex-col gap-4 px-2 py-3",
94
80
  children: [
81
+ t2,
95
82
  t3,
96
- t4,
97
- t5
83
+ t4
98
84
  ]
99
85
  }) });
100
- $[21] = t3;
101
- $[22] = t4;
102
- $[23] = t5;
103
- $[24] = t6;
104
- } else t6 = $[24];
86
+ $[13] = t2;
87
+ $[14] = t3;
88
+ $[15] = t4;
89
+ $[16] = t5;
90
+ } else t5 = $[16];
91
+ let t6;
92
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
93
+ t6 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
94
+ $[17] = t6;
95
+ } else t6 = $[17];
105
96
  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, {
97
+ if ($[18] !== t5) {
98
+ t7 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
113
99
  className: "min-h-0 flex-1",
114
- children: [t6, t7]
100
+ children: [t5, t6]
115
101
  }) });
116
- $[26] = t6;
117
- $[27] = t8;
118
- } else t8 = $[27];
119
- return t8;
102
+ $[18] = t5;
103
+ $[19] = t7;
104
+ } else t7 = $[19];
105
+ return t7;
120
106
  }
121
107
  /**
122
108
  * Shown in the last message, not after it: the scroller only brings a message the editor just
123
109
  * sent into view when it's appended last, and it arrives while the agent is already working.
124
110
  */
125
111
  function Working(t0) {
126
- const $ = c(2);
127
- const { status } = t0;
128
- const t1 = status ? STATUS_LINES[status] : "Working…";
112
+ const $ = c(10);
113
+ const { view: t1 } = t0;
114
+ const { status, usingTools } = t1;
129
115
  let t2;
130
- if ($[0] !== t1) {
131
- t2 = /* @__PURE__ */ jsx("p", {
116
+ if ($[0] !== status || $[1] !== usingTools) {
117
+ t2 = squarelingStatus(status, usingTools);
118
+ $[0] = status;
119
+ $[1] = usingTools;
120
+ $[2] = t2;
121
+ } else t2 = $[2];
122
+ let t3;
123
+ if ($[3] !== t2) {
124
+ t3 = /* @__PURE__ */ jsx(Squareling, {
125
+ status: t2,
126
+ className: "size-6"
127
+ });
128
+ $[3] = t2;
129
+ $[4] = t3;
130
+ } else t3 = $[4];
131
+ let t4;
132
+ if ($[5] !== status) {
133
+ t4 = status ? /* @__PURE__ */ jsx("span", {
134
+ className: "shimmer",
135
+ children: STATUS_LINES[status]
136
+ }) : /* @__PURE__ */ jsx("span", {
137
+ className: "sr-only",
138
+ children: "Working…"
139
+ });
140
+ $[5] = status;
141
+ $[6] = t4;
142
+ } else t4 = $[6];
143
+ let t5;
144
+ if ($[7] !== t3 || $[8] !== t4) {
145
+ t5 = /* @__PURE__ */ jsxs("div", {
132
146
  role: "status",
133
- className: "shimmer text-muted-foreground text-sm",
134
- children: t1
147
+ className: "text-muted-foreground flex items-center gap-2 text-sm",
148
+ children: [t3, t4]
135
149
  });
136
- $[0] = t1;
137
- $[1] = t2;
138
- } else t2 = $[1];
139
- return t2;
150
+ $[7] = t3;
151
+ $[8] = t4;
152
+ $[9] = t5;
153
+ } else t5 = $[9];
154
+ return t5;
155
+ }
156
+ function squarelingStatus(status, usingTools) {
157
+ if (status === "fixing") return "fixing";
158
+ return status === "building" || usingTools ? "acting" : "thinking";
140
159
  }
141
160
  const STATUS_LINES = {
142
161
  building: "Building…",
143
162
  fixing: "Fixing a build error…"
144
163
  };
145
164
  function ThreadMessageRow(t0) {
146
- const $ = c(20);
147
- const { message, showSender } = t0;
165
+ const $ = c(14);
166
+ const { message } = t0;
148
167
  if (message.from === "stopped" || message.from === "failed") {
149
168
  const t1 = message.from === "stopped" ? `Stopped by ${message.sender.name}` : "Camox couldn’t finish this. Send your message again to retry.";
150
169
  let t2;
@@ -198,18 +217,8 @@ function ThreadMessageRow(t0) {
198
217
  $[8] = t1;
199
218
  } else t1 = $[8];
200
219
  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, {
220
+ if ($[9] !== message.text) {
221
+ t2 = /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
213
222
  align: "end",
214
223
  variant: "muted",
215
224
  className: "max-w-full",
@@ -217,28 +226,21 @@ function ThreadMessageRow(t0) {
217
226
  className: "whitespace-pre-wrap",
218
227
  children: message.text
219
228
  })
229
+ }) });
230
+ $[9] = message.text;
231
+ $[10] = t2;
232
+ } else t2 = $[10];
233
+ let t3;
234
+ if ($[11] !== t1 || $[12] !== t2) {
235
+ t3 = /* @__PURE__ */ jsxs(Message, {
236
+ align: "end",
237
+ children: [t1, t2]
220
238
  });
221
- $[12] = message.text;
239
+ $[11] = t1;
240
+ $[12] = t2;
222
241
  $[13] = t3;
223
242
  } 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;
243
+ return t3;
242
244
  }
243
245
  function ContinuedIn(t0) {
244
246
  const $ = c(4);
@@ -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);
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.53.1";
2
+ var version = "0.54.0";
3
3
 
4
4
  //#endregion
5
5
  export { version };