wizards 0.7.1 → 0.7.3
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/README.md +4 -3
- package/apps/runtime/dist/auth/device.js +13 -2
- package/apps/runtime/dist/cli/account.js +114 -21
- package/apps/runtime/dist/cli/connect.js +6 -2
- package/apps/runtime/dist/cli/main.js +1 -1
- package/apps/runtime/dist/cli/menu.js +1 -1
- package/apps/runtime/dist/cli/setup.js +6 -0
- package/apps/runtime/dist/cli/ui.js +26 -0
- package/apps/runtime/dist/docs/user/install.md +1 -1
- package/apps/web/dist/assets/{AboutDialog-BJALish1.js → AboutDialog--aZOfowz.js} +1 -1
- package/apps/web/dist/assets/{ChangelogDialog-CxmHNvq1.js → ChangelogDialog-CcMXT8l9.js} +1 -1
- package/apps/web/dist/assets/{ChatView-C9ASPVJj.js → ChatView-BqK5nH84.js} +1 -1
- package/apps/web/dist/assets/{EditorPage-BHhNEiKa.js → EditorPage-BRZmuMsK.js} +3 -3
- package/apps/web/dist/assets/{FlowPreview-DvpjuQdC.js → FlowPreview-CpA_aX8t.js} +1 -1
- package/apps/web/dist/assets/{Harness-Duq0wpfg.js → Harness-C8demwfW.js} +1 -1
- package/apps/web/dist/assets/{NewWizardChannels-CGFy67jk.js → NewWizardChannels-vph1mN1m.js} +1 -1
- package/apps/web/dist/assets/{NewWizardPage-DwBcRWJj.js → NewWizardPage-u1BIy4q9.js} +1 -1
- package/apps/web/dist/assets/{OnboardingPage-YwKzupPI.js → OnboardingPage-BR3FmORm.js} +1 -1
- package/apps/web/dist/assets/{ProjectPage-DP1xMjbe.js → ProjectPage-BWN0iO0X.js} +1 -1
- package/apps/web/dist/assets/{PublicRunner-CECAuP0g.js → PublicRunner-CohatW8Y.js} +1 -1
- package/apps/web/dist/assets/{ReadOnly-BnnGcLWU.js → ReadOnly-rQGZBuzb.js} +1 -1
- package/apps/web/dist/assets/{RunDrawer-C0vf8QAc.js → RunDrawer-Cs8XqQUo.js} +2 -2
- package/apps/web/dist/assets/{RunnerView-CBrZpjt5.js → RunnerView-B85O0i1h.js} +1 -1
- package/apps/web/dist/assets/{SettingsPage-C0-mVcs5.js → SettingsPage-CM6HfO-O.js} +1 -1
- package/apps/web/dist/assets/{SetupPage-BGlYQREU.js → SetupPage-BpAobBc4.js} +1 -1
- package/apps/web/dist/assets/{SharePage-IwxlV6WC.js → SharePage-CbmAN4M4.js} +1 -1
- package/apps/web/dist/assets/changelog-BBR59khF.js +1 -0
- package/apps/web/dist/assets/{esm-6TNBQNCD.js → esm-CY-A_13f.js} +1 -1
- package/apps/web/dist/assets/index-C7HL_Fjz.js +14 -0
- package/apps/web/dist/assets/index-Co9Yr23e.css +1 -0
- package/apps/web/dist/assets/{lock-HLZib0u9.js → lock--JFmtLDU.js} +1 -1
- package/apps/web/dist/assets/{phone-DsxbIcWi.js → phone-DMtADQ4-.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-BMMkIVP1.js → settings-menu-Dac4JUiM.js} +1 -1
- package/apps/web/dist/assets/{ui-Brg2qM1A.js → ui-CTXSFCzc.js} +2 -2
- package/apps/web/dist/assets/{upload-BaGy0ppG.js → upload-Bcpc3mDn.js} +1 -1
- package/apps/web/dist/index.html +3 -3
- package/apps/web/dist/mcp/flow.html +3 -3
- package/package.json +1 -1
- package/apps/web/dist/assets/changelog-CPNPseoQ.js +0 -1
- package/apps/web/dist/assets/index-BhVJwBz7.css +0 -1
- package/apps/web/dist/assets/index-DU-Onx-c.js +0 -14
package/README.md
CHANGED
|
@@ -63,9 +63,10 @@ It needs nothing but `curl` and `tar` and asks for no password. It brings its ow
|
|
|
63
63
|
Node you already have is left alone), installs engenty wizards into `~/.engenty/wizards` and
|
|
64
64
|
then walks you through the rest:
|
|
65
65
|
|
|
66
|
-
- **Your engenty account.** “Sign in now?”: a
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
- **Your engenty account.** “Sign in, or create your account, now?”: a link and a code, and
|
|
67
|
+
the browser for the sign-in, which also creates a new account (with your invitation code); what
|
|
68
|
+
you publish on this computer then runs in the cloud too. Esc while it waits, or say no, and
|
|
69
|
+
`wizards account sign-in` does it any time.
|
|
69
70
|
`--local` leaves the account out: nothing leaves the computer, links answer on it only
|
|
70
71
|
([local only](https://engenty.ai/docs/user/local-only)).
|
|
71
72
|
- **An AI client.** It looks for Codex, Claude Code, Gemini CLI and Cursor Agent and
|
|
@@ -55,7 +55,14 @@ export async function requestDeviceCode() {
|
|
|
55
55
|
interval: Math.max(1, data.interval ?? 5),
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
/** A pause that ends early when the signal aborts. */
|
|
59
|
+
const pause = (ms, signal) => new Promise((done) => {
|
|
60
|
+
const timer = setTimeout(done, ms);
|
|
61
|
+
signal?.addEventListener("abort", () => {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
done();
|
|
64
|
+
}, { once: true });
|
|
65
|
+
});
|
|
59
66
|
/**
|
|
60
67
|
* Asks the token endpoint until the person allowed the code in the browser, and keeps the
|
|
61
68
|
* tokens as the browser flow does. `authorization_pending` asks again after `interval`;
|
|
@@ -64,10 +71,14 @@ const pause = (ms) => new Promise((done) => setTimeout(done, ms));
|
|
|
64
71
|
*/
|
|
65
72
|
export async function waitForDeviceSignIn(code, options = {}) {
|
|
66
73
|
const wait = options.wait ?? pause;
|
|
74
|
+
const { signal } = options;
|
|
67
75
|
let interval = code.interval;
|
|
68
76
|
let failures = 0;
|
|
69
77
|
for (;;) {
|
|
70
|
-
await wait(interval * 1000);
|
|
78
|
+
await wait(interval * 1000, signal);
|
|
79
|
+
if (signal?.aborted) {
|
|
80
|
+
throw new DeviceSignInError("skipped", "Skipped the sign-in.");
|
|
81
|
+
}
|
|
71
82
|
if (Date.now() >= code.expiresAt) {
|
|
72
83
|
throw new DeviceSignInError("expired", "The code has expired. Start the sign-in again.");
|
|
73
84
|
}
|
|
@@ -62,7 +62,8 @@ export async function accountState() {
|
|
|
62
62
|
export function described(account, team, credits = true) {
|
|
63
63
|
const parts = [account.name || account.email];
|
|
64
64
|
if (team) {
|
|
65
|
-
|
|
65
|
+
// "Team Anna" and "New team" say it themselves: not "team Team Anna".
|
|
66
|
+
parts.push(/\bteam\b/i.test(team.name) ? team.name : `team ${team.name}`);
|
|
66
67
|
if (credits) {
|
|
67
68
|
parts.push(`${team.balanceCredits} credits`);
|
|
68
69
|
}
|
|
@@ -100,11 +101,58 @@ async function status() {
|
|
|
100
101
|
: dim(` (${host()} didn’t respond${team ? ", so this is from last time" : ""})`)}`);
|
|
101
102
|
return 0;
|
|
102
103
|
}
|
|
104
|
+
/** A code as people read it off a screen: ABCD-EFGH. */
|
|
105
|
+
export function groupedCode(code) {
|
|
106
|
+
const plain = code.replace(/[\s-]+/g, "").toUpperCase();
|
|
107
|
+
return plain.length === 8 ? `${plain.slice(0, 4)}-${plain.slice(4)}` : code;
|
|
108
|
+
}
|
|
109
|
+
/** Whether a new account needs an invitation code, as the account's own pages say. */
|
|
110
|
+
async function signupByCode() {
|
|
111
|
+
try {
|
|
112
|
+
const res = await fetch(`${env.local.accountUrl}/api/config`, {
|
|
113
|
+
signal: AbortSignal.timeout(3000),
|
|
114
|
+
});
|
|
115
|
+
return (await res.json()).signup === "code";
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Enter and Esc on a terminal while it waits for the browser (Ctrl-C stays the spinner's: it
|
|
123
|
+
* ends the command). Returns what gives the keys back.
|
|
124
|
+
*/
|
|
125
|
+
function onKeys(keys) {
|
|
126
|
+
const input = process.stdin;
|
|
127
|
+
if (!input.isTTY) {
|
|
128
|
+
return () => undefined;
|
|
129
|
+
}
|
|
130
|
+
const raw = input.isRaw;
|
|
131
|
+
input.setRawMode(true);
|
|
132
|
+
input.resume();
|
|
133
|
+
const read = (data) => {
|
|
134
|
+
const key = data.toString();
|
|
135
|
+
if (key === "\r" || key === "\n") {
|
|
136
|
+
keys.enter();
|
|
137
|
+
}
|
|
138
|
+
else if (key === "\x1b") {
|
|
139
|
+
keys.escape();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
input.on("data", read);
|
|
143
|
+
return () => {
|
|
144
|
+
input.off("data", read);
|
|
145
|
+
input.setRawMode(raw);
|
|
146
|
+
input.pause();
|
|
147
|
+
};
|
|
148
|
+
}
|
|
103
149
|
/**
|
|
104
150
|
* The device flow on the terminal: the link and the code, the browser opened where there is
|
|
105
|
-
* one, then a wait while the person
|
|
151
|
+
* one, then a wait while the person signs in, or creates their account, and allows it. On a
|
|
152
|
+
* terminal, Enter opens the page again and Esc goes on without an account: someone without an
|
|
153
|
+
* invitation code yet is not stuck in the wait. Null when it ended without an account.
|
|
106
154
|
*/
|
|
107
|
-
async function deviceSignIn() {
|
|
155
|
+
async function deviceSignIn(interactive) {
|
|
108
156
|
let code;
|
|
109
157
|
try {
|
|
110
158
|
code = await requestDeviceCode();
|
|
@@ -113,24 +161,42 @@ async function deviceSignIn() {
|
|
|
113
161
|
p.log.error(err.message);
|
|
114
162
|
return null;
|
|
115
163
|
}
|
|
164
|
+
const shown = groupedCode(code.userCode);
|
|
165
|
+
// The complete link carries the code: the page only asks to check it.
|
|
116
166
|
const link = code.verificationUriComplete ?? code.verificationUri;
|
|
117
|
-
p.log.message(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
167
|
+
p.log.message(code.verificationUriComplete
|
|
168
|
+
? `Open ${cyan(link)}\nThe page shows the code ${bold(shown)}: check that it matches.`
|
|
169
|
+
: `Open ${cyan(link)} and enter the code ${bold(shown)}.`);
|
|
170
|
+
const opened = openBrowser(link);
|
|
171
|
+
const newHere = (await signupByCode())
|
|
172
|
+
? "New here? Create your account on that page with your invitation code, or join the waitlist there."
|
|
173
|
+
: "New here? Your account is created on that page.";
|
|
174
|
+
const keys = interactive ? "Enter opens the page again · Esc signs in later" : "";
|
|
175
|
+
p.log.message(dim([opened ? "The page opens in your browser." : "", newHere, keys].filter(Boolean).join("\n")));
|
|
176
|
+
const spinner = busy("Waiting for you in the browser…");
|
|
177
|
+
const later = new AbortController();
|
|
178
|
+
const release = interactive
|
|
179
|
+
? onKeys({ enter: () => void openBrowser(link), escape: () => later.abort() })
|
|
180
|
+
: () => undefined;
|
|
122
181
|
try {
|
|
123
|
-
const account = await waitForDeviceSignIn(code);
|
|
182
|
+
const account = await waitForDeviceSignIn(code, { signal: later.signal });
|
|
124
183
|
const overview = await accountOverview();
|
|
125
184
|
spinner.stop(`Signed in as ${described(account, overview?.tenant ?? null)}.`);
|
|
126
185
|
return account;
|
|
127
186
|
}
|
|
128
187
|
catch (err) {
|
|
188
|
+
if (err instanceof DeviceSignInError && err.reason === "skipped") {
|
|
189
|
+
spinner.stop("Not signed in yet.");
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
129
192
|
spinner.fail(err instanceof DeviceSignInError
|
|
130
193
|
? err.message
|
|
131
194
|
: `The sign-in didn’t work. ${err.message}`);
|
|
132
195
|
return null;
|
|
133
196
|
}
|
|
197
|
+
finally {
|
|
198
|
+
release();
|
|
199
|
+
}
|
|
134
200
|
}
|
|
135
201
|
/**
|
|
136
202
|
* A runtime that runs reads the account from the settings as it goes, but holds a few things
|
|
@@ -161,12 +227,20 @@ const SIGNED_IN = "your plan’s Pro modules load and your published wizards arr
|
|
|
161
227
|
async function signIn(paths, interactive) {
|
|
162
228
|
await ready();
|
|
163
229
|
const linked = await linkedAccount();
|
|
230
|
+
if (linked && isLocalOnly()) {
|
|
231
|
+
// Set up with --local by an older version, which kept the link: it only needs switching on.
|
|
232
|
+
joinedAccount(paths);
|
|
233
|
+
p.log.success(`Signed in as ${described(linked, await knownTeam(), false)} again.`);
|
|
234
|
+
await pickUp(paths, interactive, SIGNED_IN);
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
164
237
|
if (linked) {
|
|
165
238
|
p.log.info(`Already signed in as ${described(linked, await knownTeam(), false)}. ${dim(`To switch accounts, run ${cmd("account sign-out")} first.`)}`);
|
|
166
239
|
return 0;
|
|
167
240
|
}
|
|
168
|
-
const account = await deviceSignIn();
|
|
241
|
+
const account = await deviceSignIn(interactive);
|
|
169
242
|
if (!account) {
|
|
243
|
+
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
170
244
|
return 1;
|
|
171
245
|
}
|
|
172
246
|
joinedAccount(paths);
|
|
@@ -174,15 +248,10 @@ async function signIn(paths, interactive) {
|
|
|
174
248
|
await pickUp(paths, interactive, SIGNED_IN);
|
|
175
249
|
return 0;
|
|
176
250
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
? "No account is connected, so there’s nothing to sign out of."
|
|
182
|
-
: "Not signed in.");
|
|
183
|
-
return 0;
|
|
184
|
-
}
|
|
185
|
-
const spinner = busy(`Signing out ${state.account.name || state.account.email}…`);
|
|
251
|
+
/**
|
|
252
|
+
* Ends the link to the account: the same as the studio's sign-out (DELETE /api/studio/account).
|
|
253
|
+
*/
|
|
254
|
+
async function disconnect() {
|
|
186
255
|
await unlink();
|
|
187
256
|
// The same as the studio's sign-out (DELETE /api/studio/account): what was sent to the cloud
|
|
188
257
|
// is forgotten, the entitlement goes with the account's plan, and models that ran on its
|
|
@@ -199,6 +268,19 @@ async function signOut(paths, interactive) {
|
|
|
199
268
|
if (models.localModelSettings().source === "account") {
|
|
200
269
|
await models.saveLocalModels({ source: "own" });
|
|
201
270
|
}
|
|
271
|
+
}
|
|
272
|
+
async function signOut(paths, interactive) {
|
|
273
|
+
await ready();
|
|
274
|
+
// A link kept from an older --local counts as well: it is still on this computer.
|
|
275
|
+
const linked = await linkedAccount();
|
|
276
|
+
if (!linked) {
|
|
277
|
+
console.log(isLocalOnly()
|
|
278
|
+
? "No account is connected, so there’s nothing to sign out of."
|
|
279
|
+
: "Not signed in.");
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
const spinner = busy(`Signing out ${linked.name || linked.email}…`);
|
|
283
|
+
await disconnect();
|
|
202
284
|
spinner.stop("Signed out. Your wizards and results stay on this computer.");
|
|
203
285
|
await pickUp(paths, interactive, "it disconnects from the account");
|
|
204
286
|
return 0;
|
|
@@ -252,6 +334,14 @@ export async function accountMenu(paths) {
|
|
|
252
334
|
*/
|
|
253
335
|
export async function accountStep(paths, options, interactive) {
|
|
254
336
|
if (options.local) {
|
|
337
|
+
await ready();
|
|
338
|
+
const linked = await linkedAccount();
|
|
339
|
+
if (linked) {
|
|
340
|
+
// "Nothing leaves this computer" holds only without the link.
|
|
341
|
+
const spinner = busy(`Signing out ${linked.name || linked.email}…`);
|
|
342
|
+
await disconnect();
|
|
343
|
+
spinner.stop(`Signed out ${linked.name || linked.email}.`);
|
|
344
|
+
}
|
|
255
345
|
localOnly(paths);
|
|
256
346
|
p.log.warn(`No account: nothing leaves this computer. Your wizards, your space and results stay in ${tilde(settings(paths).dataDir)}. Links work only on this computer.`);
|
|
257
347
|
p.log.message(dim(`To connect an account any time: ${cmd("account sign-in")}`));
|
|
@@ -272,7 +362,10 @@ export async function accountStep(paths, options, interactive) {
|
|
|
272
362
|
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
273
363
|
return;
|
|
274
364
|
}
|
|
275
|
-
const answer = await p.confirm({
|
|
365
|
+
const answer = await p.confirm({
|
|
366
|
+
message: "Sign in, or create your account, now?",
|
|
367
|
+
initialValue: true,
|
|
368
|
+
});
|
|
276
369
|
if (p.isCancel(answer)) {
|
|
277
370
|
p.cancel(`Setup stopped. To run it again: ${cmd("setup")}`);
|
|
278
371
|
return "cancelled";
|
|
@@ -281,7 +374,7 @@ export async function accountStep(paths, options, interactive) {
|
|
|
281
374
|
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
282
375
|
return;
|
|
283
376
|
}
|
|
284
|
-
const account = await deviceSignIn();
|
|
377
|
+
const account = await deviceSignIn(interactive);
|
|
285
378
|
if (!account) {
|
|
286
379
|
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
287
380
|
return;
|
|
@@ -296,8 +296,10 @@ function claudeCode(paths) {
|
|
|
296
296
|
"add",
|
|
297
297
|
"--scope",
|
|
298
298
|
"user",
|
|
299
|
-
|
|
299
|
+
// The name before `-e`: claude's `-e` takes every value up to the next option, so a
|
|
300
|
+
// name after it is read as one more variable.
|
|
300
301
|
SERVER_NAME,
|
|
302
|
+
...Object.entries(server.env ?? {}).flatMap(([key, value]) => ["-e", `${key}=${value}`]),
|
|
301
303
|
"--",
|
|
302
304
|
server.command,
|
|
303
305
|
...server.args,
|
|
@@ -305,7 +307,9 @@ function claudeCode(paths) {
|
|
|
305
307
|
return { ok: true, message: "added with claude mcp add --scope user" };
|
|
306
308
|
}
|
|
307
309
|
catch (error) {
|
|
308
|
-
|
|
310
|
+
// claude's own words say what was wrong; "Command failed: …" only repeats the command.
|
|
311
|
+
const said = String(error.stderr ?? "").trim();
|
|
312
|
+
return { ok: false, message: (said || error.message).split("\n")[0] };
|
|
309
313
|
}
|
|
310
314
|
},
|
|
311
315
|
async disconnect() {
|
|
@@ -167,7 +167,7 @@ async function main(argv) {
|
|
|
167
167
|
const first = !readInstallNote(paths).setupAt;
|
|
168
168
|
if (first && !args.yes && process.stdin.isTTY && process.stdout.isTTY) {
|
|
169
169
|
// You asked to start it: once the setup is done, it starts.
|
|
170
|
-
if (!(await setup(paths, setupOptions))) {
|
|
170
|
+
if (!(await setup(paths, { ...setupOptions, next: "start" }))) {
|
|
171
171
|
return 130;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
@@ -127,7 +127,7 @@ function commands() {
|
|
|
127
127
|
*/
|
|
128
128
|
export async function menu(paths, setupOptions, help) {
|
|
129
129
|
if (!readInstallNote(paths).setupAt) {
|
|
130
|
-
if (!(await setup(paths, setupOptions))) {
|
|
130
|
+
if (!(await setup(paths, { ...setupOptions, next: "menu" }))) {
|
|
131
131
|
return 130;
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -324,6 +324,12 @@ export async function setup(paths, options) {
|
|
|
324
324
|
unattended: !process.stdout.isTTY,
|
|
325
325
|
}, paths);
|
|
326
326
|
p.log.info(CHROME_APP);
|
|
327
|
+
if (options.next) {
|
|
328
|
+
p.outro(options.next === "start"
|
|
329
|
+
? "Set up. Starting engenty wizards…"
|
|
330
|
+
: `Set up. ${dim(`${cmd("help")} lists every command.`)}`);
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
327
333
|
await howToUse(paths);
|
|
328
334
|
return true;
|
|
329
335
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
+
import { emitKeypressEvents } from "node:readline";
|
|
2
3
|
import { styleText } from "node:util";
|
|
3
4
|
import * as p from "@clack/prompts";
|
|
4
5
|
import { command } from "./home.js";
|
|
@@ -24,6 +25,7 @@ export function busy(message) {
|
|
|
24
25
|
if (!process.stdout.isTTY) {
|
|
25
26
|
return { stop: (text) => p.log.step(text), fail: (text) => p.log.warn(text) };
|
|
26
27
|
}
|
|
28
|
+
exitOnCtrlC();
|
|
27
29
|
const spinner = p.spinner();
|
|
28
30
|
spinner.start(message.replace(/…$/, ""));
|
|
29
31
|
return {
|
|
@@ -31,3 +33,27 @@ export function busy(message) {
|
|
|
31
33
|
fail: (text) => spinner.error(text),
|
|
32
34
|
};
|
|
33
35
|
}
|
|
36
|
+
let watching = false;
|
|
37
|
+
/**
|
|
38
|
+
* Ctrl-C under a spinner: clack ends the process itself, with code 0, as if all went well. The
|
|
39
|
+
* key is noted before clack sees it (this listener comes first), and the process ends with 130
|
|
40
|
+
* instead, as a command stopped by Ctrl-C does: `wizards setup && …` goes no further.
|
|
41
|
+
*/
|
|
42
|
+
function exitOnCtrlC() {
|
|
43
|
+
if (watching || !process.stdin.isTTY) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
watching = true;
|
|
47
|
+
let pressed = false;
|
|
48
|
+
emitKeypressEvents(process.stdin);
|
|
49
|
+
process.stdin.on("keypress", (_text, key) => {
|
|
50
|
+
if (key?.ctrl && key.name === "c") {
|
|
51
|
+
pressed = true;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
process.on("exit", () => {
|
|
55
|
+
if (pressed) {
|
|
56
|
+
process.exitCode = 130;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -28,7 +28,7 @@ have is left alone), installs engenty wizards into `~/.engenty/wizards` (about 6
|
|
|
28
28
|
|
|
29
29
|
| Step | What it does |
|
|
30
30
|
|---|---|
|
|
31
|
-
| Your engenty account | Asks “Sign in now?”. If you say yes, it shows a link and a code and opens your browser for the sign-in at account.engenty.ai (if you have no account yet, the page
|
|
31
|
+
| Your engenty account | Asks “Sign in, or create your account, now?”. If you say yes, it shows a link and a code and opens your browser for the sign-in at account.engenty.ai; check that the page shows the same code (if you have no account yet, the page creates one with your invitation code, or puts you on the waitlist). While it waits, Enter opens the page again and Esc goes on without an account. Once you are signed in, what you publish on this computer runs in the cloud too. If you say no, `wizards account sign-in` does it any time. Setting it up again with `--local` signs an account out. `--local` leaves the account out altogether: see [Local only](./local-only.md) |
|
|
32
32
|
| An AI client | Looks for Codex, Claude Code, Gemini CLI and Cursor Agent and offers to install the ones that are missing. It puts first the one whose app (ChatGPT, Claude, Cursor) is on your Mac, as you most likely have that subscription already. You can also use your account’s credits, an API key, [Ollama](https://ollama.com) or, on a Mac with Apple silicon and macOS 26, Apple Intelligence: the studio’s [first page](./first-start.md) offers them |
|
|
33
33
|
| A browser and ffmpeg | Names the browser for PDF and PNG exports and steps on websites: the first of Chrome, Edge and Chromium it finds (on a Mac also Brave). engenty wizards uses that one; [`CHROME_PATH`](./command-line.md#settings) picks another. It also says whether ffmpeg is there for MP4 videos of animated widgets, and with Homebrew it offers to install it |
|
|
34
34
|
| Start at login (optional) | engenty wizards starts in the background when you log in, so links and AI apps can always reach it. It is a LaunchAgent on a Mac and a systemd user service on Linux |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$t as r,Ft as i,Hn as a,It as o,Kt as s,Nt as c,Pt as l,Vt as u,Wt as d,fr as f,vr as p}from"./ui-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$t as r,Ft as i,Hn as a,It as o,Kt as s,Nt as c,Pt as l,Vt as u,Wt as d,fr as f,vr as p}from"./ui-CTXSFCzc.js";import{t as m}from"./preload-helper-CNEI7N0N.js";import{G as h,U as g,W as _,xt as v}from"./index-C7HL_Fjz.js";import{c as y,f as b}from"./settings-menu-Dac4JUiM.js";import{ReleaseNotes as x,loadReleases as S,releaseDate as C,releaseLabel as w}from"./ChangelogDialog-CcMXT8l9.js";var T=e(t(),1),E=[{name:`engenty wizards`,description:`credit.engenty-wizards`,homepage:`https://github.com/engenty/wizards`,license:`FSL-1.1-MIT`},{name:`engenty`,description:`credit.engenty`,homepage:`https://github.com/engenty/engenty`,license:`FSL-1.1-MIT`}],D=[{name:`Mastra`,description:`credit.mastra`,homepage:`https://github.com/mastra-ai/mastra`,license:`Apache-2.0`},{name:`AI SDK`,description:`credit.ai-sdk`,homepage:`https://github.com/vercel/ai`,license:`Apache-2.0`},{name:`Model Context Protocol`,description:`credit.model-context-protocol`,homepage:`https://github.com/modelcontextprotocol/typescript-sdk`,license:`MIT`},{name:`Hono`,description:`credit.hono`,homepage:`https://github.com/honojs/hono`,license:`MIT`},{name:`Drizzle ORM`,description:`credit.drizzle-orm`,homepage:`https://github.com/drizzle-team/drizzle-orm`,license:`Apache-2.0`},{name:`libSQL`,description:`credit.libsql`,homepage:`https://github.com/tursodatabase/libsql`,license:`MIT`},{name:`Playwright`,description:`credit.playwright`,homepage:`https://github.com/microsoft/playwright`,license:`Apache-2.0`},{name:`React`,description:`credit.react`,homepage:`https://github.com/facebook/react`,license:`MIT`},{name:`Vite`,description:`credit.vite`,homepage:`https://github.com/vitejs/vite`,license:`MIT`},{name:`Tailwind CSS`,description:`credit.tailwind-css`,homepage:`https://github.com/tailwindlabs/tailwindcss`,license:`MIT`},{name:`React Flow`,description:`credit.react-flow`,homepage:`https://github.com/xyflow/xyflow`,license:`MIT`},{name:`TanStack Query`,description:`credit.tanstack-query`,homepage:`https://github.com/TanStack/query`,license:`MIT`},{name:`xterm.js`,description:`credit.xterm-js`,homepage:`https://github.com/xtermjs/xterm.js`,license:`MIT`},{name:`Lucide`,description:`credit.lucide`,homepage:`https://github.com/lucide-icons/lucide`,license:`ISC`},{name:`Geist & Geist Mono`,description:`credit.geist-geist-mono`,homepage:`https://github.com/vercel/geist-font`,license:`OFL-1.1`},{name:`Space Grotesk`,description:`credit.space-grotesk`,homepage:`https://github.com/floriankarsten/space-grotesk`,license:`OFL-1.1`},{name:`git-cliff`,description:`credit.git-cliff`,homepage:`https://github.com/orhun/git-cliff`,license:`MIT OR Apache-2.0`}],O=e(n(),1),k=(e,...t)=>t.some(t=>t?.toLowerCase().includes(e));function A({name:e,homepage:t,version:n,license:r,description:i}){return(0,O.jsxs)(`li`,{className:`py-2.5`,children:[(0,O.jsxs)(`div`,{className:`flex flex-wrap items-baseline gap-x-2.5 gap-y-0.5`,children:[t?(0,O.jsxs)(`a`,{href:t,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 font-medium text-[0.875rem] text-ink underline-offset-4 hover:underline`,children:[e,(0,O.jsx)(f,{"aria-hidden":!0,className:`size-3 text-ink-4`})]}):(0,O.jsx)(`span`,{className:`font-medium text-[0.875rem] text-ink`,children:e}),n?(0,O.jsx)(`span`,{className:`text-[0.75rem] text-ink-3 tabular-nums`,children:n}):null,(0,O.jsx)(`span`,{className:`text-[0.75rem] text-ink-3`,children:r})]}),i?(0,O.jsx)(`p`,{className:`mt-0.5 text-[0.8125rem] text-ink-3`,children:i}):null]})}function j({title:e,hint:t,children:n}){return(0,O.jsxs)(`section`,{className:`mt-6`,children:[(0,O.jsx)(`h3`,{className:`border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:e}),t?(0,O.jsx)(`p`,{className:`mt-2 text-[0.8125rem] text-ink-3`,children:t}):null,n]})}function M({credits:e}){return(0,O.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:e.map(e=>(0,O.jsx)(A,{name:e.name,homepage:e.homepage,license:e.license,description:r(e.description)},e.name))})}function N({label:e,packages:t}){return(0,O.jsxs)(`div`,{className:`mt-4`,children:[(0,O.jsx)(`h4`,{className:`font-medium text-[0.75rem] text-ink-3 tracking-wide`,children:e}),(0,O.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:t.map(e=>(0,O.jsx)(A,{...e},e.name))})]})}function P({active:e}){let[t,n]=(0,T.useState)(null),[i,a]=(0,T.useState)(``);(0,T.useEffect)(()=>{if(!e||t)return;let r=!1;return m(()=>import(`./oss-credits-BJrR7BR1.js`).then(e=>{r||n(e.default)}),[]),()=>{r=!0}},[e,t]),(0,T.useEffect)(()=>{e||a(``)},[e]);let s=i.trim().toLowerCase(),c=e=>s?e.filter(e=>k(s,e.name,e.license,r(e.description))):e,d=e=>s?e.filter(e=>k(s,e.name,e.license,e.version)):e,f=c(E),p=c(D),h=t?[{id:`shared`,label:r(`about.creditsShared`),packages:d(t.shared)},...t.groups.map(e=>({id:e.id,label:e.label,packages:d(e.packages)}))].filter(e=>e.packages.length>0):[],g=f.length===0&&p.length===0&&h.length===0;return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(`p`,{className:`mb-4 text-[0.875rem] text-ink-3`,children:r(`about.creditsHint`)}),(0,O.jsx)(o,{type:`search`,value:i,placeholder:r(`about.search`),onChange:e=>a(e.target.value)}),f.length>0?(0,O.jsx)(j,{title:r(`about.creditsProduct`),children:(0,O.jsx)(M,{credits:f})}):null,p.length>0?(0,O.jsx)(j,{title:r(`about.creditsBuiltWith`),children:(0,O.jsx)(M,{credits:p})}):null,t===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,O.jsx)(u,{})}):h.length>0?(0,O.jsx)(j,{title:r(`about.creditsDeps`),hint:s?void 0:r(`about.creditsDepsHint`),children:h.map(e=>(0,O.jsx)(N,{label:e.label,packages:e.packages},e.id))}):null,t!==null&&g?(0,O.jsx)(l,{children:r(`about.noMatches`)}):null]})}var F=[`new`,`earlier`,`credits`],I=e=>r(e===`new`?`about.tab.new`:e===`earlier`?`about.tab.earlier`:`about.credits`),L=e=>e===1?r(`about.change`):r(`about.changes`,{n:e});function R({open:e,onClose:t,me:n}){let o=n?.mode===`local`,{data:l,latest:f}=h(o&&e),[m,E]=(0,T.useState)(null),[D,k]=(0,T.useState)(`new`),A=b(F.indexOf(D)),j=l?.newer&&f?f:_;(0,T.useEffect)(()=>{if(!e)return;let t=!1;return E(null),S(j===`0.7.3`?void 0:j).then(e=>{t||E(e)}),()=>{t=!0}},[e,j]);let M=m?.find(e=>e.version===`v${j}`)??m?.[0]??null,N=m?.filter(e=>e!==M)??[],R=o?l?.kind??null:`cloud`;return(0,O.jsxs)(c,{open:e,onClose:t,wide:!0,height:`tall`,children:[(0,O.jsx)(`div`,{className:`-mt-2 -mr-2 sticky top-0 z-10 flex h-0 justify-end`,children:(0,O.jsx)(i,{label:r(`common.close`),onClick:t,children:(0,O.jsx)(a,{className:`size-4`})})}),(0,O.jsxs)(`div`,{className:`flex flex-col items-center pt-4 text-center`,children:[(0,O.jsx)(v,{size:96}),(0,O.jsxs)(`div`,{className:`mt-4 font-display font-semibold text-[1.5rem] tracking-tight`,children:[`engenty`,(0,O.jsx)(`span`,{className:`text-ember`,children:`.`}),(0,O.jsx)(`span`,{className:`ml-1.5 font-normal text-ink-3`,children:`wizards`})]}),(0,O.jsxs)(`div`,{className:`mt-1 text-[0.9375rem] text-ink-3 tabular-nums`,children:[r(`about.version`,{v:_}),R?` · ${r(`about.kind.${R}`)}`:``]})]}),o?(0,O.jsx)(`div`,{className:`mt-5`,children:(0,O.jsx)(g,{enabled:e})}):null,(0,O.jsx)(`div`,{className:`mt-6 flex justify-center`,children:(0,O.jsx)(d,{value:D,onChange:k,options:F.map(e=>({id:e,label:I(e)})),label:r(`about.title`)})}),(0,O.jsxs)(`div`,{className:s(`mt-5`,y(A)),children:[D===`new`?m===null?(0,O.jsx)(`div`,{className:`flex justify-center py-6 text-ink-3`,children:(0,O.jsx)(u,{})}):M?(0,O.jsxs)(O.Fragment,{children:[(0,O.jsxs)(`h3`,{className:`flex items-baseline gap-3 border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:[w(M),(0,O.jsx)(`span`,{className:`font-normal font-sans text-[0.8125rem] text-ink-3 tabular-nums`,children:C(M)})]}),(0,O.jsx)(`div`,{className:`mt-3`,children:(0,O.jsx)(x,{release:M})})]}):(0,O.jsx)(`p`,{className:`text-[0.875rem] text-ink-3`,children:r(`about.changelogEmpty`)}):null,D===`earlier`?(0,O.jsx)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:N.map(e=>(0,O.jsxs)(`details`,{className:`group/r py-2`,children:[(0,O.jsxs)(`summary`,{className:`flex cursor-pointer list-none items-baseline gap-3 text-[0.875rem] [&::-webkit-details-marker]:hidden`,children:[(0,O.jsx)(p,{className:`size-3.5 shrink-0 self-center text-ink-4 transition group-open/r:rotate-90`}),(0,O.jsx)(`span`,{className:`font-medium text-ink tabular-nums`,children:w(e)}),(0,O.jsx)(`span`,{className:`text-[0.8125rem] text-ink-3 tabular-nums`,children:C(e)}),(0,O.jsx)(`span`,{className:`ml-auto text-[0.8125rem] text-ink-4`,children:L(e.commits.length)})]}),(0,O.jsx)(`div`,{className:`mt-2 pl-6`,children:(0,O.jsx)(x,{release:e})})]},e.version??`unreleased`))}):null,D===`credits`?(0,O.jsx)(P,{active:!0}):null]},D)]})}export{R as AboutDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$t as r,It as i,Kt as a,Nt as o,Pt as s,Vt as c}from"./ui-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$t as r,It as i,Kt as a,Nt as o,Pt as s,Vt as c}from"./ui-CTXSFCzc.js";import{t as l}from"./preload-helper-CNEI7N0N.js";var u=e(t(),1),d=e(n(),1);function f(e){switch(e.group){case`Added`:return{label:`NEW`,dot:`bg-moss`};case`Fixed`:return{label:`FIXED`,dot:`bg-amber`};case`Changed`:return{label:`CHANGED`,dot:`bg-cobalt`};case`Performance`:return{label:`PERFORMANCE`,dot:`bg-ember`};case`Deploy`:return{label:`DEPLOY`,dot:`bg-ink-4`};case`Docs`:return{label:`DOCS`,dot:`bg-ink-4`};default:return{label:`OTHER`,dot:`bg-ink-4`}}}var p=e=>e.version?e.version.replace(/^v/,``):r(`about.unreleased`),m=e=>e.timestamp?new Date(e.timestamp*1e3).toISOString().slice(0,10):``,h=e=>e.charAt(0).toUpperCase()+e.slice(1);function g(e,t){let n=t.trim().toLowerCase();if(!n)return e;let r=[];for(let t of e){if(`${p(t)} ${m(t)}`.toLowerCase().includes(n)){r.push(t);continue}let e=t.commits.filter(e=>`${f(e).label} ${e.scope??``} ${e.message}`.toLowerCase().includes(n));e.length>0&&r.push({...t,commits:e})}return r}async function _(e){if(e)try{let t=await fetch(`https://raw.githubusercontent.com/engenty/engenty-wizards/v${e}/apps/web/src/about/changelog.json`,{signal:AbortSignal.timeout(5e3)});if(t.ok)return await t.json()}catch{}return(await l(async()=>{let{default:e}=await import(`./changelog-BBR59khF.js`);return{default:e}},[])).default}function v({release:e}){return(0,d.jsx)(`ul`,{className:`flex flex-col gap-2`,children:e.commits.map(e=>{let t=f(e);return(0,d.jsxs)(`li`,{className:`flex items-start gap-2.5 text-[0.875rem]`,children:[(0,d.jsx)(`span`,{className:a(`mt-[7px] size-1.5 shrink-0 rounded-full`,t.dot)}),(0,d.jsxs)(`span`,{className:`min-w-0 text-ink-2`,children:[(0,d.jsxs)(`span`,{className:`font-semibold text-[0.75rem] text-ink tracking-wide`,children:[t.label,e.scope?` [${e.scope}]`:``]}),` `,h(e.message),e.breaking?(0,d.jsx)(`span`,{className:`ml-1.5 rounded-full bg-rose-tint px-1.5 py-0.5 font-medium text-[0.75rem] text-rose`,children:r(`about.breaking`)}):null]})]},e.id)})})}function y({open:e,onClose:t,version:n}){let[a,l]=(0,u.useState)(null),[f,h]=(0,u.useState)(``);(0,u.useEffect)(()=>{if(!e||a)return;let t=!1;return _(n).then(e=>{t||l(e)}),()=>{t=!0}},[e,a,n]),(0,u.useEffect)(()=>{e||h(``)},[e]);let y=a?g(a,f):[];return(0,d.jsxs)(o,{open:e,onClose:t,title:r(`about.changelog`),wide:!0,height:`tall`,children:[(0,d.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:r(`about.changelogHint`)}),a===null?(0,d.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,d.jsx)(c,{})}):a.length===0?(0,d.jsx)(s,{children:r(`about.changelogEmpty`)}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(i,{type:`search`,value:f,placeholder:r(`about.search`),onChange:e=>h(e.target.value)}),y.length===0?(0,d.jsx)(s,{children:r(`about.noMatches`)}):null,y.map(e=>(0,d.jsxs)(`section`,{className:`mt-6`,children:[(0,d.jsxs)(`h3`,{className:`flex items-baseline gap-3 border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:[p(e),(0,d.jsx)(`span`,{className:`font-normal font-sans text-[0.8125rem] text-ink-3 tabular-nums`,children:m(e)})]}),(0,d.jsx)(`div`,{className:`mt-3`,children:(0,d.jsx)(v,{release:e})})]},e.version??`unreleased`))]})]})}export{y as ChangelogDialog,v as ReleaseNotes,_ as loadReleases,m as releaseDate,p as releaseLabel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$ as r,$t as i,Fn as a,Ft as o,Gn as s,Gt as c,Jt as l,Kn as u,Kt as d,Or as f,Rt as p,Tn as m,Un as h,Vn as g,Vt as _,W as v,Xn as y,ar as b,bt as x,dt as S,er as C,ft as w,lt as T,m as E,mt as D,nn as O,nt as k,pt as A,qn as j,qt as M,rr as N,rt as P,st as F,tt as I,un as L,ut as ee,vt as R,wr as z,xr as B,xt as te,yt as ne,zr as re}from"./ui-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{n as t,t as n}from"./jsx-runtime-BNakU3Ej.js";import{$ as r,$t as i,Fn as a,Ft as o,Gn as s,Gt as c,Jt as l,Kn as u,Kt as d,Or as f,Rt as p,Tn as m,Un as h,Vn as g,Vt as _,W as v,Xn as y,ar as b,bt as x,dt as S,er as C,ft as w,lt as T,m as E,mt as D,nn as O,nt as k,pt as A,qn as j,qt as M,rr as N,rt as P,st as F,tt as I,un as L,ut as ee,vt as R,wr as z,xr as B,xt as te,yt as ne,zr as re}from"./ui-CTXSFCzc.js";import{t as ie}from"./phone-DMtADQ4-.js";import{$ as ae,Ct as oe,Ft as se,Mt as ce,Q as le,Z as ue,gt as de,t as fe}from"./index-C7HL_Fjz.js";import{n as pe}from"./RunnerView-B85O0i1h.js";var me={name:`hand`,size:24,node:[[`path`,{d:`M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2`,key:`1fvzgz`}],[`path`,{d:`M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2`,key:`1kc0my`}],[`path`,{d:`M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8`,key:`10h0bg`}],[`path`,{d:`M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15`,key:`1s1gnw`}]]};me.node;var he=f(me),ge={name:`undo-2`,size:24,node:[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]};ge.node;var _e=f(ge),ve={name:`video-off`,size:24,node:[[`path`,{d:`M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196`,key:`w8jjjt`}],[`path`,{d:`M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2`,key:`1xawa7`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]};ve.node;var V=f(ve),ye={name:`volume-x`,size:24,node:[[`path`,{d:`M11 4.702a.7.7 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.7.7 0 0 0 11 19.298z`,key:`1p7khw`}],[`path`,{d:`m16.5 14.5 5-5`,key:`cul3yw`}],[`path`,{d:`m16.5 9.5 5 5`,key:`1akey5`}]]};ye.node;var be=f(ye),xe=re(),H=e(t(),1),U=e(n(),1),Se=typeof window<`u`&&window.matchMedia(`(pointer: coarse)`).matches;function Ce({since:e}){let[t,n]=(0,H.useState)(Date.now());if((0,H.useEffect)(()=>{if(!e)return;let t=setInterval(()=>n(Date.now()),1e3);return()=>clearInterval(t)},[e]),!e)return null;let r=Math.max(0,Math.floor((t-e)/1e3)),i=String(Math.floor(r/60)).padStart(2,`0`),a=String(r%60).padStart(2,`0`);return(0,U.jsxs)(`span`,{className:`font-mono text-[0.8125rem] text-white/60 tabular-nums`,children:[i,`:`,a]})}function W({label:e,on:t,danger:n,busy:r,onClick:i,children:a}){return(0,U.jsx)(`button`,{type:`button`,"aria-label":e,title:e,"aria-pressed":t,disabled:r,onClick:i,className:d(`flex size-12 items-center justify-center rounded-full transition disabled:opacity-50`,n?`bg-rose text-white hover:brightness-110`:t===!1?`bg-white text-neutral-900 hover:bg-white/90`:`bg-white/15 text-white hover:bg-white/25`),children:r?(0,U.jsx)(_,{className:`size-5`}):a})}function we({voice:e}){let t=(0,H.useRef)(null),{captions:n}=e;return(0,H.useEffect)(()=>{n.length&&t.current?.scrollIntoView({block:`end`})},[n]),n.length?(0,U.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-4 sm:px-5`,children:(0,U.jsxs)(`ol`,{className:`mx-auto flex max-w-[720px] flex-col gap-2 py-2`,children:[n.map(e=>(0,U.jsx)(`li`,{className:d(`text-[0.9375rem] leading-snug`,e.who===`bot`?`text-white/95`:`text-right text-white/50`),children:e.text},e.id)),(0,U.jsx)(`div`,{ref:t})]})}):null}function Te({voice:e,view:t,video:n,className:r}){let a=e.state===`live`,o=e.state===`connecting`,[c,l]=(0,H.useState)(null),[u,f]=(0,H.useState)(!1);(0,H.useEffect)(()=>{l(a?Date.now():null)},[a]);let p=async()=>{f(!1),await e.start(),n&&await e.startCamera()},m=()=>{e.stop(),f(!0)},g=n||e.camera,v=[...e.captions].reverse().find(e=>e.who===`bot`),y=[...e.captions].reverse().find(e=>e.who===`me`),x=e.speaking?i(`talk.speaking`):e.listening?i(`talk.listening`):a?i(`talk.live`):o?i(`talk.connecting`):u?i(`video.ended`):``;return(0,U.jsxs)(`section`,{className:d(`relative flex min-h-0 flex-col bg-neutral-950 text-white`,`safe-top`,r),children:[(0,U.jsxs)(`div`,{className:`flex h-14 shrink-0 items-center gap-3 px-4 sm:px-5`,children:[(0,U.jsx)(`div`,{className:`min-w-0 flex-1 truncate font-display font-semibold text-[1rem] tracking-tight`,children:t?.wizard.title??``}),x?(0,U.jsxs)(`span`,{className:`flex items-center gap-1.5 text-[0.8125rem] text-white/70`,children:[a?(0,U.jsx)(`span`,{className:d(`size-2 rounded-full`,e.speaking?`animate-pulse-dot bg-emerald-400`:`bg-rose`)}):null,x]}):null,(0,U.jsx)(Ce,{since:c})]}),(0,U.jsxs)(`div`,{className:d(`grid min-h-0 gap-2 px-3 pb-2 sm:px-4`,g?`flex-1 grid-cols-1 sm:grid-cols-2`:`shrink-0 grid-cols-1`,!g&&a&&e.captions.length?`h-[38%]`:g?``:`flex-1`),children:[(0,U.jsxs)(`div`,{className:d(`relative min-h-0 overflow-hidden rounded-2xl bg-neutral-900`,!g&&`hidden`),children:[(0,U.jsx)(`video`,{ref:e.video,muted:!0,playsInline:!0,autoPlay:!0,className:d(`absolute inset-0 h-full w-full object-cover`,e.facing===`user`&&`-scale-x-100`,e.camera?`block`:`hidden`)}),e.camera?null:(0,U.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-2 text-white/50`,children:[(0,U.jsx)(V,{className:`size-8`}),(0,U.jsx)(`span`,{className:`text-[0.8125rem]`,children:i(`video.cameraOff`)})]}),(0,U.jsxs)(`span`,{className:`absolute bottom-2 left-3 rounded-md bg-black/50 px-2 py-0.5 text-[0.75rem]`,children:[i(`video.you`),e.muted?(0,U.jsx)(se,{className:`ml-1.5 inline size-3`}):null]})]}),(0,U.jsxs)(`div`,{className:d(`relative flex min-h-0 items-center justify-center overflow-hidden rounded-2xl transition-shadow`,g?`bg-neutral-900`:`bg-transparent`,g&&e.speaking&&`ring-2 ring-emerald-400/70`),children:[(0,U.jsx)(`div`,{className:d(`rounded-full transition-shadow duration-500`,!g&&e.listening&&`shadow-[0_0_80px_20px_rgba(244,63,94,0.25)]`,!g&&e.speaking&&`shadow-[0_0_80px_20px_rgba(52,211,153,0.3)]`,e.speaking&&`animate-breathe`),children:(0,U.jsx)(de,{kind:t?.wizard.avatar??`round`,size:g?140:200,fluffy:!0,interactive:!1})}),g?(0,U.jsx)(`span`,{className:`absolute bottom-2 left-3 max-w-[85%] truncate rounded-md bg-black/50 px-2 py-0.5 text-[0.75rem]`,children:t?.wizard.title??``}):null]})]}),a&&!g?(0,U.jsx)(we,{voice:e}):a&&(v||y)?(0,U.jsx)(`div`,{className:`shrink-0 px-4 pb-2 sm:px-5`,children:(0,U.jsxs)(`div`,{className:`mx-auto max-w-[720px] space-y-1 text-center`,children:[y?(0,U.jsx)(`p`,{className:`line-clamp-1 text-[0.8125rem] text-white/50`,children:y.text}):null,v?(0,U.jsx)(`p`,{className:`line-clamp-3 text-[0.9375rem] text-white/95 leading-snug`,children:v.text}):null]})}):null,e.error?(0,U.jsx)(`p`,{className:`shrink-0 px-5 pb-2 text-center text-[0.8125rem] text-rose`,children:e.error}):null,(0,U.jsx)(`div`,{className:`flex shrink-0 items-center justify-center gap-3 px-4 pt-1 pb-4`,children:a?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(W,{label:i(e.muted?`video.unmute`:`video.mute`),on:!e.muted,onClick:e.toggleMute,children:e.muted?(0,U.jsx)(se,{className:`size-5`}):(0,U.jsx)(b,{className:`size-5`})}),(0,U.jsx)(W,{label:i(e.camera?`talk.cameraOff`:`talk.camera`),on:e.camera,onClick:()=>e.camera?e.stopCamera():void e.startCamera(),children:e.camera?(0,U.jsx)(h,{className:`size-5`}):(0,U.jsx)(V,{className:`size-5`})}),e.camera&&Se?(0,U.jsx)(W,{label:i(`video.flip`),onClick:()=>void e.flipCamera(),children:(0,U.jsx)(s,{className:`size-5`})}):null,(0,U.jsx)(W,{label:i(`video.leave`),danger:!0,onClick:m,children:(0,U.jsx)(ce,{className:`size-5`})})]}):(0,U.jsxs)(`div`,{className:`flex flex-col items-center gap-2`,children:[(0,U.jsxs)(`button`,{type:`button`,disabled:o||!t?.talk,onClick:()=>void p(),className:`flex h-12 items-center gap-2 rounded-full bg-emerald-500 px-6 font-medium text-[0.9375rem] text-white transition hover:brightness-110 disabled:opacity-50`,children:[o?(0,U.jsx)(_,{className:`size-4`}):n?(0,U.jsx)(h,{className:`size-5`}):(0,U.jsx)(b,{className:`size-5`}),i(u?`video.rejoin`:n?`video.join`:`talk.start`)]}),!u&&!e.error?(0,U.jsx)(`p`,{className:`max-w-sm text-center text-[0.75rem] text-white/50`,children:i(n?`video.hint`:`talk.joinHint`)}):null]})})]})}var Ee=e=>L[e.kind]!==`device`,De=1024,Oe=4e3;function ke(e,t){return e?e.length>t?`${e.slice(0,t)} …`:e:``}function Ae(e,t,n=!1){let r=[`status: ${e.status}`,`camera: ${n?`on`:`off`}`];if(e.ask)return r.push(e.ask.kind===`confirm`?`question: the step wants to "${e.ask.action.summary}" in ${e.ask.service}; answer_ask allows or skips it`:`question: a sign-in at ${e.ask.site.host}; the person types it on the screen, wait`),r.join(`
|
|
2
2
|
`);if(e.status===`running`){let t=[...e.events].reverse().find(e=>e.type===`tool`||e.type===`info`||e.type===`step_started`);return r.push(`working on: ${e.step?.title??``}`),t&&r.push(`doing: ${M(t)}`),r.join(`
|
|
3
3
|
`)}if(e.status===`done`){r.push(`done. made:`);for(let{step:t,output:n}of e.shown)r.push(`- ${t.title}: ${ke(n?.text,400)||`(a file, on the screen)`}`);return r.join(`
|
|
4
4
|
`)}if(e.status===`failed`)return r.push(`failed: ${e.error??``}; go_back or the person retries on the screen`),r.join(`
|