@algolia/wizard 0.7.0 → 0.8.0-rc.58.43
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 +1 -1
- package/dist/main.js +845 -528
- package/package.json +1 -3
package/dist/main.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { render } from "ink";
|
|
5
5
|
|
|
6
6
|
// src/ui/App.tsx
|
|
7
|
-
import { Box as
|
|
7
|
+
import { Box as Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as useWindowSize8 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
@@ -12,32 +12,86 @@ import { nanoid } from "nanoid";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/algoliaCli.ts
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return require2.resolve("@algolia/cli/bin/run.js");
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
function npxArgs(args) {
|
|
17
|
+
return ["--yes", "@algolia/cli@latest", ...args];
|
|
19
18
|
}
|
|
20
|
-
|
|
19
|
+
var shell = process.platform === "win32";
|
|
20
|
+
function lineSplitter(emit) {
|
|
21
|
+
let buffer = "";
|
|
22
|
+
return {
|
|
23
|
+
push(chunk) {
|
|
24
|
+
buffer += chunk;
|
|
25
|
+
const lines = buffer.split("\n");
|
|
26
|
+
buffer = lines.pop() ?? "";
|
|
27
|
+
for (const line of lines) emit(line.replace(/\r$/, ""));
|
|
28
|
+
},
|
|
29
|
+
flush() {
|
|
30
|
+
if (buffer) emit(buffer.replace(/\r$/, ""));
|
|
31
|
+
buffer = "";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
var wizardSink = (stream, line) => {
|
|
36
|
+
if (!line.trim()) return;
|
|
37
|
+
useWizard.getState().pushCliOutput(stream, line);
|
|
38
|
+
};
|
|
39
|
+
var stderrSink = (stream, line) => {
|
|
40
|
+
if (stream === "stdout") return;
|
|
41
|
+
wizardSink(stream, line);
|
|
42
|
+
};
|
|
43
|
+
function runAlgoliaCli(args, { onOutput } = {}) {
|
|
44
|
+
const store = useWizard.getState();
|
|
45
|
+
const logId = store.logStart("tool", `algolia ${args.join(" ")}`);
|
|
21
46
|
return new Promise((resolve4, reject) => {
|
|
22
|
-
const child = spawn(
|
|
47
|
+
const child = spawn("npx", npxArgs(args), { shell });
|
|
23
48
|
let stdout = "";
|
|
24
49
|
let stderr = "";
|
|
25
|
-
|
|
26
|
-
|
|
50
|
+
const splitters = {
|
|
51
|
+
stdout: lineSplitter((line) => onOutput?.("stdout", line)),
|
|
52
|
+
stderr: lineSplitter((line) => onOutput?.("stderr", line))
|
|
53
|
+
};
|
|
54
|
+
child.stdout.on("data", (chunk) => {
|
|
55
|
+
const text = String(chunk);
|
|
56
|
+
stdout += text;
|
|
57
|
+
splitters.stdout.push(text);
|
|
58
|
+
});
|
|
59
|
+
child.stderr.on("data", (chunk) => {
|
|
60
|
+
const text = String(chunk);
|
|
61
|
+
stderr += text;
|
|
62
|
+
splitters.stderr.push(text);
|
|
63
|
+
});
|
|
27
64
|
child.on("error", reject);
|
|
28
65
|
child.on("close", (code) => {
|
|
66
|
+
splitters.stdout.flush();
|
|
67
|
+
splitters.stderr.flush();
|
|
29
68
|
if (code === 0) {
|
|
30
69
|
resolve4(stdout);
|
|
31
70
|
} else {
|
|
32
|
-
const
|
|
71
|
+
const failed = stderr.trim();
|
|
72
|
+
let detail = "";
|
|
73
|
+
if (failed) {
|
|
74
|
+
detail = `: ${failed}`;
|
|
75
|
+
} else if (stdout.trim()) {
|
|
76
|
+
detail = " (no stderr; stdout withheld \u2014 it may contain credentials)";
|
|
77
|
+
}
|
|
33
78
|
reject(
|
|
34
79
|
new Error(
|
|
35
|
-
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail
|
|
80
|
+
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail}`
|
|
36
81
|
)
|
|
37
82
|
);
|
|
38
83
|
}
|
|
39
84
|
});
|
|
40
|
-
})
|
|
85
|
+
}).then(
|
|
86
|
+
(out) => {
|
|
87
|
+
useWizard.getState().logEnd(logId, "success");
|
|
88
|
+
return out;
|
|
89
|
+
},
|
|
90
|
+
(err) => {
|
|
91
|
+
useWizard.getState().logEnd(logId, "error");
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
);
|
|
41
95
|
}
|
|
42
96
|
async function getUser() {
|
|
43
97
|
let raw;
|
|
@@ -52,19 +106,23 @@ async function getUser() {
|
|
|
52
106
|
return null;
|
|
53
107
|
}
|
|
54
108
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
child.on("error", reject);
|
|
63
|
-
child.on("close", (code) => {
|
|
64
|
-
if (code === 0) resolve4();
|
|
65
|
-
else reject(new Error(`Algolia authentication failed (exit ${code}).`));
|
|
66
|
-
});
|
|
109
|
+
var loginResultSchema = z.object({
|
|
110
|
+
success: z.boolean(),
|
|
111
|
+
email: z.string().optional()
|
|
112
|
+
});
|
|
113
|
+
async function runAuthLogin() {
|
|
114
|
+
const raw = await runAlgoliaCli(["auth", "login", "--non-interactive"], {
|
|
115
|
+
onOutput: stderrSink
|
|
67
116
|
});
|
|
117
|
+
let parsed;
|
|
118
|
+
try {
|
|
119
|
+
parsed = loginResultSchema.safeParse(JSON.parse(raw));
|
|
120
|
+
} catch {
|
|
121
|
+
parsed = void 0;
|
|
122
|
+
}
|
|
123
|
+
if (parsed?.success && !parsed.data.success) {
|
|
124
|
+
throw new Error("Algolia sign-in did not report success.");
|
|
125
|
+
}
|
|
68
126
|
}
|
|
69
127
|
|
|
70
128
|
// src/lib/auth.ts
|
|
@@ -171,6 +229,7 @@ function describeInputValue(value) {
|
|
|
171
229
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
172
230
|
}
|
|
173
231
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
232
|
+
var CLI_OUTPUT_LIMIT = 200;
|
|
174
233
|
var useWizard = create((set, get) => ({
|
|
175
234
|
phase: "idle",
|
|
176
235
|
homeScreen: "home",
|
|
@@ -182,10 +241,18 @@ var useWizard = create((set, get) => ({
|
|
|
182
241
|
notices: [],
|
|
183
242
|
_noticeQueue: [],
|
|
184
243
|
_noticeTimer: null,
|
|
244
|
+
cliOutput: [],
|
|
245
|
+
targetIndex: null,
|
|
185
246
|
logs: [],
|
|
186
247
|
error: null,
|
|
187
248
|
inputReq: null,
|
|
188
249
|
_resolve: null,
|
|
250
|
+
// Brackets a CLI subprocess that needs the screen. Sign-in happens after the
|
|
251
|
+
// welcome screen's enter, so `endAuth` lands on 'preflight', not 'idle':
|
|
252
|
+
// returning to 'idle' would put the welcome screen back up and ask the user
|
|
253
|
+
// to confirm the run a second time.
|
|
254
|
+
beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
|
|
255
|
+
endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
|
|
189
256
|
// Advances past the welcome screen. Only meaningful from 'idle' — once the
|
|
190
257
|
// workflow is running there's nothing left to confirm.
|
|
191
258
|
// Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
|
|
@@ -220,7 +287,13 @@ var useWizard = create((set, get) => ({
|
|
|
220
287
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
221
288
|
setActiveStep: (index) => {
|
|
222
289
|
get()._clearNoticeQueue();
|
|
223
|
-
set({
|
|
290
|
+
set({
|
|
291
|
+
phase: "running",
|
|
292
|
+
currentStepIndex: index,
|
|
293
|
+
output: "",
|
|
294
|
+
notices: [],
|
|
295
|
+
cliOutput: []
|
|
296
|
+
});
|
|
224
297
|
},
|
|
225
298
|
setUser: (user) => set({ user }),
|
|
226
299
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
@@ -261,6 +334,16 @@ var useWizard = create((set, get) => ({
|
|
|
261
334
|
get()._clearNoticeQueue();
|
|
262
335
|
set({ notices: [] });
|
|
263
336
|
},
|
|
337
|
+
// Unthrottled, unlike `pushNotice`: these lines arrive at whatever rate the
|
|
338
|
+
// subprocess emits them, and holding them back would land output after the
|
|
339
|
+
// command it belongs to has already exited.
|
|
340
|
+
pushCliOutput: (stream, text) => set((s) => ({
|
|
341
|
+
cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
|
|
342
|
+
-CLI_OUTPUT_LIMIT
|
|
343
|
+
)
|
|
344
|
+
})),
|
|
345
|
+
clearCliOutput: () => set({ cliOutput: [] }),
|
|
346
|
+
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
264
347
|
logStart: (kind, name, input) => {
|
|
265
348
|
const id = nanoid();
|
|
266
349
|
set((s) => ({
|
|
@@ -305,6 +388,8 @@ var useWizard = create((set, get) => ({
|
|
|
305
388
|
currentStepIndex: 0,
|
|
306
389
|
output: "",
|
|
307
390
|
notices: [],
|
|
391
|
+
cliOutput: [],
|
|
392
|
+
targetIndex: null,
|
|
308
393
|
logs: [],
|
|
309
394
|
error: null,
|
|
310
395
|
inputReq: null,
|
|
@@ -313,16 +398,100 @@ var useWizard = create((set, get) => ({
|
|
|
313
398
|
}
|
|
314
399
|
}));
|
|
315
400
|
|
|
401
|
+
// src/ui/CliOutput.tsx
|
|
402
|
+
import { Box, Text, useWindowSize } from "ink";
|
|
403
|
+
|
|
404
|
+
// src/ui/theme.ts
|
|
405
|
+
var MARKER = {
|
|
406
|
+
pending: "\u25CB",
|
|
407
|
+
running: "\u25D0",
|
|
408
|
+
done: "\u2713",
|
|
409
|
+
error: "\u2716"
|
|
410
|
+
};
|
|
411
|
+
var BRAND = "#003DFF";
|
|
412
|
+
var SECONDARY = "#5468FF";
|
|
413
|
+
var DANGER = "#F86E7E";
|
|
414
|
+
var COLORS = {
|
|
415
|
+
brand: BRAND,
|
|
416
|
+
primary: "#E6EDF3",
|
|
417
|
+
secondary: SECONDARY,
|
|
418
|
+
strong: "#FFFFFF",
|
|
419
|
+
muted: "#8B949E",
|
|
420
|
+
dim: "#484F58",
|
|
421
|
+
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
422
|
+
badge: "#E3B341",
|
|
423
|
+
danger: DANGER,
|
|
424
|
+
success: "#4ADE80",
|
|
425
|
+
bg: {
|
|
426
|
+
main: "#0B0E14",
|
|
427
|
+
sidebar: "#14171E"
|
|
428
|
+
},
|
|
429
|
+
border: "#30363D",
|
|
430
|
+
accent: "#76A0FF",
|
|
431
|
+
status: {
|
|
432
|
+
pending: "gray",
|
|
433
|
+
running: "#76A0FF",
|
|
434
|
+
done: "#4ADE80",
|
|
435
|
+
error: DANGER
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/ui/CliOutput.tsx
|
|
440
|
+
import { jsxs } from "react/jsx-runtime";
|
|
441
|
+
var CLI_MARKER = "\u203A";
|
|
442
|
+
var RESERVED_ROWS = 16;
|
|
443
|
+
var MAX_ROWS = 12;
|
|
444
|
+
var PANEL_TEXT_WIDTH = 45;
|
|
445
|
+
var URL_PATTERN = /https?:\/\//;
|
|
446
|
+
function rowCost(text) {
|
|
447
|
+
return URL_PATTERN.test(text) ? Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH)) : 1;
|
|
448
|
+
}
|
|
449
|
+
function CliOutput() {
|
|
450
|
+
const cliOutput = useWizard((s) => s.cliOutput);
|
|
451
|
+
const { rows } = useWindowSize();
|
|
452
|
+
if (!cliOutput.length) return null;
|
|
453
|
+
const rowBudget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_ROWS);
|
|
454
|
+
const visible = [];
|
|
455
|
+
let usedRows = 0;
|
|
456
|
+
for (let i = cliOutput.length - 1; i >= 0; i--) {
|
|
457
|
+
const cost = rowCost(cliOutput[i].text);
|
|
458
|
+
if (usedRows + cost > rowBudget && visible.length > 0) break;
|
|
459
|
+
visible.unshift(cliOutput[i]);
|
|
460
|
+
usedRows += cost;
|
|
461
|
+
}
|
|
462
|
+
const hidden = cliOutput.length - visible.length;
|
|
463
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
464
|
+
hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
|
|
465
|
+
"\u2191 ",
|
|
466
|
+
hidden,
|
|
467
|
+
" earlier line(s)"
|
|
468
|
+
] }),
|
|
469
|
+
visible.map((line) => /* @__PURE__ */ jsxs(
|
|
470
|
+
Text,
|
|
471
|
+
{
|
|
472
|
+
color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
|
|
473
|
+
wrap: URL_PATTERN.test(line.text) ? "wrap" : "truncate",
|
|
474
|
+
children: [
|
|
475
|
+
CLI_MARKER,
|
|
476
|
+
" ",
|
|
477
|
+
line.text
|
|
478
|
+
]
|
|
479
|
+
},
|
|
480
|
+
line.id
|
|
481
|
+
))
|
|
482
|
+
] });
|
|
483
|
+
}
|
|
484
|
+
|
|
316
485
|
// src/ui/Notices.tsx
|
|
317
|
-
import { Box as
|
|
486
|
+
import { Box as Box3, Text as Text3, useWindowSize as useWindowSize3 } from "ink";
|
|
318
487
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
319
488
|
|
|
320
489
|
// src/ui/Table.tsx
|
|
321
|
-
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
490
|
+
import { Box as Box2, Text as Text2, measureElement, useWindowSize as useWindowSize2 } from "ink";
|
|
322
491
|
import { useEffect, useRef, useState } from "react";
|
|
323
492
|
import { jsx } from "react/jsx-runtime";
|
|
324
493
|
function Table({ columns, rows }) {
|
|
325
|
-
const { columns: termCols } =
|
|
494
|
+
const { columns: termCols } = useWindowSize2();
|
|
326
495
|
const ref = useRef(null);
|
|
327
496
|
const [width, setWidth] = useState(0);
|
|
328
497
|
useEffect(() => {
|
|
@@ -330,7 +499,7 @@ function Table({ columns, rows }) {
|
|
|
330
499
|
}, [termCols, columns, rows]);
|
|
331
500
|
if (rows.length === 0) return null;
|
|
332
501
|
const lines = formatTable(columns, rows, width || void 0);
|
|
333
|
-
return /* @__PURE__ */ jsx(
|
|
502
|
+
return /* @__PURE__ */ jsx(Box2, { flexDirection: "column", ref, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text2, { wrap: "truncate", children: line }, `tbl-${i}`)) });
|
|
334
503
|
}
|
|
335
504
|
function formatTable(columns, rows, width) {
|
|
336
505
|
const natural = columns.map(
|
|
@@ -370,48 +539,13 @@ function resize(widths, budget) {
|
|
|
370
539
|
}
|
|
371
540
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
372
541
|
|
|
373
|
-
// src/ui/theme.ts
|
|
374
|
-
var MARKER = {
|
|
375
|
-
pending: "\u25CB",
|
|
376
|
-
running: "\u25D0",
|
|
377
|
-
done: "\u2713",
|
|
378
|
-
error: "\u2716"
|
|
379
|
-
};
|
|
380
|
-
var BRAND = "#003DFF";
|
|
381
|
-
var SECONDARY = "#5468FF";
|
|
382
|
-
var DANGER = "#F86E7E";
|
|
383
|
-
var COLORS = {
|
|
384
|
-
brand: BRAND,
|
|
385
|
-
primary: "#E6EDF3",
|
|
386
|
-
secondary: SECONDARY,
|
|
387
|
-
strong: "#FFFFFF",
|
|
388
|
-
muted: "#8B949E",
|
|
389
|
-
dim: "#484F58",
|
|
390
|
-
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
391
|
-
badge: "#E3B341",
|
|
392
|
-
danger: DANGER,
|
|
393
|
-
success: "#4ADE80",
|
|
394
|
-
bg: {
|
|
395
|
-
main: "#0B0E14",
|
|
396
|
-
sidebar: "#14171E"
|
|
397
|
-
},
|
|
398
|
-
border: "#30363D",
|
|
399
|
-
accent: "#76A0FF",
|
|
400
|
-
status: {
|
|
401
|
-
pending: "gray",
|
|
402
|
-
running: "#76A0FF",
|
|
403
|
-
done: "#4ADE80",
|
|
404
|
-
error: DANGER
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
542
|
// src/ui/Notices.tsx
|
|
409
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
543
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
410
544
|
var AGENT_MARKER = "\u2726";
|
|
411
|
-
var
|
|
412
|
-
var
|
|
545
|
+
var RESERVED_ROWS2 = 14;
|
|
546
|
+
var PANEL_TEXT_WIDTH2 = 45;
|
|
413
547
|
function messageLineCount(text) {
|
|
414
|
-
return Math.max(1, Math.ceil(text.length /
|
|
548
|
+
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH2));
|
|
415
549
|
}
|
|
416
550
|
function noticeLineCount(notice) {
|
|
417
551
|
const messageLines = (notice.messages ?? []).reduce((sum, m) => {
|
|
@@ -422,7 +556,7 @@ function noticeLineCount(notice) {
|
|
|
422
556
|
return messageLines + tableLines;
|
|
423
557
|
}
|
|
424
558
|
function fitVisibleNotices(notices, windowRows) {
|
|
425
|
-
const budget = Math.max(windowRows -
|
|
559
|
+
const budget = Math.max(windowRows - RESERVED_ROWS2, 3);
|
|
426
560
|
let used = 0;
|
|
427
561
|
let count = 0;
|
|
428
562
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -455,7 +589,7 @@ function parseHex(hex) {
|
|
|
455
589
|
}
|
|
456
590
|
function Notices() {
|
|
457
591
|
const notices = useWizard((s) => s.notices);
|
|
458
|
-
const { rows: windowRows } =
|
|
592
|
+
const { rows: windowRows } = useWindowSize3();
|
|
459
593
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
460
594
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
461
595
|
useEffect2(() => {
|
|
@@ -472,14 +606,14 @@ function Notices() {
|
|
|
472
606
|
}, []);
|
|
473
607
|
if (!visible.length) return null;
|
|
474
608
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
475
|
-
return /* @__PURE__ */ jsx2(
|
|
609
|
+
return /* @__PURE__ */ jsx2(Box3, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
476
610
|
const isLatest = i === visible.length - 1;
|
|
477
|
-
return /* @__PURE__ */
|
|
611
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
|
|
478
612
|
notice.messages?.map((m, j) => {
|
|
479
613
|
const line = typeof m === "string" ? { text: m } : m;
|
|
480
614
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
481
|
-
return /* @__PURE__ */
|
|
482
|
-
|
|
615
|
+
return /* @__PURE__ */ jsxs2(
|
|
616
|
+
Text3,
|
|
483
617
|
{
|
|
484
618
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
485
619
|
bold: line.bold,
|
|
@@ -497,41 +631,43 @@ function Notices() {
|
|
|
497
631
|
}
|
|
498
632
|
|
|
499
633
|
// src/ui/PromptInput.tsx
|
|
500
|
-
import { Box as
|
|
634
|
+
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
501
635
|
import TextInput from "ink-text-input";
|
|
502
636
|
import { useState as useState4 } from "react";
|
|
503
637
|
|
|
504
638
|
// src/ui/NextAction.tsx
|
|
505
|
-
import { Box as
|
|
506
|
-
import { Fragment, jsx as jsx3, jsxs as
|
|
639
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
640
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
507
641
|
function NextAction({
|
|
508
642
|
action,
|
|
509
643
|
keyHint,
|
|
510
644
|
hierarchy = "primary"
|
|
511
645
|
}) {
|
|
512
|
-
return /* @__PURE__ */
|
|
513
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
514
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
515
|
-
/* @__PURE__ */ jsx3(
|
|
516
|
-
/* @__PURE__ */ jsx3(
|
|
646
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "row", gap: 1, children: [
|
|
647
|
+
hierarchy === "primary" && /* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `> ${action}` }),
|
|
648
|
+
hierarchy === "secondary" && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
649
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `>` }),
|
|
650
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, bold: true, children: action })
|
|
517
651
|
] }),
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */ jsx3(
|
|
520
|
-
/* @__PURE__ */ jsx3(
|
|
521
|
-
/* @__PURE__ */ jsx3(
|
|
522
|
-
/* @__PURE__ */ jsx3(
|
|
652
|
+
/* @__PURE__ */ jsxs3(Box4, { children: [
|
|
653
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: "press " }),
|
|
654
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `[` }),
|
|
655
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, children: keyHint }),
|
|
656
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `]` })
|
|
523
657
|
] })
|
|
524
658
|
] });
|
|
525
659
|
}
|
|
526
660
|
|
|
527
661
|
// src/ui/SelectPrompt.tsx
|
|
528
|
-
import { Box as
|
|
662
|
+
import { Box as Box5, Text as Text5, measureElement as measureElement2, useInput, useWindowSize as useWindowSize4 } from "ink";
|
|
529
663
|
import { useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
530
|
-
import { jsx as jsx4, jsxs as
|
|
664
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
531
665
|
var CANCEL = "cancel";
|
|
532
666
|
var ARROW_WIDTH = 4;
|
|
533
667
|
var COLUMN_GAP = 2;
|
|
534
668
|
var BAR_PADDING = 2;
|
|
669
|
+
var ROW_HEIGHT = 3;
|
|
670
|
+
var INDICATOR_ROWS = 2;
|
|
535
671
|
function fittedWidth(node, columns) {
|
|
536
672
|
let left = 0;
|
|
537
673
|
for (let n = node; n; n = n.parentNode) {
|
|
@@ -564,13 +700,18 @@ function SelectPrompt({
|
|
|
564
700
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
565
701
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
566
702
|
const containerRef = useRef2(null);
|
|
567
|
-
const
|
|
703
|
+
const viewportRef = useRef2(null);
|
|
704
|
+
const { columns, rows: windowRows } = useWindowSize4();
|
|
568
705
|
const [width, setWidth] = useState3(columns);
|
|
706
|
+
const [viewportHeight, setViewportHeight] = useState3(null);
|
|
569
707
|
useLayoutEffect(() => {
|
|
570
708
|
if (containerRef.current) {
|
|
571
709
|
setWidth(fittedWidth(containerRef.current, columns));
|
|
572
710
|
}
|
|
573
|
-
|
|
711
|
+
if (viewportRef.current) {
|
|
712
|
+
setViewportHeight(measureElement2(viewportRef.current).height);
|
|
713
|
+
}
|
|
714
|
+
}, [columns, windowRows, error, question, helpText, messages, table]);
|
|
574
715
|
const inner = Math.max(width - BAR_PADDING, 0);
|
|
575
716
|
const labelWidth = Math.min(
|
|
576
717
|
ARROW_WIDTH + (multi ? 2 : 0) + Math.max(0, ...rows.map((opt) => opt.length)) + COLUMN_GAP,
|
|
@@ -586,6 +727,22 @@ function SelectPrompt({
|
|
|
586
727
|
const barWidth = Math.min(labelWidth + badgeWidth + BAR_PADDING, width);
|
|
587
728
|
const barLabelWidth = Math.max(barWidth - BAR_PADDING - badgeWidth, 0);
|
|
588
729
|
const textWidth = inner - labelWidth;
|
|
730
|
+
const capacity = viewportHeight === null || rows.length * ROW_HEIGHT <= viewportHeight ? rows.length : Math.max(Math.floor((viewportHeight - INDICATOR_ROWS) / ROW_HEIGHT), 1);
|
|
731
|
+
const maxOffset = Math.max(rows.length - capacity, 0);
|
|
732
|
+
const [offset, setOffset] = useState3(0);
|
|
733
|
+
useLayoutEffect(() => {
|
|
734
|
+
setOffset((o) => {
|
|
735
|
+
const clamped = Math.min(o, maxOffset);
|
|
736
|
+
if (index < clamped) return index;
|
|
737
|
+
if (index >= clamped + capacity) {
|
|
738
|
+
return Math.min(index - capacity + 1, maxOffset);
|
|
739
|
+
}
|
|
740
|
+
return clamped;
|
|
741
|
+
});
|
|
742
|
+
}, [index, capacity, maxOffset]);
|
|
743
|
+
const visible = rows.slice(offset, offset + capacity);
|
|
744
|
+
const hiddenAbove = offset;
|
|
745
|
+
const hiddenBelow = rows.length - offset - visible.length;
|
|
589
746
|
useInput((input, key) => {
|
|
590
747
|
if (rows.length === 0) return;
|
|
591
748
|
if (key.upArrow || input === "k") {
|
|
@@ -609,62 +766,77 @@ function SelectPrompt({
|
|
|
609
766
|
}
|
|
610
767
|
}
|
|
611
768
|
});
|
|
612
|
-
return /* @__PURE__ */ jsx4(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
769
|
+
return /* @__PURE__ */ jsx4(Box5, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, width, children: [
|
|
770
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
|
|
771
|
+
error && /* @__PURE__ */ jsx4(Text5, { color: COLORS.danger, children: error }),
|
|
772
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
773
|
+
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
774
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
775
|
+
question && /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: question }),
|
|
776
|
+
helpText && /* @__PURE__ */ jsx4(Text5, { color: COLORS.dim, children: helpText })
|
|
777
|
+
] })
|
|
619
778
|
] }),
|
|
620
|
-
/* @__PURE__ */
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
779
|
+
/* @__PURE__ */ jsxs4(Box5, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
780
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
781
|
+
"\u2191 ",
|
|
782
|
+
hiddenAbove,
|
|
783
|
+
" more"
|
|
784
|
+
] }),
|
|
785
|
+
visible.map((option, visibleIndex) => {
|
|
786
|
+
const i = offset + visibleIndex;
|
|
787
|
+
const highlighted = i === index;
|
|
788
|
+
const isCancel = i === cancelIndex;
|
|
789
|
+
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
790
|
+
const sec = isCancel ? void 0 : secondary?.[i];
|
|
791
|
+
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
792
|
+
const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
|
|
793
|
+
highlighted ? "\u276F " : " ",
|
|
794
|
+
bullet,
|
|
795
|
+
option
|
|
796
|
+
] });
|
|
797
|
+
const isText = sec?.kind === "text";
|
|
798
|
+
return /* @__PURE__ */ jsxs4(
|
|
799
|
+
Box5,
|
|
800
|
+
{
|
|
801
|
+
width: isText ? "100%" : barWidth,
|
|
802
|
+
paddingX: 1,
|
|
803
|
+
paddingY: 1,
|
|
804
|
+
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
805
|
+
children: [
|
|
806
|
+
/* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
807
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
808
|
+
Text5,
|
|
809
|
+
{
|
|
810
|
+
wrap: "truncate",
|
|
811
|
+
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
812
|
+
children: sec.value
|
|
813
|
+
}
|
|
814
|
+
) }),
|
|
815
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box5, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text5, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
816
|
+
]
|
|
817
|
+
},
|
|
818
|
+
`row-${i}`
|
|
819
|
+
);
|
|
820
|
+
}),
|
|
821
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
822
|
+
"\u2193 ",
|
|
823
|
+
hiddenBelow,
|
|
824
|
+
" more"
|
|
825
|
+
] })
|
|
826
|
+
] }),
|
|
827
|
+
/* @__PURE__ */ jsx4(Box5, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
656
828
|
i > 0 ? " " : "",
|
|
657
|
-
/* @__PURE__ */ jsx4(
|
|
658
|
-
/* @__PURE__ */
|
|
829
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
|
|
830
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
659
831
|
" ",
|
|
660
832
|
label
|
|
661
833
|
] })
|
|
662
|
-
] }, label)) })
|
|
834
|
+
] }, label)) }) })
|
|
663
835
|
] }) });
|
|
664
836
|
}
|
|
665
837
|
|
|
666
838
|
// src/ui/PromptInput.tsx
|
|
667
|
-
import { jsx as jsx5, jsxs as
|
|
839
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
668
840
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
669
841
|
function EnterToContinuePrompt({
|
|
670
842
|
question,
|
|
@@ -675,10 +847,10 @@ function EnterToContinuePrompt({
|
|
|
675
847
|
if (key.return) onDecide(true);
|
|
676
848
|
else if (key.escape) onDecide(false);
|
|
677
849
|
});
|
|
678
|
-
return /* @__PURE__ */
|
|
679
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
680
|
-
question && /* @__PURE__ */ jsx5(
|
|
681
|
-
/* @__PURE__ */
|
|
850
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 1, children: [
|
|
851
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
852
|
+
question && /* @__PURE__ */ jsx5(Text6, { color: COLORS.primary, children: question }),
|
|
853
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
682
854
|
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
|
|
683
855
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
684
856
|
] })
|
|
@@ -688,11 +860,11 @@ function PromptInput() {
|
|
|
688
860
|
const { phase, inputReq, submitInput } = useWizard();
|
|
689
861
|
const [draft, setDraft] = useState4("");
|
|
690
862
|
if (phase === "done" || phase === "error") {
|
|
691
|
-
return /* @__PURE__ */ jsx5(
|
|
863
|
+
return /* @__PURE__ */ jsx5(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
692
864
|
}
|
|
693
865
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
694
866
|
if (inputReq.promptType === "multipleChoice") {
|
|
695
|
-
return /* @__PURE__ */ jsx5(
|
|
867
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
696
868
|
SelectPrompt,
|
|
697
869
|
{
|
|
698
870
|
question: inputReq.prompt,
|
|
@@ -709,7 +881,7 @@ function PromptInput() {
|
|
|
709
881
|
) });
|
|
710
882
|
}
|
|
711
883
|
if (inputReq.promptType === "multiSelect") {
|
|
712
|
-
return /* @__PURE__ */ jsx5(
|
|
884
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
713
885
|
SelectPrompt,
|
|
714
886
|
{
|
|
715
887
|
multi: true,
|
|
@@ -724,7 +896,7 @@ function PromptInput() {
|
|
|
724
896
|
) });
|
|
725
897
|
}
|
|
726
898
|
if (inputReq.promptType === "notice") {
|
|
727
|
-
return /* @__PURE__ */ jsx5(
|
|
899
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
728
900
|
SelectPrompt,
|
|
729
901
|
{
|
|
730
902
|
question: inputReq.prompt,
|
|
@@ -746,7 +918,7 @@ function PromptInput() {
|
|
|
746
918
|
}
|
|
747
919
|
if (inputReq.promptType === "acceptReject") {
|
|
748
920
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
749
|
-
return /* @__PURE__ */ jsx5(
|
|
921
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
750
922
|
SelectPrompt,
|
|
751
923
|
{
|
|
752
924
|
question: inputReq.prompt,
|
|
@@ -757,11 +929,11 @@ function PromptInput() {
|
|
|
757
929
|
}
|
|
758
930
|
) });
|
|
759
931
|
}
|
|
760
|
-
return /* @__PURE__ */
|
|
761
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
762
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
763
|
-
/* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
932
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
933
|
+
inputReq.error && /* @__PURE__ */ jsx5(Text6, { color: COLORS.danger, children: inputReq.error }),
|
|
934
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
935
|
+
/* @__PURE__ */ jsxs5(Box6, { children: [
|
|
936
|
+
/* @__PURE__ */ jsxs5(Text6, { color: COLORS.primary, children: [
|
|
765
937
|
inputReq.prompt,
|
|
766
938
|
" "
|
|
767
939
|
] }),
|
|
@@ -783,7 +955,7 @@ function PromptInput() {
|
|
|
783
955
|
// src/ui/Welcome.tsx
|
|
784
956
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
785
957
|
import { fileURLToPath } from "node:url";
|
|
786
|
-
import { Box as
|
|
958
|
+
import { Box as Box7, Spacer, Text as Text7, useInput as useInput3, useWindowSize as useWindowSize5 } from "ink";
|
|
787
959
|
|
|
788
960
|
// src/ui/copy/welcome.ts
|
|
789
961
|
var sidebarItems = [
|
|
@@ -811,27 +983,27 @@ var sidebarItems = [
|
|
|
811
983
|
|
|
812
984
|
// src/ui/Welcome.tsx
|
|
813
985
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
814
|
-
import { jsx as jsx6, jsxs as
|
|
986
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
815
987
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
816
988
|
function SidebarItem({
|
|
817
989
|
title,
|
|
818
990
|
description
|
|
819
991
|
}) {
|
|
820
|
-
return /* @__PURE__ */
|
|
821
|
-
/* @__PURE__ */
|
|
822
|
-
/* @__PURE__ */ jsx6(
|
|
823
|
-
/* @__PURE__ */ jsx6(
|
|
992
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
993
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, children: [
|
|
994
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.success, children: "\u2192" }),
|
|
995
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.strong, bold: true, children: title })
|
|
824
996
|
] }),
|
|
825
|
-
/* @__PURE__ */
|
|
997
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 2, children: [
|
|
826
998
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
827
|
-
/* @__PURE__ */ jsx6(
|
|
999
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: description })
|
|
828
1000
|
] })
|
|
829
1001
|
] });
|
|
830
1002
|
}
|
|
831
1003
|
function Welcome() {
|
|
832
1004
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
833
1005
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
834
|
-
const { rows } =
|
|
1006
|
+
const { rows } = useWindowSize5();
|
|
835
1007
|
useInput3((input, key) => {
|
|
836
1008
|
if (key.return) confirmStart();
|
|
837
1009
|
else if (input === "i") openLearnMore();
|
|
@@ -850,15 +1022,15 @@ function Welcome() {
|
|
|
850
1022
|
if (rows < 30) {
|
|
851
1023
|
layout = scales["small"];
|
|
852
1024
|
}
|
|
853
|
-
return /* @__PURE__ */
|
|
1025
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
854
1026
|
/* @__PURE__ */ jsx6(
|
|
855
|
-
|
|
1027
|
+
Box7,
|
|
856
1028
|
{
|
|
857
1029
|
paddingY: layout.main.padding.y,
|
|
858
1030
|
paddingX: layout.main.padding.x,
|
|
859
1031
|
flexDirection: "column",
|
|
860
1032
|
justifyContent: "center",
|
|
861
|
-
children: /* @__PURE__ */
|
|
1033
|
+
children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 2, children: [
|
|
862
1034
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
863
1035
|
Image,
|
|
864
1036
|
{
|
|
@@ -870,16 +1042,16 @@ function Welcome() {
|
|
|
870
1042
|
protocol: "halfBlock"
|
|
871
1043
|
}
|
|
872
1044
|
) }),
|
|
873
|
-
/* @__PURE__ */ jsx6(
|
|
874
|
-
/* @__PURE__ */
|
|
1045
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
1046
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, flexDirection: "column", children: [
|
|
875
1047
|
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
876
1048
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
877
1049
|
] })
|
|
878
1050
|
] })
|
|
879
1051
|
}
|
|
880
1052
|
),
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
|
|
1053
|
+
/* @__PURE__ */ jsxs6(
|
|
1054
|
+
Box7,
|
|
883
1055
|
{
|
|
884
1056
|
backgroundColor: COLORS.bg.sidebar,
|
|
885
1057
|
width: 40,
|
|
@@ -889,7 +1061,7 @@ function Welcome() {
|
|
|
889
1061
|
flexDirection: "column",
|
|
890
1062
|
justifyContent: "center",
|
|
891
1063
|
children: [
|
|
892
|
-
/* @__PURE__ */ jsx6(
|
|
1064
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
893
1065
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
894
1066
|
]
|
|
895
1067
|
}
|
|
@@ -899,7 +1071,7 @@ function Welcome() {
|
|
|
899
1071
|
|
|
900
1072
|
// src/ui/LearnMore.tsx
|
|
901
1073
|
import { Fragment as Fragment2 } from "react";
|
|
902
|
-
import { Box as
|
|
1074
|
+
import { Box as Box8, Text as Text8, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
|
|
903
1075
|
|
|
904
1076
|
// src/ui/copy/learn-more.ts
|
|
905
1077
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -936,7 +1108,7 @@ var policyLinks = [
|
|
|
936
1108
|
];
|
|
937
1109
|
|
|
938
1110
|
// src/ui/LearnMore.tsx
|
|
939
|
-
import { jsx as jsx7, jsxs as
|
|
1111
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
940
1112
|
var TAG_COLORS = {
|
|
941
1113
|
READ: COLORS.success,
|
|
942
1114
|
WRITE: COLORS.badge,
|
|
@@ -952,25 +1124,25 @@ function NeverLine({
|
|
|
952
1124
|
}) {
|
|
953
1125
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
954
1126
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
955
|
-
return /* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */ jsx7(
|
|
1127
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1128
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" }),
|
|
957
1129
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
958
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
1130
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text8, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
959
1131
|
" ".repeat(rightPad),
|
|
960
|
-
/* @__PURE__ */ jsx7(
|
|
1132
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" })
|
|
961
1133
|
] });
|
|
962
1134
|
}
|
|
963
1135
|
function LearnMore() {
|
|
964
1136
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
965
1137
|
const backToHome = useWizard((s) => s.backToHome);
|
|
966
|
-
const { columns } =
|
|
1138
|
+
const { columns } = useWindowSize6();
|
|
967
1139
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
968
1140
|
useInput4((_input, key) => {
|
|
969
1141
|
if (key.escape) backToHome();
|
|
970
1142
|
else if (key.return) confirmStart();
|
|
971
1143
|
});
|
|
972
|
-
return /* @__PURE__ */
|
|
973
|
-
|
|
1144
|
+
return /* @__PURE__ */ jsxs7(
|
|
1145
|
+
Box8,
|
|
974
1146
|
{
|
|
975
1147
|
flexDirection: "column",
|
|
976
1148
|
paddingX: PADDING_X,
|
|
@@ -978,20 +1150,20 @@ function LearnMore() {
|
|
|
978
1150
|
width: "100%",
|
|
979
1151
|
gap: 1,
|
|
980
1152
|
children: [
|
|
981
|
-
/* @__PURE__ */ jsx7(
|
|
982
|
-
/* @__PURE__ */ jsx7(
|
|
983
|
-
/* @__PURE__ */ jsx7(
|
|
984
|
-
/* @__PURE__ */ jsx7(
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */ jsx7(
|
|
987
|
-
/* @__PURE__ */ jsx7(
|
|
988
|
-
/* @__PURE__ */ jsx7(
|
|
989
|
-
/* @__PURE__ */ jsx7(
|
|
1153
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
1154
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: accessIntro }),
|
|
1155
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1156
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
1157
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
1158
|
+
/* @__PURE__ */ jsx7(Box8, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
1159
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1160
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: item.title }),
|
|
1161
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
990
1162
|
] }) })
|
|
991
1163
|
] })
|
|
992
1164
|
] }, item.tag)) }),
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
/* @__PURE__ */ jsx7(
|
|
1165
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
1166
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
995
1167
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
996
1168
|
/* @__PURE__ */ jsx7(
|
|
997
1169
|
NeverLine,
|
|
@@ -1000,7 +1172,7 @@ function LearnMore() {
|
|
|
1000
1172
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1001
1173
|
}
|
|
1002
1174
|
),
|
|
1003
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1175
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1004
1176
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1005
1177
|
/* @__PURE__ */ jsx7(
|
|
1006
1178
|
NeverLine,
|
|
@@ -1015,23 +1187,23 @@ function LearnMore() {
|
|
|
1015
1187
|
)
|
|
1016
1188
|
] }, item)),
|
|
1017
1189
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1018
|
-
/* @__PURE__ */ jsx7(
|
|
1190
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1019
1191
|
] }),
|
|
1020
|
-
/* @__PURE__ */ jsx7(
|
|
1021
|
-
/* @__PURE__ */ jsx7(
|
|
1022
|
-
/* @__PURE__ */ jsx7(
|
|
1192
|
+
/* @__PURE__ */ jsx7(Box8, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1193
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1194
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.accent, children: link.url })
|
|
1023
1195
|
] }, link.label)) }),
|
|
1024
|
-
/* @__PURE__ */
|
|
1025
|
-
/* @__PURE__ */
|
|
1026
|
-
/* @__PURE__ */ jsx7(
|
|
1027
|
-
/* @__PURE__ */ jsx7(
|
|
1028
|
-
/* @__PURE__ */ jsx7(
|
|
1196
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1197
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1198
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1199
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "esc" }),
|
|
1200
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "] back" })
|
|
1029
1201
|
] }),
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
/* @__PURE__ */ jsx7(
|
|
1032
|
-
/* @__PURE__ */ jsx7(
|
|
1033
|
-
/* @__PURE__ */ jsx7(
|
|
1034
|
-
/* @__PURE__ */ jsx7(
|
|
1202
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1203
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1204
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "enter" }),
|
|
1205
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "]" }),
|
|
1206
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1035
1207
|
] })
|
|
1036
1208
|
] })
|
|
1037
1209
|
]
|
|
@@ -1040,10 +1212,10 @@ function LearnMore() {
|
|
|
1040
1212
|
}
|
|
1041
1213
|
|
|
1042
1214
|
// src/ui/Sidebar.tsx
|
|
1043
|
-
import { Box as
|
|
1215
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1044
1216
|
|
|
1045
1217
|
// src/ui/Steps.tsx
|
|
1046
|
-
import { Box as
|
|
1218
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1047
1219
|
import Spinner from "ink-spinner";
|
|
1048
1220
|
|
|
1049
1221
|
// src/core/persistence.ts
|
|
@@ -1072,11 +1244,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1072
1244
|
}
|
|
1073
1245
|
|
|
1074
1246
|
// src/ui/Steps.tsx
|
|
1075
|
-
import { jsx as jsx8, jsxs as
|
|
1247
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1076
1248
|
function Steps() {
|
|
1077
1249
|
const { steps } = useWizard();
|
|
1078
1250
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1079
|
-
return /* @__PURE__ */ jsx8(
|
|
1251
|
+
return /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status[s.status], children: [
|
|
1080
1252
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1081
1253
|
" ",
|
|
1082
1254
|
s.title
|
|
@@ -1086,7 +1258,7 @@ function CurrentStep() {
|
|
|
1086
1258
|
const { steps } = useWizard();
|
|
1087
1259
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1088
1260
|
if (!currentStep) return null;
|
|
1089
|
-
return /* @__PURE__ */
|
|
1261
|
+
return /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status.running, children: [
|
|
1090
1262
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1091
1263
|
" ",
|
|
1092
1264
|
` ${currentStep.title}`
|
|
@@ -1094,19 +1266,19 @@ function CurrentStep() {
|
|
|
1094
1266
|
}
|
|
1095
1267
|
|
|
1096
1268
|
// src/ui/Progress.tsx
|
|
1097
|
-
import { Box as
|
|
1098
|
-
import { jsx as jsx9, jsxs as
|
|
1269
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1270
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1099
1271
|
function Progress() {
|
|
1100
1272
|
const { steps, currentStepIndex } = useWizard();
|
|
1101
1273
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1102
1274
|
if (visibleSteps.length === 0) return null;
|
|
1103
1275
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1104
1276
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1105
|
-
return /* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */ jsx9(
|
|
1107
|
-
/* @__PURE__ */ jsx9(
|
|
1108
|
-
/* @__PURE__ */ jsx9(
|
|
1109
|
-
/* @__PURE__ */ jsx9(
|
|
1277
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1278
|
+
/* @__PURE__ */ jsx9(Text10, { color: COLORS.muted, children: "STEP" }),
|
|
1279
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: activeStepNumber }),
|
|
1280
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: "/" }),
|
|
1281
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: visibleSteps.length })
|
|
1110
1282
|
] });
|
|
1111
1283
|
}
|
|
1112
1284
|
|
|
@@ -1117,10 +1289,10 @@ var sidebarCommands = [
|
|
|
1117
1289
|
];
|
|
1118
1290
|
|
|
1119
1291
|
// src/ui/Sidebar.tsx
|
|
1120
|
-
import { jsx as jsx10, jsxs as
|
|
1292
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1121
1293
|
function Sidebar() {
|
|
1122
|
-
return /* @__PURE__ */
|
|
1123
|
-
|
|
1294
|
+
return /* @__PURE__ */ jsxs10(
|
|
1295
|
+
Box11,
|
|
1124
1296
|
{
|
|
1125
1297
|
backgroundColor: "#14171E",
|
|
1126
1298
|
width: 30,
|
|
@@ -1129,16 +1301,16 @@ function Sidebar() {
|
|
|
1129
1301
|
flexDirection: "column",
|
|
1130
1302
|
justifyContent: "space-between",
|
|
1131
1303
|
children: [
|
|
1132
|
-
/* @__PURE__ */
|
|
1133
|
-
/* @__PURE__ */ jsx10(
|
|
1304
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1305
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1134
1306
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1135
1307
|
] }),
|
|
1136
|
-
/* @__PURE__ */
|
|
1308
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1137
1309
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1138
|
-
/* @__PURE__ */ jsx10(
|
|
1139
|
-
return /* @__PURE__ */
|
|
1140
|
-
/* @__PURE__ */ jsx10(
|
|
1141
|
-
/* @__PURE__ */ jsx10(
|
|
1310
|
+
/* @__PURE__ */ jsx10(Box11, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1311
|
+
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1312
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1313
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: c.description })
|
|
1142
1314
|
] });
|
|
1143
1315
|
}) })
|
|
1144
1316
|
] })
|
|
@@ -1148,12 +1320,12 @@ function Sidebar() {
|
|
|
1148
1320
|
}
|
|
1149
1321
|
|
|
1150
1322
|
// src/ui/Ribbon.tsx
|
|
1151
|
-
import { Box as
|
|
1152
|
-
import { jsx as jsx11, jsxs as
|
|
1323
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1324
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1153
1325
|
function Ribbon() {
|
|
1154
1326
|
const firstCommand = sidebarCommands[0];
|
|
1155
|
-
return /* @__PURE__ */
|
|
1156
|
-
|
|
1327
|
+
return /* @__PURE__ */ jsxs11(
|
|
1328
|
+
Box12,
|
|
1157
1329
|
{
|
|
1158
1330
|
backgroundColor: "#14171E",
|
|
1159
1331
|
flexDirection: "row",
|
|
@@ -1163,9 +1335,9 @@ function Ribbon() {
|
|
|
1163
1335
|
children: [
|
|
1164
1336
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1165
1337
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1166
|
-
/* @__PURE__ */
|
|
1167
|
-
/* @__PURE__ */ jsx11(
|
|
1168
|
-
/* @__PURE__ */ jsx11(
|
|
1338
|
+
/* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 1, children: [
|
|
1339
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1340
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.muted, children: firstCommand.description })
|
|
1169
1341
|
] })
|
|
1170
1342
|
]
|
|
1171
1343
|
}
|
|
@@ -1177,8 +1349,8 @@ import { useState as useState6 } from "react";
|
|
|
1177
1349
|
|
|
1178
1350
|
// src/ui/Logs.tsx
|
|
1179
1351
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
|
|
1180
|
-
import { Box as
|
|
1181
|
-
import { jsx as jsx12, jsxs as
|
|
1352
|
+
import { Box as Box13, Text as Text13, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize7 } from "ink";
|
|
1353
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1182
1354
|
var KIND_COLOR = {
|
|
1183
1355
|
tool: COLORS.primary,
|
|
1184
1356
|
prompt: COLORS.badge
|
|
@@ -1208,7 +1380,7 @@ function formatTimestamp(ms) {
|
|
|
1208
1380
|
}
|
|
1209
1381
|
function Logs() {
|
|
1210
1382
|
const logs = useWizard((s) => s.logs);
|
|
1211
|
-
const { rows, columns } =
|
|
1383
|
+
const { rows, columns } = useWindowSize7();
|
|
1212
1384
|
const viewportRef = useRef3(null);
|
|
1213
1385
|
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1214
1386
|
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
@@ -1245,10 +1417,10 @@ function Logs() {
|
|
|
1245
1417
|
const visible = logs.slice(scrollOffset, scrollOffset + capacity);
|
|
1246
1418
|
const hiddenAbove = scrollOffset;
|
|
1247
1419
|
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1248
|
-
return /* @__PURE__ */
|
|
1249
|
-
logs.length === 0 && /* @__PURE__ */ jsx12(
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
1420
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1421
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "No logs yet." }),
|
|
1422
|
+
/* @__PURE__ */ jsxs12(Box13, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
1423
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
|
|
1252
1424
|
"\u2191 ",
|
|
1253
1425
|
hiddenAbove,
|
|
1254
1426
|
" more"
|
|
@@ -1263,20 +1435,20 @@ function Logs() {
|
|
|
1263
1435
|
const name = truncate2(entry.name, budget);
|
|
1264
1436
|
budget -= name.length;
|
|
1265
1437
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1266
|
-
return /* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */ jsx12(
|
|
1268
|
-
/* @__PURE__ */ jsx12(
|
|
1269
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1270
|
-
durationText && /* @__PURE__ */ jsx12(
|
|
1438
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1439
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: timestamp }),
|
|
1440
|
+
/* @__PURE__ */ jsx12(Text13, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1441
|
+
preview && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1442
|
+
durationText && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: durationText })
|
|
1271
1443
|
] }, entry.id);
|
|
1272
1444
|
}),
|
|
1273
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
1445
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
|
|
1274
1446
|
"\u2193 ",
|
|
1275
1447
|
hiddenBelow,
|
|
1276
1448
|
" more"
|
|
1277
1449
|
] })
|
|
1278
1450
|
] }),
|
|
1279
|
-
/* @__PURE__ */ jsx12(
|
|
1451
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1280
1452
|
] });
|
|
1281
1453
|
}
|
|
1282
1454
|
|
|
@@ -1468,11 +1640,11 @@ function track(event, payload) {
|
|
|
1468
1640
|
}
|
|
1469
1641
|
|
|
1470
1642
|
// src/ui/App.tsx
|
|
1471
|
-
import { jsx as jsx13, jsxs as
|
|
1643
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1472
1644
|
function App() {
|
|
1473
1645
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1474
1646
|
const { exit } = useApp();
|
|
1475
|
-
const { columns, rows } =
|
|
1647
|
+
const { columns, rows } = useWindowSize8();
|
|
1476
1648
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1477
1649
|
const finished = phase === "done" || phase === "error";
|
|
1478
1650
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1485,7 +1657,7 @@ function App() {
|
|
|
1485
1657
|
{ isActive: finished }
|
|
1486
1658
|
);
|
|
1487
1659
|
useInput6((_input, key) => {
|
|
1488
|
-
if (phase === "idle" || phase === "
|
|
1660
|
+
if (phase === "idle" || phase === "authenticating") return;
|
|
1489
1661
|
if (key.tab) {
|
|
1490
1662
|
setShowLogs(!showLogs);
|
|
1491
1663
|
track("AI Wizard Interaction", {
|
|
@@ -1495,7 +1667,7 @@ function App() {
|
|
|
1495
1667
|
});
|
|
1496
1668
|
}
|
|
1497
1669
|
});
|
|
1498
|
-
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1670
|
+
const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1499
1671
|
useInput6((_input, key) => {
|
|
1500
1672
|
if (escOwnedElsewhere) return;
|
|
1501
1673
|
if (key.escape) {
|
|
@@ -1508,53 +1680,70 @@ function App() {
|
|
|
1508
1680
|
exit();
|
|
1509
1681
|
}
|
|
1510
1682
|
});
|
|
1511
|
-
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1683
|
+
const mainWindowVisible = phase === "authenticating" || phase === "preflight" || phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1512
1684
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1513
1685
|
const showSidebar = flexDirection === "row";
|
|
1514
|
-
return
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1686
|
+
return (
|
|
1687
|
+
/* Exactly the viewport, clipped — never `minHeight`, which lets the frame
|
|
1688
|
+
grow past the terminal. Ink then abandons diffing to clear and repaint
|
|
1689
|
+
the whole screen, and the scrolling that frame causes throws off its
|
|
1690
|
+
cursor arithmetic: flicker and leftover rows, worst when a burst of CLI
|
|
1691
|
+
output is swapped out. Clipping drops the bottom of an over-tall frame;
|
|
1692
|
+
the per-panel row budgets are what keep it from coming to that. */
|
|
1693
|
+
/* @__PURE__ */ jsxs13(
|
|
1694
|
+
Box14,
|
|
1695
|
+
{
|
|
1696
|
+
backgroundColor: COLORS.bg.main,
|
|
1697
|
+
flexDirection: "row",
|
|
1698
|
+
width: columns,
|
|
1699
|
+
height: rows,
|
|
1700
|
+
overflow: "hidden",
|
|
1701
|
+
children: [
|
|
1702
|
+
mainWindowVisible && /* @__PURE__ */ jsxs13(
|
|
1703
|
+
Box14,
|
|
1704
|
+
{
|
|
1705
|
+
flexDirection,
|
|
1706
|
+
width: "100%",
|
|
1707
|
+
justifyContent: "space-between",
|
|
1708
|
+
children: [
|
|
1709
|
+
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1710
|
+
/* Fill the space the sidebar/ribbon leaves — width beside the
|
|
1711
|
+
sidebar, height above the ribbon. The height matters even
|
|
1712
|
+
stacked: it is what the prompt's scrolling list measures itself
|
|
1713
|
+
against (see SelectPrompt). */
|
|
1714
|
+
/* @__PURE__ */ jsxs13(
|
|
1715
|
+
Box14,
|
|
1716
|
+
{
|
|
1717
|
+
flexDirection: "column",
|
|
1718
|
+
paddingX: 4,
|
|
1719
|
+
paddingY: 2,
|
|
1720
|
+
width: showSidebar ? 70 : "100%",
|
|
1721
|
+
flexGrow: 1,
|
|
1722
|
+
children: [
|
|
1723
|
+
phase === "authenticating" && /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginBottom: 1, children: [
|
|
1724
|
+
/* @__PURE__ */ jsx13(Text14, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
|
|
1725
|
+
/* @__PURE__ */ jsx13(Text14, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1726
|
+
] }),
|
|
1727
|
+
/* @__PURE__ */ jsx13(CliOutput, {}),
|
|
1728
|
+
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1729
|
+
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1730
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1731
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: COLORS.status.error, children: [
|
|
1732
|
+
"\u2716 ",
|
|
1733
|
+
error
|
|
1734
|
+
] }) })
|
|
1735
|
+
]
|
|
1736
|
+
}
|
|
1737
|
+
)
|
|
1738
|
+
),
|
|
1739
|
+
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1740
|
+
]
|
|
1741
|
+
}
|
|
1742
|
+
),
|
|
1743
|
+
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1744
|
+
]
|
|
1745
|
+
}
|
|
1746
|
+
)
|
|
1558
1747
|
);
|
|
1559
1748
|
}
|
|
1560
1749
|
|
|
@@ -1790,61 +1979,138 @@ async function runWorkflow(workflow, appId) {
|
|
|
1790
1979
|
}
|
|
1791
1980
|
}
|
|
1792
1981
|
|
|
1793
|
-
// src/lib/
|
|
1794
|
-
import {
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1982
|
+
// src/lib/algoliaApp.ts
|
|
1983
|
+
import { z as z4 } from "zod";
|
|
1984
|
+
var applicationSchema = z4.object({
|
|
1985
|
+
id: z4.string().min(1),
|
|
1986
|
+
name: z4.string().default(""),
|
|
1987
|
+
plan: z4.string().optional()
|
|
1988
|
+
});
|
|
1989
|
+
var listSchema = z4.array(
|
|
1990
|
+
z4.object({
|
|
1991
|
+
id: z4.string().min(1),
|
|
1992
|
+
name: z4.string().default(""),
|
|
1993
|
+
plan_label: z4.string().optional()
|
|
1994
|
+
}).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
|
|
1995
|
+
);
|
|
1996
|
+
async function currentApplication() {
|
|
1997
|
+
let raw;
|
|
1806
1998
|
try {
|
|
1807
|
-
|
|
1999
|
+
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1808
2000
|
} catch {
|
|
1809
|
-
return
|
|
2001
|
+
return null;
|
|
2002
|
+
}
|
|
2003
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
2004
|
+
return parsed.success ? parsed.data : null;
|
|
2005
|
+
}
|
|
2006
|
+
async function requireApplication() {
|
|
2007
|
+
const app = await currentApplication();
|
|
2008
|
+
if (!app) {
|
|
2009
|
+
throw new Error(
|
|
2010
|
+
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
2011
|
+
);
|
|
2012
|
+
}
|
|
2013
|
+
return app;
|
|
2014
|
+
}
|
|
2015
|
+
async function listApplications() {
|
|
2016
|
+
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
2017
|
+
const parsed = listSchema.safeParse(parseJson(raw));
|
|
2018
|
+
if (!parsed.success) {
|
|
2019
|
+
throw new Error("Could not read the list of Algolia applications.");
|
|
2020
|
+
}
|
|
2021
|
+
return parsed.data;
|
|
2022
|
+
}
|
|
2023
|
+
async function selectApplication(id) {
|
|
2024
|
+
const raw = await runAlgoliaCli(
|
|
2025
|
+
["application", "select", "--non-interactive", "--app-id", id],
|
|
2026
|
+
{ onOutput: stderrSink }
|
|
2027
|
+
);
|
|
2028
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
2029
|
+
if (!parsed.success) {
|
|
2030
|
+
throw new Error(
|
|
2031
|
+
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
2032
|
+
);
|
|
1810
2033
|
}
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
name,
|
|
1815
|
-
appId: t.application_id,
|
|
1816
|
-
apiKey: t.api_key,
|
|
1817
|
-
isDefault: t.default === true
|
|
1818
|
-
}));
|
|
1819
|
-
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1820
|
-
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1821
|
-
}
|
|
1822
|
-
async function loadActiveProfile() {
|
|
1823
|
-
let profiles;
|
|
2034
|
+
return parsed.data;
|
|
2035
|
+
}
|
|
2036
|
+
function parseJson(text) {
|
|
1824
2037
|
try {
|
|
1825
|
-
|
|
2038
|
+
return JSON.parse(text);
|
|
1826
2039
|
} catch {
|
|
1827
|
-
|
|
2040
|
+
return void 0;
|
|
1828
2041
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
// src/lib/algoliaAppPicker.ts
|
|
2045
|
+
function secondaryFor(app) {
|
|
2046
|
+
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
2047
|
+
}
|
|
2048
|
+
function labelFor(app) {
|
|
2049
|
+
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
2050
|
+
}
|
|
2051
|
+
function selectAndReport(app) {
|
|
2052
|
+
useWizard.getState().pushCliOutput(
|
|
2053
|
+
"stdout",
|
|
2054
|
+
`Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
|
|
2055
|
+
);
|
|
2056
|
+
return selectApplication(app.id);
|
|
2057
|
+
}
|
|
2058
|
+
async function promptForApplication() {
|
|
2059
|
+
const store = useWizard.getState();
|
|
2060
|
+
const apps = await listApplications();
|
|
2061
|
+
if (apps.length === 0) {
|
|
1831
2062
|
throw new Error(
|
|
1832
|
-
"
|
|
2063
|
+
"This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
if (apps.length === 1) {
|
|
2067
|
+
const only = apps[0];
|
|
2068
|
+
logger.info(
|
|
2069
|
+
{ app: only.id },
|
|
2070
|
+
"single application on the account; selecting it"
|
|
1833
2071
|
);
|
|
2072
|
+
return selectAndReport(only);
|
|
2073
|
+
}
|
|
2074
|
+
const messages = ["Which Algolia application should the wizard work in?"];
|
|
2075
|
+
for (; ; ) {
|
|
2076
|
+
const choice = await store.requestUserInput({
|
|
2077
|
+
prompt: "Select an application",
|
|
2078
|
+
promptType: "multipleChoice",
|
|
2079
|
+
options: apps.map(labelFor),
|
|
2080
|
+
secondary: apps.map(secondaryFor),
|
|
2081
|
+
messages
|
|
2082
|
+
});
|
|
2083
|
+
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
2084
|
+
if (!chosen) {
|
|
2085
|
+
throw new Error("Application picker received an unexpected selection");
|
|
2086
|
+
}
|
|
2087
|
+
try {
|
|
2088
|
+
return await selectAndReport(chosen);
|
|
2089
|
+
} catch (err) {
|
|
2090
|
+
logger.warn(
|
|
2091
|
+
{ app: chosen.id, err: err.message },
|
|
2092
|
+
"application select failed; re-prompting"
|
|
2093
|
+
);
|
|
2094
|
+
messages.push(
|
|
2095
|
+
`Could not select \u201C${labelFor(chosen)}\u201D. It may have been removed \u2014 pick another.`
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
1834
2098
|
}
|
|
1835
|
-
|
|
2099
|
+
}
|
|
2100
|
+
async function ensureApplication() {
|
|
2101
|
+
return await currentApplication() ?? await promptForApplication();
|
|
1836
2102
|
}
|
|
1837
2103
|
|
|
1838
2104
|
// src/workflows/default.ts
|
|
1839
|
-
import { z as
|
|
2105
|
+
import { z as z27 } from "zod";
|
|
1840
2106
|
|
|
1841
2107
|
// src/actions/listIndices.ts
|
|
1842
|
-
import { z as
|
|
1843
|
-
var indicesListSchema =
|
|
1844
|
-
items:
|
|
1845
|
-
|
|
1846
|
-
name:
|
|
1847
|
-
entries:
|
|
2108
|
+
import { z as z5 } from "zod";
|
|
2109
|
+
var indicesListSchema = z5.object({
|
|
2110
|
+
items: z5.array(
|
|
2111
|
+
z5.object({
|
|
2112
|
+
name: z5.string(),
|
|
2113
|
+
entries: z5.number().default(0)
|
|
1848
2114
|
})
|
|
1849
2115
|
)
|
|
1850
2116
|
});
|
|
@@ -1915,12 +2181,12 @@ import "zod";
|
|
|
1915
2181
|
|
|
1916
2182
|
// src/lib/tools/listFiles.ts
|
|
1917
2183
|
import { tool } from "ai";
|
|
1918
|
-
import
|
|
2184
|
+
import z6 from "zod";
|
|
1919
2185
|
import { readdir } from "node:fs/promises";
|
|
1920
2186
|
|
|
1921
2187
|
// src/lib/tools/path.ts
|
|
1922
2188
|
import { lstat } from "node:fs/promises";
|
|
1923
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
2189
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join6, sep } from "node:path";
|
|
1924
2190
|
function resolveInRoot(ctx, path) {
|
|
1925
2191
|
const target = resolve2(ctx.cwd, path);
|
|
1926
2192
|
const rel = relative(ctx.root, target);
|
|
@@ -1936,7 +2202,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1936
2202
|
let current = ctx.root;
|
|
1937
2203
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
1938
2204
|
for (const part of parts) {
|
|
1939
|
-
current =
|
|
2205
|
+
current = join6(current, part);
|
|
1940
2206
|
try {
|
|
1941
2207
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
1942
2208
|
} catch (err) {
|
|
@@ -1951,7 +2217,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1951
2217
|
function listFilesTool(ctx) {
|
|
1952
2218
|
return tool({
|
|
1953
2219
|
description: "List files in the current working directory",
|
|
1954
|
-
inputSchema:
|
|
2220
|
+
inputSchema: z6.object(),
|
|
1955
2221
|
execute: async () => {
|
|
1956
2222
|
logger.info("called listFiles tool");
|
|
1957
2223
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -1967,13 +2233,13 @@ function listFilesTool(ctx) {
|
|
|
1967
2233
|
|
|
1968
2234
|
// src/lib/tools/changeDirectory.ts
|
|
1969
2235
|
import { tool as tool2 } from "ai";
|
|
1970
|
-
import
|
|
2236
|
+
import z7 from "zod";
|
|
1971
2237
|
import { stat } from "node:fs/promises";
|
|
1972
2238
|
function changeDirectoryTool(ctx) {
|
|
1973
2239
|
return tool2({
|
|
1974
2240
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
1975
|
-
inputSchema:
|
|
1976
|
-
path:
|
|
2241
|
+
inputSchema: z7.object({
|
|
2242
|
+
path: z7.string().describe("Directory to change into")
|
|
1977
2243
|
}),
|
|
1978
2244
|
execute: async ({ path }) => {
|
|
1979
2245
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -1995,13 +2261,13 @@ function changeDirectoryTool(ctx) {
|
|
|
1995
2261
|
|
|
1996
2262
|
// src/lib/tools/reportStatus.ts
|
|
1997
2263
|
import { tool as tool3 } from "ai";
|
|
1998
|
-
import
|
|
2264
|
+
import z8 from "zod";
|
|
1999
2265
|
function reportStatusTool(output) {
|
|
2000
2266
|
return tool3({
|
|
2001
2267
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2002
|
-
inputSchema:
|
|
2003
|
-
status:
|
|
2004
|
-
reason:
|
|
2268
|
+
inputSchema: z8.object({
|
|
2269
|
+
status: z8.enum(["success", "fail"]),
|
|
2270
|
+
reason: z8.string().optional(),
|
|
2005
2271
|
output
|
|
2006
2272
|
}),
|
|
2007
2273
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2013,8 +2279,8 @@ function reportStatusTool(output) {
|
|
|
2013
2279
|
|
|
2014
2280
|
// src/lib/tools/readFile.ts
|
|
2015
2281
|
import { tool as tool4 } from "ai";
|
|
2016
|
-
import
|
|
2017
|
-
import { readFile as
|
|
2282
|
+
import z9 from "zod";
|
|
2283
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
2018
2284
|
|
|
2019
2285
|
// src/lib/tools/env.ts
|
|
2020
2286
|
import { basename } from "node:path";
|
|
@@ -2041,8 +2307,8 @@ function redactEnvValues(content) {
|
|
|
2041
2307
|
function readFileTool(ctx) {
|
|
2042
2308
|
return tool4({
|
|
2043
2309
|
description: "Read the contents of a file at the given path",
|
|
2044
|
-
inputSchema:
|
|
2045
|
-
filePath:
|
|
2310
|
+
inputSchema: z9.object({
|
|
2311
|
+
filePath: z9.string().describe("Path to the file to read")
|
|
2046
2312
|
}),
|
|
2047
2313
|
execute: async ({ filePath }) => {
|
|
2048
2314
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2052,7 +2318,7 @@ function readFileTool(ctx) {
|
|
|
2052
2318
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2053
2319
|
if (!resolved.ok) return resolved.error;
|
|
2054
2320
|
try {
|
|
2055
|
-
const content = await
|
|
2321
|
+
const content = await readFile3(resolved.target, "utf8");
|
|
2056
2322
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2057
2323
|
} catch (err) {
|
|
2058
2324
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2063,15 +2329,15 @@ function readFileTool(ctx) {
|
|
|
2063
2329
|
|
|
2064
2330
|
// src/lib/tools/writeFile.ts
|
|
2065
2331
|
import { tool as tool5 } from "ai";
|
|
2066
|
-
import
|
|
2332
|
+
import z10 from "zod";
|
|
2067
2333
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2068
2334
|
import { dirname as dirname4 } from "node:path";
|
|
2069
2335
|
function writeFileTool(ctx) {
|
|
2070
2336
|
return tool5({
|
|
2071
2337
|
description: "Write content to a file at the given path, overwriting it. To set Algolia credentials in an env file, use writeCredentials instead of this tool.",
|
|
2072
|
-
inputSchema:
|
|
2073
|
-
filePath:
|
|
2074
|
-
content:
|
|
2338
|
+
inputSchema: z10.object({
|
|
2339
|
+
filePath: z10.string().describe("Path to the file to write"),
|
|
2340
|
+
content: z10.string().describe("Content to write to the file")
|
|
2075
2341
|
}),
|
|
2076
2342
|
execute: async ({ filePath, content }) => {
|
|
2077
2343
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2096,9 +2362,95 @@ function writeFileTool(ctx) {
|
|
|
2096
2362
|
|
|
2097
2363
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2098
2364
|
import { tool as tool6 } from "ai";
|
|
2099
|
-
import
|
|
2100
|
-
import { mkdir as mkdir4, readFile as
|
|
2365
|
+
import z12 from "zod";
|
|
2366
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
2101
2367
|
import { dirname as dirname5 } from "node:path";
|
|
2368
|
+
|
|
2369
|
+
// src/lib/algoliaApiKey.ts
|
|
2370
|
+
import { z as z11 } from "zod";
|
|
2371
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
2372
|
+
var WRITE_ACLS = [
|
|
2373
|
+
"addObject",
|
|
2374
|
+
"deleteObject",
|
|
2375
|
+
"settings",
|
|
2376
|
+
"editSettings",
|
|
2377
|
+
"listIndexes"
|
|
2378
|
+
];
|
|
2379
|
+
var WRITE_ACL_SET = new Set(WRITE_ACLS);
|
|
2380
|
+
var apiKeySchema = z11.object({
|
|
2381
|
+
value: z11.string().min(1),
|
|
2382
|
+
acl: z11.array(z11.string()).default([]),
|
|
2383
|
+
indexes: z11.array(z11.string()).default([])
|
|
2384
|
+
});
|
|
2385
|
+
var apiKeyListSchema = z11.object({
|
|
2386
|
+
items: z11.array(apiKeySchema).optional(),
|
|
2387
|
+
keys: z11.array(apiKeySchema).optional()
|
|
2388
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
2389
|
+
var createdKeySchema = z11.object({
|
|
2390
|
+
key: z11.string().min(1).optional(),
|
|
2391
|
+
value: z11.string().min(1).optional()
|
|
2392
|
+
});
|
|
2393
|
+
function canReuse(key, index) {
|
|
2394
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
2395
|
+
}
|
|
2396
|
+
async function createSearchKey(index) {
|
|
2397
|
+
const stdout = await runAlgoliaCli([
|
|
2398
|
+
"apikeys",
|
|
2399
|
+
"create",
|
|
2400
|
+
"--indices",
|
|
2401
|
+
index,
|
|
2402
|
+
"--acl",
|
|
2403
|
+
"search,browse",
|
|
2404
|
+
"--description",
|
|
2405
|
+
`wizard search-only key for ${index}`,
|
|
2406
|
+
"-o",
|
|
2407
|
+
"json"
|
|
2408
|
+
]);
|
|
2409
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
2410
|
+
const created = key ?? value;
|
|
2411
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
2412
|
+
return created;
|
|
2413
|
+
}
|
|
2414
|
+
function canReuseForWrites(key, index) {
|
|
2415
|
+
return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
|
|
2416
|
+
}
|
|
2417
|
+
async function resolveWriteKey(index) {
|
|
2418
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2419
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
|
|
2420
|
+
if (existing) {
|
|
2421
|
+
logger.info({ index }, "reusing existing write API key");
|
|
2422
|
+
return existing;
|
|
2423
|
+
}
|
|
2424
|
+
logger.info({ index }, "no reusable write key found; creating one");
|
|
2425
|
+
const created = await runAlgoliaCli([
|
|
2426
|
+
"apikeys",
|
|
2427
|
+
"create",
|
|
2428
|
+
"--indices",
|
|
2429
|
+
index,
|
|
2430
|
+
"--acl",
|
|
2431
|
+
WRITE_ACLS.join(","),
|
|
2432
|
+
"--description",
|
|
2433
|
+
`wizard write key for ${index}`,
|
|
2434
|
+
"-o",
|
|
2435
|
+
"json"
|
|
2436
|
+
]);
|
|
2437
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(created));
|
|
2438
|
+
const writeKey = key ?? value;
|
|
2439
|
+
if (!writeKey) throw new Error("apikeys create returned no key value");
|
|
2440
|
+
return writeKey;
|
|
2441
|
+
}
|
|
2442
|
+
async function resolveSearchOnlyKey(index) {
|
|
2443
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2444
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
2445
|
+
if (existing) {
|
|
2446
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
2447
|
+
return existing;
|
|
2448
|
+
}
|
|
2449
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
2450
|
+
return createSearchKey(index);
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2102
2454
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2103
2455
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2104
2456
|
function appendEnv(content, entries) {
|
|
@@ -2112,9 +2464,9 @@ function hasEnv(content, name) {
|
|
|
2112
2464
|
}
|
|
2113
2465
|
function writeCredentialsTool(ctx) {
|
|
2114
2466
|
return tool6({
|
|
2115
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2116
|
-
inputSchema:
|
|
2117
|
-
filePath:
|
|
2467
|
+
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials come from the selected Algolia application, with a write key scoped to the target index; you only pass the path to the env file (e.g. ".env"). If the file already defines ${APP_ID_VAR} or ${API_KEY_VAR}, the write is skipped and existing values are left untouched.`,
|
|
2468
|
+
inputSchema: z12.object({
|
|
2469
|
+
filePath: z12.string().describe(
|
|
2118
2470
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2119
2471
|
)
|
|
2120
2472
|
}),
|
|
@@ -2122,11 +2474,17 @@ function writeCredentialsTool(ctx) {
|
|
|
2122
2474
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2123
2475
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2124
2476
|
if (resolved.ok === false) return resolved.error;
|
|
2125
|
-
|
|
2477
|
+
const targetIndex = useWizard.getState().targetIndex;
|
|
2478
|
+
if (!targetIndex) {
|
|
2479
|
+
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
2480
|
+
}
|
|
2481
|
+
let appId;
|
|
2482
|
+
let writeKey;
|
|
2126
2483
|
try {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2484
|
+
appId = (await requireApplication()).id;
|
|
2485
|
+
writeKey = await resolveWriteKey(targetIndex);
|
|
2486
|
+
} catch (err) {
|
|
2487
|
+
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2130
2488
|
}
|
|
2131
2489
|
try {
|
|
2132
2490
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2134,7 +2492,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2134
2492
|
}
|
|
2135
2493
|
let existing = "";
|
|
2136
2494
|
try {
|
|
2137
|
-
existing = await
|
|
2495
|
+
existing = await readFile4(resolved.target, "utf8");
|
|
2138
2496
|
} catch (err) {
|
|
2139
2497
|
if (err.code !== "ENOENT") throw err;
|
|
2140
2498
|
}
|
|
@@ -2145,8 +2503,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2145
2503
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2146
2504
|
}
|
|
2147
2505
|
const envWithCredentials = appendEnv(existing, [
|
|
2148
|
-
[APP_ID_VAR,
|
|
2149
|
-
[API_KEY_VAR,
|
|
2506
|
+
[APP_ID_VAR, appId],
|
|
2507
|
+
[API_KEY_VAR, writeKey]
|
|
2150
2508
|
]);
|
|
2151
2509
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2152
2510
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2160,16 +2518,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2160
2518
|
|
|
2161
2519
|
// src/lib/tools/searchFiles.ts
|
|
2162
2520
|
import { tool as tool7 } from "ai";
|
|
2163
|
-
import
|
|
2164
|
-
import { readdir as readdir2, readFile as
|
|
2165
|
-
import { join as
|
|
2521
|
+
import z13 from "zod";
|
|
2522
|
+
import { readdir as readdir2, readFile as readFile5 } from "node:fs/promises";
|
|
2523
|
+
import { join as join7 } from "node:path";
|
|
2166
2524
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2167
2525
|
async function walkFiles(dir) {
|
|
2168
2526
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2169
2527
|
const out = [];
|
|
2170
2528
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2171
2529
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2172
|
-
const full =
|
|
2530
|
+
const full = join7(dir, e.name);
|
|
2173
2531
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2174
2532
|
else if (e.isFile()) out.push(full);
|
|
2175
2533
|
}
|
|
@@ -2178,9 +2536,9 @@ async function walkFiles(dir) {
|
|
|
2178
2536
|
function searchFilesTool(ctx) {
|
|
2179
2537
|
return tool7({
|
|
2180
2538
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2181
|
-
inputSchema:
|
|
2182
|
-
query:
|
|
2183
|
-
path:
|
|
2539
|
+
inputSchema: z13.object({
|
|
2540
|
+
query: z13.string().describe("JavaScript RegExp pattern to search for"),
|
|
2541
|
+
path: z13.string().optional().describe("Directory to search in (default: cwd)")
|
|
2184
2542
|
}),
|
|
2185
2543
|
execute: async ({ query, path = "." }) => {
|
|
2186
2544
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2202,7 +2560,7 @@ function searchFilesTool(ctx) {
|
|
|
2202
2560
|
for (const file of await walkFiles(resolved.target)) {
|
|
2203
2561
|
let content;
|
|
2204
2562
|
try {
|
|
2205
|
-
content = await
|
|
2563
|
+
content = await readFile5(file, "utf8");
|
|
2206
2564
|
} catch {
|
|
2207
2565
|
continue;
|
|
2208
2566
|
}
|
|
@@ -2224,7 +2582,7 @@ function searchFilesTool(ctx) {
|
|
|
2224
2582
|
|
|
2225
2583
|
// src/lib/tools/verifyImplementation.ts
|
|
2226
2584
|
import { tool as tool8 } from "ai";
|
|
2227
|
-
import
|
|
2585
|
+
import z14 from "zod";
|
|
2228
2586
|
|
|
2229
2587
|
// src/lib/tools/utils/runCommand.ts
|
|
2230
2588
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2246,9 +2604,9 @@ function runCommand(command, args, cwd) {
|
|
|
2246
2604
|
}
|
|
2247
2605
|
|
|
2248
2606
|
// src/lib/tools/utils/packageManager.ts
|
|
2249
|
-
import { readFile as
|
|
2607
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
2250
2608
|
import { existsSync } from "node:fs";
|
|
2251
|
-
import { join as
|
|
2609
|
+
import { join as join8 } from "node:path";
|
|
2252
2610
|
var LOCKFILES = [
|
|
2253
2611
|
["pnpm-lock.yaml", "pnpm"],
|
|
2254
2612
|
["yarn.lock", "yarn"],
|
|
@@ -2257,13 +2615,13 @@ var LOCKFILES = [
|
|
|
2257
2615
|
["package-lock.json", "npm"]
|
|
2258
2616
|
];
|
|
2259
2617
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2260
|
-
return JSON.parse(await
|
|
2618
|
+
return JSON.parse(await readFile6(join8(cwd, "package.json"), "utf8"));
|
|
2261
2619
|
}
|
|
2262
2620
|
function packageManagerFrom(pkg) {
|
|
2263
2621
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2264
2622
|
}
|
|
2265
2623
|
function packageManagerFromLockfile(cwd) {
|
|
2266
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2624
|
+
return LOCKFILES.find(([file]) => existsSync(join8(cwd, file)))?.[1];
|
|
2267
2625
|
}
|
|
2268
2626
|
async function detectPackageManager(cwd) {
|
|
2269
2627
|
try {
|
|
@@ -2304,7 +2662,7 @@ async function runRepoVerificationCheck() {
|
|
|
2304
2662
|
function verifyImplementationTool() {
|
|
2305
2663
|
return tool8({
|
|
2306
2664
|
description: "Run the repo's mechanical verification check for generated implementation changes. Detects lint/typecheck/check from package.json and returns structured pass/fail evidence for the verifier to interpret.",
|
|
2307
|
-
inputSchema:
|
|
2665
|
+
inputSchema: z14.object(),
|
|
2308
2666
|
execute: async () => {
|
|
2309
2667
|
logger.info("called verifyImplementation tool");
|
|
2310
2668
|
return runRepoVerificationCheck();
|
|
@@ -2318,7 +2676,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2318
2676
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2319
2677
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2320
2678
|
import { dirname as dirname6 } from "node:path";
|
|
2321
|
-
import
|
|
2679
|
+
import z15 from "zod";
|
|
2322
2680
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2323
2681
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2324
2682
|
var MAX_RECORDS = 100;
|
|
@@ -2330,17 +2688,17 @@ var anthropic = createAnthropic({
|
|
|
2330
2688
|
function generateRecordTool(ctx) {
|
|
2331
2689
|
return tool9({
|
|
2332
2690
|
description: "Generate realistic sample records for an entity and write them to a JSON file in the worktree. Provide the entity name and its attributes; this tool asks a model to invent varied, realistic values, each with a unique objectID, and returns the file path to read them from at runtime. Do not invent the record values or objectIDs yourself, and do not inline the returned records into the script \u2014 call this tool and read the file it writes.",
|
|
2333
|
-
inputSchema:
|
|
2334
|
-
entityName:
|
|
2335
|
-
attributes:
|
|
2336
|
-
count:
|
|
2337
|
-
hint:
|
|
2691
|
+
inputSchema: z15.object({
|
|
2692
|
+
entityName: z15.string().describe("Name of the entity to generate records for."),
|
|
2693
|
+
attributes: z15.array(z15.string()).describe("Attribute names each record must contain."),
|
|
2694
|
+
count: z15.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
2695
|
+
hint: z15.string().optional().describe("Optional context to steer realistic values.")
|
|
2338
2696
|
}),
|
|
2339
2697
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2340
2698
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2341
2699
|
try {
|
|
2342
|
-
const value =
|
|
2343
|
-
const recordSchema =
|
|
2700
|
+
const value = z15.union([z15.string(), z15.number(), z15.boolean(), z15.null()]);
|
|
2701
|
+
const recordSchema = z15.object(
|
|
2344
2702
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2345
2703
|
);
|
|
2346
2704
|
const generateBatch = async (batchCount) => {
|
|
@@ -2350,8 +2708,8 @@ function generateRecordTool(ctx) {
|
|
|
2350
2708
|
const { output } = await generateText({
|
|
2351
2709
|
model: anthropic(RECORD_MODEL),
|
|
2352
2710
|
output: Output.object({
|
|
2353
|
-
schema:
|
|
2354
|
-
records:
|
|
2711
|
+
schema: z15.object({
|
|
2712
|
+
records: z15.array(recordSchema).length(batchCount)
|
|
2355
2713
|
})
|
|
2356
2714
|
}),
|
|
2357
2715
|
prompt: [
|
|
@@ -2409,12 +2767,12 @@ function generateRecordTool(ctx) {
|
|
|
2409
2767
|
|
|
2410
2768
|
// src/lib/tools/notifyUser.ts
|
|
2411
2769
|
import { tool as tool10 } from "ai";
|
|
2412
|
-
import
|
|
2770
|
+
import z16 from "zod";
|
|
2413
2771
|
function notifyUserTool() {
|
|
2414
2772
|
return tool10({
|
|
2415
2773
|
description: `Give the user a brief, high-level update on what you are currently doing or about to do next. This is for the big picture (e.g. "Reading through your data models", "Writing the search UI") \u2014 not granular detail like individual tool calls, which are already logged separately. Call it when you start a new phase of work or your focus shifts, just not on every step, enough to keep the user engaged. Don't say things like "starting", just describe what you are doing. Don't mention tool calls themselves, just general direction of the work.`,
|
|
2416
|
-
inputSchema:
|
|
2417
|
-
message:
|
|
2774
|
+
inputSchema: z16.object({
|
|
2775
|
+
message: z16.string().describe(
|
|
2418
2776
|
"Short, plain-language description of what you are doing now."
|
|
2419
2777
|
)
|
|
2420
2778
|
}),
|
|
@@ -2594,10 +2952,10 @@ async function runAgent(req) {
|
|
|
2594
2952
|
}
|
|
2595
2953
|
|
|
2596
2954
|
// src/actions/detectLanguage.ts
|
|
2597
|
-
import
|
|
2598
|
-
var detectLanguageSchema =
|
|
2599
|
-
languages:
|
|
2600
|
-
frameworks:
|
|
2955
|
+
import z19 from "zod";
|
|
2956
|
+
var detectLanguageSchema = z19.object({
|
|
2957
|
+
languages: z19.array(z19.object({ name: z19.string(), version: z19.string() })),
|
|
2958
|
+
frameworks: z19.array(z19.object({ name: z19.string(), version: z19.string() }))
|
|
2601
2959
|
});
|
|
2602
2960
|
var detectLanguage = () => runAgent({
|
|
2603
2961
|
instructions: [
|
|
@@ -2615,31 +2973,31 @@ var detectLanguage = () => runAgent({
|
|
|
2615
2973
|
});
|
|
2616
2974
|
|
|
2617
2975
|
// src/actions/analyzeCodebase.ts
|
|
2618
|
-
import
|
|
2976
|
+
import z20 from "zod";
|
|
2619
2977
|
var READONLY_TOOLS = [
|
|
2620
2978
|
"listFiles",
|
|
2621
2979
|
"changeDirectory",
|
|
2622
2980
|
"readFile",
|
|
2623
2981
|
"searchFiles"
|
|
2624
2982
|
];
|
|
2625
|
-
var ingestionAnalysisSchema =
|
|
2626
|
-
ingestionAnalysis:
|
|
2627
|
-
|
|
2628
|
-
name:
|
|
2629
|
-
paths:
|
|
2983
|
+
var ingestionAnalysisSchema = z20.object({
|
|
2984
|
+
ingestionAnalysis: z20.array(
|
|
2985
|
+
z20.object({
|
|
2986
|
+
name: z20.string(),
|
|
2987
|
+
paths: z20.array(z20.string()),
|
|
2630
2988
|
// indexable fields the agent found for this entity
|
|
2631
|
-
attributes:
|
|
2989
|
+
attributes: z20.array(z20.string())
|
|
2632
2990
|
})
|
|
2633
2991
|
)
|
|
2634
2992
|
});
|
|
2635
|
-
var searchImplementationAnalysisSchema =
|
|
2636
|
-
searchImplementationAnalysis:
|
|
2993
|
+
var searchImplementationAnalysisSchema = z20.object({
|
|
2994
|
+
searchImplementationAnalysis: z20.string()
|
|
2637
2995
|
});
|
|
2638
|
-
var verificationSchema =
|
|
2639
|
-
verification:
|
|
2996
|
+
var verificationSchema = z20.object({
|
|
2997
|
+
verification: z20.array(z20.string())
|
|
2640
2998
|
});
|
|
2641
2999
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
2642
|
-
var analyzeCodebaseSchema =
|
|
3000
|
+
var analyzeCodebaseSchema = z20.object({
|
|
2643
3001
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
2644
3002
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
2645
3003
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -2701,7 +3059,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
2701
3059
|
// package.json
|
|
2702
3060
|
var package_default = {
|
|
2703
3061
|
name: "@algolia/wizard",
|
|
2704
|
-
version: "0.
|
|
3062
|
+
version: "0.8.0-rc.58.43",
|
|
2705
3063
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2706
3064
|
type: "module",
|
|
2707
3065
|
engines: {
|
|
@@ -2749,7 +3107,6 @@ var package_default = {
|
|
|
2749
3107
|
dependencies: {
|
|
2750
3108
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
2751
3109
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2752
|
-
"@algolia/cli": "^5.11.0",
|
|
2753
3110
|
"@hono/node-server": "^2.0.10",
|
|
2754
3111
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
2755
3112
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -2764,7 +3121,6 @@ var package_default = {
|
|
|
2764
3121
|
nanoid: "^5.1.15",
|
|
2765
3122
|
pino: "^10.3.1",
|
|
2766
3123
|
react: "^19.2.7",
|
|
2767
|
-
toml: "^4.1.1",
|
|
2768
3124
|
varlock: "^1.5.1",
|
|
2769
3125
|
zod: "^4.4.3",
|
|
2770
3126
|
zustand: "^5.0.14"
|
|
@@ -2822,8 +3178,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
2822
3178
|
}
|
|
2823
3179
|
|
|
2824
3180
|
// src/actions/confirmLanguage.ts
|
|
2825
|
-
import
|
|
2826
|
-
var confirmLanguageSchema =
|
|
3181
|
+
import z22 from "zod";
|
|
3182
|
+
var confirmLanguageSchema = z22.object({
|
|
2827
3183
|
languages: detectLanguageSchema.shape.languages
|
|
2828
3184
|
});
|
|
2829
3185
|
async function confirmLanguage(ctx) {
|
|
@@ -2844,8 +3200,8 @@ async function confirmLanguage(ctx) {
|
|
|
2844
3200
|
}
|
|
2845
3201
|
|
|
2846
3202
|
// src/actions/confirmFramework.ts
|
|
2847
|
-
import
|
|
2848
|
-
var confirmFrameworkSchema =
|
|
3203
|
+
import z23 from "zod";
|
|
3204
|
+
var confirmFrameworkSchema = z23.object({
|
|
2849
3205
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
2850
3206
|
});
|
|
2851
3207
|
var CURATED_FRAMEWORKS = [
|
|
@@ -2973,8 +3329,8 @@ async function promptUser(ctx, params) {
|
|
|
2973
3329
|
}
|
|
2974
3330
|
|
|
2975
3331
|
// src/actions/confirmEntities.ts
|
|
2976
|
-
import
|
|
2977
|
-
var confirmEntitiesSchema =
|
|
3332
|
+
import z24 from "zod";
|
|
3333
|
+
var confirmEntitiesSchema = z24.object({
|
|
2978
3334
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
2979
3335
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
2980
3336
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3044,15 +3400,15 @@ async function confirmEntities(ctx) {
|
|
|
3044
3400
|
}
|
|
3045
3401
|
|
|
3046
3402
|
// src/actions/review.ts
|
|
3047
|
-
import { z as
|
|
3048
|
-
var reviewSchema =
|
|
3403
|
+
import { z as z25 } from "zod";
|
|
3404
|
+
var reviewSchema = z25.object({
|
|
3049
3405
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3050
3406
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3051
3407
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3052
3408
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3053
|
-
summaryPoints:
|
|
3054
|
-
reviewPrompt:
|
|
3055
|
-
nextSteps:
|
|
3409
|
+
summaryPoints: z25.array(z25.string()),
|
|
3410
|
+
reviewPrompt: z25.string(),
|
|
3411
|
+
nextSteps: z25.array(z25.string())
|
|
3056
3412
|
});
|
|
3057
3413
|
function formatCompletedSteps(steps) {
|
|
3058
3414
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3103,16 +3459,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3103
3459
|
};
|
|
3104
3460
|
|
|
3105
3461
|
// src/actions/implement.ts
|
|
3106
|
-
import
|
|
3462
|
+
import z26 from "zod";
|
|
3107
3463
|
|
|
3108
3464
|
// src/lib/worktree.ts
|
|
3109
3465
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3110
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3466
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile7, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3111
3467
|
import {
|
|
3112
3468
|
basename as basename2,
|
|
3113
3469
|
dirname as dirname7,
|
|
3114
3470
|
isAbsolute as isAbsolute2,
|
|
3115
|
-
join as
|
|
3471
|
+
join as join9,
|
|
3116
3472
|
relative as relative2,
|
|
3117
3473
|
resolve as resolve3
|
|
3118
3474
|
} from "node:path";
|
|
@@ -3146,7 +3502,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3146
3502
|
return out.trim().length > 0;
|
|
3147
3503
|
}
|
|
3148
3504
|
async function pruneOldWorktrees(repoRoot) {
|
|
3149
|
-
const dir =
|
|
3505
|
+
const dir = join9(stateDir(repoRoot), "worktrees");
|
|
3150
3506
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3151
3507
|
for (const slug of stale) {
|
|
3152
3508
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3157,7 +3513,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3157
3513
|
"worktree",
|
|
3158
3514
|
"remove",
|
|
3159
3515
|
"--force",
|
|
3160
|
-
|
|
3516
|
+
join9(dir, slug)
|
|
3161
3517
|
]);
|
|
3162
3518
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3163
3519
|
} catch (err) {
|
|
@@ -3171,7 +3527,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3171
3527
|
async function createWorktree(repoRoot) {
|
|
3172
3528
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3173
3529
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3174
|
-
const path =
|
|
3530
|
+
const path = join9(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3175
3531
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3176
3532
|
await pruneOldWorktrees(repoRoot);
|
|
3177
3533
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3291,8 +3647,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3291
3647
|
} catch {
|
|
3292
3648
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3293
3649
|
}
|
|
3294
|
-
const relPath =
|
|
3295
|
-
const dest =
|
|
3650
|
+
const relPath = join9(ingestDir, basename2(source));
|
|
3651
|
+
const dest = join9(worktreePath, relPath);
|
|
3296
3652
|
try {
|
|
3297
3653
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3298
3654
|
await copyFile(source, dest);
|
|
@@ -3308,10 +3664,10 @@ function hasEnvVar(content, name) {
|
|
|
3308
3664
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3309
3665
|
}
|
|
3310
3666
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3311
|
-
const target =
|
|
3667
|
+
const target = join9(worktreePath, ".env");
|
|
3312
3668
|
let existing = "";
|
|
3313
3669
|
try {
|
|
3314
|
-
existing = await
|
|
3670
|
+
existing = await readFile7(target, "utf8");
|
|
3315
3671
|
} catch (err) {
|
|
3316
3672
|
if (err.code !== "ENOENT") throw err;
|
|
3317
3673
|
}
|
|
@@ -3379,63 +3735,15 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3379
3735
|
}
|
|
3380
3736
|
}
|
|
3381
3737
|
|
|
3382
|
-
// src/lib/algoliaApiKey.ts
|
|
3383
|
-
import { z as z23 } from "zod";
|
|
3384
|
-
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
3385
|
-
var apiKeySchema = z23.object({
|
|
3386
|
-
value: z23.string().min(1),
|
|
3387
|
-
acl: z23.array(z23.string()).default([]),
|
|
3388
|
-
indexes: z23.array(z23.string()).default([])
|
|
3389
|
-
});
|
|
3390
|
-
var apiKeyListSchema = z23.object({
|
|
3391
|
-
items: z23.array(apiKeySchema).optional(),
|
|
3392
|
-
keys: z23.array(apiKeySchema).optional()
|
|
3393
|
-
}).transform((o) => o.items ?? o.keys ?? []);
|
|
3394
|
-
var createdKeySchema = z23.object({
|
|
3395
|
-
key: z23.string().min(1).optional(),
|
|
3396
|
-
value: z23.string().min(1).optional()
|
|
3397
|
-
});
|
|
3398
|
-
function canReuse(key, index) {
|
|
3399
|
-
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
3400
|
-
}
|
|
3401
|
-
async function createSearchKey(index) {
|
|
3402
|
-
const stdout = await runAlgoliaCli([
|
|
3403
|
-
"apikeys",
|
|
3404
|
-
"create",
|
|
3405
|
-
"--indices",
|
|
3406
|
-
index,
|
|
3407
|
-
"--acl",
|
|
3408
|
-
"search,browse",
|
|
3409
|
-
"--description",
|
|
3410
|
-
`wizard search-only key for ${index}`,
|
|
3411
|
-
"-o",
|
|
3412
|
-
"json"
|
|
3413
|
-
]);
|
|
3414
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
3415
|
-
const created = key ?? value;
|
|
3416
|
-
if (!created) throw new Error("apikeys create returned no key value");
|
|
3417
|
-
return created;
|
|
3418
|
-
}
|
|
3419
|
-
async function resolveSearchOnlyKey(index) {
|
|
3420
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
3421
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
3422
|
-
if (existing) {
|
|
3423
|
-
logger.info({ index }, "reusing existing search-only API key");
|
|
3424
|
-
return existing;
|
|
3425
|
-
}
|
|
3426
|
-
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
3427
|
-
return createSearchKey(index);
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
3738
|
// src/lib/algoliaDocs.ts
|
|
3431
3739
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3432
|
-
import { dirname as dirname8, join as
|
|
3740
|
+
import { dirname as dirname8, join as join10 } from "node:path";
|
|
3433
3741
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3434
|
-
var DOCS_SUBPATH =
|
|
3742
|
+
var DOCS_SUBPATH = join10("docs", "algolia-sdk");
|
|
3435
3743
|
function findDocsDir() {
|
|
3436
3744
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3437
3745
|
for (; ; ) {
|
|
3438
|
-
const candidate =
|
|
3746
|
+
const candidate = join10(dir, DOCS_SUBPATH);
|
|
3439
3747
|
if (existsSync2(candidate)) return candidate;
|
|
3440
3748
|
const parent = dirname8(dir);
|
|
3441
3749
|
if (parent === dir) return void 0;
|
|
@@ -3458,7 +3766,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3458
3766
|
);
|
|
3459
3767
|
return "";
|
|
3460
3768
|
}
|
|
3461
|
-
return readFileSync(
|
|
3769
|
+
return readFileSync(join10(docsDir, files[0]), "utf8").trim();
|
|
3462
3770
|
}
|
|
3463
3771
|
function getNamedDoc(name, language) {
|
|
3464
3772
|
const docsDir = findDocsDir();
|
|
@@ -3466,7 +3774,7 @@ function getNamedDoc(name, language) {
|
|
|
3466
3774
|
logger.warn("docs/algolia-sdk not found");
|
|
3467
3775
|
return "";
|
|
3468
3776
|
}
|
|
3469
|
-
const file =
|
|
3777
|
+
const file = join10(docsDir, `${name}-${language}.md`);
|
|
3470
3778
|
if (!existsSync2(file)) {
|
|
3471
3779
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3472
3780
|
return "";
|
|
@@ -3493,50 +3801,50 @@ function shellQuote(value) {
|
|
|
3493
3801
|
}
|
|
3494
3802
|
|
|
3495
3803
|
// src/actions/implement.ts
|
|
3496
|
-
var implementSchema =
|
|
3497
|
-
filesChanged:
|
|
3498
|
-
summary:
|
|
3804
|
+
var implementSchema = z26.object({
|
|
3805
|
+
filesChanged: z26.array(z26.string()),
|
|
3806
|
+
summary: z26.string(),
|
|
3499
3807
|
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
3500
3808
|
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
3501
3809
|
// (`git -C <worktreePath> status/diff`).
|
|
3502
|
-
worktreePath:
|
|
3503
|
-
ingestCommand:
|
|
3810
|
+
worktreePath: z26.string().optional(),
|
|
3811
|
+
ingestCommand: z26.string().optional(),
|
|
3504
3812
|
// True when the user accepted the run-now prompt and the wizard executed the
|
|
3505
3813
|
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
3506
3814
|
// a script that already ran.
|
|
3507
|
-
ingestScriptRan:
|
|
3815
|
+
ingestScriptRan: z26.boolean().optional(),
|
|
3508
3816
|
// Records ingested by the run-now execution, parsed from the script's
|
|
3509
3817
|
// machine-readable count line; absent when the script didn't run or emitted
|
|
3510
3818
|
// no parseable count.
|
|
3511
|
-
ingestRecordCount:
|
|
3819
|
+
ingestRecordCount: z26.number().optional(),
|
|
3512
3820
|
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
3513
|
-
ingestDurationMs:
|
|
3514
|
-
ingestionSource:
|
|
3821
|
+
ingestDurationMs: z26.number().optional(),
|
|
3822
|
+
ingestionSource: z26.enum(["local", "fileUpload", "generated"]),
|
|
3515
3823
|
// Suggested names/values, built from framework detection. The search agent is
|
|
3516
3824
|
// instructed to rename the prefix if it doesn't match the project's build
|
|
3517
3825
|
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
3518
3826
|
// ground truth (the agent's summary carries the final names).
|
|
3519
|
-
searchEnvVars:
|
|
3520
|
-
|
|
3521
|
-
name:
|
|
3522
|
-
value:
|
|
3827
|
+
searchEnvVars: z26.array(
|
|
3828
|
+
z26.object({
|
|
3829
|
+
name: z26.string(),
|
|
3830
|
+
value: z26.string()
|
|
3523
3831
|
})
|
|
3524
3832
|
).optional()
|
|
3525
3833
|
});
|
|
3526
|
-
var implementationOutputSchema =
|
|
3527
|
-
summary:
|
|
3834
|
+
var implementationOutputSchema = z26.object({
|
|
3835
|
+
summary: z26.string(),
|
|
3528
3836
|
// Ingestion only: how to run the generated script, as a structured pair the
|
|
3529
3837
|
// wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
|
|
3530
3838
|
// command string. `runtime` is constrained to an allowlisted interpreter and
|
|
3531
3839
|
// `entrypoint` is validated to a worktree-relative path before execution, so
|
|
3532
3840
|
// the agent cannot inject extra commands or swap the interpreter.
|
|
3533
|
-
runtime:
|
|
3534
|
-
entrypoint:
|
|
3841
|
+
runtime: z26.enum(INGEST_RUNTIMES).optional(),
|
|
3842
|
+
entrypoint: z26.string().optional()
|
|
3535
3843
|
});
|
|
3536
|
-
var verificationOutputSchema =
|
|
3537
|
-
summary:
|
|
3538
|
-
sufficient:
|
|
3539
|
-
additionalInstructions:
|
|
3844
|
+
var verificationOutputSchema = z26.object({
|
|
3845
|
+
summary: z26.string(),
|
|
3846
|
+
sufficient: z26.boolean(),
|
|
3847
|
+
additionalInstructions: z26.string().optional()
|
|
3540
3848
|
});
|
|
3541
3849
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3542
3850
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3650,7 +3958,7 @@ function searchInstructions(input) {
|
|
|
3650
3958
|
doc,
|
|
3651
3959
|
`Add the search UI at ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working SearchBox and Hits against the "${input.targetIndex}" index.`,
|
|
3652
3960
|
"Read the App ID and a search-only API key from public env vars; never hardcode them. A search-only key is safe to expose client-side.",
|
|
3653
|
-
// appId always resolves (
|
|
3961
|
+
// appId always resolves (requireApplication throws otherwise); only the
|
|
3654
3962
|
// search-only key is best-effort and can fall back to a placeholder.
|
|
3655
3963
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3656
3964
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
@@ -3799,6 +4107,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3799
4107
|
}
|
|
3800
4108
|
}
|
|
3801
4109
|
const targetIndex = selected?.selection;
|
|
4110
|
+
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
3802
4111
|
await assertGitRepoWithHead(repoRoot);
|
|
3803
4112
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
3804
4113
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -3809,7 +4118,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3809
4118
|
let appId;
|
|
3810
4119
|
let searchKey;
|
|
3811
4120
|
if (useCases.includes("search")) {
|
|
3812
|
-
appId = (await
|
|
4121
|
+
appId = (await requireApplication()).id;
|
|
3813
4122
|
try {
|
|
3814
4123
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
3815
4124
|
} catch (err) {
|
|
@@ -3920,7 +4229,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3920
4229
|
messages: []
|
|
3921
4230
|
}) === true;
|
|
3922
4231
|
if (runNow) {
|
|
3923
|
-
const
|
|
4232
|
+
const ingestApp = await requireApplication();
|
|
4233
|
+
const writeKey = await resolveWriteKey(targetIndex);
|
|
3924
4234
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
3925
4235
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
3926
4236
|
runtime: ingestRuntime,
|
|
@@ -3932,8 +4242,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3932
4242
|
ingestRuntime,
|
|
3933
4243
|
ingestEntrypoint,
|
|
3934
4244
|
{
|
|
3935
|
-
[APP_ID_VAR]:
|
|
3936
|
-
[API_KEY_VAR]:
|
|
4245
|
+
[APP_ID_VAR]: ingestApp.id,
|
|
4246
|
+
[API_KEY_VAR]: writeKey
|
|
3937
4247
|
}
|
|
3938
4248
|
);
|
|
3939
4249
|
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
@@ -4144,8 +4454,8 @@ var defaultWorkflow = {
|
|
|
4144
4454
|
defineStep({
|
|
4145
4455
|
id: "select-index",
|
|
4146
4456
|
title: "Set up index",
|
|
4147
|
-
outputSchema:
|
|
4148
|
-
selection:
|
|
4457
|
+
outputSchema: z27.object({
|
|
4458
|
+
selection: z27.string()
|
|
4149
4459
|
}),
|
|
4150
4460
|
run: (ctx) => selectIndexStep(ctx)
|
|
4151
4461
|
}),
|
|
@@ -4424,7 +4734,7 @@ function parseCliArgs(argv) {
|
|
|
4424
4734
|
|
|
4425
4735
|
// src/lib/resetState.ts
|
|
4426
4736
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
4427
|
-
import { join as
|
|
4737
|
+
import { join as join11 } from "node:path";
|
|
4428
4738
|
var KEEP = ["wizard.log"];
|
|
4429
4739
|
async function resetProjectState() {
|
|
4430
4740
|
const dir = stateDir();
|
|
@@ -4436,7 +4746,7 @@ async function resetProjectState() {
|
|
|
4436
4746
|
}
|
|
4437
4747
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
4438
4748
|
await Promise.all(
|
|
4439
|
-
targets.map((name) => rm2(
|
|
4749
|
+
targets.map((name) => rm2(join11(dir, name), { recursive: true, force: true }))
|
|
4440
4750
|
);
|
|
4441
4751
|
return { dir, removed: targets };
|
|
4442
4752
|
}
|
|
@@ -4491,31 +4801,38 @@ ${formatStepList(workflow)}`);
|
|
|
4491
4801
|
}
|
|
4492
4802
|
async function run(workflow) {
|
|
4493
4803
|
const store = useWizard.getState();
|
|
4494
|
-
|
|
4804
|
+
const instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4805
|
+
await store.waitForStart();
|
|
4495
4806
|
let user = await getUser();
|
|
4496
4807
|
if (!user) {
|
|
4497
|
-
|
|
4498
|
-
instance.cleanup();
|
|
4808
|
+
store.beginAuth();
|
|
4499
4809
|
try {
|
|
4500
4810
|
await runAuthLogin();
|
|
4501
4811
|
} catch (err) {
|
|
4502
|
-
|
|
4812
|
+
store.setError(err instanceof Error ? err.message : String(err));
|
|
4813
|
+
await instance.waitUntilExit();
|
|
4503
4814
|
process.exit(1);
|
|
4504
4815
|
}
|
|
4505
|
-
|
|
4816
|
+
store.endAuth();
|
|
4506
4817
|
user = await getUser();
|
|
4507
4818
|
if (!user) {
|
|
4508
4819
|
store.setError(
|
|
4509
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
4820
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli@latest auth login` directly."
|
|
4510
4821
|
);
|
|
4511
4822
|
await instance.waitUntilExit();
|
|
4512
4823
|
process.exit(1);
|
|
4513
4824
|
}
|
|
4514
4825
|
}
|
|
4515
4826
|
store.setUser(user);
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4827
|
+
let app;
|
|
4828
|
+
try {
|
|
4829
|
+
app = await ensureApplication();
|
|
4830
|
+
} catch (err) {
|
|
4831
|
+
store.setError(err instanceof Error ? err.message : String(err));
|
|
4832
|
+
await instance.waitUntilExit();
|
|
4833
|
+
process.exit(1);
|
|
4834
|
+
}
|
|
4835
|
+
runWorkflow(workflow, app.id);
|
|
4519
4836
|
}
|
|
4520
4837
|
var started = await startup();
|
|
4521
4838
|
if (typeof started === "number") {
|