camox 0.78.0 → 0.79.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.
- package/dist/features/memory/CamoxMemory.js +47 -38
- package/dist/features/memory/VoiceGroup.js +350 -0
- package/dist/features/studio/components/DraftReview.js +52 -29
- package/dist/features/vite/vite.js +1 -0
- package/dist/lib/queries.js +6 -2
- package/dist/lib/studio-reads.d.ts +1 -0
- package/dist/lib/studio-reads.js +6 -0
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
|
@@ -6,6 +6,7 @@ import { previewStore } from "../preview/previewStore.js";
|
|
|
6
6
|
import { studioStore } from "../studio/studioStore.js";
|
|
7
7
|
import { timeAgo } from "../studio/draftLabel.js";
|
|
8
8
|
import { useWebsiteHref } from "../studio/components/Navbar.js";
|
|
9
|
+
import { VoiceGroup } from "./VoiceGroup.js";
|
|
9
10
|
import { c } from "react/compiler-runtime";
|
|
10
11
|
import * as React from "react";
|
|
11
12
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -76,7 +77,7 @@ const Loading = () => {
|
|
|
76
77
|
};
|
|
77
78
|
const words = (count) => `${count.toLocaleString("en")} word${count === 1 ? "" : "s"}`;
|
|
78
79
|
function ProjectMemory(t0) {
|
|
79
|
-
const $ = c(
|
|
80
|
+
const $ = c(21);
|
|
80
81
|
const { projectId } = t0;
|
|
81
82
|
let t1;
|
|
82
83
|
if ($[0] !== projectId) {
|
|
@@ -95,41 +96,47 @@ function ProjectMemory(t0) {
|
|
|
95
96
|
}
|
|
96
97
|
const room = Math.max(data.limitWords - data.usedWords, 0);
|
|
97
98
|
let t2;
|
|
99
|
+
let t3;
|
|
98
100
|
if ($[3] !== projectId) {
|
|
99
|
-
t2 = /* @__PURE__ */ jsx(
|
|
101
|
+
t2 = /* @__PURE__ */ jsx(VoiceGroup, { projectId });
|
|
102
|
+
t3 = /* @__PURE__ */ jsx(AddMemory, { projectId });
|
|
100
103
|
$[3] = projectId;
|
|
101
104
|
$[4] = t2;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
t3 =
|
|
106
|
-
|
|
107
|
-
$[6] = t3;
|
|
108
|
-
} else t3 = $[6];
|
|
105
|
+
$[5] = t3;
|
|
106
|
+
} else {
|
|
107
|
+
t2 = $[4];
|
|
108
|
+
t3 = $[5];
|
|
109
|
+
}
|
|
109
110
|
let t4;
|
|
110
|
-
if ($[
|
|
111
|
-
t4 =
|
|
112
|
-
$[
|
|
113
|
-
$[
|
|
114
|
-
} else t4 = $[
|
|
111
|
+
if ($[6] !== room) {
|
|
112
|
+
t4 = words(room);
|
|
113
|
+
$[6] = room;
|
|
114
|
+
$[7] = t4;
|
|
115
|
+
} else t4 = $[7];
|
|
115
116
|
let t5;
|
|
116
|
-
if ($[
|
|
117
|
-
t5 =
|
|
117
|
+
if ($[8] !== data.limitWords) {
|
|
118
|
+
t5 = data.limitWords.toLocaleString("en");
|
|
119
|
+
$[8] = data.limitWords;
|
|
120
|
+
$[9] = t5;
|
|
121
|
+
} else t5 = $[9];
|
|
122
|
+
let t6;
|
|
123
|
+
if ($[10] !== t4 || $[11] !== t5) {
|
|
124
|
+
t6 = /* @__PURE__ */ jsxs("p", {
|
|
118
125
|
"data-memory-room": true,
|
|
119
126
|
className: "text-muted-foreground text-xs",
|
|
120
127
|
children: [
|
|
121
|
-
|
|
128
|
+
t4,
|
|
122
129
|
" left of ",
|
|
123
|
-
|
|
130
|
+
t5
|
|
124
131
|
]
|
|
125
132
|
});
|
|
126
|
-
$[9] = t3;
|
|
127
133
|
$[10] = t4;
|
|
128
134
|
$[11] = t5;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
$[12] = t6;
|
|
136
|
+
} else t6 = $[12];
|
|
137
|
+
let t7;
|
|
138
|
+
if ($[13] !== data.memories || $[14] !== projectId) {
|
|
139
|
+
t7 = data.memories.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
133
140
|
"data-memory-empty": true,
|
|
134
141
|
className: "text-muted-foreground py-6 text-sm",
|
|
135
142
|
children: "Camox's agent remembers what members teach it that holds beyond one request and that the website can't show, such as how the business talks, what sets it apart, or rules like \"never use usted\". What it remembers in a draft applies there at once, and reaches the live website when the draft is published. Nothing yet: it learns as you work with it, or add a memory yourself."
|
|
@@ -141,23 +148,25 @@ function ProjectMemory(t0) {
|
|
|
141
148
|
memory
|
|
142
149
|
}, memory.id))
|
|
143
150
|
});
|
|
144
|
-
$[
|
|
145
|
-
$[
|
|
146
|
-
$[
|
|
147
|
-
} else
|
|
148
|
-
let
|
|
149
|
-
if ($[
|
|
150
|
-
|
|
151
|
+
$[13] = data.memories;
|
|
152
|
+
$[14] = projectId;
|
|
153
|
+
$[15] = t7;
|
|
154
|
+
} else t7 = $[15];
|
|
155
|
+
let t8;
|
|
156
|
+
if ($[16] !== t2 || $[17] !== t3 || $[18] !== t6 || $[19] !== t7) {
|
|
157
|
+
t8 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
158
|
t2,
|
|
152
|
-
|
|
153
|
-
t6
|
|
159
|
+
t3,
|
|
160
|
+
t6,
|
|
161
|
+
t7
|
|
154
162
|
] });
|
|
155
|
-
$[
|
|
156
|
-
$[
|
|
157
|
-
$[
|
|
158
|
-
$[
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
$[16] = t2;
|
|
164
|
+
$[17] = t3;
|
|
165
|
+
$[18] = t6;
|
|
166
|
+
$[19] = t7;
|
|
167
|
+
$[20] = t8;
|
|
168
|
+
} else t8 = $[20];
|
|
169
|
+
return t8;
|
|
161
170
|
}
|
|
162
171
|
/** Refreshes the memory a write changed. On Live, the write started a draft, which it reads. */
|
|
163
172
|
function useRefreshMemory(projectId) {
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { useDraftScope } from "../../lib/draft-scope.js";
|
|
2
|
+
import { useNavigate } from "../navigation/navigation.js";
|
|
3
|
+
import { reads, useReadQuery, useStudioCache } from "../../lib/studio-reads.js";
|
|
4
|
+
import { memoryMutations } from "../../lib/queries.js";
|
|
5
|
+
import { previewStore } from "../preview/previewStore.js";
|
|
6
|
+
import { useWebsiteHref } from "../studio/components/Navbar.js";
|
|
7
|
+
import { c } from "react/compiler-runtime";
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { useMutation } from "@tanstack/react-query";
|
|
11
|
+
import { Button } from "@camox/ui/button";
|
|
12
|
+
import { Skeleton } from "@camox/ui/skeleton";
|
|
13
|
+
import { Spinner } from "@camox/ui/spinner";
|
|
14
|
+
import { VOICE_AXES } from "@camox/api-contract/voice";
|
|
15
|
+
import { Slider } from "@camox/ui/slider";
|
|
16
|
+
|
|
17
|
+
//#region src/features/memory/VoiceGroup.tsx
|
|
18
|
+
/**
|
|
19
|
+
* The Voice group, at the top of the Memory Section (ADR 0051): a slider per Voice Axis, showing
|
|
20
|
+
* its chosen step and that step's definition, as models read it. Moving sliders saves nothing:
|
|
21
|
+
* Save shows while they differ from the saved Voice, and saves every moved axis as one change.
|
|
22
|
+
* Like any memory edit, saving while viewing Live starts a draft. "Save and rewrite", beside it,
|
|
23
|
+
* also asks Camox's agent, as the member, to rewrite the site's copy in the new Voice, and shows
|
|
24
|
+
* the draft with its thread beside the Canvas, where the rewrite happens.
|
|
25
|
+
*/
|
|
26
|
+
function VoiceGroup(t0) {
|
|
27
|
+
const $ = c(31);
|
|
28
|
+
const { projectId } = t0;
|
|
29
|
+
let t1;
|
|
30
|
+
if ($[0] !== projectId) {
|
|
31
|
+
t1 = reads.voice({ projectId });
|
|
32
|
+
$[0] = projectId;
|
|
33
|
+
$[1] = t1;
|
|
34
|
+
} else t1 = $[1];
|
|
35
|
+
const { data: saved } = useReadQuery(t1);
|
|
36
|
+
let t2;
|
|
37
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
38
|
+
t2 = {};
|
|
39
|
+
$[2] = t2;
|
|
40
|
+
} else t2 = $[2];
|
|
41
|
+
const [moved, setMoved] = React.useState(t2);
|
|
42
|
+
const cache = useStudioCache();
|
|
43
|
+
const draftScope = useDraftScope();
|
|
44
|
+
const navigate = useNavigate();
|
|
45
|
+
const websiteHref = useWebsiteHref();
|
|
46
|
+
let t3;
|
|
47
|
+
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
|
|
48
|
+
t3 = memoryMutations.saveVoice();
|
|
49
|
+
$[3] = t3;
|
|
50
|
+
} else t3 = $[3];
|
|
51
|
+
let t4;
|
|
52
|
+
if ($[4] !== cache || $[5] !== draftScope || $[6] !== navigate || $[7] !== projectId || $[8] !== websiteHref) {
|
|
53
|
+
t4 = {
|
|
54
|
+
...t3,
|
|
55
|
+
onSuccess: (_voice, t5) => {
|
|
56
|
+
const { rewrite } = t5;
|
|
57
|
+
setMoved({});
|
|
58
|
+
cache.invalidate(reads.voice({ projectId }));
|
|
59
|
+
if (!rewrite) return;
|
|
60
|
+
previewStore.send({ type: "showCanvas" });
|
|
61
|
+
navigate({
|
|
62
|
+
to: websiteHref(),
|
|
63
|
+
draft: draftScope.current() ?? void 0
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
$[4] = cache;
|
|
68
|
+
$[5] = draftScope;
|
|
69
|
+
$[6] = navigate;
|
|
70
|
+
$[7] = projectId;
|
|
71
|
+
$[8] = websiteHref;
|
|
72
|
+
$[9] = t4;
|
|
73
|
+
} else t4 = $[9];
|
|
74
|
+
const save = useMutation(t4);
|
|
75
|
+
if (!saved) {
|
|
76
|
+
let t5;
|
|
77
|
+
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
|
|
78
|
+
t5 = /* @__PURE__ */ jsx(Skeleton, { className: "h-72" });
|
|
79
|
+
$[10] = t5;
|
|
80
|
+
} else t5 = $[10];
|
|
81
|
+
return t5;
|
|
82
|
+
}
|
|
83
|
+
let t5;
|
|
84
|
+
let voice;
|
|
85
|
+
if ($[11] !== moved || $[12] !== saved) {
|
|
86
|
+
voice = {
|
|
87
|
+
...saved,
|
|
88
|
+
...moved
|
|
89
|
+
};
|
|
90
|
+
t5 = changedAxes(saved, voice);
|
|
91
|
+
$[11] = moved;
|
|
92
|
+
$[12] = saved;
|
|
93
|
+
$[13] = t5;
|
|
94
|
+
$[14] = voice;
|
|
95
|
+
} else {
|
|
96
|
+
t5 = $[13];
|
|
97
|
+
voice = $[14];
|
|
98
|
+
}
|
|
99
|
+
const changed = t5;
|
|
100
|
+
let t6;
|
|
101
|
+
if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
|
|
102
|
+
t6 = /* @__PURE__ */ jsxs("header", {
|
|
103
|
+
className: "flex flex-col gap-1",
|
|
104
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
105
|
+
id: "camox-voice-title",
|
|
106
|
+
className: "text-sm font-semibold",
|
|
107
|
+
children: "Voice"
|
|
108
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
109
|
+
className: "text-muted-foreground text-xs",
|
|
110
|
+
children: "How the website speaks. Every model that writes for visitors keeps to it."
|
|
111
|
+
})]
|
|
112
|
+
});
|
|
113
|
+
$[15] = t6;
|
|
114
|
+
} else t6 = $[15];
|
|
115
|
+
let t7;
|
|
116
|
+
if ($[16] !== save || $[17] !== voice) {
|
|
117
|
+
t7 = VOICE_AXES.map((axis) => /* @__PURE__ */ jsx(VoiceAxisRow, {
|
|
118
|
+
axis,
|
|
119
|
+
step: voice[axis.key],
|
|
120
|
+
disabled: save.isPending,
|
|
121
|
+
onStep: (step) => {
|
|
122
|
+
setMoved((current) => ({
|
|
123
|
+
...current,
|
|
124
|
+
[axis.key]: step
|
|
125
|
+
}));
|
|
126
|
+
save.reset();
|
|
127
|
+
}
|
|
128
|
+
}, axis.key));
|
|
129
|
+
$[16] = save;
|
|
130
|
+
$[17] = voice;
|
|
131
|
+
$[18] = t7;
|
|
132
|
+
} else t7 = $[18];
|
|
133
|
+
let t8;
|
|
134
|
+
if ($[19] !== t7) {
|
|
135
|
+
t8 = /* @__PURE__ */ jsx("ul", {
|
|
136
|
+
className: "flex flex-col gap-5",
|
|
137
|
+
children: t7
|
|
138
|
+
});
|
|
139
|
+
$[19] = t7;
|
|
140
|
+
$[20] = t8;
|
|
141
|
+
} else t8 = $[20];
|
|
142
|
+
let t9;
|
|
143
|
+
if ($[21] !== save.error) {
|
|
144
|
+
t9 = save.error && /* @__PURE__ */ jsx("p", {
|
|
145
|
+
"data-voice-error": true,
|
|
146
|
+
className: "text-destructive text-xs",
|
|
147
|
+
children: save.error.message
|
|
148
|
+
});
|
|
149
|
+
$[21] = save.error;
|
|
150
|
+
$[22] = t9;
|
|
151
|
+
} else t9 = $[22];
|
|
152
|
+
let t10;
|
|
153
|
+
if ($[23] !== changed || $[24] !== projectId || $[25] !== save) {
|
|
154
|
+
t10 = Object.keys(changed).length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
155
|
+
className: "flex flex-wrap gap-2",
|
|
156
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
157
|
+
disabled: save.isPending,
|
|
158
|
+
onClick: () => save.mutate({
|
|
159
|
+
projectId,
|
|
160
|
+
steps: changed
|
|
161
|
+
}),
|
|
162
|
+
children: [save.isPending && !save.variables?.rewrite && /* @__PURE__ */ jsx(Spinner, {}), "Save"]
|
|
163
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
164
|
+
variant: "outline",
|
|
165
|
+
disabled: save.isPending,
|
|
166
|
+
onClick: () => save.mutate({
|
|
167
|
+
projectId,
|
|
168
|
+
steps: changed,
|
|
169
|
+
rewrite: true
|
|
170
|
+
}),
|
|
171
|
+
children: [save.isPending && save.variables?.rewrite && /* @__PURE__ */ jsx(Spinner, {}), "Save and rewrite"]
|
|
172
|
+
})]
|
|
173
|
+
});
|
|
174
|
+
$[23] = changed;
|
|
175
|
+
$[24] = projectId;
|
|
176
|
+
$[25] = save;
|
|
177
|
+
$[26] = t10;
|
|
178
|
+
} else t10 = $[26];
|
|
179
|
+
let t11;
|
|
180
|
+
if ($[27] !== t10 || $[28] !== t8 || $[29] !== t9) {
|
|
181
|
+
t11 = /* @__PURE__ */ jsxs("section", {
|
|
182
|
+
"data-voice": true,
|
|
183
|
+
"aria-labelledby": "camox-voice-title",
|
|
184
|
+
className: "flex flex-col gap-5 rounded-lg border p-4",
|
|
185
|
+
children: [
|
|
186
|
+
t6,
|
|
187
|
+
t8,
|
|
188
|
+
t9,
|
|
189
|
+
t10
|
|
190
|
+
]
|
|
191
|
+
});
|
|
192
|
+
$[27] = t10;
|
|
193
|
+
$[28] = t8;
|
|
194
|
+
$[29] = t9;
|
|
195
|
+
$[30] = t11;
|
|
196
|
+
} else t11 = $[30];
|
|
197
|
+
return t11;
|
|
198
|
+
}
|
|
199
|
+
/** The axes `voice` moves away from `saved`, with their new steps. */
|
|
200
|
+
function changedAxes(saved, voice) {
|
|
201
|
+
const changed = {};
|
|
202
|
+
for (const { key } of VOICE_AXES) if (voice[key] !== saved[key]) changed[key] = voice[key];
|
|
203
|
+
return changed;
|
|
204
|
+
}
|
|
205
|
+
const sentenceCase = (text) => text.charAt(0).toUpperCase() + text.slice(1);
|
|
206
|
+
/** One Voice Axis: its name, its chosen step and that step's definition, over a slider. */
|
|
207
|
+
function VoiceAxisRow(t0) {
|
|
208
|
+
const $ = c(39);
|
|
209
|
+
const { axis, step, disabled, onStep } = t0;
|
|
210
|
+
const steps = axis.steps;
|
|
211
|
+
let t1;
|
|
212
|
+
if ($[0] !== step || $[1] !== steps) {
|
|
213
|
+
let t2;
|
|
214
|
+
if ($[3] !== step) {
|
|
215
|
+
t2 = (candidate) => candidate.key === step;
|
|
216
|
+
$[3] = step;
|
|
217
|
+
$[4] = t2;
|
|
218
|
+
} else t2 = $[4];
|
|
219
|
+
t1 = steps.findIndex(t2);
|
|
220
|
+
$[0] = step;
|
|
221
|
+
$[1] = steps;
|
|
222
|
+
$[2] = t1;
|
|
223
|
+
} else t1 = $[2];
|
|
224
|
+
const index = Math.max(t1, 0);
|
|
225
|
+
const chosen = steps[index];
|
|
226
|
+
let t2;
|
|
227
|
+
if ($[5] !== axis.name) {
|
|
228
|
+
t2 = /* @__PURE__ */ jsx("span", {
|
|
229
|
+
"data-voice-axis-name": true,
|
|
230
|
+
className: "font-medium",
|
|
231
|
+
children: axis.name
|
|
232
|
+
});
|
|
233
|
+
$[5] = axis.name;
|
|
234
|
+
$[6] = t2;
|
|
235
|
+
} else t2 = $[6];
|
|
236
|
+
let t3;
|
|
237
|
+
if ($[7] !== chosen.name) {
|
|
238
|
+
t3 = /* @__PURE__ */ jsx("span", {
|
|
239
|
+
"data-voice-step": true,
|
|
240
|
+
children: chosen.name
|
|
241
|
+
});
|
|
242
|
+
$[7] = chosen.name;
|
|
243
|
+
$[8] = t3;
|
|
244
|
+
} else t3 = $[8];
|
|
245
|
+
let t4;
|
|
246
|
+
if ($[9] !== t2 || $[10] !== t3) {
|
|
247
|
+
t4 = /* @__PURE__ */ jsxs("div", {
|
|
248
|
+
className: "flex items-baseline justify-between gap-3 text-sm",
|
|
249
|
+
children: [t2, t3]
|
|
250
|
+
});
|
|
251
|
+
$[9] = t2;
|
|
252
|
+
$[10] = t3;
|
|
253
|
+
$[11] = t4;
|
|
254
|
+
} else t4 = $[11];
|
|
255
|
+
const t5 = steps.length - 1;
|
|
256
|
+
let t6;
|
|
257
|
+
if ($[12] !== onStep || $[13] !== steps) {
|
|
258
|
+
t6 = (value) => {
|
|
259
|
+
const next = steps[value];
|
|
260
|
+
if (next) onStep(next.key);
|
|
261
|
+
};
|
|
262
|
+
$[12] = onStep;
|
|
263
|
+
$[13] = steps;
|
|
264
|
+
$[14] = t6;
|
|
265
|
+
} else t6 = $[14];
|
|
266
|
+
let t7;
|
|
267
|
+
if ($[15] !== axis.name || $[16] !== chosen.name || $[17] !== disabled || $[18] !== index || $[19] !== steps.length || $[20] !== t5 || $[21] !== t6) {
|
|
268
|
+
t7 = /* @__PURE__ */ jsx(Slider, {
|
|
269
|
+
label: axis.name,
|
|
270
|
+
valueText: chosen.name,
|
|
271
|
+
min: 0,
|
|
272
|
+
max: t5,
|
|
273
|
+
step: 1,
|
|
274
|
+
marks: steps.length,
|
|
275
|
+
value: index,
|
|
276
|
+
disabled,
|
|
277
|
+
onValueChange: t6
|
|
278
|
+
});
|
|
279
|
+
$[15] = axis.name;
|
|
280
|
+
$[16] = chosen.name;
|
|
281
|
+
$[17] = disabled;
|
|
282
|
+
$[18] = index;
|
|
283
|
+
$[19] = steps.length;
|
|
284
|
+
$[20] = t5;
|
|
285
|
+
$[21] = t6;
|
|
286
|
+
$[22] = t7;
|
|
287
|
+
} else t7 = $[22];
|
|
288
|
+
let t8;
|
|
289
|
+
if ($[23] !== steps[0].name) {
|
|
290
|
+
t8 = /* @__PURE__ */ jsx("span", { children: steps[0].name });
|
|
291
|
+
$[23] = steps[0].name;
|
|
292
|
+
$[24] = t8;
|
|
293
|
+
} else t8 = $[24];
|
|
294
|
+
const t9 = steps[steps.length - 1];
|
|
295
|
+
let t10;
|
|
296
|
+
if ($[25] !== t9.name) {
|
|
297
|
+
t10 = /* @__PURE__ */ jsx("span", { children: t9.name });
|
|
298
|
+
$[25] = t9.name;
|
|
299
|
+
$[26] = t10;
|
|
300
|
+
} else t10 = $[26];
|
|
301
|
+
let t11;
|
|
302
|
+
if ($[27] !== t10 || $[28] !== t8) {
|
|
303
|
+
t11 = /* @__PURE__ */ jsxs("div", {
|
|
304
|
+
"aria-hidden": true,
|
|
305
|
+
className: "text-muted-foreground flex justify-between text-[11px]",
|
|
306
|
+
children: [t8, t10]
|
|
307
|
+
});
|
|
308
|
+
$[27] = t10;
|
|
309
|
+
$[28] = t8;
|
|
310
|
+
$[29] = t11;
|
|
311
|
+
} else t11 = $[29];
|
|
312
|
+
let t12;
|
|
313
|
+
if ($[30] !== chosen.definition) {
|
|
314
|
+
t12 = sentenceCase(chosen.definition);
|
|
315
|
+
$[30] = chosen.definition;
|
|
316
|
+
$[31] = t12;
|
|
317
|
+
} else t12 = $[31];
|
|
318
|
+
let t13;
|
|
319
|
+
if ($[32] !== t12) {
|
|
320
|
+
t13 = /* @__PURE__ */ jsx("p", {
|
|
321
|
+
"data-voice-definition": true,
|
|
322
|
+
className: "text-muted-foreground text-xs",
|
|
323
|
+
children: t12
|
|
324
|
+
});
|
|
325
|
+
$[32] = t12;
|
|
326
|
+
$[33] = t13;
|
|
327
|
+
} else t13 = $[33];
|
|
328
|
+
let t14;
|
|
329
|
+
if ($[34] !== t11 || $[35] !== t13 || $[36] !== t4 || $[37] !== t7) {
|
|
330
|
+
t14 = /* @__PURE__ */ jsxs("li", {
|
|
331
|
+
"data-voice-axis": true,
|
|
332
|
+
className: "flex flex-col gap-2",
|
|
333
|
+
children: [
|
|
334
|
+
t4,
|
|
335
|
+
t7,
|
|
336
|
+
t11,
|
|
337
|
+
t13
|
|
338
|
+
]
|
|
339
|
+
});
|
|
340
|
+
$[34] = t11;
|
|
341
|
+
$[35] = t13;
|
|
342
|
+
$[36] = t4;
|
|
343
|
+
$[37] = t7;
|
|
344
|
+
$[38] = t14;
|
|
345
|
+
} else t14 = $[38];
|
|
346
|
+
return t14;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
export { VoiceGroup };
|
|
@@ -16,15 +16,16 @@ import { toast } from "@camox/ui/toaster";
|
|
|
16
16
|
import { Skeleton } from "@camox/ui/skeleton";
|
|
17
17
|
import { Spinner } from "@camox/ui/spinner";
|
|
18
18
|
import { Popover, PopoverContent, PopoverHeader, PopoverTitle, PopoverTrigger } from "@camox/ui/popover";
|
|
19
|
+
import { voiceAxis, voiceStep } from "@camox/api-contract/voice";
|
|
19
20
|
|
|
20
21
|
//#region src/features/studio/components/DraftReview.tsx
|
|
21
22
|
/**
|
|
22
|
-
* Where a subject sits: its page or layout, or the files, the languages or memory
|
|
23
|
-
* to none.
|
|
23
|
+
* Where a subject sits: its page or layout, or the files, the languages or memory (the Voice
|
|
24
|
+
* included), which belong to none.
|
|
24
25
|
*/
|
|
25
26
|
function ownerName(owner, entity) {
|
|
26
27
|
if (entity === "locale") return "Languages";
|
|
27
|
-
if (entity === "memory") return "Memory";
|
|
28
|
+
if (entity === "memory" || entity === "voiceAxis") return "Memory";
|
|
28
29
|
if (!owner) return entity === "file" ? "Files" : "Elsewhere";
|
|
29
30
|
if (owner.kind === "layout") return `Layout ${owner.name}`;
|
|
30
31
|
if (owner.kind === "syncedBlock") return `Synced block ${owner.title}`;
|
|
@@ -219,14 +220,20 @@ const MEMORY_CHANGE_LABELS = {
|
|
|
219
220
|
changed: "Changed",
|
|
220
221
|
deleted: "Deleted"
|
|
221
222
|
};
|
|
223
|
+
/** A Voice Axis the draft moves, as it reads: "Humor: Earnest → Light". */
|
|
224
|
+
function voiceLine({ axis, before, after }) {
|
|
225
|
+
const stepName = (key) => voiceStep(axis, key).name;
|
|
226
|
+
return `${voiceAxis(axis).name}: ${stepName(before)} → ${stepName(after)}`;
|
|
227
|
+
}
|
|
222
228
|
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
229
|
+
* What publishing the draft changes in memory: each Voice Axis it moves, from Live's step to the
|
|
230
|
+
* draft's, then the memories it adds, changes and deletes, each with its text, and Live's before a
|
|
231
|
+
* change. Nothing when it changes neither.
|
|
225
232
|
*/
|
|
226
233
|
function MemoryChanges(t0) {
|
|
227
|
-
const $ = c(
|
|
228
|
-
const { changes } = t0;
|
|
229
|
-
if (changes.length === 0) return null;
|
|
234
|
+
const $ = c(8);
|
|
235
|
+
const { voice, changes } = t0;
|
|
236
|
+
if (voice.length === 0 && changes.length === 0) return null;
|
|
230
237
|
let t1;
|
|
231
238
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
232
239
|
t1 = /* @__PURE__ */ jsx("h3", {
|
|
@@ -236,27 +243,34 @@ function MemoryChanges(t0) {
|
|
|
236
243
|
$[0] = t1;
|
|
237
244
|
} else t1 = $[0];
|
|
238
245
|
let t2;
|
|
239
|
-
if ($[1] !==
|
|
240
|
-
t2 =
|
|
241
|
-
$[1] =
|
|
246
|
+
if ($[1] !== voice) {
|
|
247
|
+
t2 = voice.map(_temp4);
|
|
248
|
+
$[1] = voice;
|
|
242
249
|
$[2] = t2;
|
|
243
250
|
} else t2 = $[2];
|
|
244
251
|
let t3;
|
|
245
|
-
if ($[3] !==
|
|
246
|
-
t3 =
|
|
252
|
+
if ($[3] !== changes) {
|
|
253
|
+
t3 = changes.map(_temp5);
|
|
254
|
+
$[3] = changes;
|
|
255
|
+
$[4] = t3;
|
|
256
|
+
} else t3 = $[4];
|
|
257
|
+
let t4;
|
|
258
|
+
if ($[5] !== t2 || $[6] !== t3) {
|
|
259
|
+
t4 = /* @__PURE__ */ jsxs("section", {
|
|
247
260
|
"data-memory-changes": true,
|
|
248
261
|
className: "flex flex-col gap-2",
|
|
249
|
-
children: [t1, /* @__PURE__ */
|
|
262
|
+
children: [t1, /* @__PURE__ */ jsxs("ul", {
|
|
250
263
|
className: "flex flex-col gap-2",
|
|
251
|
-
children: t2
|
|
264
|
+
children: [t2, t3]
|
|
252
265
|
})]
|
|
253
266
|
});
|
|
254
|
-
$[
|
|
255
|
-
$[
|
|
256
|
-
|
|
257
|
-
|
|
267
|
+
$[5] = t2;
|
|
268
|
+
$[6] = t3;
|
|
269
|
+
$[7] = t4;
|
|
270
|
+
} else t4 = $[7];
|
|
271
|
+
return t4;
|
|
258
272
|
}
|
|
259
|
-
function
|
|
273
|
+
function _temp5(memory) {
|
|
260
274
|
return /* @__PURE__ */ jsxs("li", {
|
|
261
275
|
className: "flex flex-col gap-0.5 rounded-lg border p-3 text-sm",
|
|
262
276
|
children: [
|
|
@@ -275,6 +289,12 @@ function _temp4(memory) {
|
|
|
275
289
|
]
|
|
276
290
|
}, memory.id);
|
|
277
291
|
}
|
|
292
|
+
function _temp4(change) {
|
|
293
|
+
return /* @__PURE__ */ jsx("li", {
|
|
294
|
+
className: "rounded-lg border p-3 text-sm",
|
|
295
|
+
children: /* @__PURE__ */ jsx("p", { children: voiceLine(change) })
|
|
296
|
+
}, change.axis);
|
|
297
|
+
}
|
|
278
298
|
/**
|
|
279
299
|
* The draft's overview: the bullets AI wrote about its changes, in full, saying it's updating
|
|
280
300
|
* while they describe an older version of the draft. While
|
|
@@ -290,7 +310,7 @@ function DraftOverview(t0) {
|
|
|
290
310
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
291
311
|
t1 = {
|
|
292
312
|
...draftMutations.retryOverview(),
|
|
293
|
-
onError:
|
|
313
|
+
onError: _temp6
|
|
294
314
|
};
|
|
295
315
|
$[0] = t1;
|
|
296
316
|
} else t1 = $[0];
|
|
@@ -311,7 +331,7 @@ function DraftOverview(t0) {
|
|
|
311
331
|
if (overview.status === "ready") {
|
|
312
332
|
let t2;
|
|
313
333
|
if ($[3] !== overview.bullets) {
|
|
314
|
-
t2 = overview.bullets.map(
|
|
334
|
+
t2 = overview.bullets.map(_temp7);
|
|
315
335
|
$[3] = overview.bullets;
|
|
316
336
|
$[4] = t2;
|
|
317
337
|
} else t2 = $[4];
|
|
@@ -352,7 +372,7 @@ function DraftOverview(t0) {
|
|
|
352
372
|
if (overview.status === "failed") {
|
|
353
373
|
let t2;
|
|
354
374
|
if ($[12] !== changes) {
|
|
355
|
-
t2 = new Set(changes.map(
|
|
375
|
+
t2 = new Set(changes.map(_temp8));
|
|
356
376
|
$[12] = changes;
|
|
357
377
|
$[13] = t2;
|
|
358
378
|
} else t2 = $[13];
|
|
@@ -455,13 +475,13 @@ function DraftOverview(t0) {
|
|
|
455
475
|
} else t2 = $[34];
|
|
456
476
|
return t2;
|
|
457
477
|
}
|
|
458
|
-
function
|
|
478
|
+
function _temp8(change) {
|
|
459
479
|
return ownerName(change.owner, change.entity);
|
|
460
480
|
}
|
|
461
|
-
function
|
|
481
|
+
function _temp7(bullet, index) {
|
|
462
482
|
return /* @__PURE__ */ jsx("li", { children: bullet }, index);
|
|
463
483
|
}
|
|
464
|
-
function
|
|
484
|
+
function _temp6(error) {
|
|
465
485
|
return toast.error(error.message || "Could not summarize the draft");
|
|
466
486
|
}
|
|
467
487
|
/**
|
|
@@ -569,8 +589,11 @@ function DraftReview(t0) {
|
|
|
569
589
|
showInCanvas(target);
|
|
570
590
|
}
|
|
571
591
|
}),
|
|
572
|
-
lines.map(
|
|
573
|
-
/* @__PURE__ */ jsx(MemoryChanges, {
|
|
592
|
+
lines.map(_temp9),
|
|
593
|
+
/* @__PURE__ */ jsx(MemoryChanges, {
|
|
594
|
+
voice: data.voiceChanges,
|
|
595
|
+
changes: data.memoryChanges
|
|
596
|
+
})
|
|
574
597
|
]
|
|
575
598
|
}) : /* @__PURE__ */ jsx("div", {
|
|
576
599
|
className: cn("flex items-center justify-center", REVIEW_BODY_HEIGHT),
|
|
@@ -646,7 +669,7 @@ function DraftReview(t0) {
|
|
|
646
669
|
} else t16 = $[50];
|
|
647
670
|
return t16;
|
|
648
671
|
}
|
|
649
|
-
function
|
|
672
|
+
function _temp9(line) {
|
|
650
673
|
return /* @__PURE__ */ jsx("p", {
|
|
651
674
|
className: "text-sm text-amber-700 dark:text-amber-400",
|
|
652
675
|
"data-review-line": true,
|
|
@@ -87,6 +87,7 @@ const CAMOX_OPTIMIZED_DEPS = [
|
|
|
87
87
|
"camox > @base-ui/react/popover",
|
|
88
88
|
"camox > @base-ui/react/select",
|
|
89
89
|
"camox > @base-ui/react/separator",
|
|
90
|
+
"camox > @base-ui/react/slider",
|
|
90
91
|
"camox > @base-ui/react/switch",
|
|
91
92
|
"camox > @base-ui/react/tabs",
|
|
92
93
|
"camox > @base-ui/react/toggle",
|
package/dist/lib/queries.js
CHANGED
|
@@ -80,11 +80,15 @@ const localeMutations = {
|
|
|
80
80
|
/** Adds a page or record deleted from the locale viewed back to it. */
|
|
81
81
|
addBack: () => getOrpc().locales.addBack.mutationOptions()
|
|
82
82
|
};
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Correcting memory and saving the Voice: content writes, so on Live they start a draft (ADR 0049,
|
|
85
|
+
* ADR 0051).
|
|
86
|
+
*/
|
|
84
87
|
const memoryMutations = {
|
|
85
88
|
add: () => getOrpc().memories.add.mutationOptions(),
|
|
86
89
|
change: () => getOrpc().memories.change.mutationOptions(),
|
|
87
|
-
delete: () => getOrpc().memories.delete.mutationOptions()
|
|
90
|
+
delete: () => getOrpc().memories.delete.mutationOptions(),
|
|
91
|
+
saveVoice: () => getOrpc().memories.saveVoice.mutationOptions()
|
|
88
92
|
};
|
|
89
93
|
const blockMutations = {
|
|
90
94
|
delete: () => getOrpc().blocks.delete.mutationOptions(),
|
|
@@ -8,6 +8,7 @@ import "react";
|
|
|
8
8
|
import "@camox/api-contract/query-keys";
|
|
9
9
|
import "@camox/api-contract/specialists";
|
|
10
10
|
import { QueryClient } from "@tanstack/react-query";
|
|
11
|
+
import "@camox/api-contract/voice";
|
|
11
12
|
//#region src/lib/studio-reads.d.ts
|
|
12
13
|
type LayoutRead = Awaited<ReturnType<ApiClient["layouts"]["get"]>>;
|
|
13
14
|
/** A layout's structure: its blocks before and after the content of its pages. */
|
package/dist/lib/studio-reads.js
CHANGED
|
@@ -65,6 +65,12 @@ const reads = {
|
|
|
65
65
|
fetch: ({ api, signal }, { projectId }) => api.memories.list({ projectId }, { signal }),
|
|
66
66
|
staleTime: Infinity
|
|
67
67
|
}),
|
|
68
|
+
voice: entry({
|
|
69
|
+
key: ({ projectId }) => [...queryKeys.memories.voice, projectId],
|
|
70
|
+
everyLocale: true,
|
|
71
|
+
fetch: ({ api, signal }, { projectId }) => api.memories.voice({ projectId }, { signal }),
|
|
72
|
+
staleTime: Infinity
|
|
73
|
+
}),
|
|
68
74
|
missingFromLocale: entry({
|
|
69
75
|
key: ({ projectId }) => [
|
|
70
76
|
"camox",
|