@algolia/wizard 0.8.0-rc.58.43 → 0.8.0-rc.58.45
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 +543 -800
- package/package.json +3 -1
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 Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as
|
|
7
|
+
import { Box as Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as useWindowSize7 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
@@ -12,86 +12,32 @@ import { nanoid } from "nanoid";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/algoliaCli.ts
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
import { createRequire } from "node:module";
|
|
16
|
+
var require2 = createRequire(import.meta.url);
|
|
17
|
+
function algoliaCliEntry() {
|
|
18
|
+
return require2.resolve("@algolia/cli/bin/run.js");
|
|
18
19
|
}
|
|
19
|
-
|
|
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(" ")}`);
|
|
20
|
+
function runAlgoliaCli(args) {
|
|
46
21
|
return new Promise((resolve4, reject) => {
|
|
47
|
-
const child = spawn(
|
|
22
|
+
const child = spawn(process.execPath, [algoliaCliEntry(), ...args]);
|
|
48
23
|
let stdout = "";
|
|
49
24
|
let stderr = "";
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
});
|
|
25
|
+
child.stdout.on("data", (chunk) => stdout += chunk);
|
|
26
|
+
child.stderr.on("data", (chunk) => stderr += chunk);
|
|
64
27
|
child.on("error", reject);
|
|
65
28
|
child.on("close", (code) => {
|
|
66
|
-
splitters.stdout.flush();
|
|
67
|
-
splitters.stderr.flush();
|
|
68
29
|
if (code === 0) {
|
|
69
30
|
resolve4(stdout);
|
|
70
31
|
} else {
|
|
71
|
-
const
|
|
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
|
-
}
|
|
32
|
+
const detail = stderr.trim() || stdout.trim();
|
|
78
33
|
reject(
|
|
79
34
|
new Error(
|
|
80
|
-
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail}`
|
|
35
|
+
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail ? `: ${detail}` : ""}`
|
|
81
36
|
)
|
|
82
37
|
);
|
|
83
38
|
}
|
|
84
39
|
});
|
|
85
|
-
})
|
|
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
|
-
);
|
|
40
|
+
});
|
|
95
41
|
}
|
|
96
42
|
async function getUser() {
|
|
97
43
|
let raw;
|
|
@@ -106,23 +52,19 @@ async function getUser() {
|
|
|
106
52
|
return null;
|
|
107
53
|
}
|
|
108
54
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
55
|
+
function runAuthLogin() {
|
|
56
|
+
return new Promise((resolve4, reject) => {
|
|
57
|
+
const child = spawn(
|
|
58
|
+
process.execPath,
|
|
59
|
+
[algoliaCliEntry(), "auth", "login", "--default"],
|
|
60
|
+
{ stdio: "inherit" }
|
|
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
|
+
});
|
|
116
67
|
});
|
|
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
|
-
}
|
|
126
68
|
}
|
|
127
69
|
|
|
128
70
|
// src/lib/auth.ts
|
|
@@ -229,7 +171,6 @@ function describeInputValue(value) {
|
|
|
229
171
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
230
172
|
}
|
|
231
173
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
232
|
-
var CLI_OUTPUT_LIMIT = 200;
|
|
233
174
|
var useWizard = create((set, get) => ({
|
|
234
175
|
phase: "idle",
|
|
235
176
|
homeScreen: "home",
|
|
@@ -241,18 +182,10 @@ var useWizard = create((set, get) => ({
|
|
|
241
182
|
notices: [],
|
|
242
183
|
_noticeQueue: [],
|
|
243
184
|
_noticeTimer: null,
|
|
244
|
-
cliOutput: [],
|
|
245
|
-
targetIndex: null,
|
|
246
185
|
logs: [],
|
|
247
186
|
error: null,
|
|
248
187
|
inputReq: null,
|
|
249
188
|
_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" } : {}),
|
|
256
189
|
// Advances past the welcome screen. Only meaningful from 'idle' — once the
|
|
257
190
|
// workflow is running there's nothing left to confirm.
|
|
258
191
|
// Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
|
|
@@ -287,13 +220,7 @@ var useWizard = create((set, get) => ({
|
|
|
287
220
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
288
221
|
setActiveStep: (index) => {
|
|
289
222
|
get()._clearNoticeQueue();
|
|
290
|
-
set({
|
|
291
|
-
phase: "running",
|
|
292
|
-
currentStepIndex: index,
|
|
293
|
-
output: "",
|
|
294
|
-
notices: [],
|
|
295
|
-
cliOutput: []
|
|
296
|
-
});
|
|
223
|
+
set({ phase: "running", currentStepIndex: index, output: "", notices: [] });
|
|
297
224
|
},
|
|
298
225
|
setUser: (user) => set({ user }),
|
|
299
226
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
@@ -334,16 +261,6 @@ var useWizard = create((set, get) => ({
|
|
|
334
261
|
get()._clearNoticeQueue();
|
|
335
262
|
set({ notices: [] });
|
|
336
263
|
},
|
|
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 }),
|
|
347
264
|
logStart: (kind, name, input) => {
|
|
348
265
|
const id = nanoid();
|
|
349
266
|
set((s) => ({
|
|
@@ -388,8 +305,6 @@ var useWizard = create((set, get) => ({
|
|
|
388
305
|
currentStepIndex: 0,
|
|
389
306
|
output: "",
|
|
390
307
|
notices: [],
|
|
391
|
-
cliOutput: [],
|
|
392
|
-
targetIndex: null,
|
|
393
308
|
logs: [],
|
|
394
309
|
error: null,
|
|
395
310
|
inputReq: null,
|
|
@@ -398,100 +313,16 @@ var useWizard = create((set, get) => ({
|
|
|
398
313
|
}
|
|
399
314
|
}));
|
|
400
315
|
|
|
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
|
-
|
|
485
316
|
// src/ui/Notices.tsx
|
|
486
|
-
import { Box as
|
|
317
|
+
import { Box as Box2, Text as Text2, useWindowSize as useWindowSize2 } from "ink";
|
|
487
318
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
488
319
|
|
|
489
320
|
// src/ui/Table.tsx
|
|
490
|
-
import { Box
|
|
321
|
+
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
491
322
|
import { useEffect, useRef, useState } from "react";
|
|
492
323
|
import { jsx } from "react/jsx-runtime";
|
|
493
324
|
function Table({ columns, rows }) {
|
|
494
|
-
const { columns: termCols } =
|
|
325
|
+
const { columns: termCols } = useWindowSize();
|
|
495
326
|
const ref = useRef(null);
|
|
496
327
|
const [width, setWidth] = useState(0);
|
|
497
328
|
useEffect(() => {
|
|
@@ -499,7 +330,7 @@ function Table({ columns, rows }) {
|
|
|
499
330
|
}, [termCols, columns, rows]);
|
|
500
331
|
if (rows.length === 0) return null;
|
|
501
332
|
const lines = formatTable(columns, rows, width || void 0);
|
|
502
|
-
return /* @__PURE__ */ jsx(
|
|
333
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", ref, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: line }, `tbl-${i}`)) });
|
|
503
334
|
}
|
|
504
335
|
function formatTable(columns, rows, width) {
|
|
505
336
|
const natural = columns.map(
|
|
@@ -539,13 +370,48 @@ function resize(widths, budget) {
|
|
|
539
370
|
}
|
|
540
371
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
541
372
|
|
|
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
|
+
|
|
542
408
|
// src/ui/Notices.tsx
|
|
543
|
-
import { jsx as jsx2, jsxs
|
|
409
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
544
410
|
var AGENT_MARKER = "\u2726";
|
|
545
|
-
var
|
|
546
|
-
var
|
|
411
|
+
var RESERVED_ROWS = 14;
|
|
412
|
+
var PANEL_TEXT_WIDTH = 45;
|
|
547
413
|
function messageLineCount(text) {
|
|
548
|
-
return Math.max(1, Math.ceil(text.length /
|
|
414
|
+
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
|
|
549
415
|
}
|
|
550
416
|
function noticeLineCount(notice) {
|
|
551
417
|
const messageLines = (notice.messages ?? []).reduce((sum, m) => {
|
|
@@ -556,7 +422,7 @@ function noticeLineCount(notice) {
|
|
|
556
422
|
return messageLines + tableLines;
|
|
557
423
|
}
|
|
558
424
|
function fitVisibleNotices(notices, windowRows) {
|
|
559
|
-
const budget = Math.max(windowRows -
|
|
425
|
+
const budget = Math.max(windowRows - RESERVED_ROWS, 3);
|
|
560
426
|
let used = 0;
|
|
561
427
|
let count = 0;
|
|
562
428
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -589,7 +455,7 @@ function parseHex(hex) {
|
|
|
589
455
|
}
|
|
590
456
|
function Notices() {
|
|
591
457
|
const notices = useWizard((s) => s.notices);
|
|
592
|
-
const { rows: windowRows } =
|
|
458
|
+
const { rows: windowRows } = useWindowSize2();
|
|
593
459
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
594
460
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
595
461
|
useEffect2(() => {
|
|
@@ -606,14 +472,14 @@ function Notices() {
|
|
|
606
472
|
}, []);
|
|
607
473
|
if (!visible.length) return null;
|
|
608
474
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
609
|
-
return /* @__PURE__ */ jsx2(
|
|
475
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
610
476
|
const isLatest = i === visible.length - 1;
|
|
611
|
-
return /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
|
|
612
478
|
notice.messages?.map((m, j) => {
|
|
613
479
|
const line = typeof m === "string" ? { text: m } : m;
|
|
614
480
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
615
|
-
return /* @__PURE__ */
|
|
616
|
-
|
|
481
|
+
return /* @__PURE__ */ jsxs(
|
|
482
|
+
Text2,
|
|
617
483
|
{
|
|
618
484
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
619
485
|
bold: line.bold,
|
|
@@ -633,40 +499,39 @@ function Notices() {
|
|
|
633
499
|
// src/ui/PromptInput.tsx
|
|
634
500
|
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
635
501
|
import TextInput from "ink-text-input";
|
|
636
|
-
import { useState as
|
|
502
|
+
import { useState as useState5 } from "react";
|
|
637
503
|
|
|
638
504
|
// src/ui/NextAction.tsx
|
|
639
|
-
import { Box as
|
|
640
|
-
import { Fragment, jsx as jsx3, jsxs as
|
|
505
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
506
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
641
507
|
function NextAction({
|
|
642
508
|
action,
|
|
643
509
|
keyHint,
|
|
644
510
|
hierarchy = "primary"
|
|
645
511
|
}) {
|
|
646
|
-
return /* @__PURE__ */
|
|
647
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
648
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */ jsx3(
|
|
650
|
-
/* @__PURE__ */ jsx3(
|
|
512
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "row", gap: 1, children: [
|
|
513
|
+
hierarchy === "primary" && /* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: `> ${action}` }),
|
|
514
|
+
hierarchy === "secondary" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
515
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: `>` }),
|
|
516
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.primary, bold: true, children: action })
|
|
651
517
|
] }),
|
|
652
|
-
/* @__PURE__ */
|
|
653
|
-
/* @__PURE__ */ jsx3(
|
|
654
|
-
/* @__PURE__ */ jsx3(
|
|
655
|
-
/* @__PURE__ */ jsx3(
|
|
656
|
-
/* @__PURE__ */ jsx3(
|
|
518
|
+
/* @__PURE__ */ jsxs2(Box3, { children: [
|
|
519
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: "press " }),
|
|
520
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: `[` }),
|
|
521
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.primary, children: keyHint }),
|
|
522
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: `]` })
|
|
657
523
|
] })
|
|
658
524
|
] });
|
|
659
525
|
}
|
|
660
526
|
|
|
661
527
|
// src/ui/SelectPrompt.tsx
|
|
662
|
-
import { Box as Box5, Text as Text5,
|
|
663
|
-
import { useLayoutEffect, useRef as
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
var ROW_HEIGHT = 3;
|
|
528
|
+
import { Box as Box5, Text as Text5, useInput, useWindowSize as useWindowSize4 } from "ink";
|
|
529
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
530
|
+
|
|
531
|
+
// src/ui/ScrollView.tsx
|
|
532
|
+
import { Box as Box4, Text as Text4, measureElement as measureElement2, useWindowSize as useWindowSize3 } from "ink";
|
|
533
|
+
import { useCallback, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
534
|
+
import { jsxs as jsxs3 } from "react/jsx-runtime";
|
|
670
535
|
var INDICATOR_ROWS = 2;
|
|
671
536
|
function fittedWidth(node, columns) {
|
|
672
537
|
let left = 0;
|
|
@@ -675,6 +540,89 @@ function fittedWidth(node, columns) {
|
|
|
675
540
|
}
|
|
676
541
|
return Math.max(Math.min(measureElement2(node).width, columns - left), 0);
|
|
677
542
|
}
|
|
543
|
+
function useScrollWindow({
|
|
544
|
+
itemCount,
|
|
545
|
+
rowHeight = 1,
|
|
546
|
+
followBottom = false
|
|
547
|
+
}) {
|
|
548
|
+
const viewportRef = useRef2(null);
|
|
549
|
+
const { columns } = useWindowSize3();
|
|
550
|
+
const [size, setSize] = useState3(
|
|
551
|
+
null
|
|
552
|
+
);
|
|
553
|
+
useLayoutEffect(() => {
|
|
554
|
+
if (!viewportRef.current) return;
|
|
555
|
+
const width = fittedWidth(viewportRef.current, columns);
|
|
556
|
+
const { height } = measureElement2(viewportRef.current);
|
|
557
|
+
setSize(
|
|
558
|
+
(prev) => prev?.width === width && prev.height === height ? prev : { width, height }
|
|
559
|
+
);
|
|
560
|
+
});
|
|
561
|
+
const capacity = size === null || itemCount * rowHeight <= size.height ? itemCount : Math.max(Math.floor((size.height - INDICATOR_ROWS) / rowHeight), 1);
|
|
562
|
+
const maxOffset = Math.max(itemCount - capacity, 0);
|
|
563
|
+
const [offset, setOffset] = useState3(0);
|
|
564
|
+
const prevMaxOffsetRef = useRef2(0);
|
|
565
|
+
useLayoutEffect(() => {
|
|
566
|
+
const wasAtBottom = offset >= prevMaxOffsetRef.current;
|
|
567
|
+
prevMaxOffsetRef.current = maxOffset;
|
|
568
|
+
setOffset(
|
|
569
|
+
(o) => followBottom && wasAtBottom ? maxOffset : Math.min(o, maxOffset)
|
|
570
|
+
);
|
|
571
|
+
}, [maxOffset, followBottom]);
|
|
572
|
+
const scrollBy = useCallback(
|
|
573
|
+
(delta) => {
|
|
574
|
+
setOffset((o) => Math.min(Math.max(o + delta, 0), maxOffset));
|
|
575
|
+
},
|
|
576
|
+
[maxOffset]
|
|
577
|
+
);
|
|
578
|
+
const revealIndex = useCallback(
|
|
579
|
+
(index) => {
|
|
580
|
+
setOffset((o) => {
|
|
581
|
+
if (index < o) return index;
|
|
582
|
+
if (index >= o + capacity) {
|
|
583
|
+
return Math.min(index - capacity + 1, maxOffset);
|
|
584
|
+
}
|
|
585
|
+
return o;
|
|
586
|
+
});
|
|
587
|
+
},
|
|
588
|
+
[capacity, maxOffset]
|
|
589
|
+
);
|
|
590
|
+
const visibleCount = Math.min(capacity, Math.max(itemCount - offset, 0));
|
|
591
|
+
return {
|
|
592
|
+
viewportRef,
|
|
593
|
+
width: size?.width ?? columns,
|
|
594
|
+
offset,
|
|
595
|
+
capacity,
|
|
596
|
+
maxOffset,
|
|
597
|
+
hiddenAbove: Math.min(offset, itemCount),
|
|
598
|
+
hiddenBelow: Math.max(itemCount - offset - visibleCount, 0),
|
|
599
|
+
scrollBy,
|
|
600
|
+
revealIndex
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function ScrollView({ scroll, children }) {
|
|
604
|
+
return /* @__PURE__ */ jsxs3(Box4, { ref: scroll.viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
605
|
+
scroll.hiddenAbove > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
606
|
+
"\u2191 ",
|
|
607
|
+
scroll.hiddenAbove,
|
|
608
|
+
" more"
|
|
609
|
+
] }),
|
|
610
|
+
children,
|
|
611
|
+
scroll.hiddenBelow > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
612
|
+
"\u2193 ",
|
|
613
|
+
scroll.hiddenBelow,
|
|
614
|
+
" more"
|
|
615
|
+
] })
|
|
616
|
+
] });
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// src/ui/SelectPrompt.tsx
|
|
620
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
621
|
+
var CANCEL = "cancel";
|
|
622
|
+
var ARROW_WIDTH = 4;
|
|
623
|
+
var COLUMN_GAP = 2;
|
|
624
|
+
var BAR_PADDING = 2;
|
|
625
|
+
var ROW_HEIGHT = 3;
|
|
678
626
|
function SelectPrompt({
|
|
679
627
|
options,
|
|
680
628
|
onSelect,
|
|
@@ -688,10 +636,10 @@ function SelectPrompt({
|
|
|
688
636
|
secondary,
|
|
689
637
|
defaultSelectedIndex = 0
|
|
690
638
|
}) {
|
|
691
|
-
const [index, setIndex] =
|
|
639
|
+
const [index, setIndex] = useState4(
|
|
692
640
|
() => defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0
|
|
693
641
|
);
|
|
694
|
-
const [checked, setChecked] =
|
|
642
|
+
const [checked, setChecked] = useState4(() => /* @__PURE__ */ new Set());
|
|
695
643
|
const hasCancel = Boolean(multi || cancelable);
|
|
696
644
|
const rows = hasCancel ? [...options, "Cancel"] : options;
|
|
697
645
|
const cancelIndex = hasCancel ? options.length : -1;
|
|
@@ -699,19 +647,14 @@ function SelectPrompt({
|
|
|
699
647
|
if (rows.length > 1) hints.push({ key: "[\u2191] [\u2193]", label: "move" });
|
|
700
648
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
701
649
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
702
|
-
const containerRef =
|
|
703
|
-
const
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
}
|
|
711
|
-
if (viewportRef.current) {
|
|
712
|
-
setViewportHeight(measureElement2(viewportRef.current).height);
|
|
713
|
-
}
|
|
714
|
-
}, [columns, windowRows, error, question, helpText, messages, table]);
|
|
650
|
+
const containerRef = useRef3(null);
|
|
651
|
+
const { columns } = useWindowSize4();
|
|
652
|
+
const [width, setWidth] = useState4(columns);
|
|
653
|
+
useLayoutEffect2(() => {
|
|
654
|
+
if (!containerRef.current) return;
|
|
655
|
+
const measured = fittedWidth(containerRef.current, columns);
|
|
656
|
+
setWidth((prev) => prev === measured ? prev : measured);
|
|
657
|
+
});
|
|
715
658
|
const inner = Math.max(width - BAR_PADDING, 0);
|
|
716
659
|
const labelWidth = Math.min(
|
|
717
660
|
ARROW_WIDTH + (multi ? 2 : 0) + Math.max(0, ...rows.map((opt) => opt.length)) + COLUMN_GAP,
|
|
@@ -727,22 +670,15 @@ function SelectPrompt({
|
|
|
727
670
|
const barWidth = Math.min(labelWidth + badgeWidth + BAR_PADDING, width);
|
|
728
671
|
const barLabelWidth = Math.max(barWidth - BAR_PADDING - badgeWidth, 0);
|
|
729
672
|
const textWidth = inner - labelWidth;
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
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;
|
|
673
|
+
const scroll = useScrollWindow({
|
|
674
|
+
itemCount: rows.length,
|
|
675
|
+
rowHeight: ROW_HEIGHT
|
|
676
|
+
});
|
|
677
|
+
const { revealIndex } = scroll;
|
|
678
|
+
useLayoutEffect2(() => {
|
|
679
|
+
revealIndex(index);
|
|
680
|
+
}, [index, revealIndex]);
|
|
681
|
+
const visible = rows.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
746
682
|
useInput((input, key) => {
|
|
747
683
|
if (rows.length === 0) return;
|
|
748
684
|
if (key.upArrow || input === "k") {
|
|
@@ -776,54 +712,42 @@ function SelectPrompt({
|
|
|
776
712
|
helpText && /* @__PURE__ */ jsx4(Text5, { color: COLORS.dim, children: helpText })
|
|
777
713
|
] })
|
|
778
714
|
] }),
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
]
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
width:
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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
|
-
] }),
|
|
715
|
+
/* @__PURE__ */ jsx4(ScrollView, { scroll, children: visible.map((option, visibleIndex) => {
|
|
716
|
+
const i = scroll.offset + visibleIndex;
|
|
717
|
+
const highlighted = i === index;
|
|
718
|
+
const isCancel = i === cancelIndex;
|
|
719
|
+
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
720
|
+
const sec = isCancel ? void 0 : secondary?.[i];
|
|
721
|
+
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
722
|
+
const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
|
|
723
|
+
highlighted ? "\u276F " : " ",
|
|
724
|
+
bullet,
|
|
725
|
+
option
|
|
726
|
+
] });
|
|
727
|
+
const isText = sec?.kind === "text";
|
|
728
|
+
return /* @__PURE__ */ jsxs4(
|
|
729
|
+
Box5,
|
|
730
|
+
{
|
|
731
|
+
width: isText ? "100%" : barWidth,
|
|
732
|
+
paddingX: 1,
|
|
733
|
+
paddingY: 1,
|
|
734
|
+
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
735
|
+
children: [
|
|
736
|
+
/* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
737
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
738
|
+
Text5,
|
|
739
|
+
{
|
|
740
|
+
wrap: "truncate",
|
|
741
|
+
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
742
|
+
children: sec.value
|
|
743
|
+
}
|
|
744
|
+
) }),
|
|
745
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box5, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text5, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
746
|
+
]
|
|
747
|
+
},
|
|
748
|
+
`row-${i}`
|
|
749
|
+
);
|
|
750
|
+
}) }),
|
|
827
751
|
/* @__PURE__ */ jsx4(Box5, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
828
752
|
i > 0 ? " " : "",
|
|
829
753
|
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
|
|
@@ -858,7 +782,7 @@ function EnterToContinuePrompt({
|
|
|
858
782
|
}
|
|
859
783
|
function PromptInput() {
|
|
860
784
|
const { phase, inputReq, submitInput } = useWizard();
|
|
861
|
-
const [draft, setDraft] =
|
|
785
|
+
const [draft, setDraft] = useState5("");
|
|
862
786
|
if (phase === "done" || phase === "error") {
|
|
863
787
|
return /* @__PURE__ */ jsx5(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
864
788
|
}
|
|
@@ -1348,8 +1272,7 @@ function Ribbon() {
|
|
|
1348
1272
|
import { useState as useState6 } from "react";
|
|
1349
1273
|
|
|
1350
1274
|
// src/ui/Logs.tsx
|
|
1351
|
-
import {
|
|
1352
|
-
import { Box as Box13, Text as Text13, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize7 } from "ink";
|
|
1275
|
+
import { Box as Box13, Text as Text13, useInput as useInput5 } from "ink";
|
|
1353
1276
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1354
1277
|
var KIND_COLOR = {
|
|
1355
1278
|
tool: COLORS.primary,
|
|
@@ -1380,74 +1303,31 @@ function formatTimestamp(ms) {
|
|
|
1380
1303
|
}
|
|
1381
1304
|
function Logs() {
|
|
1382
1305
|
const logs = useWizard((s) => s.logs);
|
|
1383
|
-
const {
|
|
1384
|
-
const viewportRef = useRef3(null);
|
|
1385
|
-
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1386
|
-
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
1387
|
-
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
1388
|
-
const prevMaxOffsetRef = useRef3(0);
|
|
1389
|
-
useLayoutEffect2(() => {
|
|
1390
|
-
if (!viewportRef.current) return;
|
|
1391
|
-
const { width, height } = measureElement3(viewportRef.current);
|
|
1392
|
-
setViewportHeight(height);
|
|
1393
|
-
setViewportWidth(width);
|
|
1394
|
-
}, [rows, columns, logs.length === 0]);
|
|
1395
|
-
let capacity = viewportHeight;
|
|
1396
|
-
for (let i = 0; i < 2; i++) {
|
|
1397
|
-
const hasAbove = scrollOffset > 0;
|
|
1398
|
-
const hasBelow = scrollOffset + capacity < logs.length;
|
|
1399
|
-
capacity = Math.max(
|
|
1400
|
-
viewportHeight - (hasAbove ? 1 : 0) - (hasBelow ? 1 : 0),
|
|
1401
|
-
0
|
|
1402
|
-
);
|
|
1403
|
-
}
|
|
1404
|
-
const capacityAtBottom = logs.length > viewportHeight ? Math.max(viewportHeight - 1, 0) : viewportHeight;
|
|
1405
|
-
const maxOffset = Math.max(logs.length - capacityAtBottom, 0);
|
|
1406
|
-
useLayoutEffect2(() => {
|
|
1407
|
-
const wasAtBottom = scrollOffset >= prevMaxOffsetRef.current;
|
|
1408
|
-
prevMaxOffsetRef.current = maxOffset;
|
|
1409
|
-
setScrollOffset((o) => wasAtBottom ? maxOffset : Math.min(o, maxOffset));
|
|
1410
|
-
}, [maxOffset]);
|
|
1306
|
+
const scroll = useScrollWindow({ itemCount: logs.length, followBottom: true });
|
|
1411
1307
|
useInput5((_input, key) => {
|
|
1412
|
-
if (
|
|
1413
|
-
|
|
1414
|
-
(o) => key.upArrow ? Math.max(o - 1, 0) : Math.min(o + 1, maxOffset)
|
|
1415
|
-
);
|
|
1308
|
+
if (key.upArrow) scroll.scrollBy(-1);
|
|
1309
|
+
else if (key.downArrow) scroll.scrollBy(1);
|
|
1416
1310
|
});
|
|
1417
|
-
const visible = logs.slice(
|
|
1418
|
-
const hiddenAbove = scrollOffset;
|
|
1419
|
-
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1311
|
+
const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
1420
1312
|
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1421
1313
|
logs.length === 0 && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "No logs yet." }),
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
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 })
|
|
1443
|
-
] }, entry.id);
|
|
1444
|
-
}),
|
|
1445
|
-
hiddenBelow > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
|
|
1446
|
-
"\u2193 ",
|
|
1447
|
-
hiddenBelow,
|
|
1448
|
-
" more"
|
|
1449
|
-
] })
|
|
1450
|
-
] }),
|
|
1314
|
+
/* @__PURE__ */ jsx12(ScrollView, { scroll, children: visible.map((entry) => {
|
|
1315
|
+
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
1316
|
+
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
1317
|
+
const rawPreview = rawInputText(entry.input);
|
|
1318
|
+
const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
|
|
1319
|
+
const gaps = (partCount - 1) * ROW_GAP;
|
|
1320
|
+
let budget = scroll.width - timestamp.length - durationText.length - gaps;
|
|
1321
|
+
const name = truncate2(entry.name, budget);
|
|
1322
|
+
budget -= name.length;
|
|
1323
|
+
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1324
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: timestamp }),
|
|
1326
|
+
/* @__PURE__ */ jsx12(Text13, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1327
|
+
preview && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1328
|
+
durationText && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: durationText })
|
|
1329
|
+
] }, entry.id);
|
|
1330
|
+
}) }),
|
|
1451
1331
|
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1452
1332
|
] });
|
|
1453
1333
|
}
|
|
@@ -1644,7 +1524,7 @@ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
|
1644
1524
|
function App() {
|
|
1645
1525
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1646
1526
|
const { exit } = useApp();
|
|
1647
|
-
const { columns, rows } =
|
|
1527
|
+
const { columns, rows } = useWindowSize7();
|
|
1648
1528
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1649
1529
|
const finished = phase === "done" || phase === "error";
|
|
1650
1530
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1657,7 +1537,7 @@ function App() {
|
|
|
1657
1537
|
{ isActive: finished }
|
|
1658
1538
|
);
|
|
1659
1539
|
useInput6((_input, key) => {
|
|
1660
|
-
if (phase === "idle" || phase === "
|
|
1540
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1661
1541
|
if (key.tab) {
|
|
1662
1542
|
setShowLogs(!showLogs);
|
|
1663
1543
|
track("AI Wizard Interaction", {
|
|
@@ -1667,7 +1547,7 @@ function App() {
|
|
|
1667
1547
|
});
|
|
1668
1548
|
}
|
|
1669
1549
|
});
|
|
1670
|
-
const escOwnedElsewhere = phase === "idle" || phase === "
|
|
1550
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1671
1551
|
useInput6((_input, key) => {
|
|
1672
1552
|
if (escOwnedElsewhere) return;
|
|
1673
1553
|
if (key.escape) {
|
|
@@ -1680,70 +1560,61 @@ function App() {
|
|
|
1680
1560
|
exit();
|
|
1681
1561
|
}
|
|
1682
1562
|
});
|
|
1683
|
-
const mainWindowVisible = phase === "
|
|
1563
|
+
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1684
1564
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1685
1565
|
const showSidebar = flexDirection === "row";
|
|
1686
|
-
return (
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
children:
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
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
|
-
)
|
|
1566
|
+
return /* @__PURE__ */ jsxs13(
|
|
1567
|
+
Box14,
|
|
1568
|
+
{
|
|
1569
|
+
backgroundColor: COLORS.bg.main,
|
|
1570
|
+
flexDirection: "row",
|
|
1571
|
+
width: columns,
|
|
1572
|
+
minHeight: rows,
|
|
1573
|
+
children: [
|
|
1574
|
+
mainWindowVisible && // Ink sizes the root by width only, so without a cap the scrolling
|
|
1575
|
+
// lists in here grow to their content instead of windowing (see
|
|
1576
|
+
// `useScrollWindow`). The home screens below stay uncapped: they are
|
|
1577
|
+
// long static copy that would be clipped rather than windowed.
|
|
1578
|
+
/* @__PURE__ */ jsxs13(
|
|
1579
|
+
Box14,
|
|
1580
|
+
{
|
|
1581
|
+
flexDirection,
|
|
1582
|
+
width: "100%",
|
|
1583
|
+
maxHeight: rows,
|
|
1584
|
+
justifyContent: "space-between",
|
|
1585
|
+
children: [
|
|
1586
|
+
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1587
|
+
/* Fill the space the sidebar/ribbon leaves — width beside the
|
|
1588
|
+
sidebar, height above the ribbon. The height matters even
|
|
1589
|
+
stacked: it is what the prompt's scrolling list measures itself
|
|
1590
|
+
against (see SelectPrompt). */
|
|
1591
|
+
/* @__PURE__ */ jsxs13(
|
|
1592
|
+
Box14,
|
|
1593
|
+
{
|
|
1594
|
+
flexDirection: "column",
|
|
1595
|
+
paddingX: 4,
|
|
1596
|
+
paddingY: 2,
|
|
1597
|
+
width: showSidebar ? 70 : "100%",
|
|
1598
|
+
flexGrow: 1,
|
|
1599
|
+
children: [
|
|
1600
|
+
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1601
|
+
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1602
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1603
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: COLORS.status.error, children: [
|
|
1604
|
+
"\u2716 ",
|
|
1605
|
+
error
|
|
1606
|
+
] }) })
|
|
1607
|
+
]
|
|
1608
|
+
}
|
|
1609
|
+
)
|
|
1610
|
+
),
|
|
1611
|
+
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
),
|
|
1615
|
+
(phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1616
|
+
]
|
|
1617
|
+
}
|
|
1747
1618
|
);
|
|
1748
1619
|
}
|
|
1749
1620
|
|
|
@@ -1979,138 +1850,61 @@ async function runWorkflow(workflow, appId) {
|
|
|
1979
1850
|
}
|
|
1980
1851
|
}
|
|
1981
1852
|
|
|
1982
|
-
// src/lib/
|
|
1983
|
-
import {
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
);
|
|
1996
|
-
async function currentApplication() {
|
|
1997
|
-
let raw;
|
|
1853
|
+
// src/lib/algoliaProfile.ts
|
|
1854
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1855
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
1856
|
+
import { homedir as homedir2 } from "node:os";
|
|
1857
|
+
import { join as join6 } from "node:path";
|
|
1858
|
+
import { parse as parseToml } from "toml";
|
|
1859
|
+
var require3 = createRequire2(import.meta.url);
|
|
1860
|
+
function configPath() {
|
|
1861
|
+
const base = process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config");
|
|
1862
|
+
return join6(base, "algolia", "config.toml");
|
|
1863
|
+
}
|
|
1864
|
+
function profilesFromConfig(tomlText) {
|
|
1865
|
+
let parsed;
|
|
1998
1866
|
try {
|
|
1999
|
-
|
|
1867
|
+
parsed = parseToml(tomlText);
|
|
2000
1868
|
} catch {
|
|
2001
|
-
return
|
|
1869
|
+
return [];
|
|
2002
1870
|
}
|
|
2003
|
-
const
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
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
|
-
);
|
|
2033
|
-
}
|
|
2034
|
-
return parsed.data;
|
|
2035
|
-
}
|
|
2036
|
-
function parseJson(text) {
|
|
1871
|
+
const profiles = Object.entries(parsed).filter(
|
|
1872
|
+
([, t]) => typeof t.application_id === "string" && typeof t.api_key === "string"
|
|
1873
|
+
).map(([name, t]) => ({
|
|
1874
|
+
name,
|
|
1875
|
+
appId: t.application_id,
|
|
1876
|
+
apiKey: t.api_key,
|
|
1877
|
+
isDefault: t.default === true
|
|
1878
|
+
}));
|
|
1879
|
+
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1880
|
+
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1881
|
+
}
|
|
1882
|
+
async function loadActiveProfile() {
|
|
1883
|
+
let profiles;
|
|
2037
1884
|
try {
|
|
2038
|
-
|
|
1885
|
+
profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
|
|
2039
1886
|
} catch {
|
|
2040
|
-
|
|
1887
|
+
profiles = [];
|
|
2041
1888
|
}
|
|
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) {
|
|
1889
|
+
const profile = profiles[0];
|
|
1890
|
+
if (!profile) {
|
|
2062
1891
|
throw new Error(
|
|
2063
|
-
"
|
|
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"
|
|
1892
|
+
"No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
|
|
2071
1893
|
);
|
|
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
|
-
}
|
|
2098
1894
|
}
|
|
2099
|
-
|
|
2100
|
-
async function ensureApplication() {
|
|
2101
|
-
return await currentApplication() ?? await promptForApplication();
|
|
1895
|
+
return profile;
|
|
2102
1896
|
}
|
|
2103
1897
|
|
|
2104
1898
|
// src/workflows/default.ts
|
|
2105
|
-
import { z as
|
|
1899
|
+
import { z as z25 } from "zod";
|
|
2106
1900
|
|
|
2107
1901
|
// src/actions/listIndices.ts
|
|
2108
|
-
import { z as
|
|
2109
|
-
var indicesListSchema =
|
|
2110
|
-
items:
|
|
2111
|
-
|
|
2112
|
-
name:
|
|
2113
|
-
entries:
|
|
1902
|
+
import { z as z3 } from "zod";
|
|
1903
|
+
var indicesListSchema = z3.object({
|
|
1904
|
+
items: z3.array(
|
|
1905
|
+
z3.object({
|
|
1906
|
+
name: z3.string(),
|
|
1907
|
+
entries: z3.number().default(0)
|
|
2114
1908
|
})
|
|
2115
1909
|
)
|
|
2116
1910
|
});
|
|
@@ -2181,12 +1975,12 @@ import "zod";
|
|
|
2181
1975
|
|
|
2182
1976
|
// src/lib/tools/listFiles.ts
|
|
2183
1977
|
import { tool } from "ai";
|
|
2184
|
-
import
|
|
1978
|
+
import z4 from "zod";
|
|
2185
1979
|
import { readdir } from "node:fs/promises";
|
|
2186
1980
|
|
|
2187
1981
|
// src/lib/tools/path.ts
|
|
2188
1982
|
import { lstat } from "node:fs/promises";
|
|
2189
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
1983
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join7, sep } from "node:path";
|
|
2190
1984
|
function resolveInRoot(ctx, path) {
|
|
2191
1985
|
const target = resolve2(ctx.cwd, path);
|
|
2192
1986
|
const rel = relative(ctx.root, target);
|
|
@@ -2202,7 +1996,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2202
1996
|
let current = ctx.root;
|
|
2203
1997
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
2204
1998
|
for (const part of parts) {
|
|
2205
|
-
current =
|
|
1999
|
+
current = join7(current, part);
|
|
2206
2000
|
try {
|
|
2207
2001
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
2208
2002
|
} catch (err) {
|
|
@@ -2217,7 +2011,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2217
2011
|
function listFilesTool(ctx) {
|
|
2218
2012
|
return tool({
|
|
2219
2013
|
description: "List files in the current working directory",
|
|
2220
|
-
inputSchema:
|
|
2014
|
+
inputSchema: z4.object(),
|
|
2221
2015
|
execute: async () => {
|
|
2222
2016
|
logger.info("called listFiles tool");
|
|
2223
2017
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -2233,13 +2027,13 @@ function listFilesTool(ctx) {
|
|
|
2233
2027
|
|
|
2234
2028
|
// src/lib/tools/changeDirectory.ts
|
|
2235
2029
|
import { tool as tool2 } from "ai";
|
|
2236
|
-
import
|
|
2030
|
+
import z5 from "zod";
|
|
2237
2031
|
import { stat } from "node:fs/promises";
|
|
2238
2032
|
function changeDirectoryTool(ctx) {
|
|
2239
2033
|
return tool2({
|
|
2240
2034
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
2241
|
-
inputSchema:
|
|
2242
|
-
path:
|
|
2035
|
+
inputSchema: z5.object({
|
|
2036
|
+
path: z5.string().describe("Directory to change into")
|
|
2243
2037
|
}),
|
|
2244
2038
|
execute: async ({ path }) => {
|
|
2245
2039
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -2261,13 +2055,13 @@ function changeDirectoryTool(ctx) {
|
|
|
2261
2055
|
|
|
2262
2056
|
// src/lib/tools/reportStatus.ts
|
|
2263
2057
|
import { tool as tool3 } from "ai";
|
|
2264
|
-
import
|
|
2058
|
+
import z6 from "zod";
|
|
2265
2059
|
function reportStatusTool(output) {
|
|
2266
2060
|
return tool3({
|
|
2267
2061
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2268
|
-
inputSchema:
|
|
2269
|
-
status:
|
|
2270
|
-
reason:
|
|
2062
|
+
inputSchema: z6.object({
|
|
2063
|
+
status: z6.enum(["success", "fail"]),
|
|
2064
|
+
reason: z6.string().optional(),
|
|
2271
2065
|
output
|
|
2272
2066
|
}),
|
|
2273
2067
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2279,8 +2073,8 @@ function reportStatusTool(output) {
|
|
|
2279
2073
|
|
|
2280
2074
|
// src/lib/tools/readFile.ts
|
|
2281
2075
|
import { tool as tool4 } from "ai";
|
|
2282
|
-
import
|
|
2283
|
-
import { readFile as
|
|
2076
|
+
import z7 from "zod";
|
|
2077
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2284
2078
|
|
|
2285
2079
|
// src/lib/tools/env.ts
|
|
2286
2080
|
import { basename } from "node:path";
|
|
@@ -2307,8 +2101,8 @@ function redactEnvValues(content) {
|
|
|
2307
2101
|
function readFileTool(ctx) {
|
|
2308
2102
|
return tool4({
|
|
2309
2103
|
description: "Read the contents of a file at the given path",
|
|
2310
|
-
inputSchema:
|
|
2311
|
-
filePath:
|
|
2104
|
+
inputSchema: z7.object({
|
|
2105
|
+
filePath: z7.string().describe("Path to the file to read")
|
|
2312
2106
|
}),
|
|
2313
2107
|
execute: async ({ filePath }) => {
|
|
2314
2108
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2318,7 +2112,7 @@ function readFileTool(ctx) {
|
|
|
2318
2112
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2319
2113
|
if (!resolved.ok) return resolved.error;
|
|
2320
2114
|
try {
|
|
2321
|
-
const content = await
|
|
2115
|
+
const content = await readFile4(resolved.target, "utf8");
|
|
2322
2116
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2323
2117
|
} catch (err) {
|
|
2324
2118
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2329,15 +2123,15 @@ function readFileTool(ctx) {
|
|
|
2329
2123
|
|
|
2330
2124
|
// src/lib/tools/writeFile.ts
|
|
2331
2125
|
import { tool as tool5 } from "ai";
|
|
2332
|
-
import
|
|
2126
|
+
import z8 from "zod";
|
|
2333
2127
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2334
2128
|
import { dirname as dirname4 } from "node:path";
|
|
2335
2129
|
function writeFileTool(ctx) {
|
|
2336
2130
|
return tool5({
|
|
2337
2131
|
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.",
|
|
2338
|
-
inputSchema:
|
|
2339
|
-
filePath:
|
|
2340
|
-
content:
|
|
2132
|
+
inputSchema: z8.object({
|
|
2133
|
+
filePath: z8.string().describe("Path to the file to write"),
|
|
2134
|
+
content: z8.string().describe("Content to write to the file")
|
|
2341
2135
|
}),
|
|
2342
2136
|
execute: async ({ filePath, content }) => {
|
|
2343
2137
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2362,95 +2156,9 @@ function writeFileTool(ctx) {
|
|
|
2362
2156
|
|
|
2363
2157
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2364
2158
|
import { tool as tool6 } from "ai";
|
|
2365
|
-
import
|
|
2366
|
-
import { mkdir as mkdir4, readFile as
|
|
2159
|
+
import z9 from "zod";
|
|
2160
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
2367
2161
|
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
|
|
2454
2162
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2455
2163
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2456
2164
|
function appendEnv(content, entries) {
|
|
@@ -2464,9 +2172,9 @@ function hasEnv(content, name) {
|
|
|
2464
2172
|
}
|
|
2465
2173
|
function writeCredentialsTool(ctx) {
|
|
2466
2174
|
return tool6({
|
|
2467
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2468
|
-
inputSchema:
|
|
2469
|
-
filePath:
|
|
2175
|
+
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials are read from the local Algolia CLI profile; 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.`,
|
|
2176
|
+
inputSchema: z9.object({
|
|
2177
|
+
filePath: z9.string().describe(
|
|
2470
2178
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2471
2179
|
)
|
|
2472
2180
|
}),
|
|
@@ -2474,17 +2182,11 @@ function writeCredentialsTool(ctx) {
|
|
|
2474
2182
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2475
2183
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2476
2184
|
if (resolved.ok === false) return resolved.error;
|
|
2477
|
-
|
|
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;
|
|
2185
|
+
let profile;
|
|
2483
2186
|
try {
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2187
|
+
profile = await loadActiveProfile();
|
|
2188
|
+
} catch {
|
|
2189
|
+
return "Error: no Algolia profile is configured, so credentials cannot be written. Ask the user to authenticate with the Algolia CLI first.";
|
|
2488
2190
|
}
|
|
2489
2191
|
try {
|
|
2490
2192
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2492,7 +2194,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2492
2194
|
}
|
|
2493
2195
|
let existing = "";
|
|
2494
2196
|
try {
|
|
2495
|
-
existing = await
|
|
2197
|
+
existing = await readFile5(resolved.target, "utf8");
|
|
2496
2198
|
} catch (err) {
|
|
2497
2199
|
if (err.code !== "ENOENT") throw err;
|
|
2498
2200
|
}
|
|
@@ -2503,8 +2205,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2503
2205
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2504
2206
|
}
|
|
2505
2207
|
const envWithCredentials = appendEnv(existing, [
|
|
2506
|
-
[APP_ID_VAR, appId],
|
|
2507
|
-
[API_KEY_VAR,
|
|
2208
|
+
[APP_ID_VAR, profile.appId],
|
|
2209
|
+
[API_KEY_VAR, profile.apiKey]
|
|
2508
2210
|
]);
|
|
2509
2211
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2510
2212
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2518,16 +2220,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2518
2220
|
|
|
2519
2221
|
// src/lib/tools/searchFiles.ts
|
|
2520
2222
|
import { tool as tool7 } from "ai";
|
|
2521
|
-
import
|
|
2522
|
-
import { readdir as readdir2, readFile as
|
|
2523
|
-
import { join as
|
|
2223
|
+
import z10 from "zod";
|
|
2224
|
+
import { readdir as readdir2, readFile as readFile6 } from "node:fs/promises";
|
|
2225
|
+
import { join as join8 } from "node:path";
|
|
2524
2226
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2525
2227
|
async function walkFiles(dir) {
|
|
2526
2228
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2527
2229
|
const out = [];
|
|
2528
2230
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2529
2231
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2530
|
-
const full =
|
|
2232
|
+
const full = join8(dir, e.name);
|
|
2531
2233
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2532
2234
|
else if (e.isFile()) out.push(full);
|
|
2533
2235
|
}
|
|
@@ -2536,9 +2238,9 @@ async function walkFiles(dir) {
|
|
|
2536
2238
|
function searchFilesTool(ctx) {
|
|
2537
2239
|
return tool7({
|
|
2538
2240
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2539
|
-
inputSchema:
|
|
2540
|
-
query:
|
|
2541
|
-
path:
|
|
2241
|
+
inputSchema: z10.object({
|
|
2242
|
+
query: z10.string().describe("JavaScript RegExp pattern to search for"),
|
|
2243
|
+
path: z10.string().optional().describe("Directory to search in (default: cwd)")
|
|
2542
2244
|
}),
|
|
2543
2245
|
execute: async ({ query, path = "." }) => {
|
|
2544
2246
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2560,7 +2262,7 @@ function searchFilesTool(ctx) {
|
|
|
2560
2262
|
for (const file of await walkFiles(resolved.target)) {
|
|
2561
2263
|
let content;
|
|
2562
2264
|
try {
|
|
2563
|
-
content = await
|
|
2265
|
+
content = await readFile6(file, "utf8");
|
|
2564
2266
|
} catch {
|
|
2565
2267
|
continue;
|
|
2566
2268
|
}
|
|
@@ -2582,7 +2284,7 @@ function searchFilesTool(ctx) {
|
|
|
2582
2284
|
|
|
2583
2285
|
// src/lib/tools/verifyImplementation.ts
|
|
2584
2286
|
import { tool as tool8 } from "ai";
|
|
2585
|
-
import
|
|
2287
|
+
import z11 from "zod";
|
|
2586
2288
|
|
|
2587
2289
|
// src/lib/tools/utils/runCommand.ts
|
|
2588
2290
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2604,9 +2306,9 @@ function runCommand(command, args, cwd) {
|
|
|
2604
2306
|
}
|
|
2605
2307
|
|
|
2606
2308
|
// src/lib/tools/utils/packageManager.ts
|
|
2607
|
-
import { readFile as
|
|
2309
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2608
2310
|
import { existsSync } from "node:fs";
|
|
2609
|
-
import { join as
|
|
2311
|
+
import { join as join9 } from "node:path";
|
|
2610
2312
|
var LOCKFILES = [
|
|
2611
2313
|
["pnpm-lock.yaml", "pnpm"],
|
|
2612
2314
|
["yarn.lock", "yarn"],
|
|
@@ -2615,13 +2317,13 @@ var LOCKFILES = [
|
|
|
2615
2317
|
["package-lock.json", "npm"]
|
|
2616
2318
|
];
|
|
2617
2319
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2618
|
-
return JSON.parse(await
|
|
2320
|
+
return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
|
|
2619
2321
|
}
|
|
2620
2322
|
function packageManagerFrom(pkg) {
|
|
2621
2323
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2622
2324
|
}
|
|
2623
2325
|
function packageManagerFromLockfile(cwd) {
|
|
2624
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2326
|
+
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2625
2327
|
}
|
|
2626
2328
|
async function detectPackageManager(cwd) {
|
|
2627
2329
|
try {
|
|
@@ -2662,7 +2364,7 @@ async function runRepoVerificationCheck() {
|
|
|
2662
2364
|
function verifyImplementationTool() {
|
|
2663
2365
|
return tool8({
|
|
2664
2366
|
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.",
|
|
2665
|
-
inputSchema:
|
|
2367
|
+
inputSchema: z11.object(),
|
|
2666
2368
|
execute: async () => {
|
|
2667
2369
|
logger.info("called verifyImplementation tool");
|
|
2668
2370
|
return runRepoVerificationCheck();
|
|
@@ -2676,7 +2378,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2676
2378
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2677
2379
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2678
2380
|
import { dirname as dirname6 } from "node:path";
|
|
2679
|
-
import
|
|
2381
|
+
import z12 from "zod";
|
|
2680
2382
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2681
2383
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2682
2384
|
var MAX_RECORDS = 100;
|
|
@@ -2688,17 +2390,17 @@ var anthropic = createAnthropic({
|
|
|
2688
2390
|
function generateRecordTool(ctx) {
|
|
2689
2391
|
return tool9({
|
|
2690
2392
|
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.",
|
|
2691
|
-
inputSchema:
|
|
2692
|
-
entityName:
|
|
2693
|
-
attributes:
|
|
2694
|
-
count:
|
|
2695
|
-
hint:
|
|
2393
|
+
inputSchema: z12.object({
|
|
2394
|
+
entityName: z12.string().describe("Name of the entity to generate records for."),
|
|
2395
|
+
attributes: z12.array(z12.string()).describe("Attribute names each record must contain."),
|
|
2396
|
+
count: z12.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
2397
|
+
hint: z12.string().optional().describe("Optional context to steer realistic values.")
|
|
2696
2398
|
}),
|
|
2697
2399
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2698
2400
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2699
2401
|
try {
|
|
2700
|
-
const value =
|
|
2701
|
-
const recordSchema =
|
|
2402
|
+
const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
|
|
2403
|
+
const recordSchema = z12.object(
|
|
2702
2404
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2703
2405
|
);
|
|
2704
2406
|
const generateBatch = async (batchCount) => {
|
|
@@ -2708,8 +2410,8 @@ function generateRecordTool(ctx) {
|
|
|
2708
2410
|
const { output } = await generateText({
|
|
2709
2411
|
model: anthropic(RECORD_MODEL),
|
|
2710
2412
|
output: Output.object({
|
|
2711
|
-
schema:
|
|
2712
|
-
records:
|
|
2413
|
+
schema: z12.object({
|
|
2414
|
+
records: z12.array(recordSchema).length(batchCount)
|
|
2713
2415
|
})
|
|
2714
2416
|
}),
|
|
2715
2417
|
prompt: [
|
|
@@ -2767,12 +2469,12 @@ function generateRecordTool(ctx) {
|
|
|
2767
2469
|
|
|
2768
2470
|
// src/lib/tools/notifyUser.ts
|
|
2769
2471
|
import { tool as tool10 } from "ai";
|
|
2770
|
-
import
|
|
2472
|
+
import z13 from "zod";
|
|
2771
2473
|
function notifyUserTool() {
|
|
2772
2474
|
return tool10({
|
|
2773
2475
|
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.`,
|
|
2774
|
-
inputSchema:
|
|
2775
|
-
message:
|
|
2476
|
+
inputSchema: z13.object({
|
|
2477
|
+
message: z13.string().describe(
|
|
2776
2478
|
"Short, plain-language description of what you are doing now."
|
|
2777
2479
|
)
|
|
2778
2480
|
}),
|
|
@@ -2952,10 +2654,10 @@ async function runAgent(req) {
|
|
|
2952
2654
|
}
|
|
2953
2655
|
|
|
2954
2656
|
// src/actions/detectLanguage.ts
|
|
2955
|
-
import
|
|
2956
|
-
var detectLanguageSchema =
|
|
2957
|
-
languages:
|
|
2958
|
-
frameworks:
|
|
2657
|
+
import z16 from "zod";
|
|
2658
|
+
var detectLanguageSchema = z16.object({
|
|
2659
|
+
languages: z16.array(z16.object({ name: z16.string(), version: z16.string() })),
|
|
2660
|
+
frameworks: z16.array(z16.object({ name: z16.string(), version: z16.string() }))
|
|
2959
2661
|
});
|
|
2960
2662
|
var detectLanguage = () => runAgent({
|
|
2961
2663
|
instructions: [
|
|
@@ -2973,31 +2675,31 @@ var detectLanguage = () => runAgent({
|
|
|
2973
2675
|
});
|
|
2974
2676
|
|
|
2975
2677
|
// src/actions/analyzeCodebase.ts
|
|
2976
|
-
import
|
|
2678
|
+
import z17 from "zod";
|
|
2977
2679
|
var READONLY_TOOLS = [
|
|
2978
2680
|
"listFiles",
|
|
2979
2681
|
"changeDirectory",
|
|
2980
2682
|
"readFile",
|
|
2981
2683
|
"searchFiles"
|
|
2982
2684
|
];
|
|
2983
|
-
var ingestionAnalysisSchema =
|
|
2984
|
-
ingestionAnalysis:
|
|
2985
|
-
|
|
2986
|
-
name:
|
|
2987
|
-
paths:
|
|
2685
|
+
var ingestionAnalysisSchema = z17.object({
|
|
2686
|
+
ingestionAnalysis: z17.array(
|
|
2687
|
+
z17.object({
|
|
2688
|
+
name: z17.string(),
|
|
2689
|
+
paths: z17.array(z17.string()),
|
|
2988
2690
|
// indexable fields the agent found for this entity
|
|
2989
|
-
attributes:
|
|
2691
|
+
attributes: z17.array(z17.string())
|
|
2990
2692
|
})
|
|
2991
2693
|
)
|
|
2992
2694
|
});
|
|
2993
|
-
var searchImplementationAnalysisSchema =
|
|
2994
|
-
searchImplementationAnalysis:
|
|
2695
|
+
var searchImplementationAnalysisSchema = z17.object({
|
|
2696
|
+
searchImplementationAnalysis: z17.string()
|
|
2995
2697
|
});
|
|
2996
|
-
var verificationSchema =
|
|
2997
|
-
verification:
|
|
2698
|
+
var verificationSchema = z17.object({
|
|
2699
|
+
verification: z17.array(z17.string())
|
|
2998
2700
|
});
|
|
2999
2701
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
3000
|
-
var analyzeCodebaseSchema =
|
|
2702
|
+
var analyzeCodebaseSchema = z17.object({
|
|
3001
2703
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3002
2704
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
3003
2705
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -3059,7 +2761,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3059
2761
|
// package.json
|
|
3060
2762
|
var package_default = {
|
|
3061
2763
|
name: "@algolia/wizard",
|
|
3062
|
-
version: "0.8.0-rc.58.
|
|
2764
|
+
version: "0.8.0-rc.58.45",
|
|
3063
2765
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3064
2766
|
type: "module",
|
|
3065
2767
|
engines: {
|
|
@@ -3107,6 +2809,7 @@ var package_default = {
|
|
|
3107
2809
|
dependencies: {
|
|
3108
2810
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3109
2811
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2812
|
+
"@algolia/cli": "^5.11.0",
|
|
3110
2813
|
"@hono/node-server": "^2.0.10",
|
|
3111
2814
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3112
2815
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3121,6 +2824,7 @@ var package_default = {
|
|
|
3121
2824
|
nanoid: "^5.1.15",
|
|
3122
2825
|
pino: "^10.3.1",
|
|
3123
2826
|
react: "^19.2.7",
|
|
2827
|
+
toml: "^4.1.1",
|
|
3124
2828
|
varlock: "^1.5.1",
|
|
3125
2829
|
zod: "^4.4.3",
|
|
3126
2830
|
zustand: "^5.0.14"
|
|
@@ -3178,8 +2882,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
3178
2882
|
}
|
|
3179
2883
|
|
|
3180
2884
|
// src/actions/confirmLanguage.ts
|
|
3181
|
-
import
|
|
3182
|
-
var confirmLanguageSchema =
|
|
2885
|
+
import z19 from "zod";
|
|
2886
|
+
var confirmLanguageSchema = z19.object({
|
|
3183
2887
|
languages: detectLanguageSchema.shape.languages
|
|
3184
2888
|
});
|
|
3185
2889
|
async function confirmLanguage(ctx) {
|
|
@@ -3200,8 +2904,8 @@ async function confirmLanguage(ctx) {
|
|
|
3200
2904
|
}
|
|
3201
2905
|
|
|
3202
2906
|
// src/actions/confirmFramework.ts
|
|
3203
|
-
import
|
|
3204
|
-
var confirmFrameworkSchema =
|
|
2907
|
+
import z20 from "zod";
|
|
2908
|
+
var confirmFrameworkSchema = z20.object({
|
|
3205
2909
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3206
2910
|
});
|
|
3207
2911
|
var CURATED_FRAMEWORKS = [
|
|
@@ -3329,8 +3033,8 @@ async function promptUser(ctx, params) {
|
|
|
3329
3033
|
}
|
|
3330
3034
|
|
|
3331
3035
|
// src/actions/confirmEntities.ts
|
|
3332
|
-
import
|
|
3333
|
-
var confirmEntitiesSchema =
|
|
3036
|
+
import z21 from "zod";
|
|
3037
|
+
var confirmEntitiesSchema = z21.object({
|
|
3334
3038
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3335
3039
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3336
3040
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3400,15 +3104,15 @@ async function confirmEntities(ctx) {
|
|
|
3400
3104
|
}
|
|
3401
3105
|
|
|
3402
3106
|
// src/actions/review.ts
|
|
3403
|
-
import { z as
|
|
3404
|
-
var reviewSchema =
|
|
3107
|
+
import { z as z22 } from "zod";
|
|
3108
|
+
var reviewSchema = z22.object({
|
|
3405
3109
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3406
3110
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3407
3111
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3408
3112
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3409
|
-
summaryPoints:
|
|
3410
|
-
reviewPrompt:
|
|
3411
|
-
nextSteps:
|
|
3113
|
+
summaryPoints: z22.array(z22.string()),
|
|
3114
|
+
reviewPrompt: z22.string(),
|
|
3115
|
+
nextSteps: z22.array(z22.string())
|
|
3412
3116
|
});
|
|
3413
3117
|
function formatCompletedSteps(steps) {
|
|
3414
3118
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3459,16 +3163,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3459
3163
|
};
|
|
3460
3164
|
|
|
3461
3165
|
// src/actions/implement.ts
|
|
3462
|
-
import
|
|
3166
|
+
import z24 from "zod";
|
|
3463
3167
|
|
|
3464
3168
|
// src/lib/worktree.ts
|
|
3465
3169
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3466
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3170
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3467
3171
|
import {
|
|
3468
3172
|
basename as basename2,
|
|
3469
3173
|
dirname as dirname7,
|
|
3470
3174
|
isAbsolute as isAbsolute2,
|
|
3471
|
-
join as
|
|
3175
|
+
join as join10,
|
|
3472
3176
|
relative as relative2,
|
|
3473
3177
|
resolve as resolve3
|
|
3474
3178
|
} from "node:path";
|
|
@@ -3502,7 +3206,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3502
3206
|
return out.trim().length > 0;
|
|
3503
3207
|
}
|
|
3504
3208
|
async function pruneOldWorktrees(repoRoot) {
|
|
3505
|
-
const dir =
|
|
3209
|
+
const dir = join10(stateDir(repoRoot), "worktrees");
|
|
3506
3210
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3507
3211
|
for (const slug of stale) {
|
|
3508
3212
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3513,7 +3217,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3513
3217
|
"worktree",
|
|
3514
3218
|
"remove",
|
|
3515
3219
|
"--force",
|
|
3516
|
-
|
|
3220
|
+
join10(dir, slug)
|
|
3517
3221
|
]);
|
|
3518
3222
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3519
3223
|
} catch (err) {
|
|
@@ -3527,7 +3231,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3527
3231
|
async function createWorktree(repoRoot) {
|
|
3528
3232
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3529
3233
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3530
|
-
const path =
|
|
3234
|
+
const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3531
3235
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3532
3236
|
await pruneOldWorktrees(repoRoot);
|
|
3533
3237
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3647,8 +3351,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3647
3351
|
} catch {
|
|
3648
3352
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3649
3353
|
}
|
|
3650
|
-
const relPath =
|
|
3651
|
-
const dest =
|
|
3354
|
+
const relPath = join10(ingestDir, basename2(source));
|
|
3355
|
+
const dest = join10(worktreePath, relPath);
|
|
3652
3356
|
try {
|
|
3653
3357
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3654
3358
|
await copyFile(source, dest);
|
|
@@ -3664,10 +3368,10 @@ function hasEnvVar(content, name) {
|
|
|
3664
3368
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3665
3369
|
}
|
|
3666
3370
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3667
|
-
const target =
|
|
3371
|
+
const target = join10(worktreePath, ".env");
|
|
3668
3372
|
let existing = "";
|
|
3669
3373
|
try {
|
|
3670
|
-
existing = await
|
|
3374
|
+
existing = await readFile8(target, "utf8");
|
|
3671
3375
|
} catch (err) {
|
|
3672
3376
|
if (err.code !== "ENOENT") throw err;
|
|
3673
3377
|
}
|
|
@@ -3735,15 +3439,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3735
3439
|
}
|
|
3736
3440
|
}
|
|
3737
3441
|
|
|
3442
|
+
// src/lib/algoliaApiKey.ts
|
|
3443
|
+
import { z as z23 } from "zod";
|
|
3444
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
3445
|
+
var apiKeySchema = z23.object({
|
|
3446
|
+
value: z23.string().min(1),
|
|
3447
|
+
acl: z23.array(z23.string()).default([]),
|
|
3448
|
+
indexes: z23.array(z23.string()).default([])
|
|
3449
|
+
});
|
|
3450
|
+
var apiKeyListSchema = z23.object({
|
|
3451
|
+
items: z23.array(apiKeySchema).optional(),
|
|
3452
|
+
keys: z23.array(apiKeySchema).optional()
|
|
3453
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
3454
|
+
var createdKeySchema = z23.object({
|
|
3455
|
+
key: z23.string().min(1).optional(),
|
|
3456
|
+
value: z23.string().min(1).optional()
|
|
3457
|
+
});
|
|
3458
|
+
function canReuse(key, index) {
|
|
3459
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
3460
|
+
}
|
|
3461
|
+
async function createSearchKey(index) {
|
|
3462
|
+
const stdout = await runAlgoliaCli([
|
|
3463
|
+
"apikeys",
|
|
3464
|
+
"create",
|
|
3465
|
+
"--indices",
|
|
3466
|
+
index,
|
|
3467
|
+
"--acl",
|
|
3468
|
+
"search,browse",
|
|
3469
|
+
"--description",
|
|
3470
|
+
`wizard search-only key for ${index}`,
|
|
3471
|
+
"-o",
|
|
3472
|
+
"json"
|
|
3473
|
+
]);
|
|
3474
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
3475
|
+
const created = key ?? value;
|
|
3476
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
3477
|
+
return created;
|
|
3478
|
+
}
|
|
3479
|
+
async function resolveSearchOnlyKey(index) {
|
|
3480
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
3481
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
3482
|
+
if (existing) {
|
|
3483
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
3484
|
+
return existing;
|
|
3485
|
+
}
|
|
3486
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
3487
|
+
return createSearchKey(index);
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3738
3490
|
// src/lib/algoliaDocs.ts
|
|
3739
3491
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3740
|
-
import { dirname as dirname8, join as
|
|
3492
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
3741
3493
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3742
|
-
var DOCS_SUBPATH =
|
|
3494
|
+
var DOCS_SUBPATH = join11("docs", "algolia-sdk");
|
|
3743
3495
|
function findDocsDir() {
|
|
3744
3496
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3745
3497
|
for (; ; ) {
|
|
3746
|
-
const candidate =
|
|
3498
|
+
const candidate = join11(dir, DOCS_SUBPATH);
|
|
3747
3499
|
if (existsSync2(candidate)) return candidate;
|
|
3748
3500
|
const parent = dirname8(dir);
|
|
3749
3501
|
if (parent === dir) return void 0;
|
|
@@ -3766,7 +3518,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3766
3518
|
);
|
|
3767
3519
|
return "";
|
|
3768
3520
|
}
|
|
3769
|
-
return readFileSync(
|
|
3521
|
+
return readFileSync(join11(docsDir, files[0]), "utf8").trim();
|
|
3770
3522
|
}
|
|
3771
3523
|
function getNamedDoc(name, language) {
|
|
3772
3524
|
const docsDir = findDocsDir();
|
|
@@ -3774,7 +3526,7 @@ function getNamedDoc(name, language) {
|
|
|
3774
3526
|
logger.warn("docs/algolia-sdk not found");
|
|
3775
3527
|
return "";
|
|
3776
3528
|
}
|
|
3777
|
-
const file =
|
|
3529
|
+
const file = join11(docsDir, `${name}-${language}.md`);
|
|
3778
3530
|
if (!existsSync2(file)) {
|
|
3779
3531
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3780
3532
|
return "";
|
|
@@ -3801,50 +3553,50 @@ function shellQuote(value) {
|
|
|
3801
3553
|
}
|
|
3802
3554
|
|
|
3803
3555
|
// src/actions/implement.ts
|
|
3804
|
-
var implementSchema =
|
|
3805
|
-
filesChanged:
|
|
3806
|
-
summary:
|
|
3556
|
+
var implementSchema = z24.object({
|
|
3557
|
+
filesChanged: z24.array(z24.string()),
|
|
3558
|
+
summary: z24.string(),
|
|
3807
3559
|
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
3808
3560
|
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
3809
3561
|
// (`git -C <worktreePath> status/diff`).
|
|
3810
|
-
worktreePath:
|
|
3811
|
-
ingestCommand:
|
|
3562
|
+
worktreePath: z24.string().optional(),
|
|
3563
|
+
ingestCommand: z24.string().optional(),
|
|
3812
3564
|
// True when the user accepted the run-now prompt and the wizard executed the
|
|
3813
3565
|
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
3814
3566
|
// a script that already ran.
|
|
3815
|
-
ingestScriptRan:
|
|
3567
|
+
ingestScriptRan: z24.boolean().optional(),
|
|
3816
3568
|
// Records ingested by the run-now execution, parsed from the script's
|
|
3817
3569
|
// machine-readable count line; absent when the script didn't run or emitted
|
|
3818
3570
|
// no parseable count.
|
|
3819
|
-
ingestRecordCount:
|
|
3571
|
+
ingestRecordCount: z24.number().optional(),
|
|
3820
3572
|
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
3821
|
-
ingestDurationMs:
|
|
3822
|
-
ingestionSource:
|
|
3573
|
+
ingestDurationMs: z24.number().optional(),
|
|
3574
|
+
ingestionSource: z24.enum(["local", "fileUpload", "generated"]),
|
|
3823
3575
|
// Suggested names/values, built from framework detection. The search agent is
|
|
3824
3576
|
// instructed to rename the prefix if it doesn't match the project's build
|
|
3825
3577
|
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
3826
3578
|
// ground truth (the agent's summary carries the final names).
|
|
3827
|
-
searchEnvVars:
|
|
3828
|
-
|
|
3829
|
-
name:
|
|
3830
|
-
value:
|
|
3579
|
+
searchEnvVars: z24.array(
|
|
3580
|
+
z24.object({
|
|
3581
|
+
name: z24.string(),
|
|
3582
|
+
value: z24.string()
|
|
3831
3583
|
})
|
|
3832
3584
|
).optional()
|
|
3833
3585
|
});
|
|
3834
|
-
var implementationOutputSchema =
|
|
3835
|
-
summary:
|
|
3586
|
+
var implementationOutputSchema = z24.object({
|
|
3587
|
+
summary: z24.string(),
|
|
3836
3588
|
// Ingestion only: how to run the generated script, as a structured pair the
|
|
3837
3589
|
// wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
|
|
3838
3590
|
// command string. `runtime` is constrained to an allowlisted interpreter and
|
|
3839
3591
|
// `entrypoint` is validated to a worktree-relative path before execution, so
|
|
3840
3592
|
// the agent cannot inject extra commands or swap the interpreter.
|
|
3841
|
-
runtime:
|
|
3842
|
-
entrypoint:
|
|
3593
|
+
runtime: z24.enum(INGEST_RUNTIMES).optional(),
|
|
3594
|
+
entrypoint: z24.string().optional()
|
|
3843
3595
|
});
|
|
3844
|
-
var verificationOutputSchema =
|
|
3845
|
-
summary:
|
|
3846
|
-
sufficient:
|
|
3847
|
-
additionalInstructions:
|
|
3596
|
+
var verificationOutputSchema = z24.object({
|
|
3597
|
+
summary: z24.string(),
|
|
3598
|
+
sufficient: z24.boolean(),
|
|
3599
|
+
additionalInstructions: z24.string().optional()
|
|
3848
3600
|
});
|
|
3849
3601
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3850
3602
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3958,7 +3710,7 @@ function searchInstructions(input) {
|
|
|
3958
3710
|
doc,
|
|
3959
3711
|
`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.`,
|
|
3960
3712
|
"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.",
|
|
3961
|
-
// appId always resolves (
|
|
3713
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3962
3714
|
// search-only key is best-effort and can fall back to a placeholder.
|
|
3963
3715
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3964
3716
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
@@ -4107,7 +3859,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4107
3859
|
}
|
|
4108
3860
|
}
|
|
4109
3861
|
const targetIndex = selected?.selection;
|
|
4110
|
-
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4111
3862
|
await assertGitRepoWithHead(repoRoot);
|
|
4112
3863
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4113
3864
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4118,7 +3869,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4118
3869
|
let appId;
|
|
4119
3870
|
let searchKey;
|
|
4120
3871
|
if (useCases.includes("search")) {
|
|
4121
|
-
appId = (await
|
|
3872
|
+
appId = (await loadActiveProfile()).appId;
|
|
4122
3873
|
try {
|
|
4123
3874
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4124
3875
|
} catch (err) {
|
|
@@ -4229,8 +3980,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4229
3980
|
messages: []
|
|
4230
3981
|
}) === true;
|
|
4231
3982
|
if (runNow) {
|
|
4232
|
-
const
|
|
4233
|
-
const writeKey = await resolveWriteKey(targetIndex);
|
|
3983
|
+
const profile = await loadActiveProfile();
|
|
4234
3984
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4235
3985
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4236
3986
|
runtime: ingestRuntime,
|
|
@@ -4242,8 +3992,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4242
3992
|
ingestRuntime,
|
|
4243
3993
|
ingestEntrypoint,
|
|
4244
3994
|
{
|
|
4245
|
-
[APP_ID_VAR]:
|
|
4246
|
-
[API_KEY_VAR]:
|
|
3995
|
+
[APP_ID_VAR]: profile.appId,
|
|
3996
|
+
[API_KEY_VAR]: profile.apiKey
|
|
4247
3997
|
}
|
|
4248
3998
|
);
|
|
4249
3999
|
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
@@ -4454,8 +4204,8 @@ var defaultWorkflow = {
|
|
|
4454
4204
|
defineStep({
|
|
4455
4205
|
id: "select-index",
|
|
4456
4206
|
title: "Set up index",
|
|
4457
|
-
outputSchema:
|
|
4458
|
-
selection:
|
|
4207
|
+
outputSchema: z25.object({
|
|
4208
|
+
selection: z25.string()
|
|
4459
4209
|
}),
|
|
4460
4210
|
run: (ctx) => selectIndexStep(ctx)
|
|
4461
4211
|
}),
|
|
@@ -4734,7 +4484,7 @@ function parseCliArgs(argv) {
|
|
|
4734
4484
|
|
|
4735
4485
|
// src/lib/resetState.ts
|
|
4736
4486
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
4737
|
-
import { join as
|
|
4487
|
+
import { join as join12 } from "node:path";
|
|
4738
4488
|
var KEEP = ["wizard.log"];
|
|
4739
4489
|
async function resetProjectState() {
|
|
4740
4490
|
const dir = stateDir();
|
|
@@ -4746,7 +4496,7 @@ async function resetProjectState() {
|
|
|
4746
4496
|
}
|
|
4747
4497
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
4748
4498
|
await Promise.all(
|
|
4749
|
-
targets.map((name) => rm2(
|
|
4499
|
+
targets.map((name) => rm2(join12(dir, name), { recursive: true, force: true }))
|
|
4750
4500
|
);
|
|
4751
4501
|
return { dir, removed: targets };
|
|
4752
4502
|
}
|
|
@@ -4801,38 +4551,31 @@ ${formatStepList(workflow)}`);
|
|
|
4801
4551
|
}
|
|
4802
4552
|
async function run(workflow) {
|
|
4803
4553
|
const store = useWizard.getState();
|
|
4804
|
-
|
|
4805
|
-
await store.waitForStart();
|
|
4554
|
+
let instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4806
4555
|
let user = await getUser();
|
|
4807
4556
|
if (!user) {
|
|
4808
|
-
|
|
4557
|
+
await instance.waitUntilRenderFlush();
|
|
4558
|
+
instance.cleanup();
|
|
4809
4559
|
try {
|
|
4810
4560
|
await runAuthLogin();
|
|
4811
4561
|
} catch (err) {
|
|
4812
|
-
|
|
4813
|
-
await instance.waitUntilExit();
|
|
4562
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
4814
4563
|
process.exit(1);
|
|
4815
4564
|
}
|
|
4816
|
-
|
|
4565
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4817
4566
|
user = await getUser();
|
|
4818
4567
|
if (!user) {
|
|
4819
4568
|
store.setError(
|
|
4820
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli
|
|
4569
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
4821
4570
|
);
|
|
4822
4571
|
await instance.waitUntilExit();
|
|
4823
4572
|
process.exit(1);
|
|
4824
4573
|
}
|
|
4825
4574
|
}
|
|
4826
4575
|
store.setUser(user);
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
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);
|
|
4576
|
+
const profile = await loadActiveProfile();
|
|
4577
|
+
await store.waitForStart();
|
|
4578
|
+
runWorkflow(workflow, profile?.appId);
|
|
4836
4579
|
}
|
|
4837
4580
|
var started = await startup();
|
|
4838
4581
|
if (typeof started === "number") {
|