camox 0.58.1 → 0.60.2

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 (102) hide show
  1. package/dist/core/createBlock.js +1 -1
  2. package/dist/core/editing/createEditableBlock.js +2 -2
  3. package/dist/core/lib/recordScope.js +1 -1
  4. package/dist/features/canvas/CamoxCanvas.js +2 -2
  5. package/dist/features/canvas/CanvasOverlays.js +1 -1
  6. package/dist/features/canvas/sidebar/LayoutPageSeo.js +1 -1
  7. package/dist/features/canvas/sidebar/PageInspector.js +1 -1
  8. package/dist/features/content/CamoxContent.js +1 -1
  9. package/dist/features/content/components/MissingFromLocale.js +1 -1
  10. package/dist/features/page/CuratedPageContent.js +1 -1
  11. package/dist/features/preview/CamoxPreview.js +3 -3
  12. package/dist/features/preview/components/AddBlockSheet.js +1 -1
  13. package/dist/features/preview/components/AssetLightbox.js +1 -1
  14. package/dist/features/preview/components/BlockActionsPopover.js +1 -1
  15. package/dist/features/preview/components/CreatePageModal.js +2 -2
  16. package/dist/features/preview/components/FieldOverlayStyles.js +1 -1
  17. package/dist/features/preview/components/MobilePreviewDrawer.js +1 -1
  18. package/dist/features/preview/components/Overlays.js +1 -1
  19. package/dist/features/preview/components/PageInfo.js +1 -1
  20. package/dist/features/preview/components/PagePicker.js +1 -1
  21. package/dist/features/preview/components/PageTree.js +1 -1
  22. package/dist/features/preview/components/PreviewPanel.js +1 -1
  23. package/dist/features/preview/components/PreviewToolbar.js +1 -1
  24. package/dist/features/preview/components/SelectionEditor.js +2 -2
  25. package/dist/features/preview/components/StudioEditingFallback.js +1 -1
  26. package/dist/features/provider/AuthenticatedCamoxProvider.js +1 -1
  27. package/dist/features/provider/CamoxProvider.js +1 -1
  28. package/dist/features/provider/CoreCamoxProvider.js +3 -3
  29. package/dist/features/provider/components/CommandPalette.js +1 -1
  30. package/dist/features/renderer/RendererApp.js +187 -103
  31. package/dist/features/renderer/rendererHost.js +3 -7
  32. package/dist/features/routes/pageRuntime.d.ts +2 -5
  33. package/dist/features/routes/pageRuntime.js +1 -2
  34. package/dist/features/runtime/RuntimeChrome.js +1 -1
  35. package/dist/features/runtime/loopbackFetch.d.ts +8 -0
  36. package/dist/features/runtime/navigationTarget.js +1 -2
  37. package/dist/features/runtime/pageApp.js +1 -1
  38. package/dist/features/runtime/publicCache.d.ts +21 -0
  39. package/dist/features/runtime/publishingDraft.d.ts +4 -0
  40. package/dist/features/runtime/rendererClient.js +1 -1
  41. package/dist/features/runtime/runtime.d.ts +0 -5
  42. package/dist/features/runtime/runtime.js +80 -33
  43. package/dist/features/runtime/worker.js +4 -7
  44. package/dist/features/runtime/workerRequest.d.ts +8 -0
  45. package/dist/features/runtime/workerRuntime.d.ts +5 -0
  46. package/dist/features/runtime/workerRuntime.js +6 -0
  47. package/dist/features/sdkBundle/buildSdkBundle.d.ts +40 -0
  48. package/dist/features/sdkBundle/buildSdkBundle.js +323 -0
  49. package/dist/features/sdkBundle/localSdkBundle.d.ts +44 -0
  50. package/dist/features/sdkBundle/localSdkBundle.js +162 -0
  51. package/dist/features/sdkBundle/sdkBundle.d.ts +3 -0
  52. package/dist/features/sdkBundle/sdkBundle.js +4 -0
  53. package/dist/features/sdkBundle/sdkBundleName.d.ts +59 -0
  54. package/dist/features/sdkBundle/sdkBundleName.js +164 -0
  55. package/dist/features/sdkBundle/specifiers.d.ts +34 -0
  56. package/dist/features/sdkBundle/specifiers.js +146 -0
  57. package/dist/features/settings/FaviconSettings.js +1 -1
  58. package/dist/features/settings/SocialProfilesSettings.js +284 -151
  59. package/dist/features/studio/CamoxStudio.js +1 -1
  60. package/dist/features/studio/FollowAgentProvider.js +72 -13
  61. package/dist/features/studio/components/ChatWidget.js +86 -44
  62. package/dist/features/studio/components/DraftsControl.js +232 -201
  63. package/dist/features/studio/components/LocalePicker.js +2 -2
  64. package/dist/features/studio/components/Navbar.js +3 -3
  65. package/dist/features/studio/components/Patrol.js +312 -209
  66. package/dist/features/studio/components/ProjectMenu.js +2 -2
  67. package/dist/features/studio/components/ReviewDraftSheet.js +9 -15
  68. package/dist/features/studio/components/Squareling.js +164 -66
  69. package/dist/features/studio/components/ThreadComposer.js +139 -69
  70. package/dist/features/studio/components/ThreadMessages.js +216 -64
  71. package/dist/features/studio/components/UserButton.js +2 -2
  72. package/dist/features/studio/draftLabel.js +1 -2
  73. package/dist/features/studio/draftNotice.js +0 -1
  74. package/dist/features/studio/editorWhereContext.js +11 -0
  75. package/dist/features/studio/showInCanvas.js +1 -1
  76. package/dist/features/studio/useEditorSelection.js +135 -0
  77. package/dist/features/vite/definitionsSync.js +14 -60
  78. package/dist/features/vite/devSignIn.js +1 -1
  79. package/dist/features/vite/hostedChecks.js +1 -1
  80. package/dist/features/vite/runtimeDev.js +2 -2
  81. package/dist/features/vite/sdkBundleBuild.js +74 -0
  82. package/dist/features/vite/staticAssetHeaders.js +7 -4
  83. package/dist/features/vite/vite.d.ts +8 -7
  84. package/dist/features/vite/vite.js +67 -28
  85. package/dist/lib/api-client-server.js +25 -8
  86. package/dist/lib/api-client.js +2 -6
  87. package/dist/lib/auth.js +25 -59
  88. package/dist/lib/draft-scope.js +5 -25
  89. package/dist/lib/preview-handoff.js +1 -1
  90. package/dist/lib/server-auth-cookie.js +23 -11
  91. package/dist/lib/stored-auth-cookies.js +76 -0
  92. package/dist/lib/studio-reads.js +1 -1
  93. package/dist/lib/use-thread.js +40 -40
  94. package/dist/package.js +1 -1
  95. package/dist/studio.css +1 -1
  96. package/package.json +17 -4
  97. package/skills/camox/references/block-definitions.md +1 -1
  98. package/dist/features/vite/publishSeededContent.js +0 -30
  99. package/skills/camox-cli/SKILL.md +0 -15
  100. package/skills/camox-cli/references/cli-common.md +0 -58
  101. package/skills/camox-cli/references/cli-content.md +0 -181
  102. package/skills/camox-cli/references/cli-publishing.md +0 -26
@@ -1,7 +1,7 @@
1
- import { getDraftReadClient } from "../../../lib/api-client.js";
2
1
  import { useDraftScope } from "../../../lib/draft-scope.js";
3
2
  import { reads, useReadQuery, useStudioCache } from "../../../lib/studio-reads.js";
4
3
  import { cn } from "../../../lib/utils.js";
4
+ import { getDraftReadClient } from "../../../lib/api-client.js";
5
5
  import { draftMutations } from "../../../lib/queries.js";
6
6
  import { previewStore } from "../../preview/previewStore.js";
7
7
  import { localeLabel } from "../localeOptions.js";
@@ -199,8 +199,7 @@ const SHARED_MESSAGE_MIN = 3;
199
199
  const isShownWarning = (problem) => problem.code === "removedInUse";
200
200
  /**
201
201
  * One card per problem, saying what's wrong and where. Problems sharing a message fold into one
202
- * card naming each: a development draft can hold dozens of definitions to release, and a removed
203
- * block can sit on dozens of pages, with the same message for each. A problem on a page has an
202
+ * card naming each: a removed block can sit on dozens of pages, with the same message for each. A problem on a page has an
204
203
  * action that shows it in the Canvas; a blocker in the draft's code, which only the agent fixes,
205
204
  * one that opens the draft's thread.
206
205
  */
@@ -626,7 +625,7 @@ const publishInput = (projectId, shown, publishAnyway) => ({
626
625
  });
627
626
  /** Why a publish with code went back to the review, as the review says it. */
628
627
  const PUBLISH_ABORTED = {
629
- revisionChanged: "The agent changed the code since this review opened, so the publish stopped. Check the preview, then publish again.",
628
+ revisionChanged: "The draft's code changed since this review opened, so the publish stopped. Check the preview, then publish again.",
630
629
  conflictsChanged: "Live changed while publishing, so the publish stopped and Live is as it was. Check the new list.",
631
630
  blocked: "Something now needs fixing before publishing, so the publish stopped.",
632
631
  codeDoesNotMerge: "Live's code changed while publishing, and it doesn't merge with this draft's yet, so the publish stopped. Camox's agent is fixing it in the draft's thread: publish again once it's done.",
@@ -963,17 +962,15 @@ function _temp8(bullet, index) {
963
962
  function _temp7(error) {
964
963
  return toast.error(error.message || "Could not summarize the draft");
965
964
  }
966
- /**
967
- * Switches the studio to Live once its draft ended here, replacing the draft's URL entry. A
968
- * development draft never ends: publishing or deleting empties it, and dev mode stays in it.
969
- */
965
+ /** Switches the studio to Live once its draft ended here, replacing the draft's URL entry. */
970
966
  function useLeaveDraft() {
971
967
  const $ = c(2);
972
968
  const draftScope = useDraftScope();
973
969
  let t0;
974
970
  if ($[0] !== draftScope) {
975
971
  t0 = (ended) => {
976
- if (draftScope.leave(ended) && ended) toast.success(`Draft ${ended.outcome}. You're now viewing Live.`);
972
+ draftScope.leave(ended);
973
+ if (ended) toast.success(`Draft ${ended.outcome}. You're now viewing Live.`);
977
974
  };
978
975
  $[0] = draftScope;
979
976
  $[1] = t0;
@@ -1358,14 +1355,11 @@ function ReviewDraftSheet(t0) {
1358
1355
  className: "flex flex-col gap-1 border-b p-4 pr-12",
1359
1356
  children: headline ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(SheetDescription, {
1360
1357
  className: "flex min-w-0 items-center gap-1",
1361
- children: [draft.data?.kind === "regular" ? /* @__PURE__ */ jsx(DraftNameInput, {
1358
+ children: [draft.data && /* @__PURE__ */ jsx(DraftNameInput, {
1362
1359
  ref: nameInput,
1363
1360
  projectId,
1364
1361
  draft: draft.data,
1365
1362
  className: "placeholder:text-muted-foreground text-muted-foreground field-sizing-content h-6 w-auto max-w-full text-sm font-normal"
1366
- }) : draft.data && /* @__PURE__ */ jsx("span", {
1367
- className: "truncate",
1368
- children: draftLabel(draft.data)
1369
1363
  }), draft.data && /* @__PURE__ */ jsxs("span", {
1370
1364
  className: "shrink-0",
1371
1365
  children: [
@@ -1378,7 +1372,7 @@ function ReviewDraftSheet(t0) {
1378
1372
  }), /* @__PURE__ */ jsx(SheetTitle, {
1379
1373
  className: "text-lg leading-snug font-semibold",
1380
1374
  children: headline
1381
- })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [draft.data?.kind === "regular" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetTitle, {
1375
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [draft.data ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SheetTitle, {
1382
1376
  className: "sr-only",
1383
1377
  children: draftLabel(draft.data)
1384
1378
  }), /* @__PURE__ */ jsx(DraftNameInput, {
@@ -1387,7 +1381,7 @@ function ReviewDraftSheet(t0) {
1387
1381
  draft: draft.data
1388
1382
  })] }) : /* @__PURE__ */ jsx(SheetTitle, {
1389
1383
  className: "text-base",
1390
- children: draft.data ? draftLabel(draft.data) : "Draft"
1384
+ children: "Draft"
1391
1385
  }), /* @__PURE__ */ jsx(SheetDescription, { children: draft.data ? `${draft.data.createdBy.name} · started ${timeAgo(draft.data.createdAt)}` : "Publishing applies this whole draft to Live." })] })
1392
1386
  });
1393
1387
  $[49] = draft.data;
@@ -1,22 +1,30 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
2
  import { c } from "react/compiler-runtime";
3
+ import * as React from "react";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
 
5
6
  //#region src/features/studio/components/Squareling.tsx
6
7
  /**
7
8
  * A squareling, drawn from the logo's shapes, with the knockout as eyes, looking right like the
8
- * mark. Its face and motion say what it is doing. The animations live in `studio.css`.
9
+ * mark, or at the editor while idle. Its face and motion say what it is doing. The animations
10
+ * live in `studio.css`.
9
11
  *
10
12
  * The agent's (the default) is the logo's square with its soft corner, in emerald. Each patroller
11
13
  * has its own, one family: the Translator is the logo's wide wedge, in violet, glancing across
12
14
  * while it works; the SEO manager is a tall block with the small shape's soft corner, in amber,
13
15
  * scanning down while it works.
16
+ *
17
+ * One face flows into the next: its eyes glide to where the next face holds them, opening or
18
+ * narrowing, and a looping motion settles before the next one starts (`useFaceChange`).
14
19
  */
15
20
  function Squareling(props) {
16
- const $ = c(18);
21
+ const $ = c(24);
17
22
  const { status, className, ref } = props;
18
23
  const variant = props.variant ?? "agent";
19
24
  const look = LOOKS[variant];
25
+ const body = React.useRef(null);
26
+ const [firstFace] = React.useState(status);
27
+ useFaceChange(body, status);
20
28
  const t0 = variant === "agent" ? void 0 : variant;
21
29
  let t1;
22
30
  if ($[0] !== className) {
@@ -25,65 +33,133 @@ function Squareling(props) {
25
33
  $[1] = t1;
26
34
  } else t1 = $[1];
27
35
  let t2;
28
- if ($[2] !== look.body || $[3] !== look.fill) {
29
- t2 = /* @__PURE__ */ jsx("path", {
36
+ if ($[2] !== look) {
37
+ t2 = towardsUs(look);
38
+ $[2] = look;
39
+ $[3] = t2;
40
+ } else t2 = $[3];
41
+ const t3 = `${t2}px`;
42
+ let t4;
43
+ if ($[4] !== t3) {
44
+ t4 = { "--squareling-towards-us": t3 };
45
+ $[4] = t3;
46
+ $[5] = t4;
47
+ } else t4 = $[5];
48
+ const t5 = t4;
49
+ let t6;
50
+ if ($[6] !== look.body || $[7] !== look.fill) {
51
+ t6 = /* @__PURE__ */ jsx("path", {
30
52
  d: look.body,
31
53
  className: look.fill
32
54
  });
33
- $[2] = look.body;
34
- $[3] = look.fill;
35
- $[4] = t2;
36
- } else t2 = $[4];
37
- let t3;
38
- if ($[5] !== look.eyes || $[6] !== props.status || $[7] !== props.variant) {
39
- t3 = /* @__PURE__ */ jsx("g", {
40
- className: "squareling-eyes fill-neutral-950",
41
- children: props.variant === void 0 || props.variant === "agent" ? /* @__PURE__ */ jsx(AgentEyes, {
42
- eyes: look.eyes,
43
- status: props.status
44
- }) : /* @__PURE__ */ jsx(PatrollerEyes, {
45
- eyes: look.eyes,
46
- working: props.status === "working"
55
+ $[6] = look.body;
56
+ $[7] = look.fill;
57
+ $[8] = t6;
58
+ } else t6 = $[8];
59
+ let t7;
60
+ if ($[9] !== look.eyes || $[10] !== props.status || $[11] !== props.variant) {
61
+ t7 = /* @__PURE__ */ jsx("g", {
62
+ className: "squareling-gaze",
63
+ children: /* @__PURE__ */ jsx("g", {
64
+ className: "squareling-eyes fill-neutral-950",
65
+ children: props.variant === void 0 || props.variant === "agent" ? /* @__PURE__ */ jsx(AgentEyes, {
66
+ eyes: look.eyes,
67
+ status: props.status
68
+ }) : /* @__PURE__ */ jsx(PatrollerEyes, {
69
+ eyes: look.eyes,
70
+ working: props.status === "working"
71
+ })
47
72
  })
48
73
  });
49
- $[5] = look.eyes;
50
- $[6] = props.status;
51
- $[7] = props.variant;
52
- $[8] = t3;
53
- } else t3 = $[8];
54
- let t4;
55
- if ($[9] !== t2 || $[10] !== t3) {
56
- t4 = /* @__PURE__ */ jsxs("g", {
74
+ $[9] = look.eyes;
75
+ $[10] = props.status;
76
+ $[11] = props.variant;
77
+ $[12] = t7;
78
+ } else t7 = $[12];
79
+ let t8;
80
+ if ($[13] !== t6 || $[14] !== t7) {
81
+ t8 = /* @__PURE__ */ jsxs("g", {
82
+ ref: body,
57
83
  className: "squareling-body",
58
- children: [t2, t3]
84
+ children: [t6, t7]
59
85
  });
60
- $[9] = t2;
61
- $[10] = t3;
62
- $[11] = t4;
63
- } else t4 = $[11];
64
- let t5;
65
- if ($[12] !== ref || $[13] !== status || $[14] !== t0 || $[15] !== t1 || $[16] !== t4) {
66
- t5 = /* @__PURE__ */ jsx("svg", {
86
+ $[13] = t6;
87
+ $[14] = t7;
88
+ $[15] = t8;
89
+ } else t8 = $[15];
90
+ let t9;
91
+ if ($[16] !== firstFace || $[17] !== ref || $[18] !== status || $[19] !== t0 || $[20] !== t1 || $[21] !== t5 || $[22] !== t8) {
92
+ t9 = /* @__PURE__ */ jsx("svg", {
67
93
  ref,
68
94
  viewBox: "0 0 100 100",
69
95
  "aria-hidden": true,
70
96
  "data-squareling": status,
97
+ "data-face": firstFace,
71
98
  "data-squareling-variant": t0,
72
99
  className: t1,
73
- children: t4
100
+ style: t5,
101
+ children: t8
74
102
  });
75
- $[12] = ref;
76
- $[13] = status;
77
- $[14] = t0;
78
- $[15] = t1;
79
- $[16] = t4;
80
- $[17] = t5;
81
- } else t5 = $[17];
82
- return t5;
103
+ $[16] = firstFace;
104
+ $[17] = ref;
105
+ $[18] = status;
106
+ $[19] = t0;
107
+ $[20] = t1;
108
+ $[21] = t5;
109
+ $[22] = t8;
110
+ $[23] = t9;
111
+ } else t9 = $[23];
112
+ return t9;
113
+ }
114
+ /**
115
+ * How long a looping motion takes to settle when the face changes, in ms. `studio.css` delays
116
+ * each face's loop by as much, so it starts from rest.
117
+ */
118
+ const SETTLE_DURATION = 300;
119
+ /**
120
+ * Changes the face `studio.css` animates to `status`, settling the one before: the body and the
121
+ * eyes ease from wherever their loop had them back to rest, where the next loop starts. Without
122
+ * motion for editors who reduce it.
123
+ */
124
+ function useFaceChange(body, status) {
125
+ const $ = c(4);
126
+ let t0;
127
+ let t1;
128
+ if ($[0] !== body || $[1] !== status) {
129
+ t0 = () => {
130
+ const svg = body.current?.ownerSVGElement;
131
+ if (!body.current || !svg || svg.getAttribute("data-face") === status) return;
132
+ const moving = [body.current, ...body.current.querySelectorAll(".squareling-eyes")];
133
+ const where = moving.map(_temp);
134
+ svg.setAttribute("data-face", status);
135
+ if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
136
+ for (const [index, part_0] of moving.entries()) {
137
+ const from = where[index];
138
+ if (!from || from === "none") continue;
139
+ part_0.animate([{ transform: from }, { transform: "none" }], {
140
+ duration: SETTLE_DURATION,
141
+ easing: "cubic-bezier(0.23, 1, 0.32, 1)"
142
+ });
143
+ }
144
+ };
145
+ t1 = [body, status];
146
+ $[0] = body;
147
+ $[1] = status;
148
+ $[2] = t0;
149
+ $[3] = t1;
150
+ } else {
151
+ t0 = $[2];
152
+ t1 = $[3];
153
+ }
154
+ React.useLayoutEffect(t0, t1);
155
+ }
156
+ function _temp(part) {
157
+ return getComputedStyle(part).transform;
83
158
  }
84
159
  const LOOKS = {
85
160
  agent: {
86
161
  body: "M20 12H80Q88 12 88 20V64Q88 88 64 88H20Q12 88 12 80V20Q12 12 20 12Z",
162
+ middle: 50,
87
163
  fill: "fill-emerald-500",
88
164
  eyes: {
89
165
  x: [50, 69],
@@ -92,6 +168,7 @@ const LOOKS = {
92
168
  },
93
169
  translator: {
94
170
  body: "M14 14H86Q92 14 89.6 19.5L67.3 69.6Q60 86 42 86H14Q8 86 8 80V20Q8 14 14 14Z",
171
+ middle: 45,
95
172
  fill: "fill-violet-500",
96
173
  eyes: {
97
174
  x: [40, 59],
@@ -100,6 +177,7 @@ const LOOKS = {
100
177
  },
101
178
  seoManager: {
102
179
  body: "M20 32Q20 8 44 8H74Q80 8 80 14V86Q80 92 74 92H26Q20 92 20 86Z",
180
+ middle: 50,
103
181
  fill: "fill-amber-500",
104
182
  eyes: {
105
183
  x: [44, 63],
@@ -108,47 +186,67 @@ const LOOKS = {
108
186
  }
109
187
  };
110
188
  const EYE_WIDTH = 11;
189
+ /** How far the eyes move across for the squareling to look at the editor: to its face's middle. */
190
+ const towardsUs = ({ middle, eyes: { x } }) => middle - (x[0] + x[1] + EYE_WIDTH) / 2;
111
191
  const OPEN = 17;
112
192
  const NARROWED = 6;
113
- /** How far down a narrowed eye sits, from the top of the open one. */
114
- const NARROWED_OFFSET = 8;
193
+ /** How far down a narrowed eye's middle sits, from the open one's. */
194
+ const NARROWED_SHIFT = 2.5;
115
195
  /**
116
- * One eye, its left edge at `x` and its top at `y` while open: open, or narrowed on the work.
117
- * Only an eye that blinks carries the class `studio.css` blinks.
196
+ * One eye, its left edge at `x` and its top at `y`: open, or narrowed on the work, lower down.
197
+ * It narrows by scaling, which `studio.css` eases. Only an eye that blinks carries the class
198
+ * `studio.css` blinks.
118
199
  */
119
200
  function Eye(t0) {
120
- const $ = c(5);
201
+ const $ = c(9);
121
202
  const { x, y, narrowed, blinks } = t0;
122
- const t1 = blinks ? "squareling-eye" : void 0;
123
- const t2 = narrowed ? y + NARROWED_OFFSET : y;
124
- const t3 = narrowed ? NARROWED : OPEN;
203
+ const t1 = blinks && "squareling-blinks";
204
+ let t2;
205
+ if ($[0] !== t1) {
206
+ t2 = cn("squareling-eye", t1);
207
+ $[0] = t1;
208
+ $[1] = t2;
209
+ } else t2 = $[1];
210
+ let t3;
211
+ if ($[2] !== narrowed) {
212
+ t3 = narrowed ? {
213
+ scale: `1 ${NARROWED / OPEN}`,
214
+ translate: `0 ${NARROWED_SHIFT}px`
215
+ } : {
216
+ scale: "1",
217
+ translate: "0"
218
+ };
219
+ $[2] = narrowed;
220
+ $[3] = t3;
221
+ } else t3 = $[3];
125
222
  let t4;
126
- if ($[0] !== t1 || $[1] !== t2 || $[2] !== t3 || $[3] !== x) {
223
+ if ($[4] !== t2 || $[5] !== t3 || $[6] !== x || $[7] !== y) {
127
224
  t4 = /* @__PURE__ */ jsx("rect", {
128
- className: t1,
225
+ className: t2,
129
226
  x,
130
- y: t2,
227
+ y,
131
228
  width: EYE_WIDTH,
132
- height: t3
229
+ height: OPEN,
230
+ style: t3
133
231
  });
134
- $[0] = t1;
135
- $[1] = t2;
136
- $[2] = t3;
137
- $[3] = x;
138
- $[4] = t4;
139
- } else t4 = $[4];
232
+ $[4] = t2;
233
+ $[5] = t3;
234
+ $[6] = x;
235
+ $[7] = y;
236
+ $[8] = t4;
237
+ } else t4 = $[8];
140
238
  return t4;
141
239
  }
142
240
  /**
143
- * The agent's eyes: open, blinking, while idle or thinking; both narrowed while acting; the
144
- * right one narrowed while fixing.
241
+ * The agent's eyes: both narrowed on the work while making changes, the right one while fixing,
242
+ * open otherwise, blinking unless it looks around.
145
243
  */
146
244
  function AgentEyes(t0) {
147
245
  const $ = c(13);
148
246
  const { eyes, status } = t0;
149
247
  const [left, right] = eyes.x;
150
- const blinks = status === "idle" || status === "thinking";
151
- const t1 = status === "acting";
248
+ const blinks = status !== "exploring" && status !== "changing";
249
+ const t1 = status === "changing";
152
250
  let t2;
153
251
  if ($[0] !== blinks || $[1] !== eyes.y || $[2] !== left || $[3] !== t1) {
154
252
  t2 = /* @__PURE__ */ jsx(Eye, {
@@ -163,7 +261,7 @@ function AgentEyes(t0) {
163
261
  $[3] = t1;
164
262
  $[4] = t2;
165
263
  } else t2 = $[4];
166
- const t3 = status === "acting" || status === "fixing";
264
+ const t3 = status === "changing" || status === "fixing";
167
265
  let t4;
168
266
  if ($[5] !== blinks || $[6] !== eyes.y || $[7] !== right || $[8] !== t3) {
169
267
  t4 = /* @__PURE__ */ jsx(Eye, {
@@ -1,17 +1,18 @@
1
1
  import { c } from "react/compiler-runtime";
2
2
  import { useState } from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import { ArrowUp, Square } from "lucide-react";
4
+ import { ArrowUp, Square, SquareDashedMousePointer, X } from "lucide-react";
5
5
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@camox/ui/input-group";
6
6
 
7
7
  //#region src/features/studio/components/ThreadComposer.tsx
8
8
  /**
9
9
  * Where an editor writes to the agent: Enter sends, Shift+Enter adds a line. While a run is
10
- * going, sending steers it, and a Stop button sits beside Send.
10
+ * going, sending steers it, and a Stop button sits beside Send. Over the message, what the
11
+ * editor has selected, which their messages carry to the agent until they clear it.
11
12
  */
12
13
  function ThreadComposer(t0) {
13
- const $ = c(32);
14
- const { onSend, onStop, running: t1, disabled: t2 } = t0;
14
+ const $ = c(36);
15
+ const { onSend, onStop, selection, onClearSelection, running: t1, disabled: t2 } = t0;
15
16
  const running = t1 === void 0 ? false : t1;
16
17
  const disabled = t2 === void 0 ? false : t2;
17
18
  const [text, setText] = useState("");
@@ -46,39 +47,53 @@ function ThreadComposer(t0) {
46
47
  $[7] = t5;
47
48
  } else t5 = $[7];
48
49
  let t6;
49
- if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
50
- t6 = (event_0) => setText(event_0.target.value);
51
- $[8] = t6;
52
- } else t6 = $[8];
50
+ if ($[8] !== onClearSelection || $[9] !== selection) {
51
+ t6 = selection && /* @__PURE__ */ jsx(InputGroupAddon, {
52
+ align: "block-start",
53
+ className: "border-input border-b",
54
+ children: /* @__PURE__ */ jsx(SelectionChip, {
55
+ name: selection,
56
+ onClear: onClearSelection
57
+ })
58
+ });
59
+ $[8] = onClearSelection;
60
+ $[9] = selection;
61
+ $[10] = t6;
62
+ } else t6 = $[10];
53
63
  let t7;
54
- if ($[9] !== submit) {
55
- t7 = (event_1) => {
64
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
65
+ t7 = (event_0) => setText(event_0.target.value);
66
+ $[11] = t7;
67
+ } else t7 = $[11];
68
+ let t8;
69
+ if ($[12] !== submit) {
70
+ t8 = (event_1) => {
56
71
  if (event_1.key !== "Enter" || event_1.shiftKey || event_1.nativeEvent.isComposing) return;
57
72
  event_1.preventDefault();
58
73
  submit();
59
74
  };
60
- $[9] = submit;
61
- $[10] = t7;
62
- } else t7 = $[10];
63
- let t8;
64
- if ($[11] !== disabled || $[12] !== t7 || $[13] !== text) {
65
- t8 = /* @__PURE__ */ jsx(InputGroupTextarea, {
75
+ $[12] = submit;
76
+ $[13] = t8;
77
+ } else t8 = $[13];
78
+ let t9;
79
+ if ($[14] !== disabled || $[15] !== t8 || $[16] !== text) {
80
+ t9 = /* @__PURE__ */ jsx(InputGroupTextarea, {
66
81
  "aria-label": "Message",
67
82
  placeholder: "Message Camox…",
68
83
  value: text,
69
84
  disabled,
70
- onChange: t6,
71
- onKeyDown: t7,
85
+ onChange: t7,
86
+ onKeyDown: t8,
72
87
  className: "max-h-48 min-h-14"
73
88
  });
74
- $[11] = disabled;
75
- $[12] = t7;
76
- $[13] = text;
77
- $[14] = t8;
78
- } else t8 = $[14];
79
- let t9;
80
- if ($[15] !== disabled || $[16] !== onStop || $[17] !== running) {
81
- t9 = running && onStop && /* @__PURE__ */ jsxs(InputGroupButton, {
89
+ $[14] = disabled;
90
+ $[15] = t8;
91
+ $[16] = text;
92
+ $[17] = t9;
93
+ } else t9 = $[17];
94
+ let t10;
95
+ if ($[18] !== disabled || $[19] !== onStop || $[20] !== running) {
96
+ t10 = running && onStop && /* @__PURE__ */ jsxs(InputGroupButton, {
82
97
  type: "button",
83
98
  variant: "outline",
84
99
  size: "icon-sm",
@@ -89,68 +104,123 @@ function ThreadComposer(t0) {
89
104
  children: "Stop"
90
105
  })]
91
106
  });
92
- $[15] = disabled;
93
- $[16] = onStop;
94
- $[17] = running;
95
- $[18] = t9;
96
- } else t9 = $[18];
97
- const t10 = !canSend;
98
- let t11;
107
+ $[18] = disabled;
108
+ $[19] = onStop;
109
+ $[20] = running;
110
+ $[21] = t10;
111
+ } else t10 = $[21];
112
+ const t11 = !canSend;
99
113
  let t12;
100
- if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
101
- t11 = /* @__PURE__ */ jsx(ArrowUp, {});
102
- t12 = /* @__PURE__ */ jsx("span", {
114
+ let t13;
115
+ if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
116
+ t12 = /* @__PURE__ */ jsx(ArrowUp, {});
117
+ t13 = /* @__PURE__ */ jsx("span", {
103
118
  className: "sr-only",
104
119
  children: "Send"
105
120
  });
106
- $[19] = t11;
107
- $[20] = t12;
121
+ $[22] = t12;
122
+ $[23] = t13;
108
123
  } else {
109
- t11 = $[19];
110
- t12 = $[20];
124
+ t12 = $[22];
125
+ t13 = $[23];
111
126
  }
112
- let t13;
113
- if ($[21] !== t10) {
114
- t13 = /* @__PURE__ */ jsxs(InputGroupButton, {
127
+ let t14;
128
+ if ($[24] !== t11) {
129
+ t14 = /* @__PURE__ */ jsxs(InputGroupButton, {
115
130
  type: "submit",
116
131
  variant: "default",
117
132
  size: "icon-sm",
118
- disabled: t10,
119
- children: [t11, t12]
120
- });
121
- $[21] = t10;
122
- $[22] = t13;
123
- } else t13 = $[22];
124
- let t14;
125
- if ($[23] !== t13 || $[24] !== t9) {
126
- t14 = /* @__PURE__ */ jsxs(InputGroupAddon, {
127
- align: "block-end",
128
- className: "justify-end",
129
- children: [t9, t13]
133
+ disabled: t11,
134
+ children: [t12, t13]
130
135
  });
131
- $[23] = t13;
132
- $[24] = t9;
136
+ $[24] = t11;
133
137
  $[25] = t14;
134
138
  } else t14 = $[25];
135
139
  let t15;
136
- if ($[26] !== t14 || $[27] !== t8) {
137
- t15 = /* @__PURE__ */ jsxs(InputGroup, { children: [t8, t14] });
138
- $[26] = t14;
139
- $[27] = t8;
140
+ if ($[26] !== t10 || $[27] !== t14) {
141
+ t15 = /* @__PURE__ */ jsxs(InputGroupAddon, {
142
+ align: "block-end",
143
+ className: "justify-end",
144
+ children: [t10, t14]
145
+ });
146
+ $[26] = t10;
147
+ $[27] = t14;
140
148
  $[28] = t15;
141
149
  } else t15 = $[28];
142
150
  let t16;
143
- if ($[29] !== t15 || $[30] !== t5) {
144
- t16 = /* @__PURE__ */ jsx("form", {
151
+ if ($[29] !== t15 || $[30] !== t6 || $[31] !== t9) {
152
+ t16 = /* @__PURE__ */ jsxs(InputGroup, { children: [
153
+ t6,
154
+ t9,
155
+ t15
156
+ ] });
157
+ $[29] = t15;
158
+ $[30] = t6;
159
+ $[31] = t9;
160
+ $[32] = t16;
161
+ } else t16 = $[32];
162
+ let t17;
163
+ if ($[33] !== t16 || $[34] !== t5) {
164
+ t17 = /* @__PURE__ */ jsx("form", {
145
165
  className: "p-2",
146
166
  onSubmit: t5,
147
- children: t15
167
+ children: t16
148
168
  });
149
- $[29] = t15;
150
- $[30] = t5;
151
- $[31] = t16;
152
- } else t16 = $[31];
153
- return t16;
169
+ $[33] = t16;
170
+ $[34] = t5;
171
+ $[35] = t17;
172
+ } else t17 = $[35];
173
+ return t17;
174
+ }
175
+ /** The selection the editor's messages carry, by its name. */
176
+ function SelectionChip(t0) {
177
+ const $ = c(8);
178
+ const { name, onClear } = t0;
179
+ let t1;
180
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
181
+ t1 = /* @__PURE__ */ jsx(SquareDashedMousePointer, { className: "text-muted-foreground size-3.5 shrink-0" });
182
+ $[0] = t1;
183
+ } else t1 = $[0];
184
+ let t2;
185
+ if ($[1] !== name) {
186
+ t2 = /* @__PURE__ */ jsx("span", {
187
+ className: "min-w-0 truncate font-medium",
188
+ children: name
189
+ });
190
+ $[1] = name;
191
+ $[2] = t2;
192
+ } else t2 = $[2];
193
+ let t3;
194
+ if ($[3] !== onClear) {
195
+ t3 = onClear && /* @__PURE__ */ jsxs(InputGroupButton, {
196
+ type: "button",
197
+ size: "icon-xs",
198
+ className: "text-muted-foreground hover:text-foreground size-5 shrink-0",
199
+ onClick: onClear,
200
+ children: [/* @__PURE__ */ jsx(X, { className: "size-3" }), /* @__PURE__ */ jsx("span", {
201
+ className: "sr-only",
202
+ children: "Clear selection"
203
+ })]
204
+ });
205
+ $[3] = onClear;
206
+ $[4] = t3;
207
+ } else t3 = $[4];
208
+ let t4;
209
+ if ($[5] !== t2 || $[6] !== t3) {
210
+ t4 = /* @__PURE__ */ jsxs("div", {
211
+ "aria-label": "Selection",
212
+ className: "bg-muted text-foreground flex h-6 max-w-full min-w-0 cursor-default items-center gap-1 rounded-sm pr-0.5 pl-1.5 text-xs",
213
+ children: [
214
+ t1,
215
+ t2,
216
+ t3
217
+ ]
218
+ });
219
+ $[5] = t2;
220
+ $[6] = t3;
221
+ $[7] = t4;
222
+ } else t4 = $[7];
223
+ return t4;
154
224
  }
155
225
 
156
226
  //#endregion